Support non-file buffers (#52) (#59)

* Support non-file buffers (#52)

Closes #52

* Apply suggestions from code review

* Oops, my bad

Co-authored-by: Radon Rosborough <radon.neon@gmail.com>
This commit is contained in:
Mohsin Kaleem 2021-11-21 18:45:50 +00:00 committed by GitHub
parent 8e0605cc29
commit 2cf903e9a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 14 deletions

View file

@ -10,6 +10,7 @@ The format is based on [Keep a Changelog].
be run in sequence.
* Support evaluating items in `apheleia-formatters` to make formatter
commands more dynamic ([#50], [#55]).
* Allow apheleia to format buffers without an underlying file ([#52]).
### Formatters
* [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) for
@ -46,6 +47,7 @@ The format is based on [Keep a Changelog].
[#48]: https://github.com/raxod502/apheleia/pull/48
[#49]: https://github.com/raxod502/apheleia/pull/49
[#50]: https://github.com/raxod502/apheleia/pull/50
[#52]: https://github.com/raxod502/apheleia/issues/52
[#54]: https://github.com/raxod502/apheleia/pull/54
[#55]: https://github.com/raxod502/apheleia/issues/55

View file

@ -107,6 +107,18 @@ variables:
only when it is bound. Observe that one of these evaluations
returns a list of flags whereas the other returns a single
string. These are substituted into the command as you'd expect.
* You can also use Apheleia to format buffers that have no underlying
files. In this case the value of `file` and `filepath` will be
the name of the current buffer with any special characters for
the file-system (such as `*` on windows) being stripped out.
This is also how the extension for any temporary files apheleia
might create will be determined. If you're using a formatter
that determines the file-type from the extension you should name
such buffers such that their suffixed with the extension. For
example a buffer called `*foo-bar.c*` that has no associated
file will have an implicit file-name of `foo-bar.c` and any
temporary files will be suffixed with a `.c` extension.
* `apheleia-mode-alist`: Alist mapping major modes and filename
regexps to names of formatters to use in those modes and files. See
the docstring for more information.

View file

@ -27,6 +27,9 @@
(require 'map)
(require 'subr-x)
(eval-when-compile
(require 'rx))
(defgroup apheleia nil
"Reformat buffer without moving point."
:group 'external
@ -394,6 +397,15 @@ as its sole argument."
;; changes, and 2 if error.
(memq status '(0 1)))))))
(defun apheleia--safe-buffer-name ()
"Return `buffer-name' without special file-system characters."
;; See https://stackoverflow.com/q/1976007 for a list of supported
;; characters on all systems.
(replace-regexp-in-string
(rx (or "/" "<" ">" ":" "\"" "\\" "|" "?" "*"))
""
(buffer-name)))
(defun apheleia--format-command (command &optional stdin-buffer)
"Format COMMAND into a shell command and list of file paths.
Returns a list with the car being the optional input file-name, the
@ -435,9 +447,10 @@ cmd is to be run."
(when (memq 'input command)
(let ((input-fname (make-temp-file
"apheleia" nil
(and buffer-file-name
(file-name-extension
buffer-file-name 'period)))))
(when-let ((file-name
(or buffer-file-name
(apheleia--safe-buffer-name))))
(file-name-extension file-name 'period)))))
(with-current-buffer stdin
(apheleia--write-region-silently nil nil input-fname))
(setq command (mapcar (lambda (arg)
@ -458,15 +471,18 @@ cmd is to be run."
(when stdin-buffer
(error "Cannot run formatter using `file' or `filepath' in a \
sequence unless it's first in the sequence"))
(setq command (mapcar (lambda (arg)
(when (eq arg 'file)
(setq stdin nil))
(if (memq arg '(file filepath))
(prog1 buffer-file-name
(when (buffer-modified-p)
(cl-return)))
arg))
command)))
(let ((file-name (or buffer-file-name
(concat default-directory
(apheleia--safe-buffer-name)))))
(setq command (mapcar (lambda (arg)
(when (eq arg 'file)
(setq stdin nil))
(if (memq arg '(file filepath))
(prog1 file-name
(when (buffer-modified-p)
(cl-return)))
arg))
command))))
;; Evaluate each element of arg that isn't a string and replace
;; it with the evaluated value. The result of an evaluation should
;; be a string or a list of strings. If the former its replaced as
@ -772,8 +788,9 @@ operating, to prevent an infinite loop.")
commands
(lambda ()
(with-demoted-errors "Apheleia: %s"
(let ((apheleia--format-after-save-in-progress t))
(apheleia--write-file-silently buffer-file-name))
(when buffer-file-name
(let ((apheleia--format-after-save-in-progress t))
(apheleia--write-file-silently buffer-file-name)))
(run-hooks 'apheleia-post-format-hook))))))))
;; Use `progn' to force the entire minor mode definition to be copied