Giter Club home page Giter Club logo

emacs-reformatter's Introduction

Melpa Status Melpa Stable Status NonGNU ELPA Build Status Support me

Define commands which run reformatters on the current Emacs buffer

This library lets elisp authors easily define an idiomatic command to reformat the current buffer using a command-line program, together with an optional minor mode which can apply this command automatically on save.

By default, reformatter.el expects programs to read from stdin and write to stdout, and you should prefer this mode of operation where possible. If this isn't possible with your particular formatting program, refer to the options for reformatter-define, and see the examples in the package's tests.

In its initial release it supports only reformatters which can read from stdin and write to stdout, but a more versatile interface will be provided as development continues.

As an example, let's define a reformat command that applies the "dhall format" command. We'll assume here that we've already defined a variable dhall-command which holds the string name or path of the dhall executable:

(reformatter-define dhall-format
  :program dhall-command
  :args '("format")
  :lighter " DF")

The reformatter-define macro expands to code which generates dhall-format-buffer and dhall-format-region interactive commands, and a local minor mode called dhall-format-on-save-mode. The :args and :program expressions will be evaluated at runtime, so they can refer to variables that may (later) have a buffer-local value. A custom variable will be generated for the mode lighter, with the supplied value becoming the default.

The generated minor mode allows idiomatic per-directory or per-file customisation, via the "modes" support baked into Emacs' file-local and directory-local variables mechanisms. For example, users of the above example might add the following to a project-specific .dir-locals.el file:

((dhall-mode
   (mode . dhall-format-on-save)))

See the documentation for reformatter-define, which provides a number of options for customising the generated code.

Library authors might like to provide autoloads for the generated code, e.g.:

;;;###autoload (autoload 'dhall-format-buffer "current-file" nil t)
;;;###autoload (autoload 'dhall-format-region "current-file" nil t)
;;;###autoload (autoload 'dhall-format-on-save-mode "current-file" nil t)

Examples of usage in the wild

To find reverse dependencies, look for "Needed by" on the MELPA page for reformatter. Here are some specific examples:

Rationale

I contribute to a number of Emacs programming language modes and tools, and increasingly use code reformatters in my daily work. It's surprisingly difficult to write robust, correct code to apply these reformatters, given that it must consider such issues as:

  • Missing programs
  • Buffers not yet saved to a file
  • Displaying error output
  • Colorising ANSI escape sequences in any error output
  • Handling file encodings correctly

With this library, I hope to help the community standardise on best practices, and make things easier for tool authors and end users alike.

FAQ

How is this different from format-all.el?

format-all is a very different approach: it aims to provide a single minor mode which you then enable and configure to do the right thing (including nothing) for all the languages you use. It even tries to tell you how to install missing programs. It's an interesting project, but IMO it's hard to design the configuration for such a grand unified approach, and it can get complex. For example, you'd have to be able to configure which of two possible reformatters you want to use for a specific language, and to be able to do that on a per-project basis.

In contrast reformatter produces small, self-contained and separate formatters and minor modes which all work consistently and are individually configured. It makes it possible to replace existing formatter code, and it's also very convenient for users to define their own ad-hoc reformatter wrappers

Installation

Manual

Ensure reformatter.el is in a directory on your load-path, and add the following to your ~/.emacs or ~/.emacs.d/init.el:

(require 'reformatter)

MELPA

If you're an Emacs 24 user or you have a recent version of package.el you can install reformatter from the MELPA repository. The version of reformatter there will always be up-to-date.

About

Author: Steve Purcell

Homepage: https://github.com/purcell/emacs-reformatter


πŸ’ Support this project and my other Open Source work

πŸ’Ό LinkedIn profile

✍ sanityinc.com

🐦 @sanityinc

emacs-reformatter's People

Contributors

bcc32 avatar bradyt avatar dependabot[bot] avatar erickgnavar avatar kenranunderscore avatar peterwvj avatar purcell avatar wbolster avatar wyuenho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emacs-reformatter's Issues

Operate inplace on the original file

Hello,
clang-format has an option to give the header file, belonging to the current file a special treatment, e.g.:

#include "test.h"

#include <string>

given the file is test.cpp, the include is put on top and a newline is added.

Obviously, clang-format needs the file name for that to work and that's where my question about emacs-reformatter starts:

If I use:

(reformatter-define c++-clang-format
              :program "/usr/bin/clang-format-14"
              :stdin nil
              :stdout nil
              :args (list "--style=file" "-i" input-file)
            )

here, input-file will be some temp file and the required information is lost. Same problem, when I use stdin/stdout.

Is there a way to have the reformatter work inplace on the actual file?

Alternative

clang-format has the parameter --assume-filename:

clang-format-14 --style=file --assume-filename="test.cpp" < test.cpp 

produces the desired result. Is there a way I can access the original filename in the :args argument?

Thanks!

evil support

first of all, thanks for this package! i started writing something similar a while ago, parked it, and then reformatter.el appeared which is better than i could wish for. :)

that said, i'm interested in using this package with evil.

defining an evil operator (a special command that operates on a region of text) that calls a normal elisp command that operates on a range of text, looks like this:

(evil-define-operator foo-evil (beg end type)
  (interactive "<R>")
  (foo-region beg end))

what are your thoughts on having reformatter.el automatically define a command like the above when evil is available?

Allow reformatter to not output stdout

I'm having an issue when trying to create a formatter for styler for R.

 MyFile.R ⚠
────────────────────────────────────────
Status	Count	Legend
βœ” 	1	File unchanged.
β„Ή 	0	File changed.
βœ– 	0	Styling threw an error.
────────────────────────────────────────

Is written to the buffer.

(use-package reformatter
  :config
  (defconst Rscript-command "Rscript")
  (reformatter-define styler
    :program Rscript-command
    :args (list "--vanilla" "-e" (format "styler::style_file(%S)" buffer-file-name))
    :lighter " styler"))

Is there anyway to disable the stdout output?

Thanks!

remote support?

Local execution of commands may be different from remote, have you considered adding remote support, more specific tramp.

Support formatters with different working directories

I, unfortunately, have a formatter that requires it to be run from the project's root directory. In my hand-written formatter, I pass projectile-project-root to the started subprocess. reformatter.el doesn't seem to support this. Any way to implement this easily?

Collect errors from stdout also (i.e. not only from stderr)

Thank you for the nice code :)

I have a request for a workaround (or enhancement): some formatters / linters output warnings and errors on stdout (instead of stderr) even when their exit code is non-zero.

For instance, djlint

echo "<p>hi" | djlint -  --lint  2>/dev/null
H025 1:0 Tag seems to be an orphan. <p>
Linted 1 file, found 1 error.

Would it be possible, in case of errors, to dump both stderr and stdout in the error buffer?

Slow in some pathological cases

In the case of reformatting this Haskell file with ormolu v0.0.1.0, replacing the buffer contents takes an extraordinary and unacceptable amount of time (from 30s to many minutes), even though the formatter program itself executes quickly (< 0.25s).

Inputs/outputs are captured in this gist. They are somewhat pathological, in that the input source file is 64kb and the resulting diff is 36kb with 202 modified regions.

The problem is visible in Emacs 26.3: in Emacs > 26.1 we use Emacs' replace-buffer-contents function, which aims to preserve text properties, regions, markers etc. as much as possible during operations such as this. (The closest alternative insert-file-contents makes only limited attempts to do this, but generally preserves point quite effectively.)

It turns out that this is a known issue with replace-buffer-contents, which has even subsequently gained a new argument to limit execution time, after which it will revert to a simpler buffer content replacement method. This seems like a strange design choice.

The options for dealing with this in reformatter.el are, roughly:

  • Skip using replace-buffer-contents entirely. Most reformatting code "in the wild" does this anyway, of course, because it pre-dates replace-buffer-contents.
  • Use replace-buffer-contents only if it supports the time limit argument, and set the time limit to something like 0.5s. This makes the results somewhat nondeterministic, but may generally give the best results for users in the usual fast-replacement case. Here, also, the fallback behaviour may not work as well as just insert-file-contents, so this would require a little testing.
  • Use replace-buffer-contents only if the current file is sufficiently small, ie. unlikely to be pathological. This limit might be around 5kb.

I'd probably favour the first approach (ie. avoid replace-buffer-contents).

/cc @mrkkrp, who raised this issue, and @wbolster & @ludwigpacifici, who encouraged the use of replace-buffer-contents in #10.

Wrong on-save mode name

Hi,

first of all thanks for this package, it sure will come in handy.

I installed it from MELPA and configured it like this:

(use-package reformatter
  :ensure t
  :config
  (defconst mu-clojure-command "/usr/local/bin/clojure")

;;;###autoload (autoload 'zprint "current-file" nil t)
;;;###autoload (autoload 'zprint-on-save-mode "current-file" nil t)
  (reformatter-define zprint
    :program mu-clojure-command
    :args '("-A:zprint")))

I also added this to the .dir-locals.el of my Clojure project:

(clojure-mode
  (mode . zprint-on-save-mode))

Upon restarting Emacs, when I visit a .clj file I get:

Debugger entered--Lisp error: (void-function zprint-on-save-mode-mode)
  zprint-on-save-mode-mode()
  #f(compiled-function (var val) "Set local variable VAR with value VAL.\nIf VAR is `mode', call `VAL-mode' as a function unless it's\nalready the major mode." #<bytecode 0x234b99>)(mode zprint-on-save-mode)
  ad-Advice-hack-one-local-variable(#f(compiled-function (var val) "Set local variable VAR with value VAL.\nIf VAR is `mode', call `VAL-mode' as a function unless it's\nalready the major mode." #<bytecode 0x234b99>) mode zprint-on-save-mode)
  apply(ad-Advice-hack-one-local-variable #f(compiled-function (var val) "Set local variable VAR with value VAL.\nIf VAR is `mode', call `VAL-mode' as a function unless it's\nalready the major mode." #<bytecode 0x234b99>) (mode zprint-on-save-mode))
  hack-one-local-variable(mode zprint-on-save-mode)
  hack-local-variables-apply()
  hack-local-variables(no-mode)
  run-mode-hooks(clojure-mode-hook)
  clojure-mode()
  set-auto-mode-0(clojure-mode nil)
  set-auto-mode()
  normal-mode(t)
  after-find-file(nil t)
  find-file-noselect-1(#<buffer aim.clj> "~/githubs/manuel-uberti/boodle/src/clj/boodle/api/..." nil nil "~/githubs/manuel-uberti/boodle/src/clj/boodle/api/..." (18088185 66306))
  find-file-noselect("/home/manuel/githubs/manuel-uberti/boodle/src/clj/..." nil nil nil)
  find-file("/home/manuel/githubs/manuel-uberti/boodle/src/clj/...")
  counsel-projectile-find-file-action("src/clj/boodle/api/resources/aim.clj")
  counsel-projectile-action("src/clj/boodle/api/resources/aim.clj")
  ivy-call()
  #f(compiled-function (arg1 arg2 &rest rest) "Read a string in the minibuffer, with completion.\n\nPROMPT is a string, normally ending in a colon and a space.\n`ivy-count-format' is prepended to PROMPT during completion.\n\nCOLLECTION is either a list of strings, a function, an alist, or\na hash table.\n\nPREDICATE is applied to filter out the COLLECTION immediately.\nThis argument is for compatibility with `completing-read'.\n\nWhen REQUIRE-MATCH is non-nil, only members of COLLECTION can be\nselected.\n\nIf INITIAL-INPUT is non-nil, then insert that input in the\nminibuffer initially.\n\nHISTORY is a name of a variable to hold the completion session\nhistory.\n\nKEYMAP is composed with `ivy-minibuffer-map'.\n\nIf PRESELECT is not nil, then select the corresponding candidate\nout of the ones that match the INITIAL-INPUT.\n\nDEF is for compatibility with `completing-read'.\n\nUPDATE-FN is called each time the candidate list is redisplayed.\n\nWhen SORT is non-nil, `ivy-sort-functions-alist' determines how\nto sort candidates before displaying them.\n\nACTION is a function to call after selecting a candidate.\nIt takes the candidate, which is a string, as its only argument.\n\nUNWIND is a function of no arguments to call before exiting.\n\nRE-BUILDER is a function transforming input text into a regex\npattern.\n\nMATCHER is a function which can override how candidates are\nfiltered based on user input.  It takes a regex pattern and a\nlist of candidates, and returns the list of matching candidates.\n\nDYNAMIC-COLLECTION is a boolean specifying whether the list of\ncandidates is updated after each input by calling COLLECTION.\n\nCALLER is a symbol to uniquely identify the caller to `ivy-read'.\nIt is used, along with COLLECTION, to determine which\ncustomizations apply to the current completion session." #<bytecode 0x11188e1>)("[boodle] Load buffer or file: " counsel-projectile--project-buffers-and-files :matcher counsel-projectile--matcher :require-match t :action (1 ("o" counsel-projectile-action "current window") ("j" counsel-projectile-action-other-window "other window") ("k" counsel-projectile-action-kill-delete "kill buffer / delete-file") ("x" counsel-projectile-action-file-extern "open file externally") ("r" counsel-projectile-action-file-root "open file as root") ("m" counsel-projectile-action-find-file-manually "find file manually") ("p" counsel-projectile-action-switch-project "switch project")) :keymap (keymap (3 keymap (11 . #f(compiled-function () (interactive nil) #<bytecode 0x1ad16f5>)))) :caller counsel-projectile)
  apply(#f(compiled-function (arg1 arg2 &rest rest) "Read a string in the minibuffer, with completion.\n\nPROMPT is a string, normally ending in a colon and a space.\n`ivy-count-format' is prepended to PROMPT during completion.\n\nCOLLECTION is either a list of strings, a function, an alist, or\na hash table.\n\nPREDICATE is applied to filter out the COLLECTION immediately.\nThis argument is for compatibility with `completing-read'.\n\nWhen REQUIRE-MATCH is non-nil, only members of COLLECTION can be\nselected.\n\nIf INITIAL-INPUT is non-nil, then insert that input in the\nminibuffer initially.\n\nHISTORY is a name of a variable to hold the completion session\nhistory.\n\nKEYMAP is composed with `ivy-minibuffer-map'.\n\nIf PRESELECT is not nil, then select the corresponding candidate\nout of the ones that match the INITIAL-INPUT.\n\nDEF is for compatibility with `completing-read'.\n\nUPDATE-FN is called each time the candidate list is redisplayed.\n\nWhen SORT is non-nil, `ivy-sort-functions-alist' determines how\nto sort candidates before displaying them.\n\nACTION is a function to call after selecting a candidate.\nIt takes the candidate, which is a string, as its only argument.\n\nUNWIND is a function of no arguments to call before exiting.\n\nRE-BUILDER is a function transforming input text into a regex\npattern.\n\nMATCHER is a function which can override how candidates are\nfiltered based on user input.  It takes a regex pattern and a\nlist of candidates, and returns the list of matching candidates.\n\nDYNAMIC-COLLECTION is a boolean specifying whether the list of\ncandidates is updated after each input by calling COLLECTION.\n\nCALLER is a symbol to uniquely identify the caller to `ivy-read'.\nIt is used, along with COLLECTION, to determine which\ncustomizations apply to the current completion session." #<bytecode 0x11188e1>) ("[boodle] Load buffer or file: " counsel-projectile--project-buffers-and-files :matcher counsel-projectile--matcher :require-match t :action (1 ("o" counsel-projectile-action "current window") ("j" counsel-projectile-action-other-window "other window") ("k" counsel-projectile-action-kill-delete "kill buffer / delete-file") ("x" counsel-projectile-action-file-extern "open file externally") ("r" counsel-projectile-action-file-root "open file as root") ("m" counsel-projectile-action-find-file-manually "find file manually") ("p" counsel-projectile-action-switch-project "switch project")) :keymap (keymap (3 keymap (11 . #f(compiled-function () (interactive nil) #<bytecode 0x1ad16f5>)))) :caller counsel-projectile))
  ivy-historian--nadvice/ivy-read(#f(compiled-function (arg1 arg2 &rest rest) "Read a string in the minibuffer, with completion.\n\nPROMPT is a string, normally ending in a colon and a space.\n`ivy-count-format' is prepended to PROMPT during completion.\n\nCOLLECTION is either a list of strings, a function, an alist, or\na hash table.\n\nPREDICATE is applied to filter out the COLLECTION immediately.\nThis argument is for compatibility with `completing-read'.\n\nWhen REQUIRE-MATCH is non-nil, only members of COLLECTION can be\nselected.\n\nIf INITIAL-INPUT is non-nil, then insert that input in the\nminibuffer initially.\n\nHISTORY is a name of a variable to hold the completion session\nhistory.\n\nKEYMAP is composed with `ivy-minibuffer-map'.\n\nIf PRESELECT is not nil, then select the corresponding candidate\nout of the ones that match the INITIAL-INPUT.\n\nDEF is for compatibility with `completing-read'.\n\nUPDATE-FN is called each time the candidate list is redisplayed.\n\nWhen SORT is non-nil, `ivy-sort-functions-alist' determines how\nto sort candidates before displaying them.\n\nACTION is a function to call after selecting a candidate.\nIt takes the candidate, which is a string, as its only argument.\n\nUNWIND is a function of no arguments to call before exiting.\n\nRE-BUILDER is a function transforming input text into a regex\npattern.\n\nMATCHER is a function which can override how candidates are\nfiltered based on user input.  It takes a regex pattern and a\nlist of candidates, and returns the list of matching candidates.\n\nDYNAMIC-COLLECTION is a boolean specifying whether the list of\ncandidates is updated after each input by calling COLLECTION.\n\nCALLER is a symbol to uniquely identify the caller to `ivy-read'.\nIt is used, along with COLLECTION, to determine which\ncustomizations apply to the current completion session." #<bytecode 0x11188e1>) "[boodle] Load buffer or file: " counsel-projectile--project-buffers-and-files :matcher counsel-projectile--matcher :require-match t :action (1 ("o" counsel-projectile-action "current window") ("j" counsel-projectile-action-other-window "other window") ("k" counsel-projectile-action-kill-delete "kill buffer / delete-file") ("x" counsel-projectile-action-file-extern "open file externally") ("r" counsel-projectile-action-file-root "open file as root") ("m" counsel-projectile-action-find-file-manually "find file manually") ("p" counsel-projectile-action-switch-project "switch project")) :keymap (keymap (3 keymap (11 . #f(compiled-function () (interactive nil) #<bytecode 0x1ad16f5>)))) :caller counsel-projectile)
  apply(ivy-historian--nadvice/ivy-read #f(compiled-function (arg1 arg2 &rest rest) "Read a string in the minibuffer, with completion.\n\nPROMPT is a string, normally ending in a colon and a space.\n`ivy-count-format' is prepended to PROMPT during completion.\n\nCOLLECTION is either a list of strings, a function, an alist, or\na hash table.\n\nPREDICATE is applied to filter out the COLLECTION immediately.\nThis argument is for compatibility with `completing-read'.\n\nWhen REQUIRE-MATCH is non-nil, only members of COLLECTION can be\nselected.\n\nIf INITIAL-INPUT is non-nil, then insert that input in the\nminibuffer initially.\n\nHISTORY is a name of a variable to hold the completion session\nhistory.\n\nKEYMAP is composed with `ivy-minibuffer-map'.\n\nIf PRESELECT is not nil, then select the corresponding candidate\nout of the ones that match the INITIAL-INPUT.\n\nDEF is for compatibility with `completing-read'.\n\nUPDATE-FN is called each time the candidate list is redisplayed.\n\nWhen SORT is non-nil, `ivy-sort-functions-alist' determines how\nto sort candidates before displaying them.\n\nACTION is a function to call after selecting a candidate.\nIt takes the candidate, which is a string, as its only argument.\n\nUNWIND is a function of no arguments to call before exiting.\n\nRE-BUILDER is a function transforming input text into a regex\npattern.\n\nMATCHER is a function which can override how candidates are\nfiltered based on user input.  It takes a regex pattern and a\nlist of candidates, and returns the list of matching candidates.\n\nDYNAMIC-COLLECTION is a boolean specifying whether the list of\ncandidates is updated after each input by calling COLLECTION.\n\nCALLER is a symbol to uniquely identify the caller to `ivy-read'.\nIt is used, along with COLLECTION, to determine which\ncustomizations apply to the current completion session." #<bytecode 0x11188e1>) ("[boodle] Load buffer or file: " counsel-projectile--project-buffers-and-files :matcher counsel-projectile--matcher :require-match t :action (1 ("o" counsel-projectile-action "current window") ("j" counsel-projectile-action-other-window "other window") ("k" counsel-projectile-action-kill-delete "kill buffer / delete-file") ("x" counsel-projectile-action-file-extern "open file externally") ("r" counsel-projectile-action-file-root "open file as root") ("m" counsel-projectile-action-find-file-manually "find file manually") ("p" counsel-projectile-action-switch-project "switch project")) :keymap (keymap (3 keymap (11 . #f(compiled-function () (interactive nil) #<bytecode 0x1ad16f5>)))) :caller counsel-projectile))
  ivy-read("[boodle] Load buffer or file: " counsel-projectile--project-buffers-and-files :matcher counsel-projectile--matcher :require-match t :action (1 ("o" counsel-projectile-action "current window") ("j" counsel-projectile-action-other-window "other window") ("k" counsel-projectile-action-kill-delete "kill buffer / delete-file") ("x" counsel-projectile-action-file-extern "open file externally") ("r" counsel-projectile-action-file-root "open file as root") ("m" counsel-projectile-action-find-file-manually "find file manually") ("p" counsel-projectile-action-switch-project "switch project")) :keymap (keymap (3 keymap (11 . #f(compiled-function () (interactive nil) #<bytecode 0x1ad16f5>)))) :caller counsel-projectile)
  counsel-projectile(nil)
  #f(compiled-function () #<bytecode 0x1ad07ad>)()
  counsel-projectile-switch-project-by-name("~/githubs/manuel-uberti/boodle/")
  counsel-projectile-switch-project-action("~/githubs/manuel-uberti/boodle/")
  ivy-call()
  #f(compiled-function (arg1 arg2 &rest rest) "Read a string in the minibuffer, with completion.\n\nPROMPT is a string, normally ending in a colon and a space.\n`ivy-count-format' is prepended to PROMPT during completion.\n\nCOLLECTION is either a list of strings, a function, an alist, or\na hash table.\n\nPREDICATE is applied to filter out the COLLECTION immediately.\nThis argument is for compatibility with `completing-read'.\n\nWhen REQUIRE-MATCH is non-nil, only members of COLLECTION can be\nselected.\n\nIf INITIAL-INPUT is non-nil, then insert that input in the\nminibuffer initially.\n\nHISTORY is a name of a variable to hold the completion session\nhistory.\n\nKEYMAP is composed with `ivy-minibuffer-map'.\n\nIf PRESELECT is not nil, then select the corresponding candidate\nout of the ones that match the INITIAL-INPUT.\n\nDEF is for compatibility with `completing-read'.\n\nUPDATE-FN is called each time the candidate list is redisplayed.\n\nWhen SORT is non-nil, `ivy-sort-functions-alist' determines how\nto sort candidates before displaying them.\n\nACTION is a function to call after selecting a candidate.\nIt takes the candidate, which is a string, as its only argument.\n\nUNWIND is a function of no arguments to call before exiting.\n\nRE-BUILDER is a function transforming input text into a regex\npattern.\n\nMATCHER is a function which can override how candidates are\nfiltered based on user input.  It takes a regex pattern and a\nlist of candidates, and returns the list of matching candidates.\n\nDYNAMIC-COLLECTION is a boolean specifying whether the list of\ncandidates is updated after each input by calling COLLECTION.\n\nCALLER is a symbol to uniquely identify the caller to `ivy-read'.\nIt is used, along with COLLECTION, to determine which\ncustomizations apply to the current completion session." #<bytecode 0x11188e1>)("[-] Switch to project: " ("~/.emacs.d/" "~/githubs/manuel-uberti/boodle/" "~/org/" "~/githubs/manuel-uberti/playbooks/" "~/githubs/manuel-uberti/manuel-uberti.github.io/" "~/7bridges/code/langohr-example/" "~/githubs/manuel-uberti/filmsinwords/" "~/7bridges/code/antigone/" "~/7bridges/code/routing-channels/" "~/.config/fish/" "~/7bridges/code/sage-graph/" "~/7bridges/code/clj-graph/" "~/7bridges/code/sage-etl/" "~/7bridges/code/ethanol/" "~/githubs/manuel-uberti/newtab/" "~/7bridges/code/gaypa-hr/" "~/githubs/manuel-uberti/stash/" "~/emacs/" "~/7bridges/code/gaypa-docs/" "~/7bridges/code/playbooks/" "~/7bridges/code/onyx-test/" "~/githubs/learn-onyx/" "~/7bridges/code/filmango/" "~/7bridges/code/chronicler/" "~/7bridges/code/onyx-dashboard/" "~/7bridges/code/clj-odbp/" "~/7bridges/code/maurice/" "~/.clojure/" "~/7bridges/code/7bv2/" "~/7bridges/code/onyx-test-bak/" "~/Documents/curriculum/Awesome-CV/" "~/7bridges/code/sage-soap/" "~/githubs/manuel-uberti/four-clojure/" "~/githubs/manuel-uberti/haskell-programming/" "~/7bridges/code/exoscale/") :preselect nil :action (1 ("o" counsel-projectile-switch-project-action "jump to a project buffer or file") ("f" counsel-projectile-switch-project-action-find-file "jump to a project file") ("d" counsel-projectile-switch-project-action-find-dir "jump to a project directory") ("D" counsel-projectile-switch-project-action-dired "open project in dired") ("b" counsel-projectile-switch-project-action-switch-to-buffer "jump to a project buffer") ("m" counsel-projectile-switch-project-action-find-file-manually "find file manually from project root") ("S" counsel-projectile-switch-project-action-save-all-buffers "save all project buffers") ("k" counsel-projectile-switch-project-action-kill-buffers "kill all project buffers") ("K" counsel-projectile-switch-project-action-remove-known-project "remove project from known projects") ("c" counsel-projectile-switch-project-action-compile "run project compilation command") ("C" counsel-projectile-switch-project-action-configure "run project configure command") ("E" counsel-projectile-switch-project-action-edit-dir-locals "edit project dir-locals") ("v" counsel-projectile-switch-project-action-vc "open project in vc-dir / magit / monky") ("sg" counsel-projectile-switch-project-action-grep "search project with grep") ("si" counsel-projectile-switch-project-action-git-grep "search project with git grep") ("ss" counsel-projectile-switch-project-action-ag "search project with ag") ("sr" counsel-projectile-switch-project-action-rg "search project with rg") ("xs" counsel-projectile-switch-project-action-run-shell "invoke shell from project root") ("xe" counsel-projectile-switch-project-action-run-eshell "invoke eshell from project root") ("xt" counsel-projectile-switch-project-action-run-term "invoke term from project root") ("Oc" counsel-projectile-switch-project-action-org-capture "capture into project") ("Oa" counsel-projectile-switch-project-action-org-agenda "open project agenda")) :require-match t :sort nil :caller counsel-projectile-switch-project)
  apply(#f(compiled-function (arg1 arg2 &rest rest) "Read a string in the minibuffer, with completion.\n\nPROMPT is a string, normally ending in a colon and a space.\n`ivy-count-format' is prepended to PROMPT during completion.\n\nCOLLECTION is either a list of strings, a function, an alist, or\na hash table.\n\nPREDICATE is applied to filter out the COLLECTION immediately.\nThis argument is for compatibility with `completing-read'.\n\nWhen REQUIRE-MATCH is non-nil, only members of COLLECTION can be\nselected.\n\nIf INITIAL-INPUT is non-nil, then insert that input in the\nminibuffer initially.\n\nHISTORY is a name of a variable to hold the completion session\nhistory.\n\nKEYMAP is composed with `ivy-minibuffer-map'.\n\nIf PRESELECT is not nil, then select the corresponding candidate\nout of the ones that match the INITIAL-INPUT.\n\nDEF is for compatibility with `completing-read'.\n\nUPDATE-FN is called each time the candidate list is redisplayed.\n\nWhen SORT is non-nil, `ivy-sort-functions-alist' determines how\nto sort candidates before displaying them.\n\nACTION is a function to call after selecting a candidate.\nIt takes the candidate, which is a string, as its only argument.\n\nUNWIND is a function of no arguments to call before exiting.\n\nRE-BUILDER is a function transforming input text into a regex\npattern.\n\nMATCHER is a function which can override how candidates are\nfiltered based on user input.  It takes a regex pattern and a\nlist of candidates, and returns the list of matching candidates.\n\nDYNAMIC-COLLECTION is a boolean specifying whether the list of\ncandidates is updated after each input by calling COLLECTION.\n\nCALLER is a symbol to uniquely identify the caller to `ivy-read'.\nIt is used, along with COLLECTION, to determine which\ncustomizations apply to the current completion session." #<bytecode 0x11188e1>) ("[-] Switch to project: " ("~/.emacs.d/" "~/githubs/manuel-uberti/boodle/" "~/org/" "~/githubs/manuel-uberti/playbooks/" "~/githubs/manuel-uberti/manuel-uberti.github.io/" "~/7bridges/code/langohr-example/" "~/githubs/manuel-uberti/filmsinwords/" "~/7bridges/code/antigone/" "~/7bridges/code/routing-channels/" "~/.config/fish/" "~/7bridges/code/sage-graph/" "~/7bridges/code/clj-graph/" "~/7bridges/code/sage-etl/" "~/7bridges/code/ethanol/" "~/githubs/manuel-uberti/newtab/" "~/7bridges/code/gaypa-hr/" "~/githubs/manuel-uberti/stash/" "~/emacs/" "~/7bridges/code/gaypa-docs/" "~/7bridges/code/playbooks/" "~/7bridges/code/onyx-test/" "~/githubs/learn-onyx/" "~/7bridges/code/filmango/" "~/7bridges/code/chronicler/" "~/7bridges/code/onyx-dashboard/" "~/7bridges/code/clj-odbp/" "~/7bridges/code/maurice/" "~/.clojure/" "~/7bridges/code/7bv2/" "~/7bridges/code/onyx-test-bak/" "~/Documents/curriculum/Awesome-CV/" "~/7bridges/code/sage-soap/" "~/githubs/manuel-uberti/four-clojure/" "~/githubs/manuel-uberti/haskell-programming/" "~/7bridges/code/exoscale/") :preselect nil :action (1 ("o" counsel-projectile-switch-project-action "jump to a project buffer or file") ("f" counsel-projectile-switch-project-action-find-file "jump to a project file") ("d" counsel-projectile-switch-project-action-find-dir "jump to a project directory") ("D" counsel-projectile-switch-project-action-dired "open project in dired") ("b" counsel-projectile-switch-project-action-switch-to-buffer "jump to a project buffer") ("m" counsel-projectile-switch-project-action-find-file-manually "find file manually from project root") ("S" counsel-projectile-switch-project-action-save-all-buffers "save all project buffers") ("k" counsel-projectile-switch-project-action-kill-buffers "kill all project buffers") ("K" counsel-projectile-switch-project-action-remove-known-project "remove project from known projects") ("c" counsel-projectile-switch-project-action-compile "run project compilation command") ("C" counsel-projectile-switch-project-action-configure "run project configure command") ("E" counsel-projectile-switch-project-action-edit-dir-locals "edit project dir-locals") ("v" counsel-projectile-switch-project-action-vc "open project in vc-dir / magit / monky") ("sg" counsel-projectile-switch-project-action-grep "search project with grep") ("si" counsel-projectile-switch-project-action-git-grep "search project with git grep") ("ss" counsel-projectile-switch-project-action-ag "search project with ag") ("sr" counsel-projectile-switch-project-action-rg "search project with rg") ("xs" counsel-projectile-switch-project-action-run-shell "invoke shell from project root") ("xe" counsel-projectile-switch-project-action-run-eshell "invoke eshell from project root") ("xt" counsel-projectile-switch-project-action-run-term "invoke term from project root") ("Oc" counsel-projectile-switch-project-action-org-capture "capture into project") ("Oa" counsel-projectile-switch-project-action-org-agenda "open project agenda")) :require-match t :sort nil :caller counsel-projectile-switch-project))
  ivy-historian--nadvice/ivy-read(#f(compiled-function (arg1 arg2 &rest rest) "Read a string in the minibuffer, with completion.\n\nPROMPT is a string, normally ending in a colon and a space.\n`ivy-count-format' is prepended to PROMPT during completion.\n\nCOLLECTION is either a list of strings, a function, an alist, or\na hash table.\n\nPREDICATE is applied to filter out the COLLECTION immediately.\nThis argument is for compatibility with `completing-read'.\n\nWhen REQUIRE-MATCH is non-nil, only members of COLLECTION can be\nselected.\n\nIf INITIAL-INPUT is non-nil, then insert that input in the\nminibuffer initially.\n\nHISTORY is a name of a variable to hold the completion session\nhistory.\n\nKEYMAP is composed with `ivy-minibuffer-map'.\n\nIf PRESELECT is not nil, then select the corresponding candidate\nout of the ones that match the INITIAL-INPUT.\n\nDEF is for compatibility with `completing-read'.\n\nUPDATE-FN is called each time the candidate list is redisplayed.\n\nWhen SORT is non-nil, `ivy-sort-functions-alist' determines how\nto sort candidates before displaying them.\n\nACTION is a function to call after selecting a candidate.\nIt takes the candidate, which is a string, as its only argument.\n\nUNWIND is a function of no arguments to call before exiting.\n\nRE-BUILDER is a function transforming input text into a regex\npattern.\n\nMATCHER is a function which can override how candidates are\nfiltered based on user input.  It takes a regex pattern and a\nlist of candidates, and returns the list of matching candidates.\n\nDYNAMIC-COLLECTION is a boolean specifying whether the list of\ncandidates is updated after each input by calling COLLECTION.\n\nCALLER is a symbol to uniquely identify the caller to `ivy-read'.\nIt is used, along with COLLECTION, to determine which\ncustomizations apply to the current completion session." #<bytecode 0x11188e1>) "[-] Switch to project: " ("~/.emacs.d/" "~/githubs/manuel-uberti/boodle/" "~/org/" "~/githubs/manuel-uberti/playbooks/" "~/githubs/manuel-uberti/manuel-uberti.github.io/" "~/7bridges/code/langohr-example/" "~/githubs/manuel-uberti/filmsinwords/" "~/7bridges/code/antigone/" "~/7bridges/code/routing-channels/" "~/.config/fish/" "~/7bridges/code/sage-graph/" "~/7bridges/code/clj-graph/" "~/7bridges/code/sage-etl/" "~/7bridges/code/ethanol/" "~/githubs/manuel-uberti/newtab/" "~/7bridges/code/gaypa-hr/" "~/githubs/manuel-uberti/stash/" "~/emacs/" "~/7bridges/code/gaypa-docs/" "~/7bridges/code/playbooks/" "~/7bridges/code/onyx-test/" "~/githubs/learn-onyx/" "~/7bridges/code/filmango/" "~/7bridges/code/chronicler/" "~/7bridges/code/onyx-dashboard/" "~/7bridges/code/clj-odbp/" "~/7bridges/code/maurice/" "~/.clojure/" "~/7bridges/code/7bv2/" "~/7bridges/code/onyx-test-bak/" "~/Documents/curriculum/Awesome-CV/" "~/7bridges/code/sage-soap/" "~/githubs/manuel-uberti/four-clojure/" "~/githubs/manuel-uberti/haskell-programming/" "~/7bridges/code/exoscale/") :preselect nil :action (1 ("o" counsel-projectile-switch-project-action "jump to a project buffer or file") ("f" counsel-projectile-switch-project-action-find-file "jump to a project file") ("d" counsel-projectile-switch-project-action-find-dir "jump to a project directory") ("D" counsel-projectile-switch-project-action-dired "open project in dired") ("b" counsel-projectile-switch-project-action-switch-to-buffer "jump to a project buffer") ("m" counsel-projectile-switch-project-action-find-file-manually "find file manually from project root") ("S" counsel-projectile-switch-project-action-save-all-buffers "save all project buffers") ("k" counsel-projectile-switch-project-action-kill-buffers "kill all project buffers") ("K" counsel-projectile-switch-project-action-remove-known-project "remove project from known projects") ("c" counsel-projectile-switch-project-action-compile "run project compilation command") ("C" counsel-projectile-switch-project-action-configure "run project configure command") ("E" counsel-projectile-switch-project-action-edit-dir-locals "edit project dir-locals") ("v" counsel-projectile-switch-project-action-vc "open project in vc-dir / magit / monky") ("sg" counsel-projectile-switch-project-action-grep "search project with grep") ("si" counsel-projectile-switch-project-action-git-grep "search project with git grep") ("ss" counsel-projectile-switch-project-action-ag "search project with ag") ("sr" counsel-projectile-switch-project-action-rg "search project with rg") ("xs" counsel-projectile-switch-project-action-run-shell "invoke shell from project root") ("xe" counsel-projectile-switch-project-action-run-eshell "invoke eshell from project root") ("xt" counsel-projectile-switch-project-action-run-term "invoke term from project root") ("Oc" counsel-projectile-switch-project-action-org-capture "capture into project") ("Oa" counsel-projectile-switch-project-action-org-agenda "open project agenda")) :require-match t :sort nil :caller counsel-projectile-switch-project)
  apply(ivy-historian--nadvice/ivy-read #f(compiled-function (arg1 arg2 &rest rest) "Read a string in the minibuffer, with completion.\n\nPROMPT is a string, normally ending in a colon and a space.\n`ivy-count-format' is prepended to PROMPT during completion.\n\nCOLLECTION is either a list of strings, a function, an alist, or\na hash table.\n\nPREDICATE is applied to filter out the COLLECTION immediately.\nThis argument is for compatibility with `completing-read'.\n\nWhen REQUIRE-MATCH is non-nil, only members of COLLECTION can be\nselected.\n\nIf INITIAL-INPUT is non-nil, then insert that input in the\nminibuffer initially.\n\nHISTORY is a name of a variable to hold the completion session\nhistory.\n\nKEYMAP is composed with `ivy-minibuffer-map'.\n\nIf PRESELECT is not nil, then select the corresponding candidate\nout of the ones that match the INITIAL-INPUT.\n\nDEF is for compatibility with `completing-read'.\n\nUPDATE-FN is called each time the candidate list is redisplayed.\n\nWhen SORT is non-nil, `ivy-sort-functions-alist' determines how\nto sort candidates before displaying them.\n\nACTION is a function to call after selecting a candidate.\nIt takes the candidate, which is a string, as its only argument.\n\nUNWIND is a function of no arguments to call before exiting.\n\nRE-BUILDER is a function transforming input text into a regex\npattern.\n\nMATCHER is a function which can override how candidates are\nfiltered based on user input.  It takes a regex pattern and a\nlist of candidates, and returns the list of matching candidates.\n\nDYNAMIC-COLLECTION is a boolean specifying whether the list of\ncandidates is updated after each input by calling COLLECTION.\n\nCALLER is a symbol to uniquely identify the caller to `ivy-read'.\nIt is used, along with COLLECTION, to determine which\ncustomizations apply to the current completion session." #<bytecode 0x11188e1>) ("[-] Switch to project: " ("~/.emacs.d/" "~/githubs/manuel-uberti/boodle/" "~/org/" "~/githubs/manuel-uberti/playbooks/" "~/githubs/manuel-uberti/manuel-uberti.github.io/" "~/7bridges/code/langohr-example/" "~/githubs/manuel-uberti/filmsinwords/" "~/7bridges/code/antigone/" "~/7bridges/code/routing-channels/" "~/.config/fish/" "~/7bridges/code/sage-graph/" "~/7bridges/code/clj-graph/" "~/7bridges/code/sage-etl/" "~/7bridges/code/ethanol/" "~/githubs/manuel-uberti/newtab/" "~/7bridges/code/gaypa-hr/" "~/githubs/manuel-uberti/stash/" "~/emacs/" "~/7bridges/code/gaypa-docs/" "~/7bridges/code/playbooks/" "~/7bridges/code/onyx-test/" "~/githubs/learn-onyx/" "~/7bridges/code/filmango/" "~/7bridges/code/chronicler/" "~/7bridges/code/onyx-dashboard/" "~/7bridges/code/clj-odbp/" "~/7bridges/code/maurice/" "~/.clojure/" "~/7bridges/code/7bv2/" "~/7bridges/code/onyx-test-bak/" "~/Documents/curriculum/Awesome-CV/" "~/7bridges/code/sage-soap/" "~/githubs/manuel-uberti/four-clojure/" "~/githubs/manuel-uberti/haskell-programming/" "~/7bridges/code/exoscale/") :preselect nil :action (1 ("o" counsel-projectile-switch-project-action "jump to a project buffer or file") ("f" counsel-projectile-switch-project-action-find-file "jump to a project file") ("d" counsel-projectile-switch-project-action-find-dir "jump to a project directory") ("D" counsel-projectile-switch-project-action-dired "open project in dired") ("b" counsel-projectile-switch-project-action-switch-to-buffer "jump to a project buffer") ("m" counsel-projectile-switch-project-action-find-file-manually "find file manually from project root") ("S" counsel-projectile-switch-project-action-save-all-buffers "save all project buffers") ("k" counsel-projectile-switch-project-action-kill-buffers "kill all project buffers") ("K" counsel-projectile-switch-project-action-remove-known-project "remove project from known projects") ("c" counsel-projectile-switch-project-action-compile "run project compilation command") ("C" counsel-projectile-switch-project-action-configure "run project configure command") ("E" counsel-projectile-switch-project-action-edit-dir-locals "edit project dir-locals") ("v" counsel-projectile-switch-project-action-vc "open project in vc-dir / magit / monky") ("sg" counsel-projectile-switch-project-action-grep "search project with grep") ("si" counsel-projectile-switch-project-action-git-grep "search project with git grep") ("ss" counsel-projectile-switch-project-action-ag "search project with ag") ("sr" counsel-projectile-switch-project-action-rg "search project with rg") ("xs" counsel-projectile-switch-project-action-run-shell "invoke shell from project root") ("xe" counsel-projectile-switch-project-action-run-eshell "invoke eshell from project root") ("xt" counsel-projectile-switch-project-action-run-term "invoke term from project root") ("Oc" counsel-projectile-switch-project-action-org-capture "capture into project") ("Oa" counsel-projectile-switch-project-action-org-agenda "open project agenda")) :require-match t :sort nil :caller counsel-projectile-switch-project))
  ivy-read("[-] Switch to project: " ("~/.emacs.d/" "~/githubs/manuel-uberti/boodle/" "~/org/" "~/githubs/manuel-uberti/playbooks/" "~/githubs/manuel-uberti/manuel-uberti.github.io/" "~/7bridges/code/langohr-example/" "~/githubs/manuel-uberti/filmsinwords/" "~/7bridges/code/antigone/" "~/7bridges/code/routing-channels/" "~/.config/fish/" "~/7bridges/code/sage-graph/" "~/7bridges/code/clj-graph/" "~/7bridges/code/sage-etl/" "~/7bridges/code/ethanol/" "~/githubs/manuel-uberti/newtab/" "~/7bridges/code/gaypa-hr/" "~/githubs/manuel-uberti/stash/" "~/emacs/" "~/7bridges/code/gaypa-docs/" "~/7bridges/code/playbooks/" "~/7bridges/code/onyx-test/" "~/githubs/learn-onyx/" "~/7bridges/code/filmango/" "~/7bridges/code/chronicler/" "~/7bridges/code/onyx-dashboard/" "~/7bridges/code/clj-odbp/" "~/7bridges/code/maurice/" "~/.clojure/" "~/7bridges/code/7bv2/" "~/7bridges/code/onyx-test-bak/" "~/Documents/curriculum/Awesome-CV/" "~/7bridges/code/sage-soap/" "~/githubs/manuel-uberti/four-clojure/" "~/githubs/manuel-uberti/haskell-programming/" "~/7bridges/code/exoscale/") :preselect nil :action (1 ("o" counsel-projectile-switch-project-action "jump to a project buffer or file") ("f" counsel-projectile-switch-project-action-find-file "jump to a project file") ("d" counsel-projectile-switch-project-action-find-dir "jump to a project directory") ("D" counsel-projectile-switch-project-action-dired "open project in dired") ("b" counsel-projectile-switch-project-action-switch-to-buffer "jump to a project buffer") ("m" counsel-projectile-switch-project-action-find-file-manually "find file manually from project root") ("S" counsel-projectile-switch-project-action-save-all-buffers "save all project buffers") ("k" counsel-projectile-switch-project-action-kill-buffers "kill all project buffers") ("K" counsel-projectile-switch-project-action-remove-known-project "remove project from known projects") ("c" counsel-projectile-switch-project-action-compile "run project compilation command") ("C" counsel-projectile-switch-project-action-configure "run project configure command") ("E" counsel-projectile-switch-project-action-edit-dir-locals "edit project dir-locals") ("v" counsel-projectile-switch-project-action-vc "open project in vc-dir / magit / monky") ("sg" counsel-projectile-switch-project-action-grep "search project with grep") ("si" counsel-projectile-switch-project-action-git-grep "search project with git grep") ("ss" counsel-projectile-switch-project-action-ag "search project with ag") ("sr" counsel-projectile-switch-project-action-rg "search project with rg") ("xs" counsel-projectile-switch-project-action-run-shell "invoke shell from project root") ("xe" counsel-projectile-switch-project-action-run-eshell "invoke eshell from project root") ("xt" counsel-projectile-switch-project-action-run-term "invoke term from project root") ("Oc" counsel-projectile-switch-project-action-org-capture "capture into project") ("Oa" counsel-projectile-switch-project-action-org-agenda "open project agenda")) :require-match t :sort nil :caller counsel-projectile-switch-project)
  counsel-projectile-switch-project()
  funcall-interactively(counsel-projectile-switch-project)
  call-interactively(counsel-projectile-switch-project nil nil)
  command-execute(counsel-projectile-switch-project)

Am I missing something? :)

Support postprocessing of formatter output before insertion

Some formatters like eslint --fix-dry-run --format json contains the formatted output in a JSON entry. Currently reformatter-replace-buffer-contents-from-file only takes the out-file and inserts directly into the original file buffer. It would be nice if we could define a postprocessor to process formatter output before insertion. Similar approaches may be used for #20 as well.

Option to display errors on save

This package looks great, thanks!

I would like an option to display errors when the function is called in the before-save-hook, in the same way as it does for myformatter-buffer.

See also #3.

Kill *... errors* buffers when it’s not needed.

Hi. Thanks for a package. It’s more a question rather than an issue. I’m wondering why the buffer for errors is always open, why it’s not killed if it’s not used at the moment? How would I set the option to kill the buffer if the formatting was successful?

Support formatters which don't accept input from stdin

Some formatters like isort need a file as input and change the file in place . An additional argument like :file t could result in creating a temp file and pass that to :program and use the changed temp file as new buffer content.

Customize where to display the error output

Hello @purcell

Thanks for this library. This is very useful!

I started to use it with OCamlFormat. You can find the proof of concept here. My end goal is to have an implementation that will be a drop-in replacement of the current Elisp integration of OCamlFormat. On my side, it looks good, except, there is a missing feature: the choice where to display error output.

The existing OCamlFormat integration comes with an option ocamlformat-show-errors:

Where to display ocamlformat error output. It can either be displayed in the compilation buffer, in the echo area, or not at all...

I wonder if there is a way to replicate that via reformatter.el. Would it make sense to add a new argument to reformatter-define to customize where to display the error output?

Support formatters that output patch

ShellCheck is an example of a tool that doesn't support writing changes in-place, but does support diff-style output. Example of running shellcheck --format=diff against edx/devstack/course-generator/create-courses.sh:

--- a/create-courses.sh
+++ b/create-courses.sh
@@ -7,21 +7,21 @@
 echo "Parsing options"
 container_error=false
 for arg in "$@"; do
-    if [ $arg == "--studio" ]; then
+    if [ "$arg" == "--studio" ]; then
         if [ ! "$(docker-compose exec lms bash -c 'echo "Course will be created for studio"; exit $?')" ]; then
             echo "Issue with studio container"
             container_error=true
         else
             studio=true
         fi
-    elif [ $arg == "--ecommerce" ]; then
+    elif [ "$arg" == "--ecommerce" ]; then
         if [ ! "$(docker exec -t edx.devstack.ecommerce bash -c 'echo "Course will be created for ecommerce"; exit $?')" ]; then
             echo "Issue with ecommerce container"
             container_error=true
         else
             ecommerce=true
         fi
-    elif [ $arg == "--marketing" ]; then
+    elif [ "$arg" == "--marketing" ]; then
         if [ ! "$(docker exec -t edx.devstack.marketing bash -c 'echo "Course will be created for marketing"; exit $?')" ]; then
             echo "Issue with marketing container. Course creation will proceed without marketing container."
         else

generic configuration and β€˜dwim’ helpers

this package is, by design, conceptually different from format-all. however, it is convenient to have have a single command as an entry-point to format a buffer (or region). this also makes keybindings easier.

a minimal β€˜dwim’ (do what i mean) command would only need the name of the reformatter (as defined by reformatter-define. a buffer-local variable pointing to a β€˜reformatter command family’ is enough to make β€˜dwim’ commands that delegate to the real reformatter commands.

i'll post my implementation in a separate comment. i think this may be useful for others as well, and i'm posting this here to see whether it would make sense to add this to reformatter.el proper. (obviously i think it does. it's what makes this package really useful for me.)

Need help for mint format.

What i said is mint-lang.

https://mint-lang.com/guide/getting-started/tools

Following is command:

 ╰─ $ 1  mint format source/Main.mint 
Mint - Formatting files
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
All files are formatted!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
All done in 299ΞΌs!

I have no idea how to make this command work.

Following is my config:

(reformatter-define mint-format
  :program "mint"
  :args '("format")
  :stdout nil
  )

Thank you.

Spacemacs example

Hi! Thanks for reformatter.el, it's super cool.

I made a simple Spacemacs layer that uses reformatter.el and black to format python code.

I don't know if you are interested in adding any more examples to the readme, but if you want to you are welcome to link to spaceblacken. No worries if not!

The project can be found here: https://github.com/backwardspy/spaceblacken

Jump to location of error

Dedicated formatters like that for go-mode.el, use compilation mode and its builtin regex alist to provide links to the source of formatting errors.

Maybe we can define a derived mode from compilation-mode, and use that instead of special-mode for the error buffer?

reformatter-define macro always yields two warnings when being byte-compiled

For every formatter defined with reformatter-define I get the following warnings when trying to byte-compile:

 1468  22 warning  β€˜make-variable-buffer-local’ not called at toplevel
 1468  22 warning  defcustom for β€˜NAME-on-save-mode-lighter’ fails to specify containing group

Would it be possible to avoid this?

Edit
I also seem to get:

the following functions are not known to be defined: NAME-region

use replace-buffer-contents if possible?

it seems reformatter tries to minimize the impact of changing the buffer:

                       ;; This replacement method minimises
                       ;; disruption to marker positions and the
                       ;; undo list
                       (narrow-to-region beg end)
                       (insert-file-contents out-file nil nil nil t)

emacs 26+ introduced a new replace-buffer-contents function that is supposed to cover the β€˜reformat buffer’ use case with minimal impact:

One potential case where this behavior is useful is external code formatting programs

https://www.gnu.org/software/emacs/manual/html_node/elisp/Replacing.html

perhaps reformatter could use this function if available?

(not sure it would be useful for formatting only a region. maybe narrowing works?)

Support custom variable to indicate current filename

I like the simple implementation but wonder if it would make sense to interpolate some variable as current buffer filename. Of course this comes with the complication, should it be only the filename, the full path or the project local one. Perhaps even the possibility to provide a custom function to deterimine the file-name if it is too complicated for the project.

The reason I am asking is that some formatters want the file name and act differently depending on the filename, e.g. prettier/eslint. Right now I have solved this by creating different formatters for the different file-extensions, where I just put a static file, such as f.ts. However I have learned with slow formatters such as ESlint that it makes it really slow, I guess it is using the actual filename to determine some cache.

Sample timings:

$ time -p eslint_d --stdin --stdin-filename test/unit/services/attachment.test.ts --fix-to-stdout < test/unit/services/attachment.test.ts
real 0.25
user 0.05
sys 0.01

$ time -p eslint_d --stdin --stdin-filename f.ts --fix-to-stdout < test/unit/services/attachment.test.ts
real 4.88
user 0.05
sys 0.01

So in order to make this formatter useable I would need to provide the filename.

My current formatter looks like:

(reformatter-define typescript-format
  :program "eslint_d"
  :args '("--stdin" "--stdin-filename=f.ts" "--fix-to-stdout")))

What would be nice:

(reformatter-define typescript-format
  :program "eslint_d"
  :args '("--stdin" "--stdin-filename=%f" "--fix-to-stdout")))

or something like this using the symbol to figure out what to do:

(reformatter-define typescript-format
  :program "eslint_d"
  :args '("--stdin" "--stdin-filename" file "--fix-to-stdout")))

Add to GNU ELPA ?

This is a library intended to be used as a dependency by other libraries, yes?

If I've understood that correctly, it would be good if it were in GNU ELPA so that GNU ELPA packages could use it as a dependency.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.