editor/reformat: refactor & fixes

+ Change +format-type to +format-region-p (now a boolean)
+ Add PRESERVE-INDENT-P boolean argument to +format-buffer
+ Add +format-preserve-indentation variable (only controls indent
  preservation during +format/buffer, not +format/region, where it's
  always enabled).
+ Fix error arising from +format|buffer hook when no formatter is
  defined for the current mode #893
+ Change +format|buffer to alias for +format/buffer.
This commit is contained in:
Henrik Lissner 2018-09-18 13:14:39 -04:00
parent f4e119a642
commit 6a44cf0124
3 changed files with 74 additions and 61 deletions

View file

@ -1,6 +1,6 @@
;;; editor/format/autoload.el -*- lexical-binding: t; -*- ;;; editor/format/autoload.el -*- lexical-binding: t; -*-
(defvar +format-type 'buffer (defvar +format-region-p 'buffer
"A symbol representing whether the buffer or a region of it is being "A symbol representing whether the buffer or a region of it is being
formatted. Can be 'buffer or 'region.") formatted. Can be 'buffer or 'region.")
@ -105,7 +105,7 @@ Stolen shamelessly from go-mode"
(funcall orig-fn))) (funcall orig-fn)))
;;;###autoload ;;;###autoload
(defun +format-buffer (formatter mode-result) (defun +format-buffer (formatter mode-result &optional preserve-indent-p)
"Format the source code in the current buffer. "Format the source code in the current buffer.
Returns any of the following values: Returns any of the following values:
@ -120,52 +120,53 @@ 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' to use as a `before-save-hook' hook." `+format|buffer' to use as a `before-save-hook' hook."
(unless formatter (if (not formatter)
(user-error "Don't know how to format '%s' code" major-mode)) 'no-formatter
(let ((f-function (gethash formatter format-all-format-table)) (let ((f-function (gethash formatter format-all-format-table))
(executable (format-all-formatter-executable formatter)) (executable (format-all-formatter-executable formatter))
indent) (indent 0))
(pcase-let (pcase-let
((`(,output ,errput ,first-diff) ((`(,output ,errput ,first-diff)
;; Since `format-all' functions (and various formatting functions, ;; Since `format-all' functions (and various formatting functions,
;; like `gofmt') widen the buffer, in order to only format a region of ;; like `gofmt') widen the buffer, in order to only format a region of
;; text, we must make a copy of the buffer to apply formatting to. ;; text, we must make a copy of the buffer to apply formatting to.
(let ((output (buffer-substring-no-properties (point-min) (point-max)))) (let ((output (buffer-substring-no-properties (point-min) (point-max))))
(with-temp-buffer (with-temp-buffer
(insert output) (insert output)
;; Since we're piping a region of text to the formatter, remove ;; Since we're piping a region of text to the formatter, remove
;; any leading indentation to make it look like a file. ;; any leading indentation to make it look like a file.
(setq indent (+format--current-indentation)) (when preserve-indent-p
(when (> indent 0) (setq indent (+format--current-indentation))
(indent-rigidly (point-min) (point-max) (- indent))) (when (> indent 0)
(funcall f-function executable mode-result))))) (indent-rigidly (point-min) (point-max) (- indent))))
(unwind-protect (funcall f-function executable mode-result)))))
(cond ((null output) 'error) (unwind-protect
((eq output t) 'noop) (cond ((null output) 'error)
((let ((tmpfile (make-temp-file "doom-format")) ((eq output t) 'noop)
(patchbuf (get-buffer-create " *doom format patch*")) ((let ((tmpfile (make-temp-file "doom-format"))
(coding-system-for-read 'utf-8) (patchbuf (get-buffer-create " *doom format patch*"))
(coding-system-for-write 'utf-8)) (coding-system-for-read 'utf-8)
(unwind-protect (coding-system-for-write 'utf-8))
(progn (unwind-protect
(with-current-buffer patchbuf (progn
(erase-buffer)) (with-current-buffer patchbuf
(with-temp-file tmpfile (erase-buffer))
(erase-buffer) (with-temp-file tmpfile
(insert output) (erase-buffer)
(when (> indent 0) (insert output)
;; restore indentation without affecting new (when (> indent 0)
;; indentation ;; restore indentation without affecting new
(indent-rigidly (point-min) (point-max) ;; indentation
(max 0 (- indent (+format--current-indentation)))))) (indent-rigidly (point-min) (point-max)
(if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile)) (max 0 (- indent (+format--current-indentation))))))
'noop (if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile))
(+format--apply-rcs-patch patchbuf) 'noop
(list output errput first-diff))) (+format--apply-rcs-patch patchbuf)
(kill-buffer patchbuf) (list output errput first-diff)))
(delete-file tmpfile))))) (kill-buffer patchbuf)
(unless (= 0 (length errput)) (delete-file tmpfile)))))
(message "Formatter error output:\n%s" errput)))))) (unless (= 0 (length errput))
(message "Formatter error output:\n%s" errput)))))))
;; ;;
@ -175,8 +176,19 @@ See `+format/buffer' for the interactive version of this function, and
(defun +format/buffer (&optional arg) (defun +format/buffer (&optional arg)
"Format the source code in the current buffer." "Format the source code in the current buffer."
(interactive "P") (interactive "P")
(let ((+format-with (if arg (+format-completing-read)))) (let ((+format-with (or (if arg (+format-completing-read)) +format-with)))
(+format|buffer))) (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)
@ -188,8 +200,8 @@ snippets or single lines."
(interactive "rP") (interactive "rP")
(save-restriction (save-restriction
(narrow-to-region beg end) (narrow-to-region beg end)
(let ((+format-type 'region)) (let ((+format-region-p t))
(+format/buffer arg)))) (call-interactively #'+format/buffer))))
;;;###autoload ;;;###autoload
(defun +format/region-or-buffer (beg end &optional arg) (defun +format/region-or-buffer (beg end &optional arg)
@ -198,7 +210,7 @@ is selected)."
(interactive "rP") (interactive "rP")
(if (use-region-p) (if (use-region-p)
(+format/region beg end arg) (+format/region beg end arg)
(+format/buffer arg))) (call-interactively #'+format/buffer)))
;; ;;
@ -210,12 +222,7 @@ is selected)."
(add-hook 'before-save-hook #'+format|buffer nil t)) (add-hook 'before-save-hook #'+format|buffer nil t))
;;;###autoload ;;;###autoload
(defun +format|buffer () (defalias '+format|buffer #'+format/buffer
"Format the source code in the current buffer with minimal feedback. "Format the source code in the current buffer with minimal feedback.
Meant for `before-save-hook'." Meant for `before-save-hook'.")
(pcase-let ((`(,formatter ,mode-result) (format-all-probe)))
(pcase (+format-buffer formatter mode-result)
(`error (message "Failed to format buffer due to errors") nil)
(`noop (message "Buffer was already formatted") nil)
(_ (message "Formatted (%s)" formatter) t))))

View file

@ -12,6 +12,12 @@ If nil, it is disabled in all modes, the same as if the +onsave flag wasn't
Irrelevant if you do not have the +onsave flag enabled for this module.") Irrelevant if you do not have the +onsave flag enabled for this module.")
(defvar +format-preserve-indentation t
"If non-nil, the leading indentation is preserved when formatting the whole
buffer. This is particularly useful for partials.
Indentation is always preserved when formatting regions. ")
(defvar-local +format-with nil (defvar-local +format-with nil
"Set this to explicitly use a certain formatter for the current buffer.") "Set this to explicitly use a certain formatter for the current buffer.")

View file

@ -15,7 +15,7 @@
;; Redefines default formatter to *not* use goimports if reformatting a ;; Redefines default formatter to *not* use goimports if reformatting a
;; region; as it doesn't play well with partial code. ;; region; as it doesn't play well with partial code.
(set-formatter! 'gofmt (set-formatter! 'gofmt
'(("%s" (if (or (eq +format-type 'region) '(("%s" (if (or +format-region-p
(not (executable-find "goimports"))) (not (executable-find "goimports")))
"gofmt" "gofmt"
"goimports")))) "goimports"))))