Is there any way to have Emacs save your undo hist

2020-02-20 07:40发布

问题:

Is there any way to have EMACS save your undo history between sessions?

I'm aware of the savehist lib, the saveplace lib, the desktop lib, and the windows lib, these all provide some session control but none seem to save the undo history.

回答1:

Here's some code I wrote which seems to do the trick. It isn't bullet-proof, as in, it doesn't handle all the file handling intricacies that Emacs does (e.g. overriding where auto-save files are put, symlink handling, etc.). But, it seemed to do the trick for some simple text files I manipulated.

(defun save-undo-filename (orig-name)
  "given a filename return the file name in which to save the undo list"
  (concat (file-name-directory orig-name)
          "."
          (file-name-nondirectory orig-name)
          ".undo"))

(defun save-undo-list ()
  "Save the undo list to a file"
  (save-excursion
    (ignore-errors
      (let ((undo-to-save `(setq buffer-undo-list ',buffer-undo-list))
            (undo-file-name (save-undo-filename (buffer-file-name))))
        (find-file undo-file-name)
        (erase-buffer)
        (let (print-level
              print-length)
          (print undo-to-save (current-buffer)))
        (let ((write-file-hooks (remove 'save-undo-list write-file-hooks)))
          (save-buffer))
        (kill-buffer))))
  nil)

(defvar handling-undo-saving nil)

(defun load-undo-list ()
  "load the undo list if appropriate"
  (ignore-errors
    (when (and
           (not handling-undo-saving)
           (null buffer-undo-list)
           (file-exists-p (save-undo-filename (buffer-file-name))))
      (let* ((handling-undo-saving t)
             (undo-buffer-to-eval (find-file-noselect (save-undo-filename (buffer-file-name)))))
        (eval (read undo-buffer-to-eval))))))

(add-hook 'write-file-hooks 'save-undo-list)
(add-hook 'find-file-hook 'load-undo-list)


回答2:

From version 0.4 onwards, undo-tree supports persistent storage of undo-tree data between sessions "out of the box". (Note that there are significant bug-fixes related to this feature in more recent versions; the latest version at the time of writing is 0.6.3.)

Simply enable the undo-tree-auto-save-history customization option to automatically save and load undo history in undo-tree buffers. Or use the undo-tree-save/load-history commands to save and load undo history manually.

You need at least Emacs version 24.3 for this to work reliably, but with a recent enough Emacs it works very well.



回答3:

Add the following to your .emacs file :

(global-undo-tree-mode)
(setq undo-tree-auto-save-history t)
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))

Explanation

  • (global-undo-tree-mode) enables undo tree.

  • (setq undo-tree-auto-save-history t) enables auto save of undo history.

  • (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))) so that your project does not get littered with undo-history savefiles.



回答4:

desktop-save-mode does not save buffer-undo-list by default. You just have to tell him!

(add-to-list 'desktop-locals-to-save 'buffer-undo-list)


回答5:

Emacs Session appears to support this:

(add-to-list 'session-locals-include 'buffer-undo-list)


回答6:

I have managed to get the undo history working by using the information provided here: http://emacs.stackexchange.com/q/3725/2287

Instead of patching the original file desktop.el.gz I created an advice that temporarily overrides (buffer-local-variables) then I use it together with the function that gathers information about the buffer.

(defun +append-buffer-undo-list-to-buffer-local-variables-advice (orig-fn &rest args)
  "Override `buffer-local-variables' and call ORIG-FN with ARGS.
There is a bug in Emacs where the `buffer-undo-list' data is
missing from the output of `buffer-local-variables'. This
advice temporarily overrides the function and appends the
missing data."
  (let ((orig-buffer-local-variables-fn (symbol-function 'buffer-local-variables)))
    (cl-letf (((symbol-function 'buffer-local-variables)
               #'(lambda () (append (funcall orig-buffer-local-variables-fn)
                               `(,(cons 'buffer-undo-list buffer-undo-list))))))
      (apply orig-fn args))))

(advice-add #'desktop-buffer-info :around #'+append-buffer-undo-list-to-buffer-local-variables-advice)
(push 'buffer-undo-list desktop-locals-to-save)
(desktop-save-mode 1)

I hope this helps someone else.



标签: emacs