2019-07-07 14:13:57 -07:00
|
|
|
;;; apheleia.el --- Reformat buffer stably -*- lexical-binding: t -*-
|
|
|
|
|
2022-05-09 15:58:41 -07:00
|
|
|
;; Copyright (C) 2019-2022 Radian LLC and contributors
|
2019-07-07 14:13:57 -07:00
|
|
|
|
2022-05-09 15:58:41 -07:00
|
|
|
;; Author: Radian LLC <contact+apheleia@radian.codes>
|
2019-07-07 14:13:57 -07:00
|
|
|
;; Created: 7 Jul 2019
|
|
|
|
;; Homepage: https://github.com/raxod502/apheleia
|
|
|
|
;; Keywords: tools
|
2022-04-10 22:21:50 +01:00
|
|
|
;; Package-Requires: ((emacs "26"))
|
2020-04-04 09:50:44 -06:00
|
|
|
;; SPDX-License-Identifier: MIT
|
2023-02-25 11:31:26 -08:00
|
|
|
;; Version: 3.2
|
2019-07-07 14:13:57 -07:00
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
;; Apheleia is an Emacs Lisp package which allows you to reformat a
|
|
|
|
;; buffer without moving point. This solves the usual problem of
|
|
|
|
;; running a tool like Prettier or Black on `before-save-hook', namely
|
|
|
|
;; that it resets point to the beginning of the buffer. Apheleia
|
|
|
|
;; maintains the position of point relative to its surrounding text
|
|
|
|
;; even if the buffer is modified by the reformatting.
|
|
|
|
|
|
|
|
;; Please see https://github.com/raxod502/apheleia for more information.
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
2023-04-20 10:55:13 +01:00
|
|
|
(require 'apheleia-utils)
|
2021-11-21 18:45:50 +00:00
|
|
|
|
2019-07-07 14:13:57 -07:00
|
|
|
(defgroup apheleia nil
|
2019-07-10 19:04:02 -07:00
|
|
|
"Reformat buffer without moving point."
|
2019-07-07 14:13:57 -07:00
|
|
|
:group 'external
|
|
|
|
:link '(url-link :tag "GitHub" "https://github.com/raxod502/apheleia")
|
|
|
|
:link '(emacs-commentary-link :tag "Commentary" "apheleia"))
|
|
|
|
|
2023-04-20 10:52:25 +01:00
|
|
|
(defcustom apheleia-formatters
|
2023-04-22 10:36:38 +01:00
|
|
|
'((astyle . ("astyle" (apheleia-formatters-locate-file
|
|
|
|
"--options" ".astylerc")))
|
|
|
|
(asmfmt . ("asmfmt"))
|
2023-04-22 10:26:49 +01:00
|
|
|
(bean-format . ("bean-format"))
|
2023-04-22 11:34:12 +01:00
|
|
|
(beautysh . ("beautysh"
|
|
|
|
(apheleia-formatters-indent
|
|
|
|
"--tab" "--indent-size" 'sh-basic-offset)
|
|
|
|
"-"))
|
2023-04-20 10:52:25 +01:00
|
|
|
(black . ("black"
|
|
|
|
(when (apheleia-formatters-extension-p "pyi") "--pyi")
|
|
|
|
(apheleia-formatters-fill-column "--line-length")
|
|
|
|
"-"))
|
|
|
|
(brittany . ("brittany"))
|
2023-04-22 11:38:15 +01:00
|
|
|
(buildifier . ("buildifier"))
|
2023-04-20 10:52:25 +01:00
|
|
|
(caddyfmt . ("caddy" "fmt" "-"))
|
|
|
|
(clang-format . ("clang-format"
|
|
|
|
"-assume-filename"
|
|
|
|
(or (buffer-file-name)
|
|
|
|
(apheleia-formatters-mode-extension)
|
|
|
|
".c")))
|
2023-04-22 11:41:37 +01:00
|
|
|
(cmake-format . ("cmake-format" "-"))
|
2023-04-20 10:52:25 +01:00
|
|
|
(crystal-tool-format . ("crystal" "tool" "format" "-"))
|
|
|
|
(dart-format . ("dart" "format"))
|
|
|
|
(elm-format . ("elm-format" "--yes" "--stdin"))
|
|
|
|
(fish-indent . ("fish_indent"))
|
2023-04-20 14:33:53 +01:00
|
|
|
(gawk . ("gawk" "-f" "-" "--pretty-print=-"))
|
2023-04-20 10:52:25 +01:00
|
|
|
(gofmt . ("gofmt"))
|
|
|
|
(gofumpt . ("gofumpt"))
|
|
|
|
(goimports . ("goimports"))
|
|
|
|
(google-java-format . ("google-java-format" "-"))
|
2023-04-22 11:44:44 +01:00
|
|
|
(html-tidy "tidy"
|
|
|
|
"--quiet" "yes"
|
|
|
|
"--tidy-mark" "no"
|
|
|
|
"--vertical-space" "yes"
|
|
|
|
"-indent"
|
|
|
|
(when (derived-mode-p 'nxml-mode)
|
|
|
|
"-xml")
|
|
|
|
(apheleia-formatters-indent
|
|
|
|
"--indent-with-tabs"
|
|
|
|
"--indent-spaces"
|
|
|
|
(cond
|
|
|
|
((derived-mode-p 'nxml-mode)
|
|
|
|
'nxml-child-indent)
|
|
|
|
((derived-mode-p 'web-mode)
|
|
|
|
'web-mode-indent-style)))
|
|
|
|
(apheleia-formatters-fill-column "-wrap"))
|
2023-04-20 10:52:25 +01:00
|
|
|
(isort . ("isort" "-"))
|
2023-04-20 13:50:03 +01:00
|
|
|
(jq "jq" "."
|
|
|
|
(apheleia-formatters-js-indent "--tab" "--indent"))
|
2023-04-20 10:52:25 +01:00
|
|
|
(lisp-indent . apheleia-indent-lisp-buffer)
|
|
|
|
(ktlint . ("ktlint" "--log-level=none" "--stdin" "-F" "-"))
|
|
|
|
(latexindent . ("latexindent" "--logfile=/dev/null"))
|
|
|
|
(mix-format . ("mix" "format" "-"))
|
|
|
|
(nixfmt . ("nixfmt"))
|
|
|
|
(ocamlformat . ("ocamlformat" "-" "--name" filepath
|
|
|
|
"--enable-outside-detected-project"))
|
|
|
|
(phpcs . ("apheleia-phpcs"))
|
|
|
|
(prettier
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-css
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=css"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-html
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=html"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-graphql
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=graphql"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-javascript
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=babel-flow"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-json
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=json"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-markdown
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=markdown"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-ruby
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=ruby"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-scss
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=scss"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-svelte
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=svelte"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-typescript
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=typescript"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(prettier-yaml
|
|
|
|
. (npx "prettier" "--stdin-filepath" filepath "--parser=yaml"
|
|
|
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
|
|
|
(purs-tidy . (npx "purs-tidy" "format"))
|
|
|
|
(shfmt . ("shfmt"
|
|
|
|
"-filename" filepath
|
|
|
|
"-ln" (cl-case (bound-and-true-p sh-shell)
|
|
|
|
(sh "posix")
|
|
|
|
(t "bash"))
|
|
|
|
"-i" (number-to-string
|
|
|
|
(cond
|
|
|
|
(indent-tabs-mode 0)
|
|
|
|
((boundp 'sh-basic-offset)
|
|
|
|
sh-basic-offset)
|
|
|
|
(t 4)))
|
|
|
|
"-"))
|
|
|
|
(stylua . ("stylua" "-"))
|
|
|
|
(rustfmt . ("rustfmt" "--quiet" "--emit" "stdout"))
|
|
|
|
(terraform . ("terraform" "fmt" "-")))
|
|
|
|
"Alist of code formatting commands.
|
|
|
|
The keys may be any symbols you want, and the values are shell
|
|
|
|
commands, lists of strings and symbols, or a function symbol.
|
|
|
|
|
|
|
|
If the value is a function, the function will be called with
|
|
|
|
keyword arguments (see the implementation of
|
|
|
|
`apheleia--run-formatter-function' to see which). It should use
|
|
|
|
`cl-defun' with `&allow-other-keys' for forward compatibility.
|
|
|
|
|
|
|
|
Otherwise in Lisp code, the format of commands is similar to what
|
|
|
|
you pass to `make-process', except as follows.
|
|
|
|
|
|
|
|
Normally, the contents of the current buffer are passed to the
|
|
|
|
command on stdin, and the output is read from stdout. However, if
|
|
|
|
you use the symbol `file' as one of the elements of commands,
|
|
|
|
then the filename of the current buffer is substituted for
|
|
|
|
it. (Use `filepath' instead of `file' if you need the filename of
|
|
|
|
the current buffer, but you still want its contents to be passed
|
|
|
|
on stdin.)
|
|
|
|
|
|
|
|
If you instead use the symbol `input' as one of the elements of
|
|
|
|
commands, then the contents of the current buffer are written to
|
|
|
|
a temporary file and its name is substituted for `input'. Also,
|
|
|
|
if you use the symbol `output' as one of the elements of
|
|
|
|
commands, then it is substituted with the name of a temporary
|
|
|
|
file. In that case, it is expected that the command writes to
|
|
|
|
that file, and the file is then read into an Emacs buffer.
|
|
|
|
|
|
|
|
If you use the symbol `inplace' as one of the elements of the
|
|
|
|
list, then the contents of the current buffer are written to a
|
|
|
|
temporary file and its name is substituted for `inplace'.
|
|
|
|
However, unlike `input', it is expected that the formatter write
|
|
|
|
the formatted file back to the same file in place. In other
|
|
|
|
words, `inplace' is like `input' and `output' together.
|
|
|
|
|
|
|
|
If you use the symbol `npx' as one of the elements of commands,
|
|
|
|
then the first string element of the command list is resolved
|
|
|
|
inside node_modules/.bin if such a directory exists anywhere
|
|
|
|
above the current `default-directory'.
|
|
|
|
|
|
|
|
Any list elements that are not strings and not any of the special
|
|
|
|
symbols mentioned above will be evaluated when the formatter is
|
|
|
|
invoked, and spliced into the list. A form can evaluate either to
|
|
|
|
a string or to a list of strings.
|
|
|
|
|
|
|
|
The \"scripts/formatters\" subdirectory of the Apheleia source
|
|
|
|
repository is automatically prepended to $PATH (variable
|
|
|
|
`exec-path', to be specific) when invoking external formatters.
|
|
|
|
This is intended for internal use. If you would like to define
|
|
|
|
your own script, you can simply place it on your normal $PATH
|
|
|
|
rather than using this system."
|
|
|
|
:type '(alist
|
|
|
|
:key-type symbol
|
|
|
|
:value-type
|
|
|
|
(choice
|
|
|
|
(repeat
|
|
|
|
(choice
|
|
|
|
(string :tag "Argument")
|
|
|
|
(const :tag "Look for command in node_modules/.bin" npx)
|
|
|
|
(const :tag "Name of file being formatted" filepath)
|
|
|
|
(const :tag "Name of real file used for input" file)
|
|
|
|
(const :tag "Name of temporary file used for input" input)
|
|
|
|
(const :tag "Name of temporary file used for output" output)))
|
|
|
|
(function :tag "Formatter function")))
|
|
|
|
: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
|
2023-04-22 10:26:49 +01:00
|
|
|
(asm-mode . asmfmt)
|
2023-04-20 14:33:53 +01:00
|
|
|
(awk-mode . gawk)
|
2023-04-20 10:52:25 +01:00
|
|
|
(bash-ts-mode . shfmt)
|
2023-04-22 11:38:15 +01:00
|
|
|
(bazel-mode . buildifier)
|
2023-04-20 10:52:25 +01:00
|
|
|
(beancount-mode . bean-format)
|
|
|
|
(c++-ts-mode . clang-format)
|
|
|
|
(caddyfile-mode . caddyfmt)
|
|
|
|
(cc-mode . clang-format)
|
|
|
|
(c-mode . clang-format)
|
|
|
|
(c-ts-mode . clang-format)
|
|
|
|
(c++-mode . clang-format)
|
|
|
|
(caml-mode . ocamlformat)
|
2023-04-22 11:41:37 +01:00
|
|
|
(cmake-mode . cmake-format)
|
|
|
|
(cmake-ts-mode . cmake-format)
|
2023-04-20 10:52:25 +01:00
|
|
|
(common-lisp-mode . lisp-indent)
|
|
|
|
(crystal-mode . crystal-tool-format)
|
|
|
|
(css-mode . prettier-css)
|
|
|
|
(css-ts-mode . prettier-css)
|
|
|
|
(dart-mode . dart-format)
|
|
|
|
(elixir-mode . mix-format)
|
|
|
|
(elixir-ts-mode . mix-format)
|
|
|
|
(elm-mode . elm-format)
|
|
|
|
(fish-mode . fish-indent)
|
|
|
|
(go-mode . gofmt)
|
|
|
|
(go-mod-ts-mode . gofmt)
|
|
|
|
(go-ts-mode . gofmt)
|
|
|
|
(graphql-mode . prettier-graphql)
|
|
|
|
(haskell-mode . brittany)
|
|
|
|
(html-mode . prettier-html)
|
|
|
|
(java-mode . google-java-format)
|
|
|
|
(java-ts-mode . google-java-format)
|
|
|
|
(js3-mode . prettier-javascript)
|
|
|
|
(js-mode . prettier-javascript)
|
|
|
|
(js-ts-mode . prettier-javascript)
|
|
|
|
(kotlin-mode . ktlint)
|
|
|
|
(latex-mode . latexindent)
|
|
|
|
(LaTeX-mode . latexindent)
|
|
|
|
(lua-mode . stylua)
|
|
|
|
(lisp-mode . lisp-indent)
|
2023-04-22 10:26:49 +01:00
|
|
|
(nasm-mode . asmfmt)
|
2023-04-20 10:52:25 +01:00
|
|
|
(nix-mode . nixfmt)
|
|
|
|
(purescript-mode . purs-tidy)
|
|
|
|
(python-mode . black)
|
|
|
|
(python-ts-mode . black)
|
|
|
|
(ruby-mode . prettier-ruby)
|
|
|
|
(ruby-ts-mode . prettier-ruby)
|
|
|
|
(rustic-mode . rustfmt)
|
|
|
|
(rust-mode . rustfmt)
|
|
|
|
(rust-ts-mode . rustfmt)
|
|
|
|
(scss-mode . prettier-scss)
|
|
|
|
(svelte-mode . prettier-svelte)
|
|
|
|
(terraform-mode . terraform)
|
|
|
|
(TeX-latex-mode . latexindent)
|
|
|
|
(TeX-mode . latexindent)
|
|
|
|
(tsx-ts-mode . prettier-typescript)
|
|
|
|
(tuareg-mode . ocamlformat)
|
|
|
|
(typescript-mode . prettier-typescript)
|
|
|
|
(typescript-ts-mode . prettier-typescript)
|
|
|
|
(web-mode . prettier)
|
|
|
|
(yaml-mode . prettier-yaml)
|
|
|
|
(yaml-ts-mode . prettier-yaml))
|
|
|
|
"Alist mapping major mode names to formatters to use in those modes.
|
|
|
|
This determines what formatter to use in buffers without a
|
|
|
|
setting for `apheleia-formatter'. The keys are major mode
|
|
|
|
symbols (matched against `major-mode' with `derived-mode-p') or
|
|
|
|
strings (matched against value of variable `buffer-file-name'
|
|
|
|
with `string-match-p'), and the values are symbols with entries
|
|
|
|
in `apheleia-formatters' (or equivalently, they are allowed
|
|
|
|
values for `apheleia-formatter'). Values can be a list of such
|
|
|
|
symnols causing each formatter in the list to be called one after
|
|
|
|
the other (with the output of the previous formatter).
|
|
|
|
Earlier entries in this variable take precedence over later ones.
|
|
|
|
|
|
|
|
Be careful when writing regexps to include \"\\'\" and to escape
|
|
|
|
\"\\.\" in order to properly match a file extension. For example,
|
|
|
|
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."
|
|
|
|
:type '(alist
|
|
|
|
:key-type
|
|
|
|
(choice (symbol :tag "Major mode")
|
|
|
|
(string :tag "Buffer name regexp"))
|
|
|
|
:value-type
|
|
|
|
(choice (symbol :tag "Formatter")
|
|
|
|
(repeat
|
|
|
|
(symbol :tag "Formatter"))))
|
|
|
|
:group 'apheleia)
|
|
|
|
|
2019-07-07 14:13:57 -07:00
|
|
|
(provide 'apheleia)
|
|
|
|
|
|
|
|
;;; apheleia.el ends here
|