diff --git a/output/index.html b/output/index.html index 00fde9238..9a7666546 100644 --- a/output/index.html +++ b/output/index.html @@ -655,6 +655,13 @@ Commands for showing output destinations + + +
ctrl+alt+o t
ctrl+alt+o r
Since Calva v2.0.423 the REPL Window prints stdout
prepended with ;
to make it into line comments. This is because stdout output easily breaks the Clojure structure of the REPL Window, making it misbehave in various ways. We made this change because as maintainers of Calva we have seen all too often how this hits users, and it is also taking too much of our Calva time to try mitigate the problem, which is fundamentally not fixable.
There are now other output destinations that do not have this limitation.
+All that said. If you want to keep using the REPL Window for stdout output, and need the old behavior, you can enable the setting: calva.legacyPrintBareReplWindowOutput
. Please note that at some point after we have created a dedicated Output Window, the REPL Window will be retired as a destination for output.
When Calva is connected to the REPL, the Output window will by default print not only results of evaluations, but also:
Calva is an integrated, REPL powered, development environment for enjoyable and productive Clojure and ClojureScript programming in Visual Studio Code. It is feature rich and turnkey. A lot of effort has been put into making Calva a good choice if you are new to Clojure. Calva is open source and free to use.
"},{"location":"#getting-started","title":"Getting Started","text":"Let's start a REPL!. \ud83d\ude80 Also see Get Started with Clojure
"},{"location":"#how-to-contribute-to-calva","title":"How to Contribute to Calva?","text":"I'm glad you asked! Please see How to Contribute and The Tao of Calva
"},{"location":"#calva-patrons","title":"Calva Patrons","text":"The right kind of different"},{"location":"#calva-gold-sponsors","title":"Calva Gold Sponsors \u2665\ufe0f","text":"Scale your growth on mobile MAKE. DO. SHIP.Please see this statement from Cognitect about the importance of supporting open source developers.
See Sponsors for information about sponsoring Calva.
If your Company benefits from Calva's existence and you see it as an important in the Clojure and ClojureScript ecosystem. please consider sponsoring!
"},{"location":"#features","title":"Features","text":"Calva includes inline code evaluation, structural editing, code formatting, code navigation, a debugger, linting, syntax highlighting, Clojure aware rainbow brackets, a test runner, refactoring support, and more.
"},{"location":"#have-questions-and-feedback-need-help","title":"Have Questions and Feedback? Need Help?","text":"Easiest way is to chat with us and other Calva users. Please join the #calva channel on the Clojurians Slack. If you haven't joined that slack workspace, you can get an invite here.
If you're a beginner to Clojure(Script), the #beginners channel of the Clojurians Slack is very active and helpful.
"},{"location":"#please-star-the-calva-repo","title":"Please star the Calva repo!","text":"Happy coding!
"},{"location":"api/","title":"The Calva Extension API","text":"Calva exposes an API for use from other VS Code extensions (such as Joyride). The API is in an experimental state, while we are figuring out what is a good shape for this API. It is also rather small, and will grow to expose more of Calva's functionality.
","boost":7},{"location":"api/#accessing","title":"Accessing","text":"To access the API the Calva extension needs to be activated. The API is exposed under the v1
key on the extension's exports
, and split up into submodules, like repl
, and ranges
.
When using Joyride you can use its unique require
API, for which one of the benefits is better lookup IDE support. When using the API from regular ClojureScript, you'll pick it up from the Calva extension instance. (Which you can do from Joyride as well, but why would you?). Here is how you access the API, with an example of usage as a bonus:
(ns ... (:require [\"ext://betterthantomorrow.calva$v1\" :as calva]))\n;; OR\n(require '[\"ext://betterthantomorrow.calva$v1\" :as calva])\n\n(calva/repl.currentSessionKey) => \"cljs\" ; or \"clj\", depending\n
(def calvaExt (vscode/extensions.getExtension \"betterthantomorrow.calva\"))\n\n(def calva (-> calvaExt\n.-exports\n.-v1\n(js->clj :keywordize-keys true)))\n\n((get-in calva [:repl :currentSessionKey])) => \"cljs\" ; or \"clj\", depending\n
const calvaExt = vscode.extensions.getExtension(\"betterthantomorrow.calva\");\n\nconst calva = calvaExt.exports.v1;\n\nconst sessionKey = calva.repl.currentSessionKey()\n
","boost":7},{"location":"api/#repl","title":"repl
","text":"The repl
module provides access to Calva's REPL connection.
repl.currentSessionKey()
","text":"Use repl.currentSessionKey()
find out which REPL/session Calva's REPL is currently connected to (depends on the active file). Returns either \"clj\"
, or \"cljs\"
, or nil
if no REPL is connected.
(def session-key (calva/repl.currentSessionKey))\n
(def session-key ((get-in [:repl :currentSessionKey] calvaApi)))\n
const sessionKey = calva.repl.currentSessionKey()\n
","boost":7},{"location":"api/#replevaluatecode","title":"repl.evaluateCode()
","text":"This function lets you evaluate Clojure code through Calva's nREPL connection. Calling it returns a promise that resolves to a Result
object. It's signature looks like so (TypeScript):
export async function evaluateCode(\nsessionKey: 'clj' | 'cljs' | 'cljc' | undefined,\ncode: string,\nns = 'user',\noutput?: {\nstdout: (m: string) => void;\nstderr: (m: string) => void;\n},\nopts = {}\n): Promise<Result>;\n
Where Result
is:
type Result = {\nresult: string;\nns: string;\noutput: string;\nerrorOutput: string;\n};\n
As you can see, the required arguments to the function are sessionKey
and code
. sessionKey
should be \"clj\"
, \"cljs\"
, \"cljc\"
, or undefined
depending on which of Calva's REPL sessions/connections that should be used. It will depend on your project, and how you connect to it, which session keys are valid. Use cljc
to request whatever REPL session \"cljc\"
files are connected to. Use undefined
to use the current REPL connection Calva would use (depends on which file is active).
An example:
JoyrideClojureScriptJavaScript(-> (p/let [evaluation (calva/repl.evaluateCode \"clj\" \"(+ 2 40)\")]\n(println (.-result evaluation)))\n(p/catch (fn [e]\n(println \"Evaluation error:\" e))))\n
(def evaluate (get-in [:repl :evaluateCode] calvaApi))\n(-> (p/let [evaluation (evaluate \"clj\" \"(+ 2 40)\")]\n(println (.-result evaluation)))\n(p/catch (fn [e]\n(println \"Evaluation error:\" e))))\n
try {\nconst evaluation = await calvaApi.repl.evaluateCode(\"clj\", \"(+ 2 40)\");\nconsole.log(evaluation.result);\n} catch (e) {\nconsole.error(\"Evaluation error:\", e);\n}\n
","boost":7},{"location":"api/#handling-output","title":"Handling Output","text":"The output
member on the Result
object will have any output produced during evaluation. (The errorOutput
member should contain error output produced, but currently some Calva bug makes this not work.) By default the stdout and stderr output is not printed anywhere.
If you want to do something with either regular output or error output during, or after, evaluation, you'll need to provide the output
argument to evaluateCode()
. (The stderr
callback function works, so this is the only way to get at any error output, until the above mentioned Calva bug is fixed.)
An example:
JoyrideClojureScriptJavaScript(def oc (joyride.core/output-channel)) ;; Assuming Joyride is used\n(def evaluate (fn [code]\n(calva/repl.evaluateCode\n\"clj\"\ncode\n\"user\"\n#js {:stdout #(.append oc %)\n:stderr #(.append oc (str \"Error: \" %))})))\n\n(-> (p/let [evaluation (evaluate \"(println :foo) (+ 2 40)\")]\n(.appendLine oc (str \"=> \" (.-result evaluation))))\n(p/catch (fn [e]\n(.appendLine oc (str \"Evaluation error: \" e)))))\n
(def oc (joyride.core/output-channel)) ;; Assuming Joyride is used\n(def evaluate (fn [code]\n((get-in [:repl :evaluateCode] calvaApi)\n\"clj\"\ncode\n\"user\"\n#js {:stdout #(.append oc %)\n:stderr #(.append oc (str \"Error: \" %))})))\n\n(-> (p/let [evaluation (evaluate \"(println :foo) (+ 2 40)\")]\n(.appendLine oc (str \"=> \" (.-result evaluation))))\n(p/catch (fn [e]\n(.appendLine oc (str \"Evaluation error: \" e)))))\n
const evaluate = (code) =>\ncalvaApi.repl.evaluateCode(\"clj\", code, \"user\", {\nstdout: (s) => {\nconsole.log(s);\n},\nstderr: (s) => {\nconsole.error(s);\n},\n});\n\ntry {\nconst evaluation = await evaluate(\"(println :foo) (+ 2 40)\");\nconsole.log(\"=>\", evaluation.result);\n} catch (e) {\nconsole.error(\"Evaluation error:\", e);\n}\n
","boost":7},{"location":"api/#ranges","title":"ranges
","text":"The ranges
module contains functions for retreiving vscode.Ranges and text for pieces of interest in a Clojure document.
All functions in this module have the following TypeScript signature:
(editor = vscode.window.activeTextEditor, position = editor?.selection?.active) => [vscode.Range, string];\n
I.e. they expect a vscode.TextEditor \u2013 defaulting to the currently active editor \u2013 and a vscode.Position \u2013 defaulting to the current active position in the editor (or the first active position if multiple selections/positions exist, and will return a tuple with the range, and the text for the piece of interest requested.
Custom REPL Commands
The ranges
function have corresponding REPL Snippets/Commands substitution variables. It is the same implementation functions used in both cases.
The functions available are:
","boost":7},{"location":"api/#rangescurrentform","title":"ranges.currentForm()
","text":"Retrieves information about the current form, as determined from the editor and position.
Corresponding REPL Snippet variable: $current-form
.
See also about Calva's Current Form on YouTube.
","boost":7},{"location":"api/#rangescurrentenclosingform","title":"ranges.currentEnclosingForm()
","text":"The list/vector/etcetera form comtaining the current form.
Corresponding REPL Snippet variable: $enclosing-form
.
ranges.currentTopLevelForm()
","text":"The current top level form. Outside (comment ...)
(Rich comments) forms this is most often ((def ...), (defgn ...)
, etcetera. Inside Rich comments it will be the current immediate child to the (comment ...)
form.
Corresponding REPL Snippet variable: $top-level-form
.
ranges.currentFunction()
","text":"The current function, i.e. the form in \u201dcall position\u201d of the closest enclosing list.
Corresponding REPL Snippet variable: $current-fn
.
ranges.currentTopLevelDef()
","text":"The symbol being defined by the current top level form. NB: Will stupidly assume it is the second form. I.e. it does not check that it is an actual definition, and will often return nonsense if used in Rich comments.
Corresponding REPL Snippet variable: $top-level-defined-symbol
.
ranges.currentTopLevelForm()
","text":"JoyrideClojureScriptJavaScript (let [[range text] (calva/ranges.currentTopLevelForm)]\n...)\n
(let [[range text] ((get-in [:ranges :currentTopLevelForm]))]\n...)\n
const [range, text] = ranges.currentTopLevelForm();\n
","boost":7},{"location":"api/#editor","title":"editor
","text":"The editor
module has facilites (well, a facility, so far) for editing Clojure documents.
editor.replace()
","text":"With editor.replace()
you can replace a range in a Clojure editor with new text. The arguments are:
editor
, a vscode.TextEditor
range
, a vscode.Range
newText
, a string(-> (p/let [top-level-form-range (first (calva/ranges.currentTopLevelForm))\n_ (calva/editor.replace vscode/window.activeTextEditor top-level-form-range \"Some new text\")]\n(println \"Text replaced!\"))\n(p/catch (fn [e]\n(println \"Error replacing text:\" e))))\n
const topLevelRange = calvaApi.ranges.currentTopLevelForm();\ncalva.editor.replace(topLevelRange, \"Some new text\")\n.then((_) => console.log(\"Text replaced!\"))\n.catch((e) => console.log(\"Error replacing text:\", e));\n
","boost":7},{"location":"api/#document","title":"document
","text":"The document
module provides access to the Clojure/Calva aspects of VS Code TextDocument
s.
document.getNamespace(document?: vscode.TextDocument): string
","text":"document.getNamespace()
returns the namespace of a document.
document
, a vscode.TextDocument
(defaults to the current active document)Example usage. To evaluate some code in the namespace of the current document:
JoyrideJavaScript(calva/repl.evaluateCode \"clj\" \"(+ 1 2 39)\" (calva/document.getNamespace))\n
calva.repl.evaluateCode(\"clj\", \"(+ 1 2 39)\", calva.document.getNamespace());\n
","boost":7},{"location":"api/#documentgetnamespaceandnsformdocument-vscodetextdocument-ns-string-nsform-string","title":"document.getNamespaceAndNsForm(document?: vscode.TextDocument): [ns: string, nsForm: string]
","text":"document.getNamespaceAndNsForm()
returns the namespace and the ns
form of a document as a tuple.
document
, a vscode.TextDocument
(defaults to the current active document)Example usage. To evaluate the ns
form of the current document:
(calva/repl.evaluateCode \"clj\" (second (calva/document.getNamespaceAndNsForm)))\n
calva.repl.evaluateCode(\"clj\", calva.document.getNamespaceAndNsForm()[1]);\n
","boost":7},{"location":"api/#pprint","title":"pprint
","text":"The pprint
module lets you pretty print Clojure code/data using Calva's pretty printing engine (which in turn uses zprint).
pprint.prettyPrint()
","text":"Use pprint.prettyPrint()
to pretty print some Clojure data using your Calva pretty printing options. It accepts these arguments:
text
, a string
with the text to pretty printoptions
, a JavaScript object with pretty printing options, this is optional and will default to the current settings.The function is synchronous and returns the prettified text.
JoyrideJavaScript(println (calva/pprint.prettyPrint \"Some text\")))\n
console.log(calvaApi.pprint.prettyPrint();\n
","boost":7},{"location":"api/#pprintprettyprintingoptions","title":"pprint.prettyPrintingOptions()
","text":"Use to get the current pretty printint options:
","boost":7},{"location":"api/#vscode","title":"vscode
","text":"In the its vscode
submodule, Calva exposes access to things from its own vscode
module instance. It gets important in some situations.
vscode.registerDocumentSymbolProvider()
","text":"This is the [vscode.languages](https://code.visualstudio.com/api/references/vscode-api#languages).registerDocumentSymbolProvider()
function from the Calva extension. Use it if you want to provide symbols for Clojure files together with the ones that Calva provides. (If you use the vscode.languages.registerDocumentSymbolProvider()
function from your extension (or Joyride) you will provide a separate group.)
(-> (joyride/extension-context)\n.-subscriptions\n(.push (calva/vscode.registerDocumentSymbolProvider ...)))\n
(-> yourExtensionContext\n.-subscriptions\n(.push ((get-in calva [:vscode :registerDocumentSymbolProvider]) ...)))\n
yourExtensionContext.subscriptions.push(calva.vscode.registerDocumentSymbolProvider(...));\n
Deprecation candidate
VS Code is still creating a separate group, just with the same name as Calva's, so this API is not good for anything, and we will probably remove it.
","boost":7},{"location":"api/#feedback-welcome","title":"Feedback Welcome","text":"Please let us know how you fare using this API. Either in the #calva or #joyride channels on Slack or via the issues/discussions sections on the repositories. (Whichever seems to apply best.)
","boost":7},{"location":"async-out/","title":"Viewing Async Output While Working On Node Projects withshadow-cljs
","text":"When working on NodeJS projects with shadow-cljs
and Calva, async output does not always appear in the Calva output window. To work around this problem, follow these steps:
shadow-cljs - nREPL server started on port <some-port>
ctrl+alt+c ctrl+alt+c
. For project type select shadow-cljs
, accept the proposed localhost:<some-port>
, and for build
select node-repl
.ctrl+alt+c Enter.
Evaluating forms in Calva will show results in the output window. Synchronous stdout
output will be printed in both the output window and in the terminal where you started the repl. Some asynchronous output may show up in the output window, but all will appear in the terminal.If you use an integrated VSCode terminal to start shadow-cljs, all stdout
will appear in the Calva window with your code. Alternatively, you can use an external terminal, which is especially nice when using a second monitor.
For a discussion of this problem and other connection options, see issue #1468.
"},{"location":"babashka/","title":"Using Calva with Babashka","text":"Since Babashka can be started such that it is an nREPL server, Calva can connect to it and a lot of the features will work.
Calva can also start Babashka and connect its REPL for you, using the Jack-in command.
Don't expect complete support
Babashka's nREPL server is still a bit limited compared to a full cider-nrepl enhanced \"regular\" Clojure nREPL server. Things like function signatures, and more do not work.
This might of course improve in the future, especially if you provide some PRs towards the Babashka nREPL.
","boost":5},{"location":"clj-java-decompiler/","title":"Decompiling and disassembly made easy","text":"If you need some piece of Clojure code to execute as fast as possible you will often benefit from examining the code generated by the Clojure compiler from your code. There is a really easy to use tool for that: clj-java-decompiler. You can make the use of this tool super convenient with Calva custom command snippets.
"},{"location":"clj-java-decompiler/#prerequisites","title":"Prerequisites","text":"Add com.clojure-goes-fast/clj-java-decompiler
as a dependency to the project.
You can add some Calva custom commands configuration to be able to decompile or disassemble any Clojure code in your editor with a keyboard shortcut. Here's an example configuration:
\"calva.customREPLCommandSnippets\": [\n{\n\"name\": \"Decompile current top level form\",\n\"key\": \"d\",\n\"snippet\": \"(require '[clj-java-decompiler.core :refer [decompile]]) (spit \\\"decompiled-$top-level-defined-symbol.java\\\" (with-out-str (decompile $top-level-form)))\"\n},\n{\n\"name\": \"Decompile current form\",\n\"snippet\": \"(require '[clj-java-decompiler.core :refer [decompile]]) (spit \\\"decompiled.java\\\" (with-out-str (decompile $current-form)))\"\n},\n{\n\"name\": \"Disassemble current top level form\",\n\"key\": \"b\",\n\"snippet\": \"(require '[clj-java-decompiler.core :refer [disassemble]]) (spit \\\"bytecode-$top-level-defined-symbol.class\\\" (with-out-str (disassemble $top-level-form)))\"\n},\n{\n\"name\": \"Disassemble current current form\",\n\"snippet\": \"(require '[clj-java-decompiler.core :refer [disassemble]]) (spit \\\"bytecode.class\\\" (with-out-str (disassemble $current-form)))\"\n}\n],\n
Now, with the cursor anywhere in a top level defined function, you can spit out a file with the Java code generated for that function by pressing ctrl+alt+space d
. For the byte code, press ctrl+alt+space b
. The files will be generated in the same folder as the Clojure file and be named decompiled-<function name>.java
and bytecode-<function name>.class
, respectively.
To decompile or disassemble the current form (or selection) press ctrl+alt+space space
and pick the desired command from the quick pick menu that pops up. You can add key
to these too if you want even quicker access, of course. The filenames for the results will here be named without any function name suffix, because there is often no function name that can be used.
See this video for a demo.
"},{"location":"clojure-lsp/","title":"Clojure-lsp","text":"Calva uses a mix of static and dynamic analysis to power the experience. A lot of the static abilities come from clojure-lsp. This enables you to check something up in a project, with a lot of navigational and contextual support, without starting a REPL for it. (And once you do start a REPL you'll get even more capabilities, enabled by the dynamic analysis.)
Which clojure-lsp does Calva use?
Calva defaults to using the latest
clojure-lsp released. To use a different version of clojure-lsp, see the configuration section. Calva does not use the clojure-lsp installed on your system, unless you set the path for clojure-lsp to the installed binary in your settings. You can see what version is being used by running the Clojure-lsp Server Info
command, which will also show the version of clj-kondo that's being used as well as other info.
By default you won't need to install/setup anything as Calva handles that for you by automatically downloading the latest clojure-lsp binary. It can take a while for clojure-lsp to start, especially the first time opening a new project, as clojure-lsp (via clj-kondo
) indexes the project files.
Calva is able to automatically start the clojure-lsp server for you and can be configured to start the server under various different conditions. These behaviours can be configured through the calva.enableClojureLspOnStart
setting, which takes the following options:
When set to \"always-use-first-workspace-root\"
Calva will attempt to start the clojure-lsp in the root of the first workspace folder if it is a valid clojure project. If it is not a valid clojure project it will fall back to starting the fallback server.
This is the default auto-start behaviour.
"},{"location":"clojure-lsp/#when-workspace-opened-use-workspace-root","title":"\"when-workspace-opened-use-workspace-root\"","text":"When set to \"when-workspace-opened-use-workspace-root\"
Calva will start the clojure-lsp in the root of all opened vscode workspaces. All Clojure files in a workspace will be serviced by the clojure-lsp server running in that workspace. This behavior requires that you are opening workspaces with a valid Clojure project in the root (the directory must contain a deps.edn
, project.clj
or shadow-cljs.edn
file).
When set to \"when-file-opened-use-furthest-project\"
Calva will attempt to start the clojure-lsp server whenever a Clojure file is opened. The LSP server will be started in the outermost valid Clojure project or will fall back to starting in the workspace root if no valid Clojure project can be found. A directory is considered a Clojure project if it contains typical Clojure project files such as a deps.edn
, project.clj
, or shadow-cljs.edn
file. When working in a mono-repo style project or in a multi-workspace VS Code configuration you may have multiple LSP servers running, one for each independent Clojure project opened.
Opening files that do not belong to a workspace folder
When opening files that do not belong to any of the workspace folders currently open then Calva will fallback to starting the fallback clojure-lsp server
"},{"location":"clojure-lsp/#never","title":"\"never\"","text":"When set to \"never\"
Calva will never attempt to automatically start the clojure-lsp server. In this case you are responsible for manually starting the server. More advanced users might want to do this in order to have more control over which projects have a clojure-lsp server running for them. To manually start the clojure-lsp server you can run the calva.clojureLsp.start
or the calva.clojureLsp.manage
command and pick the project root. You can also click the clojure-lsp
status bar icon to open the Management Menu.
Additionally Calva has commands for:
Note that the download command will download the configured clojure-lsp version regardless if it is already installed or not. This can be useful when some earlier download has failed resulting in that clojure-lsp can't be started. NB: It will not download anything if calva.clojureLspPath
is set to something non-blank.
As a fallback behaviour Calva may start a clojure-lsp server in a temporary directory and use this to service lsp requests for clojure files that do not belong to a valid clojure project. This will show up in the management menu looking something like:
Any files that are handled by this server will have limited classpath analysis and lsp features. It is therefore recommended to setup your project as a clojure project (by creating a deps.edn
file in the root, for example).
In the status bar Calva will show an indicator with the clojure-lsp status. This status will track the currently open project, showing the status (stopped
, starting
or active
) for the relevant clojure-lsp server.
You can click on the status-bar item to open the clojure-lsp management menu which will look as follows:
The menu shows which clojure-lsp servers are active and which are stopped. Selecting a project will allow you to start/stop/restart the server for that project.
"},{"location":"clojure-lsp/#ignoring-lsp-cache-files","title":"Ignoring LSP cache files","text":"Clojure-lsp stores its project analysis information in your project. Git users can add these lines to their project root directory .gitignore
:
.lsp/.cache/\n.lsp/sqlite.*.db\n
"},{"location":"clojure-lsp/#configuration","title":"Configuration","text":"For information about how to configure clojure-lsp, see the settings page of the clojure-lsp docs.
"},{"location":"clojure-lsp/#changing-the-version-of-clojure-lsp-used-by-calva","title":"Changing the Version of Clojure-lsp Used by Calva","text":"By default, Calva will use the latest released clojure-lsp. You can change the version of clojure-lsp used by Calva by setting the calva.clojureLspVersion
property to a version of clojure-lsp found in its GitHub releases. This can be helpful if you're debugging an issue with clojure-lsp or you want to try out a feature of a new release that Calva does not yet use. However, you must remember to reset this setting in order for Calva to automatically use newer versions of clojure-lsp that are released with new versions of Calva.
Example:
\"calva.clojureLspVersion\": \"2021.04.07-16.34.10\"\n
Special \u201dversion\u201d values
Apart from the actual versions you can use two special values for this setting:
latest
: Will download and use the latest stable build of clojure-lsp, when one becomes available. This is the defaultnightly
: Will always download and use the latest nightly build, whether there is a new version available or not.You can set a path to a custom clojure-lsp to be used by Calva by configuring the calva.clojureLspPath
setting. This should be an absolute path to a native binary or JAR file.
Example:
\"calva.clojureLspPath\": \"/usr/local/bin/clojure-lsp\"\n
Will override any calva.clojureLspVersion
setting
When calva.clojureLspPath
is set, the binary at the path will be used uncoditionally, and the calva.clojureLspVersion
setting will be ignored.
clojure-lsp provides many useful [commands], and Calva has configuration for most of them. The clojure-lsp team works fast and sometimes Calva might miss some command. And Calva's configuration only really work for clojure-lsp commands that take no argument, or where it makes sense to prompt for the argument. Therefore Calva provides a generic command id, clojure-lsp.command
which can be used with keyboard shortcuts and that allow for providing arguments that way. (The command can be used from Joyride too, of course.)
When using the command, provide the args as an tuple of [command-name, arguments]
, where arguments
is an array of any arguments after file-uri, row, col
which are common for all clojure-lsp extra commands and are provided automatically by Calva, based on active text editor and where the cursor is. It can look like so when binding a shortcut for extract-function
:
{\n\"key\": \"ctrl+alt+r f\",\n\"command\": \"clojure-lsp.command\",\n\"args\": [\"extract-function\", [\"new-function\"]]\n},\n
Note that even though extract-function
takes only one argument, you should still provide it via an array.
If something doesn't seem to be working correctly, and you suspect the issue is related to clojure-lsp, a good place to start investigating is the request and response logs between the LSP client and server. In your settings, set clojure.trace.server
to verbose
, then in the VS Code output tab, select the Clojure Language Client
output channel.
It may be helpful to clear the output channel, then perform the action with which you're experiencing a problem, then read through the log for clues or paste the logs into a related issue in the Calva repo.
"},{"location":"clojure-lsp/#server-info-command","title":"Server Info Command","text":"You can run the Clojure-lsp Server Info
command to get information about the running clojure-lsp server, such as the version the server being used, the version of clj-kondo it's using, and more. This info is printed to the \"Calva says\" output channel.
You can open the clojure-lsp log file by running the command Calva Diagnostics: Open Clojure-lsp Log File
. The log file will only be opened with this command if the clojure-lsp server is running and has finished initializing. If you need to open the file when the server is failing to run or initialize, see the clojure-lsp docs for information on the file location.
If clojure-lsp fails to start with \u201cServer initialization failed\u201d messages, it could be because the path to your project contains non-ASCII characters, or that the system PATH variable has been corrupted. (Or something else, of course.)
See this issue for some findings about it: Issue #2251: Server initialization failed error
"},{"location":"clojure-lsp/#related","title":"Related","text":"See also:
Since ClojureDart is Clojure, Calva just works with it. Calva is also automatically configured to make VS COde treat .cljd
files as a Clojure code.
Similar to when using ClojureScript you will often find examples for Dart and Flutter written in, you guessed it, Dart. And then you will often wish there was a converter, because manually transpiling can be a bit tedious and error prone. Luckily you are in the Clojure community, and such a converter is provided:
There are several ways you can leverage this converter, and since you are using Calva, a very convenient way is available. There is a command Calva: Convert Dart code to Clojure/ClojureDart. This command takes whatever text is selected and uses DartClojure to convert it. Lacking a selection, the command will use the whole file.
The workflow demoed in the video is something like so:
NB: The conversion will not always work. DartCLojure is work in progress. See the project repo for limitations and scope. Often when conversion, the error message will give you a clue to what is problematic. Try adjust your code selection and you will probably be able to get at least some help from the converter.
Speaking of WIP...
","boost":4},{"location":"clojuredart/#work-in-progress","title":"Work in Progress","text":"ClojureDart is very new and being super actively developed. Some feature are still missing. Like a REPL. Once that is added we will also add ClojureDart jack-in and connect support to Calva.
","boost":4},{"location":"clojuredart/#happy-clojuredart-hacking","title":"Happy ClojureDart Hacking!","text":"Please feel welcome to the #clojuredart and #calva channel at the Clojurians Slack for questions, suggestions and support.
","boost":4},{"location":"clojuredocs/","title":"ClojureDocs integration","text":"clojuredocs.org is the goto place #1 for finding out more about Clojure core(-ish) functions, macros, etcetera. It contains the doc strings from the functions and adds crowd sourced examples of usage and see alsos. You can surf for quite long on that site without getting bored. \ud83d\ude04
You can surf ClojureDocs in CalvaCalva integrates this information in two ways:
ctrl+alt+r d
ctrl+alt+o d
That means that if you just want to glance at the examples, you look in the hover. And when you want to bring the examples to the REPL to play with them, you can do so very easily.
ClojureScript support
ClojureDocs information is available both for Clojure and ClojureScript files. However, clojuredocs.org only keeps info for Clojure. Thus: All information Calva shows about a symbol will be about the Clojure respresentation of that symbol. (The symbol might not even exist in ClojureScript.)
","boost":4},{"location":"clojuredocs/#clojuredocs-repl-surfing","title":"ClojureDocs REPL Surfing","text":"Since the ClojureDocs information includes see-alsos, you can go for super interactive ClojureDocs surfing right in the file you are editing. Say you have this function:
(defn trim-text\n\"Returns text without surrounding whitespace if not empty, otherwise nil\"\n[text]\n(let [trimmed-text (clojure.string/trim text)]\n(when-not (empty? trimmed-text)\ntrimmed-text)))\n
Then you hover on when-not
and scroll down a bit in the hover:
That first example would be interesting to play with, right? Click To Rich Comment and you will get:
(defn trim-text\n\"Returns text without surrounding whitespace if not empty, otherwise nil\"\n[text]\n(let [trimmed-text (clojure.string/trim text)]\n(when-not (empty? trimmed-text)\ntrimmed-text)))\n\n(comment\n;; = when-not - Example 1 = \n\n;; build tuples over sets with the same cardinality \n(map\n#(when-not (= %2 %3) [%1 %2 %3])\n(iterate inc 0) ; a lazy list of indices\n[:a :b :c]\n[:a :a :a])\n;;=> (nil [1 :b :a] [2 :c :a])\n\n;; See also:\nwhen\nwhen-let\nif\n)\n
There you can evaluate the (map ...)
form using alt+enter
, modify it and evaluate again. You can also hover over map
, iterate
, or any of the \u201dSee also:\u201d symbols to find more fun examples to play with. And so on and so forth.
See these two tweets for some videos of early versions of this functionality:
Please retweet!
","boost":4},{"location":"clojuredocs/#quirks","title":"Quirks","text":"Some of the ClojureDocs entries have text that is not really Clojure code, and sometimes even structural errors. This can break the structural integrity of your Clojure file. If you run into trouble trying to heal things, you can always use Undo until the Rich Comment is gone.
","boost":4},{"location":"commands-top10/","title":"The Top 10 Calva Commands","text":"There are not all that many Calva commands. You can learn them all if you like, but here are the most important ones to know about for effective Clojure/ClojureScript coding:
ctrl+w
(shift+alt+right
on Windows and Linux)alt+ctrl+c enter
, evaluates the namespace code in the active editor tab. This also loads any required namespaces, and generally gives Calva what it needs to work.ctrl+enter
finds the form from the cursor position, evaluates it and displays the result inline. Hit esc
to dismiss the results display.alt+enter
: inline evaluate the current top-level form. This also works inside (comment)
forms. Use it to (re)define vars and then inside comment forms you can verify that they do what you want them to do.escape
: (VIM Extension users should read Using Calva with the VIM Extension).There are also two commands for bringing over the current form and the current top level form over to the repl window:
ctrl+alt+c ctrl+alt+e
(ctrl+alt+c ctrl+alt+v
on Windows): to paste the current form in the REPL window.ctrl+alt+c ctrl+alt+space
: to paste the current top-level form in this windowYou can also switch the name space of the output/repl window to that of the current file: alt+ctrl+c alt+n
ctrl+alt+c p
. It's on by default. There is a status bar button showing the status and that also can be used to toggle the setting.ctrl+alt+c c
(current form), ctrl+alt+c ctrl+space
(current top level form)ctrl+alt+c r
ctrl+alt+c ctrl+alt+e
(ctrl+alt+c ctrl+alt+v
on Windows)ctrl+alt+c ctrl+alt+space
ctrl+alt+c t
ctrl+alt+c shift+t
ctrl+alt+c ctrl+alt+t
ctrl+alt+c ctrl+t
ctrl+alt+c s
.ctrl+alt+c .
See also:
Many projects grow out of the template phase and call for custom developer workflows involving application start commands, customized REPLs, and what have you. Even some templates add this kind of complexity. To make Jack-in usable for a broader set of projects, Calva has a setting keyed calva.replConnectSequences
which lets you configure one ore more connect sequences.
NB: Connect sequence configuration affects Calva's Jack-in menu in the following ways:
A connect sequence configures the following:
name
: (required) This will show up in the Jack-in quick-pick menu when you start Jack-in (see above).projectType
: (required) This is either \"Leiningen\u201d, \"deps.edn\", \"shadow-cljs\", \"lein-shadow\", \"Gradle\", \u201dgeneric\u201d, or \"custom\".autoSelectForJackIn
: A boolean. If true, this sequence will be automatically selected at Jack-in, suppressing the Project Type. Use together with projectRootPath
to also suppress the Project Root menu. Add usage of menuSelections
to go for a prompt-less REPL Jack-in. If you have more than one sequence with autoSelectForJackIn
set to true, the first one will be used.autoSelectForConnect
: A boolean. If true, this sequence will be automatically selected at Connect, suppressing the Project Type menu. Use together with projectRootPath
to also suppress the Project Root menu. If you have more than one sequence with autoSelectForConnect
set to true, the first one will be used.projectRootPath
: An array of path segments leading to the root of the project to which this connect sequence corresponds. Use together with autoSelectForJackIn
/autoSelectForConnect
to suppress the Project Root menu. The path can be absolute or relative to the workspace root. If there are several Workspace Folders, the workspace root is the path of the first folder, so relative paths will only work for this first folder.nReplPortFile
: An array of path segments with the project root-relative path to the nREPL port file for this connect sequence. E.g. For shadow-cljs this would be [\".shadow-cljs\", \"nrepl.port\"]
.afterCLJReplJackInCode
: Code to evaluate in the CLJ REPL once it has been created. You can use either a string or an array of strings. If you use an array, the strings will be joined with a newline character to form the resulting code.customJackInCommandLine
: A string with a command line that should be used to launch the REPL. See Custom Command Line, below.cljsType
: This can be either \"Figwheel Main\", \"shadow-cljs\", \"ClojureScript built-in for browser\", \"ClojureScript built-in for node\", \"lein-figwheel\", \"none\", or a dictionary configuring a custom type. If set to \"none\", Calva will skip connecting a ClojureScript repl. A custom type has the following fields:dependsOn
: (required) Calva will use this to determine which dependencies it will add when starting the project (Jacking in). This can be either \"Figwheel Main\", \"shadow-cljs\", \"ClojureScript built-in for browser\", \"ClojureScript built-in for node\", \"lein-figwheel\", or \u201dUser provided\u201d. If it is \"User provided\", then you need to provide the dependencies in the project or launch with an alias (deps.edn), profile (Leiningen), or build (shadow-cljs) that provides the dependencies needed.isStarted
: Boolean. For CLJS REPLs that Calva does not need to start, set this to true. (If you base your custom cljs repl on a shadow-cljs workflow, for instance.)startCode
: Clojure code to be evaluated to create and/or start your custom CLJS REPL.isReadyToStartRegExp
: A regular expression which, when matched in the stdout from the startCode evaluation, will make Calva continue with connecting the REPL, and to prompt the user to start the application. If omitted and there is startCode Calva will continue when that code is evaluated.openUrlRegExp
: A regular expression, matched against the stdout of cljsType evaluations, for extracting the URL with which the app can be started. The expression should have a capturing group named url
. E.g. \"Open URL: (?\\<url>S+)\"shouldOpenUrl
: Choose if Calva should automatically open the URL for you or not.connectCode
: (required) Clojure code to be evaluated to convert the REPL to a CLJS REPL that Calva can use to connect to the application. (For some setups this could also conditionally start the CLJS REPL. If so: startCode
should be omitted.)isConnectedRegExp
: (required) A regular expression which, when matched in the stdout
from the connectCode
evaluation, will tell Calva that the application is connected. The default is To quit, type: :cljs/quit
and you should leave it at that unless you know it won't work.printThisLineRegExp
: regular expression which, when matched in the stdout
from any code evaluations in the cljsType
, will make the matched text be printed to the Output window.buildsRequired
: Boolean. If the repl type requires that builds are started in order to connect to them, set this to true.menuSelections
: a dictionary with pre-filled-in selections for the Jack-in and Connect prompts, making Calva not prompt for that particular selection:leinProfiles
: At Jack-in to a Leiningen project, use these profiles to launch the repl.leinAlias
: At Jack-in to a Leiningen project, launch with this alias. Set to null
to launch with Calva's default task (a headless repl), w/o prompting.cljAliases
: At Jack-in to a deps.edn project, use these aliases to launch the repl.cljsLaunchBuilds
: The cljs builds to start/watch at Jack-in/connect.cljsDefaultBuild
: Which cljs build to attach to at the initial connect.jackInEnv
: An object with environment variables that will be merged with the global calva.jackInEnv
and then applied to the Jack-in process. The merge is very similar to how Clojure's merge
works. So for any common keys between the global setting and this one, the ones from this setting will win.The Calva built-in sequences also use this format, check them out to get a clearer picture of how these settings work.
Force the project type menu to show
The convenience of autoSelectForJackIn/Connect
can be an inconvenience when you want to use another project type/sequence for a project. For this reason, the calva.connect
and calva.jackIn
can be provided with an option disableAutoSelect
, which forces the project root and project type menus to show. See Options for the Connect Command and Options for the Jack-in Command for more on this.
Path segments
projectRootPath
and nReplPortFile
both take an array of path segments. This is to make the paths work cross-platform. If you can't be bothered splitting up the path in segments, put the whole path in the first segment, though please note that if you use Windows path separators, these will not work for users with Linux or macOS.
Custom command lines are there to bridge the gap to those situations where standard Jack-in command lines don't reach. Like:
A custom command line is executed from same directory as the REPL project root (See projectRootPath
, above), and can be as simple as my-repl-jack-in-command
. You can use a relative or absolute path to your command line.
If your custom command line starts a REPL of a project type that is not \u201dknown\u201d/built-in to Calva, use custom
as the projectType
for the connect sequence.
You can use placeholders in your command line, and Calva will substitute them before executing the command. All these placeholders will also be provided to your script via environment variables with the same names (except dashes will be underscores in the env variable names):
nREPL dependency versions:
JACK-IN-NREPL-VERSION
JACK-IN-CIDER-NREPL-VERSION
JACK-IN-CIDER-PIGGIEBACK-VERSION
Paths:
JACK-IN-PROJECT-ROOT-PATH
: (See projectRootPath
, above)JACK-IN-NREPL-PORT-FILE
: The path of the nREPL port file (see nReplPortFile
above)Depending on the project type Calva will also look for these placeholders:
JACK-IN-CLJ-MIDDLEWARE
: The nREPL middleware to be used for the Clojure REPLJACK-IN-CLJS-MIDDLEWARE
: The nREPL middleware to be used for the ClojureScript REPLJACK-IN-LEIN-PROFILES
: For Leiningen projects, the profiles selected by the userJACK-IN-LEIN-LAUNCH-ALIAS
: For Leiningen projects, the launch alias selected by the userJACK-IN-CLI-ALIASES
: For deps.edn projects, the aliases selected by the userJACK-IN-CLJS-LAUNCH-BUILDS
: For ClojureScript REPLs that configures builds, the builds selected by the userJACK-IN-NREPL-PORT
: For some project types (currently nbb
and Babashka
) Calva provided the TCP port they should use.Calva has a built-in jack-in sequence for starting a Babashka REPL and connect to it. It works as long as the bb
process is on the same host as VS Code/Calva is running. So if you want it to run in WSL, but VS Code is running on your computer you need to start bb
slightly differently. These settings in your VS Code settings file will give you a jack-in option that works for this:
\"calva.replConnectSequences\": [\n{\n\"name\": \"Bashbabka (WSL)\",\n\"projectType\": \"custom\",\n\"customJackInCommandLine\": \"bash -c 'bb --nrepl-server JACK-IN-NREPL-PORT'\",\n},\n],\n
If you place it in your user settings you will have access to it from any workspace.
","boost":6},{"location":"connect-sequences/#an-exampleskeleton-script","title":"An example/skeleton script","text":"This script doesn't actually start a REPL, it's provided more for giving you an idea about what it could look like, and as a starting point for your real scripts:
#!/usr/bin/env bb\n\n(require '[clojure.string :as str])\n\n(defn parse-args [args]\n(loop [args args\nparsed {}]\n(if (empty? args)\nparsed\n(let [[flag value & rest-args] args]\n(case flag\n\"--aliases\" (recur rest-args (assoc parsed :aliases value))\n\"--cider-nrepl-version\" (recur rest-args (assoc parsed :cider-nrepl-version value))\n(do (println \"Unknown parameter:\" flag) (System/exit 1)))))))\n\n(defn process-args [args]\n(let [aliases (str/split (:aliases args) #\",\")\ncider-nrepl-version (:cider-nrepl-version args)\nproject-root-path (System/getenv \"JACK_IN_PROJECT_ROOT_PATH\")]\n(println \"Aliases:\")\n(doseq [alias aliases]\n(println alias))\n(println \"CIDER nREPL version:\" cider-nrepl-version)\n(println \"JACK_IN_PROJECT_ROOT_PATH:\" project-root-path)))\n\n(def parsed-args (parse-args *command-line-args*))\n\n(when (= *file* (System/getProperty \"babashka.file\"))\n(process-args parsed-args))\n
It's written in Babashka to encourage you to write your shell scripts in a civilized language. \ud83d\ude00 See the article Changing my mind: Converting a script from bash to Babashka for a small success-story about this mindset. See also bash2bb.
The script reads JACK-IN-CLJS-LAUNCH-BUILDS
and JACK-IN-CIDER-NREPL-VERSION
from the command line, and JACK_IN_PROJECT_ROOT_PATH
from the environment. It could be configured for use in a custom connect sequence like this:
\"customJackInCommandLine\": \"../../custom-jack-in.bb --aliases JACK-IN-CLJS-LAUNCH-BUILDS --cider-nrepl-version JACK-IN-CIDER-NREPL-VERSION\",\n
Note how in this case the REPL is started two directories \u201ddown\u201d from the workspace root where the script resides.
","boost":6},{"location":"connect-sequences/#example-sequences","title":"Example Sequences","text":"Whether you just want to speed up your workflow or encode some workflow/mechanics into it, it's often the case that you can create a custom sequence that helps.
","boost":6},{"location":"connect-sequences/#minimal-menus-with-full-stack-shadow-cljs-repls","title":"Minimal menus with full stack shadow-cljs REPLs","text":"Minimize the amount of selecting from the Jack-in/Connect menu when working with a full-stack shadow-cljs + deps/lein project:
{\n\"name\": \"backend + frontend\",\n\"projectType\": \"shadow-cljs\",\n\"cljsType\": \"shadow-cljs\",\n\"menuSelections\": {\n\"cljsLaunchBuilds\": [\n\":app\",\n\":test\",\n],\n\"cljsDefaultBuild\": \":app\"\n}\n}\n
See shadow-cljs + Clojure with Calva: The basics for how Calva and nREPL work with ClojureScript.
","boost":6},{"location":"connect-sequences/#polylith","title":"Polylith","text":"This is the connect sequences used in the Polylith Real World App. The (start)
sequence lets you jack-in to the project, and starts the Real World App without any prompts. The (connect)
sequence can be used if you prefer to start the REPL manually, and want to connect without prompts.
\"calva.replConnectSequences\": [\n{\n\"projectType\": \"deps.edn\",\n\"afterCLJReplJackInCode\": \"(require '[dev.server] :reload) (in-ns 'dev.server) (start! 6003)\",\n\"name\": \"Polylith RealWorld Server REPL (start)\",\n\"autoSelectForJackIn\": true,\n\"projectRootPath\": [\".\"],\n\"cljsType\": \"none\",\n\"menuSelections\": {\n\"cljAliases\": [\"dev\", \"test\"]\n}\n},\n{\n\"projectType\": \"deps.edn\",\n\"name\": \"Polylith RealWorld Server REPL (connect)\",\n\"autoSelectForConnect\": true,\n\"projectRootPath\": [\".\"],\n\"cljsType\": \"none\",\n}\n],\n\"calva.autoConnectRepl\": true,\n
The calva.autoConnectRepl
, when set to true
, makes Calva, at project open, look for the nRepl port file and automatically connect the repl if the file exists. Therefore, you can leave the app running when you close the project in VS Code, and Calva will reconnect when you open the project again. (Alternatively, maybe you just need to reload the VS Code window and not lose the REPL state.)
Setting for a full-stack application. It starts the backend server when the CLJ REPL has started. Then proceeds to create a custom CLJS REPL (calling in to the application code for this). And then connects to it.
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Example Sequence\",\n\"projectType\": \"Clojure-CLI\",\n\"afterCLJReplJackInCode\": \"(go)\",\n\"cljsType\": {\n\"startCode\": \"(do (require '[cljs-test.main :refer :all])(start-nrepl+fig))\",\n\"isReadyToStartRegExp\": \"Prompt will show\",\n\"connectCode\": \"(do (use 'cljs-test.main) (cljs-repl))\",\n\"isConnectedRegExp\": \"To quit, type: :cljs/quit\",\n\"printThisLineRegExp\": \"\\\\[Figwheel\\\\] Starting Server at.*\"\n}\n}\n]\n}\n
","boost":6},{"location":"connect-sequences/#juxt-edge","title":"JUXT Edge","text":"Here is an example from the JUXT Edge project template. It adds two sequences, one for when only the Clojure REPL should be launched and one for when the customized Edge cljs repl should also be connected. The Edge backend + frontend sequence specifies that the web app should be opened by Calva, making cljs repl connection more stable, and also adds menuSelections
to skip the launch aliases prompt.
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Edge backend only\",\n\"projectType\": \"deps.edn\"\n},\n{\n\"name\": \"Edge backend + frontend\",\n\"projectType\": \"deps.edn\",\n\"cljsType\": {\n\"dependsOn\": \"Figwheel Main\",\n\"startCode\": \"(do (require 'dev-extras) (dev-extras/go) (println \\\"Edge Figwheel Main started\\\") ((resolve 'dev-extras/cljs-repl)))\",\n\"isReadyToStartRegExp\": \"Edge Figwheel Main started\",\n\"openUrlRegExp\": \"Website listening on: (?<url>\\\\S+)\",\n\"printThisLineRegExp\": \"\\\\[Edge\\\\]\",\n\"shouldOpenUrl\": true,\n\"connectCode\": \"(do (require 'dev-extras) ((resolve 'dev-extras/cljs-repl)))\",\n\"isConnectedRegExp\": \"To quit, type: :cljs/quit\",\n\"buildsRequired\": false\n},\n\"menuSelections\": {\n\"cljAliases\": [\n\"dev\",\n\"build\",\n\"dev/build\"\n],\n}\n}\n]\n}\n
","boost":6},{"location":"connect-sequences/#plain-depsedn","title":"Plain deps.edn","text":"A deps.edn sequence that does not promote the ClojureScript repl at all (leaving it a Clojure REPL), and leaves that up to you to do interactively. (Could be useful while you are developing a custom cljs repl.) The example is for when adapting a Figwheel Main repl.
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Do not promote to cljs\",\n\"projectType\": \"deps.edn\",\n\"cljsType\": {\n\"dependsOn\": \"Figwheel Main\",\n\"connectCode\": \"\\\"Don't promote me bro!\\\"\",\n\"isConnectedRegExp\": \"Don't promote me bro!\"\n}\n}\n]\n}\n
","boost":6},{"location":"connect/","title":"Connect Calva to Your Project","text":"When connected to your project's REPL Calva lets you evaluate code, supporting Interactive Programming. The REPL connection is also used to provide IDE functionality through the dynamic knowledge about the project that the REPL enables. The REPL communication depends on that your project has an nREPL server running, and that the cider-nrepl middleware is enabled.
For the easiest way to provide your project with these dependencies, the recommended way to connect is to use the so called Jack-in command.
","boost":7},{"location":"connect/#jack-in-let-calva-start-the-repl-for-you","title":"Jack-in: Let Calva Start the REPL For You","text":"This way Calva can make sure it is started with the dependencies needed for a working Clojure and/or ClojureScript session. This is often referred to as Jack in (because that is what it is called in CIDER).
Jack-in supports both CLJ and for CLJS, and has built-in configurations for Leiningen, deps.edn, shadow-cljs, Gradle projects, as well as for the CLJS repl types: Figwheel Main, lein-figwheel (legacy Figwheel), shadow-cljs, and ClojureScript built-ins for both browser and node.js. Using jack-in provides your development environment with all the dependencies you need for Calva to work.
It works like so:
ctrl+alt+c ctrl+alt+j
.See also: Workspace Layouts
About project roots
You must have a project file, such as project.clj
for Leiningen, or deps.edn
for deps.edn, or shadow-cljs.edn
for shadow-cljs, or settings.gradle
/settings.gradle.kts
for Gradle in the directory opened in VS Code in order for jack-in to work. If, after adding the project file, you experience an error during jack-in that says something could not be located, make sure you have the correct dependencies in your project file. For example, when using the Figwheel Main project type, you should have com.bhauman/figwheel-main
in your project dependencies.
See also below, regarding multiple projects in a workspace
","boost":7},{"location":"connect/#aliases-profiles-builds","title":"Aliases, Profiles, Builds","text":"When Jack-in starts it will depend on the project type, and whether ClojureScript is involved or not, and if it is, what kind of ClojureScript project, what will happen next. Calva will analyze the project files and will then give you prompts with selections based on what is found there.
You will need some basic knowledge about the project and the project type terminologies to answer the prompts.
There are ways to tell Calva the answers to these prompts beforehand, so that Jack-in can be a zero-prompting command. Read on.
","boost":7},{"location":"connect/#customizing-jack-in","title":"Customizing Jack-in","text":"The main mechanism for customizing your Jack-in, including automating menu selections, and custom CLJS REPL types is Custom Connect Sequences. See also Customizing Jack-in and Connect
","boost":7},{"location":"connect/#connecting-without-jack-in","title":"Connecting Without Jack-in","text":"If, for whatever reasons, you can't use Jack-in with your project (possibly because the REPL is started as part of some other job) all is not lost. Old fashioned Connect to a running REPL is still there for you. For all features to work in Calva while connecting to a running REPL, your environment needs to have REPL related dependencies set up.
However, just as before it can be tricky to get the dependencies right. Consider using Jack in to inform yourself on how to start your REPL to Calva's satisfaction. When you use Jack in, Calva starts a VS Code task for it and the command line used is displayed in the terminal pane used to handle the task. Reading that command line tells you what dependencies are needed for your project.
Even better: Copying that command line gives you the command to start the REPL with the correct dependencies.
All this said, I still recommend you challenge the conclusion that you can't use Jack-in.
Copy the Jack-in command line
There is a Calva command for copying the Jack-in command line to the clipboard. It will copy the command line including commands to change to the current REPL project root, avoiding hard-to-detect errors when starting the REPL in the wrong directory.
The Generic Project Type
A reason to use the connect to a running REPL way, can be that Calva does not have a built in connect sequence/project type for the particular REPL you want to connect to. Maybe it is something like Lingy which doesn't yet have a built in Calva connect sequence. As long as there is an nREPL server to connect to, you can Connect with Calva, using the Generic connect sequence/project type. (You can also create a connect sequence with a custom command line, and use Jack-in anyway.)
See also Customizing Jack-in and Connect
","boost":7},{"location":"connect/#starting-the-repl-from-application-code","title":"Starting the REPL from application code?","text":"If your project is setup so that the REPL server is started by the application code, you will need to get the cider-nrepl middleware in place. See the cider-nrepl docs about embedding nREPL in your application.
","boost":7},{"location":"connect/#auto-select-project-type-and-project-root","title":"Auto-select Project Type and Project Root","text":"You can make both Jack-in and Connect stop prompting you for project type and project root path in projects where you always want to use the same. See Connect Sequences.
","boost":7},{"location":"connect/#monorepos-multiple-clojure-projects-in-one-workspace","title":"Monorepos / multiple Clojure projects in one workspace","text":"If the workspace is a monorepo, Polylith repo or just a repository with more than one Clojure project, Calva will start the connect sequence with prompting for which project to start/connect to.
","boost":7},{"location":"connect/#shadow-cljs","title":"shadow-cljs","text":"Please see the shadow-cljs page.
","boost":7},{"location":"connect/#troubleshooting","title":"Troubleshooting","text":"","boost":7},{"location":"connect/#jack-in-and-main-opts","title":"Jack-in and:main-opts
","text":"When Calva starts the project REPL and connects to it (a.k.a. Jack-in), this is done by starting an nREPL server. For deps.edn projects this by default means that Calva will add -m ...
with options that starts the server.
However: If you choose an alias at Jack-in that specifies :main-opts
, it will make the Clojure CLI to add main opts and Calva will then not override these by adding -m ...
to the command line. This means that an alias that specify :main-opts
must result in an nREPL server being started, or else Calva won't have a server to connect to. Calva won't further analyze this, but will just warn you at Jack-in.
If you don't know if an alias starts an nREPL server or not, by all means, try it, if you have reasons for using that alias. You will notice if Jack-in works or not. If it doesn't work, you will need to run without that alias, or fix what happens when that alias is used so that an nREPL server is started. See https://nrepl.org/nrepl/usage/server.html about ways to do this.
","boost":7},{"location":"connect/#command-not-found-errors-when-jacking-in","title":"Command Not Found Errors When Jacking In","text":"If you get command not found
error when Calva tries to start your project, and you know you have the command installed, it's probably because VS Code starts from an environment where the command is not on the $PATH
. It can look like so:
lein update-in :dependencies conj '[nrepl,\"0.8.3\"]' -- update-in :plugins conj '[cider/cider-nrepl,\"0.25.8\"]' -- update-in '[:repl-options,:nrepl-middleware]' conj '[\"cider.nrepl/cider-middleware\"]' -- repl :headless\n/bin/sh: lein: command not found\nJack-in process exited. Status: 127\n
The fix is to always start VS Code from the command line:
$ code\n
You might need to first run the Shell Command: Install code
command in PATH.
This will also make sure your REPL has access to the environment you probably expect it to have access to. See below.
","boost":7},{"location":"connect/#go-to-definition-not-working-for-java-definitions","title":"Go to Definition Not Working for Java Definitions","text":"On some systems, the Java source may not be installed along with the JDK. The source must be present on your system in order to navigate to Java definitions. See this comment for more details.
","boost":7},{"location":"connect/#environment-variables-are-not-readable-from-repl","title":"Environment Variables Are Not Readable From REPL","text":"If you've added environment variables in your OS, such as in your ~/.bashrc
file (Linux), in order for them to be read in a REPL created by Calva's jackin command, VS Code must be started from a shell where the environment variables are defined. For example, if you can open a bash terminal and run echo $SOME_VAR
and see the value there, then open VS Code from that terminal with code <project path>
.
It may be helpful to view the messages sent between nREPL and Calva when troubleshooting an issue related to the REPL. See how to do that here.
","boost":7},{"location":"contribute/","title":"Contribute to Calva","text":"There are many ways to contribute:
#calva
channelBe creative!
"},{"location":"contribute/#please-star-the-calva-repo","title":"Please star the Calva repo!","text":"Happy Coding! \u2764\ufe0f
"},{"location":"custom-commands/","title":"Custom REPL Commands","text":"Calva supports configuration of custom command snippets that you can evaluate in the REPL at will. This is useful if your workflow has you repeatedly evaluating a particular piece of code. There are two ways to use these:
calva.customREPLCommandSnippets
to configure it. Then either bind keyboard shortcuts to them or use the command Run Custom REPL Command to access it. The command will give you a menu with the snippets you have configured.Joyride
For some use cases you might be better served by/want to combine these with using the VS Code Extension API, and that of Calva, or any other extension, through Joyride.
The calva.customREPLCommandSnippets
is an array of objects with the following fields (required fields in bold):
name
: The name of the snippet as it will appear in the picker menusnippet
: The code that will be evaluatedkey
: A key can be used to reference the snippet from Run Custom REPL Command keyboard shortcut arguments. It will also be used in the quick-pick menu.ns
: A namespace to evaluate the command in. If omitted the command will be executed in the namespace of the current editor.repl
: Which repl session to use for the evaluation. Either \"clj\"
or \"cljs\"
. Omit if you want to use the session of the current editor.evaluationSendCodeToOutputWindow
: (default true
) Whether the evaluated code should be echoed to the Output/REPL window.There are also substitutions available, which will take elements from the current state of Calva and splice them in to the text of your command before executing it. They are
$line
: Current line number in editor$column
: Current column number in editor$file
: Full name of the current file edited$file-text
: The text of the current file edited$ns
: The namespace used for evaluating the command$editor-ns
: The namespace of the editor from which the command was run$selection
: The currently selected text$current-form
: The text of the current form$current-pair
: The text of the current pair if in a binding, otherwise empty string$enclosing-form
: The text of the current enclosing form$top-level-form
The text of the current top level form$current-fn
: The sexpr/form at call position in the current list, e.g. str
with (defn foo [] (str \"foo\" \"bar|\"))
$top-level-defined-symbol
: The second symbol of the top level form, e.g. foo
with (defn foo [] (str \"foo\" \"bar|\"))
$head
: The text between the start of the current list to the cursor$tail
: The text between the cursor and the end of the current listSettings from your User (global) level and the workspace are merged.
With these User settings:
\"calva.customREPLCommandSnippets\": [\n{\n\"name\": \"Call Current Form\",\n\"key\": \"c\",\n\"snippet\": \"($current-form)\"\n},\n{\n\"name\": \"Call Current Top Level Form\",\n\"key\": \"t\",\n\"snippet\": \"($top-level-form)\"\n},\n{\n\"name\": \"CLJ Test Top Level Defined Symbol\",\n\"repl\": \"clj\",\n\"snippet\": \"(clojure.test/test-var #'$top-level-defined-symbol)\"\n},\n{\n\"name\": \"CLJS Test Top Level Defined Symbol\",\n\"repl\": \"cljs\",\n\"snippet\": \"(cljs.test/test-var #'$top-level-defined-symbol)\",\n\"key\": \"tab\"\n}\n],\n
And these Workspace settings:
\"calva.customREPLCommandSnippets\": [\n{\n\"name\": \"Remount CLJS App\",\n\"key\": \"r\",\n\"repl\": \"cljs\",\n\"ns\": \"example.app\",\n\"snippet\": \"(start)\"\n}\n],\n
Issuing Run Custom REPL Command will then render this VS Code menu:
The default keyboard shortcut for the command is ctrl+alt+space space
. (Beware: on MacOS it may conflict with the default shortuct for Input Sources - Select next source in Input menu.)
There are four ways to bind shortcuts to custom commands:
key
shortcut. These are predefined as ctrl+alt+space <something>
, where <something>
is one of:0
through 9
a
through z
right
, left
, up
, or down
tab
, backspace
, ,
, .
, or -
calva.runCustomREPLCommand
to a shortcut with whatever code you want to evaluate in the args
slot. You have access to the substitution variables here as well.calva.runCustomREPLCommand
to a keyboard shortcut referencing the key
of one of your calva.customREPLCommandSnippets
. (If not using any of the key
s mentioned in 1.)calva.runCustomREPLCommand
to a shortcut with a customREPLCommandSnippets
in the args
slot. You have access to the substitution variables here as well.Here's an example shortcut entry for the 4th option:
{\n\"key\": \"ctrl+cmd+u alt+enter\",\n\"command\": \"calva.runCustomREPLCommand\",\n\"args\": {\n\"ns\": \"user\",\n\"snippet\": \"$current-form\",\n}\n},\n
This would evaluate the current form in the user
namespace. Please note that this Custom REPL Command will not show up in the custom commands menu mentioned above.
Calva supports custom snippets that will display their result inside the tooltip. They will only work when connected to a repl, since they eval code in it. This is mostly useful for tooling authors that want to integrate with calva. Be careful with these, since they will be executed anytime Calva displays a tooltip. So they should be fast and probably not have any side effects.
The hover snippets accept the same inputs as the Custom REPL Commands, except for the hotkey:
\"calva.customREPLHoverSnippets\": [\n{\n\"name\": \"eval text on hover\",\n\"repl\": \"clj\",\n\"ns\": \"example.app\",\n\"snippet\": \"(str \\\"$hover-text\\\")\"\n}\n]\n
With this setting anything the mouse is over will also be shown inside its tooltip. There are now also hover-
versions of most substitutions. Those currently only work inside the hover snippets.
:customREPLCommandSnippets
and :customREPLHoverSnippets
can be also be configured in your user config at .config/calva/config.edn
realative to your system home directory, or .calva/config.edn
relative to the workspace root. Three things to note about this:
.calva/config.edn
will be automatically noticed by Calva, and refresh the config. This will not happen with the user config file.:name
entry, and if you change the name, the old entry won't be removed until the VS Code window is reloaded.As for 2.: There is a command Calva: Refresh REPL snippets from User config.edn.
There is also a command to open the User config.edn, for convenience: Calva: Open REPL snippets User config.edn. This command creates the file if it doesn't previously exist.
","boost":4},{"location":"custom-commands/#snippets-inside-deps","title":"Snippets Inside Deps","text":"A new experimental feature lets library authors ship snippets inside their jar files. These accept the same options as above but should be placed in \"resources/calva.exports/config.edn\" inside the jar.
{:customREPLCommandSnippets\n[{:name \"edn test\"\n:key \"a\"\n:snippet ($current-form)}]\n:customREPLHoverSnippets\n[{:name \"edn hover\"\n:snippet (str \"$hover-tex\")}\n{:name \"edn hover show val\"\n:snippet (str \"### EDN show val\\n```clojure\\n\" (pr-str (eval (symbol (str \"$ns\" \"/\" \"$hover-top-level-defined-symbol\")))) \"\\n```\")}]}\n
","boost":4},{"location":"customizing-jack-in-and-connect/","title":"Customize Jack-in and Connect","text":"Since Jack-in and connect both are about connecting the REPL, and only differ in how the REPL is started, many settings and configuration points are shared between the two concepts. A major customization point is Custom Connect Sequences, which are relevant for both Jack-in and Standalone Connect scenarios.
This page lists some more Jack-in and Connect configuration options.
","boost":7},{"location":"customizing-jack-in-and-connect/#auto-evaluate-code-on-connect","title":"Auto-evaluate Code on Connect","text":"You can have Calva evaluate code whenever a REPL has been connected via the calva.autoEvaluateCode.onConnect
setting. It has two entries clj
and cljs
:
clj
: \"Code to evaluate when the Clojure REPL has been connected.repl-requires
/REPL utilities (like source
, doc
, etcetera). (Note that there is also a command to do this on demand.).afterCLJReplJackInCode
in any connect sequence used.cljs
: Code to evaluate when the ClojureScript REPL has been connected.repl-requires
/REPL utilities (like source
, doc
, etcetera). (Note that there is also a command to do this on demand.).clj
.Set either of these to null
to disable the feature for that REPL type. (The Settings linter will complain, but it works.)
For Clojure this is in addition to afterCLJReplJackInCode
There are two mechanisms for evaluating code when a Clojure REPL is connected. The afterCLJReplJackInCode
setting of custom connect sequences, and this calva.autoEvaluateCode.onConnect.clj
setting. There is no fundamental difference between them. This one has a default function of auto-refering in the Clojure REPL utilities. And it will be run before the connect sequence after-Jack-in code.
All configured code is concatenated
If you configure this both in User/global settings and in a Workspace, the workspace configured code will be concatenated on the user level code. Meaning both code snippets will be evaluated, first the User level code, then the Workspace level code. Also null
disables the feature:
null
in the User level code, you will disable the onConnect code evaluation for all workspaces that do not configure code for this.null
. You can also make Calva auto-evaluate code when a file has been loaded in the REPL (via the Calva command for loading files). You add code for this via the calva.autoEvaluateCode.onFileLoaded
setting. Like with onConnect
you provide code for clj
and cljs
separately.
onConnect
.If there is an nRepl port file, Calva will use it and not prompt for host:port
when connecting. You can make Calva prompt for this by setting the boolean config calva.autoSelectNReplPortFromPortFile
to false
.
With the setting calva.autoConnectRepl
you can make Calva automatically connect the REPL if there is an nRepl port file present when the project is opened.
With this and the below mentioned auto-select options you can make connect a prompt-less experience. See: Connect Sequences.
","boost":7},{"location":"customizing-jack-in-and-connect/#options-for-the-connect-command","title":"Options for the Connect Command","text":"The calva.connect
command takes an optional options argument defined like so:
options?: {\nhost?: string;\nport?: string;\nconnectSequence?: string | ReplConnectSequence;\ndisableAutoSelect?: boolean;\n}\n
Where ReplConnectSequence
is a Connect Sequences. If you provide a string it needs to match against a built-in or custom connect sequence. With disableAutoSelect
you can force the connect menus to be provided even if a custom connect sequence is set to be autoSelected.
You can provide these options from keyboard shortcuts or from Joyride scripts.
Here's a keyboard shortcut for connecting to a running REPL bypassing any connect sequence with autoSelectForConnect
.
{\n\"command\": \"calva.connect\",\n\"args\": {\"disableAutoSelect\": true},\n\"key\": \"ctrl+alt+c shift+c\",\n},\n
A Joyride command for connecting to a REPL on port 55555, without being asked for project type:
(vscode/commands.executeCommand \"calva.connect\" (clj->js {:port \"55555\" :connectSequence \"Generic\"}))\n
","boost":7},{"location":"customizing-jack-in-and-connect/#customizing-jack-in","title":"Customizing Jack-in","text":"The main mechanism for customizing your Jack-in, including automating menu selections, and custom CLJS REPL types is Custom Connect Sequences.
There are also these settings:
calva.jackInEnv
: An object with environment variables that will be added to the environment of the Jack-in process.calva.myCljAliases
: An array of deps.edn
aliases not found in the project file. Use this to tell Calva Jack-in to launch your REPL using your user defined aliases.calva.myLeinProfiles
: An array of Leiningen profiles not found in project.clj
. Use this to tell Calva Jack-in to launch your REPL using your user defined profiles.calva.openBrowserWhenFigwheelStarted
: For Legacy Figwheel only. A boolean controlling if Calva should automatically launch your ClojureScript app, once it is compiled by Figwheel. Defaults to true
.calva.depsEdnJackInExecutable
: A string which should either be clojure
or deps.clj
, or clojure or deps.clj
(default). It determines which executable Calva Jack-in should use for starting a deps.edn
project. With this setting at its default, clojure or deps.clj
, Calva will test if the clojure
executable works, and use it if it does, otherwise deps.clj
will be used, which is bundled with Calva.Note
When processing the calva.jackInEnv
setting you can refer to existing ENV variables with ${env:VARIABLE}
.
The calva.jackIn
command takes an optional options argument defined like so:
options?: {\nconnectSequence?: string | ReplConnectSequence;\ndisableAutoSelect?: boolean;\n}\n
Where ReplConnectSequence
is a Connect Sequences. If you provide a string it needs to match against a built-in or custom connect sequence. With disableAutoSelect
you can force the jack-in menus to be provided even if a custom connect sequence is set to be autoSelected.
You can provide these options from keyboard shortcuts or from Joyride scripts.
Here's a keyboard shortcut for connecting to a running REPL bypassing any connect sequence with autoSelectForConnect
.
{\n\"command\": \"calva.jackIn\",\n\"args\": {\"disableAutoSelect\": true},\n\"key\": \"ctrl+alt+c shift+j\",\n},\n
A Joyride command for starting a deps.edn
REPL for a project in the root of the workspace.
(vscode/commands.executeCommand\n\"calva.jackIn\"\n(clj->js {:connectSequence {:projectType \"deps.edn\"\n:projectRootPath [\".\"]}}))\n
It will prompt for any aliases it finds in the deps.edn
file.
If your project is setup so that the REPL server is started by the application code, you will need to get the cider-nrepl middleware in place. See the cider-nrepl docs about embedding nREPL in your application.
","boost":7},{"location":"customizing-jack-in-and-connect/#auto-select-project-type-and-project-root","title":"Auto-select Project Type and Project Root","text":"You can make both Jack-in and Connect stop prompting you for project type and project root path in projects where you always want to use the same. See Connect Sequences.
","boost":7},{"location":"customizing-jack-in-and-connect/#project-roots-search-globing","title":"Project roots search globing","text":"When searching for project roots in your workspace, Calva will glob for all files matching project.clj
, deps.edn
, or shadow-cljs.edn
. This is done using VS Code's workspace search engine, and is very efficient. However, in a large monorepo, it is still a substantial task. In order to not waste resources Calva will exclude any directories in the setting calva.projectRootsSearchExclude
.
Exclude entry globs
Each entry is a partial glob and will be part of a resulting glob of the form **/{glob1,glob2,...,globN}
. This means that all directories in the workspace matching an entry will be excluded, regardless of where in the workspace they reside.
It may be helpful to view the messages sent between nREPL and Calva when troubleshooting an issue related to the REPL. See how to do that here.
","boost":7},{"location":"customizing/","title":"Customizing Calva","text":"Don't like the defaults? On this page we can collect some of the customizations that people have done, and maybe write a thing or two about it some day.
Tip for VS Code newcomers: The search box in Settings is your friend. Also, some Calva settings are more complex than the Settings UI can handle. VS Code will then show you a link to settings.json
. And VS Code's built-in json
extension is awesome. To add settings for Calva's Pretty Printing, for example, search for \u201dprettyprint\u201d in VS Code Settings and follow the link to settings.json
. Start typing \u201dcalvapretty\u201d until auto-complete suggests calva.prettyPrintingOptions
. Press ENTER and VS Code will fill in these defaults:
\"calva.prettyPrintingOptions\": {\n\"enabled\": true,\n\"printEngine\": \"pprint\",\n\"width\": 40\n},\n
"},{"location":"customizing/#clojure-defaults","title":"Clojure Defaults","text":"Calva sets some VS Code settings for all Clojure files. Some of these are needed for Calva to function correctly, which should not be tampered with unless you really know what you are doing, and some of them are convenient defaults. If you add a setting to your settings.json
and accept the snippet help you get when you type \"[clojure]\"
, you will get the Calva defaults pasted:
\"[clojure]\": {\n\"editor.wordSeparators\": \"\\t ()\\\"':,;~@#$%^&{}[]`\",\n\"editor.autoClosingBrackets\": \"always\",\n\"editor.autoClosingQuotes\": \"always\",\n\"editor.formatOnType\": true,\n\"editor.autoIndent\": \"full\",\n\"editor.formatOnPaste\": true,\n\"editor.matchBrackets\": \"never\",\n\"editor.renderIndentGuides\": false,\n\"editor.parameterHints.enabled\": false\n}\n
Note
The above editor.wordSeparators
setting establish Clojure word boundaries. E.g -
is considered to be part of words. This affects what happens when double-clicking symbols and other things. If you want to include -
or something else as a word boundary, just add it to the setting.
Calva's pretty printing mode can be configured a bit. See Pretty Printing.
"},{"location":"customizing/#calva-highlight","title":"Calva Highlight","text":"This is highly customizable. See Syntax highlighting
"},{"location":"customizing/#color-customizations","title":"Color customizations","text":"Calva defines a set of themable colors which can be provided by the user using workbench.colorCustomizations.
\"workbench.colorCustomizations\": {\n\"calva.inlineErrorForegroundColor\": \"#ff0000\",\n\"calva.inlineForegroundColor\": \"#ff9000\"\n}\n
"},{"location":"customizing/#automatic-parameter-hints-poppup","title":"Automatic Parameter Hints Poppup","text":"Calva has helpful parameter hints to aid when typing function calls. They look like so:
To have the hints automatically pop up when you are typing, set editor.parameterHints.enabled
to true
in the above [clojure]
scoped setting. (To call them up on demand the default VS Code keybindings are cmd+shift+space
on Mac and ctrl+shift+space
on Linux/Windows.)
See Formatting for information on how to configure this.
"},{"location":"customizing/#jack-in-and-connect","title":"Jack-in and Connect","text":"Jack-in and Connect are very customizable through Custom Connect Sequences.
"},{"location":"customizing/#jack-in-dependency-versions","title":"Jack-in Dependency Versions","text":"Calva Jack-in injects the following dependencies in order for the REPL session to support IDE features
The versions used are configurable via the VS Code settings calva.jackInDependencyVersions
.
Most of Calva's commands have default keybindings. They are only defaults, though, and you can change keybindings as you wish. To facilitate precision in binding keys Calva keeps some when clause contexts updated.
"},{"location":"customizing/#when-clause-contexts","title":"When Clause Contexts","text":"The following contexts are available with Calva:
calva:keybindingsEnabled
: a master switch that you find in the settingsparedit:keyMap
: strict
, original
, or none
from the corresponding Calva setting (see Paredit)calva:connected
: true
when Calva is connected to a REPL (there is also calva:connecting
|| calva:launching
)calva:outputWindowActive
: true
when the Output/REPL window has input focuscalva:replHistoryCommandsActive
: true
when the cursor is in the Output/REPL window at the top level after the last promptcalva:replWindowSubmitOnEnter
: true
when the cursor is adjacent after the last top level form in the Output/REPL windowcalva:cursorInString
: true
when the cursor/caret is in a string or a regexpcalva:cursorInComment
: true
when the cursor is in, or adjacent to a line commentcalva:cursorBeforeComment
: true
when the cursor is adjacent before a line commentcalva:cursorAfterComment
: true
when the cursor is adjacent after a line commentcalva:cursorAtStartOfLine
: true
when the cursor is at the start of a line including any leading whitespacecalva:cursorAtEndOfLine
: true
when the cursor is at the end of a line including any trailing whitespaceHere is a collection of custom keybindings from here and there.
ctrl+alt+...
key bindings with ctrl+shift+...
, for keyboards lacking alt
key: this gistctrl+alt+c
to just alt+v
: WebWItch's keybindings.json (Please note, that alt+v
does not work for some locales, but for when it works it is much less clunky than the default prefix).ctrl+,
: manas_marthi's keybindingsAre you a vim extension user? See: Using with VIM extension.
"},{"location":"customizing/#move-by-word","title":"Move by word","text":"By default Calva changes the move-by-word key bindings to move by sexpr/form when the cursor is in structural Clojure code. Within line comments the editor default word movement is active.
If you want the VS Code default word movement shortcuts, use these settings:
{\n\"key\": \"ctrl+right\",\n\"win\": \"ctrl+right\",\n\"mac\": \"alt+right\",\n\"command\": \"cursorWordRight\"\n},\n{\n\"key\": \"ctrl+left\",\n\"win\": \"ctrl+left\",\n\"mac\": \"alt+left\",\n\"command\": \"cursorWordLeft\"\n},\n{\n\"key\": \"ctrl+right\",\n\"mac\": \"ctrl+right\",\n\"win\": \"alt+right\",\n\"command\": \"paredit.forwardSexp\",\n\"when\": \"calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+left\",\n\"mac\": \"ctrl+left\",\n\"win\": \"alt+left\",\n\"command\": \"paredit.backwardSexp\",\n\"when\": \"calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/\"\n}\n
Use it as an inspiration for customizing things to your own liking. \ud83d\ude04
"},{"location":"customizing/#wrap-using-like-cursive","title":"Wrap using(
, [
, {
(like Cursive)","text":"Something I use in IntelliJ/Cursive is the ability to select an expression and hit one of (
, [
, {
to wrap it. And after wrapping the expression I don't want the selection anymore, so if I were wrapping (foo)
then I would want to get ( | (foo))
where |
would be my cursor.
Here's how you can make this work with Calva Paredit: Update all of the Paredit: Wrap Around ...
commands so that their respective shortcuts are the wrappers themselves and update the when
clause to include editorHasSelection
(otherwise when you open a paren the next expression would get slurped in).
The change would look like this in your keybindings.json
:
{\n\"key\": \"shift+9\",\n\"command\": \"paredit.wrapAroundParens\",\n\"when\": \"editorTextFocus && editorHasSelection && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"[\",\n\"command\": \"paredit.wrapAroundSquare\",\n\"when\": \"editorHasSelection && editorTextFocus && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"shift+[\",\n\"command\": \"paredit.wrapAroundCurly\",\n\"when\": \"editorHasSelection && editorTextFocus && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n}\n
"},{"location":"debugger/","title":"Debugger","text":"Calva comes with a powerful expression-based debugger, inspired by Cider's debugger, and using the same underlying library, cider-nrepl. We hope you love it!
Note
The debugger currently does not support ClojureScript. Calva's debugger utilizes cider-nrepl for debugging. See this Cider issue for more information.
"},{"location":"debugger/#features","title":"Features","text":""},{"location":"debugger/#current","title":"Current","text":"ctrl+alt+c i
#dbg
(as opposed to the above command)#break
The debugger itself relies pretty heavily on cider-nrepl, as do other parts of Calva. This library is loaded as a dependency when you use Calva Jack-in. If you are not using Calva Jack-in, you can add these dependencies in your project definition or user profile. See the Calva Jack-in guide for more information.
"},{"location":"debugger/#using-the-debugger","title":"Using the Debugger","text":"If you're new to Clojure or expression-based debuggers, this debugger may function differently than what you're used to. Instead of placing breakpoints in the side margin and then hitting F5 to start debugging, you instead use Clojure reader tags, #break
and #dbg
, to denote breakpoints anywhere in a Clojure form. When you evaluate a call to a function that has been evaluated with that reader tag, the debugger will start when execution reaches the first breakpoint. There's also a convenience command to instrument functions. Read below about both options.
Note
The debugger is not configured via a launch.json
file, and is not started in the same way as you may be used to when working with other languages in VS Code. The debugger is used by way of the REPL. If you are new to Clojure, please visit the Getting Started section of the documentation and get familiar with evaluating code using the REPL before using the debugger.
You can instrument a top level function for debugging with ctrl+alt+c i
. This places invisible breakpoints throughout the function where pausing makes sense. When you evaluate a call to this function, the debugger will start and execution will pause at the first breakpoint. Annotations show the value of the form at the cursor.
A border is placed around the definition of the instrumented function and its references to show that it's instrumented. You can remove instrumentation by evaluating the function again normally, such as with alt+enter
.
#break
","text":"You can insert a breakpoint manually into any code by placing a #break
in front of the form where you want execution to pause, and then evaluating the top level form with alt+enter
. When you evaluate a call to this code the VS Code debugger will start, the cursor will move to right after the form that's preceded by #break
, and the line will be highlighted to show execution is paused there.
Note
Code will be executed up to and including the form after the breakpoint.
"},{"location":"debugger/#conditional-breakpoints","title":"Conditional Breakpoints","text":"You can set conditional breakpoints by adding metadata before the form that the #break
applies to.
(defn print-nums [n]\n(dotimes [i n]\n#break ^{:break/when (= i 7)} ;; This breakpoint will only be hit when i equals 7\n(prn i)))\n
"},{"location":"debugger/#instrumenting-a-form-with-dbg","title":"Instrumenting a Form with #dbg
","text":"Adding #dbg
before a form then evaluating the form with alt+enter
will instrument the form. This has the same effect as using the instrument command.
When execution is paused at a breakpoint, you can evaluate code in that context. This can be done in the editor or in the REPL window, as usual.
"},{"location":"debugger/#viewing-variable-values","title":"Viewing Variable Values","text":"While debugging, you can view the values of variables in VS Code's debugger side pane. You can also view values by hovering over the variables in the editor. Currently, values for collections and maps are shown as strings, but we plan to make them structured in the future. For now, if you want to see the value of a large structured variable, you can evaluate the variable from the editor or from the REPL window.
"},{"location":"debugger/#viewing-the-call-stack","title":"Viewing the Call Stack","text":"While debugging, you can view the call stack in VS Code's call stack side pane. Clicking the stack frames will show the related line of code in an editor.
Note
You may only see one stack frame in the call stack side pane, as the change for adding additional frames was rolled back due to an issue. You can follow the change for this at #1150.
"},{"location":"debugger/#stepping-commands","title":"Stepping Commands","text":"You can use VS Code's debugger UI to advance execution while debugging.
Note
Clicking restart does nothing, since this functionality does not make sense for our debugger.
One construct where the debugger is limited is loop
/recur
. As recur always has to appear in a tail-position inside a loop
or a fn
and the debugger uses macros to interleave breakpoints in the forms, it might happen that a recur
no longer appears in a tail position. In that case we have to avoid setting up the breakpoint. An example of such a case is:
(loop [i 0]\n#break\n(when (< i 10)\n(println i)\n(recur (inc i))))\n
Here the breakpoint is exactly in front of a form that contains as its last expression a recur
which is wrapped in a loop. This breakpoint has no effect. This does not mean you cannot use the debugger with loop
, it just means you have to set your debug statements more carefully.
When you load a file, any breakpoints that were previously set in functions will be unset. If you have the \"Eval On Save\" setting enabled, your file is also loaded with each save, therefore saving the file will remove breakpoints previously set.
"},{"location":"debugger/#troubleshooting","title":"Troubleshooting","text":""},{"location":"debugger/#debugger-hangs-when-stepping-over-infinite-seqs","title":"Debugger hangs when stepping over infinite seqs","text":"This is because the debugger tries to evaluate the form when it's stepped over, and if clojure.core/*print-length*
is set to nil
as it is by default, evaluation will never complete. If you want to debug a form with an infinite seq, make sure to set *print-length*
beforehand. For example:
(set! *print-length* 3)\n;; Or, to be more precise\n(set! clojure.core/*print-length* 3)\n
Calva does not set this for you during debug mode, instead leaving it up to you to decide the value.
"},{"location":"debugger/#my-breakpoint-isnt-being-hit","title":"My breakpoint isn't being hit","text":"It's likely that your breakpoint is in a place that cider-nrepl does not see as an appropriate place to break execution. For example, if you put a breakpoint before a literal number, it will not be hit, because there's no need to show the value of a literal.
(defn simple [x]\n(+ 1 #break 1)) ;; This breakpoint will not be hit\n
Another possible issue is that you're loading the file again after setting breakpoints, which unsets them. See Loading the File and \"Eval On Save\" under Caveats.
"},{"location":"debugger/#my-breakpoint-in-a-test-isnt-being-hit","title":"My breakpoint in a test isn't being hit","text":"If you're using the test commands like \"Run current test\" to run your tests, breakpoints will not be hit. This is because Calva loads the file before running the tests to make sure the latest version of test code is being run, and when the file is loaded, breakpoints are unset.
If you want a breakpoint to work within the test, evaluate the test form with a breakpoint tag in it, then call the test directly.
"},{"location":"debugger/#no-reader-function-for-tag-error","title":"\"No reader function for tag\" error","text":"If you get an error like this, it's likely that you connected to a REPL instead of jacking in, and you don't have the proper dependencies loaded in your REPL. You can run the command \"Copy Jack-in Command Line to Clipboard\" to see what command would be run if you jacked in.
Most importantly, make sure you have cider/cider-nrepl
as a dependency, and cider.nrepl/cider-middleware
as middleware loaded in your REPL. For example, this is a jack-in command line for a deps.edn project:
clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,\"0.8.3\"},cider/cider-nrepl {:mvn/version,\"0.25.8\"}}}' -m nrepl.cmdline --middleware \"[cider.nrepl/cider-middleware]\"\n
"},{"location":"debugger/#passing-options-to-the-repl-jvm","title":"Passing options to the REPL JVM","text":"There are times when Clojure debugging tools are not enough or not right for the job. This is usually true when use an (open source) Java library and you want to set some breakpoints in Java code. For those cases and others, you need to start the JVM in debug mode.
Typical use cases:
-Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE
Calva supports passing environment variables via jackInEnv
. You can set that option inside VSCode settings.json
file.
You can configure global settings.json
file or a project wide version, inside <project-root>/.vscode/settings.json
.
Configuring the global option will impact all projects you work on using Calva, so be aware. See the documentation for settings.json
for more information.
The bellow snippet configures JAVA_TOOL_OPTIONS
environment variable. We configure slf4j-simple logging level via a Java system property (-D
) and JVM specific options (-X
).
NOTE: You can of course pass other env variables here.
.vscode/settings.json
{\n\"calva.jackInEnv\": {\n\"JAVA_TOOL_OPTIONS\": \"${env:JAVA_TOOL_OPTIONS} -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896\"\n}\n}\n
Once you saved the file, the next time you Jack in
the project, this variable is read by the JVM and the configuration is applied accordingly.
You should see something like the message below in the Calva terminal output window:
clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,\"0.8.3\"},cider/cider-nrepl {:mvn/version,\"0.26.0\"}}}' -A:debug -m nrepl.cmdline --middleware \"[cider.nrepl/cider-middleware]\"\nPicked up JAVA_TOOL_OPTIONS: -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896\nListening for transport dt_socket at address: 7896\nnREPL server started on port 46691 on host localhost - nrepl://localhost:46691\n
"},{"location":"emacs-keybindings/","title":"Emacs Keybindings","text":"Some keybindings to make it easier for Emacs users
[\n{\n\"key\": \"ctrl+cmd+b\",\n\"command\": \"paredit.backwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+alt+left\",\n\"command\": \"-paredit.backwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"shift+cmd+]\",\n\"command\": \"-workbench.action.nextEditor\"\n},\n{\n\"key\": \"ctrl+shift+]\",\n\"command\": \"paredit.barfSexpBackward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+right\",\n\"command\": \"-paredit.barfSexpBackward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+[\",\n\"command\": \"paredit.barfSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+left\",\n\"command\": \"-paredit.barfSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+cmd+f\",\n\"command\": \"paredit.forwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+alt+right\",\n\"command\": \"-paredit.forwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+cmd+f\",\n\"command\": \"-workbench.action.toggleFullScreen\"\n},\n{\n\"key\": \"ctrl+shift+backspace\",\n\"command\": \"-paredit.killSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"shift+cmd+k\",\n\"command\": \"-editor.action.deleteLines\",\n\"when\": \"textInputFocus && !editorReadonly\"\n},\n{\n\"key\": \"ctrl+shift+0\",\n\"command\": \"paredit.slurpSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+right\",\n\"command\": \"-paredit.slurpSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+9\",\n\"command\": \"paredit.slurpSexpBackward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+left\",\n\"command\": \"-paredit.slurpSexpBackward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+c ctrl+c\",\n\"command\": \"calva.evaluateCurrentTopLevelForm\",\n\"when\": \"calva:activated\"\n},\n{\n\"key\": \"ctrl+alt+c space\",\n\"command\": \"-calva.evaluateCurrentTopLevelForm\",\n\"when\": \"calva:activated\"\n},\n{\n\"key\": \"ctrl+x ctrl+e\",\n\"command\": \"calva.evalCurrentTopLevelFormInREPLWindow\",\n\"when\": \"calva:activated\"\n},\n{\n\"key\": \"ctrl+alt+c ctrl+alt+space\",\n\"command\": \"-calva.evalCurrentTopLevelFormInREPLWindow\",\n\"when\": \"calva:activated\"\n},\n{\n\"key\": \"ctrl+x ctrl+s\",\n\"command\": \"workbench.action.files.save\"\n},\n{\n\"key\": \"cmd+s\",\n\"command\": \"-workbench.action.files.save\"\n},\n{\n\"key\": \"cmd+s\",\n\"command\": \"paredit.spliceSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+alt+s\",\n\"command\": \"-paredit.spliceSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+cmd+k\",\n\"command\": \"paredit.cutForwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+x right\",\n\"command\": \"-paredit.cutForwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+cmd+backspace\",\n\"command\": \"paredit.cutBackwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+x left\",\n\"command\": \"-paredit.cutBackwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+1\",\n\"command\": \"-workbench.action.openEditorAtIndex1\"\n},\n{\n\"key\": \"ctrl+1\",\n\"command\": \"editor.action.quickFix\",\n\"when\": \"editorHasCodeActionsProvider && editorTextFocus && !editorReadonly\"\n},\n{\n\"key\": \"cmd+.\",\n\"command\": \"-editor.action.quickFix\",\n\"when\": \"editorHasCodeActionsProvider && editorTextFocus && !editorReadonly\"\n},\n{\n\"key\": \"cmd+.\",\n\"command\": \"editor.action.revealDefinition\",\n\"when\": \"editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor\"\n},\n{\n\"key\": \"f12\",\n\"command\": \"-editor.action.revealDefinition\",\n\"when\": \"editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor\"\n}\n]\n
"},{"location":"eval-tips/","title":"Code Evaluation","text":"Calva tries to make it easy to evaluate code, supporting interactive development. The fastest path to learning about it is to use the Fire up the Getting Started REPL command, which you can learn more about in the Getting Started section.
NB: The below assumes you have read about Finding Calva Commands and Shortcuts.
","boost":7},{"location":"eval-tips/#interruptingstopping-running-evaluations","title":"Interrupting/stopping running evaluations","text":"Sometimes you evaluate things that take a very long time to complete, or might not even ever complete (infinite loops, lazy sequences, things like that). Calva has a command for interrupting running evaluations. You find it in the VS Code command palette, as well as in the REPL status bar item menu, when the REPL is connected.
","boost":7},{"location":"eval-tips/#evaluation-in-a-file-editor","title":"Evaluation in a File Editor","text":"Calva has many commands for evaluating forms, including the current form and the current top-level form.
Some of the commands also let you choose what should happen with the results:
These are important concepts in Calva in order for you to create your most effective workflow. This video explains it a bit:
","boost":7},{"location":"eval-tips/#current-form","title":"Current Form","text":"Default shortcut for evaluating the current form: ctrl+enter
.
The current form either means the current selection, or otherwise is based on the cursor position. Play some with the command Calva: Select current form, ctrl+alt+c s
, to figure out what Calva thinks is the current form for some different situations. Try it inside a symbol, adjacent to a symbol (both sides) and adjacent to an opening or closing bracket (again, both sides). Generally the current form is determined like so:
foob|ar ; foobar\n
(foo bar |(baz)) ; (baz)\n
(foo bar | (baz)) ; bar\n
(foo\n| bar (baz)) ; bar\n
Default shortcut for evaluating the current top level form: alt+enter
.
The current top-level form means top-level in a structural sense. It is not the topmost form in the file. Typically in a Clojure file you will find def
and defn
(and defwhatever
) forms at the top level, which also is one major intended use for evaluating top level form: to define and redefine variables. However, Calva does not check the contents of the form in order to determine it as a top-level forms: all forms not enclosed in any other form are top level forms.
An \u201dexception\u201d is introduced by the comment
form. It will create a new top level context, so that any forms immediately inside a (comment ...)
form will be considered top-level by Calva. This is to support a workflow with what is often referred to the Rich Comments.
At the top level the selection of which form is the current top level form follows the same rules as those for the current form.
","boost":7},{"location":"eval-tips/#evaluate-enclosing-form","title":"Evaluate Enclosing Form","text":"The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter
.
(let [foo :bar]\n(when false (str| foo))) ; => \":bar\"\n
","boost":7},{"location":"eval-tips/#evaluate-to-cursor","title":"Evaluate to Cursor","text":"There are several commands for evaluating a piece of code, closing brackets. It's good, especially in threads, but can also come in handy in other situations, for instance when you want to evaluate something that depends on bindings, such as in a let
form.
This command evaluates the text from the start of the current enclosing list to where the cursor is, and it adds the missing closing bracket for you. Convenient for checking intermediate results in thread or doto
, or similar pipelines. The cursor is right behind :d
in this form:
(->> [1 1 2 3 5 8 13 21]\n(partition 2)\n(zipmap [:a :b :c :d])\n:d| ; => (13 21)\n(apply -)\n(Math/abs))\n
The default shortcut for this command is ctrl+alt+enter.
","boost":7},{"location":"eval-tips/#evaluate-selection-closing-brackets","title":"Evaluate Selection, Closing Brackets","text":"This is the most versatile of the \u201devaluation, closing brackets\u201d commands. It will do what it says. \ud83d\ude04 It's extra handy in combination with the command Paredit: Select Backward Up Sexp/Form (shift+ctrl+up). Consider this contrieved form (buggy code, because it was supposed to result in 42
, not -42
):
(defn fortytwo-from-thirty\n[]\n(let [thirty 30]\n(-> thirty\ninc ;1\n(send-off)\n(+ 1 2 3)\n(->>\n(+ 2 2) ;2\n(+))\nlist\n(->>\n(into [1])\n(reduce + 1))\n(- 1) ;3\n(* -1))))\n
At ;1
, you can do backward up sexp (shift+ctrl+up) twice to select up to the (let ..)
, then issue Evaluate Selection, Closing Brackets. It has the same default keybinding as the command for evaluating the current list up to the cursor: ctrl+alt+enter.
At ;2
you need select backwards up three times.
;3
is included because it is close to the bug. (Which was introduced when the thread-last, ->>
was added to make this example.) Please practice the Evaluate Selection, Closing Brackets command to fix the bug.
This command has a default shortcut keybinding of shift+alt+enter
. It will create a form from the start of the current top level form, up to the cursor, close all brackets, and this will then be evaluated. Good for examining code blocks up to a certain point. Often comes in handy in Rich comments ((comment ...)
).
Take this example and paste it in a file loaded into the REPL, then place the cursor in front of each line comment and try the command.
(comment\n(do\n(def colt-express\n{:name \"Colt Express\"\n:categories [\"Family\"\n\"Strategy\"]\n:play-time 40\n:ratings {:pez 5.0\n:kat 5.0\n:wiw 5.0 ; 1, then eval `colt-express`\n:vig 3.0\n:rex 5.0\n:lun 4.0}})\n\n(defn average [coll]\n(/ (apply + coll) (count coll)))\n\n(let [foo-express (-> colt-express\n(assoc :name \"Foo Express\")\n(assoc-in [:ratings :lyr] 5.0)\n(update-in [:ratings :vig] inc))]\n(->> foo-express ; 2\n:ratings ; 3\nvals ; 4\naverage ; 5\n))))\n
","boost":7},{"location":"eval-tips/#evaluate-from-start-of-file-to-cursor-closing-brackets","title":"Evaluate From Start of File to Cursor, Closing Brackets","text":"Yup, that command also exists. \ud83d\ude04
","boost":7},{"location":"eval-tips/#copying-the-inline-results","title":"Copying the inline results","text":"There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c
.
This works regardless if you have evaluated in a file editor or in a REPL window.
","boost":7},{"location":"eval-tips/#evaluating-in-a-repl-window","title":"Evaluating in a REPL window","text":"Since the REPL Window is mostly just a regular file, things work pretty similar at the REPL prompt. You use alt+enter
to evaluate. Selecting the current form (default key binding ctrl+w
on Mac and shift+alt+right
on Windows and Linux) after evaluating will select the result.
Calva tries to make it easy to evaluate code, supporting interactive development. The fastest path to learning about it is to use the Fire up the Getting Started REPL command, which you can learn more about in the Getting Started section.
NB: The below assumes you have read about Finding Calva Commands and Shortcuts.
","boost":7},{"location":"evaluation/#interruptingstopping-running-evaluations","title":"Interrupting/stopping running evaluations","text":"Sometimes you evaluate things that take a very long time to complete, or might not even ever complete (infinite loops, lazy sequences, things like that). Calva has a command for interrupting running evaluations. You find it in the VS Code command palette, as well as in the REPL status bar item menu, when the REPL is connected.
","boost":7},{"location":"evaluation/#evaluation-in-a-file-editor","title":"Evaluation in a File Editor","text":"Calva has many commands for evaluating forms, including the current form and the current top-level form.
Some of the commands also let you choose what should happen with the results:
These are important concepts in Calva in order for you to create your most effective workflow. This video explains it a bit:
","boost":7},{"location":"evaluation/#current-form","title":"Current Form","text":"Default shortcut for evaluating the current form: ctrl+enter
.
The current form either means the current selection, or otherwise is based on the cursor position. Play some with the command Calva: Select current form, ctrl+alt+c s
, to figure out what Calva thinks is the current form for some different situations. Try it inside a symbol, adjacent to a symbol (both sides) and adjacent to an opening or closing bracket (again, both sides). Generally the current form is determined like so:
foob|ar ; foobar\n
(foo bar |(baz)) ; (baz)\n
(foo bar | (baz)) ; bar\n
(foo\n| bar (baz)) ; bar\n
Default shortcut for evaluating the current top level form: alt+enter
.
The current top-level form means top-level in a structural sense. It is not the topmost form in the file. Typically in a Clojure file you will find def
and defn
(and defwhatever
) forms at the top level, which also is one major intended use for evaluating top level form: to define and redefine variables. However, Calva does not check the contents of the form in order to determine it as a top-level forms: all forms not enclosed in any other form are top level forms.
An \u201dexception\u201d is introduced by the comment
form. It will create a new top level context, so that any forms immediately inside a (comment ...)
form will be considered top-level by Calva. This is to support a workflow with what is often referred to the Rich Comments.
At the top level the selection of which form is the current top level form follows the same rules as those for the current form.
","boost":7},{"location":"evaluation/#evaluate-enclosing-form","title":"Evaluate Enclosing Form","text":"The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter
.
(let [foo :bar]\n(when false (str| foo))) ; => \":bar\"\n
","boost":7},{"location":"evaluation/#evaluate-to-cursor","title":"Evaluate to Cursor","text":"There are several commands for evaluating a piece of code, closing brackets. It's good, especially in threads, but can also come in handy in other situations, for instance when you want to evaluate something that depends on bindings, such as in a let
form.
This command evaluates the text from the start of the current enclosing list to where the cursor is, and it adds the missing closing bracket for you. Convenient for checking intermediate results in thread or doto
, or similar pipelines. The cursor is right behind :d
in this form:
(->> [1 1 2 3 5 8 13 21]\n(partition 2)\n(zipmap [:a :b :c :d])\n:d| ; => (13 21)\n(apply -)\n(Math/abs))\n
The default shortcut for this command is ctrl+alt+enter.
","boost":7},{"location":"evaluation/#evaluate-selection-closing-brackets","title":"Evaluate Selection, Closing Brackets","text":"This is the most versatile of the \u201devaluation, closing brackets\u201d commands. It will do what it says. \ud83d\ude04 It's extra handy in combination with the command Paredit: Select Backward Up Sexp/Form (shift+ctrl+up). Consider this contrieved form (buggy code, because it was supposed to result in 42
, not -42
):
(defn fortytwo-from-thirty\n[]\n(let [thirty 30]\n(-> thirty\ninc ;1\n(send-off)\n(+ 1 2 3)\n(->>\n(+ 2 2) ;2\n(+))\nlist\n(->>\n(into [1])\n(reduce + 1))\n(- 1) ;3\n(* -1))))\n
At ;1
, you can do backward up sexp (shift+ctrl+up) twice to select up to the (let ..)
, then issue Evaluate Selection, Closing Brackets. It has the same default keybinding as the command for evaluating the current list up to the cursor: ctrl+alt+enter.
At ;2
you need select backwards up three times.
;3
is included because it is close to the bug. (Which was introduced when the thread-last, ->>
was added to make this example.) Please practice the Evaluate Selection, Closing Brackets command to fix the bug.
This command has a default shortcut keybinding of shift+alt+enter
. It will create a form from the start of the current top level form, up to the cursor, close all brackets, and this will then be evaluated. Good for examining code blocks up to a certain point. Often comes in handy in Rich comments ((comment ...)
).
Take this example and paste it in a file loaded into the REPL, then place the cursor in front of each line comment and try the command.
(comment\n(do\n(def colt-express\n{:name \"Colt Express\"\n:categories [\"Family\"\n\"Strategy\"]\n:play-time 40\n:ratings {:pez 5.0\n:kat 5.0\n:wiw 5.0 ; 1, then eval `colt-express`\n:vig 3.0\n:rex 5.0\n:lun 4.0}})\n\n(defn average [coll]\n(/ (apply + coll) (count coll)))\n\n(let [foo-express (-> colt-express\n(assoc :name \"Foo Express\")\n(assoc-in [:ratings :lyr] 5.0)\n(update-in [:ratings :vig] inc))]\n(->> foo-express ; 2\n:ratings ; 3\nvals ; 4\naverage ; 5\n))))\n
","boost":7},{"location":"evaluation/#evaluate-from-start-of-file-to-cursor-closing-brackets","title":"Evaluate From Start of File to Cursor, Closing Brackets","text":"Yup, that command also exists. \ud83d\ude04
","boost":7},{"location":"evaluation/#copying-the-inline-results","title":"Copying the inline results","text":"There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c
.
This works regardless if you have evaluated in a file editor or in a REPL window.
","boost":7},{"location":"evaluation/#evaluating-in-a-repl-window","title":"Evaluating in a REPL window","text":"Since the REPL Window is mostly just a regular file, things work pretty similar at the REPL prompt. You use alt+enter
to evaluate. Selecting the current form (default key binding ctrl+w
on Mac and shift+alt+right
on Windows and Linux) after evaluating will select the result.
In the podcast Functional Design in Clojure, Episode 014: Fiddle with the REPL, they discuss a workflow in which you keep some of your exploratory code in separate files, which they call Fiddle Files. It's like Rich Comments, and the files often consist of such comments. The Fiddle files are typically not on the classpath, and are only loaded in the REPL by you when you are developing your project. Some developers keep personal fiddle files. In some projects they are meant to be shared, and in other projects it's a combination.
Calva has some extra support for the fiddle file workflow, beyond what VS Code offers in terms of navigating between files. The support comes in the form of three commands supported by a little configuration.
","boost":5},{"location":"fiddle-files/#the-three-fiddle-file-commands","title":"The Three Fiddle File Commands","text":"The commands let you quickly navigate between your implementation code (called Source here) and your Fiddle file, and to evaluate the Fiddle file without leaving the Source file.
Command Action Shortcut Active Calva: Open Fiddle File for Current File Opens the Fiddle file corresponding to the current Clojure Source file. ctrl+alt+cf When the currently active file is not a Fiddle file. Calva: Open Source File for Current Fiddle File Opens the Source file corresponding to the current Fiddle file. ctrl+alt+cf When the currently active file is a Fiddle file + there is an existing, and corresponding, source file. Calva: Evaluate Fiddle File for Current File Evaluates the Fiddle file corresponding to the current Clojure Source file. ctrl+alt+cctrl+alt+f When the currently active file is not a Fiddle file.The commands for opening and evaluating corresponding Fiddle files will offer to Create the Fiddle file if it does not already exist. But the Calva: Open Source File for Current Fiddle File command will not offer to create the target file.
What does corresponding mean here? Without any configuration Calva will look for \u201csibling\u201d files, where files with Clojure file extensions (E.g. .clj
, .cljs
, .bb
) will be treated as Source files, and files with the .fiddle
extension will be treated as Fiddle files. \"Sibling file\" here means residing side by side in the file system. If this default behaviour is not your cup of tea, there is some flexibility added by configuration.
To know how to map between Fiddle <-> Source files, Calva has three different modes of operation:
src
/a/b/c.cljc
corresponding to:src
/a/b/c.fiddle
src
/a/b/c.cljc
corresponding to:env/dev/fiddles
/a/b/c.cljc
src
/a/b/c.cljc
and:src
/d/e/f.cljc
corresponding to:env/dev/fiddles
/x.cljc
The setting is named calva.fiddleFilePaths
and is an array of source
and fiddle
root paths, relative to the project root.
The Project Root
It is important to note that the project root depends on whether you are connected to a REPL or not, and to which project you are connected, in case the workspace contains several projects.
Without a REPL connection (disregarding that fiddle files are not very interesting then) the project root is the same as the first workspace root. And if you have a regular VS Code window open, it is the root of the folder you have opened in that window.
With a REPL connection, the project root will be the root of the project, i.e. where the project file (deps.edn
, project.clj
, shadow-cljs.edn
) is.
\"calva.fiddleFilePaths\": [\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n}\n]\n
This will make any file in the src
directory tree correspond to a matching file with the same relative path. E.g.:
src/a/b/c.clj
-> env/dev/fiddles/a/b/c.clj
, for both the open and evaluate commandsenv/dev/fiddles/a/b/c.clj
-> src/a/b/c.clj
If you generally work with one Fiddle file at a time, you can configure a mapping to a Dedicated Fiddle file. E.g.:
\"calva.fiddleFilePaths\": [\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n},\n]\n
This will make any file in the src
directory tree correspond to the same Fiddle file. E.g.:
src/a/b/c.clj
-> env/dev/fiddle.clj
, for both the open and evaluate commandssrc/d/e/f.clj
-> env/dev/fiddle.clj
, dittoenv/dev/fiddle.clj
-> Won't correspond to a Source file in this caseJumping from a dedicated fiddle to a source file
Calva's command for opening the corresponding source file won't work in this case because it is a one->many situation. If you want to open the last file you worked with before using Open Fiddle File for Current File, consider using the VS Code command: Go Previous.
","boost":5},{"location":"fiddle-files/#multiple-mappings","title":"Multiple Mappings","text":"The configuration is an array so that you can configure different mappings for different Source directories. Given several mappings with overlapping Source, the longest mapping will win. Given several mappings with the same Source, the first one will win, unless one of them is a dedicated Fiddle, in which case that one will win.
\"calva.fiddleFilePaths\": [\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n},\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n},\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddle.cljs\"]\n},\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddle.bb\"]\n},\n{\n\"source\": [\"src\", \"b\"],\n\"fiddle\": [\"env\", \"dev\", \"b-fiddles\"]\n},\n]\n
With this configuration we would get a behaviour like so:
src/a/b/c.clj
-> env/dev/fiddle.clj
, because all four first [\"src\"]
mappings match, but the second one is a dedicated fiddle file, and matches the .clj
extension.src/a/b/c/d.bb
-> env/dev/fiddle.bb
, because all four first [\"src\"]
mappings match, but the second one is a dedicated fiddle file, and matches the .bb
extension.src/a/b/c/d.cljc
-> env/dev/fiddle.clj
, because all four first [\"src\"]
mappings match, but the second one is a dedicated fiddle file, without a matching file extension, (so the first dedicated fiddle file is picked).src/b/c/d.clj
-> env/dev/b-fiddles/c/d.clj
, because the [\"src\", \"b\"]
mapping is longer than the also matching [\"src\"]
mappings.Organize your Fiddle files such that they do not get automatically loaded as part of your application. This can lead to strange errors and hard-to-detect bugs. Most often it should only be you manually loading the fiddle file, not clj/clojure or Leiningen or any such system which loads your application.
When you want your fiddle code to be evaluated in the same workspace as its corresponding Source file, you can use the same namespace declaration for both files. The linter might complain, but the REPL will happily comply.
If you primarily evaluate the fiddle file using the provided command for it, from the Source files, you can omit the namespace declaration, and Calva will evaluate it in the namespace of the Source file.
The linter and fiddle files
For some fiddle files you will get a lot of linter warnings, because clj-kondo doesn't know about fiddle files, and they are often not on the classpath. You might find yourself wanting to silence some linters for some fiddle files. E.g. like this:
(ns main.core\n{:clj-kondo/config\n'{:linters {:unresolved-symbol {:level :off}}}})\n
See clj-kondo Configuration for more on what options you have for this.
","boost":5},{"location":"fiddle-files/#see-also","title":"See Also","text":"Calva relies a lot on that VS Code makes it really easy to find commands by opening the command palette: ctrl+shift+p
(Windows/Linux), cmd+shift+p
(Mac), and then start typing some words (or parts of words) that you think might be in the command.
To leverage this, all Calva commands are prefixed with Calva
. As an example, say you want to find commands related to evaluating the top level form. Then you can do this:
calevtop
VS Code will match cal
to \u201dCalva\u201d, ev
to \u201dEvaluate\u201d, and top
to \u201dTop\u201d. It looks like so:
As you can see on the screenshot, VS Code will also reveal the keyboard shortcut for each command. My advice is to make it a habit to try to remember those shortcuts and use them for a more effective workflow.
Now might be a good time to see Calva Top 10 Commands
"},{"location":"finding-commands/#all-the-settings-and-commands","title":"All the Settings and Commands","text":"Did you know? There is a complete list of Calva settings and commands in the Contributions tab of the Calva entry in the Extensions pane in VS Code.
"},{"location":"finding-commands/#toggling-keyboard-shortcuts-onoff","title":"Toggling Keyboard Shortcuts On/Off","text":"The command calva.toggleKeybindingsEnabled
can be used to quickly enable and disable (almost) all keyboard shortcuts. This allows you to quickly toggle between Calva keybindings and other keybindings which would otherwise not be available when Calva is enabled. This is particularly useful with the Paredit keyboard shortcuts, whose default shortcuts conflict with the default VS Code shortcuts for textual (non-structural) editing.
By default it is not bound to a shortcut so as not to cause confusion by users unwittingly pressing it, but if this is something you'd like to use often, you may want to bind it to a shortcut.
"},{"location":"formatting/","title":"Formatting","text":"We have tried to make Calva's formatter so that it just works. It is enabled by default for Clojure files, and with the default configuration it mostly follows Bozhidar Batsov's Clojure Style Guide. Calva uses cljfmt for the formatting.
Tab formats the current surrounding form
Calva's code formatter sets the default keybinding of its Format Current Form command to tab
. Meaning that most often when things look a bit untidy, you can press tab
to make things look pretty. Good to know, right? For performance reasons it only formats the current enclosing form, so sometimes you want to move the cursor up/out a form (ctrl+up
) first. See The Paredit Guide for more on moving the cursor structurally through your code.
With the default settings, Calva's formatting behaves like so:
tab
ctrl+alt+l
(comment ...)
forms special, see rich commentsInfer parens at will
Calva has a command that will \u201dheal\u201d the bracket structure if it is correctly indented using Parinfer Infer parens. This command is default bound to ctrl+alt+p i
.
Also: If you have Format on Save enabled in VS Code, it will be Calva doing the formatting for Clojure files.
Calva's formatting is mostly about indenting, but it also (again, defaults):
Not a fan of some default setting? The formatter is quite configurable.
"},{"location":"formatting/#format-current-form-command-variants","title":"Format current form command variants","text":"There are three special commands for formatting the current form:
"},{"location":"formatting/#1-format-and-align-current-form","title":"1. Format and Align Current Form","text":"Aligns associative structures and bindings in two columns. See more below.
"},{"location":"formatting/#2-format-current-form-and-trim-space-between-forms","title":"2. Format Current Form and trim space between forms","text":"This formats the text, and trims consecutive, non-indent, whitespace on a line to just one space. Something like:
(let [a :b]\n(str \"foo\" \"bar\" \"baz\"\n\"a\" a))\n
Becomes:
(let [a :b]\n(str \"foo\" \"bar\" \"baz\"\n\"a\" a))\n
Basically, it behaves like if :remove-multiple-non-indenting-spaces? true
was added to the cljfmt
config. Which, in fact, is what happens. Calva merges that onto your cljfmt config when this command is used.
This command will run the code of the Current Form through Calva's pretty printer (the engine named calva
, which is using zprint) and replace the current form inline in the editor with the pretty printed results.
Unlike with the \u201dreal\u201d Calva Formatter, which never breaks up lines, this one will follow your pretty printing options and break up lines if you have set maxWidth
to something that calls for breaking up lines.
Applies to the other Current Form
Unlike the other Format commands, which applies to the current enclosing form, this one applies to the Current Form, same as with evaluations. That is because this is not really part of the Calva formatter, but rather is a convenience command for tidying up code or data.
"},{"location":"formatting/#configuration","title":"Configuration","text":"You can adjust the above mentioned defaults, and the default indents, by configuring the formatting using cljfmt's configuration EDN.
This configuration can either be provided via a file or via clojure-lsp. See Providing configuration via clojure-lsp below.
"},{"location":"formatting/#providing-configuration-via-a-config-file","title":"Providing configuration via a config file","text":"Calva will look for the configuration in one of the default cljfmt paths ('.cljfmt.edn', '.cljfmt.clj', 'cljfmt.edn', or 'cljfmt.clj' in the workspace root). If your file is somewhere else use the calva.fmt.configPath
to tell Calva where to find it. The path should either be absolute, or relative to the workspace root directory. If your config file is somewhere in the workspace root, Calva will hot reload it when you update it.
Wherever the config file is, a suggested path for providing your configuration is to start changing the Calva formatting defaults by pasting the following map into a file and save it.
{:remove-surrounding-whitespace? true\n:remove-trailing-whitespace? true\n:remove-consecutive-blank-lines? false\n:insert-missing-whitespace? true\n:remove-multiple-non-indenting-spaces? false}\n
If the file is in the workspace, you can quickly test how different settings affect the formatting. Try:
:align-associative? true
to the configtab
, and see what happens.:align-associative?
is experimental This particular setting is experimental and known to cause trouble together with namespaced keywords. Consider using ctrl+alt+l
instead of tab
as your formatting command, instead of enabling this setting. See below for more info about this. See more below about this.
The cljfmt docs mention the :cljfmt
config key of Leiningen projects. Calva does not yet read the config from there, so if your Leiningen project has such a configuration, you will need to copy it out into a file.
If you work in a team where some members use clojure-lsp for formatting, you can make Calva format using the same configuration by telling setting calva.fmt.configPath
to CLOJURE-LSP
(case sensitive). See Clojure LSP Settings) for how to provide the configuration. (It might not be provided from where you think it is, specifically check clojure-lsp's global config in you user home directory.) Use the command Calva Diagnostics: Clojure-lsp Server Info to see what cljfmt configuration is being used (under the cljfmt-raw
key).
Note that doing this you will not have hot reload of the formatting configuration, and of course you will be depending on that clojure-lsp is running and functioning.
"},{"location":"formatting/#indentation-rules","title":"Indentation rules","text":"The cljfmt
indents are highly configurable. They, and the rest of the configuration options, are masterly detailed here.
:extra-indents
vs :indents
Since Calva v2.0.383
we are using cljfmt 0.11.x
which has a breaking configuration change. From the cljfmt README:
The :indents
key has been split into :indents
and :extra-indents. The :indents
key replaces all default indents, while the :extra-indents
key will append to the default indents.
If something prevents you from using a config with :extra-indents
, there's an escape hatch to keep using the :indents
key as before, by adding :legacy/merge-indents? true
to the config map.
Calva is an extra good tool for experimenting with these settings. cljfmt
doesn't care about keys in the map that it doesn't know about so you can sneak in test code there to quickly see how it will get formatted by certain rules. Try this, for instance:
{:remove-surrounding-whitespace? true\n:remove-trailing-whitespace? true\n:remove-consecutive-blank-lines? false\n:insert-missing-whitespace? false\n:indents {#re \"^\\w\" [[:inner 0]]}\n:test-code\n(concat [2]\n(map #(inc (* % 2))\n(filter #(aget sieved %)\n(range 1 hn))))}\n
Save, then hit tab
, and the code should get formatted like so:
:test-code\n(concat [2]\n(map #(inc (* % 2))\n(filter #(aget sieved %)\n(range 1 hn))))\n
That's somewhat similar to Nikita Prokopov's Better Clojure Formatting suggestion. (Please be aware that this setting might not be sufficient to get complete Tonsky Formatting, please share any settings you use to get full compliance.)
"},{"location":"formatting/#rich-comments","title":"Rich Comments","text":"To encourage use of (comment ...)
forms for development, the default settings give these forms get a special treatment when formatting. Use the calva.fmt.keepCommentTrailParenOnOwnLine
setting to control this behaviour. See Rich Comments first.
Calva loooks in the config map for the key :align-associative?
and if it is true
it will use an old version of cljfmt which is patched with functionality for doing this alignment. Note, though:
You are hereby warned, and let us also remind you about the Format and Align Current Form command which lets you apply this formatting a bit more surgically, and on demand.
This old version of cljfmt is inlined in the Calva repository along with the discontinued rewrite-cljs
project. Regard it as frozen code. If you want Calva's formatter to have full support for newer Clojure constructs and the bugs in the alignment code fixed, contribute to cljfmt. See this issue for starting to collect context.
Welcome to a zero-install, interactive, guide to get you started with Clojure using:
Clojure runs on the JVM. How to install it is a big topic. Since you have already done that, you can, if you want, choose to install Calva in your local VS Code and fire up the Getting Started REPL. By all means read this page anyway, you can just skip the Gitpod parts.
Also: If you are using Windows your Java might have a bug that prevents things from working. Then you might want to defer fixing that and use the zero-install option first.
Is Gitpod Code exactly as VS Code?Almost! But, yeah, there are some difference between regular VS Code and Gitpod's ditto. Most of it doesn't matter, but finding the main menu can be a bit tricky:
","boost":10},{"location":"get-started-with-clojure/#what-youll-learn","title":"What you'll learn","text":"Fair enough. We can recommend watching any or all of these videos to get excited about Clojure and the rather unique mood of development it offers:
All in due time. \ud83d\ude04 It can be a bit confusing with all the things you find out about installing Clojure and creating projects when searching for information about it. We want you to relax about all that and just enjoy learning a bit about this fantastic programming language and the wonderful mode of development it offers.
There is a lot of info about this out there already. And since you will learn where to find Clojurians, you will also find guidance. But we suggest do these things later. First, let's focus on having fun with Interactive Programming!
","boost":10},{"location":"get-started-with-clojure/#what-you-need","title":"What you need","text":"There is always a competition for which system gets to catch keyboard shortcuts first. This worsens a bit when an application like VS Code runs in the web browser. Remember this if some shortcut/command doesn't work.
On some machines, with some web browsers, some shortcuts are caught by the web browser and instead re-opening a closed tab or whatever. These have been observed:
Sometimes the workaround is to redefine the shortcuts in VS Code, sometimes making your web browser stop catching the shortcut.
I am new to VS CodeYou might want to have a look at this Getting Started with VS Code video. (You can of course ignore the parts about installing for now.) Also, have this overview of the VS Code interface handy.
","boost":10},{"location":"get-started-with-clojure/#how-it-works","title":"How it works","text":"Use a desktop/laptop computer. Even if it actually works on the phone, it is far from convenient.
It sometimes takes a while (several minutes) for the environment to initialize. Take some deep breaths and be patient. \ud83d\ude0e
","boost":10},{"location":"get-started-with-clojure/#lets-go","title":"Let's go!","text":"Ready? Awesome. Click this button to start the guide in a new browser tab.
https://gitpod.io/#https://github.com/PEZ/get-started-with-clojure Stuck? Something not working? Or just unclear?Please don't hesitate to reach out for help, should you get stuck. See below for where to find Clojurians. As for the Calva team, we are almost always (true story) to be found at the Clojurians Slack, especially in the #calva
Channel. We are @pez
and @bringe
there.
Happy Interactive Programming! \u2764\ufe0f
","boost":10},{"location":"get-started-with-clojure/#and-where-do-i-find-those-clojurians","title":"And where do I find those Clojurians?","text":"We Clojurians inhabit a lot of community platforms. I'll list some of the more popular ones here in some order of popularity.
#beginners
channel is spectacularly fantasticYou can also ask questions, and find answers, about Clojure at ask.clojure.org
","boost":10},{"location":"get-started-with-clojure/#learn-and-practice-clojure-using-rich-4clojure","title":"Learn and Practice Clojure using Rich 4Clojure","text":"If you like the style of interactive learning that this guide provides, you should definitely check Rich 4Clojure out. It also can be used in the zero-installed way.
You can regard it as a companion to this guide. It is aimed at practicing Clojure, starting at the elementary levels, bringing you to advanced stuff.
Can I use Rich 4Clojure instead of this guide?We suggest you start by opening up this guide and do the Calva part of the excerises. Then use the welcome_to_clojure.clj
guide in combination with Rich 4Clojure..
In a similar manner to the Get Started with Clojure project, you can run the Clojure Exercism Track in your browser without installing anything and with full Interactive Programming enabled using this Template project.
","boost":10},{"location":"get-started-with-clojure/#clojuredocs","title":"ClojureDocs","text":"Clojurians draw tremendous value from ClojureDocs. At ClojureDocs the concise documentation for Clojure core functions, etcetera, are amended with examples and advice from fellow Clojurians. Crowdsourcing at its very best! It is a big part of the reason why you won't find an abundance of Clojure information at StackOverflow.
","boost":10},{"location":"get-started-with-clojure/#other-learning-resources","title":"Other learning resources","text":"Give us feedback. Spread the word. Please consider:
#improve-getting-started
channel at the Clojurian SlackPlease also consider other ways to contribute.
Thanks! \ud83d\ude4f
","boost":10},{"location":"getting-started/","title":"Getting Started","text":"Depending on wether you want to just start a Clojure REPL or you have a project you want to work with, getting started looks similar but a bit different. Regardless, you need to first:
","boost":10},{"location":"getting-started/#install-vs-code-and-calva","title":"Install VS Code and Calva","text":"Calva
in the VS Code Extension pane, then click Install.If you have a Clojure or ClojureScript project, you will be interested in how to get Calva connected to the REPL of your project. But before you run over there, you might want to familiarize yourself with Calva a bit, which you can do without a project.
The demo tells you about the command (and some about the Clojure Beginner's material that it makes available).
I am completely new to ClojureThe \u201dGetting Started\u201d REPL below introduces you to Clojure as well as to Calva. You might however, not want to start with installing the right version of Java and such to run the guide. If so you should definitely check the Get Started with Clojure guide on this site.
Three clicks will have you running Calva in your browser with the REPL ready to serve.
I don't have Java installedIf you like, you can defer installing anything at all and still get started with Calva (not kidding).
See Get Started with Clojure.
","boost":10},{"location":"getting-started/#theres-a-getting-started-repl","title":"There's a \u201dGetting Started\u201d REPL","text":"If you are new to Calva, a good place to start is using the command Fire up the \u201dGetting Started\u201d REPL. (You can open the command palette using the VS Code top menu by going to View -> Command Palette...
or by running the associated keyboard shortcut for your OS.) Demo:
It will open up a three files in a temporary directory, and start and connect a REPL. The files are:
hello_repl.clj
\u2013 The basics of how to evaluate code in Calvahello_paredit.clj
- A super brief intro to Calva structural editingwelcome_to_clojure.clj
- The very basics of the Clojure languageThe only prerequisite here is that you have Java installed. No pre-installed clojure tools required. (You will want to install these tools later, of course.)
Note
On Windows the Oracle Java installer sets Java up in some funny way so that the Getting Started REPL fails to start. We are figuring about workarounds for this, but for now, if you are on Windows, you will need to make VS Code have some other Java in the PATH
of its environment for this feature to work. See this issue on the Calva repo for more on this, including any progress.
Without creating a project structure or installing anything but Calva, you can start standalone ClojureScript REPLs both in a browser and for node:
core.cljs
and index.html
and starts the ClojureScript app, opening it in the browser.core.cljs
, and starts a nodejs REPL where it loads the file.The browser REPL app looks like so:
","boost":10},{"location":"getting-started/#you-have-a-project","title":"You have a Project?","text":"If you are new to Calva, please consider the above option first. Then when it will be time to get Calva connected to the REPL of your project.
","boost":10},{"location":"getting-started/#clojure-resources","title":"Clojure Resources","text":"If you are new to Clojure or ClojureScript altogether, please check out the guide material on the respective official sites:
There are also many great books on Clojure. Clojure for the Brave and True can be read for free online. It is a great resource for beginners.
","boost":10},{"location":"getting-started/#there-is-also-standalone-repl","title":"There is also Standalone REPL","text":"When you are more familiar with Calva, and want a standalone REPL, there is a separate command: Start a standalone REPL (not in project). It will open up a user.clj
in a temporary directory, containing only an (ns user)
form, and start and connect the REPL.
The command for starting the Getting Started REPL will download the files from this repository. It is very much work in progress, and there is not even a finished Clojure Beginner's Guide there yet. When you run the command again, and from then on, you will get the option to download new files or keep using your existing. Downloading new ones will not overwrite your existing ones, because they will be downloaded to a new temp directory. You can find the directory easily using VS Codes context menu command for revealing a file in the Explorer/Finder.
","boost":10},{"location":"getting-started/#one-last-thing","title":"One Last Thing","text":"Happy coding! \u2665\ufe0f
","boost":10},{"location":"hiccup/","title":"Converting HTML to Hiccup","text":"Calva can help you convert HTML to Hiccup.
","boost":7},{"location":"hiccup/#features","title":"Features","text":"","boost":7},{"location":"hiccup/#three-commands","title":"Three commands","text":"The resulting data structure is formatted with zprint using it's :style :hiccup
configuration.
In addition to, optionally, being able to convert style attributes to maps and kebab-case attributes, the conversion:
id
attribute and classes are made part of the tag, CSS selector style<foo id=\"bar\"></foo>
=> [:foo#bar]
<foo class=\"c1 c2\"></foo>
=> [:foo.c1.c2]
<foo id=\"bar\" class=\"c1 c2\"></foo>
=> [:foo#bar.c1.c2]
<foo id='foo-[id]'></foo>
=> [:foo {:id \"foo-[id]\"}]
<foo class='clz1 clz[2]'></foo>
=> [:foo.clz1 {:class [\"clz[2]\"]}]
<foo> \\nbar\\n </foo>
=> [:foo \"bar\"]
<foo> \\n </foo>
=> [:foo]
<foo disabled></foo>
=> [:foo {:disabled true}]
<foo disabled=disabled></foo>
=> [:foo {:disabled \"disabled\"}]
viewBox
and baseProfile
(SVG is picky about it)<foo bAsePROFilE=bar viewbox=\"0 0 1 1\"></foo>
=> [:foo {:baseProfile \"bar\" :viewBox \"0 0 1 1\"}]
<foo><!-- ... --></foo>
=> [:foo (comment \"...\")]
<foo></foo><foo></foo>
=> [:foo]\\n[:foo]
The Hiccup converstion can be tweaked with two options using the setting calva.html2HiccupOptions
, which is a map/object:
mapify-style
: boolean, default false
. When true
any style
attribute will be converted to a map (Reagent supports this)kebab-attrs?
: boolean, default false
. When true
attribute names will be converted from camelCase, or snake_case/SNAKE_CASE to kebab-case. (Reagent wants most attribute names like this.)add-classes-to-tag-keyword?
: boolean, default true
. When true
all class names will be added CSS-style to the tag keyword ([:tag.clz1.clz2]
), as opposed to being kept in the class attribute. Keeping the class names in the attribute may be preferable with elements having a lot of class names, such as when using Tailwind CSS.The Copy HTML as Hiccup command is available from VS Code's Edit menu, as well as the editor context menu, in both cases under the Copy as sub menu.
","boost":7},{"location":"hiccup/#the-commands-take-arguments","title":"The commands take arguments","text":"This options map can also be provided as an argument to the commands, so you can bind keyboard shortcuts to a particular configuration for the conversion.
The command calva.convertHtml2Hiccup
takes a map as an argument:
toUntitled
: boolean
, default false
. When false
the result of the conversion will be returned to the caller (This is intended for Joyride, or some other VS Code extension). When true
it will behave like the default command does, placing the result of the conversion in an Untitled Clojure file.options
: Same as those calva.html2HiccupOptions
mentioned above.The calva.pasteHtmlAsHiccup
and calva.copyHtmlAsHiccup
commands takes only a calva.html2HiccupOptions
map.
The commands have no default keyboard shortcuts, you use the Command Palette to execute them, or you bind your own shortcuts. Here are some examples:
// calva.convertHtml2Hiccup\n{\n// With args, `\"toUntitled\": true` is necessary for keyboard shortcuts\n// without it, the command just returns the result to the caller\n\"key\": \"ctrl+alt+c ctrl+h\",\n\"command\": \"calva.convertHtml2Hiccup\",\n\"args\": {\"toUntitled\": true, \"options\": {\"mapify-style?\": false}}\n},\n{\n// Only for completeness, providing the HTML is only useful from e.g. Joyride \n\"key\": \"ctrl+alt+c shift+h\",\n\"command\": \"calva.convertHtml2Hiccup\",\n\"args\": {\"html\": \"<foo style='a: b' bar='baz'>gaz<foo>\", \"toUntitled\": true}\n},\n{\n// Without args, the command uses the `calva.html2HiccupOptions` configuration\n// And writes the results to an Untitled document\n\"key\": \"ctrl+alt+c h\",\n\"command\": \"calva.convertHtml2Hiccup\",\n},\n\n// calva.pasteHtmlAsHiccup\n{\n// Override the `calva.html2HiccupOptions` configuration\n\"key\": \"ctrl+alt+h ctrl+v\",\n\"command\": \"calva.pasteHtmlAsHiccup\",\n\"args\": {\"mapify-style?\": true, \"kebab-attrs?\": true}\n},\n{\n// Without args, the command uses the `calva.html2HiccupOptions` configuration\n\"key\": \"ctrl+alt+h v\",\n\"command\": \"calva.pasteHtmlAsHiccup\"\n},\n\n// calva.copyHtmlAsHiccup\n{\n// Override the `calva.html2HiccupOptions` configuration\n\"key\": \"ctrl+alt+h ctrl+c\",\n\"command\": \"calva.copyHtmlAsHiccup\",\n\"args\": {\"mapify-style?\": false, \"kebab-attrs?\": true}\n},\n{\n// Without args, the command uses the `calva.html2HiccupOptions` configuration\n\"key\": \"ctrl+alt+h c\",\n\"command\": \"calva.copyHtmlAsHiccup\"\n},\n
The default/args-less bindings are placed last because reasons.
","boost":7},{"location":"hiccup/#using-from-joyride-or-some-other-vs-code-extension","title":"Using from Joyride (or some other VS Code extension)","text":"As with any VS Code command using these from Joyride is a matter of calling executeCommand
.
calva.pasteHtmlAsHiccup
and calva.pasteHtmlAsHiccup
","text":"(-> (vscode/commands.executeCommand \"calva.pasteHtmlAsHiccup\"\n#js {:mapify-style? true})\n(.then ...))\n\n(-> (vscode/commands.executeCommand \"calva.copyHtmlAsHiccup\"\n#js {:mapify-style? true})\n(.then ...))\n
","boost":7},{"location":"hiccup/#calvaconverthtml2hiccup","title":"calva.convertHtml2Hiccup
","text":"Without options the command behaves just like selecting the command from the command palette. If there is a selection it will be converted, otherwise the whole file. The result will be opened in a new Untitled document.
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\")\n(.then ...))\n
Called with arguments it will by default return an object with a .-result
member which is a string with the Hiccup.
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" #js {:html \"<foo class='clz1 clz2>bar</foo>\"})\n(.then #(println (.-result %))))\n\n(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" #js {:options #js {:mapify-style? false}})\n(.then #(println (.-result %))))\n
To make it put the text in a new Untitled document instead, provide the argument option :toUntitled true
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" #js {:toUntitled true\n:html \"<foo class='clz1 clz2>bar</foo>\"\n:options #js {:mapify-style? true\n:kebab-attrs? true}})\n(.then ...))\n
","boost":7},{"location":"jack-in-guide/","title":"Learn about Calva Jack-in","text":"The Calva Jack-In Academy, by @pez
Like with CIDER Jack-in, Calva's let-me-help-you-start-your-project-and-connect feature might seem a bit mysterious. It really is helpful, but also really isn't mysterious. Here are a few things about it that is good to know about.
Note
If you came here to find out how to configure the versions of the dependencies that Calva Jack-in injects, see Customizing Calva - Jack-in Dependency Versions.
","boost":6},{"location":"jack-in-guide/#what-it-solves","title":"What it Solves","text":"At first it might seem that something like lein repl
in a terminal and then connecting Calva is enough. It sometimes might be, but only if you are in luck. To provide many of its IDE features, Calva relies on nREPL middleware, mainly cider-nrepl and, for ClojureScript, piggieback. When starting your Clojure(Script) app and its REPL, it needs to be started with these dependencies satisfied. There are mainly three ways this can be achieved.
project.clj
, deps.edn
, shadow-cljs.edn
, and combination of these).~/.lein/profiles.clj
and ~/.clojure/deps.edn
).Because 1 and 2 are hard to keep in sync with the various editor environments people in your project might be using, Calva Jack-In is about 3.
Ideally, you will be able to rid your project files completely of editor dependencies when people working on the project can rely on the Jack-In features of their Clojure editor.
","boost":6},{"location":"jack-in-guide/#a-controlled-shell-command","title":"A Controlled Shell Command","text":"At its core Calva Jack-In is just a glorified, REPL-starting, command-line. No, it is more than that, but anyway. The command line can look like so for a Leiningen project using legacy Figwheel for its ClojureScript assistance:
lein update-in :dependencies conj '[nrepl\"0.6.0\"]' -- update-in :dependencies conj '[cider/piggieback\"0.4.1\"]' -- update-in :dependencies conj '[figwheel-sidecar\"0.5.18\"]' -- update-in :plugins conj '[cider/cider-nrepl\"0.22.4\"]' -- update-in '[:repl-options :nrepl-middleware]' conj '[\"cider.nrepl/cider-middleware\"]' -- update-in '[:repl-options :nrepl-middleware]' conj '[\"cider.piggieback/wrap-cljs-repl\"]' -- with-profile +dev repl :headless\n
Even if a bit long, it might look simple enough. But actually it has taken quite some effort to make Calva craft it. Shell quoting can be really tricky. Look at how '[nrepl\"0.6.0\"]'
doesn't have a space between nrepl
and the version. That was the only way I could find that was cross platform enough to make all supported shells parse the command line. (The trick relies on that the string is read by the super reliable Clojure Reader, which does not need that space to tokenize it.)
It is awesome that Clojure is used on so many platforms, but for a tool smith this also means more work. (I think Windows and its shell hell ate up about 95% of the many hours spent on getting the quoting good enough.)
The command-line crafted is then used to start a shell command that Calva controls, but we are getting ahead of ourselves...
","boost":6},{"location":"jack-in-guide/#project-types-builds-aliases-profiles-etcetera","title":"Project Types, Builds, Aliases, Profiles, etcetera","text":"In order to cook the right command for your project, Calva looks for project files, reads them, and figures out what possible project types and ClojureScript tools could be involved. Then Calva presents you with a menu with the options it has found. You need to know enough about your project to answer this question. It looks like this in a shadow-cljs project that uses a deps.edn
file for setting up its classpath.
(I know enough about this particular project to know that I should choose the shadow-cljs
project type.)
But Calva isn't ready to cook the command-line just yet. Depending on the project type, and contents of your project files, more info is needed. E.g. in the case of shadow-cljs projects, Calva needs to know what builds to start.
Here you can select any combination of builds defined in the project, and Calva will cook a command line that starts them.
You might get more prompts from Calva before it issues the command, but for this example project, Calva goes ahead, cooks the command line, and issues it. On my Mac, it looks like so:
npx shadow-cljs -d cider/piggieback:0.4.1 -d cider/cider-nrepl:0.22.4 watch :app\n
(Much shorter than the one with lein-figwheel, right? It is because shadow-cljs is aware of CIDER dependencies, so it doesn't need as many dependencies specified as some other project types do.)
","boost":6},{"location":"jack-in-guide/#connecting","title":"Connecting","text":"When the command is issued Calva needs to wait until the REPL Server is started, before connecting to it and possibly continuing with starting a ClojureScript REPL and connecting to that as well. It also needs to know which port to connect to.
Because reasons, Calva can't yet read the stdout
of the shell command it has issued, so to know when the REPL server is started, and on which port, Calva monitors the filesystem for the .nrepl-port
file. (This file is not always named like that. shadow-cljs, for instance, creates the file .shadow-cljs/nrepl.port
.)
When the port file is created, Calva picks up the port number from it and connects to the nREPL server. At this point you have a Clojure REPL backing your Calva session, providing all sorts of nice IDE help for you.
","boost":6},{"location":"jack-in-guide/#starting-your-clojure-app","title":"Starting Your Clojure App","text":"Once you have the Clojure REPL connected you can start your Clojure app/server. See Custom Connect Sequences for how to let Calva do this for you automatically. See the same article for ways to automate more of the Jack-In process. It can be brought down to a single Jack-In command/action, even for a full stack Clojure and ClojureScript application.
","boost":6},{"location":"jack-in-guide/#clojurescript","title":"ClojureScript","text":"For ClojureScript, things are not done yet, though, far from it. It turns out that cooking the command line was the easy part.
In order for Calva to provide REPL power for ClojureScript projects, several things need to happen:
Depending on ClojureScript project type, Calva uses different methods to start the compilation and the watcher:
This results in a bit of difference in the user interaction. Mainly that for shadow-cljs, the user needs to check the Jack-In Terminal tab to follow what's going on.
","boost":6},{"location":"jack-in-guide/#starting-the-app","title":"Starting the App","text":"Number 3 above, the app needs to be started, might seem obvious, but it actually trips many people up. Because of this, Calva goes to quite some lengths to provide assistance. Many projects are configured not to spawn a browser session automatically, requesting the app once it has been compiled, so we can't rely on that.
What Calva does instead is to monitor the output of the commands it uses for starting the compilation, looking for information that the app is ready to be requested/started. It then tells the user this, providing a URL, in case it is a browser app. (There are also settings that tell Calva to open the URL automatically for you, regardless what the project settings are.)
","boost":6},{"location":"jack-in-guide/#connecting_1","title":"Connecting","text":"Meanwhile, Calva is monitoring the output and when it sees that the app is started, it continues to hook up the REPL connection to the editor.
This whole connection sequence is quite configurable, using Custom Connect Sequences. In fact, Calva's built in ClojureScript sequences (Figwheel Main, lein-figwheel, shadow-cljs, and ClojureScript built-ins for both Browser and Node) are all built using those same settings mechanisms.
","boost":6},{"location":"jack-in-guide/#shadow-cljs-is-less-managed-by-calva","title":"shadow-cljs is Less Managed by Calva","text":"NB: The managed way in which Calva creates and connects the ClojureScript REPL breaks apart a bit for shadow-cljs, which works a bit differently and also outputs most of the information Calva is looking for on the stdout
of the REPL start command (where Calva can't see it, remember?). We'll figure out a better way to support shadow-cljs, but for now, the user needs to do more of this figuring out than is needed with Figwheel projects.
So, there are things going on when you start Jack-In, and even more things for ClojureScript projects, but Calva tries to keep it together, so as a user it is a matter of paying attention and responding to a few prompts/menus with pre-populated options (prompts which can be configured away, even).
","boost":6},{"location":"jack-in-guide/#switch-clojurescript-builds","title":"Switch ClojureScript Builds","text":"Once the REPL is connected you might want to change which ClojureScript build you have Calva connected to. For this Calva has the Select CLJS Build Connection command. Please note that you can only switch between builds that you have started.
","boost":6},{"location":"jack-in-guide/#play-with-starting-the-cljs-repl-yourself","title":"Play With Starting thecljs-repl
Yourself","text":"To get a good grip on what is going on when creating and connecting the ClojureScript REPL, I can recommend making a custom connect sequence which leaves the REPL unpromoted (e.g. give it nil
as connectCode
), and then evaluate the cljs-repl
start commands yourself. So for instance, promoting it to a ClojureScript Node.js REPL looks something like so:
user=> (require 'cljs.repl.node)\nuser=> (cider.piggieback/cljs-repl (cljs.repl.node/repl-env))\nClojureScript 1.10.844\nTo quit, type: :cljs/quit\nnil\ncljs.user=> |\n
It is the piggieback middleware there telling you that you can unpromote the REPL by \u201devaluating\u201d :cljs/quit
.
Because Calva uses the Clojure REPL connection to spawn the ClojureScript REPL, and because Calva only handles one Clojure REPL per VS Code window, some projects need special handling by the user.
If your full stack project is using shadow-cljs for the frontend, like this Fulcro template project does, maybe you first try to Jack-In to your backend Clojure REPL, and then to your shadow-cljs frontend. This works if you do it in separate VS Code windows, but if you do it in the same window, the second Jack-In will kill the backend session! See also connect shadow-cljs in fullstack projects.
See Workspace Layouts for tips about how to open the same project folder in two separate VS Code windows.
Please also consider to play around with starting the REPL and ClojureScript wiring entirely from the terminal, see this example project for some instructions on that. You can also use that project together with the nil
for connectCode
sequence mentioned above.
There, you now know all there is to know about Calva Jack-In.
Just kidding, there are a few more details to it, some of which might find their way into this article at a later time.
To really get to know it all, you will need to spend some time with the Calva Jack-In code. Head over to the Calva Development Wiki to learn how to hack on Calva.
","boost":6},{"location":"joyride/","title":"Using Calva With Joyride","text":"Joyride is a VS Code extension for user space scripting of VS Code itself. You find the extension here. The scripting language for Joyride is the best you language imaginable: Clojure. And, as is proper for a Clojure implementation, it has a REPL, even an nREPL server.
This means you can connect Calva to Joyride and interactively develop your VS Code scripts.
This video shows Joyride in action, using Calva as the nREPL client.
"},{"location":"joyride/#how-to-connect","title":"How to connect","text":"Once you have the Joyride extension installed you can start its REPL and connect Calva to it (a.k.a Jack-in).
Start the Joyride REPL and Connect
This 1 minute video shows the following steps:
joyride
project type(Right-click the video and choose Full Screeen if it is too tiny embedded.)
"},{"location":"joyride/#how-to-get-started-with-joyride","title":"How to Get Started with Joyride","text":"The Joyride README has some Quick Start pointers for you. Please feel invited to the #joyride
channel on the Clojurians Slack and chat with us and other Joyride users.
Come on, Join the Joyride! \u2764\ufe0f
"},{"location":"krell/","title":"Using Calva With Krell","text":"Krell is \u00e0 la carte ClojureScript tooling for React Native.
Even if Calva does not yet have built-in support, all is not lost. You can add support yourself by way of a Custom REPL Connect Sequence. Here's how;
"},{"location":"krell/#starting-the-krell-clojurescript-repl","title":"Starting the Krell ClojureScript REPL","text":"Add this REPL Connect Sequence to your workspace settings.json
:
\"calva.replConnectSequences\": [\n{\n\"name\": \"deps.edn + Krell\",\n\"projectType\": \"deps.edn\",\n\"cljsType\": {\n\"connectCode\": \"(require '[clojure.edn :as edn] \\n '[clojure.java.io :as io]\\n '[cider.piggieback] \\n '[krell.api :as krell]\\n '[krell.repl])\\n\\n(def config (edn/read-string (slurp (io/file \\\"build.edn\\\"))))\\n(apply cider.piggieback/cljs-repl (krell.repl/repl-env) (mapcat identity config))\",\n\"dependsOn\": \"User provided\"\n}\n}\n]\n
Then issue the command Start a Project REPL and Connect (aka Jack-In). It start the project and connect to the Krell REPL once the app is running on a device (wether real or virtual/emulated).
"},{"location":"krell/#additional-vs-code-tips","title":"Additional VS Code Tips","text":"For a smooth workflow you can also:
{\n\"type\": \"chrome\",\n\"request\": \"launch\",\n\"name\": \"Launch Debugger\",\n\"url\": \"http://localhost:8081/debugger-ui/\",\n\"webRoot\": \"${workspaceFolder}\"\n}\n
Together with the connect sequence this will make for a start of a Krell session like this:
F5
)Once the debugger (a Chrome session) is running, you probably will want to enable Custom Formatters in order for clojure structures to be logged conveniently.
"},{"location":"linting/","title":"Linting","text":"Calva does no linting, yet with Calva you get excellent linting. That is because Calva uses clojure-lsp, which provides linting powered by clj-kondo.
clj-kondo comes with great default rules, and the configuration can be customized. One of your options for the configuration file is to placed a config.edn
file in .clj-kondo/
at the root of your project. This folder may or may not already exist. It is safe to create it manually if it doesn't.
The configuration will be merged with the default set of rules, you can only specify the rules you want to override. The full list of available options can be found on clj-kondo's github
clojure-lsp is customizable, see Clojure LSP Settings for your options. It is safe to manually create the .lsp
folder if it doesn't exist.
You might want to read about how to configure clj-kondo. These two sections might be of extra interest:
If you see a linting squiggle under the first character of the file with an error you don't quite understand, it is probably something wrong with your clj-kondo configuration.
Files are linted as they're being edited. If you want to lint the whole project, use the clj-kondo cli command. See https://github.com/borkdude/clj-kondo for more info on that. Windows users might like to know that they too can get a clj-kondo cli command now, via npm install -g clj-kondo
. It'll be a bit slower to start than the native build, but for sure it's better than not having a clj-kondo command! See https://github.com/borkdude/clj-kondo/blob/master/doc/install.md#npm-linux-macos-windows for more on this.
When your cursor is on a macro form in the editor, you may notice a code action (click the light bulb that appears) called Resolve Macro As. Running this code action will ask you what macro you'd like to resolve the current macro as, and then what clj-kondo config file you want the macro to be saved to. This code action is also available as a command.
"},{"location":"live-share/","title":"Using Calva with Live Share","text":"Live Share is a Microsoft provided VS Code extension. It allows you to share the workspace that you have open in your computer with somebody else. Everybody is then working on the same source code files, namely those on your computer. You can edit files at the same time, everyone has their own caret. You can follow each other (i.e. when someone switches to a different file, you will as well). This is great for remote pair programming, for example.
An extra nice thing is that each participant is using their own VSCode configuration, including fonts, colors, keyboard shortcuts, etc.
Disable Calva Spritz to get rid of Notebooks interference
The headline below Calva Supports Live Share is true. However, due to a bug in LiveShare, guest participants always get their Clojure files opened in the Calva Clojure Notebooks editor. To workaround this issue Calva uses a \u201dside-car\u201d extension named Calva Spritz for the Notebooks associations of Clojure files. You can disable that extension when participating in LiveShare sessions.
"},{"location":"live-share/#calva-supports-live-share","title":"Calva Supports Live Share","text":"When using Calva, you can use Live Share as well. Editing works exactly the same as for any other programming language. What makes Calva a bit special, is the REPL. When using Live Share, Calva allows the host to share the REPL with guests as well. If you use any of the supported configuration, this will be pretty much automatic.
You need to enable the LiveShare support
Due to an issue in the LiveShare API, for some users, this feature stops Calva from connecting the REPL. Therefore the support is disabled by default. The setting is calva.useLiveShare
.
This is what a typical scenario looks like:
Voila! Both the guest and the host can now use the REPL that is running on the host. Things like documentation lookup now also work on the guest's machine.
"},{"location":"live-share/#control-visibility-of-calva-folder","title":"Control Visibility of.calva
Folder","text":"Calva depends on the output.calva-repl
file to be available. If you have the .calva
folder listed in your .gitignore
, this also causes the folder to be hidden from guests in Live Share by default. In order to make the folder visible, you can put a file called .vsls.json
in your project. In its simplest form, the contents can be this:
{\n\"$schema\": \"http://json.schemastore.org/vsls\",\n\"hideFiles\": [\n\"!.calva\"\n]\n}\n
Now the .calva
folder is shared as well. But also any other file and folder that you may have in your .gitignore
. If you want to have more fine-grained control, please refer to the section Controlling file access and visibility of the Live Share documentation.
output.calva-repl
file, which all participants are sharing. It may work better to evaluate things in the source code editors instead of from the REPL window. Otherwise you will end up in a situation where one person is typing something in the output.calva-repl
window, and somebody else is evaluating something (hence sending the output there) at the same time. That gets confusing quickly.Together with Calva there is an extension called Calva Spritz installed. All it does is to provide the association of Clojure file types to Clojure Notebooks. We do it this way because of the LiveShare issues mentioned above. So that you can disable the Notebook association when participating as a guest in LiveShare sessions. The issue is tracked here:
Calva Spritz can be disabled and enabled at will, and it will take immediate effect, without any reload of VS Code needed.
"},{"location":"luminus/","title":"How to Use Calva with Luminus","text":"Luminus is a powerful and versatile Leiningen template for creating web development projects. It comes with built in configuration which makes it easy to use Calva as your Clojure(Script) editor.
"},{"location":"luminus/#server-shadow-cljs","title":"Server + shadow-cljs","text":"Basically this is the same wokflow as with Server only. Behind the scenes there is more happening, though. Such as the ClojureScript app being built and the CLJS REPL connected once the web app is running.
$ lein new luminus my-luminus-shadow +reagent +re-frame +shadow-cljs\n
$ npm i\n
(Or yarn
if you prefer.)my-luminus-shadow
. Open it in VS Code: $ code my-luminus-shadow\n
ctrl+alt+c ctrl+alt+j
[:app] Build completed.
Note
Currently Calva has troubles following the app-start with shadow-cljs, so Calva will report Jack-in done.
in the output window before shadow-cljs is actually done building the app. If you open the app page at that stage, you will see a message to \u201cPlease run lein shadow watch app
\u201d. Rest assured that this is already underway. Follow the Jack-in process in the Terminal tab in VS Code for the message that the app is built, then reload the app page in the web browser.
The workflow here is really just: Jack-in and start hacking. However, the first time it will involve these steps:
$ lein new luminus my-luminus-server\n
my-luminus-server
. Open it in VS Code: $ code my-luminus-server\n
ctrl+alt+c ctrl+alt+j
Jack-in done.
in the output window.This is Legacy Figwheel (lein-figwheel), so the recommendation is to use the shadow-cljs setup instead. As with the server only, the workflow here is really just: Jack-in and start hacking. The first time it involves these steps:
$ lein new luminus my-fw +reagent\n
my-fw
. Open it in VS Code: $ code my-fw\n
ctrl+alt+c ctrl+alt+j
, select Server + Client - my-fw in the Project type picker menu, and wait for the web app to pop open in your web browser.If you prefer to open the web app yourself, open .vscode/settings.json
and change \"shouldOpenUrl\"
to false
in the pre-configured Calva connect sequence. Calva will then print the URL 127.0.0.1:3000 in the output, so that you can click it open.
You will have three Calva Custom Command Snippets configured. Invoke them by issuing the Run Custom REPL Command, ctrl+alt+c .
(that's a dot). These commands control the Luminus server:
Start <project> Server
Stop <project> Server
Restart <project> Server
When used, Calva will open its REPL window and execute the command, if it is not already opened. You can close this window if you prefer to use the REPL directly from the Clojure files.
Calva also opens the REPL window, and starts the Luminus server, as part of the Jack-in process.
"},{"location":"merch/","title":"Calva Merch","text":"In this video, there is a question about where you can buy the Calva T-shirt:
You couldn't, then. But now you can! On Amazon.
Zero profit
To keep the admin of this shop to a minimum the merch is sold at production prize (or as close to production prize as the respective store allows). There is no royalty going to anyone in the Calva team when you buy one of these t-shirts. You will represent, which is certainly a way to support the project. You are of course encouraged to support us via sponsoring as well:
Calva Merch is available on Zazzle and on Amazon
","boost":10},{"location":"merch/#zazzle","title":"Zazzle","text":"","boost":10},{"location":"merch/#calva-symbol-sticker","title":"Calva Symbol Sticker","text":"Calva Symbol Sticker by BetterThanTomorrow","boost":10},{"location":"merch/#joyride-symbol-sticker","title":"Joyride Symbol Sticker","text":"Joyride Symbol Sticker by BetterThanTomorrow","boost":10},{"location":"merch/#amazon-merch","title":"Amazon Merch","text":"","boost":10},{"location":"merch/#the-designs","title":"The designs","text":"There are four design, all featuring the Calva symbol (the Calva glass), which are all available for a Standard T-shirt, in men's, women's and kid's cut, and in some different colors. In the .com
store there are also Premium T-shirts**.
Available at:
The Calva symbol and Logo front, Rich Comments back.
Available at:
Available at:
The Calva symbol front, Rich Comments Back.
Available at:
Note
What's available on this or that Amazon site will vary a bit and it is a bit slow to add a particular design to a particular market. Eventually I hope to have both designs up on these markets: .com
, .co.uk
, .de
, .fr
, .it
, .es
, and .co.jp
When you create a new clojure file, a file with .clj
, .cljc
or .cljs
extension, an appropriate namespace form will be added to the file. This feature is provided by clojure-lsp.
Since nbb can be started such that it is an nREPL server, Calva can connect to it and a lot of the features will work.
Calva can also start nbb and connect its REPL for you, using the Jack-in command. This will start an nbb nREPL server on a random port and connect Calva to it. Check out this video where they use Calva and nbb to create a CLI tool as an executable npm module:
In that video they ask for a JavaScript to ClojureScript converter. And there is one: https://mauricioszabo.gitlab.io/js2cljs/
Though if you are using Calva, this converter is easier to use directly via the command Calva: Convert JavaScript to ClojureScript:
Errors jacking in to nbb on Windows?
On some machines it seems necessary to first run npx nbb
from the CMD
prompt to make jack-in work. Or try first install it npm i -g nbb
. (You probabl want nbb installed globally anyway.)
Don't expect complete support
nbb's nREPL server is completely new and and WIP. It will be a bit limited compared to a full cider-nrepl enhanced \"regular\" Clojure nREPL server. Things like function signatures, and more do not work.
It's a bit hacky
The nbb nREPL server is the first ClojureScript nREPL server around and throws Calva's assumption that an nREPL server is always started in a Clojure process out the window. The nbb Jack-in/connect option \u201dpretends\u201d it is connecting to a Clojure nREPL and then the code fro promoting the nREPL session to a ClojureScript one is just dummy code.
This means that if you open a Clojure (.clj
) file while connected to an nbb nREPL server, it will still be a ClojureScript session serving even though Calva will indicate that it is a Clojure one. Bare with us until we can fix this properly in Calva.
WIP: Notebook support is very basic and experimental
Please help test the feature. We're looking forward to your feedback!
You can open any Clojure file as a notebook by right clicking the file -> Open with...
-> Clojure Notebook
.
Running cells sends them to the REPL and pretty prints the results. If the return is a string that starts with <html
it will be displayed in an html webview.
Forms inside (comment)
blocks get shown as their own cells. When adding code blocks in between those cells they get saved with the same indentation as the first form.
Together with Calva there is an extension called Calva Spritz installed. It only provides the association of Clojure file types to Clojure Notebooks. This is due to the LiveShare issues mentioned above. So that you can disable the Notebook association when participating as a guest in LiveShare sessions. The issue is tracked here:
nREPL and cider-nrepl middleware enable Calva to support full Interactive Programming.
","boost":2},{"location":"nrepl_and_cider-nrepl/#about-nrepl","title":"About nREPL","text":"The REPL is a Clojurists quintessential tool, it\u2019s what we use to do Interactive Development, the hallmark of the LISP style of development.
In Interactive Development (more commonly but somewhat imprecisely referred to as REPL-driven development), the programmer\u2019s editor has a direct connection with the running application process. This allows evaluating pieces of code in the context of a running program, directly from where the code is written (and so not in some separate \u201cREPL place\u201d), inspecting and manipulating the innards of the process. This is helped along by the dynamic nature of Clojure in which any var can be redefined at any point, allowing for quick incremental and iterative experimentation and development.
This is why it\u2019s essential to the Clojure development experience to have proper editor support, a plugin which bridges the gap between where the code is written and where the code is run. So we have CIDER for Emacs, Calva for VS Code, Cursive for IntelliJ, Conjure or Iced for Vim, and so forth. Often these will also leverage the same (or a parallel) connection into the process for other editor affordances, like navigation and completion.
But for these editor plugins to connect to the Clojure process something needs to be listening on the other side, accepting connections, allowing the initiation of a program-to-program dialogue. The most common way to achieve this is by leveraging the nREPL protocol, an asynchronous message-based network protocol for driving interactive development. The application process is started with an embedded nREPL server, so that the editor can connect as an nREPL client.
From: Lambda Island
","boost":2},{"location":"nrepl_and_cider-nrepl/#about-the-nrepl-server-and-middleware","title":"About the nREPL Server and Middleware","text":"nREPL is an extensible protocol, the reference server implementation understands certain core operation types like \"eval\". More operations can be supported, or existing operations can be modified or augmented, through nREPL middleware. For example: the Piggieback middleware can intercept \"eval\" messages, and forward them to a ClojureScript environment, rather than evaluating them in the Clojure process itself.
Which middleware to use will mostly depend on the editor you are using. You\u2019ll typically find that the Clojure-specific functionality for a given editor is partly implemented as a typical editor extension, for instance CIDER written in Emacs LISP, or Calva written in Typescript, and partly as nREPL middleware, providing the functionality the editor extension relies on. For instance, both CIDER and Calva rely on functionality provided by cider-nrepl.
Also from: Lambda Island
","boost":2},{"location":"nrepl_and_cider-nrepl/#viewing-the-communication-between-calva-and-nrepl","title":"Viewing the Communication Between Calva and nREPL","text":"You can view the messages sent between Calva and nREPL by running the command Toggle nREPL Logging Enabled
. Enabling nREPL message logging triggers the creation of a VS Code output channel called nREPL Messages
where the messages will be logged. Messages sent to nREPL from Calva will have -> sent
above them, and messages sent from nREPL to Calva will have <- received
above them. Disabling nREPL message logging causes the nREPL Messages
channel to be removed and messages will no longer be logged.
Each message is logged as JSON. If you find a need for the messages to be logged as EDN (for example, to transform and analyze them with Clojure) please open a GitHub issue for this change. A PR would be welcome too!
The example below shows two messages logged when the cursor hovers over println
in a Clojure file while a REPL is connected.
-> sent\n{\n op: 'info',\n ns: 'test-lein.core',\n symbol: 'println',\n id: '7',\n session: '1a080b66-b1b6-4b8c-8206-c4af2cc02747'\n}\n\n<- received\n{\n added: '1.0',\n 'arglists-str': '[& more]',\n column: 1,\n doc: 'Same as print followed by (newline)',\n file: 'jar:file:/Users/brandon/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar!/clojure/core.clj',\n id: '7',\n line: 3733,\n name: 'println',\n ns: 'clojure.core',\n resource: 'clojure/core.clj',\n 'see-also': [\n 'clojure.core/prn',\n 'clojure.core/print',\n 'clojure.core/println-str',\n 'clojure.pprint/pprint'\n ],\n session: '1a080b66-b1b6-4b8c-8206-c4af2cc02747',\n static: 'true',\n status: [ 'done' ]\n}\n
","boost":2},{"location":"output/","title":"Output Destinations","text":"Calva categorizes output into three types:
With the setting calva.outputDestinations
, you can configure where each category of output should go to:
The reason there are several options for this is partly legacy and partly because VS Code restricts the placement of different views in different ways. We hope you will find a combination of output destinations that suits you.
"},{"location":"output/#commands-for-showing-output-destinations","title":"Commands for showing output destinations","text":"These are the commands and their default keyboard shortcuts for revealing output destinations
ctrl+alt+o o
ctrl+alt+o c
ctrl+alt+o t
ctrl+alt+o r
When Calva is connected to the REPL, the Output window will by default print not only results of evaluations, but also:
stdout
and stderr
in the main thread of the evaluationsstdout
and stderr
from child threads of the evaluationsstdout
and stderr
by the REPL processYou can control the default via the calva.redirectServerOutputToRepl
setting. It defaults to true
. Setting it to false
before connecting the REPL will result in that 2. and 3. will not get printed in the Output window. It will then instead be printed wherever the REPL process is printing its messages, usually the terminal from where it was started (the Jack-in terminal if Calva started the REPL).
Structural editing and navigation for Clojure.
","boost":7},{"location":"paredit/#what-is-paredit","title":"What is Paredit?","text":"Calva Paredit helps you navigate, select and edit Clojure code in a structural way. LISP isn't line or character oriented, it is based around S-expressions, a.k.a forms. We strongly recommend that you take advantage of the structural nature of Clojure, and have therefore put a lot of work into making Calva Paredit extra awesome.
If you are new to Paredit, consider starting with learning the Slurp Forward (pull in the next form into this form) and Barf Forward (push the last form out of this form). It will take you quite far.
","boost":7},{"location":"paredit/#strict-mode","title":"Strict Mode","text":"To protect the integrity of your code, Strict mode is enabled by default.
Strict mode keybinding Action Descriptionbackspace
Delete Backward Deletes one character backwards, unless it will unbalance a form. Otherwise moves past the character instead of deleting it. If the list is empty, it will remove both open and close brackets. delete
Delete Forward Deletes one character forwards, unless it will unbalance a form. Otherwise moves past the character instead of deleting it. If the list is empty, it is removed. alt+backspace
Force Delete Backward Deletes one character backwards, even if it will unbalance a form. alt+delete
Force Delete Forward Deletes one character forwards, even if it will unbalance a form. Disable at your own peril. Strict mode can be toggled on/off using the Toggle Paredit Mode command, and there is a status bar indicator telling you:
Indicator Paredit Mode[\u03bb]
Strict (\u03bb)
Cave Man (strict mode off) \u03bb
No default key bindings Toggle between Strict and Cave Man using: ctrl+alt+p ctrl+alt+m
There is also a setting, calva.paredit.strictPreventUnmatchedClosingBracket
, that will help you to not enter unbalanced closing brackets into the code.
The Paredit commands are sorted into Navigation, Selection, and Edit. As mentioned, Slurp and Barf are power commands, which go into the editing category. Learning to navigate structurally, using shortcuts, also saves time and adds precision to your editing. It has the double effect that you at the same time learn how to select structurally, because that is the same, just adding the shift key.
To make the command descriptions a bit clearer, each entry is animated. When you try to figure out what is going on in the GIFs, focus on where the cursor is at the start of the animation loop.
","boost":7},{"location":"paredit/#strings-are-not-lists-but-anyway","title":"Strings are not Lists, but Anyway...","text":"In Calva Paredit, strings are treated in much the same way as lists are. Here's an example showing Slurp and Barf, Forward/Backward List, and Expand Selection.
","boost":7},{"location":"paredit/#navigating","title":"Navigating","text":"(Modify these with shift
to select rather than move, see below.)
ctrl+right
(win/linux)alt+right
(mac) Forward Sexp Moves the cursor forward, to the end of the current form. If at the end, moves to the end of the next form. Will not move out of lists. ctrl+left
(win/linux)alt+left
(mac) Backward Sexp Moves the cursor backward, to the start of the current form. If at the start, moves to the start of the previous form. Will not move out of lists. ctrl+down
Forward Down Sexp Moves the cursor into the following list. ctrl+alt+up
Backward Down Sexp Moves the cursor into the preceding list. ctrl+alt+down
Forward Up Sexp Moves the cursor forwards, out of the current list. ctrl+up
Backward Up Sexp Moves the cursor backwards, out of the current list. Unbound Forward Sexp Or Up Moves the cursor forward, to the end of the current form. If at the end, moves to the end of the next form. Moves out of the lists if at the end of it. Unbound Backward Sexp Or Up Moves the cursor backward, to the start of the current form. If at the start, moves to the start of the previous form. Moves out of the list if at the start of it. ctrl+end
Forward to List End/Close Moves the cursor forwards, staying within the current list. ctrl+home
Backward to List Start/Open Moves the cursor backwards, staying within the current list.","boost":7},{"location":"paredit/#selecting","title":"Selecting","text":"Most of these commands are selecting \u201dversions\u201d of the navigation commands above. Repeated use will grow the current selection step by step.
Default keybinding Action Descriptionshift+alt+right
(win/linux)ctrl+w
(mac) Expand Selection Starts from the cursor and selects the current form. Then will keep expanding to enclosing forms. shift+alt+left
(win/linux)ctrl+shift+w
(mac) Shrink Selection Contracts back from an expanded selection performed by any Paredit selection command. (In the animation the selection is first grown using a combination of Expand Selection and some lateral selection commands, then shrunk all the way back down to no selection.) ctrl+alt+w space
Select Top Level Form Top level in a structural sense. Typically where your(def ...)
/(defn ...)
type forms. Please note that(comment ...)
forms create a new top level. shift+ctrl+right
(win/linux)shift+alt+right
(mac) Select Forward Sexp ctrl+shift+k
Select Right Select forward to the end of the current form or the first newline. See Kill right below. (The animation also shows Shrink Selection). shift+ctrl+left
(win/linux)shift+alt+left
(mac) Select Backward Sexp ctrl+shift+down
Select Forward Down Sexp (You probably do not need to select like this, but you can!) ctrl+shift+alt+up
Select Backward Down Sexp (You probably do not need to select like this, but you can!) ctrl+shift+alt+down
Select Forward Up Sexp (You probably do not need to select like this, but you can!) ctrl+shift+up
Select Backward Up Sexp (You probably do not need to select like this, but you can!) Unbound Select Forward Sexp Or Up (You probably do not need to select like this, but you can!) Unbound Select Backward Sexp Or Up (You probably do not need to select like this, but you can!) ctrl+shift+end
Select Forward to List End/Close ctrl+shift+home
Select Backward to List Start/Open","boost":7},{"location":"paredit/#editing","title":"Editing","text":"Default keybinding Action Description ctrl+alt+right
(mac/win)ctrl+alt+.
(linux) Slurp Forward Moves the closing bracket forward, away from the cursor, past the following form, if any. ctrl+alt+left
(mac/win)ctrl+alt+,
(linux) Barf Forward Moves the closing bracket backward, towards the cursor, past the preceding form. ctrl+alt+shift+left
Slurp Backward Moves the opening bracket backward, away from the cursor, past the preceding form, if any. ctrl+alt+shift+right
Barf Backward Moves the opening bracket forward, towards the cursor, past the following form. ctrl+alt+s
Splice Sexp Remove enclosing brackets. ctrl+shift+s
Split Sexp Splits a string, or a list, into two strings, or lists of the same type as the current. ctrl+shift+j
Join Sexps/Forms Joins two strings, or two lists of the same type, into one form (string/list). ctrl+alt+p ctrl+alt+r
Raise Sexp Replaces the enclosing list with the current form. ctrl+alt+t
Transpose Sexps/Forms Swaps place of the two forms surrounding the cursor. alt+up
alt+down
Drag Sexp Backward/Forward Moves the current form to the behind/in front of the previous/next one. (See below about behavior in maps and binding boxes.) ctrl+alt+shift
u
ctrl+alt+shift
d
Drag Sexp Backward UpDrag Sexp Forward Down Moves the current form up/out of the current list, backwards, and down/in to the following list, forwards, keeping the cursor within the sexpr being dragged. ctrl+alt+shift
k
ctrl+alt+shift
j
Drag Sexp Forward UpDrag Sexp Backward Down Moves the current form up/out of the current list, forwards, and down/in to the preceding list, backwards, keeping the cursor within the sexpr being dragged. ctrl+shift+c
Convolute \u00af\\_(\u30c4)_/\u00af ctrl+shift+delete
Kill Sexp Forward Deletes the next form in the same enclosing form as the cursor. ctrl+k ctrl+k
(win/linux)ctrl+k
(mac) Kill Right Delete forward to the end of the current form or the first newline. ctrl+k ctrl+h
(win/linux)cmd+backspace
(mac) Kill Left Delete backward to the start of the current form or the start of the line. ctrl+alt+backspace
Kill Sexp Backward Deletes the previous form in the same enclosing form as the cursor. ctrl+delete
Kill List Forward Deletes everything from the cursor to the closing of the current enclosing form. ctrl+backspace
Kill List Backward Deletes everything from the cursor to the opening of the current enclosing form. ctrl+alt+shift+delete
Splice Killing Forward Delete forward to end of the list, then Splice. ctrl+alt+shift+backspace
Splice Killing Backwards Delete backward to the start of the list, then Splice. ctrl+alt+shift+p
Wrap Around () Wraps the current form, or selection, with parens. ctrl+alt+shift+s
Wrap Around [] Wraps the current form, or selection, with square brackets. ctrl+alt+shift+c
Wrap Around {} Wraps the current form, or selection, with curlies. ctrl+alt+shift+q
Wrap Around \"\" Wraps the current form, or selection, with double quotes. Inside strings it will quote the quotes. ctrl+alt+r
ctrl+alt+p
/s
/c
/q
/h
Rewrap Changes enclosing brackets of the current form to parens/square brackets/curlies/double quotes and set (#{}
) Copy to Clipboard when killing text
You can have the kill commands always copy the deleted code to the clipboard by setting calva.paredit.killAlsoCutsToClipboard
to true
. If you want to do this more on-demand, you can kill text by using the selection commands and then Cut once you have the selection.
clojure-lsp drag fwd/back overlap
As an experimental feature, the two commands for dragging forms forward and backward have clojure-lsp alternativs. See the clojure-lsp page.
","boost":7},{"location":"paredit/#drag-bindings-forwardbackward","title":"Drag bindings forward/backward","text":"When dragging forms inside maps and binding boxes, such as with let
, for
, binding
, etcetera, it often makes most sense to drag each binding as a pair. And this is what Calva will do. Like so:
And like so (wait for it):
","boost":7},{"location":"paredit/#about-the-keyboard-shortcuts","title":"About the Keyboard Shortcuts","text":"Care has been put in to making the default keybindings somewhat logical, easy to use, and work with most keyboard layouts. Slurp and barf forward are extra accessible to go with the recommendation to learn using these two super handy editing commands.
You can relax how Paredit's shortcuts replace VS Code built in shortcuts a bit by setting calva.paredit.hijackVSCodeDefaults
to false
.
There are some context keys you can utilize to configure keyboard shortcuts with precision. See Customizing Keyboard Shortcuts.
The Nuclear Option: You can choose to disable all default key bindings by configuring calva.paredit.defaultKeyMap
to none
. (Then you probably also want to register your own shortcuts for the commands you often use.)
In some instances built-in command defaults are the same as Paredit's defaults, and Paredit's functionality in a particular case is less than what the default is. This is true of Expand Selection and Shrink Selection for Windows/Linux when multiple lines are selected. In this particular case adding !editorHasMultipleSelections
to the when
clause of the binding makes for a better workflow. The point is that when the bindings overlap and default functionality is desired peaceful integration can be achieved with the right when
clause. This is left out of Paredit's defaults to respect user preference, and ease of maintenance.
Happy Editing! \u2764\ufe0f
","boost":7},{"location":"paredit/#experimental-feature-multicursor-support","title":"Experimental Feature: Multicursor support","text":"There is an ongoing effort to support simultaneous multicursor editing with Paredit. This is an experimental feature and is not enabled by default. To enable it, set calva.paredit.multicursor
to true
. This feature is still in development and may not work as expected in all cases. Currently, this supports the following categories:
Reverted in Calva v2.0.228
The changes in v2.0.227 seemed to cause problems for some users. Unclear yet if and why. But to not risk causing problems for more users these changes where reverted and Calva v2.0.228 does not contain them. Please consider using v2.0.227 and help find what the problems are about! Please note: Even in v2.0.227 this feature is currently disabled by default.
Parinfer is a system for editing the structure of LISP text without explicit commands. The structure can be regarded as already being expressed through indentation. With Parinfer you can use your intuition about the structure inferred from the indentation to perform surprisingly many structural edits.
"},{"location":"parinfer/#quirks","title":"Quirks","text":"There are some known quirks, of varying severity, with this feature. Some of them will need to be fixed before we move this feature out of Experimental status.
For the most times you can always Undo to get back to where the document was fine. You just need to pay some attention and be aware when undo is needed.
"},{"location":"parinfer/#no-multi-cursor-support","title":"No multi-cursor support","text":"The bracket inference will remove all cursors but the first one. So for instance if you edit with multiple cursors and it causes brackets to move, you'll end up with just one cursor and the subsequent edits will not be what you intended. This is particularly important to note when you have cursors that are not in the viewport. In such cases it might be better to turn Parinfer off while you do the edits, fix formatting and such manually and then switch Parinfer on again.
"},{"location":"parinfer/#wrong-inferences","title":"Wrong inferences","text":"For yet unknown reasons an edit such as the following does the wrong thing (the cursor indicated by the vertical bar):
(foo| (bar)\n(baz))\n
backspace =>
(fo| (bar\n(baz)))\n
That is (baz)
is slurped. When what should happen is:
(fo| (bar)\n(baz))\n
"},{"location":"parinfer/#lag-causing-errors-when-fast-typing","title":"Lag causing errors when fast typing","text":"The way that Calva Parinfer works is that for any edit of the document it first reformats the code around the cursor, then infer brackets. Currently these two steps are not atomic to VS Code, so if you type fast bracket inference might happen on the yet unformatted code, and thus not be correct. You might also see the cursor end up at the wrong position at times.
"},{"location":"parinfer/#infer-parens","title":"Infer Parens","text":"This is no longer available in Calva
See above about how to try this build anyway, warts and all.
When you enable Calva's Parinfer it is all about infering brackets from indentation. There are no further Parinfer modes. Calva's auto-formatter will take care of keeping the code correctly indented.
Enable it with from this setting: calva.fmt.experimental.inferParensAsYouType
or from the status bar item.
To the right on the status bar, right before the Paredit status bar item, you will have two items, Parinfer toggle ON/OFF and a health indicator.
When Parinfer is ON, the health indicator will have three states:
Parinfer will be disabled in both the unhealthy states.
When Parinfer is OFF, only the first two states above are used.
"},{"location":"parinfer/#some-vs-code-settings-automatically-changed","title":"Some VS Code Settings automatically changed","text":"In order for some automatic VS Code behaviour not to interfere with Parinfer the following settings are automatically configured when you toggle Parinfer ON:
\"[clojure]\": {\n\"editor.autoClosingBrackets\": \"never\",\n\"editor.autoClosingOvertype\": \"never\",\n\"editor.formatOnPaste\": false\n},\n
And when you toggle Parinfer OFF:
\"[clojure]\": {\n\"editor.autoClosingBrackets\": \"always\",\n\"editor.autoClosingOvertype\": \"always\",\n\"editor.formatOnPaste\": true\n},\n
It is recommended that you let Calva handle these settings to avoid weird behaviour.
"},{"location":"parinfer/#no-tab-indenting","title":"No Tab indenting","text":"As the tab
key is used for formatting the current form in Calva, it is \u201dtaken\u201d. The closest equivalents you have are space
and backspace
. At least for now. We'll see if we can find out a good way for supporting tab
and shift+tab
for indent and dedent.
tab
for formatting is of course just a default key binding and you can assign it to something else to get it to do indenting. However, it will not be a very smart indent anyway, there is no Clojure awareness about it. You are hereby adviced to instead use some more spaces.
In Calva, Parinfer and Paredit are designed to coexist and both be there to let you edit the structure easily and efficiently. Since Paredit commands are always formatted, they leave the code in a state where Parinfer has what it needs to infer bracket placement as you either edit the indentation, or remove/add brackets.
"},{"location":"parinfer/#disable-the-parinfer-extension","title":"Disable the Parinfer Extension","text":"If you want to have Parinfer you are probably best served by Calva's built-in version. It is designed, and will continue to be improved to function well together with Calva's other structural editing and formatting features. It will also probably conflict with the Parinfer Extension.
"},{"location":"parinfer/#see-also","title":"See also","text":"Polylith is an architecture for backend projects that maximizes development ergonomics and code reuse.
When developing a Polylith application you use one REPL for everything. And as such it is a rather vanilla deps.edn
project, so there is really not much more to using Calva with Polylith than:
deps.edn
project type:dev
and :test
To make it easy to try Polylith out with Calva, the Polylith RealWorld example implementation has some Calva config to get the server started and Calva connected to its REPL quickly:
Polylith RealWorld Server REPL
project typeclj\ua789dev.server\ua789>
(start! 6003)
A ClojureScript frontend, of course:
api-url
definition in events.cljs
file to be (def api-url \"http://localhost:6003/api\")\n
:app
buildIn Calva, pretty printing is a mode. Prettiness is on by default and all your evaluation results will get that treatment.
You can also pretty print code on demand
There is a command Replace Current Form (or Selection) with Pretty Printed Form. See Clojure Formmatting for more on this.
"},{"location":"pprint/#toggle-it","title":"Toggle it","text":"There is a pprint
indicator to the right in the status bar which shows the status of the mode. Click the indicator to toggle prettification on and off. There is also a Calva: Toggle Pretty Printing for All Evaluations command.
Tip: If you have evaluated something time consuming, or that is not idempotent, with pretty printing mistakenly off: toggle it on and evaluate *1
.
For most people the defaults will probably work, but Calva pretty printing comes a few knobs you can turn, and they are all available through the calva.prettyPrintingOptions
settings. Things you can set are:
enabled
boolean So this is a third way you can change this mode \ud83d\ude04 printEngine
enum Which printer function that will be used. Default is pprint
, more about this setting below printFn
object You can configure Calva to use a custom nREPL
compatible print
function, more below. width
number The maximum line length of printed output (or at least the printers will try) maxLength
number The maximum number of elements printed in nested nodes, good for evaluating something like (iterate inc 0)
, which you shouldn't do without setting maxLength
. Most printers will indicate truncated lists with ...
at the end. maxDepth
number The maximum number of levels deep that will get printed. Different printers mark a stop different ways. puget
doesn't support it at all. See Customizing Calva for some tips on adding settings like these.
Here's an example of how zprint
handles maxDepth
(from the Calva implementation of it's client side pretty printing.).
(pretty-print [[[[[[[[:deeper]]]]]]]] {:max-depth 4})\n;; => {:value \"[[[[##]]]]\"}\n
"},{"location":"pprint/#your-selection-of-prettifiers","title":"Your Selection of Prettifiers","text":"Pretty printing can happen on the server (i.e. in the JVM, via nREPL), or on the client (i.e. in node, via VS Code/Calva). Client side always uses zprint
. Server side you can choose from these printers:
calva
client The nREPL server will plain print the results, and then Calva will pretty it (using zprint
). pprint
server Current Calva default. clojure.core/pprint
is a bit basic, but it's tried and tested, and doesn't suffer from the issues with the other server side printing options, mentioned below. fipp
server puget
server Lacks maxDepth
option. zprint
server A very good option. However, it will need to be configured before Jack-in if you want Calva's help to inject its dependencies. (If you are not using Jack-in, you'll need to supply this dependency yourself.) These particular server side functions were chosen because they have pre-configured print-functions in cider-nrepl
.
printFn
","text":"If the selection of built-in printEngine
support doesn't cut it, you can configure a custom function. This function will need to conform to the requirements of nREPL print functions. The VS Code settings editor will help you configure this one. (This is also a bit experimental, please consider giving feedback about how it works for you if you try it.)
This matters because on the server all pretty printers, except pprint
does more than just pretty print the result that would be printed with plain printing. Pretty printing results on the server causes some results to get expanded. This can have huge implications depending on the results and which printer is used. E.g. for Datomic transaction results, you will get the whole database printed. Twice. Depending on the database, you could be so unlucky that nothing gets printed, and instead you will soon have a very hot computer.
Note: With the help of zprint creator, Kim Kinnear, we have found ways to compensate for this problem. Ways that are not yet implemented, but please stay tuned.
Then why not always do it client side? It turns out that on the client side there are also things going on. Calva gets the results back as a string and therefore it needs to first be parsed back to EDN, before it can be pretty printed by zprint
. And \u2013 here's the catch \u2013 all results are not valid EDN and therefore can't be pretty printed by zprint
. Datomic transaction results are one example.
The current options are limited, because our time developing Calva is limited. But cider-nrepl
really allows for fully configurable pretty printing, so it is within reach. Please feel invited to give us feedback on what you would want to configure for the printing of results. File issues and/or chat us up in #calva in the Clojurians slack.
If pprint is not working, try a different pprint engine or use Calva's jack-in to make sure the necessary dependencies are loaded in your REPL. If you are starting your REPL without jack-in and want to continue doing so, you can use the command Copy Jack-in Command Line to Clipboard
then paste the command somewhere to see what dependencies it injects. You can then add these dependencies to your REPL in whatever way suits your needs.
Enjoy Prettiful Printing! \u2764\ufe0f
"},{"location":"quirks/","title":"Quirks","text":"Here's a shocker for ya': Calva isn't perfect. \ud83d\ude04
There are quirks and things that flat out do not work. We'll try to collect info about such things here, providing workarounds when available (or, rather, known to us).
"},{"location":"quirks/#test-features-not-available-with-clojurescript","title":"Test features not available with ClojureScript","text":"Currently cider-nrepl
does not provide its test functionality for ClojureScript code. Please consider contributing to fixing that.
See Using with Parinfer
"},{"location":"quirks/#calva-and-the-vim-extension","title":"Calva and the VIM Extension","text":"See Using Calva with the VIM Extension.
"},{"location":"quirks/#command-not-found-errors-on-jack-in","title":"\u201dCommand not found\u201d Errors on Jack-in","text":"Jack-in starts by running a command in a new terminal. You will need the commands used installed on your computer:
clojure
for tools.deps/deps.ednlein
for Leiningennpx
for shadow-cljsgradlew
for Gradle (in your project)Also, in some circumstances VS Code is not spawned from a shell with the environment variables, especially $PATH
, which might mean that even though you have the tools installed, they are not found when VS Code/Calva tries to execute them. To fix this you will need to do one of these two things:
$PATH
there includes the directory with the needed binary.$PATH
is correctly configured. (Using the code
command.)See this issue for more clues on this problem.
"},{"location":"quirks/#strange-linting-errors","title":"Strange linting errors?","text":"This is not really a quirk, and most linting errors are not strange when you learn about why they are there. Calva does not do any linting, btw, see also linting.
"},{"location":"quirks/#consider-uninstalling-these-extensions","title":"Consider uninstalling these extensions","text":"Without Calva, many users install other nifty extensions (some of which are old pieces of Calva) that help with this or that problem. It might sometimes work together with Calva, sometimes not. Here's a list of some common extensions you should consider to at least disable:
The re-frame template creates a shadow-cljs
project, making it easy to use with Calva.
npm install
ctrl+alt+c ctrl+alt+j
.shadow-cljs
project and ask for which build to compile.:app
.:app
is the only configured build, but the VS Code menu for this is a bit strange so make sure the :app
checkbox is really ticked before proceeding.:app
.Ctrl+C
in this pane will kill your app and free up all resources it has allocated.views.cljs
file from src/<your-project-name>
and issue Calva: Load/Evaluate Current File and its Requires/Dependencies. ctrl+alt+c enter
.(js/alert \"Hello from Calva\")
(alt+enter
and ctrl+enter
are your friends).REBL is a graphical, interactive tool for browsing Clojure data.
"},{"location":"rebl/#depsedn","title":"deps.edn","text":"Add the following aliases to your deps.edn file. Use the deps.edn file in the ~/.clojure
directory to enable alias reuse across multiple projects. This is the configuration for REBL on openjdk 12. Check out the REBL github page for more info.
;; REBL Base\n:rebl\n{:extra-deps {org.clojure/core.async {:mvn/version \"0.4.490\"}\n;; deps for file datafication (0.9.149 or later)\norg.clojure/data.csv {:mvn/version \"0.1.4\"}\norg.clojure/data.json {:mvn/version \"0.2.3\"}\norg.yaml/snakeyaml {:mvn/version \"1.23\"}\ncom.cognitect/rebl\n;; adjust to match your install location\n{:local/root \"/Users/ozimos/REBL/latest/REBL.jar\"}}}\n\n;; REBL 12\n:rebl-12\n{:extra-deps {org.openjfx/javafx-fxml {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-controls {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-graphics {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-media {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-swing {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-base {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-web {:mvn/version \"12.0.1\"}}}\n\n;; nREBL\n:nrebl {:extra-deps {rickmoynihan/nrebl.middleware {:mvn/version \"0.2.0\"}}\n:main-opts [\"-e\" \"((requiring-resolve,'cognitect.rebl/ui))\" \"-m\" \"nrepl.cmdline\" \"--middleware\" \"[nrebl.middleware/wrap-nrebl]\" \"-I\"]}\n
Create a Calva custom connect sequence for your VSCode editor. (Read Custom REPL Connect Sequences if you haven't.) Add the following to your vscode settings.json:
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Rebl Connect\",\n\"projectType\": \"deps.edn\",\n\"menuSelections\": {\n\"cljAliases\": [\n\"rebl\",\n\"rebl-12\",\n\"nrebl\"\n]\n}\n}\n]\n}\n
"},{"location":"rebl/#leiningen","title":"Leiningen","text":"Add rebl profiles to your user-wide profiles so that they will be available for all your projects. Here's a sample user profile (located at ~/.lein/profiles.clj
on mac):
{:user {:plugins [[lein-ancient \"0.6.15\"]]}\n\n;; REBL Base\n:rebl {:resource-paths [\"/Users/ozimos/REBL/latest/REBL.jar\"]\n:dependencies [[org.clojure/core.async \"0.4.490\"]\n[org.clojure/data.csv \"0.1.4\"]\n[org.clojure/data.json \"0.2.3\"]\n[cljfmt \"0.6.4\"]\n[org.yaml/snakeyaml \"1.23\"]]}\n\n;; REBL 12 for JDK 12.0.1. Swap out for your JDK version\n:rebl-12 {:dependencies [[org.openjfx/javafx-fxml \"12.0.1\"]\n[org.openjfx/javafx-controls \"12.0.1\"]\n[org.openjfx/javafx-graphics \"12.0.1\"]\n[org.openjfx/javafx-media \"12.0.1\"]\n[org.openjfx/javafx-swing \"12.0.1\"]\n[org.openjfx/javafx-base \"12.0.1\"]\n[org.openjfx/javafx-web \"12.0.1\"]]}\n\n;; NREBL https://github.com/RickMoynihan/nrebl.middleware\n:nrebl {:repl-options {:nrepl-middleware [nrebl.middleware/wrap-nrebl]}\n:dependencies [[rickmoynihan/nrebl.middleware \"0.3.1\"]]}}\n
More info here Create a Calva custom connect sequence for your VSCode editor. (Read Custom REPL Connect Sequences if you haven't.) Add the following to your vscode settings.json:
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Lein REBL\",\n\"projectType\": \"Leiningen\",\n\"menuSelections\": {\n\"leinProfiles\": [\"rebl\", \"rebl-12\", \":nrebl\"]\n},\n\"afterCLJReplJackInCode\": \"((requiring-resolve 'cognitect.rebl/ui))\"\n}\n]\n}\n
"},{"location":"rebl/#shadow-cljs-tbd","title":"shadow-cljs (TBD)","text":"TBD. If you know how to do it, please update this page.
"},{"location":"refactoring/","title":"Refactoring","text":"There are two \u201dflavours\u201d to refactoring support. Some (just a few) refactorings are made available as Quick Fix suggestions (the light bulb), the rest are regular commands in the clojure-lsp Refactoring category.
You can enable or disable the Quick Fix suggestion lightbulb using the VS Code setting editor.lightbulb.enabled
.
The refactoring commands do not have default keyboard shortcuts. You find them all by typing \u201dclojure-lsp Refactor\u201d in the Command Palette.
"},{"location":"refactoring/#commands","title":"Commands","text":"Command Title Command Key Description Clean NS FormclojureLsp.refactor.cleanNs
Add Missing Require clojureLsp.refactor.addMissingLibspec
Extract to New Function clojureLsp.refactor.extractFunction
Cycle/Toggle Privacy clojureLsp.refactor.cyclePrivacy
Inline Symbol clojureLsp.refactor.inlineSymbol
Introduce let clojureLsp.refactor.introduceLet
Creates a new let box with the binding. Follow up with \u201dExpand let\u201d to move it upwards. Expand Let clojureLsp.refactor.expandLet
Move to Previous let Box clojureLsp.refactor.moveToLet
Thread First clojureLsp.refactor.threadFirst
Thread First All clojureLsp.refactor.threadFirstAll
Thread Last clojureLsp.refactor.threadLast
Thread Last All clojureLsp.refactor.threadLastAll
Unwind All clojureLsp.refactor.unwindAll
Unwind Thread clojureLsp.refactor.unwindThread
Formatting
The way that some of the refactorings are applied to the document, makes it difficult for Calva to format the results. So, sometimes you'll need to navigate the cursor to the enclosing form and hit tab
to tidy up the formatting after a refactoring. See also Formatting.
Most of Calva's refactoring support is sourced directly from clojure-lsp. This also means that most often, if you find issues with refactoring, or have suggestions about it, the clojure-lsp repo is where to direct your reporting.
"},{"location":"remote-development/","title":"Using Calva with Remote Development","text":"VS Code Remote Development is a new feature in version 1.35 of VS Code that allows a developer to use a container, remote machine, or the Windows Subsystem for Linux (WSL) as a full-featured development environment.
I would recommend reading the introductory blog post and watching the videos. I find the feature extremely exciting and wish more IDEs would implement something like it.
From a Clojure perspective it allows you to have VS Code installed on your Java-less, Clojure-less hardware and still use it to develop Clojure through it.
"},{"location":"remote-development/#a-use-case","title":"A use-case","text":"Run Remote-Containers: Add Development Container Configuration Files... and pick a suitable Java base image. Then:
"},{"location":"remote-development/#modify-dockerfile-to-install-clojure-cli-and-optionally-lein","title":"Modify Dockerfile to install Clojure CLI (and optionally lein)","text":"Add:
# ...\n\n# Install Clojure - see https://github.com/Quantisan/docker-clojure/blob/master/target/openjdk-14-slim-buster/tools-deps/Dockerfile\nENV CLOJURE_VERSION=1.10.1.619\nWORKDIR /tmp\nRUN \\\napt-get update && \\\napt-get install -y curl make rlwrap wget && \\\nrm -rf /var/lib/apt/lists/* && \\\nwget https://download.clojure.org/install/linux-install-$CLOJURE_VERSION.sh && \\\nsha256sum linux-install-$CLOJURE_VERSION.sh && \\\necho \"28b1652686426cdf856f83551b8ca01ff949b03bc9a533d270204d6511a8ca9d *linux-install-$CLOJURE_VERSION.sh\" | sha256sum -c - && \\\nchmod +x linux-install-$CLOJURE_VERSION.sh && \\\n./linux-install-$CLOJURE_VERSION.sh\nRUN \\\nsu vscode -c \"clojure -e '(clojure-version)'\" && \\\nrm ./linux-install-$CLOJURE_VERSION.sh\n\n# Install Lein\nRUN \\\nwget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein -O /bin/lein && \\\nchmod uog+x /bin/lein\nRUN su vscode -c \"/bin/lein\"\n\n# Cleanup\nRUN apt-get purge -y --auto-remove curl wget\n\n# ...\n
"},{"location":"remote-development/#modify-devcontainerjson","title":"Modify devcontainer.json","text":"Add Calva and, optionally, forward some ports to the host::
\"extensions\": [\"betterthantomorrow.calva\"],\n\"forwardPorts\": [8088, 52162], // example: your webapp, your nREPL\n
"},{"location":"remote-development/#build-and-start","title":"Build and start","text":"Run Remote-Containers: Rebuild and Reopen in container
"},{"location":"remote-development/#wsl","title":"WSL","text":"See Using Calva with WSL
"},{"location":"repl-window/","title":"The REPL Window/File","text":"The Calva REPL Window is actually a regular file with some extra treatment from Calva, like displaying a prompt, offering evaluation history recall and generally \u201cfollowing\u201d the current namespace. This file is created and opened when Calva is connected to a REPL. You can use it for experimental code (though there are also Rich Comments and Fiddle Files for this).
In ClojureScript projects, the window will be associated with the cljs
REPL once it is connected. It will then look something like this:
The first prompt is from when the clj
REPL is connected, and the second from cljs
. The first part of the prompt tells you which REPL type the window is currently connected to.
By default the REPL Window doubles as the place where Calva sends output like stdout/stderr and other messages. See Calva Output for more about this and how to change this behaviour.
"},{"location":"repl-window/#finding-the-repl-window","title":"Finding the REPL Window","text":"If you quickly want to open and/or switch to the REPL Window there is the command Calva: Show/Open REPL Window, ctrl+alt+o r
.
To sync the REPL window namespace with the current file before switching, use the Switch Namespace of the REPL Window to Current Namespace command, ctrl+alt+c alt+n
.
When you are editing things in the REPL window, and want to open the file that defines its current namespace, use the Show File for the Current REPL Window Namespace command, ctrl+alt+o r
.
Note
This also works for Clojure core and library namespaces.
"},{"location":"repl-window/#evaluating-code","title":"Evaluating Code","text":"The window will be automatically associated with the REPL and the namespace of any project Clojure/ClojureScript file you evaluate code in. So for instance if you evaluate this code in a clj
file with the namespace fresh-reagent.handler
:
(def mount-target\n[:div#app\n[:h2 \"Welcome to fresh-reagent\"]\n[:p \"please wait while Figwheel is waking up ...\"]\n[:p \"(Check the js console for hints if nothing exciting happens.)\"]])\n
If the REPL Window is the configured destination for evaluation results, the defined var will be printed there. Otherwise, it will be printed to the destination you've configured. In either case, the REPL window will print a new prompt reflecting the current REPL connection and namespace:
If you then switch to the output window (ctrl+alt+o r
), and enter this at the prompt:
mount-target\n
then evaluate it using alt+enter
, you'll get this:
... because the namespace \u201dfollowed\u201d the first evaluation in the REPL window.
"},{"location":"repl-window/#repl-history","title":"REPL History","text":"Recently evaluated forms in the REPL file are persisted and can easily be shown again for modifying and re-evaluating.
"},{"location":"repl-window/#navigate-repl-history","title":"Navigate REPL History","text":"You can navigate up and down the history of evaluated forms in the REPL file by pressing alt+up
and alt+down
, provided your cursor is at the end of the last form after the prompt. If the cursor is not at the end of the last form, then alt+up
and alt+down
will do whatever they are mapped to, which is by default \"Move Line Up\" and \"Move Line Down,\" respectively.
If you have typed some text after the prompt before you start traversing up the history, this text will be preserved and will display when you traverse back down the history. If you modify some text in the history while traversing, the modification will be saved at that location in history.
"},{"location":"repl-window/#clear-repl-history","title":"Clear REPL History","text":"You can clear the repl history by running the command \"Clear REPL History\" from the command palette.
"},{"location":"repl-window/#stack-traces","title":"Stack Traces","text":"When an evaluation produces an error, it will automatically be printed in the REPL Window. If there is a stack trace associated with the error, it can now be printed on demand using the Calva: Print Last Stacktrace to the Output Window command. You can also print the stack trace for any error message printed to the REPL Window via the Codelens button below it.
For printed stacktraces, when source locations are available (Clojure files), you will be able to navigate to them by pressing ctrl+click
(cmd+click
on Mac) on the file name. You can also hover over symbols in the stack trace to see the symbol's documentation, and ctrl+click
(cmd+click
on Mac) the symbol to Peek Definition.
Output destinations
If you have configured some other destination for stderr output, the error message will be printed there as well. But it will also be printed to the REPL Window, because the augmented stack traces need this (because reasons).
"},{"location":"repl-window/#load-current-namespace","title":"Load Current Namespace","text":"When navigating namespaces it is easy to forget to first require them and that can be tricky to debug. To help with this, Calva's command Load/Evaluate Current File and its Requires/Dependencies also works in the REPL Window, but there, it acts like Load Current Namespace.
Suppose you have two files, pez/xxx.clj
and pez/yyy.clj
, where pez.yyy
requires pez.xxx
.
(ns pez.xxx)\n\n(def a :xxx-a)\n\n(def b :xxx-b)\n
(ns pez.yyy\n(:require [pez.xxx]))\n\n(def a :yyy-a)\n\n(println \"Hello\" pez.xxx/a)\n
Then, with a freshly jacked-in REPL, you evaluate (ns pez.yyy)
and want to work with the vars defined there, Clojure will complain. But if you Load/Evaluate Current File and its Requires/Dependencies, it will start working. Something like so:
Note
This currently suffers from a limitation in Calva where it won't reload dependencies, so you will sometimes have to do this \u201dmanually\u201d anyways (by opening the files and loading them yourself). See Calva issue #907
"},{"location":"repl-window/#peek-current-namespace","title":"Peek Current Namespace","text":"A somewhat hidden feature: You can peek, see documentation for, and navigate to a namespace by hovering on the namespace symbol in one of the REPL Window prompts (just like you would if it was not in the prompt \ud83d\ude04).
"},{"location":"repl-window/#paredit-enabled","title":"Paredit Enabled","text":"The REPL Window is mostly a regular Calva Clojure/ClojureScript file, which makes everything that works in a regular file work in this file, including Paredit. This makes it easy to navigate the input and output there. For instance, to select the last evaluation results, you can press ctrl+w
(shift+alt+right
on Windows and Linux):
The output window is mostly a regular... (you get it), which means you also have the Calva debugger at your command at the REPL prompt (only for clj
sessions, for now). So instead of evaluating a function definition using alt+enter
, you can evaluate it and instrument it for debugging using ctrl+alt+c i
, and then call the function.
The contents of the output/REPL window is written to a file named output.repl
in the .calva/output-window
directory of your project. The file is recreated every new session, so you should copy or save anything you want to preserve between sessions.
You probably want to add .calva/output-window/
to your .<something>ignore
files. (There are some more files in that directory that you shouldn't keep under source control.)
In full-stack projects, you will probably use the window as a REPL for both clj
and cljs
. You can toggle which REPL the window is connected to by using the command Calva: Toggle REPL Connection for CLJC files. There is also a button for this in the status bar:
Due to limitations in the VS Code API it is hard for Calva to know if the REPL file is open, and if it was opened more than once. Therefore, we suggest you make it a habit to leave this window open, or even pinned. And if it is open in several tabs, expect evaluation printouts to be a bit unpredictable.
If you save the REPL file (which most often does not make much sense, but anyway) you will sometimes be presented with a message about VS Code being confused about the file contents being out of sync. Just choose to Overwrite the currently saved version and you should be fine.
"},{"location":"reveal/","title":"How to use Calva and Reveal together","text":"Reveal is a \"Read Eval Visualize Loop for Clojure\". This page describes how to use Reveal in your development setup based on Calva.
Note
See https://vlaaad.github.io/reveal for the latest version and use that wherever this page says <version>
.
You can go for the nrepl middleware or just add the dependency.
Please see the Calva test-data project minimal-reveal for an example.
"},{"location":"reveal/#middleware","title":"Middleware","text":"This will make Reveal to start together with your project.
Note
This will make all Calva evaluations go to Reveal. Too chatty for you? Take the dependencies only approach.
Add this alias deps.edn
:
:aliases\n{:reveal-nrepl-middleware\n{:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}\n:main-opts [\"-m\" \"nrepl.cmdline\"\n\"--middleware\" \"[vlaaad.reveal.nrepl/middleware,cider.nrepl/cider-middleware]\"]}}\n
And then jack-in choosing the deps.edn option and then pick the :reveal-nrepl-middleware
alias.
If you don't want to use the nrepl-middleware you can configure just the dependency and then start Reveal yourself.
The alias:
:reveal-dep-only\n{:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}}\n
A custom REPL command for starting Reveal in your project:
\"calva.customREPLCommandSnippets\": [\n...\n{\n\"name\": \"Start Reveal Tapper\",\n\"snippet\": \"(require '[vlaaad.reveal :as reveal])(add-tap (reveal/ui))\",\n\"key\": \"sr\"\n},\n...\n]\n
See Custom REPL Command for how to configure more commands, and bind shortcuts to them, to make Reveal integration nice for you.
"},{"location":"reveal/#when-using-leiningen","title":"When using Leiningen","text":"In your project.clj
, add a profile named \"reveal\":
:profiles {:reveal {:dependencies [[vlaaad/reveal \"<version>\"]]\n:repl-options {:nrepl-middleware [vlaaad.reveal.nrepl/middleware]}}}\n
Now when you jack-in using Calva, you enable this profile and Reveal will be started automatically. Please note that Reveal requires Java 8 or higher, and uses JavaFX. Depending on your setup, you may need to make sure it is available.
"},{"location":"reveal/#tips-about-font-size","title":"Tips about font size","text":"If you find the font to small you can add a :jvm-opts
key to make it a little bigger:
:aliases\n{:reveal\n{:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}\n:jvm-opts [\"-Dvlaaad.reveal.prefs={:font-size,17}\"]\n:main-opts [\"-m\" \"nrepl.cmdline\"\n\"--middleware\" \"[vlaaad.reveal.nrepl/middleware,cider.nrepl/cider-middleware]\"]}}\n
"},{"location":"reveal/#using-java-11","title":"Using Java > 11?","text":"Reveal needs some reflective access to internal classes that has since Java 11 been restricted. You can relax this and get things working via JVM options. Tuck this into your reveal alias:
:jvm-opts [\"--add-opens\" \"javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED\"]\n
(If you are using the font size tips, just add the options into the :jvm-opts
vector.)
See https://github.com/vlaaad/reveal/issues/1 for some more context around this issue.
"},{"location":"rich-comments/","title":"Rich Comments Support","text":"Why bother with Rich comments? Read on. Consider watching this Youtube video for a demo of the workflow using the (in?)famous FizzBuzz problem as an example.
","boost":5},{"location":"rich-comments/#things-in-comment-are-not-evaluated","title":"Things incomment
are not evaluated","text":"The Clojure comment
macro is defined like so:
(defmacro comment\n\"Ignores body, yields nil\"\n{:added \"1.0\"}\n[& body])\n
It has no forms in its body and will therefore always (as long as the Clojure Reader can read it) evaluate to nil
. That is: nothing in the (comment ...)
form will get evaluated when the file is loaded.
This makes it a very good \u201dplace\u201d where you can develop code, experiment with code, and keep example code. Since you will be able to load/evaluate the current file without worrying that the code in the comment
form will get evaluated. This also holds true when using tools that hot-reload the code on save, such as Figwheel, shadow-cljs and Krell.
To develop or refine a function you might:
(comment ...)
formcomment
form, type some code to test your function and evaluate thatcomment
formcomment
form to keep some of the test code as example use, or \u201ddesign decision log\u201d for the function.Note
Using (comment ...)
forms for developing code is very common among Clojure coders. Rich Hickey is known for using it, which is why they are called Rich comments to begin with (even if it also is a very rich experience).
Calva has several features to facilitate the Rich comments workflow, e.g.
(rcf
, will make it appear.comment
forms are rendered in italicsNote that the command and snippet for creating Rich comments add the keyword :rcf
right before the closing paren. This makes the closing paren stay and not fold when you format the code. The special formatting (see below) will treat this and also any ignored (with #_
) form at the end of the form specially.
comment
is top-level","text":"To make it easy to evaluate forms in (comment ...)
forms, they create a new top-level context. Instead of you having to place the cursor with precision before evaluating the current form, you can have the cursor anywhere within a comment
enclosed form and Evaluate Top-Level Form.
This carries over to all commands in Calva which deal with the top level form. Including custom command snippets.
","boost":5},{"location":"rich-comments/#special-formatting","title":"Special formatting","text":"To invite a Rich comments workflow, the Calva command Format Current Form will not fold the closing bracket of the (comment ...)
form. Instead it will place this bracket on a line of its own (or keep it there).
(comment\n)\n
With the cursor somewhere directly inside the comment form (denoted with a |
):
(comment\n(def foo\n:foo)|)\n
tab
(comment\n(def foo\n:foo)\n|)\n
!!! Note \"Only for the current comment form\u201d The special formatting only applies in the current comment
form. When outside it, formatting tucks the closing paren in again. That's why fold when done, below works like it does. This also applies to VS Code commands like Format Document, or when you have Format On Save enabled. There are several reasons for this, and one is that there is no cljfmt
config for it and leaving the closing comment un-tucked might give you troubles with CI pipelines that enforce some cljfmt config be followed. (Another reason is that it would be pretty hard to do on the whole document.)
:rcf
","text":"If the Rich comment ends with :rcf
(or an ignored form), the special formatting doesn't happen. So if you have:
(comment\n(def foo\n:foo)\n|\n:rcf)\n
And hit tab, you will get:
(comment\n(def foo\n:foo)\n|\n:rcf)\n
","boost":5},{"location":"rich-comments/#thinking-space-is-kept","title":"Thinking space is kept","text":"The formatter will not remove newlines between the cursor and the closing bracket. So if you have entered a few lines to get \u201dthinking\u201d room:
(comment\n(def foo\n:foo)\n\n|\n\n)\n
tab
(comment\n(def foo\n:foo)\n\n|\n\n)\n
","boost":5},{"location":"rich-comments/#fold-when-done","title":"Fold when done","text":"To fold the trailing paren automatically, place the cursor immediately outside (before or after) the form:
(comment\n(def foo\n:foo))|\n
tab
(comment\n(def foo\n:foo))|\n
","boost":5},{"location":"rich-comments/#enabled-by-default","title":"Enabled by default","text":"You can disable this behavior with the setting: calva.fmt.keepCommentTrailParenOnOwnLine
.
Note
This treatment only applies to formatting of the current form. With fold when done as an exception.
","boost":5},{"location":"shadow-cljs/","title":"shadow-cljs","text":"Calva supports most any JVM hosted ClojureScript environment (and some others, including SCI based, too), but shadow-cljs gets some special treatment to try make it extra convenient to use.
With many shadow-cljs projects, Calva's connect project type shadow-cljs, is the right choice. Projects that use Leiningen or deps.edn can be used both with the Leiningen/deps.edn and shadow-cljs type, depending on configuration see below for more on this.
","boost":7},{"location":"shadow-cljs/#shadow-cljs-browser-quickstart","title":"shadow-cljs - browser quickstart","text":"Here's how you start a shadow-cljs ClojureScript REPL and connect Calva with the shadow-cljs - browser quickstart example project:
Prep:
npm install
Connect Calva:
Now you can should be able to evaluate forms, e.g.:
(See Code Evaluation)
","boost":7},{"location":"shadow-cljs/#shadow-cljs-in-full-stack-projects","title":"shadow-cljs in full stack projects","text":"shadow-cljs is a bit special in regards to Calva REPL connection. Mainly because you can start shadow-cljs and it's nREPL server in two ways:
These options show up as project types when connecting or jacking in:
The technical difference here is wether you let shadow-cljs start clojure/Leiningen (the first option) or if you let Calva do it (the second option). If you let Calva do it, Calva will then start the shadow-cljs watcher from the Clojure process. From a usage perspective the two approaches will result in different channeling of shadow-cljs output, e.g. test runner results. With the first option (the shadow-cljs project type), shadow-cljs output will be channeled to the Jack-in terminal. With the deps.edn/Leiningen option, that output will be channeled to the Output/REPL window.
See shadow-cljs + Clojure with Calva: The basics for some more discussion on how the REPL connection works.
shadow-cljs and clojure
aliases
The shadow-cljs project type will not prompt you for any aliases found in the deps.edn
file. Usually you should provide such aliases in shadow-cljs.edn
like :deps {:aliases [...]}
. If, for whatever reason you can't provide the aliases that way, you can configure a Custom REPL Connect Sequence and provide the aliases as menuSelections
-> cljAliases
.
Leiningen + shadow-cljs middleware issue
Please note that for Leiningen, the command line dependency injection of the shadow-cljs nrepl middleware doesn't work. You need to add it to your project.clj
:
:repl-options {:nrepl-middleware [shadow.cljs.devtools.server.nrepl/middleware]}\n
","boost":7},{"location":"shadow-cljs/#see-also","title":"See also:","text":"Calva is open source and free to use. It is actively maintained during our free time, and it keeps improving. You can contribute in many different ways, one of which is sponsoring. You can sponsor Calva by directly sponsoring any of us.
If you are working at a company which benefits from Calva's existence and continued development, please consider sponsoring at the Calva Gold Sponsor tier.
Please see this statement from Cognitect about the importance of supporting open source developers.
","boost":7},{"location":"sponsors/#patrons","title":"Patrons","text":"The right kind of different","boost":7},{"location":"sponsors/#gold-sponsors","title":"Gold Sponsors","text":"Scale your growth on mobile MAKE. DO. SHIP.","boost":7},{"location":"sponsors/#silver-sponsors","title":"Silver Sponsors","text":"","boost":7},{"location":"sponsors/#clojurists-together","title":"Clojurists Together","text":"Significant additions to Calva have been made possible by funding from Clojurists Together. And this has often been transformational for the whole project. Calva would not be where it is today without Clojurists Together.
","boost":7},{"location":"sponsors/#our-sponsoring-profiles","title":"Our Sponsoring Profiles","text":"These are the sponsoring profiles for the active maintainers of Calva (a.k.a. The Calva Team).
There is also a sponsors section in the README of the Calva project (which means it is also displayed in the VS Code Extension Marketlace).
","boost":7},{"location":"syntax-highlighting/","title":"Calva Highlight","text":"Calva takes care of syntax highlighting, and also provides some features not available through VS Code's highlighting mechanism. These extras include rainbow parens, sane bracket matching, and comment form dimming/highlighting.
"},{"location":"syntax-highlighting/#syntax-highlighting","title":"Syntax Highlighting","text":"When using Calva, you are also using its TMLanguage grammar (the core mechanism VS Code uses for syntax highlighting).
Our grammar tokenizes Clojure keywords as constant.keyword.clojure
. Since it is pretty uncommon with keyword constants in the programming languages out there, your theme might not have a highlight defined for this scope. Try find a grammar that highlights keywords! If you are very fond of some theme lacking this, you can help it with a setting:
\"editor.tokenColorCustomizations\": {\n \"[Default Dark+]\": {\n \"textMateRules\": [\n {\n \"scope\": [\n \"constant.keyword.clojure\"\n ],\n \"settings\": {\n \"foreground\": \"#6fbfff\"\n }\n }\n ]\n }\n},\n
Instead of Default Dark+
you should use your theme's name/key. And choose a color you like, of course.
You are in charge of how brackets and comments are highlighted via the calva.highlight.<setting>
settings:
enableBracketColors
Enable rainbow colors true
rainbowIndentGuides
Enable rainbow indent guides true
highlightActiveIndent
Highlight the active indent guide true
bracketColors
Which colors to use [\"#000\", \"#999\"]
cycleBracketColors
Whether same colors should be reused for deeply nested brackets true
misplacedBracketStyle
Style of misplaced bracket { \"border\": \"2px solid #c33\" }
matchedBracketStyle
Style of bracket pair highlight {\"backgroundColor\": \"#E0E0E0\"}
ignoredFormStyle
Style of #_...
form {\"textDecoration\": \"none; opacity: 0.5\"}
commentFormStyle
Style of (comment ...)
form {\"fontStyle\": \"italic\"}
Calva disables the VS Code built-in indent guides
The VS Code built-in settings editor.renderIndentGuides
and editor.highlightActiveIndent
do not have any effect, since the former is switched off by the Clojure Defaults, mentioned above. Use Calva Highlight's rainbowIndentGuides
and highlightActiveIndent
instead. They are different from the built in ones in that they are independent, meaning you can choose to have active indent highlighted while the guides generally are not rendered (this is the default, even).
VS Code bracket coloring vs Calva's
Calva's bracket coloring is more Clojure aware than VS Code's built-in coloring. And also will chime better with Calva's indent guides. If you like to have bracket coloring outside Clojure code, by all means enable it. Calva's bracket coloring will \u201dover paint\u201d in Clojure files, when enabled. These settings work nicely:
\"calva.highlight.highlightActiveIndent\": true,\n\"editor.bracketPairColorization.enabled\": true,\n
The calva.highlight.bracketColors
setting can be used to harmonize the coloring between VS Code and Calva.
Calva, the spirit, gains much of its taste and color from the Cider it is distilled from, and the oak it is matured in. I started to wonder what it is that shapes Calva, the VS Code Clojure Extension. I should know, being the master distiller, right?. Indeed. Poking some at the question, I do find that I have some answers.
Please read the following to learn what Calva is, and, to some extent, is not, about. Read it to get an idea about which path Calva is following, where we are headed with the project, and how you can contribute to the journey.
"},{"location":"tao/#why-calva","title":"Why Calva?","text":"Calva's raison d\u00b4\u00eatre is to provide Visual Studio Code users with an easy to use and productive environment for Clojure and ClojureScript development. See the Why Calva? page for some evidence that we are succeeding.
While Calva draws a lot of inspiration from CIDER, Cursive, Fireplace, and other Clojure development environments, it does not try to compete with them. Reading r/Clojure and elsewhere, it is easy to get the impression that the most common question is \"Which editor should I use for Clojure development?\u201d. I think a much more common question is \u201dHow do I use my favorite editor for Clojure development?\u201d. For VS Code users, that is where Calva should be a good choice.
I also have an ambition to leverage VS Code for easing the path to Clojure. Given that it is the favorite editor for so many developers, it is important to have a good development environment in place on this platform, and to make it as easy to use as we possibly can, while also being productive and something that you want to stick with, once you are hooked on Clojure.
That said, and therefore: For people who want to start out with Clojure, and do ask about what development environment would make it the most enjoyable, I'd like for Calva to be a really good option, an option so good that Clojurians feel they can recommend it.
"},{"location":"tao/#design-goals","title":"Design Goals","text":"Calva should be easy to start with and productive enough to stick with. It should support Clojure Best Practices, and be pleasant and enjoyable to use. It should also be easy to hack on, and to contribute to. The ClojureScript story keeps getting more important. Calva should contribute to making the development experience with ClojureScript delightful.
"},{"location":"tao/#easy-to-start-with","title":"Easy to Start With","text":"There are reasons as to why VS Code is so popular. Among those, one stands out to me: It is the most approachable code editor out there. There is nothing you need to learn when you start using it. The editor makes it obvious that you can start typing, deleting, cutting, pasting and undoing, without having to figure anything out. Then you learn how to bring up the command palette and get a boost few other environments can provide with such immediacy.
A language extension for VS Code can leverage this, by recognizing that what's old is old, and that what's new should be as easy as possible to pick up. Coming to a new language, people bring with them a lot of expectations from the languages they are used to. This is also true for the editor support. Syntax highlighting and formatting should just work, as should documentation lookup, linting and other IDE commodities.
Clojure brings some new concepts to the table. Chief among these: The REPL. It does take some time to grasp it. Calva needs to remove any obstacles it can when it comes to helping the user to reach the REPL, in order to help getting it, and start loving it.
To help the users to quickly focus on Clojure, we provide a package that is all-inclusive, with few knobs to turn, and with sane defaults for the knobs that still need to be there.
"},{"location":"tao/#productive-enough-to-stick-with","title":"Productive Enough to Stick With","text":"I think VS Code brings inspiration also when it comes to following up its excellent Getting Started story. You do not have to dig very deep under its surface to find that there is a lot more power to be unleashed. VS Code makes it easy to pick up more features as you get ready for it, and each little piece makes you more productive. To me, only Vim beats VS Code in this game.
Most often there should be no contradiction between Easy to Start With and Productive. Quite the contrary. This story is mainly about being feature complete with the most important tools. As beginners start to pick up the first few features, they should be rewarded with finding more productive tools when they go looking for them. The VS Code way is Calva's way.
"},{"location":"tao/#pleasant-and-enjoyable","title":"Pleasant and Enjoyable","text":"Enjoyable starts with that Calva shouldn't be an experience full of pains. I think Calva is living up to this first bar of enjoyability. The next step is making it delightful!
Calva has two main assets it can leverage for being delightful to use: Clojure and VS Code:
Clojure is plain wonderful and also has this totally awesome REPL thing. Wherever we can, Calva should use the REPL to make the editor spark and bring joy to the developer.
VS Code is a sweet development environment, offering its power in a consistent way across languages. Even if Clojure is very special, most of Calva's features are surfaced in the ways that VS Code encourages. It makes for less to learn for the user, and most often also makes it easier to implement functionality.
"},{"location":"tao/#support-clojure-best-practices","title":"Support Clojure Best Practices","text":"Mainly, I think Stuart Halloway is right about the REPL being best used from inside the files you are editing rather than from the prompt. It doesn't mean that Calva's REPL window should be neglected, but efforts should be directed such that the file editor REPL is our first way to improve the experience. Expect the Calva REPL window to get much less \u201din your face\u201d, than it is today, as the editor REPL gets stronger.
Halloway also gives me some peace of mind with his reasoning of keeping a spartan setup. Calva does not need to pack every feature imaginable. If we can get the right features in place, in the right way, the mission is accomplished.
Clojure is data centric. Calva should make it easy to examine data and how our code affects it. Today, this is not good enough when it comes to data structures larger than a few elements.
Clojure is a LISP. Thus Structural Editing is possible, and TBH, desirable. Calva should support this and encourage it. There is little we can do about Parinfer not playing well with VS Code, but there is Paredit, and Paredit rocks! Calva's Paredit plays in the top league of Paredits, for this reason.
"},{"location":"tao/#made-from-the-produce-of-the-orchard","title":"Made from the Produce of the Orchard","text":"Calva is distilled from CIDER, which in turn is brewed from the products of The Orchard. This makes a lot of Calva's features thin wrappers around cider-nrepl and related middleware. It also should mean that we strive for adding features by thinking \u201dThe Orchard\u201d first. If it lacks what we need, we should assist in providing it there. We need to up this game a bit from where we are today, I think.
"},{"location":"tao/#leveraging-clojure-lsp","title":"Leveraging clojure-lsp","text":"Today, Calva draws a lot of its static power from clojure-lsp. As does a lot of other Clojure tooling out there. The Calva and the clojure-lsp teams work very nicely together, which is something we cherish and should take care to maintain.
"},{"location":"tao/#project-stewardship","title":"Project Stewardship","text":"Here Calva takes inspiration from many Clojure related projects, and perhaps most so from CIDER,shadow-cljs, and clojure-lsp. Bozhidar Batsov, Thomas Heller, and Eric Dallo all lead their projects with clarity and with gusto. You can feel how they really care about their products and their users. They are there. They listen. They respond. And they relentlessly keep improving their products.
So we are there. We listen. We respond. And we keep trying to improve Calva.
The Calva team cares deeply about the user experience. That is a major part of why we do this. When implementing a new feature, or changing a feature, Ux is always the first thing on our mind. Personally, to keep that direction I often start with the documentation of the feature. Reading the documentation before implementation reveals a lot about if the Ux design is within the ballpark or not.
We have limited time on our hands, however, and we must cut some corners. We can't afford to spend very much time in Ux design. Rather we will use our Ux intuition, iterate the documentation quickly, and be fast to get things out. Then we are responsive in tweaking those things, based on user feedback. This also has impact on general quality at times. We only can do so much QA, and it happens that some releases of Calva cause disruptions in people's workflow because of things we haven't thought of, or not found during our testing. Again, we try to be attentive to feedback and quick to fix. Apologies in advance for any inconveniences caused!
A super major part of our love for Ux is that Calva should be serving its users. That's why we treat feedback as a gift, listen intently, and use the feedback as a major ingredient in shaping Calva.
Calva develops from user feedback in more direct ways as well. It is quite astonishing how many people have decided to improve on it by hacking it to do some small or big thing differently. That's great! We should make sure Calva is super easy to contribute to.
There has been quite a lot of work put into improving the development process. Starting to hack on Calva is just a few steps, taking less than three minutes from cloning to running a dev version in the VS Code debugger. We encourage contributions, from the tiniest typo to whole new features. And we are ready to spend time helping people get their contributions integrated.
However, Calva can't be what everyone wants it to be, that would make it useless. It needs direction and aim. And it is we, the Calva Team, who are the stewards. We need to be in charge of what Calva is about, and what it is not about.
"},{"location":"tao/#the-road-ahead","title":"The Road Ahead","text":"Tying back to Stuart Halloway, I don't think he means that spartan needs to also mean poor. The products he helps to bring to the market tell another story. VS Code and Clojure brought together has the capacity to create something amazingly rich and luxurious. And I want Calva to tap into that potential.
On the Calva journey we will allow ourselves to change our minds about how things work. Calva is not a library. Its an interface between Clojure and human beings. Human beings can adapt. And they will need to enjoy adapting in order to enjoy Calva. \ud83d\ude04
By now it should be clear that you can expect Calva to keep evolving, keep being tended and maintained, and keep getting ever more enjoyable to use. Lately we have been improving Calva pretty rapidly. It would be great to keep it up like that, but I think it is good to expect a more humble and sustainable pace.
Calva is still quite new. A bit like freshly distilled Calvados. It will need time in those oak barrels to develop its full bouquet of flavors. And time is what we will give it. Our time, our creativity, and our passion.
"},{"location":"test-runner/","title":"Test Runner","text":"Calva provides commands that make running your Clojure tests easier.
Note
Since the test commands utilize cider-nrepl, they only work with Clojure, not ClojureScript. See this issue for more details.
"},{"location":"test-runner/#test-commands","title":"Test Commands","text":"Command Shortcut Description Run All Testsctrl+alt+c shift+t
Runs all tests Run Failing Tests ctrl+alt+c ctrl+t
Runs the tests that failed Run Tests for Current Namespace ctrl+alt+c t
Runs the tests for the current namespace. If not a -test
namespace, tests for the current namespace plus its corresponding <current-namespace>-test
namespace will be run. Run Current Test ctrl+alt+c ctrl+alt+t
Runs the test at the cursor. This includes a defn
with a :test
in its metadata, a defn
defined in a with-test
, and a deftest
. Toggle between implementation and test - Switches the file between implementation and test, prompts to create a new file if not found."},{"location":"test-runner/#test-on-save","title":"Test on Save","text":"You can enable the Calva setting \"Test on Save\" to have tests for the current namespace run on file save.
"},{"location":"test-runner/#vs-code-test-ui","title":"VS Code Test UI","text":"Calva has experimental support for showing test results in VS Code's Test UI. You can enable this support by setting calva.useTestExplorer
to true
. When you enable this setting, the Testing icon will appear in the Testing tab of VS Code's Activity Bar.
With this feature enabled you will be able to browse and run tests directly from the Testing tab.
Please join the #calva channel on the Clojurians Slack if you have any feedback on this new feature.
"},{"location":"test-runner/#troubleshooting","title":"Troubleshooting","text":""},{"location":"test-runner/#tests-are-not-found","title":"Tests Are Not Found","text":"Calva will not load namespaces in the REPL that you haven't loaded. This is so that you can be in control of what is loaded in the REPL. However, it also means that commands like Run All tests actually mean Run All Tests That are Loaded in the REPL, since the test-runner only runs tests that it knows about, i.e. are loaded in the REPL. Some developers choose to make sure all test namespaces are loaded as part of starting their REPL. Others register a custom REPL command for loading test namepaces. (Yet others use test-runners such as Cognitect's test-runner, Kaocha, poly test, or some other that runner allows for tests being run automatically, separate from the REPL used for development.)
If you have tests in a test directory separate from your source directory, and those tests are not being found by the test runner, make sure the test directory is included in your paths. This will not be the case by default with a tools.deps (deps.edn) project. If your project is a tools.deps project, you can create an alias in your deps.edn file with :extra-paths
that includes \"test\"
(or the name of your test directory).
{:aliases {:dev {:extra-paths [\"test\"]}}}\n
"},{"location":"test-runner/#changes-arent-taking-effect-when-running-tests","title":"Changes Aren't Taking Effect When Running Tests","text":"In order for changes in code to take effect, you need to load the file or evaluate the changed code before running a test command. Prior to version 2.0.301, Calva would load the file for you when running some test commands, but that behavior was removed in favor of leaving control to the user, and to avoid a potential issue.
Having added the above to your deps.edn, when you jack-in, choose the :dev
alias and the test
directory will be added to your paths, which will allow tests located in the directory to be found by the test runner.
This feature mostly works with projects that has leiningen style folder structure and makes some assumption about your folder structure and test file names.
_test
prefix.src
folder and the test files are in test
folder.If you are using any non leiningen style folder structure, you may have to add source paths inside .lsp/config.edn
.
You should start with loading the file you are working with. Do this with Load/Evaluate Current File and its Requires/Dependencies, ctrl+alt+c enter
.
To get a feeling for evaluating code in the editor and get immediate response from the REPL try this:
comment
form and put some code inside it:(comment\n(+ (* 2 2)\n2)\n(Math/abs -1)\n(hello \"Calva REPL\")\n(defn hello [s]\n(str \"Hello \" s))\n(range 10)\n\"I \u2665\ufe0f Clojure\")\n
Then:
(* 2 2)
and issue the command Calva: Evaluate Current Form, ctrl+enter
.esc
to dismiss it.alt+enter
.(+ (* 2 2) 2)
getting highlighted and the result of that expression being displayed inline.(hello \"Calva REPL\")
form before the (defn hello...
form should result in an error/exception. A stacktrace is then printed in the output windowdefn
form.Demo:
"},{"location":"try-first/#how-does-this-work","title":"How does this work?","text":"Calva has this notion about the current form. Issue the Evaluate Current Form command, with the cursor placed in different locations to get a feeling for how the current form is determined.
There is also a concept about the current top level form. Good for evaluating various def
s defn
, defthis
, defthat
. With your cursor placed anywhere inside such a form.
The Top Level command also works inside (comment ...)
forms, treating the comment
as creating a new top level context. It is good for in-file code experimentation.
First thing first. The VIM Extension and Calva has a history of friction between them. Less so these days, but you might still encounter some rough edges. Please don't hesitate to reach out to the Calva team, as we might be able to fix things if only we are aware of them.
"},{"location":"vim/#key-bindings","title":"Key bindings","text":"In general Calva's default key bindings are not very VI-ish.
"},{"location":"vim/#expand-selection-on-mac","title":"Expand selection on Mac","text":"On Mac, Calva binds expand selection to ctrl+w
. This conflicts with the VIM Extension's default mapping of window splitting shortcuts. You'll need to remap it either with Calva or with the VIM Extension.
esc
key","text":"While showing inline evaluation results, Calva binds the esc
key to dismiss the display of inline results. If you want to be able to use the esc
key to enter command mode while inline results are showing, you'll need to rebind Calva's command for dismissing the inline results.
clearInlineResults
","text":"clearInlineResults
and remap the command e.g.// Place your key bindings in this file to override the defaults\n[\n{\n\"key\": \"escape\",\n\"command\": \"-calva.clearInlineResults\"\n},\n{\n\"key\": \"shift+escape\",\n\"command\": \"calva.clearInlineResults\",\n\"when\": \"editorTextFocus && !editorHasMultipleSelections && !editorReadOnly && !hasOtherSuggestions && !suggestWidgetVisible && editorLangId == 'clojure'\"\n}\n]\n
If you run into issues, refer to the commands in the default Keyboard Shortcuts JSON file.
"},{"location":"vim/#remap-vims-insert-mode","title":"Remap Vim's Insert Mode","text":"Remap vim's insert mode keybinding to go into command mode by adding the following to your user settings:
\"vim.insertModeKeyBindings\": [\n{\n\"before\": [\"j\", \"k\"],\n\"after\": [\"<esc>\"]\n}\n]\n
(Change before
to whatever keybinding you are comfortable with!)
You can add these keybindings to your init.vim
if you are using the VSCode Neovim extension. It is inspired by and tries to emulate the keybindings found in vim-fireplace which is the most popular vim plugin for Clojure.
nmap cqp :call VSCodeNotify('calva.jackIn')<CR>\nnmap cqq :call VSCodeNotify('calva.disconnect')<CR>\nnmap cpr :call VSCodeNotify('calva.loadFile')<CR>\nnmap cpR :call VSCodeNotify('calva.loadNamespace')<CR>\nnmap cpp :call VSCodeNotify('calva.evaluateSelection')<CR>\nnmap cqc :call VSCodeNotify('calva.evalCurrentFormInREPLWindow')<CR>\n
Unfortunately these key combinations will not work in the normal VIM extension as c
is an operator key and cannot be remapped. This is a call for someone to share their VIM re-mappings.
When clause contexts is a powerful customization mechanism in VS Code. The most common use for end users is with keyboard shortcut bindings. Extensions can provide their own. The following contexts are available with Calva:
calva:keybindingsEnabled
: a master switch that you find in the settingsparedit:keyMap
: strict
, original
, or none
from the corresponding Calva setting (see Paredit)calva:connected
: true
when Calva is connected to a REPL (there is also calva:connecting
|| calva:launching
)calva:outputWindowActive
: true
when the Output/REPL window has input focuscalva:replHistoryCommandsActive
: true
when the cursor is in the Output/REPL window at the top level after the last promptcalva:replWindowSubmitOnEnter
: true
when the cursor is adjacent after the last top level form in the Output/REPL windowcalva:cursorInString
: true
when the cursor/caret is in a string or a regexpcalva:cursorInComment
: true
when the cursor is in, or adjacent to a line commentcalva:cursorBeforeComment
: true
when the cursor is adjacent before a line commentcalva:cursorAfterComment
: true
when the cursor is adjacent after a line commentcalva:cursorAtStartOfLine
: true
when the cursor is at the start of a line including any leading whitespacecalva:cursorAtEndOfLine
: true
when the cursor is at the end of a line including any trailing whitespaceThe main reason you would choose Calva for your Clojure and/or ClojureScript coding is that you want to use Visual Studio Code. Calva provides VS Code users with a comprehensive set of features to keep you productive and make it easy to follow Clojure coding best practices. This also means that if your choice of editor is not made yet, we think you should give VS Code and Calva a try.
While Calva is a good choice for professional and experienced Clojure developers, great care has been taken in making Calva a really good choice for beginners of Clojure as well.
We who make Calva are actively stewarding, maintaining, documenting and supporting it. We are also very active Clojure (and Calva) users, participating in the community. Clojure is dear to us, a lot because it keeps programming fun and rewarding.
Calva has very happy users! Check out the Programming Languages section on the Visual Studio Code Marketplace, sorted by rating:
Recently there was a thread over at ClojureVerse, asking about how Calva Compares to Emacs with CIDER. It is well worth reading. We would like to highlight the answer by Nick Cernis, which focuses on Calva. We'll even quote parts of it. \ud83d\ude0d
"},{"location":"why-calva/#nick-cernis-on-clojureverse","title":"Nick Cernis on ClojureVerse","text":"My advice to anyone starting their Clojure journey who is unsure about what editor to use:
I now use VS Code with Calva every day but went through a long journey trying almost every other editor and plugin combo first. I switched from Emacs to VS Code, which might make my perspective different to others here.
\u2026
I started with the jaded assumption that VS Code was probably bad because it's built by committee at Microsoft on a web-tech based Electron stack, only to find that it succeeds in embodying the spirit of a \u201chacker's editor\u201d more than even Emacs does in many ways:
\u2026
On the benefits of Calva:
Of all the amazing Clojure community projects, Calva seems most likely to encourage new users to try Clojure and ClojureScript. A lot of developers use VS Code. It\u2019s been tricky to convince frontend developer friends to try ClojureScript, but at least they don\u2019t have the excuse that they\u2019ll need to switch editors to even try it now. I think as a community we should try to support the projects that encourage Clojure\u2019s adoption and ease of use, including by using those products ourselves.
Calva provides a better first-time experience than any other editor/plugin combo whether you\u2019re new to Clojure or not. You can install the plugin and be chatting with your REPL in under a minute without any knowledge of Elisp or VimScript/Lua or how to configure Run Configurations in IntelliJ.
We are super proud of the Calva reviews on the Visual Studio Code Marketplace. Please read them all. \ud83d\ude04 Here's a selection that we think captures what we focus on in when developing Calva:
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f Calva has become an essential part of my Clojure workflow.
It's an incredible piece of work by the team behind it.
Sean Corfield
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f Calva hits the sweet spot of being both approachable for new users and powerful for seasoned ones.
The creators/maintainers are fantastic individuals that care deeply about streamlining the user experience, and it shows.
Good stuff, check it out.
Clay Hopperdietzel
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f I switched from IntelliJ / Cursive to VS Code and Calva and it's been amazing.
...
That is the biggest thing I can say for Calva, it just works. I was never a fan of VS Code before, but VS Code + Calva for Clojure is now my favorite language / IDE experience.
Plus, the #calva on the clojurians slack is brilliant, always someone there to help if you have issues (although any issue I've had has been squarely on me, and never Calva itself).
I often feel we live in an age where so much software is badly written, without care, slow, buggy and just generally awful. Calva is the complete opposite. I think the maintainers want to, and have, made a wonderful piece of software for Clojure developers.
Stuart Stein
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f This is great, and makes VS Code a truly viable IDE/editor for clojure development.
It already has great REPL support (including inline evaluation), an extensive Paredit implementation, and excellent linting (care of the bundled clj-kondo). Calva is being improved on at an impressive clip by maintainers who appear solidly committed to its ongoing development. It's well-documented, and manages to be both approachable and capable.
A no-brainer if you're already a VS Code user, and well worth a look if you're not.
Crispin Bennett
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f I'm using Calva now for a few months and I'm loving it.
I joined the Slack channel about 2 wks ago and I must say that I'm very impressed by how active and responsive this community is. Already 2 of my issues fixed and I really like Calva (and the extensions it uses!).
These are professional people and they make me very happy!
Uitbeijerse, E (Eric)
"},{"location":"workspace-layouts/","title":"Workspace Layouts","text":"Project directory layouts can vary quite a lot. From the \u201dtemplate\u201d projects where the Clojure project files are at the root, to, well, let's just say that the project files are not always at the root. And sometimes there is more than one project (read here how to get clojure-lsp support with a Leiningen project in a subfolder).
Calva only really supports working with one project at a time per VS Code window. Here's a short guide for some different setups:
As is mentioned in the Calva Jack-In Guide, if you have a full stack project using a Clojure backend and a shadow-cljs frontend, you will need to open the same project in two separate VS Code windows, one for the backend and one for the frontend. This is how you can do that:
Server.code-workspace
.Client.code-workspace
.Now, whenever you want to Jack-in to the backend and/or frontend, do it from the Server and/or Client workspace, respectively.
"},{"location":"wsl/","title":"Calva \u2764\ufe0f WSL","text":"The use of Calva with WSL (Windows Subsystem for Linux) is fully supported through the Remote - WSL extension. Simply install the extension and open your project with one of the Remote-WSL
commands. Calva will run directly in the WSL environment and no further configuration is required.
See also Remote Development.
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-\\._]","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome!","text":"Calva is an integrated, REPL powered, development environment for enjoyable and productive Clojure and ClojureScript programming in Visual Studio Code. It is feature rich and turnkey. A lot of effort has been put into making Calva a good choice if you are new to Clojure. Calva is open source and free to use.
"},{"location":"#getting-started","title":"Getting Started","text":"Let's start a REPL!. \ud83d\ude80 Also see Get Started with Clojure
"},{"location":"#how-to-contribute-to-calva","title":"How to Contribute to Calva?","text":"I'm glad you asked! Please see How to Contribute and The Tao of Calva
"},{"location":"#calva-patrons","title":"Calva Patrons","text":"The right kind of different"},{"location":"#calva-gold-sponsors","title":"Calva Gold Sponsors \u2665\ufe0f","text":"Scale your growth on mobile MAKE. DO. SHIP.Please see this statement from Cognitect about the importance of supporting open source developers.
See Sponsors for information about sponsoring Calva.
If your Company benefits from Calva's existence and you see it as an important in the Clojure and ClojureScript ecosystem. please consider sponsoring!
"},{"location":"#features","title":"Features","text":"Calva includes inline code evaluation, structural editing, code formatting, code navigation, a debugger, linting, syntax highlighting, Clojure aware rainbow brackets, a test runner, refactoring support, and more.
"},{"location":"#have-questions-and-feedback-need-help","title":"Have Questions and Feedback? Need Help?","text":"Easiest way is to chat with us and other Calva users. Please join the #calva channel on the Clojurians Slack. If you haven't joined that slack workspace, you can get an invite here.
If you're a beginner to Clojure(Script), the #beginners channel of the Clojurians Slack is very active and helpful.
"},{"location":"#please-star-the-calva-repo","title":"Please star the Calva repo!","text":"Happy coding!
"},{"location":"api/","title":"The Calva Extension API","text":"Calva exposes an API for use from other VS Code extensions (such as Joyride). The API is in an experimental state, while we are figuring out what is a good shape for this API. It is also rather small, and will grow to expose more of Calva's functionality.
","boost":7},{"location":"api/#accessing","title":"Accessing","text":"To access the API the Calva extension needs to be activated. The API is exposed under the v1
key on the extension's exports
, and split up into submodules, like repl
, and ranges
.
When using Joyride you can use its unique require
API, for which one of the benefits is better lookup IDE support. When using the API from regular ClojureScript, you'll pick it up from the Calva extension instance. (Which you can do from Joyride as well, but why would you?). Here is how you access the API, with an example of usage as a bonus:
(ns ... (:require [\"ext://betterthantomorrow.calva$v1\" :as calva]))\n;; OR\n(require '[\"ext://betterthantomorrow.calva$v1\" :as calva])\n\n(calva/repl.currentSessionKey) => \"cljs\" ; or \"clj\", depending\n
(def calvaExt (vscode/extensions.getExtension \"betterthantomorrow.calva\"))\n\n(def calva (-> calvaExt\n.-exports\n.-v1\n(js->clj :keywordize-keys true)))\n\n((get-in calva [:repl :currentSessionKey])) => \"cljs\" ; or \"clj\", depending\n
const calvaExt = vscode.extensions.getExtension(\"betterthantomorrow.calva\");\n\nconst calva = calvaExt.exports.v1;\n\nconst sessionKey = calva.repl.currentSessionKey()\n
","boost":7},{"location":"api/#repl","title":"repl
","text":"The repl
module provides access to Calva's REPL connection.
repl.currentSessionKey()
","text":"Use repl.currentSessionKey()
find out which REPL/session Calva's REPL is currently connected to (depends on the active file). Returns either \"clj\"
, or \"cljs\"
, or nil
if no REPL is connected.
(def session-key (calva/repl.currentSessionKey))\n
(def session-key ((get-in [:repl :currentSessionKey] calvaApi)))\n
const sessionKey = calva.repl.currentSessionKey()\n
","boost":7},{"location":"api/#replevaluatecode","title":"repl.evaluateCode()
","text":"This function lets you evaluate Clojure code through Calva's nREPL connection. Calling it returns a promise that resolves to a Result
object. It's signature looks like so (TypeScript):
export async function evaluateCode(\nsessionKey: 'clj' | 'cljs' | 'cljc' | undefined,\ncode: string,\nns = 'user',\noutput?: {\nstdout: (m: string) => void;\nstderr: (m: string) => void;\n},\nopts = {}\n): Promise<Result>;\n
Where Result
is:
type Result = {\nresult: string;\nns: string;\noutput: string;\nerrorOutput: string;\n};\n
As you can see, the required arguments to the function are sessionKey
and code
. sessionKey
should be \"clj\"
, \"cljs\"
, \"cljc\"
, or undefined
depending on which of Calva's REPL sessions/connections that should be used. It will depend on your project, and how you connect to it, which session keys are valid. Use cljc
to request whatever REPL session \"cljc\"
files are connected to. Use undefined
to use the current REPL connection Calva would use (depends on which file is active).
An example:
JoyrideClojureScriptJavaScript(-> (p/let [evaluation (calva/repl.evaluateCode \"clj\" \"(+ 2 40)\")]\n(println (.-result evaluation)))\n(p/catch (fn [e]\n(println \"Evaluation error:\" e))))\n
(def evaluate (get-in [:repl :evaluateCode] calvaApi))\n(-> (p/let [evaluation (evaluate \"clj\" \"(+ 2 40)\")]\n(println (.-result evaluation)))\n(p/catch (fn [e]\n(println \"Evaluation error:\" e))))\n
try {\nconst evaluation = await calvaApi.repl.evaluateCode(\"clj\", \"(+ 2 40)\");\nconsole.log(evaluation.result);\n} catch (e) {\nconsole.error(\"Evaluation error:\", e);\n}\n
","boost":7},{"location":"api/#handling-output","title":"Handling Output","text":"The output
member on the Result
object will have any output produced during evaluation. (The errorOutput
member should contain error output produced, but currently some Calva bug makes this not work.) By default the stdout and stderr output is not printed anywhere.
If you want to do something with either regular output or error output during, or after, evaluation, you'll need to provide the output
argument to evaluateCode()
. (The stderr
callback function works, so this is the only way to get at any error output, until the above mentioned Calva bug is fixed.)
An example:
JoyrideClojureScriptJavaScript(def oc (joyride.core/output-channel)) ;; Assuming Joyride is used\n(def evaluate (fn [code]\n(calva/repl.evaluateCode\n\"clj\"\ncode\n\"user\"\n#js {:stdout #(.append oc %)\n:stderr #(.append oc (str \"Error: \" %))})))\n\n(-> (p/let [evaluation (evaluate \"(println :foo) (+ 2 40)\")]\n(.appendLine oc (str \"=> \" (.-result evaluation))))\n(p/catch (fn [e]\n(.appendLine oc (str \"Evaluation error: \" e)))))\n
(def oc (joyride.core/output-channel)) ;; Assuming Joyride is used\n(def evaluate (fn [code]\n((get-in [:repl :evaluateCode] calvaApi)\n\"clj\"\ncode\n\"user\"\n#js {:stdout #(.append oc %)\n:stderr #(.append oc (str \"Error: \" %))})))\n\n(-> (p/let [evaluation (evaluate \"(println :foo) (+ 2 40)\")]\n(.appendLine oc (str \"=> \" (.-result evaluation))))\n(p/catch (fn [e]\n(.appendLine oc (str \"Evaluation error: \" e)))))\n
const evaluate = (code) =>\ncalvaApi.repl.evaluateCode(\"clj\", code, \"user\", {\nstdout: (s) => {\nconsole.log(s);\n},\nstderr: (s) => {\nconsole.error(s);\n},\n});\n\ntry {\nconst evaluation = await evaluate(\"(println :foo) (+ 2 40)\");\nconsole.log(\"=>\", evaluation.result);\n} catch (e) {\nconsole.error(\"Evaluation error:\", e);\n}\n
","boost":7},{"location":"api/#ranges","title":"ranges
","text":"The ranges
module contains functions for retreiving vscode.Ranges and text for pieces of interest in a Clojure document.
All functions in this module have the following TypeScript signature:
(editor = vscode.window.activeTextEditor, position = editor?.selection?.active) => [vscode.Range, string];\n
I.e. they expect a vscode.TextEditor \u2013 defaulting to the currently active editor \u2013 and a vscode.Position \u2013 defaulting to the current active position in the editor (or the first active position if multiple selections/positions exist, and will return a tuple with the range, and the text for the piece of interest requested.
Custom REPL Commands
The ranges
function have corresponding REPL Snippets/Commands substitution variables. It is the same implementation functions used in both cases.
The functions available are:
","boost":7},{"location":"api/#rangescurrentform","title":"ranges.currentForm()
","text":"Retrieves information about the current form, as determined from the editor and position.
Corresponding REPL Snippet variable: $current-form
.
See also about Calva's Current Form on YouTube.
","boost":7},{"location":"api/#rangescurrentenclosingform","title":"ranges.currentEnclosingForm()
","text":"The list/vector/etcetera form comtaining the current form.
Corresponding REPL Snippet variable: $enclosing-form
.
ranges.currentTopLevelForm()
","text":"The current top level form. Outside (comment ...)
(Rich comments) forms this is most often ((def ...), (defgn ...)
, etcetera. Inside Rich comments it will be the current immediate child to the (comment ...)
form.
Corresponding REPL Snippet variable: $top-level-form
.
ranges.currentFunction()
","text":"The current function, i.e. the form in \u201dcall position\u201d of the closest enclosing list.
Corresponding REPL Snippet variable: $current-fn
.
ranges.currentTopLevelDef()
","text":"The symbol being defined by the current top level form. NB: Will stupidly assume it is the second form. I.e. it does not check that it is an actual definition, and will often return nonsense if used in Rich comments.
Corresponding REPL Snippet variable: $top-level-defined-symbol
.
ranges.currentTopLevelForm()
","text":"JoyrideClojureScriptJavaScript (let [[range text] (calva/ranges.currentTopLevelForm)]\n...)\n
(let [[range text] ((get-in [:ranges :currentTopLevelForm]))]\n...)\n
const [range, text] = ranges.currentTopLevelForm();\n
","boost":7},{"location":"api/#editor","title":"editor
","text":"The editor
module has facilites (well, a facility, so far) for editing Clojure documents.
editor.replace()
","text":"With editor.replace()
you can replace a range in a Clojure editor with new text. The arguments are:
editor
, a vscode.TextEditor
range
, a vscode.Range
newText
, a string(-> (p/let [top-level-form-range (first (calva/ranges.currentTopLevelForm))\n_ (calva/editor.replace vscode/window.activeTextEditor top-level-form-range \"Some new text\")]\n(println \"Text replaced!\"))\n(p/catch (fn [e]\n(println \"Error replacing text:\" e))))\n
const topLevelRange = calvaApi.ranges.currentTopLevelForm();\ncalva.editor.replace(topLevelRange, \"Some new text\")\n.then((_) => console.log(\"Text replaced!\"))\n.catch((e) => console.log(\"Error replacing text:\", e));\n
","boost":7},{"location":"api/#document","title":"document
","text":"The document
module provides access to the Clojure/Calva aspects of VS Code TextDocument
s.
document.getNamespace(document?: vscode.TextDocument): string
","text":"document.getNamespace()
returns the namespace of a document.
document
, a vscode.TextDocument
(defaults to the current active document)Example usage. To evaluate some code in the namespace of the current document:
JoyrideJavaScript(calva/repl.evaluateCode \"clj\" \"(+ 1 2 39)\" (calva/document.getNamespace))\n
calva.repl.evaluateCode(\"clj\", \"(+ 1 2 39)\", calva.document.getNamespace());\n
","boost":7},{"location":"api/#documentgetnamespaceandnsformdocument-vscodetextdocument-ns-string-nsform-string","title":"document.getNamespaceAndNsForm(document?: vscode.TextDocument): [ns: string, nsForm: string]
","text":"document.getNamespaceAndNsForm()
returns the namespace and the ns
form of a document as a tuple.
document
, a vscode.TextDocument
(defaults to the current active document)Example usage. To evaluate the ns
form of the current document:
(calva/repl.evaluateCode \"clj\" (second (calva/document.getNamespaceAndNsForm)))\n
calva.repl.evaluateCode(\"clj\", calva.document.getNamespaceAndNsForm()[1]);\n
","boost":7},{"location":"api/#pprint","title":"pprint
","text":"The pprint
module lets you pretty print Clojure code/data using Calva's pretty printing engine (which in turn uses zprint).
pprint.prettyPrint()
","text":"Use pprint.prettyPrint()
to pretty print some Clojure data using your Calva pretty printing options. It accepts these arguments:
text
, a string
with the text to pretty printoptions
, a JavaScript object with pretty printing options, this is optional and will default to the current settings.The function is synchronous and returns the prettified text.
JoyrideJavaScript(println (calva/pprint.prettyPrint \"Some text\")))\n
console.log(calvaApi.pprint.prettyPrint();\n
","boost":7},{"location":"api/#pprintprettyprintingoptions","title":"pprint.prettyPrintingOptions()
","text":"Use to get the current pretty printint options:
","boost":7},{"location":"api/#vscode","title":"vscode
","text":"In the its vscode
submodule, Calva exposes access to things from its own vscode
module instance. It gets important in some situations.
vscode.registerDocumentSymbolProvider()
","text":"This is the [vscode.languages](https://code.visualstudio.com/api/references/vscode-api#languages).registerDocumentSymbolProvider()
function from the Calva extension. Use it if you want to provide symbols for Clojure files together with the ones that Calva provides. (If you use the vscode.languages.registerDocumentSymbolProvider()
function from your extension (or Joyride) you will provide a separate group.)
(-> (joyride/extension-context)\n.-subscriptions\n(.push (calva/vscode.registerDocumentSymbolProvider ...)))\n
(-> yourExtensionContext\n.-subscriptions\n(.push ((get-in calva [:vscode :registerDocumentSymbolProvider]) ...)))\n
yourExtensionContext.subscriptions.push(calva.vscode.registerDocumentSymbolProvider(...));\n
Deprecation candidate
VS Code is still creating a separate group, just with the same name as Calva's, so this API is not good for anything, and we will probably remove it.
","boost":7},{"location":"api/#feedback-welcome","title":"Feedback Welcome","text":"Please let us know how you fare using this API. Either in the #calva or #joyride channels on Slack or via the issues/discussions sections on the repositories. (Whichever seems to apply best.)
","boost":7},{"location":"async-out/","title":"Viewing Async Output While Working On Node Projects withshadow-cljs
","text":"When working on NodeJS projects with shadow-cljs
and Calva, async output does not always appear in the Calva output window. To work around this problem, follow these steps:
shadow-cljs - nREPL server started on port <some-port>
ctrl+alt+c ctrl+alt+c
. For project type select shadow-cljs
, accept the proposed localhost:<some-port>
, and for build
select node-repl
.ctrl+alt+c Enter.
Evaluating forms in Calva will show results in the output window. Synchronous stdout
output will be printed in both the output window and in the terminal where you started the repl. Some asynchronous output may show up in the output window, but all will appear in the terminal.If you use an integrated VSCode terminal to start shadow-cljs, all stdout
will appear in the Calva window with your code. Alternatively, you can use an external terminal, which is especially nice when using a second monitor.
For a discussion of this problem and other connection options, see issue #1468.
"},{"location":"babashka/","title":"Using Calva with Babashka","text":"Since Babashka can be started such that it is an nREPL server, Calva can connect to it and a lot of the features will work.
Calva can also start Babashka and connect its REPL for you, using the Jack-in command.
Don't expect complete support
Babashka's nREPL server is still a bit limited compared to a full cider-nrepl enhanced \"regular\" Clojure nREPL server. Things like function signatures, and more do not work.
This might of course improve in the future, especially if you provide some PRs towards the Babashka nREPL.
","boost":5},{"location":"clj-java-decompiler/","title":"Decompiling and disassembly made easy","text":"If you need some piece of Clojure code to execute as fast as possible you will often benefit from examining the code generated by the Clojure compiler from your code. There is a really easy to use tool for that: clj-java-decompiler. You can make the use of this tool super convenient with Calva custom command snippets.
"},{"location":"clj-java-decompiler/#prerequisites","title":"Prerequisites","text":"Add com.clojure-goes-fast/clj-java-decompiler
as a dependency to the project.
You can add some Calva custom commands configuration to be able to decompile or disassemble any Clojure code in your editor with a keyboard shortcut. Here's an example configuration:
\"calva.customREPLCommandSnippets\": [\n{\n\"name\": \"Decompile current top level form\",\n\"key\": \"d\",\n\"snippet\": \"(require '[clj-java-decompiler.core :refer [decompile]]) (spit \\\"decompiled-$top-level-defined-symbol.java\\\" (with-out-str (decompile $top-level-form)))\"\n},\n{\n\"name\": \"Decompile current form\",\n\"snippet\": \"(require '[clj-java-decompiler.core :refer [decompile]]) (spit \\\"decompiled.java\\\" (with-out-str (decompile $current-form)))\"\n},\n{\n\"name\": \"Disassemble current top level form\",\n\"key\": \"b\",\n\"snippet\": \"(require '[clj-java-decompiler.core :refer [disassemble]]) (spit \\\"bytecode-$top-level-defined-symbol.class\\\" (with-out-str (disassemble $top-level-form)))\"\n},\n{\n\"name\": \"Disassemble current current form\",\n\"snippet\": \"(require '[clj-java-decompiler.core :refer [disassemble]]) (spit \\\"bytecode.class\\\" (with-out-str (disassemble $current-form)))\"\n}\n],\n
Now, with the cursor anywhere in a top level defined function, you can spit out a file with the Java code generated for that function by pressing ctrl+alt+space d
. For the byte code, press ctrl+alt+space b
. The files will be generated in the same folder as the Clojure file and be named decompiled-<function name>.java
and bytecode-<function name>.class
, respectively.
To decompile or disassemble the current form (or selection) press ctrl+alt+space space
and pick the desired command from the quick pick menu that pops up. You can add key
to these too if you want even quicker access, of course. The filenames for the results will here be named without any function name suffix, because there is often no function name that can be used.
See this video for a demo.
"},{"location":"clojure-lsp/","title":"Clojure-lsp","text":"Calva uses a mix of static and dynamic analysis to power the experience. A lot of the static abilities come from clojure-lsp. This enables you to check something up in a project, with a lot of navigational and contextual support, without starting a REPL for it. (And once you do start a REPL you'll get even more capabilities, enabled by the dynamic analysis.)
Which clojure-lsp does Calva use?
Calva defaults to using the latest
clojure-lsp released. To use a different version of clojure-lsp, see the configuration section. Calva does not use the clojure-lsp installed on your system, unless you set the path for clojure-lsp to the installed binary in your settings. You can see what version is being used by running the Clojure-lsp Server Info
command, which will also show the version of clj-kondo that's being used as well as other info.
By default you won't need to install/setup anything as Calva handles that for you by automatically downloading the latest clojure-lsp binary. It can take a while for clojure-lsp to start, especially the first time opening a new project, as clojure-lsp (via clj-kondo
) indexes the project files.
Calva is able to automatically start the clojure-lsp server for you and can be configured to start the server under various different conditions. These behaviours can be configured through the calva.enableClojureLspOnStart
setting, which takes the following options:
When set to \"always-use-first-workspace-root\"
Calva will attempt to start the clojure-lsp in the root of the first workspace folder if it is a valid clojure project. If it is not a valid clojure project it will fall back to starting the fallback server.
This is the default auto-start behaviour.
"},{"location":"clojure-lsp/#when-workspace-opened-use-workspace-root","title":"\"when-workspace-opened-use-workspace-root\"","text":"When set to \"when-workspace-opened-use-workspace-root\"
Calva will start the clojure-lsp in the root of all opened vscode workspaces. All Clojure files in a workspace will be serviced by the clojure-lsp server running in that workspace. This behavior requires that you are opening workspaces with a valid Clojure project in the root (the directory must contain a deps.edn
, project.clj
or shadow-cljs.edn
file).
When set to \"when-file-opened-use-furthest-project\"
Calva will attempt to start the clojure-lsp server whenever a Clojure file is opened. The LSP server will be started in the outermost valid Clojure project or will fall back to starting in the workspace root if no valid Clojure project can be found. A directory is considered a Clojure project if it contains typical Clojure project files such as a deps.edn
, project.clj
, or shadow-cljs.edn
file. When working in a mono-repo style project or in a multi-workspace VS Code configuration you may have multiple LSP servers running, one for each independent Clojure project opened.
Opening files that do not belong to a workspace folder
When opening files that do not belong to any of the workspace folders currently open then Calva will fallback to starting the fallback clojure-lsp server
"},{"location":"clojure-lsp/#never","title":"\"never\"","text":"When set to \"never\"
Calva will never attempt to automatically start the clojure-lsp server. In this case you are responsible for manually starting the server. More advanced users might want to do this in order to have more control over which projects have a clojure-lsp server running for them. To manually start the clojure-lsp server you can run the calva.clojureLsp.start
or the calva.clojureLsp.manage
command and pick the project root. You can also click the clojure-lsp
status bar icon to open the Management Menu.
Additionally Calva has commands for:
Note that the download command will download the configured clojure-lsp version regardless if it is already installed or not. This can be useful when some earlier download has failed resulting in that clojure-lsp can't be started. NB: It will not download anything if calva.clojureLspPath
is set to something non-blank.
As a fallback behaviour Calva may start a clojure-lsp server in a temporary directory and use this to service lsp requests for clojure files that do not belong to a valid clojure project. This will show up in the management menu looking something like:
Any files that are handled by this server will have limited classpath analysis and lsp features. It is therefore recommended to setup your project as a clojure project (by creating a deps.edn
file in the root, for example).
In the status bar Calva will show an indicator with the clojure-lsp status. This status will track the currently open project, showing the status (stopped
, starting
or active
) for the relevant clojure-lsp server.
You can click on the status-bar item to open the clojure-lsp management menu which will look as follows:
The menu shows which clojure-lsp servers are active and which are stopped. Selecting a project will allow you to start/stop/restart the server for that project.
"},{"location":"clojure-lsp/#ignoring-lsp-cache-files","title":"Ignoring LSP cache files","text":"Clojure-lsp stores its project analysis information in your project. Git users can add these lines to their project root directory .gitignore
:
.lsp/.cache/\n.lsp/sqlite.*.db\n
"},{"location":"clojure-lsp/#configuration","title":"Configuration","text":"For information about how to configure clojure-lsp, see the settings page of the clojure-lsp docs.
"},{"location":"clojure-lsp/#changing-the-version-of-clojure-lsp-used-by-calva","title":"Changing the Version of Clojure-lsp Used by Calva","text":"By default, Calva will use the latest released clojure-lsp. You can change the version of clojure-lsp used by Calva by setting the calva.clojureLspVersion
property to a version of clojure-lsp found in its GitHub releases. This can be helpful if you're debugging an issue with clojure-lsp or you want to try out a feature of a new release that Calva does not yet use. However, you must remember to reset this setting in order for Calva to automatically use newer versions of clojure-lsp that are released with new versions of Calva.
Example:
\"calva.clojureLspVersion\": \"2021.04.07-16.34.10\"\n
Special \u201dversion\u201d values
Apart from the actual versions you can use two special values for this setting:
latest
: Will download and use the latest stable build of clojure-lsp, when one becomes available. This is the defaultnightly
: Will always download and use the latest nightly build, whether there is a new version available or not.You can set a path to a custom clojure-lsp to be used by Calva by configuring the calva.clojureLspPath
setting. This should be an absolute path to a native binary or JAR file.
Example:
\"calva.clojureLspPath\": \"/usr/local/bin/clojure-lsp\"\n
Will override any calva.clojureLspVersion
setting
When calva.clojureLspPath
is set, the binary at the path will be used uncoditionally, and the calva.clojureLspVersion
setting will be ignored.
clojure-lsp provides many useful [commands], and Calva has configuration for most of them. The clojure-lsp team works fast and sometimes Calva might miss some command. And Calva's configuration only really work for clojure-lsp commands that take no argument, or where it makes sense to prompt for the argument. Therefore Calva provides a generic command id, clojure-lsp.command
which can be used with keyboard shortcuts and that allow for providing arguments that way. (The command can be used from Joyride too, of course.)
When using the command, provide the args as an tuple of [command-name, arguments]
, where arguments
is an array of any arguments after file-uri, row, col
which are common for all clojure-lsp extra commands and are provided automatically by Calva, based on active text editor and where the cursor is. It can look like so when binding a shortcut for extract-function
:
{\n\"key\": \"ctrl+alt+r f\",\n\"command\": \"clojure-lsp.command\",\n\"args\": [\"extract-function\", [\"new-function\"]]\n},\n
Note that even though extract-function
takes only one argument, you should still provide it via an array.
If something doesn't seem to be working correctly, and you suspect the issue is related to clojure-lsp, a good place to start investigating is the request and response logs between the LSP client and server. In your settings, set clojure.trace.server
to verbose
, then in the VS Code output tab, select the Clojure Language Client
output channel.
It may be helpful to clear the output channel, then perform the action with which you're experiencing a problem, then read through the log for clues or paste the logs into a related issue in the Calva repo.
"},{"location":"clojure-lsp/#server-info-command","title":"Server Info Command","text":"You can run the Clojure-lsp Server Info
command to get information about the running clojure-lsp server, such as the version the server being used, the version of clj-kondo it's using, and more. This info is printed to the \"Calva says\" output channel.
You can open the clojure-lsp log file by running the command Calva Diagnostics: Open Clojure-lsp Log File
. The log file will only be opened with this command if the clojure-lsp server is running and has finished initializing. If you need to open the file when the server is failing to run or initialize, see the clojure-lsp docs for information on the file location.
If clojure-lsp fails to start with \u201cServer initialization failed\u201d messages, it could be because the path to your project contains non-ASCII characters, or that the system PATH variable has been corrupted. (Or something else, of course.)
See this issue for some findings about it: Issue #2251: Server initialization failed error
"},{"location":"clojure-lsp/#related","title":"Related","text":"See also:
Since ClojureDart is Clojure, Calva just works with it. Calva is also automatically configured to make VS COde treat .cljd
files as a Clojure code.
Similar to when using ClojureScript you will often find examples for Dart and Flutter written in, you guessed it, Dart. And then you will often wish there was a converter, because manually transpiling can be a bit tedious and error prone. Luckily you are in the Clojure community, and such a converter is provided:
There are several ways you can leverage this converter, and since you are using Calva, a very convenient way is available. There is a command Calva: Convert Dart code to Clojure/ClojureDart. This command takes whatever text is selected and uses DartClojure to convert it. Lacking a selection, the command will use the whole file.
The workflow demoed in the video is something like so:
NB: The conversion will not always work. DartCLojure is work in progress. See the project repo for limitations and scope. Often when conversion, the error message will give you a clue to what is problematic. Try adjust your code selection and you will probably be able to get at least some help from the converter.
Speaking of WIP...
","boost":4},{"location":"clojuredart/#work-in-progress","title":"Work in Progress","text":"ClojureDart is very new and being super actively developed. Some feature are still missing. Like a REPL. Once that is added we will also add ClojureDart jack-in and connect support to Calva.
","boost":4},{"location":"clojuredart/#happy-clojuredart-hacking","title":"Happy ClojureDart Hacking!","text":"Please feel welcome to the #clojuredart and #calva channel at the Clojurians Slack for questions, suggestions and support.
","boost":4},{"location":"clojuredocs/","title":"ClojureDocs integration","text":"clojuredocs.org is the goto place #1 for finding out more about Clojure core(-ish) functions, macros, etcetera. It contains the doc strings from the functions and adds crowd sourced examples of usage and see alsos. You can surf for quite long on that site without getting bored. \ud83d\ude04
You can surf ClojureDocs in CalvaCalva integrates this information in two ways:
ctrl+alt+r d
ctrl+alt+o d
That means that if you just want to glance at the examples, you look in the hover. And when you want to bring the examples to the REPL to play with them, you can do so very easily.
ClojureScript support
ClojureDocs information is available both for Clojure and ClojureScript files. However, clojuredocs.org only keeps info for Clojure. Thus: All information Calva shows about a symbol will be about the Clojure respresentation of that symbol. (The symbol might not even exist in ClojureScript.)
","boost":4},{"location":"clojuredocs/#clojuredocs-repl-surfing","title":"ClojureDocs REPL Surfing","text":"Since the ClojureDocs information includes see-alsos, you can go for super interactive ClojureDocs surfing right in the file you are editing. Say you have this function:
(defn trim-text\n\"Returns text without surrounding whitespace if not empty, otherwise nil\"\n[text]\n(let [trimmed-text (clojure.string/trim text)]\n(when-not (empty? trimmed-text)\ntrimmed-text)))\n
Then you hover on when-not
and scroll down a bit in the hover:
That first example would be interesting to play with, right? Click To Rich Comment and you will get:
(defn trim-text\n\"Returns text without surrounding whitespace if not empty, otherwise nil\"\n[text]\n(let [trimmed-text (clojure.string/trim text)]\n(when-not (empty? trimmed-text)\ntrimmed-text)))\n\n(comment\n;; = when-not - Example 1 = \n\n;; build tuples over sets with the same cardinality \n(map\n#(when-not (= %2 %3) [%1 %2 %3])\n(iterate inc 0) ; a lazy list of indices\n[:a :b :c]\n[:a :a :a])\n;;=> (nil [1 :b :a] [2 :c :a])\n\n;; See also:\nwhen\nwhen-let\nif\n)\n
There you can evaluate the (map ...)
form using alt+enter
, modify it and evaluate again. You can also hover over map
, iterate
, or any of the \u201dSee also:\u201d symbols to find more fun examples to play with. And so on and so forth.
See these two tweets for some videos of early versions of this functionality:
Please retweet!
","boost":4},{"location":"clojuredocs/#quirks","title":"Quirks","text":"Some of the ClojureDocs entries have text that is not really Clojure code, and sometimes even structural errors. This can break the structural integrity of your Clojure file. If you run into trouble trying to heal things, you can always use Undo until the Rich Comment is gone.
","boost":4},{"location":"commands-top10/","title":"The Top 10 Calva Commands","text":"There are not all that many Calva commands. You can learn them all if you like, but here are the most important ones to know about for effective Clojure/ClojureScript coding:
ctrl+w
(shift+alt+right
on Windows and Linux)alt+ctrl+c enter
, evaluates the namespace code in the active editor tab. This also loads any required namespaces, and generally gives Calva what it needs to work.ctrl+enter
finds the form from the cursor position, evaluates it and displays the result inline. Hit esc
to dismiss the results display.alt+enter
: inline evaluate the current top-level form. This also works inside (comment)
forms. Use it to (re)define vars and then inside comment forms you can verify that they do what you want them to do.escape
: (VIM Extension users should read Using Calva with the VIM Extension).There are also two commands for bringing over the current form and the current top level form over to the repl window:
ctrl+alt+c ctrl+alt+e
(ctrl+alt+c ctrl+alt+v
on Windows): to paste the current form in the REPL window.ctrl+alt+c ctrl+alt+space
: to paste the current top-level form in this windowYou can also switch the name space of the output/repl window to that of the current file: alt+ctrl+c alt+n
ctrl+alt+c p
. It's on by default. There is a status bar button showing the status and that also can be used to toggle the setting.ctrl+alt+c c
(current form), ctrl+alt+c ctrl+space
(current top level form)ctrl+alt+c r
ctrl+alt+c ctrl+alt+e
(ctrl+alt+c ctrl+alt+v
on Windows)ctrl+alt+c ctrl+alt+space
ctrl+alt+c t
ctrl+alt+c shift+t
ctrl+alt+c ctrl+alt+t
ctrl+alt+c ctrl+t
ctrl+alt+c s
.ctrl+alt+c .
See also:
Many projects grow out of the template phase and call for custom developer workflows involving application start commands, customized REPLs, and what have you. Even some templates add this kind of complexity. To make Jack-in usable for a broader set of projects, Calva has a setting keyed calva.replConnectSequences
which lets you configure one ore more connect sequences.
NB: Connect sequence configuration affects Calva's Jack-in menu in the following ways:
A connect sequence configures the following:
name
: (required) This will show up in the Jack-in quick-pick menu when you start Jack-in (see above).projectType
: (required) This is either \"Leiningen\u201d, \"deps.edn\", \"shadow-cljs\", \"lein-shadow\", \"Gradle\", \u201dgeneric\u201d, or \"custom\".autoSelectForJackIn
: A boolean. If true, this sequence will be automatically selected at Jack-in, suppressing the Project Type. Use together with projectRootPath
to also suppress the Project Root menu. Add usage of menuSelections
to go for a prompt-less REPL Jack-in. If you have more than one sequence with autoSelectForJackIn
set to true, the first one will be used.autoSelectForConnect
: A boolean. If true, this sequence will be automatically selected at Connect, suppressing the Project Type menu. Use together with projectRootPath
to also suppress the Project Root menu. If you have more than one sequence with autoSelectForConnect
set to true, the first one will be used.projectRootPath
: An array of path segments leading to the root of the project to which this connect sequence corresponds. Use together with autoSelectForJackIn
/autoSelectForConnect
to suppress the Project Root menu. The path can be absolute or relative to the workspace root. If there are several Workspace Folders, the workspace root is the path of the first folder, so relative paths will only work for this first folder.nReplPortFile
: An array of path segments with the project root-relative path to the nREPL port file for this connect sequence. E.g. For shadow-cljs this would be [\".shadow-cljs\", \"nrepl.port\"]
.afterCLJReplJackInCode
: Code to evaluate in the CLJ REPL once it has been created. You can use either a string or an array of strings. If you use an array, the strings will be joined with a newline character to form the resulting code.customJackInCommandLine
: A string with a command line that should be used to launch the REPL. See Custom Command Line, below.cljsType
: This can be either \"Figwheel Main\", \"shadow-cljs\", \"ClojureScript built-in for browser\", \"ClojureScript built-in for node\", \"lein-figwheel\", \"none\", or a dictionary configuring a custom type. If set to \"none\", Calva will skip connecting a ClojureScript repl. A custom type has the following fields:dependsOn
: (required) Calva will use this to determine which dependencies it will add when starting the project (Jacking in). This can be either \"Figwheel Main\", \"shadow-cljs\", \"ClojureScript built-in for browser\", \"ClojureScript built-in for node\", \"lein-figwheel\", or \u201dUser provided\u201d. If it is \"User provided\", then you need to provide the dependencies in the project or launch with an alias (deps.edn), profile (Leiningen), or build (shadow-cljs) that provides the dependencies needed.isStarted
: Boolean. For CLJS REPLs that Calva does not need to start, set this to true. (If you base your custom cljs repl on a shadow-cljs workflow, for instance.)startCode
: Clojure code to be evaluated to create and/or start your custom CLJS REPL.isReadyToStartRegExp
: A regular expression which, when matched in the stdout from the startCode evaluation, will make Calva continue with connecting the REPL, and to prompt the user to start the application. If omitted and there is startCode Calva will continue when that code is evaluated.openUrlRegExp
: A regular expression, matched against the stdout of cljsType evaluations, for extracting the URL with which the app can be started. The expression should have a capturing group named url
. E.g. \"Open URL: (?\\<url>S+)\"shouldOpenUrl
: Choose if Calva should automatically open the URL for you or not.connectCode
: (required) Clojure code to be evaluated to convert the REPL to a CLJS REPL that Calva can use to connect to the application. (For some setups this could also conditionally start the CLJS REPL. If so: startCode
should be omitted.)isConnectedRegExp
: (required) A regular expression which, when matched in the stdout
from the connectCode
evaluation, will tell Calva that the application is connected. The default is To quit, type: :cljs/quit
and you should leave it at that unless you know it won't work.printThisLineRegExp
: regular expression which, when matched in the stdout
from any code evaluations in the cljsType
, will make the matched text be printed to the Output window.buildsRequired
: Boolean. If the repl type requires that builds are started in order to connect to them, set this to true.menuSelections
: a dictionary with pre-filled-in selections for the Jack-in and Connect prompts, making Calva not prompt for that particular selection:leinProfiles
: At Jack-in to a Leiningen project, use these profiles to launch the repl.leinAlias
: At Jack-in to a Leiningen project, launch with this alias. Set to null
to launch with Calva's default task (a headless repl), w/o prompting.cljAliases
: At Jack-in to a deps.edn project, use these aliases to launch the repl.cljsLaunchBuilds
: The cljs builds to start/watch at Jack-in/connect.cljsDefaultBuild
: Which cljs build to attach to at the initial connect.jackInEnv
: An object with environment variables that will be merged with the global calva.jackInEnv
and then applied to the Jack-in process. The merge is very similar to how Clojure's merge
works. So for any common keys between the global setting and this one, the ones from this setting will win.The Calva built-in sequences also use this format, check them out to get a clearer picture of how these settings work.
Force the project type menu to show
The convenience of autoSelectForJackIn/Connect
can be an inconvenience when you want to use another project type/sequence for a project. For this reason, the calva.connect
and calva.jackIn
can be provided with an option disableAutoSelect
, which forces the project root and project type menus to show. See Options for the Connect Command and Options for the Jack-in Command for more on this.
Path segments
projectRootPath
and nReplPortFile
both take an array of path segments. This is to make the paths work cross-platform. If you can't be bothered splitting up the path in segments, put the whole path in the first segment, though please note that if you use Windows path separators, these will not work for users with Linux or macOS.
Custom command lines are there to bridge the gap to those situations where standard Jack-in command lines don't reach. Like:
A custom command line is executed from same directory as the REPL project root (See projectRootPath
, above), and can be as simple as my-repl-jack-in-command
. You can use a relative or absolute path to your command line.
If your custom command line starts a REPL of a project type that is not \u201dknown\u201d/built-in to Calva, use custom
as the projectType
for the connect sequence.
You can use placeholders in your command line, and Calva will substitute them before executing the command. All these placeholders will also be provided to your script via environment variables with the same names (except dashes will be underscores in the env variable names):
nREPL dependency versions:
JACK-IN-NREPL-VERSION
JACK-IN-CIDER-NREPL-VERSION
JACK-IN-CIDER-PIGGIEBACK-VERSION
Paths:
JACK-IN-PROJECT-ROOT-PATH
: (See projectRootPath
, above)JACK-IN-NREPL-PORT-FILE
: The path of the nREPL port file (see nReplPortFile
above)Depending on the project type Calva will also look for these placeholders:
JACK-IN-CLJ-MIDDLEWARE
: The nREPL middleware to be used for the Clojure REPLJACK-IN-CLJS-MIDDLEWARE
: The nREPL middleware to be used for the ClojureScript REPLJACK-IN-LEIN-PROFILES
: For Leiningen projects, the profiles selected by the userJACK-IN-LEIN-LAUNCH-ALIAS
: For Leiningen projects, the launch alias selected by the userJACK-IN-CLI-ALIASES
: For deps.edn projects, the aliases selected by the userJACK-IN-CLJS-LAUNCH-BUILDS
: For ClojureScript REPLs that configures builds, the builds selected by the userJACK-IN-NREPL-PORT
: For some project types (currently nbb
and Babashka
) Calva provided the TCP port they should use.Calva has a built-in jack-in sequence for starting a Babashka REPL and connect to it. It works as long as the bb
process is on the same host as VS Code/Calva is running. So if you want it to run in WSL, but VS Code is running on your computer you need to start bb
slightly differently. These settings in your VS Code settings file will give you a jack-in option that works for this:
\"calva.replConnectSequences\": [\n{\n\"name\": \"Bashbabka (WSL)\",\n\"projectType\": \"custom\",\n\"customJackInCommandLine\": \"bash -c 'bb --nrepl-server JACK-IN-NREPL-PORT'\",\n},\n],\n
If you place it in your user settings you will have access to it from any workspace.
","boost":6},{"location":"connect-sequences/#an-exampleskeleton-script","title":"An example/skeleton script","text":"This script doesn't actually start a REPL, it's provided more for giving you an idea about what it could look like, and as a starting point for your real scripts:
#!/usr/bin/env bb\n\n(require '[clojure.string :as str])\n\n(defn parse-args [args]\n(loop [args args\nparsed {}]\n(if (empty? args)\nparsed\n(let [[flag value & rest-args] args]\n(case flag\n\"--aliases\" (recur rest-args (assoc parsed :aliases value))\n\"--cider-nrepl-version\" (recur rest-args (assoc parsed :cider-nrepl-version value))\n(do (println \"Unknown parameter:\" flag) (System/exit 1)))))))\n\n(defn process-args [args]\n(let [aliases (str/split (:aliases args) #\",\")\ncider-nrepl-version (:cider-nrepl-version args)\nproject-root-path (System/getenv \"JACK_IN_PROJECT_ROOT_PATH\")]\n(println \"Aliases:\")\n(doseq [alias aliases]\n(println alias))\n(println \"CIDER nREPL version:\" cider-nrepl-version)\n(println \"JACK_IN_PROJECT_ROOT_PATH:\" project-root-path)))\n\n(def parsed-args (parse-args *command-line-args*))\n\n(when (= *file* (System/getProperty \"babashka.file\"))\n(process-args parsed-args))\n
It's written in Babashka to encourage you to write your shell scripts in a civilized language. \ud83d\ude00 See the article Changing my mind: Converting a script from bash to Babashka for a small success-story about this mindset. See also bash2bb.
The script reads JACK-IN-CLJS-LAUNCH-BUILDS
and JACK-IN-CIDER-NREPL-VERSION
from the command line, and JACK_IN_PROJECT_ROOT_PATH
from the environment. It could be configured for use in a custom connect sequence like this:
\"customJackInCommandLine\": \"../../custom-jack-in.bb --aliases JACK-IN-CLJS-LAUNCH-BUILDS --cider-nrepl-version JACK-IN-CIDER-NREPL-VERSION\",\n
Note how in this case the REPL is started two directories \u201ddown\u201d from the workspace root where the script resides.
","boost":6},{"location":"connect-sequences/#example-sequences","title":"Example Sequences","text":"Whether you just want to speed up your workflow or encode some workflow/mechanics into it, it's often the case that you can create a custom sequence that helps.
","boost":6},{"location":"connect-sequences/#minimal-menus-with-full-stack-shadow-cljs-repls","title":"Minimal menus with full stack shadow-cljs REPLs","text":"Minimize the amount of selecting from the Jack-in/Connect menu when working with a full-stack shadow-cljs + deps/lein project:
{\n\"name\": \"backend + frontend\",\n\"projectType\": \"shadow-cljs\",\n\"cljsType\": \"shadow-cljs\",\n\"menuSelections\": {\n\"cljsLaunchBuilds\": [\n\":app\",\n\":test\",\n],\n\"cljsDefaultBuild\": \":app\"\n}\n}\n
See shadow-cljs + Clojure with Calva: The basics for how Calva and nREPL work with ClojureScript.
","boost":6},{"location":"connect-sequences/#polylith","title":"Polylith","text":"This is the connect sequences used in the Polylith Real World App. The (start)
sequence lets you jack-in to the project, and starts the Real World App without any prompts. The (connect)
sequence can be used if you prefer to start the REPL manually, and want to connect without prompts.
\"calva.replConnectSequences\": [\n{\n\"projectType\": \"deps.edn\",\n\"afterCLJReplJackInCode\": \"(require '[dev.server] :reload) (in-ns 'dev.server) (start! 6003)\",\n\"name\": \"Polylith RealWorld Server REPL (start)\",\n\"autoSelectForJackIn\": true,\n\"projectRootPath\": [\".\"],\n\"cljsType\": \"none\",\n\"menuSelections\": {\n\"cljAliases\": [\"dev\", \"test\"]\n}\n},\n{\n\"projectType\": \"deps.edn\",\n\"name\": \"Polylith RealWorld Server REPL (connect)\",\n\"autoSelectForConnect\": true,\n\"projectRootPath\": [\".\"],\n\"cljsType\": \"none\",\n}\n],\n\"calva.autoConnectRepl\": true,\n
The calva.autoConnectRepl
, when set to true
, makes Calva, at project open, look for the nRepl port file and automatically connect the repl if the file exists. Therefore, you can leave the app running when you close the project in VS Code, and Calva will reconnect when you open the project again. (Alternatively, maybe you just need to reload the VS Code window and not lose the REPL state.)
Setting for a full-stack application. It starts the backend server when the CLJ REPL has started. Then proceeds to create a custom CLJS REPL (calling in to the application code for this). And then connects to it.
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Example Sequence\",\n\"projectType\": \"Clojure-CLI\",\n\"afterCLJReplJackInCode\": \"(go)\",\n\"cljsType\": {\n\"startCode\": \"(do (require '[cljs-test.main :refer :all])(start-nrepl+fig))\",\n\"isReadyToStartRegExp\": \"Prompt will show\",\n\"connectCode\": \"(do (use 'cljs-test.main) (cljs-repl))\",\n\"isConnectedRegExp\": \"To quit, type: :cljs/quit\",\n\"printThisLineRegExp\": \"\\\\[Figwheel\\\\] Starting Server at.*\"\n}\n}\n]\n}\n
","boost":6},{"location":"connect-sequences/#juxt-edge","title":"JUXT Edge","text":"Here is an example from the JUXT Edge project template. It adds two sequences, one for when only the Clojure REPL should be launched and one for when the customized Edge cljs repl should also be connected. The Edge backend + frontend sequence specifies that the web app should be opened by Calva, making cljs repl connection more stable, and also adds menuSelections
to skip the launch aliases prompt.
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Edge backend only\",\n\"projectType\": \"deps.edn\"\n},\n{\n\"name\": \"Edge backend + frontend\",\n\"projectType\": \"deps.edn\",\n\"cljsType\": {\n\"dependsOn\": \"Figwheel Main\",\n\"startCode\": \"(do (require 'dev-extras) (dev-extras/go) (println \\\"Edge Figwheel Main started\\\") ((resolve 'dev-extras/cljs-repl)))\",\n\"isReadyToStartRegExp\": \"Edge Figwheel Main started\",\n\"openUrlRegExp\": \"Website listening on: (?<url>\\\\S+)\",\n\"printThisLineRegExp\": \"\\\\[Edge\\\\]\",\n\"shouldOpenUrl\": true,\n\"connectCode\": \"(do (require 'dev-extras) ((resolve 'dev-extras/cljs-repl)))\",\n\"isConnectedRegExp\": \"To quit, type: :cljs/quit\",\n\"buildsRequired\": false\n},\n\"menuSelections\": {\n\"cljAliases\": [\n\"dev\",\n\"build\",\n\"dev/build\"\n],\n}\n}\n]\n}\n
","boost":6},{"location":"connect-sequences/#plain-depsedn","title":"Plain deps.edn","text":"A deps.edn sequence that does not promote the ClojureScript repl at all (leaving it a Clojure REPL), and leaves that up to you to do interactively. (Could be useful while you are developing a custom cljs repl.) The example is for when adapting a Figwheel Main repl.
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Do not promote to cljs\",\n\"projectType\": \"deps.edn\",\n\"cljsType\": {\n\"dependsOn\": \"Figwheel Main\",\n\"connectCode\": \"\\\"Don't promote me bro!\\\"\",\n\"isConnectedRegExp\": \"Don't promote me bro!\"\n}\n}\n]\n}\n
","boost":6},{"location":"connect/","title":"Connect Calva to Your Project","text":"When connected to your project's REPL Calva lets you evaluate code, supporting Interactive Programming. The REPL connection is also used to provide IDE functionality through the dynamic knowledge about the project that the REPL enables. The REPL communication depends on that your project has an nREPL server running, and that the cider-nrepl middleware is enabled.
For the easiest way to provide your project with these dependencies, the recommended way to connect is to use the so called Jack-in command.
","boost":7},{"location":"connect/#jack-in-let-calva-start-the-repl-for-you","title":"Jack-in: Let Calva Start the REPL For You","text":"This way Calva can make sure it is started with the dependencies needed for a working Clojure and/or ClojureScript session. This is often referred to as Jack in (because that is what it is called in CIDER).
Jack-in supports both CLJ and for CLJS, and has built-in configurations for Leiningen, deps.edn, shadow-cljs, Gradle projects, as well as for the CLJS repl types: Figwheel Main, lein-figwheel (legacy Figwheel), shadow-cljs, and ClojureScript built-ins for both browser and node.js. Using jack-in provides your development environment with all the dependencies you need for Calva to work.
It works like so:
ctrl+alt+c ctrl+alt+j
.See also: Workspace Layouts
About project roots
You must have a project file, such as project.clj
for Leiningen, or deps.edn
for deps.edn, or shadow-cljs.edn
for shadow-cljs, or settings.gradle
/settings.gradle.kts
for Gradle in the directory opened in VS Code in order for jack-in to work. If, after adding the project file, you experience an error during jack-in that says something could not be located, make sure you have the correct dependencies in your project file. For example, when using the Figwheel Main project type, you should have com.bhauman/figwheel-main
in your project dependencies.
See also below, regarding multiple projects in a workspace
","boost":7},{"location":"connect/#aliases-profiles-builds","title":"Aliases, Profiles, Builds","text":"When Jack-in starts it will depend on the project type, and whether ClojureScript is involved or not, and if it is, what kind of ClojureScript project, what will happen next. Calva will analyze the project files and will then give you prompts with selections based on what is found there.
You will need some basic knowledge about the project and the project type terminologies to answer the prompts.
There are ways to tell Calva the answers to these prompts beforehand, so that Jack-in can be a zero-prompting command. Read on.
","boost":7},{"location":"connect/#customizing-jack-in","title":"Customizing Jack-in","text":"The main mechanism for customizing your Jack-in, including automating menu selections, and custom CLJS REPL types is Custom Connect Sequences. See also Customizing Jack-in and Connect
","boost":7},{"location":"connect/#connecting-without-jack-in","title":"Connecting Without Jack-in","text":"If, for whatever reasons, you can't use Jack-in with your project (possibly because the REPL is started as part of some other job) all is not lost. Old fashioned Connect to a running REPL is still there for you. For all features to work in Calva while connecting to a running REPL, your environment needs to have REPL related dependencies set up.
However, just as before it can be tricky to get the dependencies right. Consider using Jack in to inform yourself on how to start your REPL to Calva's satisfaction. When you use Jack in, Calva starts a VS Code task for it and the command line used is displayed in the terminal pane used to handle the task. Reading that command line tells you what dependencies are needed for your project.
Even better: Copying that command line gives you the command to start the REPL with the correct dependencies.
All this said, I still recommend you challenge the conclusion that you can't use Jack-in.
Copy the Jack-in command line
There is a Calva command for copying the Jack-in command line to the clipboard. It will copy the command line including commands to change to the current REPL project root, avoiding hard-to-detect errors when starting the REPL in the wrong directory.
The Generic Project Type
A reason to use the connect to a running REPL way, can be that Calva does not have a built in connect sequence/project type for the particular REPL you want to connect to. Maybe it is something like Lingy which doesn't yet have a built in Calva connect sequence. As long as there is an nREPL server to connect to, you can Connect with Calva, using the Generic connect sequence/project type. (You can also create a connect sequence with a custom command line, and use Jack-in anyway.)
See also Customizing Jack-in and Connect
","boost":7},{"location":"connect/#starting-the-repl-from-application-code","title":"Starting the REPL from application code?","text":"If your project is setup so that the REPL server is started by the application code, you will need to get the cider-nrepl middleware in place. See the cider-nrepl docs about embedding nREPL in your application.
","boost":7},{"location":"connect/#auto-select-project-type-and-project-root","title":"Auto-select Project Type and Project Root","text":"You can make both Jack-in and Connect stop prompting you for project type and project root path in projects where you always want to use the same. See Connect Sequences.
","boost":7},{"location":"connect/#monorepos-multiple-clojure-projects-in-one-workspace","title":"Monorepos / multiple Clojure projects in one workspace","text":"If the workspace is a monorepo, Polylith repo or just a repository with more than one Clojure project, Calva will start the connect sequence with prompting for which project to start/connect to.
","boost":7},{"location":"connect/#shadow-cljs","title":"shadow-cljs","text":"Please see the shadow-cljs page.
","boost":7},{"location":"connect/#troubleshooting","title":"Troubleshooting","text":"","boost":7},{"location":"connect/#jack-in-and-main-opts","title":"Jack-in and:main-opts
","text":"When Calva starts the project REPL and connects to it (a.k.a. Jack-in), this is done by starting an nREPL server. For deps.edn projects this by default means that Calva will add -m ...
with options that starts the server.
However: If you choose an alias at Jack-in that specifies :main-opts
, it will make the Clojure CLI to add main opts and Calva will then not override these by adding -m ...
to the command line. This means that an alias that specify :main-opts
must result in an nREPL server being started, or else Calva won't have a server to connect to. Calva won't further analyze this, but will just warn you at Jack-in.
If you don't know if an alias starts an nREPL server or not, by all means, try it, if you have reasons for using that alias. You will notice if Jack-in works or not. If it doesn't work, you will need to run without that alias, or fix what happens when that alias is used so that an nREPL server is started. See https://nrepl.org/nrepl/usage/server.html about ways to do this.
","boost":7},{"location":"connect/#command-not-found-errors-when-jacking-in","title":"Command Not Found Errors When Jacking In","text":"If you get command not found
error when Calva tries to start your project, and you know you have the command installed, it's probably because VS Code starts from an environment where the command is not on the $PATH
. It can look like so:
lein update-in :dependencies conj '[nrepl,\"0.8.3\"]' -- update-in :plugins conj '[cider/cider-nrepl,\"0.25.8\"]' -- update-in '[:repl-options,:nrepl-middleware]' conj '[\"cider.nrepl/cider-middleware\"]' -- repl :headless\n/bin/sh: lein: command not found\nJack-in process exited. Status: 127\n
The fix is to always start VS Code from the command line:
$ code\n
You might need to first run the Shell Command: Install code
command in PATH.
This will also make sure your REPL has access to the environment you probably expect it to have access to. See below.
","boost":7},{"location":"connect/#go-to-definition-not-working-for-java-definitions","title":"Go to Definition Not Working for Java Definitions","text":"On some systems, the Java source may not be installed along with the JDK. The source must be present on your system in order to navigate to Java definitions. See this comment for more details.
","boost":7},{"location":"connect/#environment-variables-are-not-readable-from-repl","title":"Environment Variables Are Not Readable From REPL","text":"If you've added environment variables in your OS, such as in your ~/.bashrc
file (Linux), in order for them to be read in a REPL created by Calva's jackin command, VS Code must be started from a shell where the environment variables are defined. For example, if you can open a bash terminal and run echo $SOME_VAR
and see the value there, then open VS Code from that terminal with code <project path>
.
It may be helpful to view the messages sent between nREPL and Calva when troubleshooting an issue related to the REPL. See how to do that here.
","boost":7},{"location":"contribute/","title":"Contribute to Calva","text":"There are many ways to contribute:
#calva
channelBe creative!
"},{"location":"contribute/#please-star-the-calva-repo","title":"Please star the Calva repo!","text":"Happy Coding! \u2764\ufe0f
"},{"location":"custom-commands/","title":"Custom REPL Commands","text":"Calva supports configuration of custom command snippets that you can evaluate in the REPL at will. This is useful if your workflow has you repeatedly evaluating a particular piece of code. There are two ways to use these:
calva.customREPLCommandSnippets
to configure it. Then either bind keyboard shortcuts to them or use the command Run Custom REPL Command to access it. The command will give you a menu with the snippets you have configured.Joyride
For some use cases you might be better served by/want to combine these with using the VS Code Extension API, and that of Calva, or any other extension, through Joyride.
The calva.customREPLCommandSnippets
is an array of objects with the following fields (required fields in bold):
name
: The name of the snippet as it will appear in the picker menusnippet
: The code that will be evaluatedkey
: A key can be used to reference the snippet from Run Custom REPL Command keyboard shortcut arguments. It will also be used in the quick-pick menu.ns
: A namespace to evaluate the command in. If omitted the command will be executed in the namespace of the current editor.repl
: Which repl session to use for the evaluation. Either \"clj\"
or \"cljs\"
. Omit if you want to use the session of the current editor.evaluationSendCodeToOutputWindow
: (default true
) Whether the evaluated code should be echoed to the Output/REPL window.There are also substitutions available, which will take elements from the current state of Calva and splice them in to the text of your command before executing it. They are
$line
: Current line number in editor$column
: Current column number in editor$file
: Full name of the current file edited$file-text
: The text of the current file edited$ns
: The namespace used for evaluating the command$editor-ns
: The namespace of the editor from which the command was run$selection
: The currently selected text$current-form
: The text of the current form$current-pair
: The text of the current pair if in a binding, otherwise empty string$enclosing-form
: The text of the current enclosing form$top-level-form
The text of the current top level form$current-fn
: The sexpr/form at call position in the current list, e.g. str
with (defn foo [] (str \"foo\" \"bar|\"))
$top-level-defined-symbol
: The second symbol of the top level form, e.g. foo
with (defn foo [] (str \"foo\" \"bar|\"))
$head
: The text between the start of the current list to the cursor$tail
: The text between the cursor and the end of the current listSettings from your User (global) level and the workspace are merged.
With these User settings:
\"calva.customREPLCommandSnippets\": [\n{\n\"name\": \"Call Current Form\",\n\"key\": \"c\",\n\"snippet\": \"($current-form)\"\n},\n{\n\"name\": \"Call Current Top Level Form\",\n\"key\": \"t\",\n\"snippet\": \"($top-level-form)\"\n},\n{\n\"name\": \"CLJ Test Top Level Defined Symbol\",\n\"repl\": \"clj\",\n\"snippet\": \"(clojure.test/test-var #'$top-level-defined-symbol)\"\n},\n{\n\"name\": \"CLJS Test Top Level Defined Symbol\",\n\"repl\": \"cljs\",\n\"snippet\": \"(cljs.test/test-var #'$top-level-defined-symbol)\",\n\"key\": \"tab\"\n}\n],\n
And these Workspace settings:
\"calva.customREPLCommandSnippets\": [\n{\n\"name\": \"Remount CLJS App\",\n\"key\": \"r\",\n\"repl\": \"cljs\",\n\"ns\": \"example.app\",\n\"snippet\": \"(start)\"\n}\n],\n
Issuing Run Custom REPL Command will then render this VS Code menu:
The default keyboard shortcut for the command is ctrl+alt+space space
. (Beware: on MacOS it may conflict with the default shortuct for Input Sources - Select next source in Input menu.)
There are four ways to bind shortcuts to custom commands:
key
shortcut. These are predefined as ctrl+alt+space <something>
, where <something>
is one of:0
through 9
a
through z
right
, left
, up
, or down
tab
, backspace
, ,
, .
, or -
calva.runCustomREPLCommand
to a shortcut with whatever code you want to evaluate in the args
slot. You have access to the substitution variables here as well.calva.runCustomREPLCommand
to a keyboard shortcut referencing the key
of one of your calva.customREPLCommandSnippets
. (If not using any of the key
s mentioned in 1.)calva.runCustomREPLCommand
to a shortcut with a customREPLCommandSnippets
in the args
slot. You have access to the substitution variables here as well.Here's an example shortcut entry for the 4th option:
{\n\"key\": \"ctrl+cmd+u alt+enter\",\n\"command\": \"calva.runCustomREPLCommand\",\n\"args\": {\n\"ns\": \"user\",\n\"snippet\": \"$current-form\",\n}\n},\n
This would evaluate the current form in the user
namespace. Please note that this Custom REPL Command will not show up in the custom commands menu mentioned above.
Calva supports custom snippets that will display their result inside the tooltip. They will only work when connected to a repl, since they eval code in it. This is mostly useful for tooling authors that want to integrate with calva. Be careful with these, since they will be executed anytime Calva displays a tooltip. So they should be fast and probably not have any side effects.
The hover snippets accept the same inputs as the Custom REPL Commands, except for the hotkey:
\"calva.customREPLHoverSnippets\": [\n{\n\"name\": \"eval text on hover\",\n\"repl\": \"clj\",\n\"ns\": \"example.app\",\n\"snippet\": \"(str \\\"$hover-text\\\")\"\n}\n]\n
With this setting anything the mouse is over will also be shown inside its tooltip. There are now also hover-
versions of most substitutions. Those currently only work inside the hover snippets.
:customREPLCommandSnippets
and :customREPLHoverSnippets
can be also be configured in your user config at .config/calva/config.edn
realative to your system home directory, or .calva/config.edn
relative to the workspace root. Three things to note about this:
.calva/config.edn
will be automatically noticed by Calva, and refresh the config. This will not happen with the user config file.:name
entry, and if you change the name, the old entry won't be removed until the VS Code window is reloaded.As for 2.: There is a command Calva: Refresh REPL snippets from User config.edn.
There is also a command to open the User config.edn, for convenience: Calva: Open REPL snippets User config.edn. This command creates the file if it doesn't previously exist.
","boost":4},{"location":"custom-commands/#snippets-inside-deps","title":"Snippets Inside Deps","text":"A new experimental feature lets library authors ship snippets inside their jar files. These accept the same options as above but should be placed in \"resources/calva.exports/config.edn\" inside the jar.
{:customREPLCommandSnippets\n[{:name \"edn test\"\n:key \"a\"\n:snippet ($current-form)}]\n:customREPLHoverSnippets\n[{:name \"edn hover\"\n:snippet (str \"$hover-tex\")}\n{:name \"edn hover show val\"\n:snippet (str \"### EDN show val\\n```clojure\\n\" (pr-str (eval (symbol (str \"$ns\" \"/\" \"$hover-top-level-defined-symbol\")))) \"\\n```\")}]}\n
","boost":4},{"location":"customizing-jack-in-and-connect/","title":"Customize Jack-in and Connect","text":"Since Jack-in and connect both are about connecting the REPL, and only differ in how the REPL is started, many settings and configuration points are shared between the two concepts. A major customization point is Custom Connect Sequences, which are relevant for both Jack-in and Standalone Connect scenarios.
This page lists some more Jack-in and Connect configuration options.
","boost":7},{"location":"customizing-jack-in-and-connect/#auto-evaluate-code-on-connect","title":"Auto-evaluate Code on Connect","text":"You can have Calva evaluate code whenever a REPL has been connected via the calva.autoEvaluateCode.onConnect
setting. It has two entries clj
and cljs
:
clj
: \"Code to evaluate when the Clojure REPL has been connected.repl-requires
/REPL utilities (like source
, doc
, etcetera). (Note that there is also a command to do this on demand.).afterCLJReplJackInCode
in any connect sequence used.cljs
: Code to evaluate when the ClojureScript REPL has been connected.repl-requires
/REPL utilities (like source
, doc
, etcetera). (Note that there is also a command to do this on demand.).clj
.Set either of these to null
to disable the feature for that REPL type. (The Settings linter will complain, but it works.)
For Clojure this is in addition to afterCLJReplJackInCode
There are two mechanisms for evaluating code when a Clojure REPL is connected. The afterCLJReplJackInCode
setting of custom connect sequences, and this calva.autoEvaluateCode.onConnect.clj
setting. There is no fundamental difference between them. This one has a default function of auto-refering in the Clojure REPL utilities. And it will be run before the connect sequence after-Jack-in code.
All configured code is concatenated
If you configure this both in User/global settings and in a Workspace, the workspace configured code will be concatenated on the user level code. Meaning both code snippets will be evaluated, first the User level code, then the Workspace level code. Also null
disables the feature:
null
in the User level code, you will disable the onConnect code evaluation for all workspaces that do not configure code for this.null
. You can also make Calva auto-evaluate code when a file has been loaded in the REPL (via the Calva command for loading files). You add code for this via the calva.autoEvaluateCode.onFileLoaded
setting. Like with onConnect
you provide code for clj
and cljs
separately.
onConnect
.If there is an nRepl port file, Calva will use it and not prompt for host:port
when connecting. You can make Calva prompt for this by setting the boolean config calva.autoSelectNReplPortFromPortFile
to false
.
With the setting calva.autoConnectRepl
you can make Calva automatically connect the REPL if there is an nRepl port file present when the project is opened.
With this and the below mentioned auto-select options you can make connect a prompt-less experience. See: Connect Sequences.
","boost":7},{"location":"customizing-jack-in-and-connect/#options-for-the-connect-command","title":"Options for the Connect Command","text":"The calva.connect
command takes an optional options argument defined like so:
options?: {\nhost?: string;\nport?: string;\nconnectSequence?: string | ReplConnectSequence;\ndisableAutoSelect?: boolean;\n}\n
Where ReplConnectSequence
is a Connect Sequences. If you provide a string it needs to match against a built-in or custom connect sequence. With disableAutoSelect
you can force the connect menus to be provided even if a custom connect sequence is set to be autoSelected.
You can provide these options from keyboard shortcuts or from Joyride scripts.
Here's a keyboard shortcut for connecting to a running REPL bypassing any connect sequence with autoSelectForConnect
.
{\n\"command\": \"calva.connect\",\n\"args\": {\"disableAutoSelect\": true},\n\"key\": \"ctrl+alt+c shift+c\",\n},\n
A Joyride command for connecting to a REPL on port 55555, without being asked for project type:
(vscode/commands.executeCommand \"calva.connect\" (clj->js {:port \"55555\" :connectSequence \"Generic\"}))\n
","boost":7},{"location":"customizing-jack-in-and-connect/#customizing-jack-in","title":"Customizing Jack-in","text":"The main mechanism for customizing your Jack-in, including automating menu selections, and custom CLJS REPL types is Custom Connect Sequences.
There are also these settings:
calva.jackInEnv
: An object with environment variables that will be added to the environment of the Jack-in process.calva.myCljAliases
: An array of deps.edn
aliases not found in the project file. Use this to tell Calva Jack-in to launch your REPL using your user defined aliases.calva.myLeinProfiles
: An array of Leiningen profiles not found in project.clj
. Use this to tell Calva Jack-in to launch your REPL using your user defined profiles.calva.openBrowserWhenFigwheelStarted
: For Legacy Figwheel only. A boolean controlling if Calva should automatically launch your ClojureScript app, once it is compiled by Figwheel. Defaults to true
.calva.depsEdnJackInExecutable
: A string which should either be clojure
or deps.clj
, or clojure or deps.clj
(default). It determines which executable Calva Jack-in should use for starting a deps.edn
project. With this setting at its default, clojure or deps.clj
, Calva will test if the clojure
executable works, and use it if it does, otherwise deps.clj
will be used, which is bundled with Calva.Note
When processing the calva.jackInEnv
setting you can refer to existing ENV variables with ${env:VARIABLE}
.
The calva.jackIn
command takes an optional options argument defined like so:
options?: {\nconnectSequence?: string | ReplConnectSequence;\ndisableAutoSelect?: boolean;\n}\n
Where ReplConnectSequence
is a Connect Sequences. If you provide a string it needs to match against a built-in or custom connect sequence. With disableAutoSelect
you can force the jack-in menus to be provided even if a custom connect sequence is set to be autoSelected.
You can provide these options from keyboard shortcuts or from Joyride scripts.
Here's a keyboard shortcut for connecting to a running REPL bypassing any connect sequence with autoSelectForConnect
.
{\n\"command\": \"calva.jackIn\",\n\"args\": {\"disableAutoSelect\": true},\n\"key\": \"ctrl+alt+c shift+j\",\n},\n
A Joyride command for starting a deps.edn
REPL for a project in the root of the workspace.
(vscode/commands.executeCommand\n\"calva.jackIn\"\n(clj->js {:connectSequence {:projectType \"deps.edn\"\n:projectRootPath [\".\"]}}))\n
It will prompt for any aliases it finds in the deps.edn
file.
If your project is setup so that the REPL server is started by the application code, you will need to get the cider-nrepl middleware in place. See the cider-nrepl docs about embedding nREPL in your application.
","boost":7},{"location":"customizing-jack-in-and-connect/#auto-select-project-type-and-project-root","title":"Auto-select Project Type and Project Root","text":"You can make both Jack-in and Connect stop prompting you for project type and project root path in projects where you always want to use the same. See Connect Sequences.
","boost":7},{"location":"customizing-jack-in-and-connect/#project-roots-search-globing","title":"Project roots search globing","text":"When searching for project roots in your workspace, Calva will glob for all files matching project.clj
, deps.edn
, or shadow-cljs.edn
. This is done using VS Code's workspace search engine, and is very efficient. However, in a large monorepo, it is still a substantial task. In order to not waste resources Calva will exclude any directories in the setting calva.projectRootsSearchExclude
.
Exclude entry globs
Each entry is a partial glob and will be part of a resulting glob of the form **/{glob1,glob2,...,globN}
. This means that all directories in the workspace matching an entry will be excluded, regardless of where in the workspace they reside.
It may be helpful to view the messages sent between nREPL and Calva when troubleshooting an issue related to the REPL. See how to do that here.
","boost":7},{"location":"customizing/","title":"Customizing Calva","text":"Don't like the defaults? On this page we can collect some of the customizations that people have done, and maybe write a thing or two about it some day.
Tip for VS Code newcomers: The search box in Settings is your friend. Also, some Calva settings are more complex than the Settings UI can handle. VS Code will then show you a link to settings.json
. And VS Code's built-in json
extension is awesome. To add settings for Calva's Pretty Printing, for example, search for \u201dprettyprint\u201d in VS Code Settings and follow the link to settings.json
. Start typing \u201dcalvapretty\u201d until auto-complete suggests calva.prettyPrintingOptions
. Press ENTER and VS Code will fill in these defaults:
\"calva.prettyPrintingOptions\": {\n\"enabled\": true,\n\"printEngine\": \"pprint\",\n\"width\": 40\n},\n
"},{"location":"customizing/#clojure-defaults","title":"Clojure Defaults","text":"Calva sets some VS Code settings for all Clojure files. Some of these are needed for Calva to function correctly, which should not be tampered with unless you really know what you are doing, and some of them are convenient defaults. If you add a setting to your settings.json
and accept the snippet help you get when you type \"[clojure]\"
, you will get the Calva defaults pasted:
\"[clojure]\": {\n\"editor.wordSeparators\": \"\\t ()\\\"':,;~@#$%^&{}[]`\",\n\"editor.autoClosingBrackets\": \"always\",\n\"editor.autoClosingQuotes\": \"always\",\n\"editor.formatOnType\": true,\n\"editor.autoIndent\": \"full\",\n\"editor.formatOnPaste\": true,\n\"editor.matchBrackets\": \"never\",\n\"editor.renderIndentGuides\": false,\n\"editor.parameterHints.enabled\": false\n}\n
Note
The above editor.wordSeparators
setting establish Clojure word boundaries. E.g -
is considered to be part of words. This affects what happens when double-clicking symbols and other things. If you want to include -
or something else as a word boundary, just add it to the setting.
Calva's pretty printing mode can be configured a bit. See Pretty Printing.
"},{"location":"customizing/#calva-highlight","title":"Calva Highlight","text":"This is highly customizable. See Syntax highlighting
"},{"location":"customizing/#color-customizations","title":"Color customizations","text":"Calva defines a set of themable colors which can be provided by the user using workbench.colorCustomizations.
\"workbench.colorCustomizations\": {\n\"calva.inlineErrorForegroundColor\": \"#ff0000\",\n\"calva.inlineForegroundColor\": \"#ff9000\"\n}\n
"},{"location":"customizing/#automatic-parameter-hints-poppup","title":"Automatic Parameter Hints Poppup","text":"Calva has helpful parameter hints to aid when typing function calls. They look like so:
To have the hints automatically pop up when you are typing, set editor.parameterHints.enabled
to true
in the above [clojure]
scoped setting. (To call them up on demand the default VS Code keybindings are cmd+shift+space
on Mac and ctrl+shift+space
on Linux/Windows.)
See Formatting for information on how to configure this.
"},{"location":"customizing/#jack-in-and-connect","title":"Jack-in and Connect","text":"Jack-in and Connect are very customizable through Custom Connect Sequences.
"},{"location":"customizing/#jack-in-dependency-versions","title":"Jack-in Dependency Versions","text":"Calva Jack-in injects the following dependencies in order for the REPL session to support IDE features
The versions used are configurable via the VS Code settings calva.jackInDependencyVersions
.
Most of Calva's commands have default keybindings. They are only defaults, though, and you can change keybindings as you wish. To facilitate precision in binding keys Calva keeps some when clause contexts updated.
"},{"location":"customizing/#when-clause-contexts","title":"When Clause Contexts","text":"The following contexts are available with Calva:
calva:keybindingsEnabled
: a master switch that you find in the settingsparedit:keyMap
: strict
, original
, or none
from the corresponding Calva setting (see Paredit)calva:connected
: true
when Calva is connected to a REPL (there is also calva:connecting
|| calva:launching
)calva:outputWindowActive
: true
when the Output/REPL window has input focuscalva:replHistoryCommandsActive
: true
when the cursor is in the Output/REPL window at the top level after the last promptcalva:replWindowSubmitOnEnter
: true
when the cursor is adjacent after the last top level form in the Output/REPL windowcalva:cursorInString
: true
when the cursor/caret is in a string or a regexpcalva:cursorInComment
: true
when the cursor is in, or adjacent to a line commentcalva:cursorBeforeComment
: true
when the cursor is adjacent before a line commentcalva:cursorAfterComment
: true
when the cursor is adjacent after a line commentcalva:cursorAtStartOfLine
: true
when the cursor is at the start of a line including any leading whitespacecalva:cursorAtEndOfLine
: true
when the cursor is at the end of a line including any trailing whitespaceHere is a collection of custom keybindings from here and there.
ctrl+alt+...
key bindings with ctrl+shift+...
, for keyboards lacking alt
key: this gistctrl+alt+c
to just alt+v
: WebWItch's keybindings.json (Please note, that alt+v
does not work for some locales, but for when it works it is much less clunky than the default prefix).ctrl+,
: manas_marthi's keybindingsAre you a vim extension user? See: Using with VIM extension.
"},{"location":"customizing/#move-by-word","title":"Move by word","text":"By default Calva changes the move-by-word key bindings to move by sexpr/form when the cursor is in structural Clojure code. Within line comments the editor default word movement is active.
If you want the VS Code default word movement shortcuts, use these settings:
{\n\"key\": \"ctrl+right\",\n\"win\": \"ctrl+right\",\n\"mac\": \"alt+right\",\n\"command\": \"cursorWordRight\"\n},\n{\n\"key\": \"ctrl+left\",\n\"win\": \"ctrl+left\",\n\"mac\": \"alt+left\",\n\"command\": \"cursorWordLeft\"\n},\n{\n\"key\": \"ctrl+right\",\n\"mac\": \"ctrl+right\",\n\"win\": \"alt+right\",\n\"command\": \"paredit.forwardSexp\",\n\"when\": \"calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+left\",\n\"mac\": \"ctrl+left\",\n\"win\": \"alt+left\",\n\"command\": \"paredit.backwardSexp\",\n\"when\": \"calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/\"\n}\n
Use it as an inspiration for customizing things to your own liking. \ud83d\ude04
"},{"location":"customizing/#wrap-using-like-cursive","title":"Wrap using(
, [
, {
(like Cursive)","text":"Something I use in IntelliJ/Cursive is the ability to select an expression and hit one of (
, [
, {
to wrap it. And after wrapping the expression I don't want the selection anymore, so if I were wrapping (foo)
then I would want to get ( | (foo))
where |
would be my cursor.
Here's how you can make this work with Calva Paredit: Update all of the Paredit: Wrap Around ...
commands so that their respective shortcuts are the wrappers themselves and update the when
clause to include editorHasSelection
(otherwise when you open a paren the next expression would get slurped in).
The change would look like this in your keybindings.json
:
{\n\"key\": \"shift+9\",\n\"command\": \"paredit.wrapAroundParens\",\n\"when\": \"editorTextFocus && editorHasSelection && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"[\",\n\"command\": \"paredit.wrapAroundSquare\",\n\"when\": \"editorHasSelection && editorTextFocus && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"shift+[\",\n\"command\": \"paredit.wrapAroundCurly\",\n\"when\": \"editorHasSelection && editorTextFocus && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n}\n
"},{"location":"debugger/","title":"Debugger","text":"Calva comes with a powerful expression-based debugger, inspired by Cider's debugger, and using the same underlying library, cider-nrepl. We hope you love it!
Note
The debugger currently does not support ClojureScript. Calva's debugger utilizes cider-nrepl for debugging. See this Cider issue for more information.
"},{"location":"debugger/#features","title":"Features","text":""},{"location":"debugger/#current","title":"Current","text":"ctrl+alt+c i
#dbg
(as opposed to the above command)#break
The debugger itself relies pretty heavily on cider-nrepl, as do other parts of Calva. This library is loaded as a dependency when you use Calva Jack-in. If you are not using Calva Jack-in, you can add these dependencies in your project definition or user profile. See the Calva Jack-in guide for more information.
"},{"location":"debugger/#using-the-debugger","title":"Using the Debugger","text":"If you're new to Clojure or expression-based debuggers, this debugger may function differently than what you're used to. Instead of placing breakpoints in the side margin and then hitting F5 to start debugging, you instead use Clojure reader tags, #break
and #dbg
, to denote breakpoints anywhere in a Clojure form. When you evaluate a call to a function that has been evaluated with that reader tag, the debugger will start when execution reaches the first breakpoint. There's also a convenience command to instrument functions. Read below about both options.
Note
The debugger is not configured via a launch.json
file, and is not started in the same way as you may be used to when working with other languages in VS Code. The debugger is used by way of the REPL. If you are new to Clojure, please visit the Getting Started section of the documentation and get familiar with evaluating code using the REPL before using the debugger.
You can instrument a top level function for debugging with ctrl+alt+c i
. This places invisible breakpoints throughout the function where pausing makes sense. When you evaluate a call to this function, the debugger will start and execution will pause at the first breakpoint. Annotations show the value of the form at the cursor.
A border is placed around the definition of the instrumented function and its references to show that it's instrumented. You can remove instrumentation by evaluating the function again normally, such as with alt+enter
.
#break
","text":"You can insert a breakpoint manually into any code by placing a #break
in front of the form where you want execution to pause, and then evaluating the top level form with alt+enter
. When you evaluate a call to this code the VS Code debugger will start, the cursor will move to right after the form that's preceded by #break
, and the line will be highlighted to show execution is paused there.
Note
Code will be executed up to and including the form after the breakpoint.
"},{"location":"debugger/#conditional-breakpoints","title":"Conditional Breakpoints","text":"You can set conditional breakpoints by adding metadata before the form that the #break
applies to.
(defn print-nums [n]\n(dotimes [i n]\n#break ^{:break/when (= i 7)} ;; This breakpoint will only be hit when i equals 7\n(prn i)))\n
"},{"location":"debugger/#instrumenting-a-form-with-dbg","title":"Instrumenting a Form with #dbg
","text":"Adding #dbg
before a form then evaluating the form with alt+enter
will instrument the form. This has the same effect as using the instrument command.
When execution is paused at a breakpoint, you can evaluate code in that context. This can be done in the editor or in the REPL window, as usual.
"},{"location":"debugger/#viewing-variable-values","title":"Viewing Variable Values","text":"While debugging, you can view the values of variables in VS Code's debugger side pane. You can also view values by hovering over the variables in the editor. Currently, values for collections and maps are shown as strings, but we plan to make them structured in the future. For now, if you want to see the value of a large structured variable, you can evaluate the variable from the editor or from the REPL window.
"},{"location":"debugger/#viewing-the-call-stack","title":"Viewing the Call Stack","text":"While debugging, you can view the call stack in VS Code's call stack side pane. Clicking the stack frames will show the related line of code in an editor.
Note
You may only see one stack frame in the call stack side pane, as the change for adding additional frames was rolled back due to an issue. You can follow the change for this at #1150.
"},{"location":"debugger/#stepping-commands","title":"Stepping Commands","text":"You can use VS Code's debugger UI to advance execution while debugging.
Note
Clicking restart does nothing, since this functionality does not make sense for our debugger.
One construct where the debugger is limited is loop
/recur
. As recur always has to appear in a tail-position inside a loop
or a fn
and the debugger uses macros to interleave breakpoints in the forms, it might happen that a recur
no longer appears in a tail position. In that case we have to avoid setting up the breakpoint. An example of such a case is:
(loop [i 0]\n#break\n(when (< i 10)\n(println i)\n(recur (inc i))))\n
Here the breakpoint is exactly in front of a form that contains as its last expression a recur
which is wrapped in a loop. This breakpoint has no effect. This does not mean you cannot use the debugger with loop
, it just means you have to set your debug statements more carefully.
When you load a file, any breakpoints that were previously set in functions will be unset. If you have the \"Eval On Save\" setting enabled, your file is also loaded with each save, therefore saving the file will remove breakpoints previously set.
"},{"location":"debugger/#troubleshooting","title":"Troubleshooting","text":""},{"location":"debugger/#debugger-hangs-when-stepping-over-infinite-seqs","title":"Debugger hangs when stepping over infinite seqs","text":"This is because the debugger tries to evaluate the form when it's stepped over, and if clojure.core/*print-length*
is set to nil
as it is by default, evaluation will never complete. If you want to debug a form with an infinite seq, make sure to set *print-length*
beforehand. For example:
(set! *print-length* 3)\n;; Or, to be more precise\n(set! clojure.core/*print-length* 3)\n
Calva does not set this for you during debug mode, instead leaving it up to you to decide the value.
"},{"location":"debugger/#my-breakpoint-isnt-being-hit","title":"My breakpoint isn't being hit","text":"It's likely that your breakpoint is in a place that cider-nrepl does not see as an appropriate place to break execution. For example, if you put a breakpoint before a literal number, it will not be hit, because there's no need to show the value of a literal.
(defn simple [x]\n(+ 1 #break 1)) ;; This breakpoint will not be hit\n
Another possible issue is that you're loading the file again after setting breakpoints, which unsets them. See Loading the File and \"Eval On Save\" under Caveats.
"},{"location":"debugger/#my-breakpoint-in-a-test-isnt-being-hit","title":"My breakpoint in a test isn't being hit","text":"If you're using the test commands like \"Run current test\" to run your tests, breakpoints will not be hit. This is because Calva loads the file before running the tests to make sure the latest version of test code is being run, and when the file is loaded, breakpoints are unset.
If you want a breakpoint to work within the test, evaluate the test form with a breakpoint tag in it, then call the test directly.
"},{"location":"debugger/#no-reader-function-for-tag-error","title":"\"No reader function for tag\" error","text":"If you get an error like this, it's likely that you connected to a REPL instead of jacking in, and you don't have the proper dependencies loaded in your REPL. You can run the command \"Copy Jack-in Command Line to Clipboard\" to see what command would be run if you jacked in.
Most importantly, make sure you have cider/cider-nrepl
as a dependency, and cider.nrepl/cider-middleware
as middleware loaded in your REPL. For example, this is a jack-in command line for a deps.edn project:
clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,\"0.8.3\"},cider/cider-nrepl {:mvn/version,\"0.25.8\"}}}' -m nrepl.cmdline --middleware \"[cider.nrepl/cider-middleware]\"\n
"},{"location":"debugger/#passing-options-to-the-repl-jvm","title":"Passing options to the REPL JVM","text":"There are times when Clojure debugging tools are not enough or not right for the job. This is usually true when use an (open source) Java library and you want to set some breakpoints in Java code. For those cases and others, you need to start the JVM in debug mode.
Typical use cases:
-Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE
Calva supports passing environment variables via jackInEnv
. You can set that option inside VSCode settings.json
file.
You can configure global settings.json
file or a project wide version, inside <project-root>/.vscode/settings.json
.
Configuring the global option will impact all projects you work on using Calva, so be aware. See the documentation for settings.json
for more information.
The bellow snippet configures JAVA_TOOL_OPTIONS
environment variable. We configure slf4j-simple logging level via a Java system property (-D
) and JVM specific options (-X
).
NOTE: You can of course pass other env variables here.
.vscode/settings.json
{\n\"calva.jackInEnv\": {\n\"JAVA_TOOL_OPTIONS\": \"${env:JAVA_TOOL_OPTIONS} -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896\"\n}\n}\n
Once you saved the file, the next time you Jack in
the project, this variable is read by the JVM and the configuration is applied accordingly.
You should see something like the message below in the Calva terminal output window:
clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,\"0.8.3\"},cider/cider-nrepl {:mvn/version,\"0.26.0\"}}}' -A:debug -m nrepl.cmdline --middleware \"[cider.nrepl/cider-middleware]\"\nPicked up JAVA_TOOL_OPTIONS: -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896\nListening for transport dt_socket at address: 7896\nnREPL server started on port 46691 on host localhost - nrepl://localhost:46691\n
"},{"location":"emacs-keybindings/","title":"Emacs Keybindings","text":"Some keybindings to make it easier for Emacs users
[\n{\n\"key\": \"ctrl+cmd+b\",\n\"command\": \"paredit.backwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+alt+left\",\n\"command\": \"-paredit.backwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"shift+cmd+]\",\n\"command\": \"-workbench.action.nextEditor\"\n},\n{\n\"key\": \"ctrl+shift+]\",\n\"command\": \"paredit.barfSexpBackward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+right\",\n\"command\": \"-paredit.barfSexpBackward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+[\",\n\"command\": \"paredit.barfSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+left\",\n\"command\": \"-paredit.barfSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+cmd+f\",\n\"command\": \"paredit.forwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+alt+right\",\n\"command\": \"-paredit.forwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+cmd+f\",\n\"command\": \"-workbench.action.toggleFullScreen\"\n},\n{\n\"key\": \"ctrl+shift+backspace\",\n\"command\": \"-paredit.killSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"shift+cmd+k\",\n\"command\": \"-editor.action.deleteLines\",\n\"when\": \"textInputFocus && !editorReadonly\"\n},\n{\n\"key\": \"ctrl+shift+0\",\n\"command\": \"paredit.slurpSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+right\",\n\"command\": \"-paredit.slurpSexpForward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+9\",\n\"command\": \"paredit.slurpSexpBackward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+left\",\n\"command\": \"-paredit.slurpSexpBackward\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+c ctrl+c\",\n\"command\": \"calva.evaluateCurrentTopLevelForm\",\n\"when\": \"calva:activated\"\n},\n{\n\"key\": \"ctrl+alt+c space\",\n\"command\": \"-calva.evaluateCurrentTopLevelForm\",\n\"when\": \"calva:activated\"\n},\n{\n\"key\": \"ctrl+x ctrl+e\",\n\"command\": \"calva.evalCurrentTopLevelFormInREPLWindow\",\n\"when\": \"calva:activated\"\n},\n{\n\"key\": \"ctrl+alt+c ctrl+alt+space\",\n\"command\": \"-calva.evalCurrentTopLevelFormInREPLWindow\",\n\"when\": \"calva:activated\"\n},\n{\n\"key\": \"ctrl+x ctrl+s\",\n\"command\": \"workbench.action.files.save\"\n},\n{\n\"key\": \"cmd+s\",\n\"command\": \"-workbench.action.files.save\"\n},\n{\n\"key\": \"cmd+s\",\n\"command\": \"paredit.spliceSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+alt+s\",\n\"command\": \"-paredit.spliceSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+cmd+k\",\n\"command\": \"paredit.cutForwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+x right\",\n\"command\": \"-paredit.cutForwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+cmd+backspace\",\n\"command\": \"paredit.cutBackwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+shift+x left\",\n\"command\": \"-paredit.cutBackwardSexp\",\n\"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n},\n{\n\"key\": \"ctrl+1\",\n\"command\": \"-workbench.action.openEditorAtIndex1\"\n},\n{\n\"key\": \"ctrl+1\",\n\"command\": \"editor.action.quickFix\",\n\"when\": \"editorHasCodeActionsProvider && editorTextFocus && !editorReadonly\"\n},\n{\n\"key\": \"cmd+.\",\n\"command\": \"-editor.action.quickFix\",\n\"when\": \"editorHasCodeActionsProvider && editorTextFocus && !editorReadonly\"\n},\n{\n\"key\": \"cmd+.\",\n\"command\": \"editor.action.revealDefinition\",\n\"when\": \"editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor\"\n},\n{\n\"key\": \"f12\",\n\"command\": \"-editor.action.revealDefinition\",\n\"when\": \"editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor\"\n}\n]\n
"},{"location":"eval-tips/","title":"Code Evaluation","text":"Calva tries to make it easy to evaluate code, supporting interactive development. The fastest path to learning about it is to use the Fire up the Getting Started REPL command, which you can learn more about in the Getting Started section.
NB: The below assumes you have read about Finding Calva Commands and Shortcuts.
","boost":7},{"location":"eval-tips/#interruptingstopping-running-evaluations","title":"Interrupting/stopping running evaluations","text":"Sometimes you evaluate things that take a very long time to complete, or might not even ever complete (infinite loops, lazy sequences, things like that). Calva has a command for interrupting running evaluations. You find it in the VS Code command palette, as well as in the REPL status bar item menu, when the REPL is connected.
","boost":7},{"location":"eval-tips/#evaluation-in-a-file-editor","title":"Evaluation in a File Editor","text":"Calva has many commands for evaluating forms, including the current form and the current top-level form.
Some of the commands also let you choose what should happen with the results:
These are important concepts in Calva in order for you to create your most effective workflow. This video explains it a bit:
","boost":7},{"location":"eval-tips/#current-form","title":"Current Form","text":"Default shortcut for evaluating the current form: ctrl+enter
.
The current form either means the current selection, or otherwise is based on the cursor position. Play some with the command Calva: Select current form, ctrl+alt+c s
, to figure out what Calva thinks is the current form for some different situations. Try it inside a symbol, adjacent to a symbol (both sides) and adjacent to an opening or closing bracket (again, both sides). Generally the current form is determined like so:
foob|ar ; foobar\n
(foo bar |(baz)) ; (baz)\n
(foo bar | (baz)) ; bar\n
(foo\n| bar (baz)) ; bar\n
Default shortcut for evaluating the current top level form: alt+enter
.
The current top-level form means top-level in a structural sense. It is not the topmost form in the file. Typically in a Clojure file you will find def
and defn
(and defwhatever
) forms at the top level, which also is one major intended use for evaluating top level form: to define and redefine variables. However, Calva does not check the contents of the form in order to determine it as a top-level forms: all forms not enclosed in any other form are top level forms.
An \u201dexception\u201d is introduced by the comment
form. It will create a new top level context, so that any forms immediately inside a (comment ...)
form will be considered top-level by Calva. This is to support a workflow with what is often referred to the Rich Comments.
At the top level the selection of which form is the current top level form follows the same rules as those for the current form.
","boost":7},{"location":"eval-tips/#evaluate-enclosing-form","title":"Evaluate Enclosing Form","text":"The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter
.
(let [foo :bar]\n(when false (str| foo))) ; => \":bar\"\n
","boost":7},{"location":"eval-tips/#evaluate-to-cursor","title":"Evaluate to Cursor","text":"There are several commands for evaluating a piece of code, closing brackets. It's good, especially in threads, but can also come in handy in other situations, for instance when you want to evaluate something that depends on bindings, such as in a let
form.
This command evaluates the text from the start of the current enclosing list to where the cursor is, and it adds the missing closing bracket for you. Convenient for checking intermediate results in thread or doto
, or similar pipelines. The cursor is right behind :d
in this form:
(->> [1 1 2 3 5 8 13 21]\n(partition 2)\n(zipmap [:a :b :c :d])\n:d| ; => (13 21)\n(apply -)\n(Math/abs))\n
The default shortcut for this command is ctrl+alt+enter.
","boost":7},{"location":"eval-tips/#evaluate-selection-closing-brackets","title":"Evaluate Selection, Closing Brackets","text":"This is the most versatile of the \u201devaluation, closing brackets\u201d commands. It will do what it says. \ud83d\ude04 It's extra handy in combination with the command Paredit: Select Backward Up Sexp/Form (shift+ctrl+up). Consider this contrieved form (buggy code, because it was supposed to result in 42
, not -42
):
(defn fortytwo-from-thirty\n[]\n(let [thirty 30]\n(-> thirty\ninc ;1\n(send-off)\n(+ 1 2 3)\n(->>\n(+ 2 2) ;2\n(+))\nlist\n(->>\n(into [1])\n(reduce + 1))\n(- 1) ;3\n(* -1))))\n
At ;1
, you can do backward up sexp (shift+ctrl+up) twice to select up to the (let ..)
, then issue Evaluate Selection, Closing Brackets. It has the same default keybinding as the command for evaluating the current list up to the cursor: ctrl+alt+enter.
At ;2
you need select backwards up three times.
;3
is included because it is close to the bug. (Which was introduced when the thread-last, ->>
was added to make this example.) Please practice the Evaluate Selection, Closing Brackets command to fix the bug.
This command has a default shortcut keybinding of shift+alt+enter
. It will create a form from the start of the current top level form, up to the cursor, close all brackets, and this will then be evaluated. Good for examining code blocks up to a certain point. Often comes in handy in Rich comments ((comment ...)
).
Take this example and paste it in a file loaded into the REPL, then place the cursor in front of each line comment and try the command.
(comment\n(do\n(def colt-express\n{:name \"Colt Express\"\n:categories [\"Family\"\n\"Strategy\"]\n:play-time 40\n:ratings {:pez 5.0\n:kat 5.0\n:wiw 5.0 ; 1, then eval `colt-express`\n:vig 3.0\n:rex 5.0\n:lun 4.0}})\n\n(defn average [coll]\n(/ (apply + coll) (count coll)))\n\n(let [foo-express (-> colt-express\n(assoc :name \"Foo Express\")\n(assoc-in [:ratings :lyr] 5.0)\n(update-in [:ratings :vig] inc))]\n(->> foo-express ; 2\n:ratings ; 3\nvals ; 4\naverage ; 5\n))))\n
","boost":7},{"location":"eval-tips/#evaluate-from-start-of-file-to-cursor-closing-brackets","title":"Evaluate From Start of File to Cursor, Closing Brackets","text":"Yup, that command also exists. \ud83d\ude04
","boost":7},{"location":"eval-tips/#copying-the-inline-results","title":"Copying the inline results","text":"There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c
.
This works regardless if you have evaluated in a file editor or in a REPL window.
","boost":7},{"location":"eval-tips/#evaluating-in-a-repl-window","title":"Evaluating in a REPL window","text":"Since the REPL Window is mostly just a regular file, things work pretty similar at the REPL prompt. You use alt+enter
to evaluate. Selecting the current form (default key binding ctrl+w
on Mac and shift+alt+right
on Windows and Linux) after evaluating will select the result.
Calva tries to make it easy to evaluate code, supporting interactive development. The fastest path to learning about it is to use the Fire up the Getting Started REPL command, which you can learn more about in the Getting Started section.
NB: The below assumes you have read about Finding Calva Commands and Shortcuts.
","boost":7},{"location":"evaluation/#interruptingstopping-running-evaluations","title":"Interrupting/stopping running evaluations","text":"Sometimes you evaluate things that take a very long time to complete, or might not even ever complete (infinite loops, lazy sequences, things like that). Calva has a command for interrupting running evaluations. You find it in the VS Code command palette, as well as in the REPL status bar item menu, when the REPL is connected.
","boost":7},{"location":"evaluation/#evaluation-in-a-file-editor","title":"Evaluation in a File Editor","text":"Calva has many commands for evaluating forms, including the current form and the current top-level form.
Some of the commands also let you choose what should happen with the results:
These are important concepts in Calva in order for you to create your most effective workflow. This video explains it a bit:
","boost":7},{"location":"evaluation/#current-form","title":"Current Form","text":"Default shortcut for evaluating the current form: ctrl+enter
.
The current form either means the current selection, or otherwise is based on the cursor position. Play some with the command Calva: Select current form, ctrl+alt+c s
, to figure out what Calva thinks is the current form for some different situations. Try it inside a symbol, adjacent to a symbol (both sides) and adjacent to an opening or closing bracket (again, both sides). Generally the current form is determined like so:
foob|ar ; foobar\n
(foo bar |(baz)) ; (baz)\n
(foo bar | (baz)) ; bar\n
(foo\n| bar (baz)) ; bar\n
Default shortcut for evaluating the current top level form: alt+enter
.
The current top-level form means top-level in a structural sense. It is not the topmost form in the file. Typically in a Clojure file you will find def
and defn
(and defwhatever
) forms at the top level, which also is one major intended use for evaluating top level form: to define and redefine variables. However, Calva does not check the contents of the form in order to determine it as a top-level forms: all forms not enclosed in any other form are top level forms.
An \u201dexception\u201d is introduced by the comment
form. It will create a new top level context, so that any forms immediately inside a (comment ...)
form will be considered top-level by Calva. This is to support a workflow with what is often referred to the Rich Comments.
At the top level the selection of which form is the current top level form follows the same rules as those for the current form.
","boost":7},{"location":"evaluation/#evaluate-enclosing-form","title":"Evaluate Enclosing Form","text":"The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter
.
(let [foo :bar]\n(when false (str| foo))) ; => \":bar\"\n
","boost":7},{"location":"evaluation/#evaluate-to-cursor","title":"Evaluate to Cursor","text":"There are several commands for evaluating a piece of code, closing brackets. It's good, especially in threads, but can also come in handy in other situations, for instance when you want to evaluate something that depends on bindings, such as in a let
form.
This command evaluates the text from the start of the current enclosing list to where the cursor is, and it adds the missing closing bracket for you. Convenient for checking intermediate results in thread or doto
, or similar pipelines. The cursor is right behind :d
in this form:
(->> [1 1 2 3 5 8 13 21]\n(partition 2)\n(zipmap [:a :b :c :d])\n:d| ; => (13 21)\n(apply -)\n(Math/abs))\n
The default shortcut for this command is ctrl+alt+enter.
","boost":7},{"location":"evaluation/#evaluate-selection-closing-brackets","title":"Evaluate Selection, Closing Brackets","text":"This is the most versatile of the \u201devaluation, closing brackets\u201d commands. It will do what it says. \ud83d\ude04 It's extra handy in combination with the command Paredit: Select Backward Up Sexp/Form (shift+ctrl+up). Consider this contrieved form (buggy code, because it was supposed to result in 42
, not -42
):
(defn fortytwo-from-thirty\n[]\n(let [thirty 30]\n(-> thirty\ninc ;1\n(send-off)\n(+ 1 2 3)\n(->>\n(+ 2 2) ;2\n(+))\nlist\n(->>\n(into [1])\n(reduce + 1))\n(- 1) ;3\n(* -1))))\n
At ;1
, you can do backward up sexp (shift+ctrl+up) twice to select up to the (let ..)
, then issue Evaluate Selection, Closing Brackets. It has the same default keybinding as the command for evaluating the current list up to the cursor: ctrl+alt+enter.
At ;2
you need select backwards up three times.
;3
is included because it is close to the bug. (Which was introduced when the thread-last, ->>
was added to make this example.) Please practice the Evaluate Selection, Closing Brackets command to fix the bug.
This command has a default shortcut keybinding of shift+alt+enter
. It will create a form from the start of the current top level form, up to the cursor, close all brackets, and this will then be evaluated. Good for examining code blocks up to a certain point. Often comes in handy in Rich comments ((comment ...)
).
Take this example and paste it in a file loaded into the REPL, then place the cursor in front of each line comment and try the command.
(comment\n(do\n(def colt-express\n{:name \"Colt Express\"\n:categories [\"Family\"\n\"Strategy\"]\n:play-time 40\n:ratings {:pez 5.0\n:kat 5.0\n:wiw 5.0 ; 1, then eval `colt-express`\n:vig 3.0\n:rex 5.0\n:lun 4.0}})\n\n(defn average [coll]\n(/ (apply + coll) (count coll)))\n\n(let [foo-express (-> colt-express\n(assoc :name \"Foo Express\")\n(assoc-in [:ratings :lyr] 5.0)\n(update-in [:ratings :vig] inc))]\n(->> foo-express ; 2\n:ratings ; 3\nvals ; 4\naverage ; 5\n))))\n
","boost":7},{"location":"evaluation/#evaluate-from-start-of-file-to-cursor-closing-brackets","title":"Evaluate From Start of File to Cursor, Closing Brackets","text":"Yup, that command also exists. \ud83d\ude04
","boost":7},{"location":"evaluation/#copying-the-inline-results","title":"Copying the inline results","text":"There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c
.
This works regardless if you have evaluated in a file editor or in a REPL window.
","boost":7},{"location":"evaluation/#evaluating-in-a-repl-window","title":"Evaluating in a REPL window","text":"Since the REPL Window is mostly just a regular file, things work pretty similar at the REPL prompt. You use alt+enter
to evaluate. Selecting the current form (default key binding ctrl+w
on Mac and shift+alt+right
on Windows and Linux) after evaluating will select the result.
In the podcast Functional Design in Clojure, Episode 014: Fiddle with the REPL, they discuss a workflow in which you keep some of your exploratory code in separate files, which they call Fiddle Files. It's like Rich Comments, and the files often consist of such comments. The Fiddle files are typically not on the classpath, and are only loaded in the REPL by you when you are developing your project. Some developers keep personal fiddle files. In some projects they are meant to be shared, and in other projects it's a combination.
Calva has some extra support for the fiddle file workflow, beyond what VS Code offers in terms of navigating between files. The support comes in the form of three commands supported by a little configuration.
","boost":5},{"location":"fiddle-files/#the-three-fiddle-file-commands","title":"The Three Fiddle File Commands","text":"The commands let you quickly navigate between your implementation code (called Source here) and your Fiddle file, and to evaluate the Fiddle file without leaving the Source file.
Command Action Shortcut Active Calva: Open Fiddle File for Current File Opens the Fiddle file corresponding to the current Clojure Source file. ctrl+alt+cf When the currently active file is not a Fiddle file. Calva: Open Source File for Current Fiddle File Opens the Source file corresponding to the current Fiddle file. ctrl+alt+cf When the currently active file is a Fiddle file + there is an existing, and corresponding, source file. Calva: Evaluate Fiddle File for Current File Evaluates the Fiddle file corresponding to the current Clojure Source file. ctrl+alt+cctrl+alt+f When the currently active file is not a Fiddle file.The commands for opening and evaluating corresponding Fiddle files will offer to Create the Fiddle file if it does not already exist. But the Calva: Open Source File for Current Fiddle File command will not offer to create the target file.
What does corresponding mean here? Without any configuration Calva will look for \u201csibling\u201d files, where files with Clojure file extensions (E.g. .clj
, .cljs
, .bb
) will be treated as Source files, and files with the .fiddle
extension will be treated as Fiddle files. \"Sibling file\" here means residing side by side in the file system. If this default behaviour is not your cup of tea, there is some flexibility added by configuration.
To know how to map between Fiddle <-> Source files, Calva has three different modes of operation:
src
/a/b/c.cljc
corresponding to:src
/a/b/c.fiddle
src
/a/b/c.cljc
corresponding to:env/dev/fiddles
/a/b/c.cljc
src
/a/b/c.cljc
and:src
/d/e/f.cljc
corresponding to:env/dev/fiddles
/x.cljc
The setting is named calva.fiddleFilePaths
and is an array of source
and fiddle
root paths, relative to the project root.
The Project Root
It is important to note that the project root depends on whether you are connected to a REPL or not, and to which project you are connected, in case the workspace contains several projects.
Without a REPL connection (disregarding that fiddle files are not very interesting then) the project root is the same as the first workspace root. And if you have a regular VS Code window open, it is the root of the folder you have opened in that window.
With a REPL connection, the project root will be the root of the project, i.e. where the project file (deps.edn
, project.clj
, shadow-cljs.edn
) is.
\"calva.fiddleFilePaths\": [\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n}\n]\n
This will make any file in the src
directory tree correspond to a matching file with the same relative path. E.g.:
src/a/b/c.clj
-> env/dev/fiddles/a/b/c.clj
, for both the open and evaluate commandsenv/dev/fiddles/a/b/c.clj
-> src/a/b/c.clj
If you generally work with one Fiddle file at a time, you can configure a mapping to a Dedicated Fiddle file. E.g.:
\"calva.fiddleFilePaths\": [\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n},\n]\n
This will make any file in the src
directory tree correspond to the same Fiddle file. E.g.:
src/a/b/c.clj
-> env/dev/fiddle.clj
, for both the open and evaluate commandssrc/d/e/f.clj
-> env/dev/fiddle.clj
, dittoenv/dev/fiddle.clj
-> Won't correspond to a Source file in this caseJumping from a dedicated fiddle to a source file
Calva's command for opening the corresponding source file won't work in this case because it is a one->many situation. If you want to open the last file you worked with before using Open Fiddle File for Current File, consider using the VS Code command: Go Previous.
","boost":5},{"location":"fiddle-files/#multiple-mappings","title":"Multiple Mappings","text":"The configuration is an array so that you can configure different mappings for different Source directories. Given several mappings with overlapping Source, the longest mapping will win. Given several mappings with the same Source, the first one will win, unless one of them is a dedicated Fiddle, in which case that one will win.
\"calva.fiddleFilePaths\": [\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n},\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n},\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddle.cljs\"]\n},\n{\n\"source\": [\"src\"],\n\"fiddle\": [\"env\", \"dev\", \"fiddle.bb\"]\n},\n{\n\"source\": [\"src\", \"b\"],\n\"fiddle\": [\"env\", \"dev\", \"b-fiddles\"]\n},\n]\n
With this configuration we would get a behaviour like so:
src/a/b/c.clj
-> env/dev/fiddle.clj
, because all four first [\"src\"]
mappings match, but the second one is a dedicated fiddle file, and matches the .clj
extension.src/a/b/c/d.bb
-> env/dev/fiddle.bb
, because all four first [\"src\"]
mappings match, but the second one is a dedicated fiddle file, and matches the .bb
extension.src/a/b/c/d.cljc
-> env/dev/fiddle.clj
, because all four first [\"src\"]
mappings match, but the second one is a dedicated fiddle file, without a matching file extension, (so the first dedicated fiddle file is picked).src/b/c/d.clj
-> env/dev/b-fiddles/c/d.clj
, because the [\"src\", \"b\"]
mapping is longer than the also matching [\"src\"]
mappings.Organize your Fiddle files such that they do not get automatically loaded as part of your application. This can lead to strange errors and hard-to-detect bugs. Most often it should only be you manually loading the fiddle file, not clj/clojure or Leiningen or any such system which loads your application.
When you want your fiddle code to be evaluated in the same workspace as its corresponding Source file, you can use the same namespace declaration for both files. The linter might complain, but the REPL will happily comply.
If you primarily evaluate the fiddle file using the provided command for it, from the Source files, you can omit the namespace declaration, and Calva will evaluate it in the namespace of the Source file.
The linter and fiddle files
For some fiddle files you will get a lot of linter warnings, because clj-kondo doesn't know about fiddle files, and they are often not on the classpath. You might find yourself wanting to silence some linters for some fiddle files. E.g. like this:
(ns main.core\n{:clj-kondo/config\n'{:linters {:unresolved-symbol {:level :off}}}})\n
See clj-kondo Configuration for more on what options you have for this.
","boost":5},{"location":"fiddle-files/#see-also","title":"See Also","text":"Calva relies a lot on that VS Code makes it really easy to find commands by opening the command palette: ctrl+shift+p
(Windows/Linux), cmd+shift+p
(Mac), and then start typing some words (or parts of words) that you think might be in the command.
To leverage this, all Calva commands are prefixed with Calva
. As an example, say you want to find commands related to evaluating the top level form. Then you can do this:
calevtop
VS Code will match cal
to \u201dCalva\u201d, ev
to \u201dEvaluate\u201d, and top
to \u201dTop\u201d. It looks like so:
As you can see on the screenshot, VS Code will also reveal the keyboard shortcut for each command. My advice is to make it a habit to try to remember those shortcuts and use them for a more effective workflow.
Now might be a good time to see Calva Top 10 Commands
"},{"location":"finding-commands/#all-the-settings-and-commands","title":"All the Settings and Commands","text":"Did you know? There is a complete list of Calva settings and commands in the Contributions tab of the Calva entry in the Extensions pane in VS Code.
"},{"location":"finding-commands/#toggling-keyboard-shortcuts-onoff","title":"Toggling Keyboard Shortcuts On/Off","text":"The command calva.toggleKeybindingsEnabled
can be used to quickly enable and disable (almost) all keyboard shortcuts. This allows you to quickly toggle between Calva keybindings and other keybindings which would otherwise not be available when Calva is enabled. This is particularly useful with the Paredit keyboard shortcuts, whose default shortcuts conflict with the default VS Code shortcuts for textual (non-structural) editing.
By default it is not bound to a shortcut so as not to cause confusion by users unwittingly pressing it, but if this is something you'd like to use often, you may want to bind it to a shortcut.
"},{"location":"formatting/","title":"Formatting","text":"We have tried to make Calva's formatter so that it just works. It is enabled by default for Clojure files, and with the default configuration it mostly follows Bozhidar Batsov's Clojure Style Guide. Calva uses cljfmt for the formatting.
Tab formats the current surrounding form
Calva's code formatter sets the default keybinding of its Format Current Form command to tab
. Meaning that most often when things look a bit untidy, you can press tab
to make things look pretty. Good to know, right? For performance reasons it only formats the current enclosing form, so sometimes you want to move the cursor up/out a form (ctrl+up
) first. See The Paredit Guide for more on moving the cursor structurally through your code.
With the default settings, Calva's formatting behaves like so:
tab
ctrl+alt+l
(comment ...)
forms special, see rich commentsInfer parens at will
Calva has a command that will \u201dheal\u201d the bracket structure if it is correctly indented using Parinfer Infer parens. This command is default bound to ctrl+alt+p i
.
Also: If you have Format on Save enabled in VS Code, it will be Calva doing the formatting for Clojure files.
Calva's formatting is mostly about indenting, but it also (again, defaults):
Not a fan of some default setting? The formatter is quite configurable.
"},{"location":"formatting/#format-current-form-command-variants","title":"Format current form command variants","text":"There are three special commands for formatting the current form:
"},{"location":"formatting/#1-format-and-align-current-form","title":"1. Format and Align Current Form","text":"Aligns associative structures and bindings in two columns. See more below.
"},{"location":"formatting/#2-format-current-form-and-trim-space-between-forms","title":"2. Format Current Form and trim space between forms","text":"This formats the text, and trims consecutive, non-indent, whitespace on a line to just one space. Something like:
(let [a :b]\n(str \"foo\" \"bar\" \"baz\"\n\"a\" a))\n
Becomes:
(let [a :b]\n(str \"foo\" \"bar\" \"baz\"\n\"a\" a))\n
Basically, it behaves like if :remove-multiple-non-indenting-spaces? true
was added to the cljfmt
config. Which, in fact, is what happens. Calva merges that onto your cljfmt config when this command is used.
This command will run the code of the Current Form through Calva's pretty printer (the engine named calva
, which is using zprint) and replace the current form inline in the editor with the pretty printed results.
Unlike with the \u201dreal\u201d Calva Formatter, which never breaks up lines, this one will follow your pretty printing options and break up lines if you have set maxWidth
to something that calls for breaking up lines.
Applies to the other Current Form
Unlike the other Format commands, which applies to the current enclosing form, this one applies to the Current Form, same as with evaluations. That is because this is not really part of the Calva formatter, but rather is a convenience command for tidying up code or data.
"},{"location":"formatting/#configuration","title":"Configuration","text":"You can adjust the above mentioned defaults, and the default indents, by configuring the formatting using cljfmt's configuration EDN.
This configuration can either be provided via a file or via clojure-lsp. See Providing configuration via clojure-lsp below.
"},{"location":"formatting/#providing-configuration-via-a-config-file","title":"Providing configuration via a config file","text":"Calva will look for the configuration in one of the default cljfmt paths ('.cljfmt.edn', '.cljfmt.clj', 'cljfmt.edn', or 'cljfmt.clj' in the workspace root). If your file is somewhere else use the calva.fmt.configPath
to tell Calva where to find it. The path should either be absolute, or relative to the workspace root directory. If your config file is somewhere in the workspace root, Calva will hot reload it when you update it.
Wherever the config file is, a suggested path for providing your configuration is to start changing the Calva formatting defaults by pasting the following map into a file and save it.
{:remove-surrounding-whitespace? true\n:remove-trailing-whitespace? true\n:remove-consecutive-blank-lines? false\n:insert-missing-whitespace? true\n:remove-multiple-non-indenting-spaces? false}\n
If the file is in the workspace, you can quickly test how different settings affect the formatting. Try:
:align-associative? true
to the configtab
, and see what happens.:align-associative?
is experimental This particular setting is experimental and known to cause trouble together with namespaced keywords. Consider using ctrl+alt+l
instead of tab
as your formatting command, instead of enabling this setting. See below for more info about this. See more below about this.
The cljfmt docs mention the :cljfmt
config key of Leiningen projects. Calva does not yet read the config from there, so if your Leiningen project has such a configuration, you will need to copy it out into a file.
If you work in a team where some members use clojure-lsp for formatting, you can make Calva format using the same configuration by telling setting calva.fmt.configPath
to CLOJURE-LSP
(case sensitive). See Clojure LSP Settings) for how to provide the configuration. (It might not be provided from where you think it is, specifically check clojure-lsp's global config in you user home directory.) Use the command Calva Diagnostics: Clojure-lsp Server Info to see what cljfmt configuration is being used (under the cljfmt-raw
key).
Note that doing this you will not have hot reload of the formatting configuration, and of course you will be depending on that clojure-lsp is running and functioning.
"},{"location":"formatting/#indentation-rules","title":"Indentation rules","text":"The cljfmt
indents are highly configurable. They, and the rest of the configuration options, are masterly detailed here.
:extra-indents
vs :indents
Since Calva v2.0.383
we are using cljfmt 0.11.x
which has a breaking configuration change. From the cljfmt README:
The :indents
key has been split into :indents
and :extra-indents. The :indents
key replaces all default indents, while the :extra-indents
key will append to the default indents.
If something prevents you from using a config with :extra-indents
, there's an escape hatch to keep using the :indents
key as before, by adding :legacy/merge-indents? true
to the config map.
Calva is an extra good tool for experimenting with these settings. cljfmt
doesn't care about keys in the map that it doesn't know about so you can sneak in test code there to quickly see how it will get formatted by certain rules. Try this, for instance:
{:remove-surrounding-whitespace? true\n:remove-trailing-whitespace? true\n:remove-consecutive-blank-lines? false\n:insert-missing-whitespace? false\n:indents {#re \"^\\w\" [[:inner 0]]}\n:test-code\n(concat [2]\n(map #(inc (* % 2))\n(filter #(aget sieved %)\n(range 1 hn))))}\n
Save, then hit tab
, and the code should get formatted like so:
:test-code\n(concat [2]\n(map #(inc (* % 2))\n(filter #(aget sieved %)\n(range 1 hn))))\n
That's somewhat similar to Nikita Prokopov's Better Clojure Formatting suggestion. (Please be aware that this setting might not be sufficient to get complete Tonsky Formatting, please share any settings you use to get full compliance.)
"},{"location":"formatting/#rich-comments","title":"Rich Comments","text":"To encourage use of (comment ...)
forms for development, the default settings give these forms get a special treatment when formatting. Use the calva.fmt.keepCommentTrailParenOnOwnLine
setting to control this behaviour. See Rich Comments first.
Calva loooks in the config map for the key :align-associative?
and if it is true
it will use an old version of cljfmt which is patched with functionality for doing this alignment. Note, though:
You are hereby warned, and let us also remind you about the Format and Align Current Form command which lets you apply this formatting a bit more surgically, and on demand.
This old version of cljfmt is inlined in the Calva repository along with the discontinued rewrite-cljs
project. Regard it as frozen code. If you want Calva's formatter to have full support for newer Clojure constructs and the bugs in the alignment code fixed, contribute to cljfmt. See this issue for starting to collect context.
Welcome to a zero-install, interactive, guide to get you started with Clojure using:
Clojure runs on the JVM. How to install it is a big topic. Since you have already done that, you can, if you want, choose to install Calva in your local VS Code and fire up the Getting Started REPL. By all means read this page anyway, you can just skip the Gitpod parts.
Also: If you are using Windows your Java might have a bug that prevents things from working. Then you might want to defer fixing that and use the zero-install option first.
Is Gitpod Code exactly as VS Code?Almost! But, yeah, there are some difference between regular VS Code and Gitpod's ditto. Most of it doesn't matter, but finding the main menu can be a bit tricky:
","boost":10},{"location":"get-started-with-clojure/#what-youll-learn","title":"What you'll learn","text":"Fair enough. We can recommend watching any or all of these videos to get excited about Clojure and the rather unique mood of development it offers:
All in due time. \ud83d\ude04 It can be a bit confusing with all the things you find out about installing Clojure and creating projects when searching for information about it. We want you to relax about all that and just enjoy learning a bit about this fantastic programming language and the wonderful mode of development it offers.
There is a lot of info about this out there already. And since you will learn where to find Clojurians, you will also find guidance. But we suggest do these things later. First, let's focus on having fun with Interactive Programming!
","boost":10},{"location":"get-started-with-clojure/#what-you-need","title":"What you need","text":"There is always a competition for which system gets to catch keyboard shortcuts first. This worsens a bit when an application like VS Code runs in the web browser. Remember this if some shortcut/command doesn't work.
On some machines, with some web browsers, some shortcuts are caught by the web browser and instead re-opening a closed tab or whatever. These have been observed:
Sometimes the workaround is to redefine the shortcuts in VS Code, sometimes making your web browser stop catching the shortcut.
I am new to VS CodeYou might want to have a look at this Getting Started with VS Code video. (You can of course ignore the parts about installing for now.) Also, have this overview of the VS Code interface handy.
","boost":10},{"location":"get-started-with-clojure/#how-it-works","title":"How it works","text":"Use a desktop/laptop computer. Even if it actually works on the phone, it is far from convenient.
It sometimes takes a while (several minutes) for the environment to initialize. Take some deep breaths and be patient. \ud83d\ude0e
","boost":10},{"location":"get-started-with-clojure/#lets-go","title":"Let's go!","text":"Ready? Awesome. Click this button to start the guide in a new browser tab.
https://gitpod.io/#https://github.com/PEZ/get-started-with-clojure Stuck? Something not working? Or just unclear?Please don't hesitate to reach out for help, should you get stuck. See below for where to find Clojurians. As for the Calva team, we are almost always (true story) to be found at the Clojurians Slack, especially in the #calva
Channel. We are @pez
and @bringe
there.
Happy Interactive Programming! \u2764\ufe0f
","boost":10},{"location":"get-started-with-clojure/#and-where-do-i-find-those-clojurians","title":"And where do I find those Clojurians?","text":"We Clojurians inhabit a lot of community platforms. I'll list some of the more popular ones here in some order of popularity.
#beginners
channel is spectacularly fantasticYou can also ask questions, and find answers, about Clojure at ask.clojure.org
","boost":10},{"location":"get-started-with-clojure/#learn-and-practice-clojure-using-rich-4clojure","title":"Learn and Practice Clojure using Rich 4Clojure","text":"If you like the style of interactive learning that this guide provides, you should definitely check Rich 4Clojure out. It also can be used in the zero-installed way.
You can regard it as a companion to this guide. It is aimed at practicing Clojure, starting at the elementary levels, bringing you to advanced stuff.
Can I use Rich 4Clojure instead of this guide?We suggest you start by opening up this guide and do the Calva part of the excerises. Then use the welcome_to_clojure.clj
guide in combination with Rich 4Clojure..
In a similar manner to the Get Started with Clojure project, you can run the Clojure Exercism Track in your browser without installing anything and with full Interactive Programming enabled using this Template project.
","boost":10},{"location":"get-started-with-clojure/#clojuredocs","title":"ClojureDocs","text":"Clojurians draw tremendous value from ClojureDocs. At ClojureDocs the concise documentation for Clojure core functions, etcetera, are amended with examples and advice from fellow Clojurians. Crowdsourcing at its very best! It is a big part of the reason why you won't find an abundance of Clojure information at StackOverflow.
","boost":10},{"location":"get-started-with-clojure/#other-learning-resources","title":"Other learning resources","text":"Give us feedback. Spread the word. Please consider:
#improve-getting-started
channel at the Clojurian SlackPlease also consider other ways to contribute.
Thanks! \ud83d\ude4f
","boost":10},{"location":"getting-started/","title":"Getting Started","text":"Depending on wether you want to just start a Clojure REPL or you have a project you want to work with, getting started looks similar but a bit different. Regardless, you need to first:
","boost":10},{"location":"getting-started/#install-vs-code-and-calva","title":"Install VS Code and Calva","text":"Calva
in the VS Code Extension pane, then click Install.If you have a Clojure or ClojureScript project, you will be interested in how to get Calva connected to the REPL of your project. But before you run over there, you might want to familiarize yourself with Calva a bit, which you can do without a project.
The demo tells you about the command (and some about the Clojure Beginner's material that it makes available).
I am completely new to ClojureThe \u201dGetting Started\u201d REPL below introduces you to Clojure as well as to Calva. You might however, not want to start with installing the right version of Java and such to run the guide. If so you should definitely check the Get Started with Clojure guide on this site.
Three clicks will have you running Calva in your browser with the REPL ready to serve.
I don't have Java installedIf you like, you can defer installing anything at all and still get started with Calva (not kidding).
See Get Started with Clojure.
","boost":10},{"location":"getting-started/#theres-a-getting-started-repl","title":"There's a \u201dGetting Started\u201d REPL","text":"If you are new to Calva, a good place to start is using the command Fire up the \u201dGetting Started\u201d REPL. (You can open the command palette using the VS Code top menu by going to View -> Command Palette...
or by running the associated keyboard shortcut for your OS.) Demo:
It will open up a three files in a temporary directory, and start and connect a REPL. The files are:
hello_repl.clj
\u2013 The basics of how to evaluate code in Calvahello_paredit.clj
- A super brief intro to Calva structural editingwelcome_to_clojure.clj
- The very basics of the Clojure languageThe only prerequisite here is that you have Java installed. No pre-installed clojure tools required. (You will want to install these tools later, of course.)
Note
On Windows the Oracle Java installer sets Java up in some funny way so that the Getting Started REPL fails to start. We are figuring about workarounds for this, but for now, if you are on Windows, you will need to make VS Code have some other Java in the PATH
of its environment for this feature to work. See this issue on the Calva repo for more on this, including any progress.
Without creating a project structure or installing anything but Calva, you can start standalone ClojureScript REPLs both in a browser and for node:
core.cljs
and index.html
and starts the ClojureScript app, opening it in the browser.core.cljs
, and starts a nodejs REPL where it loads the file.The browser REPL app looks like so:
","boost":10},{"location":"getting-started/#you-have-a-project","title":"You have a Project?","text":"If you are new to Calva, please consider the above option first. Then when it will be time to get Calva connected to the REPL of your project.
","boost":10},{"location":"getting-started/#clojure-resources","title":"Clojure Resources","text":"If you are new to Clojure or ClojureScript altogether, please check out the guide material on the respective official sites:
There are also many great books on Clojure. Clojure for the Brave and True can be read for free online. It is a great resource for beginners.
","boost":10},{"location":"getting-started/#there-is-also-standalone-repl","title":"There is also Standalone REPL","text":"When you are more familiar with Calva, and want a standalone REPL, there is a separate command: Start a standalone REPL (not in project). It will open up a user.clj
in a temporary directory, containing only an (ns user)
form, and start and connect the REPL.
The command for starting the Getting Started REPL will download the files from this repository. It is very much work in progress, and there is not even a finished Clojure Beginner's Guide there yet. When you run the command again, and from then on, you will get the option to download new files or keep using your existing. Downloading new ones will not overwrite your existing ones, because they will be downloaded to a new temp directory. You can find the directory easily using VS Codes context menu command for revealing a file in the Explorer/Finder.
","boost":10},{"location":"getting-started/#one-last-thing","title":"One Last Thing","text":"Happy coding! \u2665\ufe0f
","boost":10},{"location":"hiccup/","title":"Converting HTML to Hiccup","text":"Calva can help you convert HTML to Hiccup.
","boost":7},{"location":"hiccup/#features","title":"Features","text":"","boost":7},{"location":"hiccup/#three-commands","title":"Three commands","text":"The resulting data structure is formatted with zprint using it's :style :hiccup
configuration.
In addition to, optionally, being able to convert style attributes to maps and kebab-case attributes, the conversion:
id
attribute and classes are made part of the tag, CSS selector style<foo id=\"bar\"></foo>
=> [:foo#bar]
<foo class=\"c1 c2\"></foo>
=> [:foo.c1.c2]
<foo id=\"bar\" class=\"c1 c2\"></foo>
=> [:foo#bar.c1.c2]
<foo id='foo-[id]'></foo>
=> [:foo {:id \"foo-[id]\"}]
<foo class='clz1 clz[2]'></foo>
=> [:foo.clz1 {:class [\"clz[2]\"]}]
<foo> \\nbar\\n </foo>
=> [:foo \"bar\"]
<foo> \\n </foo>
=> [:foo]
<foo disabled></foo>
=> [:foo {:disabled true}]
<foo disabled=disabled></foo>
=> [:foo {:disabled \"disabled\"}]
viewBox
and baseProfile
(SVG is picky about it)<foo bAsePROFilE=bar viewbox=\"0 0 1 1\"></foo>
=> [:foo {:baseProfile \"bar\" :viewBox \"0 0 1 1\"}]
<foo><!-- ... --></foo>
=> [:foo (comment \"...\")]
<foo></foo><foo></foo>
=> [:foo]\\n[:foo]
The Hiccup converstion can be tweaked with two options using the setting calva.html2HiccupOptions
, which is a map/object:
mapify-style
: boolean, default false
. When true
any style
attribute will be converted to a map (Reagent supports this)kebab-attrs?
: boolean, default false
. When true
attribute names will be converted from camelCase, or snake_case/SNAKE_CASE to kebab-case. (Reagent wants most attribute names like this.)add-classes-to-tag-keyword?
: boolean, default true
. When true
all class names will be added CSS-style to the tag keyword ([:tag.clz1.clz2]
), as opposed to being kept in the class attribute. Keeping the class names in the attribute may be preferable with elements having a lot of class names, such as when using Tailwind CSS.The Copy HTML as Hiccup command is available from VS Code's Edit menu, as well as the editor context menu, in both cases under the Copy as sub menu.
","boost":7},{"location":"hiccup/#the-commands-take-arguments","title":"The commands take arguments","text":"This options map can also be provided as an argument to the commands, so you can bind keyboard shortcuts to a particular configuration for the conversion.
The command calva.convertHtml2Hiccup
takes a map as an argument:
toUntitled
: boolean
, default false
. When false
the result of the conversion will be returned to the caller (This is intended for Joyride, or some other VS Code extension). When true
it will behave like the default command does, placing the result of the conversion in an Untitled Clojure file.options
: Same as those calva.html2HiccupOptions
mentioned above.The calva.pasteHtmlAsHiccup
and calva.copyHtmlAsHiccup
commands takes only a calva.html2HiccupOptions
map.
The commands have no default keyboard shortcuts, you use the Command Palette to execute them, or you bind your own shortcuts. Here are some examples:
// calva.convertHtml2Hiccup\n{\n// With args, `\"toUntitled\": true` is necessary for keyboard shortcuts\n// without it, the command just returns the result to the caller\n\"key\": \"ctrl+alt+c ctrl+h\",\n\"command\": \"calva.convertHtml2Hiccup\",\n\"args\": {\"toUntitled\": true, \"options\": {\"mapify-style?\": false}}\n},\n{\n// Only for completeness, providing the HTML is only useful from e.g. Joyride \n\"key\": \"ctrl+alt+c shift+h\",\n\"command\": \"calva.convertHtml2Hiccup\",\n\"args\": {\"html\": \"<foo style='a: b' bar='baz'>gaz<foo>\", \"toUntitled\": true}\n},\n{\n// Without args, the command uses the `calva.html2HiccupOptions` configuration\n// And writes the results to an Untitled document\n\"key\": \"ctrl+alt+c h\",\n\"command\": \"calva.convertHtml2Hiccup\",\n},\n\n// calva.pasteHtmlAsHiccup\n{\n// Override the `calva.html2HiccupOptions` configuration\n\"key\": \"ctrl+alt+h ctrl+v\",\n\"command\": \"calva.pasteHtmlAsHiccup\",\n\"args\": {\"mapify-style?\": true, \"kebab-attrs?\": true}\n},\n{\n// Without args, the command uses the `calva.html2HiccupOptions` configuration\n\"key\": \"ctrl+alt+h v\",\n\"command\": \"calva.pasteHtmlAsHiccup\"\n},\n\n// calva.copyHtmlAsHiccup\n{\n// Override the `calva.html2HiccupOptions` configuration\n\"key\": \"ctrl+alt+h ctrl+c\",\n\"command\": \"calva.copyHtmlAsHiccup\",\n\"args\": {\"mapify-style?\": false, \"kebab-attrs?\": true}\n},\n{\n// Without args, the command uses the `calva.html2HiccupOptions` configuration\n\"key\": \"ctrl+alt+h c\",\n\"command\": \"calva.copyHtmlAsHiccup\"\n},\n
The default/args-less bindings are placed last because reasons.
","boost":7},{"location":"hiccup/#using-from-joyride-or-some-other-vs-code-extension","title":"Using from Joyride (or some other VS Code extension)","text":"As with any VS Code command using these from Joyride is a matter of calling executeCommand
.
calva.pasteHtmlAsHiccup
and calva.pasteHtmlAsHiccup
","text":"(-> (vscode/commands.executeCommand \"calva.pasteHtmlAsHiccup\"\n#js {:mapify-style? true})\n(.then ...))\n\n(-> (vscode/commands.executeCommand \"calva.copyHtmlAsHiccup\"\n#js {:mapify-style? true})\n(.then ...))\n
","boost":7},{"location":"hiccup/#calvaconverthtml2hiccup","title":"calva.convertHtml2Hiccup
","text":"Without options the command behaves just like selecting the command from the command palette. If there is a selection it will be converted, otherwise the whole file. The result will be opened in a new Untitled document.
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\")\n(.then ...))\n
Called with arguments it will by default return an object with a .-result
member which is a string with the Hiccup.
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" #js {:html \"<foo class='clz1 clz2>bar</foo>\"})\n(.then #(println (.-result %))))\n\n(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" #js {:options #js {:mapify-style? false}})\n(.then #(println (.-result %))))\n
To make it put the text in a new Untitled document instead, provide the argument option :toUntitled true
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" #js {:toUntitled true\n:html \"<foo class='clz1 clz2>bar</foo>\"\n:options #js {:mapify-style? true\n:kebab-attrs? true}})\n(.then ...))\n
","boost":7},{"location":"jack-in-guide/","title":"Learn about Calva Jack-in","text":"The Calva Jack-In Academy, by @pez
Like with CIDER Jack-in, Calva's let-me-help-you-start-your-project-and-connect feature might seem a bit mysterious. It really is helpful, but also really isn't mysterious. Here are a few things about it that is good to know about.
Note
If you came here to find out how to configure the versions of the dependencies that Calva Jack-in injects, see Customizing Calva - Jack-in Dependency Versions.
","boost":6},{"location":"jack-in-guide/#what-it-solves","title":"What it Solves","text":"At first it might seem that something like lein repl
in a terminal and then connecting Calva is enough. It sometimes might be, but only if you are in luck. To provide many of its IDE features, Calva relies on nREPL middleware, mainly cider-nrepl and, for ClojureScript, piggieback. When starting your Clojure(Script) app and its REPL, it needs to be started with these dependencies satisfied. There are mainly three ways this can be achieved.
project.clj
, deps.edn
, shadow-cljs.edn
, and combination of these).~/.lein/profiles.clj
and ~/.clojure/deps.edn
).Because 1 and 2 are hard to keep in sync with the various editor environments people in your project might be using, Calva Jack-In is about 3.
Ideally, you will be able to rid your project files completely of editor dependencies when people working on the project can rely on the Jack-In features of their Clojure editor.
","boost":6},{"location":"jack-in-guide/#a-controlled-shell-command","title":"A Controlled Shell Command","text":"At its core Calva Jack-In is just a glorified, REPL-starting, command-line. No, it is more than that, but anyway. The command line can look like so for a Leiningen project using legacy Figwheel for its ClojureScript assistance:
lein update-in :dependencies conj '[nrepl\"0.6.0\"]' -- update-in :dependencies conj '[cider/piggieback\"0.4.1\"]' -- update-in :dependencies conj '[figwheel-sidecar\"0.5.18\"]' -- update-in :plugins conj '[cider/cider-nrepl\"0.22.4\"]' -- update-in '[:repl-options :nrepl-middleware]' conj '[\"cider.nrepl/cider-middleware\"]' -- update-in '[:repl-options :nrepl-middleware]' conj '[\"cider.piggieback/wrap-cljs-repl\"]' -- with-profile +dev repl :headless\n
Even if a bit long, it might look simple enough. But actually it has taken quite some effort to make Calva craft it. Shell quoting can be really tricky. Look at how '[nrepl\"0.6.0\"]'
doesn't have a space between nrepl
and the version. That was the only way I could find that was cross platform enough to make all supported shells parse the command line. (The trick relies on that the string is read by the super reliable Clojure Reader, which does not need that space to tokenize it.)
It is awesome that Clojure is used on so many platforms, but for a tool smith this also means more work. (I think Windows and its shell hell ate up about 95% of the many hours spent on getting the quoting good enough.)
The command-line crafted is then used to start a shell command that Calva controls, but we are getting ahead of ourselves...
","boost":6},{"location":"jack-in-guide/#project-types-builds-aliases-profiles-etcetera","title":"Project Types, Builds, Aliases, Profiles, etcetera","text":"In order to cook the right command for your project, Calva looks for project files, reads them, and figures out what possible project types and ClojureScript tools could be involved. Then Calva presents you with a menu with the options it has found. You need to know enough about your project to answer this question. It looks like this in a shadow-cljs project that uses a deps.edn
file for setting up its classpath.
(I know enough about this particular project to know that I should choose the shadow-cljs
project type.)
But Calva isn't ready to cook the command-line just yet. Depending on the project type, and contents of your project files, more info is needed. E.g. in the case of shadow-cljs projects, Calva needs to know what builds to start.
Here you can select any combination of builds defined in the project, and Calva will cook a command line that starts them.
You might get more prompts from Calva before it issues the command, but for this example project, Calva goes ahead, cooks the command line, and issues it. On my Mac, it looks like so:
npx shadow-cljs -d cider/piggieback:0.4.1 -d cider/cider-nrepl:0.22.4 watch :app\n
(Much shorter than the one with lein-figwheel, right? It is because shadow-cljs is aware of CIDER dependencies, so it doesn't need as many dependencies specified as some other project types do.)
","boost":6},{"location":"jack-in-guide/#connecting","title":"Connecting","text":"When the command is issued Calva needs to wait until the REPL Server is started, before connecting to it and possibly continuing with starting a ClojureScript REPL and connecting to that as well. It also needs to know which port to connect to.
Because reasons, Calva can't yet read the stdout
of the shell command it has issued, so to know when the REPL server is started, and on which port, Calva monitors the filesystem for the .nrepl-port
file. (This file is not always named like that. shadow-cljs, for instance, creates the file .shadow-cljs/nrepl.port
.)
When the port file is created, Calva picks up the port number from it and connects to the nREPL server. At this point you have a Clojure REPL backing your Calva session, providing all sorts of nice IDE help for you.
","boost":6},{"location":"jack-in-guide/#starting-your-clojure-app","title":"Starting Your Clojure App","text":"Once you have the Clojure REPL connected you can start your Clojure app/server. See Custom Connect Sequences for how to let Calva do this for you automatically. See the same article for ways to automate more of the Jack-In process. It can be brought down to a single Jack-In command/action, even for a full stack Clojure and ClojureScript application.
","boost":6},{"location":"jack-in-guide/#clojurescript","title":"ClojureScript","text":"For ClojureScript, things are not done yet, though, far from it. It turns out that cooking the command line was the easy part.
In order for Calva to provide REPL power for ClojureScript projects, several things need to happen:
Depending on ClojureScript project type, Calva uses different methods to start the compilation and the watcher:
This results in a bit of difference in the user interaction. Mainly that for shadow-cljs, the user needs to check the Jack-In Terminal tab to follow what's going on.
","boost":6},{"location":"jack-in-guide/#starting-the-app","title":"Starting the App","text":"Number 3 above, the app needs to be started, might seem obvious, but it actually trips many people up. Because of this, Calva goes to quite some lengths to provide assistance. Many projects are configured not to spawn a browser session automatically, requesting the app once it has been compiled, so we can't rely on that.
What Calva does instead is to monitor the output of the commands it uses for starting the compilation, looking for information that the app is ready to be requested/started. It then tells the user this, providing a URL, in case it is a browser app. (There are also settings that tell Calva to open the URL automatically for you, regardless what the project settings are.)
","boost":6},{"location":"jack-in-guide/#connecting_1","title":"Connecting","text":"Meanwhile, Calva is monitoring the output and when it sees that the app is started, it continues to hook up the REPL connection to the editor.
This whole connection sequence is quite configurable, using Custom Connect Sequences. In fact, Calva's built in ClojureScript sequences (Figwheel Main, lein-figwheel, shadow-cljs, and ClojureScript built-ins for both Browser and Node) are all built using those same settings mechanisms.
","boost":6},{"location":"jack-in-guide/#shadow-cljs-is-less-managed-by-calva","title":"shadow-cljs is Less Managed by Calva","text":"NB: The managed way in which Calva creates and connects the ClojureScript REPL breaks apart a bit for shadow-cljs, which works a bit differently and also outputs most of the information Calva is looking for on the stdout
of the REPL start command (where Calva can't see it, remember?). We'll figure out a better way to support shadow-cljs, but for now, the user needs to do more of this figuring out than is needed with Figwheel projects.
So, there are things going on when you start Jack-In, and even more things for ClojureScript projects, but Calva tries to keep it together, so as a user it is a matter of paying attention and responding to a few prompts/menus with pre-populated options (prompts which can be configured away, even).
","boost":6},{"location":"jack-in-guide/#switch-clojurescript-builds","title":"Switch ClojureScript Builds","text":"Once the REPL is connected you might want to change which ClojureScript build you have Calva connected to. For this Calva has the Select CLJS Build Connection command. Please note that you can only switch between builds that you have started.
","boost":6},{"location":"jack-in-guide/#play-with-starting-the-cljs-repl-yourself","title":"Play With Starting thecljs-repl
Yourself","text":"To get a good grip on what is going on when creating and connecting the ClojureScript REPL, I can recommend making a custom connect sequence which leaves the REPL unpromoted (e.g. give it nil
as connectCode
), and then evaluate the cljs-repl
start commands yourself. So for instance, promoting it to a ClojureScript Node.js REPL looks something like so:
user=> (require 'cljs.repl.node)\nuser=> (cider.piggieback/cljs-repl (cljs.repl.node/repl-env))\nClojureScript 1.10.844\nTo quit, type: :cljs/quit\nnil\ncljs.user=> |\n
It is the piggieback middleware there telling you that you can unpromote the REPL by \u201devaluating\u201d :cljs/quit
.
Because Calva uses the Clojure REPL connection to spawn the ClojureScript REPL, and because Calva only handles one Clojure REPL per VS Code window, some projects need special handling by the user.
If your full stack project is using shadow-cljs for the frontend, like this Fulcro template project does, maybe you first try to Jack-In to your backend Clojure REPL, and then to your shadow-cljs frontend. This works if you do it in separate VS Code windows, but if you do it in the same window, the second Jack-In will kill the backend session! See also connect shadow-cljs in fullstack projects.
See Workspace Layouts for tips about how to open the same project folder in two separate VS Code windows.
Please also consider to play around with starting the REPL and ClojureScript wiring entirely from the terminal, see this example project for some instructions on that. You can also use that project together with the nil
for connectCode
sequence mentioned above.
There, you now know all there is to know about Calva Jack-In.
Just kidding, there are a few more details to it, some of which might find their way into this article at a later time.
To really get to know it all, you will need to spend some time with the Calva Jack-In code. Head over to the Calva Development Wiki to learn how to hack on Calva.
","boost":6},{"location":"joyride/","title":"Using Calva With Joyride","text":"Joyride is a VS Code extension for user space scripting of VS Code itself. You find the extension here. The scripting language for Joyride is the best you language imaginable: Clojure. And, as is proper for a Clojure implementation, it has a REPL, even an nREPL server.
This means you can connect Calva to Joyride and interactively develop your VS Code scripts.
This video shows Joyride in action, using Calva as the nREPL client.
"},{"location":"joyride/#how-to-connect","title":"How to connect","text":"Once you have the Joyride extension installed you can start its REPL and connect Calva to it (a.k.a Jack-in).
Start the Joyride REPL and Connect
This 1 minute video shows the following steps:
joyride
project type(Right-click the video and choose Full Screeen if it is too tiny embedded.)
"},{"location":"joyride/#how-to-get-started-with-joyride","title":"How to Get Started with Joyride","text":"The Joyride README has some Quick Start pointers for you. Please feel invited to the #joyride
channel on the Clojurians Slack and chat with us and other Joyride users.
Come on, Join the Joyride! \u2764\ufe0f
"},{"location":"krell/","title":"Using Calva With Krell","text":"Krell is \u00e0 la carte ClojureScript tooling for React Native.
Even if Calva does not yet have built-in support, all is not lost. You can add support yourself by way of a Custom REPL Connect Sequence. Here's how;
"},{"location":"krell/#starting-the-krell-clojurescript-repl","title":"Starting the Krell ClojureScript REPL","text":"Add this REPL Connect Sequence to your workspace settings.json
:
\"calva.replConnectSequences\": [\n{\n\"name\": \"deps.edn + Krell\",\n\"projectType\": \"deps.edn\",\n\"cljsType\": {\n\"connectCode\": \"(require '[clojure.edn :as edn] \\n '[clojure.java.io :as io]\\n '[cider.piggieback] \\n '[krell.api :as krell]\\n '[krell.repl])\\n\\n(def config (edn/read-string (slurp (io/file \\\"build.edn\\\"))))\\n(apply cider.piggieback/cljs-repl (krell.repl/repl-env) (mapcat identity config))\",\n\"dependsOn\": \"User provided\"\n}\n}\n]\n
Then issue the command Start a Project REPL and Connect (aka Jack-In). It start the project and connect to the Krell REPL once the app is running on a device (wether real or virtual/emulated).
"},{"location":"krell/#additional-vs-code-tips","title":"Additional VS Code Tips","text":"For a smooth workflow you can also:
{\n\"type\": \"chrome\",\n\"request\": \"launch\",\n\"name\": \"Launch Debugger\",\n\"url\": \"http://localhost:8081/debugger-ui/\",\n\"webRoot\": \"${workspaceFolder}\"\n}\n
Together with the connect sequence this will make for a start of a Krell session like this:
F5
)Once the debugger (a Chrome session) is running, you probably will want to enable Custom Formatters in order for clojure structures to be logged conveniently.
"},{"location":"linting/","title":"Linting","text":"Calva does no linting, yet with Calva you get excellent linting. That is because Calva uses clojure-lsp, which provides linting powered by clj-kondo.
clj-kondo comes with great default rules, and the configuration can be customized. One of your options for the configuration file is to placed a config.edn
file in .clj-kondo/
at the root of your project. This folder may or may not already exist. It is safe to create it manually if it doesn't.
The configuration will be merged with the default set of rules, you can only specify the rules you want to override. The full list of available options can be found on clj-kondo's github
clojure-lsp is customizable, see Clojure LSP Settings for your options. It is safe to manually create the .lsp
folder if it doesn't exist.
You might want to read about how to configure clj-kondo. These two sections might be of extra interest:
If you see a linting squiggle under the first character of the file with an error you don't quite understand, it is probably something wrong with your clj-kondo configuration.
Files are linted as they're being edited. If you want to lint the whole project, use the clj-kondo cli command. See https://github.com/borkdude/clj-kondo for more info on that. Windows users might like to know that they too can get a clj-kondo cli command now, via npm install -g clj-kondo
. It'll be a bit slower to start than the native build, but for sure it's better than not having a clj-kondo command! See https://github.com/borkdude/clj-kondo/blob/master/doc/install.md#npm-linux-macos-windows for more on this.
When your cursor is on a macro form in the editor, you may notice a code action (click the light bulb that appears) called Resolve Macro As. Running this code action will ask you what macro you'd like to resolve the current macro as, and then what clj-kondo config file you want the macro to be saved to. This code action is also available as a command.
"},{"location":"live-share/","title":"Using Calva with Live Share","text":"Live Share is a Microsoft provided VS Code extension. It allows you to share the workspace that you have open in your computer with somebody else. Everybody is then working on the same source code files, namely those on your computer. You can edit files at the same time, everyone has their own caret. You can follow each other (i.e. when someone switches to a different file, you will as well). This is great for remote pair programming, for example.
An extra nice thing is that each participant is using their own VSCode configuration, including fonts, colors, keyboard shortcuts, etc.
Disable Calva Spritz to get rid of Notebooks interference
The headline below Calva Supports Live Share is true. However, due to a bug in LiveShare, guest participants always get their Clojure files opened in the Calva Clojure Notebooks editor. To workaround this issue Calva uses a \u201dside-car\u201d extension named Calva Spritz for the Notebooks associations of Clojure files. You can disable that extension when participating in LiveShare sessions.
"},{"location":"live-share/#calva-supports-live-share","title":"Calva Supports Live Share","text":"When using Calva, you can use Live Share as well. Editing works exactly the same as for any other programming language. What makes Calva a bit special, is the REPL. When using Live Share, Calva allows the host to share the REPL with guests as well. If you use any of the supported configuration, this will be pretty much automatic.
You need to enable the LiveShare support
Due to an issue in the LiveShare API, for some users, this feature stops Calva from connecting the REPL. Therefore the support is disabled by default. The setting is calva.useLiveShare
.
This is what a typical scenario looks like:
Voila! Both the guest and the host can now use the REPL that is running on the host. Things like documentation lookup now also work on the guest's machine.
"},{"location":"live-share/#control-visibility-of-calva-folder","title":"Control Visibility of.calva
Folder","text":"Calva depends on the output.calva-repl
file to be available. If you have the .calva
folder listed in your .gitignore
, this also causes the folder to be hidden from guests in Live Share by default. In order to make the folder visible, you can put a file called .vsls.json
in your project. In its simplest form, the contents can be this:
{\n\"$schema\": \"http://json.schemastore.org/vsls\",\n\"hideFiles\": [\n\"!.calva\"\n]\n}\n
Now the .calva
folder is shared as well. But also any other file and folder that you may have in your .gitignore
. If you want to have more fine-grained control, please refer to the section Controlling file access and visibility of the Live Share documentation.
output.calva-repl
file, which all participants are sharing. It may work better to evaluate things in the source code editors instead of from the REPL window. Otherwise you will end up in a situation where one person is typing something in the output.calva-repl
window, and somebody else is evaluating something (hence sending the output there) at the same time. That gets confusing quickly.Together with Calva there is an extension called Calva Spritz installed. All it does is to provide the association of Clojure file types to Clojure Notebooks. We do it this way because of the LiveShare issues mentioned above. So that you can disable the Notebook association when participating as a guest in LiveShare sessions. The issue is tracked here:
Calva Spritz can be disabled and enabled at will, and it will take immediate effect, without any reload of VS Code needed.
"},{"location":"luminus/","title":"How to Use Calva with Luminus","text":"Luminus is a powerful and versatile Leiningen template for creating web development projects. It comes with built in configuration which makes it easy to use Calva as your Clojure(Script) editor.
"},{"location":"luminus/#server-shadow-cljs","title":"Server + shadow-cljs","text":"Basically this is the same wokflow as with Server only. Behind the scenes there is more happening, though. Such as the ClojureScript app being built and the CLJS REPL connected once the web app is running.
$ lein new luminus my-luminus-shadow +reagent +re-frame +shadow-cljs\n
$ npm i\n
(Or yarn
if you prefer.)my-luminus-shadow
. Open it in VS Code: $ code my-luminus-shadow\n
ctrl+alt+c ctrl+alt+j
[:app] Build completed.
Note
Currently Calva has troubles following the app-start with shadow-cljs, so Calva will report Jack-in done.
in the output window before shadow-cljs is actually done building the app. If you open the app page at that stage, you will see a message to \u201cPlease run lein shadow watch app
\u201d. Rest assured that this is already underway. Follow the Jack-in process in the Terminal tab in VS Code for the message that the app is built, then reload the app page in the web browser.
The workflow here is really just: Jack-in and start hacking. However, the first time it will involve these steps:
$ lein new luminus my-luminus-server\n
my-luminus-server
. Open it in VS Code: $ code my-luminus-server\n
ctrl+alt+c ctrl+alt+j
Jack-in done.
in the output window.This is Legacy Figwheel (lein-figwheel), so the recommendation is to use the shadow-cljs setup instead. As with the server only, the workflow here is really just: Jack-in and start hacking. The first time it involves these steps:
$ lein new luminus my-fw +reagent\n
my-fw
. Open it in VS Code: $ code my-fw\n
ctrl+alt+c ctrl+alt+j
, select Server + Client - my-fw in the Project type picker menu, and wait for the web app to pop open in your web browser.If you prefer to open the web app yourself, open .vscode/settings.json
and change \"shouldOpenUrl\"
to false
in the pre-configured Calva connect sequence. Calva will then print the URL 127.0.0.1:3000 in the output, so that you can click it open.
You will have three Calva Custom Command Snippets configured. Invoke them by issuing the Run Custom REPL Command, ctrl+alt+c .
(that's a dot). These commands control the Luminus server:
Start <project> Server
Stop <project> Server
Restart <project> Server
When used, Calva will open its REPL window and execute the command, if it is not already opened. You can close this window if you prefer to use the REPL directly from the Clojure files.
Calva also opens the REPL window, and starts the Luminus server, as part of the Jack-in process.
"},{"location":"merch/","title":"Calva Merch","text":"In this video, there is a question about where you can buy the Calva T-shirt:
You couldn't, then. But now you can! On Amazon.
Zero profit
To keep the admin of this shop to a minimum the merch is sold at production prize (or as close to production prize as the respective store allows). There is no royalty going to anyone in the Calva team when you buy one of these t-shirts. You will represent, which is certainly a way to support the project. You are of course encouraged to support us via sponsoring as well:
Calva Merch is available on Zazzle and on Amazon
","boost":10},{"location":"merch/#zazzle","title":"Zazzle","text":"","boost":10},{"location":"merch/#calva-symbol-sticker","title":"Calva Symbol Sticker","text":"Calva Symbol Sticker by BetterThanTomorrow","boost":10},{"location":"merch/#joyride-symbol-sticker","title":"Joyride Symbol Sticker","text":"Joyride Symbol Sticker by BetterThanTomorrow","boost":10},{"location":"merch/#amazon-merch","title":"Amazon Merch","text":"","boost":10},{"location":"merch/#the-designs","title":"The designs","text":"There are four design, all featuring the Calva symbol (the Calva glass), which are all available for a Standard T-shirt, in men's, women's and kid's cut, and in some different colors. In the .com
store there are also Premium T-shirts**.
Available at:
The Calva symbol and Logo front, Rich Comments back.
Available at:
Available at:
The Calva symbol front, Rich Comments Back.
Available at:
Note
What's available on this or that Amazon site will vary a bit and it is a bit slow to add a particular design to a particular market. Eventually I hope to have both designs up on these markets: .com
, .co.uk
, .de
, .fr
, .it
, .es
, and .co.jp
When you create a new clojure file, a file with .clj
, .cljc
or .cljs
extension, an appropriate namespace form will be added to the file. This feature is provided by clojure-lsp.
Since nbb can be started such that it is an nREPL server, Calva can connect to it and a lot of the features will work.
Calva can also start nbb and connect its REPL for you, using the Jack-in command. This will start an nbb nREPL server on a random port and connect Calva to it. Check out this video where they use Calva and nbb to create a CLI tool as an executable npm module:
In that video they ask for a JavaScript to ClojureScript converter. And there is one: https://mauricioszabo.gitlab.io/js2cljs/
Though if you are using Calva, this converter is easier to use directly via the command Calva: Convert JavaScript to ClojureScript:
Errors jacking in to nbb on Windows?
On some machines it seems necessary to first run npx nbb
from the CMD
prompt to make jack-in work. Or try first install it npm i -g nbb
. (You probabl want nbb installed globally anyway.)
Don't expect complete support
nbb's nREPL server is completely new and and WIP. It will be a bit limited compared to a full cider-nrepl enhanced \"regular\" Clojure nREPL server. Things like function signatures, and more do not work.
It's a bit hacky
The nbb nREPL server is the first ClojureScript nREPL server around and throws Calva's assumption that an nREPL server is always started in a Clojure process out the window. The nbb Jack-in/connect option \u201dpretends\u201d it is connecting to a Clojure nREPL and then the code fro promoting the nREPL session to a ClojureScript one is just dummy code.
This means that if you open a Clojure (.clj
) file while connected to an nbb nREPL server, it will still be a ClojureScript session serving even though Calva will indicate that it is a Clojure one. Bare with us until we can fix this properly in Calva.
WIP: Notebook support is very basic and experimental
Please help test the feature. We're looking forward to your feedback!
You can open any Clojure file as a notebook by right clicking the file -> Open with...
-> Clojure Notebook
.
Running cells sends them to the REPL and pretty prints the results. If the return is a string that starts with <html
it will be displayed in an html webview.
Forms inside (comment)
blocks get shown as their own cells. When adding code blocks in between those cells they get saved with the same indentation as the first form.
Together with Calva there is an extension called Calva Spritz installed. It only provides the association of Clojure file types to Clojure Notebooks. This is due to the LiveShare issues mentioned above. So that you can disable the Notebook association when participating as a guest in LiveShare sessions. The issue is tracked here:
nREPL and cider-nrepl middleware enable Calva to support full Interactive Programming.
","boost":2},{"location":"nrepl_and_cider-nrepl/#about-nrepl","title":"About nREPL","text":"The REPL is a Clojurists quintessential tool, it\u2019s what we use to do Interactive Development, the hallmark of the LISP style of development.
In Interactive Development (more commonly but somewhat imprecisely referred to as REPL-driven development), the programmer\u2019s editor has a direct connection with the running application process. This allows evaluating pieces of code in the context of a running program, directly from where the code is written (and so not in some separate \u201cREPL place\u201d), inspecting and manipulating the innards of the process. This is helped along by the dynamic nature of Clojure in which any var can be redefined at any point, allowing for quick incremental and iterative experimentation and development.
This is why it\u2019s essential to the Clojure development experience to have proper editor support, a plugin which bridges the gap between where the code is written and where the code is run. So we have CIDER for Emacs, Calva for VS Code, Cursive for IntelliJ, Conjure or Iced for Vim, and so forth. Often these will also leverage the same (or a parallel) connection into the process for other editor affordances, like navigation and completion.
But for these editor plugins to connect to the Clojure process something needs to be listening on the other side, accepting connections, allowing the initiation of a program-to-program dialogue. The most common way to achieve this is by leveraging the nREPL protocol, an asynchronous message-based network protocol for driving interactive development. The application process is started with an embedded nREPL server, so that the editor can connect as an nREPL client.
From: Lambda Island
","boost":2},{"location":"nrepl_and_cider-nrepl/#about-the-nrepl-server-and-middleware","title":"About the nREPL Server and Middleware","text":"nREPL is an extensible protocol, the reference server implementation understands certain core operation types like \"eval\". More operations can be supported, or existing operations can be modified or augmented, through nREPL middleware. For example: the Piggieback middleware can intercept \"eval\" messages, and forward them to a ClojureScript environment, rather than evaluating them in the Clojure process itself.
Which middleware to use will mostly depend on the editor you are using. You\u2019ll typically find that the Clojure-specific functionality for a given editor is partly implemented as a typical editor extension, for instance CIDER written in Emacs LISP, or Calva written in Typescript, and partly as nREPL middleware, providing the functionality the editor extension relies on. For instance, both CIDER and Calva rely on functionality provided by cider-nrepl.
Also from: Lambda Island
","boost":2},{"location":"nrepl_and_cider-nrepl/#viewing-the-communication-between-calva-and-nrepl","title":"Viewing the Communication Between Calva and nREPL","text":"You can view the messages sent between Calva and nREPL by running the command Toggle nREPL Logging Enabled
. Enabling nREPL message logging triggers the creation of a VS Code output channel called nREPL Messages
where the messages will be logged. Messages sent to nREPL from Calva will have -> sent
above them, and messages sent from nREPL to Calva will have <- received
above them. Disabling nREPL message logging causes the nREPL Messages
channel to be removed and messages will no longer be logged.
Each message is logged as JSON. If you find a need for the messages to be logged as EDN (for example, to transform and analyze them with Clojure) please open a GitHub issue for this change. A PR would be welcome too!
The example below shows two messages logged when the cursor hovers over println
in a Clojure file while a REPL is connected.
-> sent\n{\n op: 'info',\n ns: 'test-lein.core',\n symbol: 'println',\n id: '7',\n session: '1a080b66-b1b6-4b8c-8206-c4af2cc02747'\n}\n\n<- received\n{\n added: '1.0',\n 'arglists-str': '[& more]',\n column: 1,\n doc: 'Same as print followed by (newline)',\n file: 'jar:file:/Users/brandon/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar!/clojure/core.clj',\n id: '7',\n line: 3733,\n name: 'println',\n ns: 'clojure.core',\n resource: 'clojure/core.clj',\n 'see-also': [\n 'clojure.core/prn',\n 'clojure.core/print',\n 'clojure.core/println-str',\n 'clojure.pprint/pprint'\n ],\n session: '1a080b66-b1b6-4b8c-8206-c4af2cc02747',\n static: 'true',\n status: [ 'done' ]\n}\n
","boost":2},{"location":"output/","title":"Output Destinations","text":"Calva categorizes output into three types:
With the setting calva.outputDestinations
, you can configure where each category of output should go to:
The reason there are several options for this is partly legacy and partly because VS Code restricts the placement of different views in different ways. We hope you will find a combination of output destinations that suits you.
"},{"location":"output/#commands-for-showing-output-destinations","title":"Commands for showing output destinations","text":"These are the commands and their default keyboard shortcuts for revealing output destinations
ctrl+alt+o o
ctrl+alt+o c
ctrl+alt+o t
ctrl+alt+o r
Since Calva v2.0.423 the REPL Window prints stdout
prepended with ;
to make it into line comments. This is because stdout output easily breaks the Clojure structure of the REPL Window, making it misbehave in various ways. We made this change because as maintainers of Calva we have seen all too often how this hits users, and it is also taking too much of our Calva time to try mitigate the problem, which is fundamentally not fixable.
There are now other output destinations that do not have this limitation.
All that said. If you want to keep using the REPL Window for stdout output, and need the old behavior, you can enable the setting: calva.legacyPrintBareReplWindowOutput
. Please note that at some point after we have created a dedicated Output Window, the REPL Window will be retired as a destination for output.
When Calva is connected to the REPL, the Output window will by default print not only results of evaluations, but also:
stdout
and stderr
in the main thread of the evaluationsstdout
and stderr
from child threads of the evaluationsstdout
and stderr
by the REPL processYou can control the default via the calva.redirectServerOutputToRepl
setting. It defaults to true
. Setting it to false
before connecting the REPL will result in that 2. and 3. will not get printed in the Output window. It will then instead be printed wherever the REPL process is printing its messages, usually the terminal from where it was started (the Jack-in terminal if Calva started the REPL).
Structural editing and navigation for Clojure.
","boost":7},{"location":"paredit/#what-is-paredit","title":"What is Paredit?","text":"Calva Paredit helps you navigate, select and edit Clojure code in a structural way. LISP isn't line or character oriented, it is based around S-expressions, a.k.a forms. We strongly recommend that you take advantage of the structural nature of Clojure, and have therefore put a lot of work into making Calva Paredit extra awesome.
If you are new to Paredit, consider starting with learning the Slurp Forward (pull in the next form into this form) and Barf Forward (push the last form out of this form). It will take you quite far.
","boost":7},{"location":"paredit/#strict-mode","title":"Strict Mode","text":"To protect the integrity of your code, Strict mode is enabled by default.
Strict mode keybinding Action Descriptionbackspace
Delete Backward Deletes one character backwards, unless it will unbalance a form. Otherwise moves past the character instead of deleting it. If the list is empty, it will remove both open and close brackets. delete
Delete Forward Deletes one character forwards, unless it will unbalance a form. Otherwise moves past the character instead of deleting it. If the list is empty, it is removed. alt+backspace
Force Delete Backward Deletes one character backwards, even if it will unbalance a form. alt+delete
Force Delete Forward Deletes one character forwards, even if it will unbalance a form. Disable at your own peril. Strict mode can be toggled on/off using the Toggle Paredit Mode command, and there is a status bar indicator telling you:
Indicator Paredit Mode[\u03bb]
Strict (\u03bb)
Cave Man (strict mode off) \u03bb
No default key bindings Toggle between Strict and Cave Man using: ctrl+alt+p ctrl+alt+m
There is also a setting, calva.paredit.strictPreventUnmatchedClosingBracket
, that will help you to not enter unbalanced closing brackets into the code.
The Paredit commands are sorted into Navigation, Selection, and Edit. As mentioned, Slurp and Barf are power commands, which go into the editing category. Learning to navigate structurally, using shortcuts, also saves time and adds precision to your editing. It has the double effect that you at the same time learn how to select structurally, because that is the same, just adding the shift key.
To make the command descriptions a bit clearer, each entry is animated. When you try to figure out what is going on in the GIFs, focus on where the cursor is at the start of the animation loop.
","boost":7},{"location":"paredit/#strings-are-not-lists-but-anyway","title":"Strings are not Lists, but Anyway...","text":"In Calva Paredit, strings are treated in much the same way as lists are. Here's an example showing Slurp and Barf, Forward/Backward List, and Expand Selection.
","boost":7},{"location":"paredit/#navigating","title":"Navigating","text":"(Modify these with shift
to select rather than move, see below.)
ctrl+right
(win/linux)alt+right
(mac) Forward Sexp Moves the cursor forward, to the end of the current form. If at the end, moves to the end of the next form. Will not move out of lists. ctrl+left
(win/linux)alt+left
(mac) Backward Sexp Moves the cursor backward, to the start of the current form. If at the start, moves to the start of the previous form. Will not move out of lists. ctrl+down
Forward Down Sexp Moves the cursor into the following list. ctrl+alt+up
Backward Down Sexp Moves the cursor into the preceding list. ctrl+alt+down
Forward Up Sexp Moves the cursor forwards, out of the current list. ctrl+up
Backward Up Sexp Moves the cursor backwards, out of the current list. Unbound Forward Sexp Or Up Moves the cursor forward, to the end of the current form. If at the end, moves to the end of the next form. Moves out of the lists if at the end of it. Unbound Backward Sexp Or Up Moves the cursor backward, to the start of the current form. If at the start, moves to the start of the previous form. Moves out of the list if at the start of it. ctrl+end
Forward to List End/Close Moves the cursor forwards, staying within the current list. ctrl+home
Backward to List Start/Open Moves the cursor backwards, staying within the current list.","boost":7},{"location":"paredit/#selecting","title":"Selecting","text":"Most of these commands are selecting \u201dversions\u201d of the navigation commands above. Repeated use will grow the current selection step by step.
Default keybinding Action Descriptionshift+alt+right
(win/linux)ctrl+w
(mac) Expand Selection Starts from the cursor and selects the current form. Then will keep expanding to enclosing forms. shift+alt+left
(win/linux)ctrl+shift+w
(mac) Shrink Selection Contracts back from an expanded selection performed by any Paredit selection command. (In the animation the selection is first grown using a combination of Expand Selection and some lateral selection commands, then shrunk all the way back down to no selection.) ctrl+alt+w space
Select Top Level Form Top level in a structural sense. Typically where your(def ...)
/(defn ...)
type forms. Please note that(comment ...)
forms create a new top level. shift+ctrl+right
(win/linux)shift+alt+right
(mac) Select Forward Sexp ctrl+shift+k
Select Right Select forward to the end of the current form or the first newline. See Kill right below. (The animation also shows Shrink Selection). shift+ctrl+left
(win/linux)shift+alt+left
(mac) Select Backward Sexp ctrl+shift+down
Select Forward Down Sexp (You probably do not need to select like this, but you can!) ctrl+shift+alt+up
Select Backward Down Sexp (You probably do not need to select like this, but you can!) ctrl+shift+alt+down
Select Forward Up Sexp (You probably do not need to select like this, but you can!) ctrl+shift+up
Select Backward Up Sexp (You probably do not need to select like this, but you can!) Unbound Select Forward Sexp Or Up (You probably do not need to select like this, but you can!) Unbound Select Backward Sexp Or Up (You probably do not need to select like this, but you can!) ctrl+shift+end
Select Forward to List End/Close ctrl+shift+home
Select Backward to List Start/Open","boost":7},{"location":"paredit/#editing","title":"Editing","text":"Default keybinding Action Description ctrl+alt+right
(mac/win)ctrl+alt+.
(linux) Slurp Forward Moves the closing bracket forward, away from the cursor, past the following form, if any. ctrl+alt+left
(mac/win)ctrl+alt+,
(linux) Barf Forward Moves the closing bracket backward, towards the cursor, past the preceding form. ctrl+alt+shift+left
Slurp Backward Moves the opening bracket backward, away from the cursor, past the preceding form, if any. ctrl+alt+shift+right
Barf Backward Moves the opening bracket forward, towards the cursor, past the following form. ctrl+alt+s
Splice Sexp Remove enclosing brackets. ctrl+shift+s
Split Sexp Splits a string, or a list, into two strings, or lists of the same type as the current. ctrl+shift+j
Join Sexps/Forms Joins two strings, or two lists of the same type, into one form (string/list). ctrl+alt+p ctrl+alt+r
Raise Sexp Replaces the enclosing list with the current form. ctrl+alt+t
Transpose Sexps/Forms Swaps place of the two forms surrounding the cursor. alt+up
alt+down
Drag Sexp Backward/Forward Moves the current form to the behind/in front of the previous/next one. (See below about behavior in maps and binding boxes.) ctrl+alt+shift
u
ctrl+alt+shift
d
Drag Sexp Backward UpDrag Sexp Forward Down Moves the current form up/out of the current list, backwards, and down/in to the following list, forwards, keeping the cursor within the sexpr being dragged. ctrl+alt+shift
k
ctrl+alt+shift
j
Drag Sexp Forward UpDrag Sexp Backward Down Moves the current form up/out of the current list, forwards, and down/in to the preceding list, backwards, keeping the cursor within the sexpr being dragged. ctrl+shift+c
Convolute \u00af\\_(\u30c4)_/\u00af ctrl+shift+delete
Kill Sexp Forward Deletes the next form in the same enclosing form as the cursor. ctrl+k ctrl+k
(win/linux)ctrl+k
(mac) Kill Right Delete forward to the end of the current form or the first newline. ctrl+k ctrl+h
(win/linux)cmd+backspace
(mac) Kill Left Delete backward to the start of the current form or the start of the line. ctrl+alt+backspace
Kill Sexp Backward Deletes the previous form in the same enclosing form as the cursor. ctrl+delete
Kill List Forward Deletes everything from the cursor to the closing of the current enclosing form. ctrl+backspace
Kill List Backward Deletes everything from the cursor to the opening of the current enclosing form. ctrl+alt+shift+delete
Splice Killing Forward Delete forward to end of the list, then Splice. ctrl+alt+shift+backspace
Splice Killing Backwards Delete backward to the start of the list, then Splice. ctrl+alt+shift+p
Wrap Around () Wraps the current form, or selection, with parens. ctrl+alt+shift+s
Wrap Around [] Wraps the current form, or selection, with square brackets. ctrl+alt+shift+c
Wrap Around {} Wraps the current form, or selection, with curlies. ctrl+alt+shift+q
Wrap Around \"\" Wraps the current form, or selection, with double quotes. Inside strings it will quote the quotes. ctrl+alt+r
ctrl+alt+p
/s
/c
/q
/h
Rewrap Changes enclosing brackets of the current form to parens/square brackets/curlies/double quotes and set (#{}
) Copy to Clipboard when killing text
You can have the kill commands always copy the deleted code to the clipboard by setting calva.paredit.killAlsoCutsToClipboard
to true
. If you want to do this more on-demand, you can kill text by using the selection commands and then Cut once you have the selection.
clojure-lsp drag fwd/back overlap
As an experimental feature, the two commands for dragging forms forward and backward have clojure-lsp alternativs. See the clojure-lsp page.
","boost":7},{"location":"paredit/#drag-bindings-forwardbackward","title":"Drag bindings forward/backward","text":"When dragging forms inside maps and binding boxes, such as with let
, for
, binding
, etcetera, it often makes most sense to drag each binding as a pair. And this is what Calva will do. Like so:
And like so (wait for it):
","boost":7},{"location":"paredit/#about-the-keyboard-shortcuts","title":"About the Keyboard Shortcuts","text":"Care has been put in to making the default keybindings somewhat logical, easy to use, and work with most keyboard layouts. Slurp and barf forward are extra accessible to go with the recommendation to learn using these two super handy editing commands.
You can relax how Paredit's shortcuts replace VS Code built in shortcuts a bit by setting calva.paredit.hijackVSCodeDefaults
to false
.
There are some context keys you can utilize to configure keyboard shortcuts with precision. See Customizing Keyboard Shortcuts.
The Nuclear Option: You can choose to disable all default key bindings by configuring calva.paredit.defaultKeyMap
to none
. (Then you probably also want to register your own shortcuts for the commands you often use.)
In some instances built-in command defaults are the same as Paredit's defaults, and Paredit's functionality in a particular case is less than what the default is. This is true of Expand Selection and Shrink Selection for Windows/Linux when multiple lines are selected. In this particular case adding !editorHasMultipleSelections
to the when
clause of the binding makes for a better workflow. The point is that when the bindings overlap and default functionality is desired peaceful integration can be achieved with the right when
clause. This is left out of Paredit's defaults to respect user preference, and ease of maintenance.
Happy Editing! \u2764\ufe0f
","boost":7},{"location":"paredit/#experimental-feature-multicursor-support","title":"Experimental Feature: Multicursor support","text":"There is an ongoing effort to support simultaneous multicursor editing with Paredit. This is an experimental feature and is not enabled by default. To enable it, set calva.paredit.multicursor
to true
. This feature is still in development and may not work as expected in all cases. Currently, this supports the following categories:
Reverted in Calva v2.0.228
The changes in v2.0.227 seemed to cause problems for some users. Unclear yet if and why. But to not risk causing problems for more users these changes where reverted and Calva v2.0.228 does not contain them. Please consider using v2.0.227 and help find what the problems are about! Please note: Even in v2.0.227 this feature is currently disabled by default.
Parinfer is a system for editing the structure of LISP text without explicit commands. The structure can be regarded as already being expressed through indentation. With Parinfer you can use your intuition about the structure inferred from the indentation to perform surprisingly many structural edits.
"},{"location":"parinfer/#quirks","title":"Quirks","text":"There are some known quirks, of varying severity, with this feature. Some of them will need to be fixed before we move this feature out of Experimental status.
For the most times you can always Undo to get back to where the document was fine. You just need to pay some attention and be aware when undo is needed.
"},{"location":"parinfer/#no-multi-cursor-support","title":"No multi-cursor support","text":"The bracket inference will remove all cursors but the first one. So for instance if you edit with multiple cursors and it causes brackets to move, you'll end up with just one cursor and the subsequent edits will not be what you intended. This is particularly important to note when you have cursors that are not in the viewport. In such cases it might be better to turn Parinfer off while you do the edits, fix formatting and such manually and then switch Parinfer on again.
"},{"location":"parinfer/#wrong-inferences","title":"Wrong inferences","text":"For yet unknown reasons an edit such as the following does the wrong thing (the cursor indicated by the vertical bar):
(foo| (bar)\n(baz))\n
backspace =>
(fo| (bar\n(baz)))\n
That is (baz)
is slurped. When what should happen is:
(fo| (bar)\n(baz))\n
"},{"location":"parinfer/#lag-causing-errors-when-fast-typing","title":"Lag causing errors when fast typing","text":"The way that Calva Parinfer works is that for any edit of the document it first reformats the code around the cursor, then infer brackets. Currently these two steps are not atomic to VS Code, so if you type fast bracket inference might happen on the yet unformatted code, and thus not be correct. You might also see the cursor end up at the wrong position at times.
"},{"location":"parinfer/#infer-parens","title":"Infer Parens","text":"This is no longer available in Calva
See above about how to try this build anyway, warts and all.
When you enable Calva's Parinfer it is all about infering brackets from indentation. There are no further Parinfer modes. Calva's auto-formatter will take care of keeping the code correctly indented.
Enable it with from this setting: calva.fmt.experimental.inferParensAsYouType
or from the status bar item.
To the right on the status bar, right before the Paredit status bar item, you will have two items, Parinfer toggle ON/OFF and a health indicator.
When Parinfer is ON, the health indicator will have three states:
Parinfer will be disabled in both the unhealthy states.
When Parinfer is OFF, only the first two states above are used.
"},{"location":"parinfer/#some-vs-code-settings-automatically-changed","title":"Some VS Code Settings automatically changed","text":"In order for some automatic VS Code behaviour not to interfere with Parinfer the following settings are automatically configured when you toggle Parinfer ON:
\"[clojure]\": {\n\"editor.autoClosingBrackets\": \"never\",\n\"editor.autoClosingOvertype\": \"never\",\n\"editor.formatOnPaste\": false\n},\n
And when you toggle Parinfer OFF:
\"[clojure]\": {\n\"editor.autoClosingBrackets\": \"always\",\n\"editor.autoClosingOvertype\": \"always\",\n\"editor.formatOnPaste\": true\n},\n
It is recommended that you let Calva handle these settings to avoid weird behaviour.
"},{"location":"parinfer/#no-tab-indenting","title":"No Tab indenting","text":"As the tab
key is used for formatting the current form in Calva, it is \u201dtaken\u201d. The closest equivalents you have are space
and backspace
. At least for now. We'll see if we can find out a good way for supporting tab
and shift+tab
for indent and dedent.
tab
for formatting is of course just a default key binding and you can assign it to something else to get it to do indenting. However, it will not be a very smart indent anyway, there is no Clojure awareness about it. You are hereby adviced to instead use some more spaces.
In Calva, Parinfer and Paredit are designed to coexist and both be there to let you edit the structure easily and efficiently. Since Paredit commands are always formatted, they leave the code in a state where Parinfer has what it needs to infer bracket placement as you either edit the indentation, or remove/add brackets.
"},{"location":"parinfer/#disable-the-parinfer-extension","title":"Disable the Parinfer Extension","text":"If you want to have Parinfer you are probably best served by Calva's built-in version. It is designed, and will continue to be improved to function well together with Calva's other structural editing and formatting features. It will also probably conflict with the Parinfer Extension.
"},{"location":"parinfer/#see-also","title":"See also","text":"Polylith is an architecture for backend projects that maximizes development ergonomics and code reuse.
When developing a Polylith application you use one REPL for everything. And as such it is a rather vanilla deps.edn
project, so there is really not much more to using Calva with Polylith than:
deps.edn
project type:dev
and :test
To make it easy to try Polylith out with Calva, the Polylith RealWorld example implementation has some Calva config to get the server started and Calva connected to its REPL quickly:
Polylith RealWorld Server REPL
project typeclj\ua789dev.server\ua789>
(start! 6003)
A ClojureScript frontend, of course:
api-url
definition in events.cljs
file to be (def api-url \"http://localhost:6003/api\")\n
:app
buildIn Calva, pretty printing is a mode. Prettiness is on by default and all your evaluation results will get that treatment.
You can also pretty print code on demand
There is a command Replace Current Form (or Selection) with Pretty Printed Form. See Clojure Formmatting for more on this.
"},{"location":"pprint/#toggle-it","title":"Toggle it","text":"There is a pprint
indicator to the right in the status bar which shows the status of the mode. Click the indicator to toggle prettification on and off. There is also a Calva: Toggle Pretty Printing for All Evaluations command.
Tip: If you have evaluated something time consuming, or that is not idempotent, with pretty printing mistakenly off: toggle it on and evaluate *1
.
For most people the defaults will probably work, but Calva pretty printing comes a few knobs you can turn, and they are all available through the calva.prettyPrintingOptions
settings. Things you can set are:
enabled
boolean So this is a third way you can change this mode \ud83d\ude04 printEngine
enum Which printer function that will be used. Default is pprint
, more about this setting below printFn
object You can configure Calva to use a custom nREPL
compatible print
function, more below. width
number The maximum line length of printed output (or at least the printers will try) maxLength
number The maximum number of elements printed in nested nodes, good for evaluating something like (iterate inc 0)
, which you shouldn't do without setting maxLength
. Most printers will indicate truncated lists with ...
at the end. maxDepth
number The maximum number of levels deep that will get printed. Different printers mark a stop different ways. puget
doesn't support it at all. See Customizing Calva for some tips on adding settings like these.
Here's an example of how zprint
handles maxDepth
(from the Calva implementation of it's client side pretty printing.).
(pretty-print [[[[[[[[:deeper]]]]]]]] {:max-depth 4})\n;; => {:value \"[[[[##]]]]\"}\n
"},{"location":"pprint/#your-selection-of-prettifiers","title":"Your Selection of Prettifiers","text":"Pretty printing can happen on the server (i.e. in the JVM, via nREPL), or on the client (i.e. in node, via VS Code/Calva). Client side always uses zprint
. Server side you can choose from these printers:
calva
client The nREPL server will plain print the results, and then Calva will pretty it (using zprint
). pprint
server Current Calva default. clojure.core/pprint
is a bit basic, but it's tried and tested, and doesn't suffer from the issues with the other server side printing options, mentioned below. fipp
server puget
server Lacks maxDepth
option. zprint
server A very good option. However, it will need to be configured before Jack-in if you want Calva's help to inject its dependencies. (If you are not using Jack-in, you'll need to supply this dependency yourself.) These particular server side functions were chosen because they have pre-configured print-functions in cider-nrepl
.
printFn
","text":"If the selection of built-in printEngine
support doesn't cut it, you can configure a custom function. This function will need to conform to the requirements of nREPL print functions. The VS Code settings editor will help you configure this one. (This is also a bit experimental, please consider giving feedback about how it works for you if you try it.)
This matters because on the server all pretty printers, except pprint
does more than just pretty print the result that would be printed with plain printing. Pretty printing results on the server causes some results to get expanded. This can have huge implications depending on the results and which printer is used. E.g. for Datomic transaction results, you will get the whole database printed. Twice. Depending on the database, you could be so unlucky that nothing gets printed, and instead you will soon have a very hot computer.
Note: With the help of zprint creator, Kim Kinnear, we have found ways to compensate for this problem. Ways that are not yet implemented, but please stay tuned.
Then why not always do it client side? It turns out that on the client side there are also things going on. Calva gets the results back as a string and therefore it needs to first be parsed back to EDN, before it can be pretty printed by zprint
. And \u2013 here's the catch \u2013 all results are not valid EDN and therefore can't be pretty printed by zprint
. Datomic transaction results are one example.
The current options are limited, because our time developing Calva is limited. But cider-nrepl
really allows for fully configurable pretty printing, so it is within reach. Please feel invited to give us feedback on what you would want to configure for the printing of results. File issues and/or chat us up in #calva in the Clojurians slack.
If pprint is not working, try a different pprint engine or use Calva's jack-in to make sure the necessary dependencies are loaded in your REPL. If you are starting your REPL without jack-in and want to continue doing so, you can use the command Copy Jack-in Command Line to Clipboard
then paste the command somewhere to see what dependencies it injects. You can then add these dependencies to your REPL in whatever way suits your needs.
Enjoy Prettiful Printing! \u2764\ufe0f
"},{"location":"quirks/","title":"Quirks","text":"Here's a shocker for ya': Calva isn't perfect. \ud83d\ude04
There are quirks and things that flat out do not work. We'll try to collect info about such things here, providing workarounds when available (or, rather, known to us).
"},{"location":"quirks/#test-features-not-available-with-clojurescript","title":"Test features not available with ClojureScript","text":"Currently cider-nrepl
does not provide its test functionality for ClojureScript code. Please consider contributing to fixing that.
See Using with Parinfer
"},{"location":"quirks/#calva-and-the-vim-extension","title":"Calva and the VIM Extension","text":"See Using Calva with the VIM Extension.
"},{"location":"quirks/#command-not-found-errors-on-jack-in","title":"\u201dCommand not found\u201d Errors on Jack-in","text":"Jack-in starts by running a command in a new terminal. You will need the commands used installed on your computer:
clojure
for tools.deps/deps.ednlein
for Leiningennpx
for shadow-cljsgradlew
for Gradle (in your project)Also, in some circumstances VS Code is not spawned from a shell with the environment variables, especially $PATH
, which might mean that even though you have the tools installed, they are not found when VS Code/Calva tries to execute them. To fix this you will need to do one of these two things:
$PATH
there includes the directory with the needed binary.$PATH
is correctly configured. (Using the code
command.)See this issue for more clues on this problem.
"},{"location":"quirks/#strange-linting-errors","title":"Strange linting errors?","text":"This is not really a quirk, and most linting errors are not strange when you learn about why they are there. Calva does not do any linting, btw, see also linting.
"},{"location":"quirks/#consider-uninstalling-these-extensions","title":"Consider uninstalling these extensions","text":"Without Calva, many users install other nifty extensions (some of which are old pieces of Calva) that help with this or that problem. It might sometimes work together with Calva, sometimes not. Here's a list of some common extensions you should consider to at least disable:
The re-frame template creates a shadow-cljs
project, making it easy to use with Calva.
npm install
ctrl+alt+c ctrl+alt+j
.shadow-cljs
project and ask for which build to compile.:app
.:app
is the only configured build, but the VS Code menu for this is a bit strange so make sure the :app
checkbox is really ticked before proceeding.:app
.Ctrl+C
in this pane will kill your app and free up all resources it has allocated.views.cljs
file from src/<your-project-name>
and issue Calva: Load/Evaluate Current File and its Requires/Dependencies. ctrl+alt+c enter
.(js/alert \"Hello from Calva\")
(alt+enter
and ctrl+enter
are your friends).REBL is a graphical, interactive tool for browsing Clojure data.
"},{"location":"rebl/#depsedn","title":"deps.edn","text":"Add the following aliases to your deps.edn file. Use the deps.edn file in the ~/.clojure
directory to enable alias reuse across multiple projects. This is the configuration for REBL on openjdk 12. Check out the REBL github page for more info.
;; REBL Base\n:rebl\n{:extra-deps {org.clojure/core.async {:mvn/version \"0.4.490\"}\n;; deps for file datafication (0.9.149 or later)\norg.clojure/data.csv {:mvn/version \"0.1.4\"}\norg.clojure/data.json {:mvn/version \"0.2.3\"}\norg.yaml/snakeyaml {:mvn/version \"1.23\"}\ncom.cognitect/rebl\n;; adjust to match your install location\n{:local/root \"/Users/ozimos/REBL/latest/REBL.jar\"}}}\n\n;; REBL 12\n:rebl-12\n{:extra-deps {org.openjfx/javafx-fxml {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-controls {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-graphics {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-media {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-swing {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-base {:mvn/version \"12.0.1\"}\norg.openjfx/javafx-web {:mvn/version \"12.0.1\"}}}\n\n;; nREBL\n:nrebl {:extra-deps {rickmoynihan/nrebl.middleware {:mvn/version \"0.2.0\"}}\n:main-opts [\"-e\" \"((requiring-resolve,'cognitect.rebl/ui))\" \"-m\" \"nrepl.cmdline\" \"--middleware\" \"[nrebl.middleware/wrap-nrebl]\" \"-I\"]}\n
Create a Calva custom connect sequence for your VSCode editor. (Read Custom REPL Connect Sequences if you haven't.) Add the following to your vscode settings.json:
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Rebl Connect\",\n\"projectType\": \"deps.edn\",\n\"menuSelections\": {\n\"cljAliases\": [\n\"rebl\",\n\"rebl-12\",\n\"nrebl\"\n]\n}\n}\n]\n}\n
"},{"location":"rebl/#leiningen","title":"Leiningen","text":"Add rebl profiles to your user-wide profiles so that they will be available for all your projects. Here's a sample user profile (located at ~/.lein/profiles.clj
on mac):
{:user {:plugins [[lein-ancient \"0.6.15\"]]}\n\n;; REBL Base\n:rebl {:resource-paths [\"/Users/ozimos/REBL/latest/REBL.jar\"]\n:dependencies [[org.clojure/core.async \"0.4.490\"]\n[org.clojure/data.csv \"0.1.4\"]\n[org.clojure/data.json \"0.2.3\"]\n[cljfmt \"0.6.4\"]\n[org.yaml/snakeyaml \"1.23\"]]}\n\n;; REBL 12 for JDK 12.0.1. Swap out for your JDK version\n:rebl-12 {:dependencies [[org.openjfx/javafx-fxml \"12.0.1\"]\n[org.openjfx/javafx-controls \"12.0.1\"]\n[org.openjfx/javafx-graphics \"12.0.1\"]\n[org.openjfx/javafx-media \"12.0.1\"]\n[org.openjfx/javafx-swing \"12.0.1\"]\n[org.openjfx/javafx-base \"12.0.1\"]\n[org.openjfx/javafx-web \"12.0.1\"]]}\n\n;; NREBL https://github.com/RickMoynihan/nrebl.middleware\n:nrebl {:repl-options {:nrepl-middleware [nrebl.middleware/wrap-nrebl]}\n:dependencies [[rickmoynihan/nrebl.middleware \"0.3.1\"]]}}\n
More info here Create a Calva custom connect sequence for your VSCode editor. (Read Custom REPL Connect Sequences if you haven't.) Add the following to your vscode settings.json:
{\n\"calva.replConnectSequences\": [\n{\n\"name\": \"Lein REBL\",\n\"projectType\": \"Leiningen\",\n\"menuSelections\": {\n\"leinProfiles\": [\"rebl\", \"rebl-12\", \":nrebl\"]\n},\n\"afterCLJReplJackInCode\": \"((requiring-resolve 'cognitect.rebl/ui))\"\n}\n]\n}\n
"},{"location":"rebl/#shadow-cljs-tbd","title":"shadow-cljs (TBD)","text":"TBD. If you know how to do it, please update this page.
"},{"location":"refactoring/","title":"Refactoring","text":"There are two \u201dflavours\u201d to refactoring support. Some (just a few) refactorings are made available as Quick Fix suggestions (the light bulb), the rest are regular commands in the clojure-lsp Refactoring category.
You can enable or disable the Quick Fix suggestion lightbulb using the VS Code setting editor.lightbulb.enabled
.
The refactoring commands do not have default keyboard shortcuts. You find them all by typing \u201dclojure-lsp Refactor\u201d in the Command Palette.
"},{"location":"refactoring/#commands","title":"Commands","text":"Command Title Command Key Description Clean NS FormclojureLsp.refactor.cleanNs
Add Missing Require clojureLsp.refactor.addMissingLibspec
Extract to New Function clojureLsp.refactor.extractFunction
Cycle/Toggle Privacy clojureLsp.refactor.cyclePrivacy
Inline Symbol clojureLsp.refactor.inlineSymbol
Introduce let clojureLsp.refactor.introduceLet
Creates a new let box with the binding. Follow up with \u201dExpand let\u201d to move it upwards. Expand Let clojureLsp.refactor.expandLet
Move to Previous let Box clojureLsp.refactor.moveToLet
Thread First clojureLsp.refactor.threadFirst
Thread First All clojureLsp.refactor.threadFirstAll
Thread Last clojureLsp.refactor.threadLast
Thread Last All clojureLsp.refactor.threadLastAll
Unwind All clojureLsp.refactor.unwindAll
Unwind Thread clojureLsp.refactor.unwindThread
Formatting
The way that some of the refactorings are applied to the document, makes it difficult for Calva to format the results. So, sometimes you'll need to navigate the cursor to the enclosing form and hit tab
to tidy up the formatting after a refactoring. See also Formatting.
Most of Calva's refactoring support is sourced directly from clojure-lsp. This also means that most often, if you find issues with refactoring, or have suggestions about it, the clojure-lsp repo is where to direct your reporting.
"},{"location":"remote-development/","title":"Using Calva with Remote Development","text":"VS Code Remote Development is a new feature in version 1.35 of VS Code that allows a developer to use a container, remote machine, or the Windows Subsystem for Linux (WSL) as a full-featured development environment.
I would recommend reading the introductory blog post and watching the videos. I find the feature extremely exciting and wish more IDEs would implement something like it.
From a Clojure perspective it allows you to have VS Code installed on your Java-less, Clojure-less hardware and still use it to develop Clojure through it.
"},{"location":"remote-development/#a-use-case","title":"A use-case","text":"Run Remote-Containers: Add Development Container Configuration Files... and pick a suitable Java base image. Then:
"},{"location":"remote-development/#modify-dockerfile-to-install-clojure-cli-and-optionally-lein","title":"Modify Dockerfile to install Clojure CLI (and optionally lein)","text":"Add:
# ...\n\n# Install Clojure - see https://github.com/Quantisan/docker-clojure/blob/master/target/openjdk-14-slim-buster/tools-deps/Dockerfile\nENV CLOJURE_VERSION=1.10.1.619\nWORKDIR /tmp\nRUN \\\napt-get update && \\\napt-get install -y curl make rlwrap wget && \\\nrm -rf /var/lib/apt/lists/* && \\\nwget https://download.clojure.org/install/linux-install-$CLOJURE_VERSION.sh && \\\nsha256sum linux-install-$CLOJURE_VERSION.sh && \\\necho \"28b1652686426cdf856f83551b8ca01ff949b03bc9a533d270204d6511a8ca9d *linux-install-$CLOJURE_VERSION.sh\" | sha256sum -c - && \\\nchmod +x linux-install-$CLOJURE_VERSION.sh && \\\n./linux-install-$CLOJURE_VERSION.sh\nRUN \\\nsu vscode -c \"clojure -e '(clojure-version)'\" && \\\nrm ./linux-install-$CLOJURE_VERSION.sh\n\n# Install Lein\nRUN \\\nwget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein -O /bin/lein && \\\nchmod uog+x /bin/lein\nRUN su vscode -c \"/bin/lein\"\n\n# Cleanup\nRUN apt-get purge -y --auto-remove curl wget\n\n# ...\n
"},{"location":"remote-development/#modify-devcontainerjson","title":"Modify devcontainer.json","text":"Add Calva and, optionally, forward some ports to the host::
\"extensions\": [\"betterthantomorrow.calva\"],\n\"forwardPorts\": [8088, 52162], // example: your webapp, your nREPL\n
"},{"location":"remote-development/#build-and-start","title":"Build and start","text":"Run Remote-Containers: Rebuild and Reopen in container
"},{"location":"remote-development/#wsl","title":"WSL","text":"See Using Calva with WSL
"},{"location":"repl-window/","title":"The REPL Window/File","text":"The Calva REPL Window is actually a regular file with some extra treatment from Calva, like displaying a prompt, offering evaluation history recall and generally \u201cfollowing\u201d the current namespace. This file is created and opened when Calva is connected to a REPL. You can use it for experimental code (though there are also Rich Comments and Fiddle Files for this).
In ClojureScript projects, the window will be associated with the cljs
REPL once it is connected. It will then look something like this:
The first prompt is from when the clj
REPL is connected, and the second from cljs
. The first part of the prompt tells you which REPL type the window is currently connected to.
By default the REPL Window doubles as the place where Calva sends output like stdout/stderr and other messages. See Calva Output for more about this and how to change this behaviour.
"},{"location":"repl-window/#finding-the-repl-window","title":"Finding the REPL Window","text":"If you quickly want to open and/or switch to the REPL Window there is the command Calva: Show/Open REPL Window, ctrl+alt+o r
.
To sync the REPL window namespace with the current file before switching, use the Switch Namespace of the REPL Window to Current Namespace command, ctrl+alt+c alt+n
.
When you are editing things in the REPL window, and want to open the file that defines its current namespace, use the Show File for the Current REPL Window Namespace command, ctrl+alt+o r
.
Note
This also works for Clojure core and library namespaces.
"},{"location":"repl-window/#evaluating-code","title":"Evaluating Code","text":"The window will be automatically associated with the REPL and the namespace of any project Clojure/ClojureScript file you evaluate code in. So for instance if you evaluate this code in a clj
file with the namespace fresh-reagent.handler
:
(def mount-target\n[:div#app\n[:h2 \"Welcome to fresh-reagent\"]\n[:p \"please wait while Figwheel is waking up ...\"]\n[:p \"(Check the js console for hints if nothing exciting happens.)\"]])\n
If the REPL Window is the configured destination for evaluation results, the defined var will be printed there. Otherwise, it will be printed to the destination you've configured. In either case, the REPL window will print a new prompt reflecting the current REPL connection and namespace:
If you then switch to the output window (ctrl+alt+o r
), and enter this at the prompt:
mount-target\n
then evaluate it using alt+enter
, you'll get this:
... because the namespace \u201dfollowed\u201d the first evaluation in the REPL window.
"},{"location":"repl-window/#repl-history","title":"REPL History","text":"Recently evaluated forms in the REPL file are persisted and can easily be shown again for modifying and re-evaluating.
"},{"location":"repl-window/#navigate-repl-history","title":"Navigate REPL History","text":"You can navigate up and down the history of evaluated forms in the REPL file by pressing alt+up
and alt+down
, provided your cursor is at the end of the last form after the prompt. If the cursor is not at the end of the last form, then alt+up
and alt+down
will do whatever they are mapped to, which is by default \"Move Line Up\" and \"Move Line Down,\" respectively.
If you have typed some text after the prompt before you start traversing up the history, this text will be preserved and will display when you traverse back down the history. If you modify some text in the history while traversing, the modification will be saved at that location in history.
"},{"location":"repl-window/#clear-repl-history","title":"Clear REPL History","text":"You can clear the repl history by running the command \"Clear REPL History\" from the command palette.
"},{"location":"repl-window/#stack-traces","title":"Stack Traces","text":"When an evaluation produces an error, it will automatically be printed in the REPL Window. If there is a stack trace associated with the error, it can now be printed on demand using the Calva: Print Last Stacktrace to the Output Window command. You can also print the stack trace for any error message printed to the REPL Window via the Codelens button below it.
For printed stacktraces, when source locations are available (Clojure files), you will be able to navigate to them by pressing ctrl+click
(cmd+click
on Mac) on the file name. You can also hover over symbols in the stack trace to see the symbol's documentation, and ctrl+click
(cmd+click
on Mac) the symbol to Peek Definition.
Output destinations
If you have configured some other destination for stderr output, the error message will be printed there as well. But it will also be printed to the REPL Window, because the augmented stack traces need this (because reasons).
"},{"location":"repl-window/#load-current-namespace","title":"Load Current Namespace","text":"When navigating namespaces it is easy to forget to first require them and that can be tricky to debug. To help with this, Calva's command Load/Evaluate Current File and its Requires/Dependencies also works in the REPL Window, but there, it acts like Load Current Namespace.
Suppose you have two files, pez/xxx.clj
and pez/yyy.clj
, where pez.yyy
requires pez.xxx
.
(ns pez.xxx)\n\n(def a :xxx-a)\n\n(def b :xxx-b)\n
(ns pez.yyy\n(:require [pez.xxx]))\n\n(def a :yyy-a)\n\n(println \"Hello\" pez.xxx/a)\n
Then, with a freshly jacked-in REPL, you evaluate (ns pez.yyy)
and want to work with the vars defined there, Clojure will complain. But if you Load/Evaluate Current File and its Requires/Dependencies, it will start working. Something like so:
Note
This currently suffers from a limitation in Calva where it won't reload dependencies, so you will sometimes have to do this \u201dmanually\u201d anyways (by opening the files and loading them yourself). See Calva issue #907
"},{"location":"repl-window/#peek-current-namespace","title":"Peek Current Namespace","text":"A somewhat hidden feature: You can peek, see documentation for, and navigate to a namespace by hovering on the namespace symbol in one of the REPL Window prompts (just like you would if it was not in the prompt \ud83d\ude04).
"},{"location":"repl-window/#paredit-enabled","title":"Paredit Enabled","text":"The REPL Window is mostly a regular Calva Clojure/ClojureScript file, which makes everything that works in a regular file work in this file, including Paredit. This makes it easy to navigate the input and output there. For instance, to select the last evaluation results, you can press ctrl+w
(shift+alt+right
on Windows and Linux):
The output window is mostly a regular... (you get it), which means you also have the Calva debugger at your command at the REPL prompt (only for clj
sessions, for now). So instead of evaluating a function definition using alt+enter
, you can evaluate it and instrument it for debugging using ctrl+alt+c i
, and then call the function.
The contents of the output/REPL window is written to a file named output.repl
in the .calva/output-window
directory of your project. The file is recreated every new session, so you should copy or save anything you want to preserve between sessions.
You probably want to add .calva/output-window/
to your .<something>ignore
files. (There are some more files in that directory that you shouldn't keep under source control.)
In full-stack projects, you will probably use the window as a REPL for both clj
and cljs
. You can toggle which REPL the window is connected to by using the command Calva: Toggle REPL Connection for CLJC files. There is also a button for this in the status bar:
Due to limitations in the VS Code API it is hard for Calva to know if the REPL file is open, and if it was opened more than once. Therefore, we suggest you make it a habit to leave this window open, or even pinned. And if it is open in several tabs, expect evaluation printouts to be a bit unpredictable.
If you save the REPL file (which most often does not make much sense, but anyway) you will sometimes be presented with a message about VS Code being confused about the file contents being out of sync. Just choose to Overwrite the currently saved version and you should be fine.
"},{"location":"reveal/","title":"How to use Calva and Reveal together","text":"Reveal is a \"Read Eval Visualize Loop for Clojure\". This page describes how to use Reveal in your development setup based on Calva.
Note
See https://vlaaad.github.io/reveal for the latest version and use that wherever this page says <version>
.
You can go for the nrepl middleware or just add the dependency.
Please see the Calva test-data project minimal-reveal for an example.
"},{"location":"reveal/#middleware","title":"Middleware","text":"This will make Reveal to start together with your project.
Note
This will make all Calva evaluations go to Reveal. Too chatty for you? Take the dependencies only approach.
Add this alias deps.edn
:
:aliases\n{:reveal-nrepl-middleware\n{:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}\n:main-opts [\"-m\" \"nrepl.cmdline\"\n\"--middleware\" \"[vlaaad.reveal.nrepl/middleware,cider.nrepl/cider-middleware]\"]}}\n
And then jack-in choosing the deps.edn option and then pick the :reveal-nrepl-middleware
alias.
If you don't want to use the nrepl-middleware you can configure just the dependency and then start Reveal yourself.
The alias:
:reveal-dep-only\n{:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}}\n
A custom REPL command for starting Reveal in your project:
\"calva.customREPLCommandSnippets\": [\n...\n{\n\"name\": \"Start Reveal Tapper\",\n\"snippet\": \"(require '[vlaaad.reveal :as reveal])(add-tap (reveal/ui))\",\n\"key\": \"sr\"\n},\n...\n]\n
See Custom REPL Command for how to configure more commands, and bind shortcuts to them, to make Reveal integration nice for you.
"},{"location":"reveal/#when-using-leiningen","title":"When using Leiningen","text":"In your project.clj
, add a profile named \"reveal\":
:profiles {:reveal {:dependencies [[vlaaad/reveal \"<version>\"]]\n:repl-options {:nrepl-middleware [vlaaad.reveal.nrepl/middleware]}}}\n
Now when you jack-in using Calva, you enable this profile and Reveal will be started automatically. Please note that Reveal requires Java 8 or higher, and uses JavaFX. Depending on your setup, you may need to make sure it is available.
"},{"location":"reveal/#tips-about-font-size","title":"Tips about font size","text":"If you find the font to small you can add a :jvm-opts
key to make it a little bigger:
:aliases\n{:reveal\n{:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}\n:jvm-opts [\"-Dvlaaad.reveal.prefs={:font-size,17}\"]\n:main-opts [\"-m\" \"nrepl.cmdline\"\n\"--middleware\" \"[vlaaad.reveal.nrepl/middleware,cider.nrepl/cider-middleware]\"]}}\n
"},{"location":"reveal/#using-java-11","title":"Using Java > 11?","text":"Reveal needs some reflective access to internal classes that has since Java 11 been restricted. You can relax this and get things working via JVM options. Tuck this into your reveal alias:
:jvm-opts [\"--add-opens\" \"javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED\"]\n
(If you are using the font size tips, just add the options into the :jvm-opts
vector.)
See https://github.com/vlaaad/reveal/issues/1 for some more context around this issue.
"},{"location":"rich-comments/","title":"Rich Comments Support","text":"Why bother with Rich comments? Read on. Consider watching this Youtube video for a demo of the workflow using the (in?)famous FizzBuzz problem as an example.
","boost":5},{"location":"rich-comments/#things-in-comment-are-not-evaluated","title":"Things incomment
are not evaluated","text":"The Clojure comment
macro is defined like so:
(defmacro comment\n\"Ignores body, yields nil\"\n{:added \"1.0\"}\n[& body])\n
It has no forms in its body and will therefore always (as long as the Clojure Reader can read it) evaluate to nil
. That is: nothing in the (comment ...)
form will get evaluated when the file is loaded.
This makes it a very good \u201dplace\u201d where you can develop code, experiment with code, and keep example code. Since you will be able to load/evaluate the current file without worrying that the code in the comment
form will get evaluated. This also holds true when using tools that hot-reload the code on save, such as Figwheel, shadow-cljs and Krell.
To develop or refine a function you might:
(comment ...)
formcomment
form, type some code to test your function and evaluate thatcomment
formcomment
form to keep some of the test code as example use, or \u201ddesign decision log\u201d for the function.Note
Using (comment ...)
forms for developing code is very common among Clojure coders. Rich Hickey is known for using it, which is why they are called Rich comments to begin with (even if it also is a very rich experience).
Calva has several features to facilitate the Rich comments workflow, e.g.
(rcf
, will make it appear.comment
forms are rendered in italicsNote that the command and snippet for creating Rich comments add the keyword :rcf
right before the closing paren. This makes the closing paren stay and not fold when you format the code. The special formatting (see below) will treat this and also any ignored (with #_
) form at the end of the form specially.
comment
is top-level","text":"To make it easy to evaluate forms in (comment ...)
forms, they create a new top-level context. Instead of you having to place the cursor with precision before evaluating the current form, you can have the cursor anywhere within a comment
enclosed form and Evaluate Top-Level Form.
This carries over to all commands in Calva which deal with the top level form. Including custom command snippets.
","boost":5},{"location":"rich-comments/#special-formatting","title":"Special formatting","text":"To invite a Rich comments workflow, the Calva command Format Current Form will not fold the closing bracket of the (comment ...)
form. Instead it will place this bracket on a line of its own (or keep it there).
(comment\n)\n
With the cursor somewhere directly inside the comment form (denoted with a |
):
(comment\n(def foo\n:foo)|)\n
tab
(comment\n(def foo\n:foo)\n|)\n
!!! Note \"Only for the current comment form\u201d The special formatting only applies in the current comment
form. When outside it, formatting tucks the closing paren in again. That's why fold when done, below works like it does. This also applies to VS Code commands like Format Document, or when you have Format On Save enabled. There are several reasons for this, and one is that there is no cljfmt
config for it and leaving the closing comment un-tucked might give you troubles with CI pipelines that enforce some cljfmt config be followed. (Another reason is that it would be pretty hard to do on the whole document.)
:rcf
","text":"If the Rich comment ends with :rcf
(or an ignored form), the special formatting doesn't happen. So if you have:
(comment\n(def foo\n:foo)\n|\n:rcf)\n
And hit tab, you will get:
(comment\n(def foo\n:foo)\n|\n:rcf)\n
","boost":5},{"location":"rich-comments/#thinking-space-is-kept","title":"Thinking space is kept","text":"The formatter will not remove newlines between the cursor and the closing bracket. So if you have entered a few lines to get \u201dthinking\u201d room:
(comment\n(def foo\n:foo)\n\n|\n\n)\n
tab
(comment\n(def foo\n:foo)\n\n|\n\n)\n
","boost":5},{"location":"rich-comments/#fold-when-done","title":"Fold when done","text":"To fold the trailing paren automatically, place the cursor immediately outside (before or after) the form:
(comment\n(def foo\n:foo))|\n
tab
(comment\n(def foo\n:foo))|\n
","boost":5},{"location":"rich-comments/#enabled-by-default","title":"Enabled by default","text":"You can disable this behavior with the setting: calva.fmt.keepCommentTrailParenOnOwnLine
.
Note
This treatment only applies to formatting of the current form. With fold when done as an exception.
","boost":5},{"location":"shadow-cljs/","title":"shadow-cljs","text":"Calva supports most any JVM hosted ClojureScript environment (and some others, including SCI based, too), but shadow-cljs gets some special treatment to try make it extra convenient to use.
With many shadow-cljs projects, Calva's connect project type shadow-cljs, is the right choice. Projects that use Leiningen or deps.edn can be used both with the Leiningen/deps.edn and shadow-cljs type, depending on configuration see below for more on this.
","boost":7},{"location":"shadow-cljs/#shadow-cljs-browser-quickstart","title":"shadow-cljs - browser quickstart","text":"Here's how you start a shadow-cljs ClojureScript REPL and connect Calva with the shadow-cljs - browser quickstart example project:
Prep:
npm install
Connect Calva:
Now you can should be able to evaluate forms, e.g.:
(See Code Evaluation)
","boost":7},{"location":"shadow-cljs/#shadow-cljs-in-full-stack-projects","title":"shadow-cljs in full stack projects","text":"shadow-cljs is a bit special in regards to Calva REPL connection. Mainly because you can start shadow-cljs and it's nREPL server in two ways:
These options show up as project types when connecting or jacking in:
The technical difference here is wether you let shadow-cljs start clojure/Leiningen (the first option) or if you let Calva do it (the second option). If you let Calva do it, Calva will then start the shadow-cljs watcher from the Clojure process. From a usage perspective the two approaches will result in different channeling of shadow-cljs output, e.g. test runner results. With the first option (the shadow-cljs project type), shadow-cljs output will be channeled to the Jack-in terminal. With the deps.edn/Leiningen option, that output will be channeled to the Output/REPL window.
See shadow-cljs + Clojure with Calva: The basics for some more discussion on how the REPL connection works.
shadow-cljs and clojure
aliases
The shadow-cljs project type will not prompt you for any aliases found in the deps.edn
file. Usually you should provide such aliases in shadow-cljs.edn
like :deps {:aliases [...]}
. If, for whatever reason you can't provide the aliases that way, you can configure a Custom REPL Connect Sequence and provide the aliases as menuSelections
-> cljAliases
.
Leiningen + shadow-cljs middleware issue
Please note that for Leiningen, the command line dependency injection of the shadow-cljs nrepl middleware doesn't work. You need to add it to your project.clj
:
:repl-options {:nrepl-middleware [shadow.cljs.devtools.server.nrepl/middleware]}\n
","boost":7},{"location":"shadow-cljs/#see-also","title":"See also:","text":"Calva is open source and free to use. It is actively maintained during our free time, and it keeps improving. You can contribute in many different ways, one of which is sponsoring. You can sponsor Calva by directly sponsoring any of us.
If you are working at a company which benefits from Calva's existence and continued development, please consider sponsoring at the Calva Gold Sponsor tier.
Please see this statement from Cognitect about the importance of supporting open source developers.
","boost":7},{"location":"sponsors/#patrons","title":"Patrons","text":"The right kind of different","boost":7},{"location":"sponsors/#gold-sponsors","title":"Gold Sponsors","text":"Scale your growth on mobile MAKE. DO. SHIP.","boost":7},{"location":"sponsors/#silver-sponsors","title":"Silver Sponsors","text":"","boost":7},{"location":"sponsors/#clojurists-together","title":"Clojurists Together","text":"Significant additions to Calva have been made possible by funding from Clojurists Together. And this has often been transformational for the whole project. Calva would not be where it is today without Clojurists Together.
","boost":7},{"location":"sponsors/#our-sponsoring-profiles","title":"Our Sponsoring Profiles","text":"These are the sponsoring profiles for the active maintainers of Calva (a.k.a. The Calva Team).
There is also a sponsors section in the README of the Calva project (which means it is also displayed in the VS Code Extension Marketlace).
","boost":7},{"location":"syntax-highlighting/","title":"Calva Highlight","text":"Calva takes care of syntax highlighting, and also provides some features not available through VS Code's highlighting mechanism. These extras include rainbow parens, sane bracket matching, and comment form dimming/highlighting.
"},{"location":"syntax-highlighting/#syntax-highlighting","title":"Syntax Highlighting","text":"When using Calva, you are also using its TMLanguage grammar (the core mechanism VS Code uses for syntax highlighting).
Our grammar tokenizes Clojure keywords as constant.keyword.clojure
. Since it is pretty uncommon with keyword constants in the programming languages out there, your theme might not have a highlight defined for this scope. Try find a grammar that highlights keywords! If you are very fond of some theme lacking this, you can help it with a setting:
\"editor.tokenColorCustomizations\": {\n \"[Default Dark+]\": {\n \"textMateRules\": [\n {\n \"scope\": [\n \"constant.keyword.clojure\"\n ],\n \"settings\": {\n \"foreground\": \"#6fbfff\"\n }\n }\n ]\n }\n},\n
Instead of Default Dark+
you should use your theme's name/key. And choose a color you like, of course.
You are in charge of how brackets and comments are highlighted via the calva.highlight.<setting>
settings:
enableBracketColors
Enable rainbow colors true
rainbowIndentGuides
Enable rainbow indent guides true
highlightActiveIndent
Highlight the active indent guide true
bracketColors
Which colors to use [\"#000\", \"#999\"]
cycleBracketColors
Whether same colors should be reused for deeply nested brackets true
misplacedBracketStyle
Style of misplaced bracket { \"border\": \"2px solid #c33\" }
matchedBracketStyle
Style of bracket pair highlight {\"backgroundColor\": \"#E0E0E0\"}
ignoredFormStyle
Style of #_...
form {\"textDecoration\": \"none; opacity: 0.5\"}
commentFormStyle
Style of (comment ...)
form {\"fontStyle\": \"italic\"}
Calva disables the VS Code built-in indent guides
The VS Code built-in settings editor.renderIndentGuides
and editor.highlightActiveIndent
do not have any effect, since the former is switched off by the Clojure Defaults, mentioned above. Use Calva Highlight's rainbowIndentGuides
and highlightActiveIndent
instead. They are different from the built in ones in that they are independent, meaning you can choose to have active indent highlighted while the guides generally are not rendered (this is the default, even).
VS Code bracket coloring vs Calva's
Calva's bracket coloring is more Clojure aware than VS Code's built-in coloring. And also will chime better with Calva's indent guides. If you like to have bracket coloring outside Clojure code, by all means enable it. Calva's bracket coloring will \u201dover paint\u201d in Clojure files, when enabled. These settings work nicely:
\"calva.highlight.highlightActiveIndent\": true,\n\"editor.bracketPairColorization.enabled\": true,\n
The calva.highlight.bracketColors
setting can be used to harmonize the coloring between VS Code and Calva.
Calva, the spirit, gains much of its taste and color from the Cider it is distilled from, and the oak it is matured in. I started to wonder what it is that shapes Calva, the VS Code Clojure Extension. I should know, being the master distiller, right?. Indeed. Poking some at the question, I do find that I have some answers.
Please read the following to learn what Calva is, and, to some extent, is not, about. Read it to get an idea about which path Calva is following, where we are headed with the project, and how you can contribute to the journey.
"},{"location":"tao/#why-calva","title":"Why Calva?","text":"Calva's raison d\u00b4\u00eatre is to provide Visual Studio Code users with an easy to use and productive environment for Clojure and ClojureScript development. See the Why Calva? page for some evidence that we are succeeding.
While Calva draws a lot of inspiration from CIDER, Cursive, Fireplace, and other Clojure development environments, it does not try to compete with them. Reading r/Clojure and elsewhere, it is easy to get the impression that the most common question is \"Which editor should I use for Clojure development?\u201d. I think a much more common question is \u201dHow do I use my favorite editor for Clojure development?\u201d. For VS Code users, that is where Calva should be a good choice.
I also have an ambition to leverage VS Code for easing the path to Clojure. Given that it is the favorite editor for so many developers, it is important to have a good development environment in place on this platform, and to make it as easy to use as we possibly can, while also being productive and something that you want to stick with, once you are hooked on Clojure.
That said, and therefore: For people who want to start out with Clojure, and do ask about what development environment would make it the most enjoyable, I'd like for Calva to be a really good option, an option so good that Clojurians feel they can recommend it.
"},{"location":"tao/#design-goals","title":"Design Goals","text":"Calva should be easy to start with and productive enough to stick with. It should support Clojure Best Practices, and be pleasant and enjoyable to use. It should also be easy to hack on, and to contribute to. The ClojureScript story keeps getting more important. Calva should contribute to making the development experience with ClojureScript delightful.
"},{"location":"tao/#easy-to-start-with","title":"Easy to Start With","text":"There are reasons as to why VS Code is so popular. Among those, one stands out to me: It is the most approachable code editor out there. There is nothing you need to learn when you start using it. The editor makes it obvious that you can start typing, deleting, cutting, pasting and undoing, without having to figure anything out. Then you learn how to bring up the command palette and get a boost few other environments can provide with such immediacy.
A language extension for VS Code can leverage this, by recognizing that what's old is old, and that what's new should be as easy as possible to pick up. Coming to a new language, people bring with them a lot of expectations from the languages they are used to. This is also true for the editor support. Syntax highlighting and formatting should just work, as should documentation lookup, linting and other IDE commodities.
Clojure brings some new concepts to the table. Chief among these: The REPL. It does take some time to grasp it. Calva needs to remove any obstacles it can when it comes to helping the user to reach the REPL, in order to help getting it, and start loving it.
To help the users to quickly focus on Clojure, we provide a package that is all-inclusive, with few knobs to turn, and with sane defaults for the knobs that still need to be there.
"},{"location":"tao/#productive-enough-to-stick-with","title":"Productive Enough to Stick With","text":"I think VS Code brings inspiration also when it comes to following up its excellent Getting Started story. You do not have to dig very deep under its surface to find that there is a lot more power to be unleashed. VS Code makes it easy to pick up more features as you get ready for it, and each little piece makes you more productive. To me, only Vim beats VS Code in this game.
Most often there should be no contradiction between Easy to Start With and Productive. Quite the contrary. This story is mainly about being feature complete with the most important tools. As beginners start to pick up the first few features, they should be rewarded with finding more productive tools when they go looking for them. The VS Code way is Calva's way.
"},{"location":"tao/#pleasant-and-enjoyable","title":"Pleasant and Enjoyable","text":"Enjoyable starts with that Calva shouldn't be an experience full of pains. I think Calva is living up to this first bar of enjoyability. The next step is making it delightful!
Calva has two main assets it can leverage for being delightful to use: Clojure and VS Code:
Clojure is plain wonderful and also has this totally awesome REPL thing. Wherever we can, Calva should use the REPL to make the editor spark and bring joy to the developer.
VS Code is a sweet development environment, offering its power in a consistent way across languages. Even if Clojure is very special, most of Calva's features are surfaced in the ways that VS Code encourages. It makes for less to learn for the user, and most often also makes it easier to implement functionality.
"},{"location":"tao/#support-clojure-best-practices","title":"Support Clojure Best Practices","text":"Mainly, I think Stuart Halloway is right about the REPL being best used from inside the files you are editing rather than from the prompt. It doesn't mean that Calva's REPL window should be neglected, but efforts should be directed such that the file editor REPL is our first way to improve the experience. Expect the Calva REPL window to get much less \u201din your face\u201d, than it is today, as the editor REPL gets stronger.
Halloway also gives me some peace of mind with his reasoning of keeping a spartan setup. Calva does not need to pack every feature imaginable. If we can get the right features in place, in the right way, the mission is accomplished.
Clojure is data centric. Calva should make it easy to examine data and how our code affects it. Today, this is not good enough when it comes to data structures larger than a few elements.
Clojure is a LISP. Thus Structural Editing is possible, and TBH, desirable. Calva should support this and encourage it. There is little we can do about Parinfer not playing well with VS Code, but there is Paredit, and Paredit rocks! Calva's Paredit plays in the top league of Paredits, for this reason.
"},{"location":"tao/#made-from-the-produce-of-the-orchard","title":"Made from the Produce of the Orchard","text":"Calva is distilled from CIDER, which in turn is brewed from the products of The Orchard. This makes a lot of Calva's features thin wrappers around cider-nrepl and related middleware. It also should mean that we strive for adding features by thinking \u201dThe Orchard\u201d first. If it lacks what we need, we should assist in providing it there. We need to up this game a bit from where we are today, I think.
"},{"location":"tao/#leveraging-clojure-lsp","title":"Leveraging clojure-lsp","text":"Today, Calva draws a lot of its static power from clojure-lsp. As does a lot of other Clojure tooling out there. The Calva and the clojure-lsp teams work very nicely together, which is something we cherish and should take care to maintain.
"},{"location":"tao/#project-stewardship","title":"Project Stewardship","text":"Here Calva takes inspiration from many Clojure related projects, and perhaps most so from CIDER,shadow-cljs, and clojure-lsp. Bozhidar Batsov, Thomas Heller, and Eric Dallo all lead their projects with clarity and with gusto. You can feel how they really care about their products and their users. They are there. They listen. They respond. And they relentlessly keep improving their products.
So we are there. We listen. We respond. And we keep trying to improve Calva.
The Calva team cares deeply about the user experience. That is a major part of why we do this. When implementing a new feature, or changing a feature, Ux is always the first thing on our mind. Personally, to keep that direction I often start with the documentation of the feature. Reading the documentation before implementation reveals a lot about if the Ux design is within the ballpark or not.
We have limited time on our hands, however, and we must cut some corners. We can't afford to spend very much time in Ux design. Rather we will use our Ux intuition, iterate the documentation quickly, and be fast to get things out. Then we are responsive in tweaking those things, based on user feedback. This also has impact on general quality at times. We only can do so much QA, and it happens that some releases of Calva cause disruptions in people's workflow because of things we haven't thought of, or not found during our testing. Again, we try to be attentive to feedback and quick to fix. Apologies in advance for any inconveniences caused!
A super major part of our love for Ux is that Calva should be serving its users. That's why we treat feedback as a gift, listen intently, and use the feedback as a major ingredient in shaping Calva.
Calva develops from user feedback in more direct ways as well. It is quite astonishing how many people have decided to improve on it by hacking it to do some small or big thing differently. That's great! We should make sure Calva is super easy to contribute to.
There has been quite a lot of work put into improving the development process. Starting to hack on Calva is just a few steps, taking less than three minutes from cloning to running a dev version in the VS Code debugger. We encourage contributions, from the tiniest typo to whole new features. And we are ready to spend time helping people get their contributions integrated.
However, Calva can't be what everyone wants it to be, that would make it useless. It needs direction and aim. And it is we, the Calva Team, who are the stewards. We need to be in charge of what Calva is about, and what it is not about.
"},{"location":"tao/#the-road-ahead","title":"The Road Ahead","text":"Tying back to Stuart Halloway, I don't think he means that spartan needs to also mean poor. The products he helps to bring to the market tell another story. VS Code and Clojure brought together has the capacity to create something amazingly rich and luxurious. And I want Calva to tap into that potential.
On the Calva journey we will allow ourselves to change our minds about how things work. Calva is not a library. Its an interface between Clojure and human beings. Human beings can adapt. And they will need to enjoy adapting in order to enjoy Calva. \ud83d\ude04
By now it should be clear that you can expect Calva to keep evolving, keep being tended and maintained, and keep getting ever more enjoyable to use. Lately we have been improving Calva pretty rapidly. It would be great to keep it up like that, but I think it is good to expect a more humble and sustainable pace.
Calva is still quite new. A bit like freshly distilled Calvados. It will need time in those oak barrels to develop its full bouquet of flavors. And time is what we will give it. Our time, our creativity, and our passion.
"},{"location":"test-runner/","title":"Test Runner","text":"Calva provides commands that make running your Clojure tests easier.
Note
Since the test commands utilize cider-nrepl, they only work with Clojure, not ClojureScript. See this issue for more details.
"},{"location":"test-runner/#test-commands","title":"Test Commands","text":"Command Shortcut Description Run All Testsctrl+alt+c shift+t
Runs all tests Run Failing Tests ctrl+alt+c ctrl+t
Runs the tests that failed Run Tests for Current Namespace ctrl+alt+c t
Runs the tests for the current namespace. If not a -test
namespace, tests for the current namespace plus its corresponding <current-namespace>-test
namespace will be run. Run Current Test ctrl+alt+c ctrl+alt+t
Runs the test at the cursor. This includes a defn
with a :test
in its metadata, a defn
defined in a with-test
, and a deftest
. Toggle between implementation and test - Switches the file between implementation and test, prompts to create a new file if not found."},{"location":"test-runner/#test-on-save","title":"Test on Save","text":"You can enable the Calva setting \"Test on Save\" to have tests for the current namespace run on file save.
"},{"location":"test-runner/#vs-code-test-ui","title":"VS Code Test UI","text":"Calva has experimental support for showing test results in VS Code's Test UI. You can enable this support by setting calva.useTestExplorer
to true
. When you enable this setting, the Testing icon will appear in the Testing tab of VS Code's Activity Bar.
With this feature enabled you will be able to browse and run tests directly from the Testing tab.
Please join the #calva channel on the Clojurians Slack if you have any feedback on this new feature.
"},{"location":"test-runner/#troubleshooting","title":"Troubleshooting","text":""},{"location":"test-runner/#tests-are-not-found","title":"Tests Are Not Found","text":"Calva will not load namespaces in the REPL that you haven't loaded. This is so that you can be in control of what is loaded in the REPL. However, it also means that commands like Run All tests actually mean Run All Tests That are Loaded in the REPL, since the test-runner only runs tests that it knows about, i.e. are loaded in the REPL. Some developers choose to make sure all test namespaces are loaded as part of starting their REPL. Others register a custom REPL command for loading test namepaces. (Yet others use test-runners such as Cognitect's test-runner, Kaocha, poly test, or some other that runner allows for tests being run automatically, separate from the REPL used for development.)
If you have tests in a test directory separate from your source directory, and those tests are not being found by the test runner, make sure the test directory is included in your paths. This will not be the case by default with a tools.deps (deps.edn) project. If your project is a tools.deps project, you can create an alias in your deps.edn file with :extra-paths
that includes \"test\"
(or the name of your test directory).
{:aliases {:dev {:extra-paths [\"test\"]}}}\n
"},{"location":"test-runner/#changes-arent-taking-effect-when-running-tests","title":"Changes Aren't Taking Effect When Running Tests","text":"In order for changes in code to take effect, you need to load the file or evaluate the changed code before running a test command. Prior to version 2.0.301, Calva would load the file for you when running some test commands, but that behavior was removed in favor of leaving control to the user, and to avoid a potential issue.
Having added the above to your deps.edn, when you jack-in, choose the :dev
alias and the test
directory will be added to your paths, which will allow tests located in the directory to be found by the test runner.
This feature mostly works with projects that has leiningen style folder structure and makes some assumption about your folder structure and test file names.
_test
prefix.src
folder and the test files are in test
folder.If you are using any non leiningen style folder structure, you may have to add source paths inside .lsp/config.edn
.
You should start with loading the file you are working with. Do this with Load/Evaluate Current File and its Requires/Dependencies, ctrl+alt+c enter
.
To get a feeling for evaluating code in the editor and get immediate response from the REPL try this:
comment
form and put some code inside it:(comment\n(+ (* 2 2)\n2)\n(Math/abs -1)\n(hello \"Calva REPL\")\n(defn hello [s]\n(str \"Hello \" s))\n(range 10)\n\"I \u2665\ufe0f Clojure\")\n
Then:
(* 2 2)
and issue the command Calva: Evaluate Current Form, ctrl+enter
.esc
to dismiss it.alt+enter
.(+ (* 2 2) 2)
getting highlighted and the result of that expression being displayed inline.(hello \"Calva REPL\")
form before the (defn hello...
form should result in an error/exception. A stacktrace is then printed in the output windowdefn
form.Demo:
"},{"location":"try-first/#how-does-this-work","title":"How does this work?","text":"Calva has this notion about the current form. Issue the Evaluate Current Form command, with the cursor placed in different locations to get a feeling for how the current form is determined.
There is also a concept about the current top level form. Good for evaluating various def
s defn
, defthis
, defthat
. With your cursor placed anywhere inside such a form.
The Top Level command also works inside (comment ...)
forms, treating the comment
as creating a new top level context. It is good for in-file code experimentation.
First thing first. The VIM Extension and Calva has a history of friction between them. Less so these days, but you might still encounter some rough edges. Please don't hesitate to reach out to the Calva team, as we might be able to fix things if only we are aware of them.
"},{"location":"vim/#key-bindings","title":"Key bindings","text":"In general Calva's default key bindings are not very VI-ish.
"},{"location":"vim/#expand-selection-on-mac","title":"Expand selection on Mac","text":"On Mac, Calva binds expand selection to ctrl+w
. This conflicts with the VIM Extension's default mapping of window splitting shortcuts. You'll need to remap it either with Calva or with the VIM Extension.
esc
key","text":"While showing inline evaluation results, Calva binds the esc
key to dismiss the display of inline results. If you want to be able to use the esc
key to enter command mode while inline results are showing, you'll need to rebind Calva's command for dismissing the inline results.
clearInlineResults
","text":"clearInlineResults
and remap the command e.g.// Place your key bindings in this file to override the defaults\n[\n{\n\"key\": \"escape\",\n\"command\": \"-calva.clearInlineResults\"\n},\n{\n\"key\": \"shift+escape\",\n\"command\": \"calva.clearInlineResults\",\n\"when\": \"editorTextFocus && !editorHasMultipleSelections && !editorReadOnly && !hasOtherSuggestions && !suggestWidgetVisible && editorLangId == 'clojure'\"\n}\n]\n
If you run into issues, refer to the commands in the default Keyboard Shortcuts JSON file.
"},{"location":"vim/#remap-vims-insert-mode","title":"Remap Vim's Insert Mode","text":"Remap vim's insert mode keybinding to go into command mode by adding the following to your user settings:
\"vim.insertModeKeyBindings\": [\n{\n\"before\": [\"j\", \"k\"],\n\"after\": [\"<esc>\"]\n}\n]\n
(Change before
to whatever keybinding you are comfortable with!)
You can add these keybindings to your init.vim
if you are using the VSCode Neovim extension. It is inspired by and tries to emulate the keybindings found in vim-fireplace which is the most popular vim plugin for Clojure.
nmap cqp :call VSCodeNotify('calva.jackIn')<CR>\nnmap cqq :call VSCodeNotify('calva.disconnect')<CR>\nnmap cpr :call VSCodeNotify('calva.loadFile')<CR>\nnmap cpR :call VSCodeNotify('calva.loadNamespace')<CR>\nnmap cpp :call VSCodeNotify('calva.evaluateSelection')<CR>\nnmap cqc :call VSCodeNotify('calva.evalCurrentFormInREPLWindow')<CR>\n
Unfortunately these key combinations will not work in the normal VIM extension as c
is an operator key and cannot be remapped. This is a call for someone to share their VIM re-mappings.
When clause contexts is a powerful customization mechanism in VS Code. The most common use for end users is with keyboard shortcut bindings. Extensions can provide their own. The following contexts are available with Calva:
calva:keybindingsEnabled
: a master switch that you find in the settingsparedit:keyMap
: strict
, original
, or none
from the corresponding Calva setting (see Paredit)calva:connected
: true
when Calva is connected to a REPL (there is also calva:connecting
|| calva:launching
)calva:outputWindowActive
: true
when the Output/REPL window has input focuscalva:replHistoryCommandsActive
: true
when the cursor is in the Output/REPL window at the top level after the last promptcalva:replWindowSubmitOnEnter
: true
when the cursor is adjacent after the last top level form in the Output/REPL windowcalva:cursorInString
: true
when the cursor/caret is in a string or a regexpcalva:cursorInComment
: true
when the cursor is in, or adjacent to a line commentcalva:cursorBeforeComment
: true
when the cursor is adjacent before a line commentcalva:cursorAfterComment
: true
when the cursor is adjacent after a line commentcalva:cursorAtStartOfLine
: true
when the cursor is at the start of a line including any leading whitespacecalva:cursorAtEndOfLine
: true
when the cursor is at the end of a line including any trailing whitespaceThe main reason you would choose Calva for your Clojure and/or ClojureScript coding is that you want to use Visual Studio Code. Calva provides VS Code users with a comprehensive set of features to keep you productive and make it easy to follow Clojure coding best practices. This also means that if your choice of editor is not made yet, we think you should give VS Code and Calva a try.
While Calva is a good choice for professional and experienced Clojure developers, great care has been taken in making Calva a really good choice for beginners of Clojure as well.
We who make Calva are actively stewarding, maintaining, documenting and supporting it. We are also very active Clojure (and Calva) users, participating in the community. Clojure is dear to us, a lot because it keeps programming fun and rewarding.
Calva has very happy users! Check out the Programming Languages section on the Visual Studio Code Marketplace, sorted by rating:
Recently there was a thread over at ClojureVerse, asking about how Calva Compares to Emacs with CIDER. It is well worth reading. We would like to highlight the answer by Nick Cernis, which focuses on Calva. We'll even quote parts of it. \ud83d\ude0d
"},{"location":"why-calva/#nick-cernis-on-clojureverse","title":"Nick Cernis on ClojureVerse","text":"My advice to anyone starting their Clojure journey who is unsure about what editor to use:
I now use VS Code with Calva every day but went through a long journey trying almost every other editor and plugin combo first. I switched from Emacs to VS Code, which might make my perspective different to others here.
\u2026
I started with the jaded assumption that VS Code was probably bad because it's built by committee at Microsoft on a web-tech based Electron stack, only to find that it succeeds in embodying the spirit of a \u201chacker's editor\u201d more than even Emacs does in many ways:
\u2026
On the benefits of Calva:
Of all the amazing Clojure community projects, Calva seems most likely to encourage new users to try Clojure and ClojureScript. A lot of developers use VS Code. It\u2019s been tricky to convince frontend developer friends to try ClojureScript, but at least they don\u2019t have the excuse that they\u2019ll need to switch editors to even try it now. I think as a community we should try to support the projects that encourage Clojure\u2019s adoption and ease of use, including by using those products ourselves.
Calva provides a better first-time experience than any other editor/plugin combo whether you\u2019re new to Clojure or not. You can install the plugin and be chatting with your REPL in under a minute without any knowledge of Elisp or VimScript/Lua or how to configure Run Configurations in IntelliJ.
We are super proud of the Calva reviews on the Visual Studio Code Marketplace. Please read them all. \ud83d\ude04 Here's a selection that we think captures what we focus on in when developing Calva:
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f Calva has become an essential part of my Clojure workflow.
It's an incredible piece of work by the team behind it.
Sean Corfield
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f Calva hits the sweet spot of being both approachable for new users and powerful for seasoned ones.
The creators/maintainers are fantastic individuals that care deeply about streamlining the user experience, and it shows.
Good stuff, check it out.
Clay Hopperdietzel
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f I switched from IntelliJ / Cursive to VS Code and Calva and it's been amazing.
...
That is the biggest thing I can say for Calva, it just works. I was never a fan of VS Code before, but VS Code + Calva for Clojure is now my favorite language / IDE experience.
Plus, the #calva on the clojurians slack is brilliant, always someone there to help if you have issues (although any issue I've had has been squarely on me, and never Calva itself).
I often feel we live in an age where so much software is badly written, without care, slow, buggy and just generally awful. Calva is the complete opposite. I think the maintainers want to, and have, made a wonderful piece of software for Clojure developers.
Stuart Stein
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f This is great, and makes VS Code a truly viable IDE/editor for clojure development.
It already has great REPL support (including inline evaluation), an extensive Paredit implementation, and excellent linting (care of the bundled clj-kondo). Calva is being improved on at an impressive clip by maintainers who appear solidly committed to its ongoing development. It's well-documented, and manages to be both approachable and capable.
A no-brainer if you're already a VS Code user, and well worth a look if you're not.
Crispin Bennett
\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f I'm using Calva now for a few months and I'm loving it.
I joined the Slack channel about 2 wks ago and I must say that I'm very impressed by how active and responsive this community is. Already 2 of my issues fixed and I really like Calva (and the extensions it uses!).
These are professional people and they make me very happy!
Uitbeijerse, E (Eric)
"},{"location":"workspace-layouts/","title":"Workspace Layouts","text":"Project directory layouts can vary quite a lot. From the \u201dtemplate\u201d projects where the Clojure project files are at the root, to, well, let's just say that the project files are not always at the root. And sometimes there is more than one project (read here how to get clojure-lsp support with a Leiningen project in a subfolder).
Calva only really supports working with one project at a time per VS Code window. Here's a short guide for some different setups:
As is mentioned in the Calva Jack-In Guide, if you have a full stack project using a Clojure backend and a shadow-cljs frontend, you will need to open the same project in two separate VS Code windows, one for the backend and one for the frontend. This is how you can do that:
Server.code-workspace
.Client.code-workspace
.Now, whenever you want to Jack-in to the backend and/or frontend, do it from the Server and/or Client workspace, respectively.
"},{"location":"wsl/","title":"Calva \u2764\ufe0f WSL","text":"The use of Calva with WSL (Windows Subsystem for Linux) is fully supported through the Remote - WSL extension. Simply install the extension and open your project with one of the Remote-WSL
commands. Calva will run directly in the WSL environment and no further configuration is required.
See also Remote Development.
"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 777c65d6f..15e674895 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,302 +2,302 @@