diff --git a/404.html b/404.html index 55175b5a4..f56767adc 100644 --- a/404.html +++ b/404.html @@ -12,8 +12,9 @@ + - + @@ -21,13 +22,16 @@ - + + + + @@ -53,9 +57,7 @@ - - - + @@ -69,9 +71,6 @@
For a discussion of this problem and other connection options, see issue #1468.
isStarted
startCode
isReadyToStartRegExp
openUrlRegExp
url
shouldOpenUrl
connectCode
isConnectedRegExp
stdout
To quit, type: :cljs/quit
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.
(
[
rewrite-cljs
calva.convertHtml2Hiccup
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.
You 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).
calva.redirectServerOutputToRepl
true
false
[λ]
(λ)
λ
Toggle between Strict and Cave Man using: ctrl+alt+p ctrl+alt+m
ctrl+alt+p ctrl+alt+m
Semi-colons (;) in Clojure are non-structural because they comment out the rest of the line regardless of brackets. In a way they can delete brackets. There is a somewhat secret command in Paredit that can be used to insert ; in a safe way:
;
paredit.insertSemiColon
Bind it to the ; key with a when clause that activates it tygether with the other Strict mode commands:
when
{ + "command": "paredit.insertSemiColon", + "key": ";", + "when": "calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap == strict && !editorReadOnly && !editorHasMultipleSelections && !calva:cursorInComment" + }, +
There is also a setting, calva.paredit.strictPreventUnmatchedClosingBracket, that will help you to not enter unbalanced closing brackets into the code.
calva.paredit.strictPreventUnmatchedClosingBracket
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.
As an experimental feature, the two commands for dragging forms forward and backward have clojure-lsp alternatives. See the clojure-lsp page.
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:
let
for
binding
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:
calva.paredit.multicursor
Select Current Form
See Using Calva with WSL
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.
Let's start a REPL!. \ud83d\ude80 Also see Get Started with Clojure
I'm glad you asked! Please see How to Contribute and The Tao of Calva
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!
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.
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.
Happy coding!
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.
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.
v1
exports
repl
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:
require
(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
The repl module provides access to Calva's REPL connection.
repl.currentSessionKey()
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.
\"clj\"
\"cljs\"
nil
(def session-key (calva/repl.currentSessionKey))\n
(def session-key ((get-in [:repl :currentSessionKey] calvaApi)))\n
const sessionKey = calva.repl.currentSessionKey()\n
repl.evaluateCode()
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):
Result
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).
sessionKey
code
\"cljc\"
undefined
cljc
An example:
(-> (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
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.
output
errorOutput
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.)
evaluateCode()
stderr
(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
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:
ranges.currentForm()
Retrieves information about the current form, as determined from the editor and position.
Corresponding REPL Snippet variable: $current-form.
$current-form
See also about Calva's Current Form on YouTube.
ranges.currentEnclosingForm()
The list/vector/etcetera form comtaining the current form.
Corresponding REPL Snippet variable: $enclosing-form.
$enclosing-form
ranges.currentTopLevelForm()
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.
(comment ...)
(def ...), (defgn ...)
Corresponding REPL Snippet variable: $top-level-form.
$top-level-form
ranges.currentFunction()
The current function, i.e. the form in \u201dcall position\u201d of the closest enclosing list.
Corresponding REPL Snippet variable: $current-fn.
$current-fn
ranges.currentTopLevelDef()
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.
$top-level-defined-symbol
(let [[range text] (calva/ranges.currentTopLevelForm)]\n...)\n
(let [[range text] ((get-in [:ranges :currentTopLevelForm]))]\n...)\n
const [range, text] = ranges.currentTopLevelForm();\n
editor
The editor module has facilites (well, a facility, so far) for editing Clojure documents.
editor.replace()
With editor.replace() you can replace a range in a Clojure editor with new text. The arguments are:
vscode.TextEditor
range
vscode.Range
newText
(-> (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
document
The document module provides access to the Clojure/Calva aspects of VS Code TextDocuments.
TextDocument
document.getNamespace(document?: vscode.TextDocument): string
document.getNamespace() returns the namespace of a document.
document.getNamespace()
vscode.TextDocument
Example usage. To evaluate some code in the namespace of the current document:
(calva/repl.evaluateCode \"clj\" \"(+ 1 2 39)\" (calva/document.getNamespace))\n
calva.repl.evaluateCode(\"clj\", \"(+ 1 2 39)\", calva.document.getNamespace());\n
document.getNamespaceAndNsForm(document?: vscode.TextDocument): [ns: string, nsForm: string]
document.getNamespaceAndNsForm() returns the namespace and the ns form of a document as a tuple.
document.getNamespaceAndNsForm()
ns
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
pprint
The pprint module lets you pretty print Clojure code/data using Calva's pretty printing engine (which in turn uses zprint).
pprint.prettyPrint()
Use pprint.prettyPrint() to pretty print some Clojure data using your Calva pretty printing options. It accepts these arguments:
text
string
options
The function is synchronous and returns the prettified text.
(println (calva/pprint.prettyPrint \"Some text\")))\n
console.log(calvaApi.pprint.prettyPrint();\n
pprint.prettyPrintingOptions()
Use to get the current pretty printint options:
vscode
In the its vscode submodule, Calva exposes access to things from its own vscode module instance. It gets important in some situations.
vscode.registerDocumentSymbolProvider()
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.)
[vscode.languages](https://code.visualstudio.com/api/references/vscode-api#languages).registerDocumentSymbolProvider()
vscode.languages.registerDocumentSymbolProvider()
(-> (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.
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.)
shadow-cljs
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
localhost:<some-port>
build
node-repl
ctrl+alt+c Enter.
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.
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.
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.
Add com.clojure-goes-fast/clj-java-decompiler as a dependency to the project.
com.clojure-goes-fast/clj-java-decompiler
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.
ctrl+alt+space d
ctrl+alt+space b
decompiled-<function name>.java
bytecode-<function name>.class
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.
ctrl+alt+space space
key
See this video for a demo.
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.
latest
Clojure-lsp Server 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.
clj-kondo
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:
calva.enableClojureLspOnStart
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.
\"always-use-first-workspace-root\"
This is the default auto-start behaviour.
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-workspace-opened-use-workspace-root\"
deps.edn
project.clj
shadow-cljs.edn
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.
\"when-file-opened-use-furthest-project\"
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
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.
\"never\"
calva.clojureLsp.start
calva.clojureLsp.manage
clojure-lsp
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.
calva.clojureLspPath
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.
stopped
starting
active
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.
Clojure-lsp stores its project analysis information in your project. Git users can add these lines to their project root directory .gitignore:
.gitignore
.lsp/.cache/\n.lsp/sqlite.*.db\n
For information about how to configure clojure-lsp, see the settings page of the clojure-lsp docs.
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.
calva.clojureLspVersion
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:
nightly
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.
\"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.)
clojure-lsp.command
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:
[command-name, arguments]
arguments
file-uri, row, col
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.
clojure.trace.server
verbose
Clojure Language Client
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.
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.
Calva Diagnostics: Open Clojure-lsp Log File
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
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.
.cljd
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...
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.
Please feel welcome to the #clojuredart and #calva channel at the Clojurians Slack for questions, suggestions and support.
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
Calva 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.)
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:
when-not
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.
(map ...)
alt+enter
map
iterate
See these two tweets for some videos of early versions of this functionality:
Please retweet!
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.
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
alt+ctrl+c enter
ctrl+enter
esc
(comment)
escape
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
ctrl+alt+c ctrl+alt+space
You can also switch the name space of the output/repl window to that of the current file: alt+ctrl+c alt+n
alt+ctrl+c alt+n
ctrl+alt+c p
ctrl+alt+c c
ctrl+alt+c ctrl+space
ctrl+alt+c r
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 .
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.
calva.replConnectSequences
NB: Connect sequence configuration affects Calva's Jack-in menu in the following ways:
A connect sequence configures the following:
name
projectType
autoSelectForJackIn
projectRootPath
menuSelections
autoSelectForConnect
nReplPortFile
[\".shadow-cljs\", \"nrepl.port\"]
afterCLJReplJackInCode
customJackInCommandLine
cljsType
dependsOn
printThisLineRegExp
buildsRequired
leinProfiles
leinAlias
null
cljAliases
cljsLaunchBuilds
cljsDefaultBuild
jackInEnv
calva.jackInEnv
merge
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.
autoSelectForJackIn/Connect
calva.connect
calva.jackIn
disableAutoSelect
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.
my-repl-jack-in-command
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.
custom
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
JACK-IN-NREPL-PORT-FILE
Depending on the project type Calva will also look for these placeholders:
JACK-IN-CLJ-MIDDLEWARE
JACK-IN-CLJS-MIDDLEWARE
JACK-IN-LEIN-PROFILES
JACK-IN-LEIN-LAUNCH-ALIAS
JACK-IN-CLI-ALIASES
JACK-IN-CLJS-LAUNCH-BUILDS
JACK-IN-NREPL-PORT
nbb
Babashka
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:
bb
\"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.
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:
JACK_IN_PROJECT_ROOT_PATH
\"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.
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.
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.
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.
(start)
(connect)
\"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.)
calva.autoConnectRepl
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
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
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
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.
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.
settings.gradle
settings.gradle.kts
com.bhauman/figwheel-main
See also below, regarding multiple projects in a workspace
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.
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
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
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.
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.
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.
Please see the shadow-cljs page.
:main-opts
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.
-m ...
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.
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:
command not found
$PATH
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.
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.
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>.
~/.bashrc
echo $SOME_VAR
code <project path>
There are many ways to contribute:
#calva
Be creative!
Happy Coding! \u2764\ufe0f
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
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):
snippet
evaluationSendCodeToOutputWindow
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
$column
$file
$file-text
$ns
$editor-ns
$selection
$current-pair
str
(defn foo [] (str \"foo\" \"bar|\"))
foo
$head
$tail
Settings 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:
ctrl+alt+space <something>
<something>
0
9
a
z
right
left
up
down
tab
backspace
,
.
-
calva.runCustomREPLCommand
args
customREPLCommandSnippets
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.
user
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.
hover-
: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:
:customREPLCommandSnippets
:customREPLHoverSnippets
.config/calva/config.edn
.calva/config.edn
:name
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.
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
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.
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:
calva.autoEvaluateCode.onConnect
clj
cljs
repl-requires
source
doc
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.
calva.autoEvaluateCode.onConnect.clj
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:
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.
calva.autoEvaluateCode.onFileLoaded
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.
host:port
calva.autoSelectNReplPortFromPortFile
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.
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.
ReplConnectSequence
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
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.myCljAliases
calva.myLeinProfiles
calva.openBrowserWhenFigwheelStarted
calva.depsEdnJackInExecutable
clojure
deps.clj
clojure or deps.clj
Note
When processing the calva.jackInEnv setting you can refer to existing ENV variables with ${env:VARIABLE}.
${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.
{\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.
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.
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.
**/{glob1,glob2,...,globN}
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:
settings.json
json
calva.prettyPrintingOptions
\"calva.prettyPrintingOptions\": {\n\"enabled\": true,\n\"printEngine\": \"pprint\",\n\"width\": 40\n},\n
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]\"
\"[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
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.
editor.wordSeparators
Calva's pretty printing mode can be configured a bit. See Pretty Printing.
This is highly customizable. See Syntax highlighting
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
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.)
editor.parameterHints.enabled
[clojure]
cmd+shift+space
ctrl+shift+space
See Formatting for information on how to configure this.
Jack-in and Connect are very customizable through Custom Connect Sequences.
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.
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.
The following contexts are available with Calva:
calva:keybindingsEnabled
paredit:keyMap
strict
original
none
calva:connected
calva:connecting
calva:launching
calva:outputWindowActive
calva:replHistoryCommandsActive
calva:replWindowSubmitOnEnter
calva:cursorInString
calva:cursorInComment
calva:cursorBeforeComment
calva:cursorAfterComment
calva:cursorAtStartOfLine
calva:cursorAtEndOfLine
Here is a collection of custom keybindings from here and there.
ctrl+alt+...
ctrl+shift+...
alt
ctrl+alt+c
alt+v
ctrl+,
Are you a vim extension user? See: Using with VIM extension.
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
{
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.
(foo)
( | (foo))
|
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).
Paredit: Wrap Around ...
editorHasSelection
The change would look like this in your keybindings.json:
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
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!
The debugger currently does not support ClojureScript. Calva's debugger utilizes cider-nrepl for debugging. See this Cider issue for more information.
ctrl+alt+c i
#dbg
#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.
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.
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.
launch.json
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.
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.
Code will be executed up to and including the form after the breakpoint.
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
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.
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.
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.
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.
You can use VS Code's debugger UI to advance execution while debugging.
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
recur
fn
(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.
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:
clojure.core/*print-length*
*print-length*
(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.
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.
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.
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:
cider/cider-nrepl
cider.nrepl/cider-middleware
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
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.
<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).
JAVA_TOOL_OPTIONS
-D
-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.
Jack in
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
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
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.
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.
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:
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.
def
defn
defwhatever
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.
comment
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.
The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter.
ctrl+shift+enter
(let [foo :bar]\n(when false (str| foo))) ; => \":bar\"\n
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:
doto
:d
(->> [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.
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):
42
-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.
;1
(let ..)
At ;2 you need select backwards up three times.
;2
;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.
;3
->>
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 ...)).
shift+alt+enter
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
Yup, that command also exists. \ud83d\ude04
There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c.
ctrl+alt+c ctrl+c
This works regardless if you have evaluated in a file editor or in a REPL window.
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.
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.
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.
.clj
.cljs
.bb
.fiddle
To know how to map between Fiddle <-> Source files, Calva has three different modes of operation:
src
/a/b/c.cljc
/a/b/c.fiddle
env/dev/fiddles
/d/e/f.cljc
/x.cljc
The setting is named calva.fiddleFilePaths and is an array of source and fiddle root paths, relative to the project root.
calva.fiddleFilePaths
fiddle
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
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.:
env/dev/fiddle.clj
src/d/e/f.clj
Jumping 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.
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\"]
src/a/b/c/d.bb
env/dev/fiddle.bb
src/a/b/c/d.cljc
src/b/c/d.clj
env/dev/b-fiddles/c/d.clj
[\"src\", \"b\"]
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.
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.
ctrl+shift+p
cmd+shift+p
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:
Calva
calevtop
VS Code will match cal to \u201dCalva\u201d, ev to \u201dEvaluate\u201d, and top to \u201dTop\u201d. It looks like so:
cal
ev
top
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
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.
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.
calva.toggleKeybindingsEnabled
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.
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.
ctrl+up
With the default settings, Calva's formatting behaves like so:
ctrl+alt+l
Infer 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.
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.
There are three special commands for formatting the current form:
Aligns associative structures and bindings in two columns. See more below.
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:
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.
:remove-multiple-non-indenting-spaces? true
cljfmt
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.
calva
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.
maxWidth
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.
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.
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.
calva.fmt.configPath
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
:align-associative?
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.
:cljfmt
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).
CLOJURE-LSP
cljfmt-raw
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.
The cljfmt indents are highly configurable. They, and the rest of the configuration options, are masterly detailed here.
:extra-indents vs :indents
:extra-indents
:indents
Since Calva v2.0.383 we are using cljfmt 0.11.x which has a breaking configuration change. From the cljfmt README:
v2.0.383
0.11.x
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.
:legacy/merge-indents? true
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.)
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.fmt.keepCommentTrailParenOnOwnLine
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.
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:
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!
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.
You 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.
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
Ready? Awesome. Click this button to start the guide in a new browser tab.
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.
@pez
@bringe
Happy Interactive Programming! \u2764\ufe0f
We Clojurians inhabit a lot of community platforms. I'll list some of the more popular ones here in some order of popularity.
#beginners
You can also ask questions, and find answers, about Clojure at ask.clojure.org
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.
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..
welcome_to_clojure.clj
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.
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.
Give us feedback. Spread the word. Please consider:
#improve-getting-started
Please also consider other ways to contribute.
Thanks! \ud83d\ude4f
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:
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).
The \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.
If you like, you can defer installing anything at all and still get started with Calva (not kidding).
See Get Started with Clojure.
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:
View -> Command Palette...
It will open up a three files in a temporary directory, and start and connect a REPL. The files are:
hello_repl.clj
hello_paredit.clj
The 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.)
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.
PATH
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
index.html
The browser REPL app looks like so:
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.
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.
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.
user.clj
(ns user)
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.
Happy coding! \u2665\ufe0f
Calva can help you convert HTML to Hiccup.
The resulting data structure is formatted with zprint using it's :style :hiccup configuration.
:style :hiccup
In addition to, optionally, being able to convert style attributes to maps and kebab-case attributes, the conversion:
id
<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
baseProfile
<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:
calva.html2HiccupOptions
mapify-style
style
kebab-attrs?
add-classes-to-tag-keyword?
[:tag.clz1.clz2]
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.
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
The calva.pasteHtmlAsHiccup and calva.copyHtmlAsHiccup commands takes only a calva.html2HiccupOptions map.
calva.pasteHtmlAsHiccup
calva.copyHtmlAsHiccup
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.
As with any VS Code command using these from Joyride is a matter of calling executeCommand.
executeCommand
(-> (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
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.
.-result
(-> (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
: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
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.
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.
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.
lein repl
~/.lein/profiles.clj
~/.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.
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.)
'[nrepl\"0.6.0\"]'
nrepl
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...
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.)
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.)
.nrepl-port
.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.
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.
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.
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.)
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.
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).
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.
cljs-repl
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.
: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.
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.
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
(Right-click the video and choose Full Screeen if it is too tiny embedded.)
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.
#joyride
Come on, Join the Joyride! \u2764\ufe0f
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;
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).
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.
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.
config.edn
.clj-kondo/
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.
.lsp
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.
npm install -g clj-kondo
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.
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.
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.
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.
.calva
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:
output.calva-repl
.vsls.json
{\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.
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.
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.
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
yarn
my-luminus-shadow
$ code my-luminus-shadow\n
[:app] Build completed.
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.
Jack-in done.
lein shadow watch app
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
$ code my-luminus-server\n
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
$ code my-fw\n
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.
\"shouldOpenUrl\"
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.
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
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**.
.com
Available at:
The Calva symbol and Logo front, Rich Comments back.
The Calva symbol front, Rich Comments Back.
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
.co.uk
.de
.fr
.it
.es
.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.
.cljc
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.)
npx nbb
CMD
npm i -g nbb
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.
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.
<html
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.
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
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
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.
Toggle nREPL Logging Enabled
nREPL Messages
-> sent
<- received
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.
println
-> 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
Calva categorizes output into three types:
With the setting calva.outputDestinations, you can configure where each category of output should go to:
calva.outputDestinations
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.
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.
calva.legacyPrintBareReplWindowOutput
When Calva is connected to the REPL, the Output window will by default print not only results of evaluations, but also:
Structural editing and navigation for Clojure.
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.
To protect the integrity of your code, Strict mode is enabled by default.
delete
alt+backspace
alt+delete
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:
[\u03bb]
(\u03bb)
\u03bb
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.
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.
(Modify these with shift to select rather than move, see below.)
shift
ctrl+right
alt+right
ctrl+left
alt+left
ctrl+down
ctrl+alt+up
ctrl+alt+down
ctrl+end
ctrl+home
Most of these commands are selecting \u201dversions\u201d of the navigation commands above. Repeated use will grow the current selection step by step.
shift+alt+left
ctrl+shift+w
ctrl+alt+w space
(def ...)
(defn ...)
shift+ctrl+right
ctrl+shift+k
shift+ctrl+left
ctrl+shift+down
ctrl+shift+alt+up
ctrl+shift+alt+down
ctrl+shift+up
ctrl+shift+end
ctrl+shift+home
ctrl+alt+right
ctrl+alt+.
ctrl+alt+left
ctrl+alt+,
ctrl+alt+shift+left
ctrl+alt+shift+right
ctrl+alt+s
ctrl+shift+s
ctrl+shift+j
ctrl+alt+p ctrl+alt+r
ctrl+alt+t
alt+up
alt+down
ctrl+alt+shift
u
d
k
j
ctrl+shift+c
ctrl+shift+delete
ctrl+k ctrl+k
ctrl+k
ctrl+k ctrl+h
cmd+backspace
ctrl+alt+backspace
ctrl+delete
ctrl+backspace
ctrl+alt+shift+delete
ctrl+alt+shift+backspace
ctrl+alt+shift+p
ctrl+alt+shift+s
ctrl+alt+shift+c
ctrl+alt+shift+q
ctrl+alt+r
ctrl+alt+p
s
c
q
h
#{}
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.
calva.paredit.killAlsoCutsToClipboard
And like so (wait for it):
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.
calva.paredit.hijackVSCodeDefaults
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.)
calva.paredit.defaultKeyMap
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.
!editorHasMultipleSelections
Happy Editing! \u2764\ufe0f
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.
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.
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.
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:
(baz)
(fo| (bar)\n(baz))\n
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.
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.
calva.fmt.experimental.inferParensAsYouType
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.
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.
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.
space
shift+tab
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.
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.
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:
:dev
: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
clj\ua789dev.server\ua789>
(start! 6003)
A ClojureScript frontend, of course:
api-url
events.cljs
(def api-url \"http://localhost:6003/api\")\n
:app
In 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.
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.
*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
printEngine
printFn
nREPL
print
width
maxLength
(iterate inc 0)
...
maxDepth
puget
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.).
zprint
(pretty-print [[[[[[[[:deeper]]]]]]]] {:max-depth 4})\n;; => {:value \"[[[[##]]]]\"}\n
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:
clojure.core/pprint
fipp
These particular server side functions were chosen because they have pre-configured print-functions in cider-nrepl.
cider-nrepl
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.
Copy Jack-in Command Line to Clipboard
Enjoy Prettiful Printing! \u2764\ufe0f
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).
Currently cider-nrepl does not provide its test functionality for ClojureScript code. Please consider contributing to fixing that.
See Using with Parinfer
See Using Calva with the VIM Extension.
Jack-in starts by running a command in a new terminal. You will need the commands used installed on your computer:
lein
npx
gradlew
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:
See this issue for more clues on this problem.
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.
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+C
views.cljs
src/<your-project-name>
ctrl+alt+c enter
(js/alert \"Hello from Calva\")
REBL is a graphical, interactive tool for browsing Clojure data.
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.
~/.clojure
;; 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
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
{\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
TBD. If you know how to do it, please update this page.
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.
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.
clojureLsp.refactor.cleanNs
clojureLsp.refactor.addMissingLibspec
clojureLsp.refactor.extractFunction
clojureLsp.refactor.cyclePrivacy
clojureLsp.refactor.inlineSymbol
clojureLsp.refactor.introduceLet
clojureLsp.refactor.expandLet
clojureLsp.refactor.moveToLet
clojureLsp.refactor.threadFirst
clojureLsp.refactor.threadFirstAll
clojureLsp.refactor.threadLast
clojureLsp.refactor.threadLastAll
clojureLsp.refactor.unwindAll
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.
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.
Run Remote-Containers: Add Development Container Configuration Files... and pick a suitable Java base image. Then:
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
Add Calva and, optionally, forward some ports to the host::
\"extensions\": [\"betterthantomorrow.calva\"],\n\"forwardPorts\": [8088, 52162], // example: your webapp, your nREPL\n
Run Remote-Containers: Rebuild and Reopen in container
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.
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.
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.
This also works for Clojure core and library namespaces.
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:
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.
Recently evaluated forms in the REPL file are persisted and can easily be shown again for modifying and re-evaluating.
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.
You can clear the repl history by running the command \"Clear REPL History\" from the command palette.
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.
ctrl+click
cmd+click
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).
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.
pez/xxx.clj
pez/yyy.clj
pez.yyy
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:
(ns pez.yyy)
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
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).
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.
output.repl
.calva/output-window
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.)
.calva/output-window/
.<something>ignore
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.
Reveal is a \"Read Eval Visualize Loop for Clojure\". This page describes how to use Reveal in your development setup based on Calva.
See https://vlaaad.github.io/reveal for the latest version and use that wherever this page says <version>.
<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.
This will make Reveal to start together with your project.
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.
:reveal-nrepl-middleware
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.
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.
If you find the font to small you can add a :jvm-opts key to make it a little bigger:
:jvm-opts
: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
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.
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.
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:
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
Note 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.
:rcf
#_
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.
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
(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.)
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:
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
To fold the trailing paren automatically, place the cursor immediately outside (before or after) the form:
(comment\n(def foo\n:foo))|\n
You can disable this behavior with the setting: calva.fmt.keepCommentTrailParenOnOwnLine.
This treatment only applies to formatting of the current form. With fold when done as an exception.
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.
Here's how you start a shadow-cljs ClojureScript REPL and connect Calva with the shadow-cljs - browser quickstart example project:
Prep:
Connect Calva:
Now you can should be able to evaluate forms, e.g.:
(See Code Evaluation)
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.
:deps {:aliases [...]}
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
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.
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.
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).
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.
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:
constant.keyword.clojure
\"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.
Default Dark+
You are in charge of how brackets and comments are highlighted via the calva.highlight.<setting> settings:
calva.highlight.<setting>
enableBracketColors
rainbowIndentGuides
highlightActiveIndent
bracketColors
[\"#000\", \"#999\"]
cycleBracketColors
misplacedBracketStyle
{ \"border\": \"2px solid #c33\" }
matchedBracketStyle
{\"backgroundColor\": \"#E0E0E0\"}
ignoredFormStyle
#_...
{\"textDecoration\": \"none; opacity: 0.5\"}
commentFormStyle
{\"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).
editor.renderIndentGuides
editor.highlightActiveIndent
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.highlight.bracketColors
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Calva provides commands that make running your Clojure tests easier.
Since the test commands utilize cider-nrepl, they only work with Clojure, not ClojureScript. See this issue for more details.
-test
<current-namespace>-test
with-test
deftest
You can enable the Calva setting \"Test on Save\" to have tests for the current namespace run on file save.
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.
calva.useTestExplorer
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.
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).
:extra-paths
\"test\"
{:aliases {:dev {:extra-paths [\"test\"]}}}\n
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.
test
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
If you are using any non leiningen style folder structure, you may have to add source paths inside .lsp/config.edn.
.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\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)
(+ (* 2 2) 2)
(hello \"Calva REPL\")
(defn hello...
Demo:
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 defs defn, defthis, defthat. With your cursor placed anywhere inside such a form.
defthis
defthat
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.
In general Calva's default key bindings are not very VI-ish.
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.
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
// 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.
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!)
before
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.
init.vim
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:
The 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
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:
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)
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.
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.
Remote-WSL
See also Remote Development.
(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
export async function evaluateCode(\n sessionKey: 'clj' | 'cljs' | 'cljc' | undefined,\n code: string,\n ns = 'user',\n output?: {\n stdout: (m: string) => void;\n stderr: (m: string) => void;\n },\n opts = {}\n): Promise<Result>;\n
type Result = {\n result: string;\n ns: string;\n output: string;\n errorOutput: string;\n};\n
(-> (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 {\n const evaluation = await calvaApi.repl.evaluateCode(\"clj\", \"(+ 2 40)\");\n console.log(evaluation.result);\n} catch (e) {\n console.error(\"Evaluation error:\", e);\n}\n
(def oc (joyride.core/output-channel)) ;; Assuming Joyride is used\n(def evaluate (fn [code]\n (calva/repl.evaluateCode\n \"clj\"\n code\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\"\n code\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) =>\n calvaApi.repl.evaluateCode(\"clj\", code, \"user\", {\n stdout: (s) => {\n console.log(s);\n },\n stderr: (s) => {\n console.error(s);\n },\n });\n\ntry {\n const evaluation = await evaluate(\"(println :foo) (+ 2 40)\");\n console.log(\"=>\", evaluation.result);\n} catch (e) {\n console.error(\"Evaluation error:\", e);\n}\n
(let [[range text] (calva/ranges.currentTopLevelForm)]\n ...)\n
(let [[range text] ((get-in [:ranges :currentTopLevelForm]))]\n ...)\n
(-> (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
(-> (joyride/extension-context)\n .-subscriptions\n (.push (calva/vscode.registerDocumentSymbolProvider ...)))\n
(-> yourExtensionContext\n .-subscriptions\n (.push ((get-in calva [:vscode :registerDocumentSymbolProvider]) ...)))\n
\"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
{\n \"key\": \"ctrl+alt+r f\",\n \"command\": \"clojure-lsp.command\",\n \"args\": [\"extract-function\", [\"new-function\"]]\n },\n
(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)\n trimmed-text)))\n
(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)\n trimmed-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:\n when\n when-let\n if\n )\n
\"calva.replConnectSequences\": [\n {\n \"name\": \"Bashbabka (WSL)\",\n \"projectType\": \"custom\",\n \"customJackInCommandLine\": \"bash -c 'bb --nrepl-server JACK-IN-NREPL-PORT'\",\n },\n ],\n
#!/usr/bin/env bb\n\n(require '[clojure.string :as str])\n\n(defn parse-args [args]\n (loop [args args\n parsed {}]\n (if (empty? args)\n parsed\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) #\",\")\n cider-nrepl-version (:cider-nrepl-version args)\n project-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
{\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
\"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
{\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
{\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
{\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
\"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
\"calva.customREPLCommandSnippets\": [\n {\n \"name\": \"Remount CLJS App\",\n \"key\": \"r\",\n \"repl\": \"cljs\",\n \"ns\": \"example.app\",\n \"snippet\": \"(start)\"\n }\n ],\n
{\n \"key\": \"ctrl+cmd+u alt+enter\",\n \"command\": \"calva.runCustomREPLCommand\",\n \"args\": {\n \"ns\": \"user\",\n \"snippet\": \"$current-form\",\n }\n },\n
\"calva.customREPLHoverSnippets\": [\n {\n \"name\": \"eval text on hover\",\n \"repl\": \"clj\",\n \"ns\": \"example.app\",\n \"snippet\": \"(str \\\"$hover-text\\\")\"\n }\n ]\n
{: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
options?: {\n host?: string;\n port?: string;\n connectSequence?: string | ReplConnectSequence;\n disableAutoSelect?: boolean;\n }\n
{\n \"command\": \"calva.connect\",\n \"args\": {\"disableAutoSelect\": true},\n \"key\": \"ctrl+alt+c shift+c\",\n },\n
options?: {\n connectSequence?: string | ReplConnectSequence;\n disableAutoSelect?: boolean;\n }\n
{\n \"command\": \"calva.jackIn\",\n \"args\": {\"disableAutoSelect\": true},\n \"key\": \"ctrl+alt+c shift+j\",\n },\n
(vscode/commands.executeCommand\n \"calva.jackIn\"\n (clj->js {:connectSequence {:projectType \"deps.edn\"\n :projectRootPath [\".\"]}}))\n
\"calva.prettyPrintingOptions\": {\n \"enabled\": true,\n \"printEngine\": \"pprint\",\n \"width\": 40\n },\n
\"[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
\"workbench.colorCustomizations\": {\n \"calva.inlineErrorForegroundColor\": \"#ff0000\",\n \"calva.inlineForegroundColor\": \"#ff9000\"\n }\n
{\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
{\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
(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
(loop [i 0]\n #break\n (when (< i 10)\n (println i)\n (recur (inc i))))\n
(defn simple [x]\n (+ 1 #break 1)) ;; This breakpoint will not be hit\n
{\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
[\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
(let [foo :bar]\n (when false (str| foo))) ; => \":bar\"\n
(->> [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
(defn fortytwo-from-thirty\n []\n (let [thirty 30]\n (-> thirty\n inc ;1\n (send-off)\n (+ 1 2 3)\n (->>\n (+ 2 2) ;2\n (+))\n list\n (->>\n (into [1])\n (reduce + 1))\n (- 1) ;3\n (* -1))))\n
(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\n vals ; 4\n average ; 5\n ))))\n
\"calva.fiddleFilePaths\": [\n {\n \"source\": [\"src\"],\n \"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n }\n]\n
\"calva.fiddleFilePaths\": [\n {\n \"source\": [\"src\"],\n \"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n },\n]\n
\"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
(ns main.core\n {:clj-kondo/config\n '{:linters {:unresolved-symbol {:level :off}}}})\n
(let [a :b]\n (str \"foo\" \"bar\" \"baz\"\n \"a\" a))\n
{: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
{: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
:test-code\n (concat [2]\n (map #(inc (* % 2))\n (filter #(aget sieved %)\n (range 1 hn))))\n
// 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
(-> (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
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\")\n (.then ...))\n
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" \n #js {:html \"<foo class='clz1 clz2>bar</foo>\"})\n (.then #(println (.-result %))))\n\n(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" \n #js {:options #js {:mapify-style? false}})\n (.then #(println (.-result %))))\n
(-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" \n #js {:toUntitled true\n :html \"<foo class='clz1 clz2>bar</foo>\"\n :options #js {:mapify-style? true\n :kebab-attrs? true}})\n (.then ...))\n
\"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
{\n \"type\": \"chrome\",\n \"request\": \"launch\",\n \"name\": \"Launch Debugger\",\n \"url\": \"http://localhost:8081/debugger-ui/\",\n \"webRoot\": \"${workspaceFolder}\"\n }\n
{\n \"$schema\": \"http://json.schemastore.org/vsls\",\n \"hideFiles\": [\n \"!.calva\"\n ]\n}\n
{\n \"command\": \"paredit.insertSemiColon\",\n \"key\": \";\",\n \"when\": \"calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap == strict && !editorReadOnly && !editorHasMultipleSelections && !calva:cursorInComment\"\n },\n
(foo| (bar)\n (baz))\n
(fo| (bar\n (baz)))\n
(fo| (bar)\n (baz))\n
\"[clojure]\": {\n \"editor.autoClosingBrackets\": \"never\",\n \"editor.autoClosingOvertype\": \"never\",\n \"editor.formatOnPaste\": false\n },\n
\"[clojure]\": {\n \"editor.autoClosingBrackets\": \"always\",\n \"editor.autoClosingOvertype\": \"always\",\n \"editor.formatOnPaste\": true\n },\n
(pretty-print [[[[[[[[:deeper]]]]]]]] {:max-depth 4})\n ;; => {:value \"[[[[##]]]]\"}\n
;; 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)\n org.clojure/data.csv {:mvn/version \"0.1.4\"}\n org.clojure/data.json {:mvn/version \"0.2.3\"}\n org.yaml/snakeyaml {:mvn/version \"1.23\"}\n com.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\"}\n org.openjfx/javafx-controls {:mvn/version \"12.0.1\"}\n org.openjfx/javafx-graphics {:mvn/version \"12.0.1\"}\n org.openjfx/javafx-media {:mvn/version \"12.0.1\"}\n org.openjfx/javafx-swing {:mvn/version \"12.0.1\"}\n org.openjfx/javafx-base {:mvn/version \"12.0.1\"}\n org.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
{\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
{: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
{\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
(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
(ns pez.yyy\n (:require [pez.xxx]))\n\n(def a :yyy-a)\n\n(println \"Hello\" pez.xxx/a)\n
: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
:reveal-dep-only\n {:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}}\n
\"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
:profiles {:reveal {:dependencies [[vlaaad/reveal \"<version>\"]]\n :repl-options {:nrepl-middleware [vlaaad.reveal.nrepl/middleware]}}}\n
: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
(defmacro comment\n \"Ignores body, yields nil\"\n {:added \"1.0\"}\n [& body])\n
(comment\n )\n
(comment\n (def foo\n:foo)|)\n
(comment\n (def foo\n :foo)\n |)\n
(comment\n (def foo\n:foo)\n |\n :rcf)\n
(comment\n (def foo\n :foo)\n |\n :rcf)\n
(comment\n (def foo\n:foo)\n\n|\n\n)\n
(comment\n (def foo\n :foo)\n\n |\n\n )\n
(comment\n (def foo\n:foo))|\n
(comment\n (def foo\n :foo))|\n
(comment\n (+ (* 2 2)\n 2)\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
// 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
\"vim.insertModeKeyBindings\": [\n {\n \"before\": [\"j\", \"k\"],\n \"after\": [\"<esc>\"]\n }\n]\n