Merge pull request #382 from ayyess/master

Support commands with multiple read-chars
This commit is contained in:
Magnar Sveen 2023-07-28 07:18:59 +02:00 committed by GitHub
commit 234806c832
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 24 deletions

View File

@ -50,6 +50,13 @@ Feature: Multiple cursors core
And I press "C-!" And I press "C-!"
Then I should see "This aatext contains the word aatext twice" Then I should see "This aatext contains the word aatext twice"
Scenario: Unknown command with multiple read: yes, do for all
Given I have bound C-! to a new command that inserts two read-chars
And I have cursors at "text" in "This text contains the word text twice"
When I press "C-! b c y"
And I press "C-! d e"
Then I should see "This bcdetext contains the word bcdetext twice"
Scenario: Unknown command: no, don't do for all Scenario: Unknown command: no, don't do for all
Given I have bound C-! to another new command that inserts "a" Given I have bound C-! to another new command that inserts "a"
And I have cursors at "text" in "This text contains the word text twice" And I have cursors at "text" in "This text contains the word text twice"

View File

@ -130,6 +130,11 @@
(defun mc-test-temp-command-2 () (interactive) (insert ins)) (defun mc-test-temp-command-2 () (interactive) (insert ins))
(global-set-key (kbd "C-!") 'mc-test-temp-command-2)))) (global-set-key (kbd "C-!") 'mc-test-temp-command-2))))
(Given "^I have bound C-! to a new command that inserts two read-chars$"
(lambda ()
(defun mc-test-temp-command-3 () (interactive) (insert (read-char "first: ")) (insert (read-char "second: ")))
(global-set-key (kbd "C-!") 'mc-test-temp-command-3)))
(Given "^I have bound C-! to a keyboard macro that insert \"_\"$" (Given "^I have bound C-! to a keyboard macro that insert \"_\"$"
(lambda () (lambda ()
(fset 'mc-test-temp-kmacro "\C-q_") (fset 'mc-test-temp-kmacro "\C-q_")

View File

@ -28,8 +28,6 @@
(require 'cl-lib) (require 'cl-lib)
(require 'rect) (require 'rect)
(defvar mc--read-char)
(defface mc/cursor-face (defface mc/cursor-face
'((t (:inverse-video t))) '((t (:inverse-video t)))
"The face used for fake cursors" "The face used for fake cursors"
@ -52,11 +50,6 @@ rendered or shift text."
:type '(boolean) :type '(boolean)
:group 'multiple-cursors) :group 'multiple-cursors)
(defcustom mc--reset-read-variables '()
"A list of cache variable names to reset by multiple-cursors."
:type '(list symbol)
:group 'multiple-cursors)
(defface mc/region-face (defface mc/region-face
'((t :inherit region)) '((t :inherit region))
"The face used for fake regions" "The face used for fake regions"
@ -326,34 +319,35 @@ cursor with updated info."
;; Intercept some reading commands so you won't have to ;; Intercept some reading commands so you won't have to
;; answer them for every single cursor ;; answer them for every single cursor
(defvar multiple-cursors-mode nil) (defvar mc--input-function-cache nil)
(defun mc--reset-read-prompts () (defun mc--reset-read-prompts ()
(mapc (lambda (var) (set var nil)) (setq mc--input-function-cache nil))
mc--reset-read-variables))
(defmacro mc--cache-input-function (fn-name) (defmacro mc--cache-input-function (fn-name args-cache-key-fn)
"Advise FN-NAME to cache its value in a private variable. Cache "Advise FN-NAME to cache its value in a private variable. Cache
is to be used by mc/execute-command-for-all-fake-cursors and is to be used by mc/execute-command-for-all-fake-cursors and
caches will be reset by mc--reset-read-prompts." caches will be reset by mc--reset-read-prompts. ARGS-CACHE-KEY-FN
should transform FN-NAME's args to a unique cache-key so that
different calls to FN-NAME during a command can return multiple
values."
(let ((mc-name (intern (concat "mc--" (symbol-name fn-name))))) (let ((mc-name (intern (concat "mc--" (symbol-name fn-name)))))
`(progn `(progn
(defvar ,mc-name nil)
(defun ,mc-name (orig-fun &rest args) (defun ,mc-name (orig-fun &rest args)
(if (not multiple-cursors-mode) (if (not multiple-cursors-mode)
(apply orig-fun args) (apply orig-fun args)
(unless ,mc-name (let* ((cache-key (cons ,(symbol-name fn-name) (,args-cache-key-fn args)))
(setq ,mc-name (apply orig-fun args))) (cached-value (assoc cache-key mc--input-function-cache))
,mc-name)) (return-value (if cached-value (cdr cached-value) (apply orig-fun args))))
(advice-add ',fn-name :around #',mc-name) (unless cached-value
(add-to-list 'mc--reset-read-variables ',mc-name)))) (push (cons cache-key return-value) mc--input-function-cache))
return-value)))
(advice-add ',fn-name :around #',mc-name))))
(mc--cache-input-function read-char) (mc--cache-input-function read-char car)
(mc--cache-input-function read-quoted-char) (mc--cache-input-function read-quoted-char car)
(mc--cache-input-function register-read-with-preview) ; used by insert-register (mc--cache-input-function register-read-with-preview car) ; used by insert-register
(mc--cache-input-function read-char-from-minibuffer) ; used by zap-to-char (mc--cache-input-function read-char-from-minibuffer car) ; used by zap-to-char
(mc--reset-read-prompts)
(defun mc/fake-cursor-p (o) (defun mc/fake-cursor-p (o)
"Predicate to check if an overlay is a fake cursor" "Predicate to check if an overlay is a fake cursor"