Updating Doom Emacs.

This commit is contained in:
Derek Taylor
2020-06-19 22:43:40 -05:00
parent 0f664d532a
commit a5c86c514a
453 changed files with 13527 additions and 12455 deletions

View File

@@ -12,8 +12,8 @@ successfully sets indent_style/indent_size.")
(defvar-local doom-large-file-p nil)
(put 'doom-large-file-p 'permanent-local t)
(defvar doom-large-file-size-alist '((t . 1.0))
"An alist mapping major mode to filesize thresholds.
(defvar doom-large-file-size-alist '(("." . 1.0))
"An alist mapping regexps (like `auto-mode-alist') to filesize thresholds.
If a file is opened and discovered to be larger than the threshold, Doom
performs emergency optimizations to prevent Emacs from hanging, crashing or
@@ -42,15 +42,17 @@ possible."
(if (setq doom-large-file-p
(and buffer-file-name
(not doom-large-file-p)
(file-readable-p buffer-file-name)
(> (nth 7 (file-attributes buffer-file-name))
(* 1024 1024
(cdr (or (assq major-mode doom-large-file-size-alist)
(assq 't doom-large-file-size-alist)))))))
(file-exists-p buffer-file-name)
(ignore-errors
(> (nth 7 (file-attributes buffer-file-name))
(* 1024 1024
(assoc-default buffer-file-name doom-large-file-size-alist
#'string-match-p))))))
(prog1 (apply orig-fn args)
(if (memq major-mode doom-large-file-excluded-modes)
(setq doom-large-file-p nil)
(so-long-minor-mode +1)
(when (fboundp 'so-long-minor-mode) ; in case the user disabled it
(so-long-minor-mode +1))
(message "Large file detected! Cutting a few corners to improve performance...")))
(apply orig-fn args)))
@@ -77,68 +79,94 @@ possible."
t))))))
;; Don't autosave files or create lock/history/backup files. We don't want
;; copies of potentially sensitive material floating around, and we'll rely on
;; git and our own good fortune instead. Fingers crossed!
;; copies of potentially sensitive material floating around or polluting our
;; filesystem. We rely on git and our own good fortune instead. Fingers crossed!
(setq auto-save-default nil
create-lockfiles nil
make-backup-files nil
;; But have a place to store them in case we do use them...
auto-save-list-file-name (concat doom-cache-dir "autosave")
backup-directory-alist `(("." . ,(concat doom-cache-dir "backup/"))))
;; auto-save-list-file-name (concat doom-cache-dir "autosave")
auto-save-list-file-prefix (concat doom-cache-dir "autosave/")
auto-save-file-name-transforms `((".*" ,auto-save-list-file-prefix t))
backup-directory-alist `((".*" . ,(concat doom-cache-dir "backup/"))))
(after! tramp
(add-to-list 'backup-directory-alist (cons tramp-file-name-regexp nil)))
(add-hook! 'after-save-hook
(defun doom-guess-mode-h ()
"Guess mode when saving a file in `fundamental-mode'."
(and (eq major-mode 'fundamental-mode)
(buffer-file-name (buffer-base-buffer))
(eq (current-buffer) (window-buffer (selected-window))) ; only visible buffers
(set-auto-mode))))
(when (eq major-mode 'fundamental-mode)
(let ((buffer (or (buffer-base-buffer) (current-buffer))))
(and (buffer-file-name buffer)
(eq buffer (window-buffer (selected-window))) ; only visible buffers
(set-auto-mode))))))
;;
;;; Formatting
;; Indentation
(setq-default tab-width 4
tab-always-indent t
indent-tabs-mode nil
fill-column 80)
;; Favor spaces over tabs. Pls dun h8, but I think spaces (and 4 of them) is a
;; more consistent default than 8-space tabs. It can be changed on a per-mode
;; basis anyway (and is, where tabs are the canonical style, like go-mode).
(setq-default indent-tabs-mode nil
tab-width 4)
;; Word wrapping
(setq-default word-wrap t
truncate-lines t
truncate-partial-width-windows nil)
;; Make `tabify' and `untabify' only affect indentation. Not tabs/spaces in the
;; middle of a line.
(setq tabify-regexp "^\t* [ \t]+")
(setq sentence-end-double-space nil
delete-trailing-lines nil
require-final-newline t
tabify-regexp "^\t* [ \t]+") ; for :retab
;; An archaic default in the age of widescreen 4k displays? I disagree. We still
;; frequently split our terminals and editor frames, or have them side-by-side,
;; using up more of that newly available horizontal real-estate.
(setq-default fill-column 80)
;; Favor hard-wrapping in text modes
(add-hook 'text-mode-hook #'auto-fill-mode)
;; Continue wrapped words at whitespace, rather than in the middle of a word.
(setq-default word-wrap t)
;; ...but don't do any wrapping by default. It's expensive. Enable
;; `visual-line-mode' if you want soft line-wrapping. `auto-fill-mode' for hard
;; line-wrapping.
(setq-default truncate-lines t)
;; If enabled (and `truncate-lines' was disabled), soft wrapping no longer
;; occurs when that window is less than `truncate-partial-width-windows'
;; characters wide. We don't need this, and it's extra work for Emacs otherwise,
;; so off it goes.
(setq truncate-partial-width-windows nil)
;; This was a widespread practice in the days of typewriters. I actually prefer
;; it when writing prose with monospace fonts, but it is obsolete otherwise.
(setq sentence-end-double-space nil)
;; The POSIX standard defines a line is "a sequence of zero or more non-newline
;; characters followed by a terminating newline", so files should end in a
;; newline. Windows doesn't respect this (because it's Windows), but we should,
;; since programmers' tools tend to be POSIX compliant.
(setq require-final-newline t)
;; Default to soft line-wrapping in text modes. It is more sensibile for text
;; modes, even if hard wrapping is more performant.
(add-hook 'text-mode-hook #'visual-line-mode)
;;
;;; Clipboard / kill-ring
;; Eliminate duplicates in the kill ring. That is, if you kill the same thing
;; twice, you won't have to use M-y twice to get past it to older entries in the
;; kill ring.
;; Cull duplicates in the kill ring to reduce bloat and make the kill ring
;; easier to peruse (with `counsel-yank-pop' or `helm-show-kill-ring'.
(setq kill-do-not-save-duplicates t)
;;
;; Allow UTF or composed text from the clipboard, even in the terminal or on
;; non-X systems (like Windows or macOS), where only `STRING' is used.
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
;; Save clipboard contents into kill-ring before replacing them
(setq save-interprogram-paste-before-kill t)
;; Fixes the clipboard in tty Emacs by piping clipboard I/O through xclip, xsel,
;; pb{copy,paste}, wl-copy, termux-clipboard-get, or getclip (cygwin).
(add-hook! 'tty-setup-hook
(defun doom-init-clipboard-in-tty-emacs-h ()
(and (not (getenv "SSH_CONNECTION"))
(require 'xclip nil t)
(xclip-mode +1))))
;; pb{copy,paste}, wl-copy, termux-clipboard-get, or getclip (cygwin); depending
;; on what is available.
(unless IS-WINDOWS
(add-hook! 'tty-setup-hook
(defun doom-init-clipboard-in-tty-emacs-h ()
(and (require 'clipetty nil t)
(global-clipetty-mode +1)))))
;;
@@ -146,6 +174,8 @@ possible."
(push '("/LICENSE\\'" . text-mode) auto-mode-alist)
(push '("\\.log\\'" . text-mode) auto-mode-alist)
(push '("rc\\'" . conf-mode) auto-mode-alist)
(push '("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode) auto-mode-alist)
;;
@@ -164,13 +194,13 @@ possible."
;; Only prompts for confirmation when buffer is unsaved.
revert-without-query (list "."))
;; Instead of using `auto-revert-mode' or `global-auto-revert-mode', we employ
;; lazy auto reverting on `focus-in-hook' and `doom-switch-buffer-hook'.
;; Instead of `auto-revert-mode' or `global-auto-revert-mode', we lazily auto
;; revert; when we save a file or switch buffers/windows (or focus on Emacs).
;;
;; This is because autorevert abuses the heck out of inotify handles which can
;; grind Emacs to a halt if you do expensive IO (outside of Emacs) on the
;; files you have open (like compression). We only really need to revert
;; changes when we switch to a buffer or when we focus the Emacs frame.
;; Autorevert normally abuses the heck out of inotify handles which can grind
;; Emacs to a halt if you do expensive IO (outside of Emacs) on the files you
;; have open (like compression). The only alternative is aggressive polling,
;; which is unreliable and expensive with a lot of buffers open.
(defun doom-auto-revert-buffer-h ()
"Auto revert current buffer, if necessary."
(unless (or auto-revert-mode (active-minibuffer-window))
@@ -186,7 +216,7 @@ possible."
(use-package! recentf
;; Keep track of recently opened files
:defer-incrementally easymenu tree-widget timer
:after-call after-find-file
:hook (doom-first-file . recentf-mode)
:commands recentf-open-files
:config
(defun doom--recent-file-truename (file)
@@ -194,9 +224,11 @@ possible."
(not (file-remote-p file)))
(file-truename file)
file))
(setq recentf-filename-handlers '(doom--recent-file-truename abbreviate-file-name))
(setq recentf-save-file (concat doom-cache-dir "recentf")
(setq recentf-filename-handlers
'(substring-no-properties ; strip out lingering text properties
doom--recent-file-truename ; resolve symlinks of local files
abbreviate-file-name) ; replace $HOME with ~
recentf-save-file (concat doom-cache-dir "recentf")
recentf-auto-cleanup 'never
recentf-max-menu-items 0
recentf-max-saved-items 200)
@@ -214,22 +246,20 @@ possible."
"Add dired directory to recentf file list."
(recentf-add-file default-directory)))
(when doom-interactive-mode
(add-hook 'kill-emacs-hook #'recentf-cleanup)
(quiet! (recentf-mode +1))))
(add-hook 'kill-emacs-hook #'recentf-cleanup)
(advice-add #'recentf-load-list :around #'doom-shut-up-a))
(use-package! savehist
;; persist variables across sessions
:defer-incrementally custom
:after-call post-command-hook
:hook (doom-first-input . savehist-mode)
:init
(setq savehist-file (concat doom-cache-dir "savehist"))
:config
(setq savehist-file (concat doom-cache-dir "savehist")
savehist-save-minibuffer-history t
(setq savehist-save-minibuffer-history t
savehist-autosave-interval nil ; save on kill only
savehist-additional-variables '(kill-ring search-ring regexp-search-ring))
(savehist-mode +1)
(add-hook! 'kill-emacs-hook
(defun doom-unpropertize-kill-ring-h ()
"Remove text properties from `kill-ring' for a smaller savehist file."
@@ -241,31 +271,33 @@ possible."
(use-package! saveplace
;; persistent point location in buffers
:after-call after-find-file dired-initial-position-hook
:config
:hook (doom-first-file . save-place-mode)
:init
(setq save-place-file (concat doom-cache-dir "saveplace")
save-place-limit 100)
:config
(defadvice! doom--recenter-on-load-saveplace-a (&rest _)
"Recenter on cursor when loading a saved place."
:after-while #'save-place-find-file-hook
(if buffer-file-name (ignore-errors (recenter))))
(defadvice! doom--inhibit-saveplace-in-long-files-a (orig-fn &rest args)
:around #'save-place-to-alist
(unless doom-large-file-p
(apply orig-fn args)))
(defadvice! doom--dont-prettify-saveplace-cache-a (orig-fn)
"`save-place-alist-to-file' uses `pp' to prettify the contents of its cache.
`pp' can be expensive for longer lists, and there's no reason to prettify cache
files, so we replace calls to `pp' with the much faster `prin1'."
:around #'save-place-alist-to-file
(cl-letf (((symbol-function #'pp)
(symbol-function #'prin1)))
(funcall orig-fn)))
(save-place-mode +1))
(letf! ((#'pp #'prin1)) (funcall orig-fn))))
(use-package! server
:when (display-graphic-p)
:after-call pre-command-hook after-find-file focus-out-hook
:defer 1
:init
(when-let (name (getenv "EMACS_SERVER_NAME"))
(setq server-name name))
@@ -278,7 +310,8 @@ files, so we replace calls to `pp' with the much faster `prin1'."
;;; Packages
(use-package! better-jumper
:after-call pre-command-hook
:hook (doom-first-input . better-jumper-mode)
:hook (better-jumper-post-jump . recenter)
:preface
;; REVIEW Suppress byte-compiler warning spawning a *Compile-Log* buffer at
;; startup. This can be removed once gilbertw1/better-jumper#2 is merged.
@@ -288,17 +321,14 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(global-set-key [remap evil-jump-backward] #'better-jumper-jump-backward)
(global-set-key [remap xref-pop-marker-stack] #'better-jumper-jump-backward)
:config
(better-jumper-mode +1)
(add-hook 'better-jumper-post-jump-hook #'recenter)
(defadvice! doom-set-jump-a (orig-fn &rest args)
(defun doom-set-jump-a (orig-fn &rest args)
"Set a jump point and ensure ORIG-FN doesn't set any new jump points."
(better-jumper-set-jump (if (markerp (car args)) (car args)))
(let ((evil--jumps-jumping t)
(better-jumper--jumping t))
(apply orig-fn args)))
(defadvice! doom-set-jump-maybe-a (orig-fn &rest args)
(defun doom-set-jump-maybe-a (orig-fn &rest args)
"Set a jump point if ORIG-FN returns non-nil."
(let ((origin (point-marker))
(result
@@ -329,20 +359,19 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(use-package! dtrt-indent
;; Automatic detection of indent settings
:when doom-interactive-mode
:defer t
:init
(add-hook! '(change-major-mode-after-body-hook read-only-mode-hook)
(defun doom-detect-indentation-h ()
(unless (or (not after-init-time)
doom-inhibit-indent-detection
doom-large-file-p
(memq major-mode doom-detect-indentation-excluded-modes)
(member (substring (buffer-name) 0 1) '(" " "*")))
;; Don't display messages in the echo area, but still log them
(let ((inhibit-message (not doom-debug-mode)))
(dtrt-indent-mode +1)))))
:when doom-interactive-p
:hook ((change-major-mode-after-body read-only-mode) . doom-detect-indentation-h)
:config
(defun doom-detect-indentation-h ()
(unless (or (not after-init-time)
doom-inhibit-indent-detection
doom-large-file-p
(memq major-mode doom-detect-indentation-excluded-modes)
(member (substring (buffer-name) 0 1) '(" " "*")))
;; Don't display messages in the echo area, but still log them
(let ((inhibit-message (not doom-debug-p)))
(dtrt-indent-mode +1))))
;; Enable dtrt-indent even in smie modes so that it can update `tab-width',
;; `standard-indent' and `evil-shift-width' there as well.
(setq dtrt-indent-run-after-smie t)
@@ -358,18 +387,14 @@ files, so we replace calls to `pp' with the much faster `prin1'."
`nim-mode'. This prevents them from leaving Emacs in a broken state."
:around #'dtrt-indent-mode
(let ((dtrt-indent-run-after-smie dtrt-indent-run-after-smie))
(cl-letf* ((old-smie-config-guess (symbol-function 'smie-config-guess))
(old-smie-config--guess (symbol-function 'symbol-config--guess))
((symbol-function 'symbol-config--guess)
(lambda (beg end)
(funcall old-smie-config--guess beg (min end 10000))))
((symbol-function 'smie-config-guess)
(lambda ()
(condition-case e (funcall old-smie-config-guess)
(error (setq dtrt-indent-run-after-smie t)
(message "[WARNING] Indent detection: %s"
(error-message-string e))
(message "")))))) ; warn silently
(letf! ((defun symbol-config--guess (beg end)
(funcall symbol-config--guess beg (min end 10000)))
(defun smie-config-guess ()
(condition-case e (funcall smie-config-guess)
(error (setq dtrt-indent-run-after-smie t)
(message "[WARNING] Indent detection: %s"
(error-message-string e))
(message ""))))) ; warn silently
(funcall orig-fn arg)))))
@@ -377,17 +402,16 @@ files, so we replace calls to `pp' with the much faster `prin1'."
;; a better *help* buffer
:commands helpful--read-symbol
:init
(define-key!
[remap describe-function] #'helpful-callable
[remap describe-command] #'helpful-command
[remap describe-variable] #'helpful-variable
[remap describe-key] #'helpful-key
[remap describe-symbol] #'doom/describe-symbol)
(global-set-key [remap describe-function] #'helpful-callable)
(global-set-key [remap describe-command] #'helpful-command)
(global-set-key [remap describe-variable] #'helpful-variable)
(global-set-key [remap describe-key] #'helpful-key)
(global-set-key [remap describe-symbol] #'helpful-symbol)
(defun doom-use-helpful-a (orig-fn &rest args)
"Force ORIG-FN to use helpful instead of the old describe-* commands."
(cl-letf (((symbol-function #'describe-function) #'helpful-function)
((symbol-function #'describe-variable) #'helpful-variable))
(letf! ((#'describe-function #'helpful-function)
(#'describe-variable #'helpful-variable))
(apply orig-fn args)))
(after! apropos
@@ -411,30 +435,33 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(use-package! smartparens
;; Auto-close delimiters and blocks as you type. It's more powerful than that,
;; but that is all Doom uses it for.
:after-call doom-switch-buffer-hook after-find-file
:hook (doom-first-buffer . smartparens-global-mode)
:commands sp-pair sp-local-pair sp-with-modes sp-point-in-comment sp-point-in-string
:config
;; smartparens recognizes `slime-mrepl-mode', but not `sly-mrepl-mode', so...
(add-to-list 'sp-lisp-modes 'sly-mrepl-mode)
;; Load default smartparens rules for various languages
(require 'smartparens-config)
;; Overlays are too distracting and not terribly helpful. show-parens does
;; this for us already, so...
;; this for us already (and is faster), so...
(setq sp-highlight-pair-overlay nil
sp-highlight-wrap-overlay nil
sp-highlight-wrap-tag-overlay nil)
;; But if someone does want overlays enabled, evil users will be stricken with
;; an off-by-one issue where smartparens assumes you're outside the pair when
;; you're really at the last character in insert mode. We must correct this
;; vile injustice.
(setq sp-show-pair-from-inside t)
;; ...and stay highlighted until we've truly escaped the pair!
(setq sp-cancel-autoskip-on-backward-movement nil)
(with-eval-after-load 'evil
;; But if someone does want overlays enabled, evil users will be stricken
;; with an off-by-one issue where smartparens assumes you're outside the
;; pair when you're really at the last character in insert mode. We must
;; correct this vile injustice.
(setq sp-show-pair-from-inside t)
;; ...and stay highlighted until we've truly escaped the pair!
(setq sp-cancel-autoskip-on-backward-movement nil))
;; The default is 100, because smartparen's scans are relatively expensive
;; (especially with large pair lists for somoe modes), we halve it, as a
;; (especially with large pair lists for some modes), we reduce it, as a
;; better compromise between performance and accuracy.
(setq sp-max-prefix-length 50)
;; This speeds up smartparens. No pair has any business being longer than 4
;; characters; if they must, the modes that need it set it buffer-locally.
(setq sp-max-prefix-length 25)
;; No pair has any business being longer than 4 characters; if they must, set
;; it buffer-locally. It's less work for smartparens.
(setq sp-max-pair-length 4)
;; This isn't always smart enough to determine when we're in a string or not.
;; See https://github.com/Fuco1/smartparens/issues/783.
@@ -442,14 +469,15 @@ files, so we replace calls to `pp' with the much faster `prin1'."
;; Silence some harmless but annoying echo-area spam
(dolist (key '(:unmatched-expression :no-matching-tag))
(setf (cdr (assq key sp-message-alist)) nil))
(setf (alist-get key sp-message-alist) nil))
(add-hook! 'minibuffer-setup-hook
(defun doom-init-smartparens-in-minibuffer-maybe-h ()
"Enable `smartparens-mode' in the minibuffer, during `eval-expression' or
`evil-ex'."
(when (memq this-command '(eval-expression evil-ex))
(smartparens-mode))))
"Enable `smartparens-mode' in the minibuffer, during `eval-expression',
`pp-eval-expression' or `evil-ex'."
(and (memq this-command '(eval-expression pp-eval-expression evil-ex))
smartparens-global-mode
(smartparens-mode))))
;; You're likely writing lisp in the minibuffer, therefore, disable these
;; quote pairs, which lisps doesn't use for strings:
@@ -467,16 +495,13 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(defun doom-disable-smartparens-mode-maybe-h ()
(when smartparens-mode
(setq-local doom-buffer-smartparens-mode t)
(turn-off-smartparens-mode))))
(smartparens-global-mode +1))
(turn-off-smartparens-mode)))))
(use-package! so-long
:after-call after-find-file
:hook (doom-first-file . global-so-long-mode)
:config
(when doom-interactive-mode
(global-so-long-mode +1))
(setq so-long-threshold 400) ; reduce false positives w/ larger threshold
;; Don't disable syntax highlighting and line numbers, or make the buffer
;; read-only, in `so-long-minor-mode', so we can have a basic editing
;; experience in them, at least. It will remain off in `so-long-mode',
@@ -486,6 +511,8 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(delq! 'buffer-read-only so-long-variable-overrides 'assq)
;; ...but at least reduce the level of syntax highlighting
(add-to-list 'so-long-variable-overrides '(font-lock-maximum-decoration . 1))
;; ...and insist that save-place not operate in large/long files
(add-to-list 'so-long-variable-overrides '(save-place-alist . nil))
;; Text files could possibly be too long too
(add-to-list 'so-long-target-modes 'text-mode)
;; But disable everything else that may be unnecessary/expensive for large
@@ -493,6 +520,7 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(appendq! so-long-minor-modes
'(flycheck-mode
flyspell-mode
spell-fu-mode
eldoc-mode
smartparens-mode
highlight-numbers-mode
@@ -502,60 +530,28 @@ files, so we replace calls to `pp' with the much faster `prin1'."
undo-tree-mode
highlight-indent-guides-mode
hl-fill-column-mode))
;; HACK Fix #2183: `so-long-detected-long-line-p' tries to parse comment
;; syntax, but in some buffers comment state isn't initialized, leading
;; to a wrong-type-argument: stringp error.
(defun doom-buffer-has-long-lines-p ()
(when (bound-and-true-p comment-use-syntax)
;; HACK Fix #2183: `so-long-detected-long-line-p' tries to parse comment
;; syntax, but in some buffers comment state isn't initialized,
;; leading to a wrong-type-argument: stringp error.
(let ((so-long-skip-leading-comments (bound-and-true-p comment-use-syntax))
;; HACK If visual-line-mode is on, then false positives are more
;; likely, so up the threshold. More so in text-mode, since long
;; paragraphs are the norm.
(so-long-threshold
(if visual-line-mode
(* so-long-threshold
(if (derived-mode-p 'text-mode)
3
2))
so-long-threshold)))
(so-long-detected-long-line-p)))
(setq so-long-predicate #'doom-buffer-has-long-lines-p))
(use-package! undo-tree
;; Branching & persistent undo
:after-call doom-switch-buffer-hook after-find-file
:config
(setq undo-tree-auto-save-history 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))))))
(global-undo-tree-mode +1))
(use-package! ws-butler
;; a less intrusive `delete-trailing-whitespaces' on save
:after-call after-find-file
:config
(appendq! ws-butler-global-exempt-modes
'(special-mode comint-mode term-mode eshell-mode))
(ws-butler-global-mode))
:hook (doom-first-buffer . ws-butler-global-mode))
(provide 'core-editor)
;;; core-editor.el ends here