Fix #2605: update editor/format module

This commit is contained in:
Henrik Lissner 2020-03-10 01:48:20 -04:00
parent 691ecee621
commit c2a0ac8b3e
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
3 changed files with 91 additions and 95 deletions

View file

@ -92,6 +92,7 @@ Stolen shamelessly from go-mode"
;; Public library ;; Public library
(defun +format-completing-read () (defun +format-completing-read ()
"TODO"
(require 'format-all) (require 'format-all)
(let* ((fmtlist (mapcar #'symbol-name (hash-table-keys format-all--format-table))) (let* ((fmtlist (mapcar #'symbol-name (hash-table-keys format-all--format-table)))
(fmt (completing-read "Formatter: " fmtlist))) (fmt (completing-read "Formatter: " fmtlist)))
@ -99,110 +100,105 @@ Stolen shamelessly from go-mode"
;;;###autoload ;;;###autoload
(defun +format-probe-a (orig-fn) (defun +format-probe-a (orig-fn)
"Use `+format-with' instead, if it is set." "Use `+format-with' instead, if it is set.
(if +format-with Prompts for a formatter if universal arg is set."
(list +format-with t) (cond (current-prefix-arg
(funcall orig-fn))) (list (or (+format-completing-read)
(user-error "Aborted"))
t))
(+format-with
(list +format-with t))
((funcall orig-fn))))
;;;###autoload ;;;###autoload
(defun +format-buffer (formatter mode-result &optional preserve-indent-p) (defun +format-buffer-a (orig-fn formatter mode-result)
"Format the source code in the current buffer. "Advice that extends `format-all-buffer--with' to:
Returns any of the following values: 1. Enable partial/region reformatting, while preserving leading indentation,
2. Applies changes via RCS patch, line by line, to protect buffer markers and
'unknown No formatter is defined for this major-mode reduce cursor movement or window scrolling.
'error Couldn't format buffer due to formatter errors
'noop Buffer is already formatted
Otherwise, returns a list: (list OUTPUT ERRORS FIRST-DIFF), where OUTPUT is the
formatted text, ERRORS are any errors in string format, and FIRST-DIFF is the
position of the first change in the buffer.
See `+format/buffer' for the interactive version of this function, and See `+format/buffer' for the interactive version of this function, and
`+format-buffer-h' to use as a `before-save-hook' hook." `+format-buffer-h' to use as a `before-save-hook' hook."
(if (not formatter) (let ((f-function (gethash formatter format-all--format-table))
'no-formatter (executable (format-all--formatter-executable formatter))
(let ((f-function (gethash formatter format-all--format-table)) (indent 0)
(executable (format-all--formatter-executable formatter)) (old-line-number (line-number-at-pos))
(indent 0)) (old-column (current-column)))
(pcase-let (pcase-let*
((`(,output ,errput ,first-diff) ((`(,output ,errput)
;; Since `format-all' functions (and various formatting functions, ;; To reliably format regions, rather than the whole buffer, and
;; like `gofmt') widen the buffer, in order to only format a region of ;; `format-all' (and various formatting functions, like `gofmt') widen
;; text, we must make a copy of the buffer to apply formatting to. ;; the buffer, we must copy the region first.
(let ((output (buffer-substring-no-properties (point-min) (point-max))) (let ((output (buffer-substring-no-properties (point-min) (point-max)))
(origin-buffer (or (buffer-base-buffer) (current-buffer)))) (origin-buffer (or (buffer-base-buffer) (current-buffer))))
(with-temp-buffer (with-temp-buffer
(with-silent-modifications (with-silent-modifications
(insert output) (insert output)
;; Ensure this temp buffer _seems_ as much like the origin ;; Ensure this temp buffer seems as much like the origin
;; buffer as possible. ;; buffer as possible, in case the formatter is an elisp
(cl-loop for (var . val) ;; function, like `gofmt'.
in (cl-remove-if-not #'listp (buffer-local-variables origin-buffer)) (cl-loop for (var . val)
;; Making enable-multibyte-characters buffer-local in (cl-remove-if-not #'listp (buffer-local-variables origin-buffer))
;; causes an error. ;; Making enable-multibyte-characters buffer-local
unless (eq var 'enable-multibyte-characters) ;; causes an error.
;; Using setq-local would quote var. unless (eq var 'enable-multibyte-characters)
do (set (make-local-variable var) val)) ;; Using setq-local would quote var.
;; Since we're piping a region of text to the formatter, remove do (set (make-local-variable var) val))
;; any leading indentation to make it look like a file. ;; Since we're piping a region of text to the formatter, remove
(when preserve-indent-p ;; any leading indentation to make it look like a file.
(setq indent (+format--current-indentation)) (setq indent (+format--current-indentation))
(when (> indent 0) (when (> indent 0)
(indent-rigidly (point-min) (point-max) (- indent)))) (indent-rigidly (point-min) (point-max) (- indent)))
(funcall f-function executable mode-result)))))) (funcall f-function executable mode-result)))))
(unwind-protect (`,status
(cond ((null output) 'error) (cond ((null output) :error)
((eq output t) 'noop) ((eq output t) :already-formatted)
((let ((tmpfile (make-temp-file "doom-format")) (t :reformatted))))
(patchbuf (get-buffer-create " *doom format patch*")) (unwind-protect
(coding-system-for-read coding-system-for-read) (when (eq status :reformatted)
(coding-system-for-write coding-system-for-write)) (let ((tmpfile (make-temp-file "doom-format"))
(unless IS-WINDOWS (patchbuf (get-buffer-create " *doom format patch*"))
(setq coding-system-for-read 'utf-8 (coding-system-for-read coding-system-for-read)
coding-system-for-write 'utf-8)) (coding-system-for-write coding-system-for-write))
(unwind-protect (unless IS-WINDOWS
(progn (setq coding-system-for-read 'utf-8
(with-current-buffer patchbuf coding-system-for-write 'utf-8))
(erase-buffer)) (unwind-protect
(with-temp-file tmpfile (progn
(erase-buffer) (with-current-buffer patchbuf
(insert output) (erase-buffer))
(when (> indent 0) (with-temp-file tmpfile
;; restore indentation without affecting new (erase-buffer)
;; indentation (insert output)
(indent-rigidly (point-min) (point-max) (when (> indent 0)
(max 0 (- indent (+format--current-indentation)))))) ;; restore indentation without affecting new
(if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile)) ;; indentation
'noop (indent-rigidly (point-min) (point-max)
(+format--apply-rcs-patch patchbuf) (max 0 (- indent (+format--current-indentation))))))
(list output errput first-diff))) (if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile))
(kill-buffer patchbuf) (setq status :already-formatted)
(delete-file tmpfile))))) (+format--apply-rcs-patch patchbuf)
(unless (= 0 (length errput)) (list output errput)))
(message "Formatter error output:\n%s" 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))))))))
;; ;;
;; Commands ;;; Commands
;;;###autoload ;;;###autoload
(defun +format/buffer (&optional arg) (defalias '+format/buffer #'format-all-buffer)
"Format the source code in the current buffer."
(interactive "P")
(let ((+format-with (or (if arg (+format-completing-read)) +format-with)))
(pcase-let ((`(,formatter ,mode-result) (format-all--probe)))
(pcase
(+format-buffer
formatter mode-result
(or +format-preserve-indentation +format-region-p))
(`no-formatter
(when (called-interactively-p 'any)
(message "No formatter specified for %s" major-mode))
nil)
(`error (message "Failed to format buffer due to errors") nil)
(`noop (message "Buffer was already formatted") nil)
(_ (message "Formatted (%s)" formatter) t)))))
;;;###autoload ;;;###autoload
(defun +format/region (beg end &optional arg) (defun +format/region (beg end &optional arg)

View file

@ -55,4 +55,4 @@ This is controlled by `+format-on-save-enabled-modes'."
;; 1. Enables partial reformatting (while preserving leading indentation), ;; 1. Enables partial reformatting (while preserving leading indentation),
;; 2. Applies changes via RCS patch, line by line, to protect buffer markers ;; 2. Applies changes via RCS patch, line by line, to protect buffer markers
;; and avoid any jarring cursor+window scrolling. ;; and avoid any jarring cursor+window scrolling.
(advice-add #'format-all-buffer :override #'+format/buffer) (advice-add #'format-all-buffer--with :around #'+format-buffer-a)

View file

@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; editor/format/packages.el ;;; editor/format/packages.el
(package! format-all :pin "f57a2a8abb") (package! format-all :pin "8c8c47a863")