diff --git a/core/core-editor.el b/core/core-editor.el index 554e3b6b6..42d8ddde7 100644 --- a/core/core-editor.el +++ b/core/core-editor.el @@ -563,41 +563,6 @@ files, so we replace calls to `pp' with the much faster `prin1'." (setq so-long-predicate #'doom-buffer-has-long-lines-p)) -(use-package! undo-fu - :after-call doom-switch-buffer-hook after-find-file - :config - ;; Store more undo history to prevent loss of data - (setq undo-limit 400000 - undo-strong-limit 3000000 - undo-outer-limit 3000000) - - (global-set-key [remap undo] #'undo-fu-only-undo) - (global-set-key [remap redo] #'undo-fu-only-redo) - - (with-eval-after-load 'undo-tree - (global-undo-tree-mode -1))) - - -(use-package! undo-fu-session - :after undo-fu - :preface - (setq undo-fu-session-directory (concat doom-cache-dir "undo-fu-session/") - undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'")) - ;; HACK We avoid `:config' here because `use-package's `:after' complicates - ;; the load order of a package's `:config' block and makes it impossible - ;; for the user to override its settings with merely `after!' (or - ;; `eval-after-load'). See jwiegley/use-package#829. - (after! undo-fu-session - ;; HACK Use the faster zstd to compress undo files instead of gzip - (when (executable-find "zstd") - (defadvice! doom--undo-fu-session-use-zstd-a (filename) - :filter-return #'undo-fu-session--make-file-name - (if undo-fu-session-compression - (concat (file-name-sans-extension filename) ".zst") - filename))) - (global-undo-fu-session-mode +1))) - - (use-package! ws-butler ;; a less intrusive `delete-trailing-whitespaces' on save :after-call after-find-file diff --git a/core/packages.el b/core/packages.el index 2d3e6c9c9..3aae1cffb 100644 --- a/core/packages.el +++ b/core/packages.el @@ -27,8 +27,6 @@ ;; on a potato. :recipe (:host github :repo "hlissner/emacs-so-long") :pin "ed666b0716") -(package! undo-fu :pin "0c34b6747e") -(package! undo-fu-session :pin "b808ef0cdc") (package! ws-butler ;; Use my fork of ws-butler, which has a few choice improvements and ;; optimizations (the original has been abandoned). diff --git a/docs/modules.org b/docs/modules.org index d06998879..7ad429148 100644 --- a/docs/modules.org +++ b/docs/modules.org @@ -76,6 +76,7 @@ Modules that reconfigure or augment packages or features built into Emacs. + [[file:../modules/emacs/dired/README.org][dired]] =+ranger +icons= - TODO + electric - TODO + [[file:../modules/emacs/ibuffer/README.org][ibuffer]] =+icons= - TODO ++ [[file:../modules/emacs/undo/README.org][undo]] =+tree= - A smarter, more intuitive & persistent undo history + vc - TODO * :email diff --git a/init.example.el b/init.example.el index 5fdef3212..2ffe28979 100644 --- a/init.example.el +++ b/init.example.el @@ -66,6 +66,7 @@ dired ; making dired pretty [functional] electric ; smarter, keyword-based electric-indent ;;ibuffer ; interactive buffer management + undo ; persistent, smarter undo for your inevitable mistakes vc ; version-control and Emacs, sitting in a tree :term diff --git a/modules/emacs/undo/README.org b/modules/emacs/undo/README.org new file mode 100644 index 000000000..870498c7a --- /dev/null +++ b/modules/emacs/undo/README.org @@ -0,0 +1,54 @@ +#+TITLE: emacs/undo +#+DATE: April 13, 2020 +#+SINCE: v3.0.0 +#+STARTUP: inlineimages nofold + +* Table of Contents :TOC_3:noexport: +- [[#description][Description]] + - [[#maintainers][Maintainers]] + - [[#module-flags][Module Flags]] + - [[#plugins][Plugins]] + - [[#hacks][Hacks]] +- [[#prerequisites][Prerequisites]] +- [[#features][Features]] +- [[#configuration][Configuration]] +- [[#troubleshooting][Troubleshooting]] + +* Description +This module augments Emacs' built-in undo system to be more intuitive. + +** Maintainers +This module has no dedicated maintainers. + +** Module Flags ++ =+tree= Uses ~undo-tree~ instead of ~undo-fu~, which is a little less stable, + but offers branching undo history and a visualizer for navigating it. + +** Plugins ++ [[https://gitlab.com/ideasman42/emacs-undo-fu][undo-fu]] ++ [[https://gitlab.com/ideasman42/emacs-undo-fu-session][undo-fu-session]] ++ [[https://github.com/emacsmirror/undo-tree][undo-tree]] (=+tree=) + +** Hacks ++ Both undo-fu and undo-tree have been modified to use zstd to compress undo + history if it is available. ++ undo-tree only + + Text properties are stripped from undo history to shrink it. + + Undo-tree is too chatty about saving its history files. This has be + "silenced". i.e. It's visible in \*Messages\*, but won't appear in your + minibuffer. ++ unfo-fu only + + Doom defines =undo-fu-mode= to make it easier to add hooks/mode-local + keybinds. + +* Prerequisites +This module has no prereqisites. + +* TODO Features +# An in-depth list of features, how to use them, and their dependencies. + +* TODO Configuration +# How to configure this module, including common problems and how to address them. + +* TODO Troubleshooting +# Common issues and their solution, or places to look for help. diff --git a/modules/emacs/undo/config.el b/modules/emacs/undo/config.el new file mode 100644 index 000000000..87b2187d4 --- /dev/null +++ b/modules/emacs/undo/config.el @@ -0,0 +1,89 @@ +;;; emacs/undo/config.el -*- lexical-binding: t; -*- + +(use-package! undo-fu + :unless (featurep! +tree) + :after-call doom-switch-buffer after-find-file + :init + (after! undo-tree + (global-undo-tree-mode -1)) + :config + ;; Store more undo history to prevent loss of data + (setq undo-limit 400000 + undo-strong-limit 3000000 + undo-outer-limit 3000000) + + (define-minor-mode undo-fu-mode + "Enables `undo-fu' for the current session." + :keymap (let ((map (make-sparse-keymap))) + (define-key map [remap undo] #'undo-fu-only-undo) + (define-key map [remap redo] #'undo-fu-only-redo) + map) + :init-value t + :global t)) + + +(use-package! undo-fu-session + :unless (featurep! +tree) + :hook (undo-fu-mode . global-undo-fu-session-mode) + :preface + (setq undo-fu-session-directory (concat doom-cache-dir "undo-fu-session/") + undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'")) + + ;; HACK We avoid `:config' here because `use-package's `:after' complicates + ;; the load order of a package's `:config' block and makes it impossible + ;; for the user to override its settings with merely `after!' (or + ;; `eval-after-load'). See jwiegley/use-package#829. + (after! undo-fu-session + ;; HACK Use the faster zstd to compress undo files instead of gzip + (when (executable-find "zstd") + (defadvice! doom--undo-fu-session-use-zstd-a (filename) + :filter-return #'undo-fu-session--make-file-name + (if undo-fu-session-compression + (concat (file-name-sans-extension filename) ".zst") + filename))))) + + +(use-package! undo-tree + :when (featurep! +tree) + ;; Branching & persistent undo + :after-call doom-switch-buffer-hook after-find-file + :config + (setq undo-tree-visualizer-diff t + undo-tree-auto-save-history t + undo-tree-enable-undo-in-region t + ;; Increase undo-limits by a factor of ten to avoid emacs prematurely + ;; truncating the undo history and corrupting the tree. See + ;; https://github.com/syl20bnr/spacemacs/issues/12110 + undo-limit 800000 + undo-strong-limit 12000000 + undo-outer-limit 120000000 + undo-tree-history-directory-alist + `(("." . ,(concat doom-cache-dir "undo-tree-hist/")))) + + ;; Compress undo-tree history files with zstd, if available. File size isn't + ;; the (only) concern here: the file IO barrier is slow for Emacs to cross; + ;; reading a tiny file and piping it in-memory through zstd is *slightly* + ;; faster than Emacs reading the entire undo-tree file from the get go (on + ;; SSDs). Whether or not that's true in practice, we still enjoy zstd's ~80% + ;; file savings (these files add up over time and zstd is so incredibly fast). + (when (executable-find "zstd") + (defadvice! doom--undo-tree-make-history-save-file-name-a (file) + :filter-return #'undo-tree-make-history-save-file-name + (concat file ".zst"))) + + ;; Strip text properties from undo-tree data to stave off bloat. File size + ;; isn't the concern here; undo cache files bloat easily, which can cause + ;; freezing, crashes, GC-induced stuttering or delays when opening files. + (defadvice! doom--undo-tree-strip-text-properties-a (&rest _) + :before #'undo-list-transfer-to-tree + (dolist (item buffer-undo-list) + (and (consp item) + (stringp (car item)) + (setcar item (substring-no-properties (car item)))))) + + ;; Undo-tree is too chatty about saving its history files. This doesn't + ;; totally suppress it logging to *Messages*, it only stops it from appearing + ;; in the echo-area. + (advice-add #'undo-tree-save-history :around #'doom-shut-up-a) + + (global-undo-tree-mode +1)) diff --git a/modules/emacs/undo/packages.el b/modules/emacs/undo/packages.el new file mode 100644 index 000000000..b173386a0 --- /dev/null +++ b/modules/emacs/undo/packages.el @@ -0,0 +1,7 @@ +;; -*- no-byte-compile: t; -*- +;;; emacs/undo/packages.el + +(if (not (featurep! +tree)) + (package! undo-tree :pin "5b6df03781") + (package! undo-fu :pin "0c34b6747e") + (package! undo-fu-session :pin "b808ef0cdc"))