Open honmaple opened 8 years ago
Yea, I haven't used evil-escape. So, I haven't run into this problem before. I'll take a look when I get a chance. Thanks for reporting.
For a quick fix, just to get you going, you could add evil-escape
to the evil-mc-incompatible-minor-modes
so that it gets disabled when there are multiple cursors. That way you can just use the regular escape key when there are multiple cursors and jj
otherwise.
I just add
(push 'evil-escape-mode evil-mc-incompatible-minor-modes)
to disable 'jj'. Though it's not resolve,use the regular escape key is also a way.Thank you
Confirming this, when using evil-escape
from insert-mode, the first letter of the escape sequence is erroneously added to all cursors except the currently active one.
I binded evil-escape to a "jk" key-chord, and the fake cursors are not stepping back one character if I use it with active evil-mc.
@gabesoft is there something like a before-cursor-deletion-hook
that would allow us to call evil-escape--delete-func
at each cursor before they are removed?
There is a hook that gets run when cursors are deleted. See evil-mc-after-cursors-deleted
but it's called only once after all cursors are deleted.
This might be a solution to exit from insert state with evil-escape.
(defun custom/evil-mc-evil-escape-fix ()
(when (evil-mc-has-cursors-p)
(evil-mc-pause-cursors)
(run-with-idle-timer 0 nil '(lambda () (evil-mc-resume-cursors)))))
(advice-add 'evil-escape-func :before 'custom/evil-mc-evil-escape-fix)
;; (advice-remove 'evil-escape-func 'custom/evil-mc-evil-escape-fix)
It pauses the cursors before exiting insert state, therefore nothing is written to the fake cursors.
An issue remains, about how to align the cursors.
The real cursor moves backwards one character (default vim behavior), but the paused cursors remains at their pre evil-escape positions.
[] = fake cursors | = real cursor, in insert state
Before:
ab[c]
ab[c]
ab|c
After, pressing fd
quickly.
ab[c]
ab[c]
a[b]c
I don't know how to move the fake cursors in elisp.
(evil-forward-char)
or (evil-backward-char)
only moves the real cursor,
when the cursors are paused or resumed.
The real cursor can be moved forward once to align them,
but the expected behavior is that all cursors are moved backwards when exiting insert state,
that's how it works when Esc
is pressed instead of fd
quickly.
This moves back the fake cursors, to keep them aligned.
(defun custom/evil-mc-evil-escape-fix ()
(when (evil-mc-has-cursors-p)
(evil-mc-pause-cursors)
(run-with-idle-timer
0 nil '(lambda ()
(evil-mc-resume-cursors)
(let ((evil-mc-command '((:name . evil-backward-char))))
(evil-mc-execute-for-all))))))
But there are two cases where they become unaligned:
If insert state is entered on the lines last character, by pressing a
(evil-append
).
abc|
def abc[]
abc[]
fd
results in:
ab[c]
def a[b]c
a[b]c
It seems like the fake cursors only looked like they were after the last character.
Update:
This issue isn't limited to this "solution".
And it's unrelated to evil-escape
.
Because it also happens when pressing Esc
.
An issue has been opened about this:
esc
unaligns the cursors, when real cursor on first column https://github.com/gabesoft/evil-mc/issues/124
End of Update
When the real cursor is on the first column.
|abc
def [a]bc
[a]bc
fd
moves back the fake cursors that are not on the first column.
[a]bc
def[ ]abc
[a]bc
The docstring for: evil-mc-execute-for-all
says:
Execute the current command, stored at ‘evil-mc-command’, for all fake cursors.
When there are multiple evil-mc cursors.
and h
(evil-backward-char
) is pressed.
Then evil-mc-execute-for-all
is called in the post-command-hook
.
And evil-mc-command
contains:
((nil) (:keys . [104]) (:keys-count) (:undo-list-pointer-post nil (nil rear-nonsticky nil 8 . 9) (
. -12) (8 . 13) 5 nil (nil rear-nonsticky nil 4 . 5) (
. -8) (4 . 9) 3 nil (1 . 4) (t . 0)) (:keys-post-raw . [104]) (:keys-post . [104]) (:last-input . 104) (:evil-state-end . normal) (:undo-list-pointer-pre nil (nil rear-nonsticky nil 8 . 9) (
. -12) (8 . 13) 5 nil (nil rear-nonsticky nil 4 . 5) (
. -8) (4 . 9) 3 nil (1 . 4) (t . 0)) (:evil-state-begin . normal) (:keys-pre-with-count nil evil-backward-char [104] nil) (:keys-pre . [104]) (:name . evil-backward-char))
And it works to move the back the fake cursors when evaluating: (newlines have been added to show each list on it's own line, for readability)
(let ((evil-mc-command '((nil)
(:keys . [104])
(:keys-count)
(:undo-list-pointer-post nil (nil rear-nonsticky nil 8 . 9) ( . -12) (8 . 13) 5 nil (nil rear-nonsticky nil 4 . 5) ( . -8) (4 . 9) 3 nil (1 . 4) (t . 0))
(:keys-post-raw . [104])
(:keys-post . [104])
(:last-input . 104)
(:evil-state-end . normal)
(:undo-list-pointer-pre nil (nil rear-nonsticky nil 8 . 9) ( . -12) (8 . 13) 5 nil (nil rear-nonsticky nil 4 . 5) ( . -8) (4 . 9) 3 nil (1 . 4) (t . 0))
(:evil-state-begin . normal)
(:keys-pre-with-count nil evil-backward-char [104] nil)
(:keys-pre . [104])
(:name . evil-backward-char))))
(evil-mc-execute-for-all))
But it seems to also work to reduce evil-mc-command
to:
(let ((evil-mc-command '((:name . evil-backward-char))))
(evil-mc-execute-for-all))
Are the other commands important?
This seems to work:
(setq evil-mc-custom-known-commands
'((custom/evil-mc-evil-escape-move-back-fake-cursors
(:default . evil-mc-execute-default-call))))
(defun custom/evil-mc-evil-escape-move-back-fake-cursors ()
"Move the fake cursors to the left once,
unless they already are at the beginning of the line."
(unless (bolp) (backward-char)))
(defun custom/evil-mc-evil-escape-fix ()
"Prevent the first evil-escape-key-sequence key (default: f),
from being typed at all of the fake cursors.
And move back the fake cursors when the real insert state cursor is at the end
of a line."
(when (evil-mc-has-cursors-p)
(evil-mc-pause-cursors)
(run-with-idle-timer
0 nil '(lambda ()
(evil-mc-resume-cursors)
(let ((evil-mc-command '((:name . custom/evil-mc-evil-escape-move-back-fake-cursors))))
(evil-mc-execute-for-all))))))
(advice-add 'evil-escape-func :before 'custom/evil-mc-evil-escape-fix)
;; (advice-remove 'evil-escape-func 'custom/evil-mc-evil-escape-fix)
It handles issue 1 of 2 above: https://github.com/gabesoft/evil-mc/issues/27#issuecomment-859996030
Pressing fd
(evil-escape
) with the real insert state cursor at the end of a line.
Moves back the fake cursors so that all cursors are aligned.
Issue 2 of 2 might not have an easy/desired fix. The expected vim behavior when exiting insert state to normal state is that the cursor moves back. This causes the evil-mc cursors to become unaligned, when the real or a fake cursor is at the beginning of a line.
I use evil-escape to quit insert-state,but I find a trouble with this.
I edit (insert)
when I press escape,it quit insert-state well.But I use 'jj' to quit insert-state.The content would look like this(normal-state)
How can I resolve this problem?
and I suggest use 'escape' instead of 'g r u' for evil-mc-undo-all-cursors. Sorry abot my English.Thank you.