5.2 KiB
would-reformat - automatic reformatting for emacs (and maybe other editors) without being annoying
Motivation
I've never liked it when a text editor formats code for me without my asking. I don't like it when the editor uses cheap heuristics (indent a new line to match the previous one? blah!) and I don't like it when the editor shells out to one of the new generation of automatic code formatters.
But I don't enjoy formatting code by hand either. Who does?
This is my solution: some shell scripts and some emacs lisp code.
The shell script would-reformat.sh takes a file's full path as
its argument. It tells you if that file would be reformatted.
The shell script do-reformat.sh takes a file's full path as its argument. It
reformats the file.
Finally, there is some rudimentary machinery to run would-reformat.sh when
saving a file and to run do-reformat.sh when you hit <F1>.
Supported programming languages and file formats
- css
- dart
- go
- html
- javascript
- jsx
- php
- python
- scss
- sh
- tsx
- typescript
- vue
Out of the box, for python we use isort and black, for go we use gofmt,
for dart we use dart format, for rust we use rustfmt, and for everything
else we use prettier.
Adding suuport for other programming languages is easy, assuming they have a formatter with a dry run mode. And even if they don't it shouldn't be that bad.
Installation
- Change to the directory where you want to use
would-reformat:you@host:~ $ cd ~/devel/my-project - From that directory, call the script
install.shin the directory where you havewould-reformatchecked out:you@host:~/devel/my-project $ ~/src/would-reformat/install.sh
Be sure to run the installation script from the root of your project's directory, not a subdirectory.
This will do the following:
- create the directory
~/devel/my-project/binif it does not exist - create
~/devel/my-project/bin/_reformat-common.sh,~/devel/my-project/bin/do-reformat.sh, and~/devel/my-project/bin/would-reformat.shas symlinks to files with the same names in~/src/would-reformat. - create
~/devel/my-project/.dir-locals.elas a symlink to the file with the same name in~/src/would-reformat.
This should work from a checkout wherever you happen to have it. It doesn't
need to be in ~/src. However, if you remove the checkout, then the symlinks
will break, so don't do that. If you rename the checkout, the symlinks will
break.
The directory bin with respect to my-project however is hardcoded
(enhancements here are welcome).
The script install.sh favors conservatism over cleverness: for example,
if it finds the file ~/devel/my-project/bin/do-reformat.sh then it
checks whether it is a symlink to ~/src/would-reformat/do-reformat.sh.
If it is not, then it just prints a warning rather than attempting to correct
the situation.
FIXME: Document how to reinstall if the checkout was moved, incompatible changes were made, etc.
Customization
For information on changing how would-format handles different files, see
CUSTOMIZATION.md.
Development
If you want to hack on would-format, see DEVELOPMENT.md
for more info.
Troubleshooting
nothing works from emacs
Be sure to run the install script from your project's root as determined by
(projectile-project-root).
problems with nvm, pyenv, goenv, etc
The problem might be that their shims aren't in your PATH. To work around
this sort of problem I run emacs from a wrapper script that ensures the shims
are loaded in my PATH.
Running prettier is slow
The scripts by default call npx prettier with some arguments. If you call
these scripts from a directory where there's a node_modules/ directory with
prettier and plugins, if necessary, installed, then npx should be fast
enough.
The solution, therefore, seems to be to say yarn add --dev prettier (or
npm install --dev prettier) in the right place.
(This seems to work for me, but it is admittedly still uncomfortably cargoculty. There should be a more solid basis for this answer.)
problems running black
The solution seems to be to run pip install black pipx somewhere.
I need to use one version of would-reformat with one of my projects and another with another
With the per-project configuration [see below] this should rarely be
necessary, but in case it is, one thing you can try is creating different
would-reformat checkouts for different projects. For example, something
like this might work:
$ ls ~/devel
new-project1 new-project2 old-and-weird-project1
$ git clone https://github.com/maw/would-reformat
$ cd new-project1; ../would-reformat/install.sh
$ cd ../new-project2; ../would-reformat/install.sh
$ cd ..
$ git clone https://github.com/maw/would-reformat would-reformat-for-old-and-weird-project1
$ cd would-reformat-for-old-and-weird-project1; git checkout vSome-old-tag
$ cd ../old-and-weird-project1; ../would-reformat-for-old-and-weird-project1/install.sh
Similar projects
If you don't like would-reformat's approach, maybe one or more of these
would be more suitable.