From d7263f21f0817b878296f26e647dbcec27adb5a3 Mon Sep 17 00:00:00 2001 From: Magnar Sveen Date: Thu, 27 Sep 2012 00:29:25 +0200 Subject: [PATCH] A more rubust way of finding the command currently being invoked. - which is necessary because cua-mode does some wacky stuff. Fixes #8 --- features/multiple-cursors-core.feature | 10 +++++ features/support/env.el | 1 + multiple-cursors-core.el | 61 ++++++++++++++++++-------- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/features/multiple-cursors-core.feature b/features/multiple-cursors-core.feature index 64e3ae6..718e17f 100644 --- a/features/multiple-cursors-core.feature +++ b/features/multiple-cursors-core.feature @@ -109,6 +109,16 @@ Feature: Multiple cursors core And I press "M-l" Then I should see "This text_snippet contains the word text_snippet twice" + Scenario: cua-mode + Given I turn on cua-mode + And I insert "This text contains the word text twice" + And I go to the front of the word "text" + And I press "C-SPC" + And I press "M-f" + And I press "C->" + And I type "!" + Then I should see "This ! contains the word ! twice" + Scenario: Interprogram paste Given I have cursors at "text" in "This text contains the word text twice" When I copy "external" in another program diff --git a/features/support/env.el b/features/support/env.el index 652016a..a55d319 100644 --- a/features/support/env.el +++ b/features/support/env.el @@ -15,6 +15,7 @@ (defun mc/save-lists ()) ;; redefine to do nothing when running tests (Before + (cua-mode 0) (multiple-cursors-mode 0) (rectangular-region-mode 0) (global-set-key (kbd "C->") 'mc/mark-next-like-this) diff --git a/multiple-cursors-core.el b/multiple-cursors-core.el index 3adcaa6..12f3f48 100644 --- a/multiple-cursors-core.el +++ b/multiple-cursors-core.el @@ -249,6 +249,22 @@ cursor with updated info." (1+ (count-if 'mc/fake-cursor-p (overlays-in (point-min) (point-max))))) +(defvar mc--this-command nil + "Used to store the original command being run.") +(make-variable-buffer-local 'mc--this-command) + +(defun mc/make-a-note-of-the-command-being-run () + "Used with pre-command-hook to store the original command being run. +Since that cannot be reliably determined in the post-command-hook. + +Specifically, this-original-command isn't always right, because it could have +been remapped. And certain modes (cua comes to mind) will change their +remapping based on state. So a command that changes the state will afterwards +not be recognized through the command-remapping lookup." + (unless mc--executing-command-for-fake-cursor + (setq mc--this-command (or (command-remapping this-original-command) + this-original-command)))) + (defun mc/execute-this-command-for-all-cursors () "Used with post-command-hook to execute supported commands for all cursors. @@ -260,26 +276,29 @@ Some commands are so unsupported that they are even prevented for the original cursor, to inform about the lack of support." (if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode (multiple-cursors-mode 0) - (let ((original-command (or (command-remapping this-original-command) - this-original-command))) - ;; if it's a lambda, we can't know if it's supported or not - ;; - so go ahead and assume it's ok, because we're just optimistic like that - (if (not (symbolp original-command)) - (mc/execute-command-for-all-fake-cursors original-command) + (when this-original-command + (let ((original-command (or mc--this-command + (command-remapping this-original-command) + this-original-command))) - ;; otherwise it's a symbol, and we can be more thorough - (if (get original-command 'mc--unsupported) - (message "%S is not supported with multiple cursors%s" - original-command - (get original-command 'mc--unsupported)) - (when (and original-command - (not (memq original-command mc--default-cmds-to-run-once)) - (not (memq original-command mc/cmds-to-run-once)) - (or (memq original-command mc--default-cmds-to-run-for-all) - (memq original-command mc/cmds-to-run-for-all) - (mc/prompt-for-inclusion-in-whitelist original-command))) - (mc/execute-command-for-all-fake-cursors original-command))))))) + ;; if it's a lambda, we can't know if it's supported or not + ;; - so go ahead and assume it's ok, because we're just optimistic like that + (if (not (symbolp original-command)) + (mc/execute-command-for-all-fake-cursors original-command) + + ;; otherwise it's a symbol, and we can be more thorough + (if (get original-command 'mc--unsupported) + (message "%S is not supported with multiple cursors%s" + original-command + (get original-command 'mc--unsupported)) + (when (and original-command + (not (memq original-command mc--default-cmds-to-run-once)) + (not (memq original-command mc/cmds-to-run-once)) + (or (memq original-command mc--default-cmds-to-run-for-all) + (memq original-command mc/cmds-to-run-for-all) + (mc/prompt-for-inclusion-in-whitelist original-command))) + (mc/execute-command-for-all-fake-cursors original-command)))))))) (defun mc/remove-fake-cursors () "Remove all fake cursors. @@ -338,6 +357,7 @@ They are temporarily disabled when multiple-cursors are active.") (make-variable-buffer-local 'mc/temporarily-disabled-minor-modes) (defun mc/temporarily-disable-minor-mode (mode) + "If MODE is available and turned on, remember that and turn it off." (when (and (boundp mode) (eval mode)) (add-to-list 'mc/temporarily-disabled-minor-modes mode) (funcall mode -1))) @@ -358,9 +378,12 @@ They are temporarily disabled when multiple-cursors are active.") (if multiple-cursors-mode (progn (mc/temporarily-disable-unsupported-minor-modes) + (add-hook 'pre-command-hook 'mc/make-a-note-of-the-command-being-run nil t) (add-hook 'post-command-hook 'mc/execute-this-command-for-all-cursors t t) (run-hooks 'multiple-cursors-mode-enabled-hook)) (remove-hook 'post-command-hook 'mc/execute-this-command-for-all-cursors t) + (remove-hook 'pre-command-hook 'mc/make-a-note-of-the-command-being-run t) + (setq mc--this-command nil) (mc--maybe-set-killed-rectangle) (mc/remove-fake-cursors) (mc/enable-temporarily-disabled-minor-modes) @@ -536,6 +559,8 @@ for running commands with multiple cursors.") end-of-line set-mark-command exchange-point-and-mark + cua-set-mark + cua-replace-region move-end-of-line beginning-of-line move-beginning-of-line