Editing the ns Form
CIDER can add requires and imports to the ns form of the current buffer,
so you don’t have to jump to the top of the file and back whenever you need
another namespace, and remove the ones the code doesn’t use.
The edits are plain text manipulation, so adding a require or an import
works without a REPL. When one is connected, the prompts complete against it.
Adding what a symbol needs and cleaning the ns form are the exceptions,
since they ask the REPL.
If you’re coming from clj-refactor, see Coming from clj-refactor for what replaces its commands.
Adding a Require
C-c M-n a (cider-ns-add-require) prompts for a namespace, completing
over the namespaces loaded in the REPL, and then for an alias. The alias starts
out as the last segment of the namespace’s name. Edit it, or clear it to
require the namespace without an alias.
Requiring clojure.string as str turns
(ns my.app
(:require [clojure.set :as set]))
into
(ns my.app
(:require [clojure.set :as set]
[clojure.string :as str]))
The :require clause gets created when there isn’t one, ahead of the
:import clause if the ns form has it. When the namespace is already
required without an alias, the alias goes into its libspec. CIDER refuses to
give the namespace a second alias, or to use an alias another namespace already
has.
CIDER doesn’t look into reader conditionals (#?(:clj …)): a require
inside one doesn’t count, and a new require always goes into the top-level
:require clause. In a .cljc file that means it applies to both Clojure and
ClojureScript, so wrap it in a reader conditional yourself if only one side
should see it. The same goes for imports.
Adding an Import
C-c M-n i (cider-ns-add-import) prompts for a fully qualified class
name, completing over the classes the REPL knows about. The class joins an
existing import list for its package, so importing java.util.Map turns
(ns my.app
(:import (java.util Date List)))
into
(ns my.app
(:import (java.util Date List Map)))
Without such a list, the fully qualified name goes into the :import clause,
which gets created when it’s missing.
Adding What a Symbol Needs
C-c M-n m (cider-ns-add-missing) takes the symbol at point and asks the
REPL where it could come from: the loaded namespaces with a public var of that
name, and the classes of that name. With more than one candidate, you pick one.
A symbol that already resolves gets nothing, so the command never changes what
it means.
What gets added depends on how the symbol is written:
| Symbol | Added to the ns form |
|---|---|
|
|
|
|
|
|
|
|
When the namespace is already required, its libspec gets the refer or the
alias, so join turns [clojure.string :as str] into
[clojure.string :as str :refer [join]]. When that can’t work, CIDER says why
and changes nothing: the namespace already has another alias, or another libspec
already has the alias or refers the name. A type made by deftype or
defrecord gets imported, and the namespace that defines it gets required as
well, because the class doesn’t exist until that namespace is loaded.
On an auto-resolved keyword like ::config/aero, it requires the namespace
config stands for, going by the same namespaces as
magic requires. When there’s more than one, it asks which.
A plain keyword like :config/aero needs no require, so there’s nothing to do.
Only namespaces that are loaded in the REPL count, so load the one you’re after first if it isn’t. In ClojureScript buffers the ClojureScript REPL gets asked, and it knows about namespaces but not about JavaScript classes.
This needs cider-nrepl 0.64.0 or newer. With an older one, the command says the op it needs is missing.
Magic Requires
With magic requires on, typing a slash after an alias the ns form doesn’t
have yet adds the require it needs. Type str/ in a buffer without a str
alias, and [clojure.string :as str] goes into the :require clause, while
you carry on typing str/join where you are.
They’re off by default. To turn them on:
(setq cider-ns-magic-requires t)
With t, CIDER adds the namespace right away when it’s the only one the alias
could stand for, and asks which when there are several. Set it to prompt to
be asked every time. Picking none leaves that alias alone in the buffer from
then on. The require is an undo step of its own, so C-/ right after it
takes it back without touching what you typed.
The project’s own source files decide what an alias stands for: the namespaces
they give it, the most used first, so the codebase’s conventions carry over.
For an alias the project doesn’t use yet, CIDER falls back on
cider-ns-magic-require-aliases, which has the usual aliases of Clojure’s own
namespaces (str, set, io and so on), and on the project namespaces named
like the alias, such as acme.billing for billing. An entry of
cider-ns-magic-require-aliases can list the platforms its namespace is there
on:
(add-to-list 'cider-ns-magic-require-aliases '("json" "cheshire.core" "clj"))
The slash counts only where an alias can go: not in strings, comments or
discarded forms, and not after a keyword like :foo/ (though ::foo/ counts),
a number, a quoted symbol, a namespace or class name, or a name in a :keys
vector. An alias with dots, like utils.strings/, counts too. In
ClojureScript, js/ is left alone. In a .cljc file, the namespace
has to work for both Clojure and ClojureScript.
Magic requires work in the buffers where cider-mode is on, which is the
Clojure buffers of a project you’re connected to. Going by the project’s source
files needs cider-nrepl 0.64.0 or newer. With an older one, CIDER uses
cider-ns-magic-require-aliases only.
clj-refactor 4.1 and newer leave / to CIDER when
cider-ns-magic-requires is on. Older versions bind it to their own magic
requires, so CIDER’s don’t run in buffers where clj-refactor-mode is on. To
use CIDER’s there, unbind it:
|
(with-eval-after-load 'clj-refactor
(define-key clj-refactor-map (kbd "/") nil))
Cleaning the ns Form
C-c M-n c (cider-ns-clean) removes what the ns form requires, refers
and imports, but the code doesn’t use. With
(ns my.app
(:require [clojure.set :as set]
[clojure.string :as str :refer [join split]])
(:import (java.util Date List)))
(join ", " [(Date.)])
it leaves
(ns my.app
(:require [clojure.string :refer [join]])
(:import (java.util Date)))
The REPL tells what goes unused by reading the code after the ns form,
without loading it, so the code doesn’t have to compile, only to read. That
makes it cautious: a name counts as used wherever it comes up, a comment form,
a quoted form or a local of the same name included. These always count as
used:
-
a require with no alias and nothing to refer, like
[my.app.specs], as it’s likely there for its side effects; -
:refer :alland:rename, as telling what they bring in takes loading the namespace; -
prefix lists, like
[clojure [set :as set]], and what’s in a reader conditional.
A namespace that’s still used fully qualified, as in clojure.string/join,
or that defines a class the ns form imports, stays required, without the
alias or the referred names it doesn’t need. Everything else in the ns form
stays the way it’s written, comments included, and cider-ns-edit-actions
applies afterwards, as after any other edit.
To clean the ns form whenever you save:
(add-hook 'clojure-mode-hook
(lambda () (add-hook 'before-save-hook #'cider-ns-clean nil t)))
(With clojure-ts-mode, that’s clojure-ts-mode-hook.) Run from a hook,
cider-ns-clean does nothing without a REPL that can tell what’s unused, and
code that doesn’t read yet gets a message in the echo area rather than
stopping the save. A .cljc file with code that only reads once a platform is
picked, like #?@ splicing into a map literal, can’t be cleaned.
This needs cider-nrepl 0.64.0 or newer. With an older one, the command says the op it needs is missing.
After an Edit
cider-ns-edit-actions says what happens after a change to the ns form. By
default CIDER sorts the libspecs and, when a REPL is connected, evaluates the
ns form, so a new alias works right away.
To keep the libspecs in the order you wrote them, drop the sorting:
(setq cider-ns-edit-actions '(eval))
CIDER never removes anything from the ns form on its own, only when you
clean it.
Each change, together with the sorting, is a single undo step.
Coming from clj-refactor
These commands and the magic requires take over from clj-refactor’s, which clj-refactor 4.1 deprecates. They don’t need yasnippet or refactor-nrepl.
| clj-refactor | CIDER | Keybinding |
|---|---|---|
|
|
C-c M-n a |
|
|
C-c M-n i |
|
|
C-c M-n m |
|
|
/ |
|
|
C-c M-n c |
Cleaning the ns form never happens on its own, unlike with
cljr-auto-clean-ns, though you can run it on save.