Contrary to my experience with free or open source projects, when it comes to the proprietary software I have been developing for work since late 2004, code formatting has never been matter of discussion. There was a team, back in my days in the UK, that enforced some strict rules via Ant, but until today that was the sole exception.
Luckily the people I am coding with nowadays are more open to this kind of problem. Yes, I used the word problem. As I explained to a co-worker when I raised the question of formatting tools, I read code as I read a book. I cannot imagine sitting through different books each written according to the authors’ own ideas of stylistic conventions. It’s about having the text, whether words or code,1 accessible to anyone by making the assumption that the first step to understanding is ease of legibility.
The team agreed on using
cljfmt2 for this task. Most of the developers here
use Clojure LSP and, from what I understand, the integration with
already there for them. I, on the other hand, went with a more manual approach.
I first built the
cljfmt binary with GraalVM thanks to Rune Juhl Jacobsen’s
cljfmt-graalvm.3 Rune offers a snippet for
Projectile users, but I leveraged
project.el and a CIDER hook instead.
(defvar mu-cljfmt-edn "cljfmt.edn" "The name of `cljfmt' configuration file.") (defun mu-cljfmt-format-buffer () "Format current buffer with `cljfmt'." (when (derived-mode-p 'clojure-mode) (let* ((pr (project-root (project-current))) (cfg-dir (locate-dominating-file pr mu-cljfmt-edn)) (cfg-edn (expand-file-name mu-cljfmt-edn cfg-dir)) (cmd (if (file-exists-p cfg-edn) (format "cljfmt -c %s %s" cfg-edn buffer-file-name) (format "cljfmt %s" buffer-file-name)))) (shell-command-to-string cmd)) (revert-buffer t t))) (defun mu-cider-format-buffer () "Automatically format current buffer after saving." (add-hook 'after-save-hook #'mu-cljfmt-format-buffer nil t)) (add-hook 'cider-mode-hook #'mu-cider-format-buffer)
Some things worth considering:
the location and the name of the
cljfmt.ednfile matter, so check your projects if you follow my approach. For instance, the snippet provided by Rune uses
mu-cljfmt-ednI can customize it per-project via directory variables, if needed.
clojurescript-modeare both derived from
clojure-mode. This explains the use of
in buffers handled by
clojure-modeI always have CIDER enabled, even if not necessarily jacked-in. For a more general approach,
clojure-mode-hookshould be preferred;
CIDER provides an integration with
cljfmt.4 Depending on your needs that may be already enough.
With a tool tweaked to format code idiomatically5 for us, now it’s time to argue about names. Wait, let me refresh my hadoukens first.