editor/format: redesign

This isn't the apheleia rewrite, just a redesign to fix the module's
current issues with its +onsave feature.

+ Rethinks how the formatter dispatches to lsp/eglot's formatter.
+ Stops format-all from being too imposing with its warnings.
+ Relies more on format-all-mode to control formatting-on-save.
+ Sidestep +format-buffer-a hackery when using lsp/eglot formatters.

Fixes #5121
Fixes #5128
Fixes #5133
This commit is contained in:
Henrik Lissner 2021-06-04 15:56:07 -04:00
parent 99fbdb1092
commit 68b422c786
2 changed files with 126 additions and 138 deletions

View file

@ -34,38 +34,19 @@ select buffers.")
;;
;;; Bootstrap
(defun +format-enable-for-lsp-on-save-maybe-h ()
"Enable LSP formatter when LSP client is available."
(remove-hook 'lsp-mode-hook #'+format-enable-for-lsp-on-save-maybe-h 'local)
(cond ((not +format-with-lsp) nil)
((bound-and-true-p lsp-mode)
(when (lsp-feature? "textDocument/formatting")
(+format-enable-on-save-h))
t)
((bound-and-true-p eglot--managed-mode)
(when (eglot--server-capable :documentRangeFormattingProvider)
(+format-enable-on-save-h))
t)
((bound-and-true-p lsp--buffer-deferred)
(add-hook 'lsp-mode-hook #'+format-enable-for-lsp-on-save-maybe-h
nil 'local)
t)))
(defun +format-enable-on-save-maybe-h ()
"Enable formatting on save in certain major modes.
This is controlled by `+format-on-save-enabled-modes'."
(and (not (eq major-mode 'fundamental-mode))
(cond ((booleanp +format-on-save-enabled-modes)
+format-on-save-enabled-modes)
((eq (car-safe +format-on-save-enabled-modes) 'not)
(not (memq major-mode (cdr +format-on-save-enabled-modes))))
((memq major-mode +format-on-save-enabled-modes))
((not (require 'format-all nil t))))
(not (+format-enable-for-lsp-on-save-maybe-h))
(let (current-prefix-arg) ; never prompt
(car (format-all--probe)))
(+format-enable-on-save-h)))
(cond ((eq major-mode 'fundamental-mode))
((string-prefix-p " " (buffer-name)))
((booleanp +format-on-save-enabled-modes)
+format-on-save-enabled-modes)
((if (eq (car-safe +format-on-save-enabled-modes) 'not)
(memq major-mode (cdr +format-on-save-enabled-modes))
(not (memq major-mode +format-on-save-enabled-modes))))
((not (require 'format-all nil t)))
((format-all-mode +1))))
(when (featurep! +onsave)
(add-hook 'after-change-major-mode-hook #'+format-enable-on-save-maybe-h))
@ -82,8 +63,22 @@ This is controlled by `+format-on-save-enabled-modes'."
;; 1. Enables partial reformatting (while preserving leading indentation),
;; 2. Applies changes via RCS patch, line by line, to protect buffer markers
;; and avoid any jarring cursor+window scrolling.
(advice-add #'format-all-buffer--with :around #'+format-buffer-a)
(advice-add #'format-all-buffer--with :override #'+format-buffer-a)
;; format-all-mode "helpfully" raises an error when it doesn't know how to
;; format a buffer.
(add-to-list 'debug-ignored-errors "^Don't know how to format ")
;; Don't pop up imposing warnings about missing formatters, but still log it in
;; to *Messages*.
(defadvice! +format--all-buffer-from-hook-a (orig-fn &rest args)
:around #'format-all-buffer--from-hook
(letf! (defun format-all-buffer--with (formatter mode-result)
(and (condition-case-unless-debug e
(format-all--formatter-executable formatter)
(error
(message "Warning: cannot reformat buffer because %S isn't installed"
(gethash formatter format-all--executable-table))
nil))
(funcall format-all-buffer--with formatter mode-result)))
(apply orig-fn args)))