Is there emacs capability for visiting last edits?
Asked Answered
S

5

22

In the JetBrains products, there's a very handy key binding that lets you visit all the spots you made an edit. Hit the key once to go to the last edit (file and location), and keep hitting the key to go back to earlier edits. It's typically when editing that you want to be editing the same places over and over again, and if one has many buffers open, many of which are not edited, this is even more useful.

Emacs has a mark ring, but that's not quite the same thing.

On a related note, is there functionality in magit, the emacs git add-on, to jump to edits?

Spontoon answered 9/5, 2013 at 19:29 Comment(0)
F
17

There is GotoLastChange which allows you to travel along the chain of undo locations. You can assign it to a key:

(global-set-key "\C-x\C-\\" 'goto-last-change)

Fahy answered 9/5, 2013 at 20:4 Comment(5)
This is awesome! BUT, it doesn't jump between open buffers like the JetBrains command. Also, this can be installed using M-x package-list-packages.Spontoon
If somebody can do the lisp on making a function, work for all buffers, that will be the winner...Otherwise, this is a great solution within a file.Spontoon
Each buffer has a separate undo list. For what you request you would need to gather and merge the undo lists of all of the buffers. That should be doable, but I'm not sure how user friendly it would be. An alternative, while waiting for someone to implement that, is to use C-x C-SPC (or bind it to something easier) to cycle through the global-mark-ring.Irrespective
Ignore previous comment. Each buffer has a separate undo list. For what you request a function would need to gather and merge the undo lists of all of the buffers. Unfortunately, there is no timestamp on an undo-list entry, so there is no way to merge them by time. An alternative is to use C-x C-SPC (or bind it to something easier) to cycle through the global-mark-ring.Irrespective
I am having Invalid undo entry: undo-tree-canary errorSelfcontent
C
6

There is GotoChg which allows you to travel back and forth the chain of undo locations. Sample init code snippet:

(require 'goto-chg)
(global-set-key [(control ?.)] 'goto-last-change)
(global-set-key [(control ?,)] 'goto-last-change-reverse)

(Just like the other alternatives, GotoLastChange and session.el, it can not jump between buffers)

Compunction answered 11/12, 2013 at 3:28 Comment(1)
I set it opposite (global-set-key (kbd "C-,") 'goto-last-change): left to go back, right to go forward (in goto history). Thanks for making me realize C-. and C-, are open.Consequent
P
4

Global, multi-buffer goto-last-change:

;;; record two different file's last change. cycle them
(defvar feng-last-change-pos1 nil)
(defvar feng-last-change-pos2 nil)

(defun feng-swap-last-changes ()
  (when feng-last-change-pos2
    (let ((tmp feng-last-change-pos2))
      (setf feng-last-change-pos2 feng-last-change-pos1
            feng-last-change-pos1 tmp))))

(defun feng-goto-last-change ()
  (interactive)
  (when feng-last-change-pos1
    (let* ((buffer (find-file-noselect (car feng-last-change-pos1)))
           (win (get-buffer-window buffer)))
      (if win
          (select-window win)
        (switch-to-buffer-other-window buffer))
      (goto-char (cdr feng-last-change-pos1))
      (feng-swap-last-changes))))

(defun feng-buffer-change-hook (beg end len)
  (let ((bfn (buffer-file-name))
        (file (car feng-last-change-pos1)))
    (when bfn
      (if (or (not file) (equal bfn file)) ;; change the same file
          (setq feng-last-change-pos1 (cons bfn end))
        (progn (setq feng-last-change-pos2 (cons bfn end))
               (feng-swap-last-changes))))))

(add-hook 'after-change-functions 'feng-buffer-change-hook)
;;; just quick to reach
(global-set-key (kbd "M-`") 'feng-goto-last-change)

from http://shenfeng.me/emacs-last-edit-location.html

This implementation works for the last two changes in any buffers. I imagine extending the length of its change-list beyond two wouldn't be too hard.

Puiia answered 26/12, 2016 at 20:23 Comment(0)
C
3

There is the command session-jump-to-last-change in session.el which allows you to travel along the chain of undo locations. Init code snippet:

(require 'session)
(setq session-jump-undo-threshold 80)  ; default was 240
(global-set-key [(control ?.)] 'session-jump-to-last-change)

(Just like the other alternatives, GotoLastChange and GotoChg, it can not jump between buffers)

Compunction answered 11/12, 2013 at 3:35 Comment(0)
B
3

Single buffer

Tracking edits and go back to where they occurred depends on the type of them.
If your edit added something, you can go back to it with a rather simple:

(goto-char (car(cadr  buffer-undo-list)))

If you deleted, something you can go back to it with:

(goto-char (abs (cdr(cadr  buffer-undo-list))))

and you might like displaying what you deleted in the minibuffer:

(progn
 (goto-char (abs (cdr(cadr  buffer-undo-list))))
 (message "DEL->: %s"  (substring-no-properties (car(cadr  buffer-undo-list)))))

Summing up:

(defun last-edit ()
  "Go back to last add/delete edit"
  (interactive)
  (let* ((ubuf (cadr buffer-undo-list))
     (beg (car ubuf))
     (end (cdr ubuf)))
    (cond
     ((integerp beg) (goto-char beg))
     ((stringp beg) (goto-char (abs end))
      (message "DEL-> %s" (substring-no-properties beg)))
     (t (message "No add/delete edit occurred")))))

Read C-h v buffer-undo-list and you might integrate this for less subtle edits, such as setting text properties (assuming you really need it).

Multi-buffer

I used the buffer-undo-list variable to carry out the tasks. There is a distinct list for each buffer and, as far as I know, there is no global undo-list. Most likely you know in which buffer you typed something and you want Emacs to bring to the edited spot. There is in this case a single global-mark-ring variable recording the sequence of buffers that you have been.

Successive uses of the command Meta-Xpop-global-mark, or simply Ctrl-X Ctrl-Space, will bring you to earlier visited buffers (and mark positions). Once you get to the target buffer, you can trigger Meta-Xlast-edit (or the bound keys).

Bullroarer answered 18/8, 2014 at 19:9 Comment(1)
I am having Wrong type argument: listp, undo-tree-canary error message for the last-edit() functionSelfcontent

© 2022 - 2024 — McMap. All rights reserved.