Skip to content

Instantly share code, notes, and snippets.

@inscapist
Created June 6, 2021 06:28
Show Gist options
  • Save inscapist/e9ee3a324fd54e5bf65212d6b90b5795 to your computer and use it in GitHub Desktop.
Save inscapist/e9ee3a324fd54e5bf65212d6b90b5795 to your computer and use it in GitHub Desktop.
LSP format fix
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