6

This a follow up to my earlier question Why does multiple-cursors use the same char for all cursors with iy-go-to-char, but not with zap-up-to-char?.

As I describe in that question, for some commands that prompt for a character in the mini-buffer multiple-cursors will repeat the prompting for each cursor, but for others it will happily prompt only once and use that character for all cursors. In particular, for iy-go-to-char multiple-cursors prompts only once, but for zap-up-to-char it prompts per cursor.

Now, oddly enough for zap-to-char the prompting also happens only once, not once per cursor! My question is why does this happen? As far as I can tell the difference is caused by their different calls to interactive:

  • zap-up-to-char uses the seemingly sensible (interactive "p\ncZap up to char: "),

  • zap-to-char instead has:

    (interactive (list (prefix-numeric-value current-prefix-arg)
                       (read-char "Zap to char: " t)))
    

That is indeed the cause because taking the implementation of zap-up-to-char from misc.el and replacing the interactive call with one similar to the one zap-to-char uses produces a version of zap-up-to-char that, when used with multiple-cursors, only prompts once (not once per cursor):

(defun mc-friendly/zap-up-to-char (arg char)
  (interactive (list (prefix-numeric-value current-prefix-arg)
                     (read-char "Zap up to char: " t)))
  (let ((direction (if (>= arg 0) 1 -1)))
    (kill-region (point)
                 (progn
                   (forward-char direction)
                   (unwind-protect
                       (search-forward (char-to-string char) nil nil arg)
                     (backward-char direction))
           (point)))))

Why does changing the call to interactive have that effect?

Omar
  • 4,732
  • 1
  • 17
  • 32

1 Answers1

6

This is because read-char is advised to have special behaviour. When running in 'multiple-cursors-mode' it caches the character read the first time. If this cache is full then it does not ask for a character again.

Whatever function is called by "c" in the interactive description is not advised in this way.

The implementation is incredibly hackish: for example if you have multiple calls to read-char in the same interactive specification you get nonsense. unfortunately I don't see how to improve the situation.

jyp
  • 128
  • 7
  • 5
    As far as I can tell, the only real solution to this problem is to remove the `read-char` special handling and have everything behave worse, but the same. I'd be happy to see alternative solutions. – Magnar Dec 16 '15 at 08:51
  • 1
    "c" in the `interactive` call seems to directly call the C function `Fread_char` (that's the C primitive underlying the Emacs Lisp function `read-char`). – Omar Dec 18 '15 at 21:17