Ⅰ. 插件描述
A tool for formatting Clojure codeⅡ. 基本信息
|
Ⅲ. 安装方法
使用Vundle管理器安装
在你的.vimrc下添加:Plugin 'weavejester/cljfmt'
… 然后在Vim中运行以下命令:
:source %
:PluginInstall
对于Vundle版本 < 0.10.2,请用上面的Bundle替换Plugin。
使用NeoBundle管理器安装
在你的.vimrc下添加:NeoBundle 'weavejester/cljfmt'
… 然后在Vim中运行以下命令:
:source %
:NeoBundleInstall
使用VimPlug管理器安装
在你的.vimrc下添加:Plug 'weavejester/cljfmt'
… 然后在Vim中运行以下命令:
:source %
:PlugInstall
使用Pathogen管理器安装
在终端中运行以下命令:cd ~/.vim/bundle
git clone https://github.com/weavejester/cljfmt
Ⅳ. 文档说明
# cljfmt
cljfmt is a tool for formatting Clojure code [idiomatically][].
It can turn something like this:
( let [x 3
y 4]
(+ (* x x
)(* y y)
))Into nicely formatted Clojure code like this:
(let [x 3
y 4]
(+ (* x x) (* y y)))However, it is not the goal of cljfmt to provide a canonical format.
Installation
The easiest way to get started with cljfmt is to add the lein-cljfmt
plugin to your [Leiningen][] project map:
:plugins [[lein-cljfmt "0.6.7"]]cljfmt has tested on Leiningen 2.5, but may not work on older
versions, particularly versions prior to Leiningen 2.4.
Usage
To check the formatting of your source files, use:
lein cljfmt check
If the formatting of any source file is incorrect, a diff will be
supplied showing the problem, and what cljfmt thinks it should be.
If you want to check only a specific file, or several specific files,
you can do that, too:
lein cljfmt check src/foo/core.clj
Once you've identified formatting issues, you can choose to ignore
them, fix them manually, or let cljfmt fix them with:
lein cljfmt fix
As with the check task, you can choose to fix a specific file:
lein cljfmt fix src/foo/core.clj
deps.tools usage
It is possible to execute cljfmt using the
[Clojure CLI], without integrating with lein.
clojure -Sdeps '{:deps {cljfmt {:mvn/version "0.6.4"}}}' \
-m cljfmt.main [check|fix]Customizing the rules is possible passing edn formated files,
using the same content used on lein profiles.
As example, with the following content to the indentation.edn
file, it is possible to customize the rules.
{org.me/foo [[:inner 0]]}clojure -Sdeps '{:deps {cljfmt {:mvn/version "0.6.4"}}}' \
-m cljfmt.main check \
--indents indentation.ednEditor Support
- vim-cljfmt
- CIDER 0.9+
- Calva (VS Code)
- clojureVSCode (VS Code)
Configuration
You can configure lein-cljfmt by adding a :cljfmt map to your
project:
:cljfmt {}cljfmt has several different formatting rules, and these can be
selectively enabled or disabled:
:indentation?-
true if cljfmt should correct the indentation of your code.
Defaults to true.
:remove-surrounding-whitespace?-
true if cljfmt should remove whitespace surrounding inner- This will convert
( foo )to(foo).
Defaults to true.
- This will convert
:remove-trailing-whitespace?-
true if cljfmt should remove trailing whitespace in lines. This will
convert (foo) \n to (foo)\n. Defaults to true.
:insert-missing-whitespace?-
true if cljfmt should insert whitespace missing from between- This will convert
(foo(bar))to(foo (bar)).
Defaults to true.
- This will convert
:remove-consecutive-blank-lines?-
true if cljfmt should collapse consecutive blank lines. This will
convert (foo)\n\n\n(bar) to (foo)\n\n(bar). Defaults to true.
You can also configure the behavior of cljfmt:
:paths- determines which directories to include in the- Arguments to
lein checktake precedence. If neither:paths - command line arguments are given, cljfmt uses the lein project's
- Arguments to
:source-paths and :test-paths.
:file-pattern-
determines which files to scan,#”\.clj[csx]?$”by default.:indents-
a map of var symbols to indentation rules, i.e.{symbol [& rules]}.
See the next section for a detailed explanation.
Unqualified symbols in the indents map will apply to any symbol with a
matching "name" - so foo would apply to both org.me/foo and
com.them/foo. If you want finer-grained control, you can use a fully
qualified symbol in the indents map to configure indentation that
applies only to org.me/foo:
:cljfmt {:indents {org.me/foo [[:inner 0]]}}Configured this way, org.me/foo will indent differently from
com.them/foo.
Note that cljfmt currently doesn't resolve symbols brought into a
namespace using :refer or :use - they can only be controlled by an
unqualified indent rule.
As with Leiningen profiles, you can add metadata hints. If you want to
override all existing indents, instead of just supplying new indents
that are merged with the defaults, you can use the :replace hint:
:cljfmt {:indents ^:replace {#".*" [[:inner 0]]}}:alias-map-
a map of namespace alias strings to fully qualified namespace- This option is unnecessary in almost all cases, because
cljfmtcan compute the alias map from anns
- This option is unnecessary in almost all cases, because
declaration.
However, it can't do that when used as a CLJS library,
or when indenting something with no ns declaration like an EDN
- Even in those situations, you only need this option when using
- rules that rely on the fully qualified symbol name.
If you definitely need to configure this, it should look like this:
:cljfmt {:indents {org.me/foo [[:inner 0]]}
:alias-map {"me" "org.me"}}Indentation rules
When we talk about how rules affect indentation of source code, we refer to(foo arg1 arg2 ... argn) as a
form, foo as a form symbol, and arg1 arg2 ... as form arguments.
argn
The default indentation rules are encoded here.
Rules affect indentation of form arguments. A form argument is eligible for
indentation only when it is the first element on a line.
An indentation rule specifies an indentation type and indentation type
- One or more rules can be applied to a form symbol.
Indentation types are:
:inner- two character indentation applied to form arguments at a depth
relative to a form symbol:block- first argument aligned indentation applied to form arguments at
form depth 0 for a symbol
Form depth
A rule for depth n affects indentation of form arguments relative to form symbol at depth n.
Form depth is the nested depth of any element within the form.
A contrived example will help to explain depth:
(foo
bar
(baz
(qux plugh)
corge)
(grault
waldo
(thud wubble flob)))If we look at the example code as a tree, we can visualize the effect of different form depths
relative to foo:



Default behavior
In the absence of indentation rules:
(foo bar (foo bar
baz == formats to => baz
bang) bang)(foo (foo
bar == formats to => bar
bang) bang)Inner rules
The :inner rule applies an indentation of two spaces to all eligible form
arguments of forms at a given form depth. It has 2 rule type arguments:
form-depth- apply inner indentation within forms at this depthlimit-to-form-index- optionally limit indentation formatting to a single form, by default
formatting is applied to all forms atform-depth
Indent rule:
{foo [[:inner 0]]}... will indent all arguments for symbol foo at depth 0 by two spaces:
(foo bar (foo bar
baz == formats to => baz
bang) bang)Indent rule:
{foo [[:inner 1]]}... results in :inner indenting form arguments at depth 1. Form (bang...)
is at depth 1 so its arguments are affected:
(foo bar (foo bar
baz baz
(bang == formats to => (bang
quz quz
qoz)) qoz))Because no rule was specified for depth 0, default indentation is applied tobar baz and (bang...).
Limiting inner indentation
Sometimes it is useful to limit :inner indentation to one, rather than all,
forms at the specified depth. For example, we'd like letfn to use inner
indentation only in its binding vector.
Let's look at letfn example in the absence of any indentation rules:
(letfn [(double [x]
(* x 2))] ;; want inner indentation here
(let [y (double 2)
z (double 3)]
(println y
z))) ;; but not hereApplying the rule:
{letfn [[:inner 2]]}... brings in the letfn function body to where we want it by affecting form(double [x]...):
(letfn [(double [x]
(* x 2))] ;; want inner indentation here
(let [y (double 2)
z (double 3)]
(println y
z))) ;; but not here... but also affects all other forms at depth 2. In this case, (println...)
indentation is affected in an undesirable way. To limit formatting to `(double
[x]...), the 0th form at depth 2, the limit-to-form-index` rule type
argument is added:
{letfn [[:inner 2 0]]}... giving us:
(letfn [(double [x]
(* x 2))] ;; want inner indentation here
(let [y (double 2)
z (double 3)]
(println y
z))) ;; but not hereRemember than when calculating limit-to-form-index, all forms at the specified
depth are included, even self-evaluating ones. Given:
(foo a b c
(e f
g)
(h i
j))To affect inner indentation within form (e...) only, we use a rule of:
{foo [[:inner 1 3]]}... which results in:
(foo a b c
(e f
g)
(h i
j))... because (e...) is the 4th (index 3) at form depth 1.
Block rules
The :block rule supports indenting to the first form argument. It has a single
rule type argument:
line-arg-count-threshold- when there are more than
line-arg-count-thresholdform arguments on the same line as the form symbol,
eligible form arguments on subsequent lines are indented to align with the
first form argument. Otherwise, two space inner indentation is applied.
For indent rule:
{foo [[:block 0]]}... the single argument bar on the same line as foo breaks the threshold of0 and indents eligible form arguments on subsequent lines to bar:
(foo bar (foo bar
baz == formats to => baz
bang) bang)... the two arguments bar baz on the same line as foo also breaks the
threshold of 0 and invokes indentation to the first argument:
(foo bar baz == formats to => (foo bar baz
bang) bang)... no arguments on the same line as foo does not break the threshold of 0, so
2 space inner indentation is applied:
(foo (foo
bar == formats to => bar
baz baz
bang) bang)For indent rule:
{foo [[:block 1]]}... the single arg bar on the same line as foo does not break the threshold
of 1 so we get inner indentation:
(foo bar (foo bar
baz == formats to => baz
bang) bang)... two args bar baz on the same line as foo breaks the threshold of 1 so
we get first argument aligned indentation:
(foo bar baz == formats to => (foo bar baz
bang) bang)Multiple rules
Multiple rules can be specified. Picking up from our previous letfn example,
the rule:
{letfn [[:inner 2 0]]}... gave us:
(letfn [(double [x]
(* x 2))] ;; want inner indentation here
(let [y (double 2)
z (double 3)]
(println y
z))) ;; but not hereAdding a :block rule:
{letfn [[:block 1][:inner 2 0]]}... matches the [current default rule forletfn](cljfmt/resources/cljfmt/indents/clojure.clj) and results in indenting
the (let... to where we want it:
(letfn [(double [x]
(* x 2))] ;; want inner indentation here
(let [y (double 2)
z (double 3)]
(println y
z))) ;; but not hereIn this case, single form argument [(double...)] does not break theline-arg-count-threshold of 1 and we therefore get inner indentation for
form argument (let...).
License
Copyright © 2019 James Reeves
Distributed under the Eclipse Public License either version 1.0 or (at
your option) any later version.