Make apheleia-mode-alist order-independent(-ish) (#207)

Solves https://github.com/radian-software/apheleia/issues/206
This commit is contained in:
Radon Rosborough 2023-09-09 16:13:13 -07:00 committed by GitHub
parent 937fe9a940
commit e944e24584
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 16 deletions

View file

@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog].
## Unreleased
### Breaking changes
* The order of entries in `apheleia-mode-alist` is no longer as
important. Specifically, if two different mode entries in
`apheleia-mode-alist` match the current buffer, then the more
specific one is used, even if it comes later. This is generally
speaking what you would expect to happen. For other cases, such as
ordering of regex entries, or modes versus regexes, order is
respected as before ([#206]).
### Enhancements
* Prettier is now enabled in `svelte-mode`.
* More tree-sitter based major modes have been added to

View file

@ -1016,6 +1016,15 @@ When ARG is not a list its turned into a list."
arg
(list arg)))
(defun apheleia--get-mode-chain ()
"Return list of major modes in current buffer.
This is a list starting with `major-mode' and followed by its
parents, if any."
(let ((modes (list major-mode)))
(while (get (car modes) 'derived-mode-parent)
(push (get (car modes) 'derived-mode-parent) modes))
(nreverse modes)))
(defun apheleia--get-formatters (&optional interactive)
"Return the list of formatters to use for the current buffer.
This is a list of symbols that may appear as cars in
@ -1032,14 +1041,45 @@ even if a formatter is configured."
(or (and (not (eq interactive 'prompt))
(apheleia--ensure-list
(or apheleia-formatter
(cl-dolist (entry apheleia-mode-alist)
(when (or (and (symbolp (car entry))
(derived-mode-p (car entry)))
(and (stringp (car entry))
buffer-file-name
(string-match-p
(car entry) buffer-file-name)))
(cl-return (cdr entry)))))))
;; Go through the mode alist. There are two types of
;; entries, mode and regex. We should return whichever
;; entry matches first in the list. However, if two
;; modes match, then we should return the entry for
;; the more specific mode.
;;
;; Implementation: Iterate once. If we match a regex,
;; immediately return, unless we already matched a
;; mode (setting the `formatters' variable), in which
;; case do not return, but also keep going to see if
;; there is a more specific mode later in the list. If
;; we match a mode, save the entry for later
;; reference, as well as the mode that matched it.
;; Update that saved entry only when we find a more
;; specific mode (i.e., a mode that is derived from
;; but not equal to the previously saved mode). Return
;; at the end of the loop the saved entry, if we
;; didn't exit early.
(let* ((unset (make-symbol "gensym-unset"))
(matched-mode nil)
(formatters unset))
(cl-dolist (entry apheleia-mode-alist
(unless (eq formatters unset)
formatters))
(when (and (stringp (car entry))
buffer-file-name
(string-match-p
(car entry) buffer-file-name)
(eq formatters unset))
(cl-return (cdr entry)))
(when (and (symbolp (car entry))
(derived-mode-p (car entry))
(or (eq formatters unset)
(and
(not (eq (car entry) matched-mode))
(provided-mode-derived-p
(car entry) matched-mode))))
(setq matched-mode (car entry))
(setq formatters (cdr entry))))))))
(and interactive
(list
(intern

View file

@ -215,12 +215,7 @@ rather than using this system."
:group 'apheleia)
(defcustom apheleia-mode-alist
'(;; php-mode has to come before cc-mode
(php-mode . phpcs)
;; json-mode has to come before javascript-mode (aka js-mode)
(json-mode . prettier-json)
(json-ts-mode . prettier-json)
;; rest are alphabetical
'(;; Alphabetical please
(asm-mode . asmfmt)
(awk-mode . gawk)
(bash-ts-mode . shfmt)
@ -257,6 +252,8 @@ rather than using this system."
(js3-mode . prettier-javascript)
(js-mode . prettier-javascript)
(js-ts-mode . prettier-javascript)
(json-mode . prettier-json)
(json-ts-mode . prettier-json)
(kotlin-mode . ktlint)
(latex-mode . latexindent)
(LaTeX-mode . latexindent)
@ -265,6 +262,7 @@ rather than using this system."
(nasm-mode . asmfmt)
(nix-mode . nixfmt)
(perl-mode . perltidy)
(php-mode . phpcs)
(purescript-mode . purs-tidy)
(python-mode . black)
(python-ts-mode . black)
@ -302,8 +300,10 @@ Be careful when writing regexps to include \"\\'\" and to escape
to match \".jsx\" files you might use \"\\.jsx\\'\".
If a given mode derives from another mode (e.g. `php-mode' and
`cc-mode'), then ensure that the deriving mode comes before the mode
to derive from, as the list is interpreted sequentially."
`cc-mode'), then whichever entry in the alist is more specific
will apply. In the case that multiple modes match
`derived-mode-p' for the current buffer but neither derives from
the other, whichever entry comes first will be used."
:type '(alist
:key-type
(choice (symbol :tag "Major mode")