Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stored registers are removed on multi cursor creation #83

Open
duianto opened this issue Oct 23, 2018 · 12 comments
Open

Stored registers are removed on multi cursor creation #83

duianto opened this issue Oct 23, 2018 · 12 comments

Comments

@duianto
Copy link
Contributor

duianto commented Oct 23, 2018

Observed behavior

Stored registers are removed when multiple cursors are created.

Expected behavior

That stored registers remained after cursor creation.

Steps to reproduce

  • Start Emacs
  • Open the scratch buffer
  • Type: abc
  • Store abc in register a: "ayiw
  • Look at the registers: :reg RET, there an entry for:
a          abc
  • Switch back to the scratch buffer: C-w w
  • Create a second cursor: grh
  • Look at the registers again, the entry for register a is gone.

Notes

Any registers that were stored while multiple cursors were active. Remain after pausing, resuming or undoing the cursors.

System information

Evil-mc Version: 0.0.4 (20180921.1727)
Evil version evil-git-9865e7731
GNU Emacs 26.1 (build 1, x86_64-w64-mingw32) of 2018-05-30
Windows 10 Version 1803
@dchrzanowski
Copy link

Same spotted on Linux Emacs 26.1.

@dchrzanowski
Copy link

dchrzanowski commented Feb 7, 2019

If someone has a good elisp fu, then perhaps an easy solution would be to make a copy of all text registers before the multiple cursors are made. Then when the cursors are killed the registers are restored...food for thought.

EDIT:
For the time being I am removing register-alist here and then byte-recompiling the file. Works just fine, it's not that I need named registers while multiple cursors are active anyway.

@duianto
Copy link
Contributor Author

duianto commented Jul 16, 2019

Update

No, the "fix" below only works when creating additional cursors with (evil-mc-make-cursor-here).
The named registers are still removed if one creates a cursor with for example:
(evil-mc-make-and-goto-next-match).

A to limited solution

I might have found a possible solution that doesn't remove the named registers.
By wrapping the call to (evil-mc-cursors-before) in a temporary register-alist variable.

(defun evil-mc-run-cursors-before ()
  "Runs `evil-mc-cursors-before' if there are no cursors created yet."
  (when (not (evil-mc-has-cursors-p))
    (let (register-alist)
      (evil-mc-cursors-before))))

The optimal solution would be to be able to paste from a register at every cursor, but with this "fix" it only pastes from a register at the main cursor.

But the major issue of not removing the named registers is probably enough for now.

@sooqua
Copy link

sooqua commented Aug 20, 2019

If someone has a good elisp fu, then perhaps an easy solution would be to make a copy of all text registers before the multiple cursors are made. Then when the cursors are killed the registers are restored...food for thought.

EDIT:
For the time being I am removing register-alist here and then byte-recompiling the file. Works just fine, it's not that I need named registers while multiple cursors are active anyway.

(setq ~+multiple-cursors--evil-mc-registers-copy '())

(defun ~+multiple-cursors*evil-mc-run-cursors-before (&rest r)
  (cl-loop for reg from 97 to 122 do
           (setq ~+multiple-cursors--evil-mc-registers-copy (nconc ~+multiple-cursors--evil-mc-registers-copy (cons (get-register reg) nil)))))

(defun ~+multiple-cursors*evil-mc-run-cursors-after (&rest r)
  (cl-loop for reg in ~+multiple-cursors--evil-mc-registers-copy
           for i from 97 do
           (when reg
             (set-register i reg)))
  (setq ~+multiple-cursors--evil-mc-registers-copy nil))

(advice-add #'evil-mc-run-cursors-before :before #'~+multiple-cursors*evil-mc-run-cursors-before)
(advice-add #'evil-mc-run-cursors-after :after #'~+multiple-cursors*evil-mc-run-cursors-after)

@duianto
Copy link
Contributor Author

duianto commented Aug 20, 2019

@sooqua
That only seems to work with:
evil-mc-make-and-goto-next-match and evil-mc-make-and-goto-prev-match

It doesn't work with:
evil-mc-make-cursor-here or evil-mc-make-all-cursors

And there might be an off by one issue, because while I was storing text in the a, b and c registers and creating evil-mc cursors, then it would sometimes show that the same text was stored in the } and | registers.

@duianto
Copy link
Contributor Author

duianto commented Aug 20, 2019

The author of this Spacemacs issue:
Problem persisting registers syl20bnr/spacemacs#12606

Says:

On exiting spacemacs the register list seems to persist alphabetic and numeric registers differently, as regards the buffer name.

In the - rather longer than is probably necessary - line below from .emacs.desktop the numeric registers seems to be stored along with the full path name of the buffer. Whereas a lot of registers seem to refer only to the file name.

That might be why the alphabetic registers are erased when evil-mc cursors are created.

@sooqua
Copy link

sooqua commented Aug 20, 2019

Quick fix:

(defun ~+multiple-cursors*evil-mc-write-cursor-state (state)
  "Write the state of the real cursor with values from STATE."
  (let ((names (evil-mc-get-cursor-variables)))
    (dolist (name names)
      (when (boundp name)
        (let ((p (evil-mc-get-cursor-property state name)))
          (when (not (and (string= name "register-alist") (null p)))
            (set name (evil-mc-get-cursor-property state name))))))))
(advice-add #'evil-mc-write-cursor-state :override #'~+multiple-cursors*evil-mc-write-cursor-state)

@duianto
Copy link
Contributor Author

duianto commented Aug 21, 2019

That seems to work for all evil-mc cursor creation commands 👍

It seems to also keep the 0 register from being deleted.
There's an open issue about it:
Nils out evil-was-yanked-without-register #70

@duianto
Copy link
Contributor Author

duianto commented Aug 29, 2019

Could that solution or something similar be implemented to also prevent the position markers from being removed when evil-mc cursors are created?

Position markers (I might not be the correct name), can be store with ma, mb, etc.
And jumped to with:

  • `a (backtick and a) to jump to the character where the mark was set.
  • 'a (single quote and a) to jump to the beginning of that markers line

@sooqua
Copy link

sooqua commented Aug 30, 2019

Yeah. I'm not sure why (null p) check doesn't work with evil-markers-alist, it seems like it doesn't write null in there but something breaks anyway.

(defun ~+multiple-cursors-evil-mc-write-cursor-state-a (state)
  "Write the state of the real cursor with values from STATE."
  (let ((names (evil-mc-get-cursor-variables)))
    (dolist (name names)
      (when (boundp name)
        (let ((p (evil-mc-get-cursor-property state name)))
          (when (not
                 (or
                  (eq name 'register-alist)
                  (eq name 'evil-markers-alist)))
            (set name p)))))))
(advice-add #'evil-mc-write-cursor-state :override #'~+multiple-cursors-evil-mc-write-cursor-state-a)

@sooqua
Copy link

sooqua commented Aug 30, 2019

You could probably just remove register-alist and evil-markers-alist from evil-mc-cursor-variables at this point instead of overriding evil-mc-write-cursor-state, for some negligible performance benefit, but I don't know what these variables are used for anyway.

(when (featurep! :editor multiple-cursors)
  (after! evil-mc
    (setq evil-mc-cursor-variables (mapcar
                                    (lambda (s)
                                      (remove 'register-alist (remove 'evil-markers-alist s)))
                                    evil-mc-cursor-variables))))

I'm using Doom Emacs, you will have to modify everything before and including after! to run this code only after evil-mc is loaded.

@duianto
Copy link
Contributor Author

duianto commented Aug 31, 2019

This seems to work to prevent the removal of:

  • alphabetic registers
  • position markers
  • the 0 register
(with-eval-after-load 'evil-mc
  (setq evil-mc-cursor-variables
        (mapcar
          (lambda (s)
            (remove 'register-alist
                    (remove 'evil-markers-alist
                            (remove evil-was-yanked-without-register s))))
          evil-mc-cursor-variables)))

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants