diff --git a/lisp/doom-editor.el b/lisp/doom-editor.el index b17e7ee8a..e11a0c285 100644 --- a/lisp/doom-editor.el +++ b/lisp/doom-editor.el @@ -2,19 +2,6 @@ ;;; Commentary: ;;; Code: -(defvar doom-detect-indentation-excluded-modes - '(pascal-mode - so-long-mode - ;; Automatic indent detection in org files is meaningless. Not to mention, a - ;; non-standard `tab-width' causes an error in org-mode. - org-mode) - "A list of major modes where indentation shouldn't be auto-detected.") - -(defvar-local doom-inhibit-indent-detection nil - "A buffer-local flag that indicates whether `dtrt-indent' should try to detect -indentation settings or not. This should be set by editorconfig if it -successfully sets indent_style/indent_size.") - (defvar doom-inhibit-large-file-detection nil "If non-nil, inhibit large/long file detection when opening files.") @@ -468,50 +455,6 @@ files, so this replace calls to `pp' with the much faster `prin1'." (advice-add #'imenu :around #'doom-set-jump-a)) -(use-package! dtrt-indent - ;; Automatic detection of indent settings - :unless noninteractive - ;; I'm not using `global-dtrt-indent-mode' because it has hard-coded and rigid - ;; major mode checks, so I implement it in `doom-detect-indentation-h'. - :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 - (eq major-mode 'fundamental-mode) - (member (substring (buffer-name) 0 1) '(" " "*")) - (apply #'derived-mode-p doom-detect-indentation-excluded-modes)) - ;; Don't display messages in the echo area, but still log them - (let ((inhibit-message (not init-file-debug))) - (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) - ;; Reduced from the default of 5000 for slightly faster analysis - (setq dtrt-indent-max-lines 2000) - - ;; always keep tab-width up-to-date - (push '(t tab-width) dtrt-indent-hook-generic-mapping-list) - - (defvar dtrt-indent-run-after-smie) - (defadvice! doom--fix-broken-smie-modes-a (fn &optional arg) - "Some smie modes throw errors when trying to guess their indentation, like -`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)) - (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 fn arg))))) - - (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. @@ -636,17 +579,5 @@ on." smartparens-mode smartparens-strict-mode))) - -(use-package! ws-butler - ;; a less intrusive `delete-trailing-whitespaces' on save - :hook (doom-first-buffer . ws-butler-global-mode) - :config - (pushnew! ws-butler-global-exempt-modes - 'special-mode - 'comint-mode - 'term-mode - 'eshell-mode - 'diff-mode)) - (provide 'doom-editor) ;;; doom-editor.el ends here diff --git a/lisp/doom-ui.el b/lisp/doom-ui.el index a0d437342..4f281b8f8 100644 --- a/lisp/doom-ui.el +++ b/lisp/doom-ui.el @@ -502,17 +502,6 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original show-paren-when-point-in-periphery t)) -;;;###package whitespace -(setq whitespace-line-column nil - whitespace-style - '(face indentation tabs tab-mark spaces space-mark newline newline-mark - trailing lines-tail) - whitespace-display-mappings - '((tab-mark ?\t [?› ?\t]) - (newline-mark ?\n [?¬ ?\n]) - (space-mark ?\ [?·] [?.]))) - - ;; ;;; Third party packages @@ -768,12 +757,5 @@ triggering hooks during startup." (put sym 'disabled "Doom doesn't support `customize', configure Emacs from $DOOMDIR/config.el instead")) (put 'customize-themes 'disabled "Set `doom-theme' or use `load-theme' in $DOOMDIR/config.el instead") -(after! whitespace - (defun doom--in-parent-frame-p () - "`whitespace-mode' inundates child frames with whitespace markers, so -disable it to fix all that visual noise." - (null (frame-parameter nil 'parent-frame))) - (add-function :before-while whitespace-enable-predicate #'doom--in-parent-frame-p)) - (provide 'doom-ui) ;;; doom-ui.el ends here diff --git a/lisp/lib/text.el b/lisp/lib/text.el index 5c87dfc92..b03060af7 100644 --- a/lisp/lib/text.el +++ b/lisp/lib/text.el @@ -359,7 +359,7 @@ Respects `require-final-newline'." "Change the indentation size to WIDTH of the current buffer. The effectiveness of this command is significantly improved if you have -editorconfig or dtrt-indent installed." +editorconfig installed." (interactive (list (if (integerp current-prefix-arg) current-prefix-arg @@ -391,20 +391,6 @@ editorconfig or dtrt-indent installed." ;; ;;; Hooks -;;;###autoload -(defun doom-enable-delete-trailing-whitespace-h () - "Enables the automatic deletion of trailing whitespaces upon file save. - -i.e. enables `ws-butler-mode' in the current buffer." - (ws-butler-mode +1)) - -;;;###autoload -(defun doom-disable-delete-trailing-whitespace-h () - "Disables the automatic deletion of trailing whitespaces upon file save. - -i.e. disables `ws-butler-mode' in the current buffer." - (ws-butler-mode -1)) - ;;;###autoload (defun doom-enable-show-trailing-whitespace-h () "Enable `show-trailing-whitespace' in the current buffer." diff --git a/lisp/packages.el b/lisp/packages.el index 6f1ed034a..ce4edaa51 100644 --- a/lisp/packages.el +++ b/lisp/packages.el @@ -27,17 +27,7 @@ ;; doom-editor.el (package! better-jumper :pin "b1bf7a3c8cb820d942a0305e0e6412ef369f819c") -(package! dtrt-indent :pin "9108979357e8c9a1015baa5d37c0b596e2dda11b") (package! smartparens :pin "b629b4e893ba21ba5a381f6c0054bb72f8e96df2") -(package! ws-butler - ;; REVIEW: emacsmirror/nongnu_elpa serves this package from a branch. To stop - ;; Straight from clobbering a single repo for multiple packages, we must be - ;; explicit to force it to clone it multiple times. - :recipe (:host github - :repo "emacsmirror/nongnu_elpa" - :branch "elpa/ws-butler" - :local-repo "ws-butler") - :pin "67c49cfdf5a5a9f28792c500c8eb0017cfe74a3a") ;; doom-projects.el (package! projectile :pin "9325c45e0fd96d5421e75ad901a91ee5353e10ad") diff --git a/modules/editor/whitespace/README.org b/modules/editor/whitespace/README.org new file mode 100644 index 000000000..4557316f9 --- /dev/null +++ b/modules/editor/whitespace/README.org @@ -0,0 +1,68 @@ +:PROPERTIES: +:ID: abf2da25-88b2-41d7-9d9d-3f12ba193f94 +:END: +#+title: :editor whitespace +#+subtitle: a butler for your whitespace +#+created: September 24, 2025 +#+since: 25.10.0 + +* Description :unfold: +Replace this with a short (1-2 sentence) description of what this module does. +This is displayed in the module index. + +Then a longer, multiple paragraph description goes here, which should explain +the purpose of the module and the features/technology(ies) it provides. + +** Maintainers +- [[doom-user:][@hlissner]] + +[[doom-contrib-maintainer:][Become a maintainer?]] + +** Module flags +- +guess :: + Use heuristics to automatically detect and set indent style and width settings + for non-project files (or all files if ~+whitespace-guess-in-projects~ is set). +- +trim :: + Automatically strips trailing whitespace at EOL or EOF, but only in regions of + the file that have been touched in the current session (as to not too + aggressively adjust whitespace in parts of a codebase you aren't responsible + for). + +** Packages +- [[doom-package:dtrt-indent]] if [[doom-module:+guess]] +- [[doom-package:ws-butler]] if [[doom-module:+trim]] + +** Hacks +#+begin_quote +󱌣 This module's hacks haven't been documented yet. [[doom-contrib-module:][Document them?]] +#+end_quote + +** TODO Changelog +# This section will be machine generated. Don't edit it by hand. +/This module does not have a changelog yet./ + +* Installation +[[id:01cffea4-3329-45e2-a892-95a384ab2338][Enable this module in your ~doom!~ block.]] + +/This module has no external requirements./ + +* Usage +#+begin_quote +󱌣 This module has no usage documentation yet. [[doom-contrib-module:][Write some?]] +#+end_quote + +* TODO Configuration +#+begin_quote +󱌣 This module has no configuration documentation yet. [[doom-contrib-module:][Write some?]] +#+end_quote + +* Troubleshooting +/There are no known problems with this module./ [[doom-report:][Report one?]] + +* Frequently asked questions +/This module has no FAQs yet./ [[doom-suggest-faq:][Ask one?]] + +* TODO Appendix +#+begin_quote +󱌣 This module has no appendix yet. [[doom-contrib-module:][Write one?]] +#+end_quote diff --git a/modules/editor/whitespace/config.el b/modules/editor/whitespace/config.el new file mode 100644 index 000000000..9390ddc52 --- /dev/null +++ b/modules/editor/whitespace/config.el @@ -0,0 +1,116 @@ +;;; editor/whitespace/config.el -*- lexical-binding: t; -*- + +(defvar +whitespace-guess-excluded-modes + '(pascal-mode + so-long-mode + ;; Variable-width indentation is superior in elisp. Otherwise, `dtrt-indent' + ;; and `editorconfig' would force fixed indentation on elisp. + emacs-lisp-mode + ;; See #5823: indent detection is slow and inconclusive in these major modes + ;; so they are disabled there. + coq-mode + ;; Automatic indent detection in org files is meaningless. Not to mention, a + ;; non-standard `tab-width' causes an error in org-mode. + org-mode) + "A list of major modes where indentation shouldn't be auto-detected.") + +(defvar +whitespace-guess-in-projects nil + "If non-nil, indentation settings will be guessed in project files. + +This is off by default because, generally, indent-guessing is less useful for +projects, which have many options for configuring editors (editorconfig, +.dir-locals.el, global settings, etc). While single files have fewer options and +are more likely to use varied styles (and would be a pain to accommodate on a +per-file basis).") + +(defvar-local +whitespace-guess-inhibit nil + "A buffer-local flag that indicates whether `dtrt-indent' should try to guess +indentation settings or not. This should be set by editorconfig if it +successfully sets indent_style/indent_size.") + + +;; +;;; Packages + +(use-package! whitespace + :defer t + :config + (setq whitespace-line-column nil + whitespace-style + '(face indentation tabs tab-mark spaces space-mark newline newline-mark + trailing lines-tail) + whitespace-display-mappings + '((tab-mark ?\t [?› ?\t]) + (newline-mark ?\n [?¬ ?\n]) + (space-mark ?\ [?·] [?.]))) + + ;; HACK: `whitespace-mode' inundates child frames with whitespace markers, so + ;; disable it to fix all that visual noise. + (defun +whitespace--in-parent-frame-p () (null (frame-parameter nil 'parent-frame))) + (add-function :before-while whitespace-enable-predicate #'+whitespace--in-parent-frame-p)) + + +(use-package! dtrt-indent + :when (modulep! +guess) + ;; Automatic detection of indent settings + :unless noninteractive + ;; I'm not using `global-dtrt-indent-mode' because it has hard-coded and rigid + ;; major mode checks, so I implement it in `+whitespace-guess-indentation-h'. + :hook ((change-major-mode-after-body read-only-mode) . +whitespace-guess-indentation-h) + :config + (defun +whitespace-guess-indentation-h () + (unless (or (not after-init-time) + doom-large-file-p + +whitespace-guess-inhibit + (eq major-mode 'fundamental-mode) + (member (substring (buffer-name) 0 1) '(" " "*")) + (apply #'derived-mode-p +whitespace-guess-excluded-modes) + buffer-read-only + (and (not +whitespace-guess-in-projects) + (doom-project-root))) + ;; Don't display messages in the echo area, but still log them + (let ((inhibit-message (not init-file-debug))) + (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) + ;; Reduced from the default of 5000 for slightly faster analysis + (setq dtrt-indent-max-lines 2000) + + ;; Always keep tab-width up-to-date + (add-to-list 'dtrt-indent-hook-generic-mapping-list '(t tab-width)) + + ;; Add missing language support + ;; REVIEW: PR these upstream. + (add-to-list 'dtrt-indent-hook-mapping-list '(gdscript-mode default gdscript-indent-offset)) + (add-to-list 'dtrt-indent-hook-mapping-list '(graphviz-mode graphviz-dot-indent-width)) + (add-to-list 'dtrt-indent-hook-mapping-list '(janet-mode janet janet-indent)) + + (defadvice! +whitespace--guess-smie-modes-a (fn &optional arg) + "Some smie modes throw errors when trying to guess their indentation, like +`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)) + (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 fn arg))))) + + +;; a less intrusive `delete-trailing-whitespaces' on save +(use-package! ws-butler + :when (modulep! +trim) + :hook (doom-first-buffer . ws-butler-global-mode) + :config + (pushnew! ws-butler-global-exempt-modes + 'special-mode + 'comint-mode + 'term-mode + 'eshell-mode + 'diff-mode)) diff --git a/modules/editor/whitespace/packages.el b/modules/editor/whitespace/packages.el new file mode 100644 index 000000000..f7b95d017 --- /dev/null +++ b/modules/editor/whitespace/packages.el @@ -0,0 +1,16 @@ +;; -*- no-byte-compile: t; -*- +;;; editor/whitespace/packages.el + +(when (modulep! +guess) + (package! dtrt-indent :pin "9108979357e8c9a1015baa5d37c0b596e2dda11b")) + +(when (modulep! +trim) + (package! ws-butler + ;; REVIEW: emacsmirror/nongnu_elpa serves this package from a branch. To stop + ;; Straight from clobbering a single repo for multiple packages, we must be + ;; explicit to force it to clone it multiple times. + :recipe (:host github + :repo "emacsmirror/nongnu_elpa" + :branch "elpa/ws-butler" + :local-repo "ws-butler") + :pin "67c49cfdf5a5a9f28792c500c8eb0017cfe74a3a")) diff --git a/modules/editor/word-wrap/autoload.el b/modules/editor/word-wrap/autoload.el index 3261d9e32..40d67ea59 100644 --- a/modules/editor/word-wrap/autoload.el +++ b/modules/editor/word-wrap/autoload.el @@ -64,14 +64,15 @@ wrapped at `fill-column' by configuring `+word-wrap-fill-style'." (eq +word-wrap-fill-style 'soft))) (unless +word-wrap--major-mode-is-visual - (require 'dtrt-indent) ; for dtrt-indent--search-hook-mapping - (setq-local +word-wrap--major-mode-indent-var - (let ((indent-var (caddr (dtrt-indent--search-hook-mapping major-mode)))) - (if (listp indent-var) - (car indent-var) - indent-var))) - - (advice-add #'adaptive-wrap-fill-context-prefix :around #'+word-wrap--adjust-extra-indent-a)) + (when (require 'dtrt-indent nil t) + ;; for dtrt-indent--search-hook-mapping + ;; TODO: Generalize this? + (setq-local +word-wrap--major-mode-indent-var + (let ((indent-var (caddr (dtrt-indent--search-hook-mapping major-mode)))) + (if (listp indent-var) + (car indent-var) + indent-var))) + (advice-add #'adaptive-wrap-fill-context-prefix :around #'+word-wrap--adjust-extra-indent-a))) (when +word-wrap--enable-adaptive-wrap-mode (adaptive-wrap-prefix-mode +1)) diff --git a/modules/lang/coq/config.el b/modules/lang/coq/config.el index c9103513e..3398b257c 100644 --- a/modules/lang/coq/config.el +++ b/modules/lang/coq/config.el @@ -17,10 +17,6 @@ ;; sane `comment-line-break-function', so... comment-line-break-function nil) -;; HACK: See #5823: indent detection is slow and inconclusive in coq-mode files, -;; and rarely helpful anyway, so I inhibit it. -(add-to-list 'doom-detect-indentation-excluded-modes 'coq-mode) - ;; We've replaced coq-mode abbrevs with yasnippet snippets (in the snippets ;; library included with Doom). (setq coq-mode-abbrev-table '()) diff --git a/modules/lang/emacs-lisp/config.el b/modules/lang/emacs-lisp/config.el index fd338d850..33add8751 100644 --- a/modules/lang/emacs-lisp/config.el +++ b/modules/lang/emacs-lisp/config.el @@ -79,10 +79,6 @@ See `+emacs-lisp-non-package-mode' for details.") ;; Introduces logic to improve plist indentation in emacs-lisp-mode. (advice-add #'calculate-lisp-indent :override #'+emacs-lisp--calculate-lisp-indent-a) - ;; Variable-width indentation is superior in elisp. Otherwise, `dtrt-indent' - ;; and `editorconfig' would force fixed indentation on elisp. - (add-to-list 'doom-detect-indentation-excluded-modes 'emacs-lisp-mode) - (add-hook! '(emacs-lisp-mode-hook lisp-data-mode-local-vars-hook) ;; Allow folding of outlines in comments #'outline-minor-mode diff --git a/modules/lang/gdscript/config.el b/modules/lang/gdscript/config.el index f8ee13ec4..91480d677 100644 --- a/modules/lang/gdscript/config.el +++ b/modules/lang/gdscript/config.el @@ -40,9 +40,6 @@ (when (modulep! +lsp) (add-hook 'gdscript-mode-local-vars-hook #'lsp! 'append)) - (after! dtrt-indent - (add-to-list 'dtrt-indent-hook-mapping-list '(gdscript-mode default gdscript-indent-offset))) - (map! :localleader :map gdscript-mode-map (:prefix ("r" . "run") diff --git a/modules/lang/graphviz/config.el b/modules/lang/graphviz/config.el index daae33ac1..eb2258141 100644 --- a/modules/lang/graphviz/config.el +++ b/modules/lang/graphviz/config.el @@ -9,9 +9,6 @@ (set-company-backend! 'graphviz-dot-mode 'company-graphviz-dot-backend) (set-formatter! 'graphviz-dot #'+graphviz-formatter :modes '(graphviz-dot-mode)) - (after! dtrt-indent - (add-to-list 'dtrt-indent-hook-mapping-list '(graphviz-mode graphviz-dot-indent-width))) - (when (modulep! :checkers syntax -flymake) (after! flycheck (eval '(flycheck-define-checker graphviz-dot diff --git a/modules/lang/janet/config.el b/modules/lang/janet/config.el index f1564a68e..fcadf3542 100644 --- a/modules/lang/janet/config.el +++ b/modules/lang/janet/config.el @@ -7,9 +7,6 @@ :mode "\\.\\(jdn\\|janet\\)\\'" :interpreter "janet[0-9]*\\'" :config - (after! dtrt-indent - (add-to-list 'dtrt-indent-hook-mapping-list '(janet-mode janet janet-indent))) - ;; HACK: janet-mode calls `janet--set-indentation' each time it's activated, ;; making its (global) side-effects unnecessarily difficult to change, so I ;; disable it and call it manually (and once). diff --git a/modules/tools/editorconfig/README.org b/modules/tools/editorconfig/README.org index 924c4bd17..5778fb06e 100644 --- a/modules/tools/editorconfig/README.org +++ b/modules/tools/editorconfig/README.org @@ -20,9 +20,6 @@ with or without the native editorconfig binary. - [[doom-package:editorconfig-emacs]] ** Hacks -- *Special integration for =dtrt-indent=:* If the local editorconfig file - specifies ~indent_style~ or ~indent_size~, the [[doom-package:dtrt-indent]] (which tries to - guess your indent settings by analyzing your text file) will bow out. - *Special integration for =ws-butler=:* this module will use [[doom-package:ws-butler]] to enforce ~trim_trailing_whitespace~. diff --git a/modules/tools/editorconfig/config.el b/modules/tools/editorconfig/config.el index 7cce161eb..35aa96199 100644 --- a/modules/tools/editorconfig/config.el +++ b/modules/tools/editorconfig/config.el @@ -13,7 +13,7 @@ ;; expecting it to be used. (setq editorconfig-get-properties-function #'editorconfig-get-properties) - (when (require 'ws-butler nil t) + (when (modulep! :editor whitespace +trim) (setq editorconfig-trim-whitespaces-mode 'ws-butler-mode)) ;; Fix #5057 archives don't need editorconfig settings, and they may otherwise @@ -26,10 +26,11 @@ (defun +editorconfig-disable-indent-detection-h (props) "Inhibit `dtrt-indent' if an explicit indent_style and indent_size is specified by editorconfig." - (when (and (not doom-inhibit-indent-detection) + (when (and (modulep! :editor whitespace +guess) + (not +whitespace-guess-inhibit) (or (gethash 'indent_style props) (gethash 'indent_size props))) - (setq doom-inhibit-indent-detection 'editorconfig))) + (setq +whitespace-guess-inhibit 'editorconfig))) ;; I use a hook over `editorconfig-exclude-modes' because the option ;; inhibits all settings, and I only want to inhibit indent_size. Plus modes ;; in that option won't apply to derived modes, so we'd have to add *all* diff --git a/static/init.example.el b/static/init.example.el index f33881644..8d3167694 100644 --- a/static/init.example.el +++ b/static/init.example.el @@ -65,6 +65,7 @@ ;;parinfer ; turn lisp into python, sort of ;;rotate-text ; cycle region at point between text candidates snippets ; my elves. They type so I don't have to + (whitespace +guess +trim) ; a butler for your whitespace ;;word-wrap ; soft wrapping with language-aware indent :emacs