Created
June 6, 2021 06:28
-
-
Save inscapist/e9ee3a324fd54e5bf65212d6b90b5795 to your computer and use it in GitHub Desktop.
LSP format fix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/modules/editor/format/autoload/format.el b/modules/editor/format/autoload/format.el | |
index 729ed8779..6565b7c7d 100644 | |
--- a/modules/editor/format/autoload/format.el | |
+++ b/modules/editor/format/autoload/format.el | |
@@ -102,7 +102,9 @@ Stolen shamelessly from go-mode" | |
(defun +format-probe-a (orig-fn) | |
"Use `+format-with' instead, if it is set. | |
Prompts for a formatter if universal arg is set." | |
- (cond ((or buffer-read-only (eq +format-with :none)) | |
+ (cond ((or (eq +format-with :none) | |
+ (doom-temp-buffer-p (current-buffer)) | |
+ (derived-mode-p 'special-mode)) | |
(list nil nil)) | |
(current-prefix-arg | |
(list (or (+format-completing-read) | |
@@ -110,18 +112,10 @@ Prompts for a formatter if universal arg is set." | |
t)) | |
(+format-with | |
(list +format-with t)) | |
- ((and +format-with-lsp | |
- (bound-and-true-p lsp-managed-mode) | |
- (lsp-feature? "textDocument/rangeFormatting")) | |
- (list 'lsp nil)) | |
- ((and +format-with-lsp | |
- (bound-and-true-p eglot--managed-mode) | |
- (eglot--server-capable :documentFormattingProvider)) | |
- (list 'eglot nil)) | |
((funcall orig-fn)))) | |
;;;###autoload | |
-(defun +format-buffer-a (formatter mode-result) | |
+(defun +format-buffer-a (orig-fn formatter mode-result) | |
"Advice that extends `format-all-buffer--with' to: | |
1. Enable partial/region reformatting, while preserving leading indentation, | |
@@ -130,96 +124,78 @@ Prompts for a formatter if universal arg is set." | |
See `+format/buffer' for the interactive version of this function, and | |
`+format-buffer-h' to use as a `before-save-hook' hook." | |
- (cond | |
- ((eq formatter 'lsp) | |
- (call-interactively | |
- (if +format-region-p #'lsp-format-region #'lsp-format-buffer))) | |
- ((eq formatter 'eglot) | |
- (call-interactively | |
- (if +format-region-p #'eglot-format #'eglot-format-buffer))) | |
- ((let ((f-function (gethash formatter format-all--format-table)) | |
- (executable (format-all--formatter-executable formatter)) | |
- (indent 0) | |
- (old-line-number (line-number-at-pos)) | |
- (old-column (current-column))) | |
- (pcase-let* | |
- ((`(,output ,errput) | |
- ;; To reliably format regions, rather than the whole buffer, and | |
- ;; `format-all' (and various formatting functions, like `gofmt') widen | |
- ;; the buffer, we must copy the region first. | |
- (let ((output (buffer-substring-no-properties (point-min) (point-max))) | |
- (origin-buffer (or (buffer-base-buffer) (current-buffer))) | |
- ;; Fixes #5133: some packages (like lsp-mode) can do a bunch | |
- ;; of complicated stuff in these hooks. Better to not have to | |
- ;; deal with any of them at all. | |
- write-file-functions | |
- before-save-hook | |
- after-save-hook | |
- kill-buffer-query-functions | |
- kill-buffer-hook) | |
- (with-temp-buffer | |
- (with-silent-modifications | |
- (insert output) | |
- ;; Ensure this temp buffer seems as much like the origin | |
- ;; buffer as possible, in case the formatter is an elisp | |
- ;; function, like `gofmt'. | |
- (cl-loop for (var . val) | |
- in (cl-remove-if-not #'listp (buffer-local-variables (current-buffer))) | |
- ;; Making enable-multibyte-characters buffer-local | |
- ;; causes an error. | |
- unless (eq var 'enable-multibyte-characters) | |
- ;; Fixes #5133: don't deal with complicated hook | |
- ;; functionality! This isn't a real buffer anyway. | |
- unless (string-match-p (symbol-name var) "-\\(hook\\|functions\\)$") | |
- ;; Using setq-local would quote var. | |
- do (set (make-local-variable var) val)) | |
- ;; Since we're piping a region of text to the formatter, remove | |
- ;; any leading indentation to make it look like a file. | |
- (setq indent (+format--current-indentation)) | |
- (when (> indent 0) | |
- (indent-rigidly (point-min) (point-max) (- indent))) | |
- (funcall f-function executable mode-result))))) | |
- (`,status | |
- (cond ((null output) :error) | |
- ((eq output t) :already-formatted) | |
- (t :reformatted)))) | |
- (unwind-protect | |
- (when (eq status :reformatted) | |
- (let ((tmpfile (make-temp-file "doom-format")) | |
- (patchbuf (get-buffer-create " *doom format patch*")) | |
- (coding-system-for-read coding-system-for-read) | |
- (coding-system-for-write coding-system-for-write)) | |
- (unless IS-WINDOWS | |
- (setq coding-system-for-read 'utf-8 | |
- coding-system-for-write 'utf-8)) | |
- (unwind-protect | |
- (progn | |
- (with-current-buffer patchbuf | |
- (erase-buffer)) | |
- (with-temp-file tmpfile | |
- (erase-buffer) | |
- (insert output) | |
- (when (> indent 0) | |
- ;; restore indentation without affecting new | |
- ;; indentation | |
- (indent-rigidly (point-min) (point-max) | |
- (max 0 (- indent (+format--current-indentation)))))) | |
- (if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile)) | |
- (setq status :already-formatted) | |
- (+format--apply-rcs-patch patchbuf) | |
- (list output errput))) | |
- (kill-buffer patchbuf) | |
- (delete-file tmpfile)))) | |
- (format-all--show-or-hide-errors errput) | |
- (goto-char (point-min)) | |
- (forward-line (1- old-line-number)) | |
- (let ((line-length (- (point-at-eol) (point-at-bol)))) | |
- (goto-char (+ (point) (min old-column line-length)))) | |
- (run-hook-with-args 'format-all-after-format-functions formatter status) | |
- (message (pcase status | |
- (:error "Formatting error") | |
- (:already-formatted "Already formatted") | |
- (:reformatted (format "Reformatted with %s" formatter)))))))))) | |
+ (let ((f-function (gethash formatter format-all--format-table)) | |
+ (executable (format-all--formatter-executable formatter)) | |
+ (indent 0) | |
+ (old-line-number (line-number-at-pos)) | |
+ (old-column (current-column))) | |
+ (pcase-let* | |
+ ((`(,output ,errput) | |
+ ;; To reliably format regions, rather than the whole buffer, and | |
+ ;; `format-all' (and various formatting functions, like `gofmt') widen | |
+ ;; the buffer, we must copy the region first. | |
+ (let ((output (buffer-substring-no-properties (point-min) (point-max))) | |
+ (origin-buffer (or (buffer-base-buffer) (current-buffer)))) | |
+ (with-temp-buffer | |
+ (with-silent-modifications | |
+ (insert output) | |
+ ;; Ensure this temp buffer seems as much like the origin | |
+ ;; buffer as possible, in case the formatter is an elisp | |
+ ;; function, like `gofmt'. | |
+ (cl-loop for (var . val) | |
+ in (cl-remove-if-not #'listp (buffer-local-variables origin-buffer)) | |
+ ;; Making enable-multibyte-characters buffer-local | |
+ ;; causes an error. | |
+ unless (eq var 'enable-multibyte-characters) | |
+ ;; Using setq-local would quote var. | |
+ do (set (make-local-variable var) val)) | |
+ ;; Since we're piping a region of text to the formatter, remove | |
+ ;; any leading indentation to make it look like a file. | |
+ (setq indent (+format--current-indentation)) | |
+ (when (> indent 0) | |
+ (indent-rigidly (point-min) (point-max) (- indent))) | |
+ (funcall f-function executable mode-result))))) | |
+ (`,status | |
+ (cond ((null output) :error) | |
+ ((eq output t) :already-formatted) | |
+ (t :reformatted)))) | |
+ (unwind-protect | |
+ (when (eq status :reformatted) | |
+ (let ((tmpfile (make-temp-file "doom-format")) | |
+ (patchbuf (get-buffer-create " *doom format patch*")) | |
+ (coding-system-for-read coding-system-for-read) | |
+ (coding-system-for-write coding-system-for-write)) | |
+ (unless IS-WINDOWS | |
+ (setq coding-system-for-read 'utf-8 | |
+ coding-system-for-write 'utf-8)) | |
+ (unwind-protect | |
+ (progn | |
+ (with-current-buffer patchbuf | |
+ (erase-buffer)) | |
+ (with-temp-file tmpfile | |
+ (erase-buffer) | |
+ (insert output) | |
+ (when (> indent 0) | |
+ ;; restore indentation without affecting new | |
+ ;; indentation | |
+ (indent-rigidly (point-min) (point-max) | |
+ (max 0 (- indent (+format--current-indentation)))))) | |
+ (if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile)) | |
+ (setq status :already-formatted) | |
+ (+format--apply-rcs-patch patchbuf) | |
+ (list output errput))) | |
+ (kill-buffer patchbuf) | |
+ (delete-file tmpfile)))) | |
+ (format-all--show-or-hide-errors errput) | |
+ (goto-char (point-min)) | |
+ (forward-line (1- old-line-number)) | |
+ (let ((line-length (- (point-at-eol) (point-at-bol)))) | |
+ (goto-char (+ (point) (min old-column line-length)))) | |
+ (run-hook-with-args 'format-all-after-format-functions formatter status) | |
+ (message (pcase status | |
+ (:error "Formatting error") | |
+ (:already-formatted "Already formatted") | |
+ (:reformatted (format "Reformatted with %s" formatter)))))))) | |
;; | |
@@ -245,19 +221,23 @@ If nil, BEG and/or END will default to the boundaries of the src block at point. | |
(user-error "Cannot reformat an org src block in org-mode") | |
(+format/region beg end)))))) | |
-(defun +format--buffer () | |
- (if (and (eq major-mode 'org-mode) | |
- (org-in-src-block-p t)) | |
- (+format--org-region (point-min) (point-max)) | |
- (if (called-interactively-p 'any) | |
- (format-all-buffer) | |
- (ignore-errors (format-all-buffer))))) | |
- | |
;;;###autoload | |
(defun +format/buffer () | |
"Reformat the current buffer using LSP or `format-all-buffer'." | |
(interactive) | |
- (+format--buffer)) | |
+ (if (eq major-mode 'org-mode) | |
+ (when (org-in-src-block-p t) | |
+ (+format--org-region nil nil)) | |
+ (call-interactively | |
+ (cond ((and +format-with-lsp | |
+ (bound-and-true-p lsp-mode) | |
+ (lsp-feature? "textDocument/formatting")) | |
+ #'lsp-format-buffer) | |
+ ((and +format-with-lsp | |
+ (bound-and-true-p eglot--managed-mode) | |
+ (eglot--server-capable :documentFormattingProvider)) | |
+ #'eglot-format-buffer) | |
+ (#'format-all-buffer))))) | |
;;;###autoload | |
(defun +format/region (beg end) | |
@@ -267,10 +247,21 @@ WARNING: this may not work everywhere. It will throw errors if the region | |
contains a syntax error in isolation. It is mostly useful for formatting | |
snippets or single lines." | |
(interactive "rP") | |
- (let ((+format-region-p t)) | |
- (save-restriction | |
- (narrow-to-region beg end) | |
- (+format--buffer)))) | |
+ (if (and (eq major-mode 'org-mode) | |
+ (org-in-src-block-p t)) | |
+ (+format--org-region beg end) | |
+ (cond ((and +format-with-lsp | |
+ (bound-and-true-p lsp-mode) | |
+ (lsp-feature? "textDocument/rangeFormatting")) | |
+ (call-interactively #'lsp-format-region)) | |
+ ((and +format-with-lsp | |
+ (bound-and-true-p eglot--managed-mode) | |
+ (eglot--server-capable :documentRangeFormattingProvider)) | |
+ (call-interactively #'eglot-format)) | |
+ ((save-restriction | |
+ (narrow-to-region beg end) | |
+ (let ((+format-region-p t)) | |
+ (+format/buffer))))))) | |
;;;###autoload | |
(defun +format/region-or-buffer () | |
@@ -286,6 +277,11 @@ is selected)." | |
;; | |
;; Hooks | |
+;;;###autoload | |
+(defun +format-enable-on-save-h () | |
+ "Enables formatting on save." | |
+ (add-hook 'before-save-hook #'+format-buffer-h nil t)) | |
+ | |
;;;###autoload | |
(defalias '+format-buffer-h #'+format/buffer | |
"Format the source code in the current buffer with minimal feedback. | |
diff --git a/modules/editor/format/config.el b/modules/editor/format/config.el | |
index 6b39582b8..f2810ce98 100644 | |
--- a/modules/editor/format/config.el | |
+++ b/modules/editor/format/config.el | |
@@ -1,11 +1,10 @@ | |
;;; editor/format/config.el -*- lexical-binding: t; -*- | |
(defvar +format-on-save-enabled-modes | |
- '(not emacs-lisp-mode ; elisp's mechanisms are good enough | |
- sql-mode ; sqlformat is currently broken | |
- tex-mode ; latexindent is broken | |
- latex-mode | |
- org-msg-edit-mode) ; doesn't need a formatter | |
+ '(not emacs-lisp-mode ; elisp's mechanisms are good enough | |
+ sql-mode ; sqlformat is currently broken | |
+ tex-mode ; latexindent is broken | |
+ latex-mode) | |
"A list of major modes in which to reformat the buffer upon saving. | |
If this list begins with `not', then it negates the list. | |
@@ -38,15 +37,14 @@ select buffers.") | |
"Enable formatting on save in certain major modes. | |
This is controlled by `+format-on-save-enabled-modes'." | |
- (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)))) | |
+ (unless (or (eq major-mode 'fundamental-mode) | |
+ (cond ((booleanp +format-on-save-enabled-modes) | |
+ (null +format-on-save-enabled-modes)) | |
+ ((eq (car +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-enable-on-save-h))) | |
(when (featurep! +onsave) | |
(add-hook 'after-change-major-mode-hook #'+format-enable-on-save-maybe-h)) | |
@@ -63,22 +61,8 @@ 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 :override #'+format-buffer-a) | |
+(advice-add #'format-all-buffer--with :around #'+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))) | |
diff --git a/modules/editor/format/packages.el b/modules/editor/format/packages.el | |
index eada328ac..26cd61452 100644 | |
--- a/modules/editor/format/packages.el | |
+++ b/modules/editor/format/packages.el | |
@@ -1,4 +1,4 @@ | |
;; -*- no-byte-compile: t; -*- | |
;;; editor/format/packages.el | |
-(package! format-all :pin "47d862d40a088ca089c92cd393c6dca4628f87d3") | |
+(package! format-all :pin "47d862d40a") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment