From 65cf21ee2b235d236c96cec965d41d25f298ce05 Mon Sep 17 00:00:00 2001 From: <> Date: Sat, 27 Apr 2024 08:34:23 +0000 Subject: [PATCH] [skip ci] --- assets/images/social/evaluation.png | Bin 0 -> 46133 bytes joyride/index.html | 4 +- search/search_index.json | 2 +- sitemap.xml | 122 ++++++++++++++-------------- sitemap.xml.gz | Bin 685 -> 685 bytes 5 files changed, 64 insertions(+), 64 deletions(-) diff --git a/assets/images/social/evaluation.png b/assets/images/social/evaluation.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0995063170f73f23f800b73014f9e3925663557f 100644 GIT binary patch literal 46133 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 JCC8nv{S!TN=(_*_ literal 0 HcmV?d00001 diff --git a/joyride/index.html b/joyride/index.html index 47e263997..27384ed16 100644 --- a/joyride/index.html +++ b/joyride/index.html @@ -1959,9 +1959,9 @@

How to connectthe Joyride Extension -
  • Isssuing the command Calva: Start a REPL in your Project and (a.k.a Jack-in)
  • +
  • Issuing the command Calva: Start a REPL in your Project and (a.k.a Jack-in)
  • Selecting joyride project type
  • -
  • Isssuing the command Calva: Load/Evaluate Current File and its Requires/Dependencies
  • +
  • Issuing the command Calva: Load/Evaluate Current File and its Requires/Dependencies
  • Evaluating some non-vscode code
  • Evaluating code exercising something from the VS Code API
  • diff --git a/search/search_index.json b/search/search_index.json index 5d4e4ebdc..17a6922b1 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-\\._]","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome!","text":"

    Calva is an integrated, REPL powered, development environment for enjoyable and productive Clojure and ClojureScript programming in Visual Studio Code. It is feature rich and turnkey. A lot of effort has been put into making Calva a good choice if you are new to Clojure. Calva is open source and free to use.

    "},{"location":"#getting-started","title":"Getting Started","text":"

    Let's start a REPL!. \ud83d\ude80 Also see Get Started with Clojure

    "},{"location":"#how-to-contribute-to-calva","title":"How to Contribute to Calva?","text":"

    I'm glad you asked! Please see How to Contribute and The Tao of Calva

    "},{"location":"#calva-patrons","title":"Calva Patrons","text":"The right kind of different"},{"location":"#calva-gold-sponsors","title":"Calva Gold Sponsors \u2665\ufe0f","text":"Scale your growth on mobile MAKE. DO. SHIP.

    Please see this statement from Cognitect about the importance of supporting open source developers.

    See Sponsors for information about sponsoring Calva.

    If your Company benefits from Calva's existence and you see it as an important in the Clojure and ClojureScript ecosystem. please consider sponsoring!

    "},{"location":"#features","title":"Features","text":"

    Calva includes inline code evaluation, structural editing, code formatting, code navigation, a debugger, linting, syntax highlighting, Clojure aware rainbow brackets, a test runner, refactoring support, and more.

    "},{"location":"#have-questions-and-feedback-need-help","title":"Have Questions and Feedback? Need Help?","text":"

    Easiest way is to chat with us and other Calva users. Please join the #calva channel on the Clojurians Slack. If you haven't joined that slack workspace, you can get an invite here.

    If you're a beginner to Clojure(Script), the #beginners channel of the Clojurians Slack is very active and helpful.

    "},{"location":"#please-star-the-calva-repo","title":"Please star the Calva repo!","text":"

    Happy coding!

    "},{"location":"api/","title":"The Calva Extension API","text":"

    Calva exposes an API for use from other VS Code extensions (such as Joyride). The API is in an experimental state, while we are figuring out what is a good shape for this API. It is also rather small, and will grow to expose more of Calva's functionality.

    ","boost":7},{"location":"api/#accessing","title":"Accessing","text":"

    To access the API the Calva extension needs to be activated. The API is exposed under the v1 key on the extension's exports, and split up into submodules, like repl, and ranges.

    When using Joyride you can use its unique require API, for which one of the benefits is better lookup IDE support. When using the API from regular ClojureScript, you'll pick it up from the Calva extension instance. (Which you can do from Joyride as well, but why would you?). Here is how you access the API, with an example of usage as a bonus:

    JoyrideClojureScriptJavaScript
    (ns ... (:require [\"ext://betterthantomorrow.calva$v1\" :as calva]))\n;; OR\n(require '[\"ext://betterthantomorrow.calva$v1\" :as calva])\n\n(calva/repl.currentSessionKey) => \"cljs\" ; or \"clj\", depending\n
    (def calvaExt (vscode/extensions.getExtension \"betterthantomorrow.calva\"))\n\n(def calva (-> calvaExt\n             .-exports\n             .-v1\n             (js->clj :keywordize-keys true)))\n\n((get-in calva [:repl :currentSessionKey])) => \"cljs\" ; or \"clj\", depending\n
    const calvaExt = vscode.extensions.getExtension(\"betterthantomorrow.calva\");\n\nconst calva = calvaExt.exports.v1;\n\nconst sessionKey = calva.repl.currentSessionKey()\n
    ","boost":7},{"location":"api/#repl","title":"repl","text":"

    The repl module provides access to Calva's REPL connection.

    ","boost":7},{"location":"api/#replcurrentsessionkey","title":"repl.currentSessionKey()","text":"

    Use repl.currentSessionKey() find out which REPL/session Calva's REPL is currently connected to (depends on the active file). Returns either \"clj\", or \"cljs\", or nil if no REPL is connected.

    JoyrideClojureScriptJavaScript
    (def session-key (calva/repl.currentSessionKey))\n
    (def session-key ((get-in [:repl :currentSessionKey] calvaApi)))\n
    const sessionKey = calva.repl.currentSessionKey()\n
    ","boost":7},{"location":"api/#replevaluatecode","title":"repl.evaluateCode()","text":"

    This function lets you evaluate Clojure code through Calva's nREPL connection. Calling it returns a promise that resolves to a Result object. It's signature looks like so (TypeScript):

    export async function evaluateCode(\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

    Where Result is:

    type Result = {\n  result: string;\n  ns: string;\n  output: string;\n  errorOutput: string;\n};\n

    As you can see, the required arguments to the function are sessionKey and code. sessionKey should be \"clj\", \"cljs\", \"cljc\", or undefined depending on which of Calva's REPL sessions/connections that should be used. It will depend on your project, and how you connect to it, which session keys are valid. Use cljc to request whatever REPL session \"cljc\" files are connected to. Use undefined to use the current REPL connection Calva would use (depends on which file is active).

    An example:

    JoyrideClojureScriptJavaScript
    (-> (p/let [evaluation (calva/repl.evaluateCode \"clj\" \"(+ 2 40)\")]\n      (println (.-result evaluation)))\n    (p/catch (fn [e]\n               (println \"Evaluation error:\" e))))\n
    (def evaluate (get-in [:repl :evaluateCode] calvaApi))\n(-> (p/let [evaluation (evaluate \"clj\" \"(+ 2 40)\")]\n      (println (.-result evaluation)))\n    (p/catch (fn [e]\n               (println \"Evaluation error:\" e))))\n
    try {\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
    ","boost":7},{"location":"api/#handling-output","title":"Handling Output","text":"

    The output member on the Result object will have any output produced during evaluation. (The errorOutput member should contain error output produced, but currently some Calva bug makes this not work.) By default the stdout and stderr output is not printed anywhere.

    If you want to do something with either regular output or error output during, or after, evaluation, you'll need to provide the output argument to evaluateCode(). (The stderr callback function works, so this is the only way to get at any error output, until the above mentioned Calva bug is fixed.)

    An example:

    JoyrideClojureScriptJavaScript
    (def oc (joyride.core/output-channel)) ;; Assuming Joyride is used\n(def evaluate (fn [code]\n                (calva/repl.evaluateCode\n                 \"clj\"\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
    ","boost":7},{"location":"api/#ranges","title":"ranges","text":"

    The ranges module contains functions for retreiving vscode.Ranges and text for pieces of interest in a Clojure document.

    All functions in this module have the following TypeScript signature:

    (editor = vscode.window.activeTextEditor, position = editor?.selection?.active) => [vscode.Range, string];\n

    I.e. they expect a vscode.TextEditor \u2013 defaulting to the currently active editor \u2013 and a vscode.Position \u2013 defaulting to the current active position in the editor (or the first active position if multiple selections/positions exist, and will return a tuple with the range, and the text for the piece of interest requested.

    Custom REPL Commands

    The ranges function have corresponding REPL Snippets/Commands substitution variables. It is the same implementation functions used in both cases.

    The functions available are:

    ","boost":7},{"location":"api/#rangescurrentform","title":"ranges.currentForm()","text":"

    Retrieves information about the current form, as determined from the editor and position.

    Corresponding REPL Snippet variable: $current-form.

    See also about Calva's Current Form on YouTube.

    ","boost":7},{"location":"api/#rangescurrentenclosingform","title":"ranges.currentEnclosingForm()","text":"

    The list/vector/etcetera form comtaining the current form.

    Corresponding REPL Snippet variable: $enclosing-form.

    ","boost":7},{"location":"api/#rangescurrenttoplevelform","title":"ranges.currentTopLevelForm()","text":"

    The current top level form. Outside (comment ...) (Rich comments) forms this is most often ((def ...), (defgn ...), etcetera. Inside Rich comments it will be the current immediate child to the (comment ...) form.

    Corresponding REPL Snippet variable: $top-level-form.

    ","boost":7},{"location":"api/#rangescurrentfunction","title":"ranges.currentFunction()","text":"

    The current function, i.e. the form in \u201dcall position\u201d of the closest enclosing list.

    Corresponding REPL Snippet variable: $current-fn.

    ","boost":7},{"location":"api/#rangescurrenttopleveldef","title":"ranges.currentTopLevelDef()","text":"

    The symbol being defined by the current top level form. NB: Will stupidly assume it is the second form. I.e. it does not check that it is an actual definition, and will often return nonsense if used in Rich comments.

    Corresponding REPL Snippet variable: $top-level-defined-symbol.

    ","boost":7},{"location":"api/#example-rangescurrenttoplevelform","title":"Example: ranges.currentTopLevelForm()","text":"JoyrideClojureScriptJavaScript
    (let [[range text] (calva/ranges.currentTopLevelForm)]\n  ...)\n
    (let [[range text] ((get-in [:ranges :currentTopLevelForm]))]\n  ...)\n
    const [range, text] = ranges.currentTopLevelForm();\n
    ","boost":7},{"location":"api/#editor","title":"editor","text":"

    The editor module has facilites (well, a facility, so far) for editing Clojure documents.

    ","boost":7},{"location":"api/#editorreplace","title":"editor.replace()","text":"

    With editor.replace() you can replace a range in a Clojure editor with new text. The arguments are:

    • editor, a vscode.TextEditor
    • range, a vscode.Range
    • newText, a string
    JoyrideJavaScript
    (-> (p/let [top-level-form-range (first (calva/ranges.currentTopLevelForm))\n            _ (calva/editor.replace vscode/window.activeTextEditor top-level-form-range \"Some new text\")]\n      (println \"Text replaced!\"))\n    (p/catch (fn [e]\n               (println \"Error replacing text:\" e))))\n
    const topLevelRange = calvaApi.ranges.currentTopLevelForm();\ncalva.editor.replace(topLevelRange, \"Some new text\")\n  .then((_) => console.log(\"Text replaced!\"))\n  .catch((e) => console.log(\"Error replacing text:\", e));\n
    ","boost":7},{"location":"api/#document","title":"document","text":"

    The document module provides access to the Clojure/Calva aspects of VS Code TextDocuments.

    ","boost":7},{"location":"api/#documentgetnamespacedocument-vscodetextdocument-string","title":"document.getNamespace(document?: vscode.TextDocument): string","text":"

    document.getNamespace() returns the namespace of a document.

    • document, a vscode.TextDocument (defaults to the current active document)

    Example usage. To evaluate some code in the namespace of the current document:

    JoyrideJavaScript
    (calva/repl.evaluateCode \"clj\" \"(+ 1 2 39)\" (calva/document.getNamespace))\n
    calva.repl.evaluateCode(\"clj\",  \"(+ 1 2 39)\", calva.document.getNamespace());\n
    ","boost":7},{"location":"api/#documentgetnamespaceandnsformdocument-vscodetextdocument-ns-string-nsform-string","title":"document.getNamespaceAndNsForm(document?: vscode.TextDocument): [ns: string, nsForm: string]","text":"

    document.getNamespaceAndNsForm() returns the namespace and the ns form of a document as a tuple.

    • document, a vscode.TextDocument (defaults to the current active document)

    Example usage. To evaluate the ns form of the current document:

    JoyrideJavaScript
    (calva/repl.evaluateCode \"clj\" (second (calva/document.getNamespaceAndNsForm)))\n
    calva.repl.evaluateCode(\"clj\", calva.document.getNamespaceAndNsForm()[1]);\n
    ","boost":7},{"location":"api/#pprint","title":"pprint","text":"

    The pprint module lets you pretty print Clojure code/data using Calva's pretty printing engine (which in turn uses zprint).

    ","boost":7},{"location":"api/#pprintprettyprint","title":"pprint.prettyPrint()","text":"

    Use pprint.prettyPrint() to pretty print some Clojure data using your Calva pretty printing options. It accepts these arguments:

    • text, a string with the text to pretty print
    • options, a JavaScript object with pretty printing options, this is optional and will default to the current settings.

    The function is synchronous and returns the prettified text.

    JoyrideJavaScript
    (println (calva/pprint.prettyPrint \"Some text\")))\n
    console.log(calvaApi.pprint.prettyPrint();\n
    ","boost":7},{"location":"api/#pprintprettyprintingoptions","title":"pprint.prettyPrintingOptions()","text":"

    Use to get the current pretty printint options:

    ","boost":7},{"location":"api/#vscode","title":"vscode","text":"

    In the its vscode submodule, Calva exposes access to things from its own vscode module instance. It gets important in some situations.

    ","boost":7},{"location":"api/#vscoderegisterdocumentsymbolprovider","title":"vscode.registerDocumentSymbolProvider()","text":"

    This is the [vscode.languages](https://code.visualstudio.com/api/references/vscode-api#languages).registerDocumentSymbolProvider() function from the Calva extension. Use it if you want to provide symbols for Clojure files together with the ones that Calva provides. (If you use the vscode.languages.registerDocumentSymbolProvider() function from your extension (or Joyride) you will provide a separate group.)

    JoyrideClojureScriptJavaScript
    (-> (joyride/extension-context)\n  .-subscriptions\n  (.push (calva/vscode.registerDocumentSymbolProvider ...)))\n
    (-> yourExtensionContext\n  .-subscriptions\n  (.push ((get-in calva [:vscode :registerDocumentSymbolProvider]) ...)))\n
    yourExtensionContext.subscriptions.push(calva.vscode.registerDocumentSymbolProvider(...));\n

    Deprecation candidate

    VS Code is still creating a separate group, just with the same name as Calva's, so this API is not good for anything, and we will probably remove it.

    ","boost":7},{"location":"api/#feedback-welcome","title":"Feedback Welcome","text":"

    Please let us know how you fare using this API. Either in the #calva or #joyride channels on Slack or via the issues/discussions sections on the repositories. (Whichever seems to apply best.)

    ","boost":7},{"location":"async-out/","title":"Viewing Async Output While Working On Node Projects with shadow-cljs","text":"

    When working on NodeJS projects with shadow-cljs and Calva, async output does not always appear in the Calva output window. To work around this problem, follow these steps:

    1. Run the command \"Calva: Copy Jack-in Command Line to Clipboard\", then paste the command in a terminal and run it.
    2. Wait for the message shadow-cljs - nREPL server started on port <some-port>
    3. Issue the command Calva: Connect to a running REPL server in your project, ctrl+alt+c ctrl+alt+c. For project type select shadow-cljs, accept the proposed localhost:<some-port>, and for build select node-repl.
    4. Load a file from your project with the command ctrl+alt+c Enter. Evaluating forms in Calva will show results in the output window. Synchronous stdout output will be printed in both the output window and in the terminal where you started the repl. Some asynchronous output may show up in the output window, but all will appear in the terminal.

    If you use an integrated VSCode terminal to start shadow-cljs, all stdout will appear in the Calva window with your code. Alternatively, you can use an external terminal, which is especially nice when using a second monitor.

    For a discussion of this problem and other connection options, see issue #1468.

    "},{"location":"babashka/","title":"Using Calva with Babashka","text":"

    Since Babashka can be started such that it is an nREPL server, Calva can connect to it and a lot of the features will work.

    Calva can also start Babashka and connect its REPL for you, using the Jack-in command.

    Don't expect complete support

    Babashka's nREPL server is still a bit limited compared to a full cider-nrepl enhanced \"regular\" Clojure nREPL server. Things like function signatures, and more do not work.

    This might of course improve in the future, especially if you provide some PRs towards the Babashka nREPL.

    ","boost":5},{"location":"clj-java-decompiler/","title":"Decompiling and disassembly made easy","text":"

    If you need some piece of Clojure code to execute as fast as possible you will often benefit from examining the code generated by the Clojure compiler from your code. There is a really easy to use tool for that: clj-java-decompiler. You can make the use of this tool super convenient with Calva custom command snippets.

    "},{"location":"clj-java-decompiler/#prerequisites","title":"Prerequisites","text":"

    Add com.clojure-goes-fast/clj-java-decompiler as a dependency to the project.

    "},{"location":"clj-java-decompiler/#the-custom-snippets","title":"The custom snippets","text":"

    You can add some Calva custom commands configuration to be able to decompile or disassemble any Clojure code in your editor with a keyboard shortcut. Here's an example configuration:

        \"calva.customREPLCommandSnippets\": [\n        {\n            \"name\": \"Decompile current top level form\",\n            \"key\": \"d\",\n            \"snippet\": \"(require '[clj-java-decompiler.core :refer [decompile]]) (spit \\\"decompiled-$top-level-defined-symbol.java\\\" (with-out-str (decompile $top-level-form)))\"\n        },\n        {\n            \"name\": \"Decompile current form\",\n            \"snippet\": \"(require '[clj-java-decompiler.core :refer [decompile]]) (spit \\\"decompiled.java\\\" (with-out-str (decompile $current-form)))\"\n        },\n        {\n            \"name\": \"Disassemble current top level form\",\n            \"key\": \"b\",\n            \"snippet\": \"(require '[clj-java-decompiler.core :refer [disassemble]]) (spit \\\"bytecode-$top-level-defined-symbol.class\\\" (with-out-str (disassemble $top-level-form)))\"\n        },\n        {\n            \"name\": \"Disassemble current current form\",\n            \"snippet\": \"(require '[clj-java-decompiler.core :refer [disassemble]]) (spit \\\"bytecode.class\\\" (with-out-str (disassemble $current-form)))\"\n        }\n    ],\n

    Now, with the cursor anywhere in a top level defined function, you can spit out a file with the Java code generated for that function by pressing ctrl+alt+space d. For the byte code, press ctrl+alt+space b. The files will be generated in the same folder as the Clojure file and be named decompiled-<function name>.java and bytecode-<function name>.class, respectively.

    To decompile or disassemble the current form (or selection) press ctrl+alt+space space and pick the desired command from the quick pick menu that pops up. You can add key to these too if you want even quicker access, of course. The filenames for the results will here be named without any function name suffix, because there is often no function name that can be used.

    See this video for a demo.

    "},{"location":"clojure-lsp/","title":"Clojure-lsp","text":"

    Calva uses a mix of static and dynamic analysis to power the experience. A lot of the static abilities come from clojure-lsp. This enables you to check something up in a project, with a lot of navigational and contextual support, without starting a REPL for it. (And once you do start a REPL you'll get even more capabilities, enabled by the dynamic analysis.)

    Which clojure-lsp does Calva use?

    Calva defaults to using the latest clojure-lsp released. To use a different version of clojure-lsp, see the configuration section. Calva does not use the clojure-lsp installed on your system, unless you set the path for clojure-lsp to the installed binary in your settings. You can see what version is being used by running the Clojure-lsp Server Info command, which will also show the version of clj-kondo that's being used as well as other info.

    "},{"location":"clojure-lsp/#the-lsp-server-lifecycle","title":"The LSP server lifecycle","text":"

    By default you won't need to install/setup anything as Calva handles that for you by automatically downloading the latest clojure-lsp binary. It can take a while for clojure-lsp to start, especially the first time opening a new project, as clojure-lsp (via clj-kondo) indexes the project files.

    Calva is able to automatically start the clojure-lsp server for you and can be configured to start the server under various different conditions. These behaviours can be configured through the calva.enableClojureLspOnStart setting, which takes the following options:

    • \"always-use-first-workspace-root\"
    • \"when-workspace-opened-use-workspace-root\"
    • \"when-file-opened-use-furthest-project\"
    • \"never\"
    "},{"location":"clojure-lsp/#always-use-first-workspace-root-default","title":"\"always-use-first-workspace-root\" [default]","text":"

    When set to \"always-use-first-workspace-root\" Calva will attempt to start the clojure-lsp in the root of the first workspace folder if it is a valid clojure project. If it is not a valid clojure project it will fall back to starting the fallback server.

    This is the default auto-start behaviour.

    "},{"location":"clojure-lsp/#when-workspace-opened-use-workspace-root","title":"\"when-workspace-opened-use-workspace-root\"","text":"

    When set to \"when-workspace-opened-use-workspace-root\" Calva will start the clojure-lsp in the root of all opened vscode workspaces. All Clojure files in a workspace will be serviced by the clojure-lsp server running in that workspace. This behavior requires that you are opening workspaces with a valid Clojure project in the root (the directory must contain a deps.edn, project.clj or shadow-cljs.edn file).

    "},{"location":"clojure-lsp/#when-file-opened-use-furthest-project","title":"\"when-file-opened-use-furthest-project\"","text":"

    When set to \"when-file-opened-use-furthest-project\" Calva will attempt to start the clojure-lsp server whenever a Clojure file is opened. The LSP server will be started in the outermost valid Clojure project or will fall back to starting in the workspace root if no valid Clojure project can be found. A directory is considered a Clojure project if it contains typical Clojure project files such as a deps.edn, project.clj, or shadow-cljs.edn file. When working in a mono-repo style project or in a multi-workspace VS Code configuration you may have multiple LSP servers running, one for each independent Clojure project opened.

    Opening files that do not belong to a workspace folder

    When opening files that do not belong to any of the workspace folders currently open then Calva will fallback to starting the fallback clojure-lsp server

    "},{"location":"clojure-lsp/#never","title":"\"never\"","text":"

    When set to \"never\" Calva will never attempt to automatically start the clojure-lsp server. In this case you are responsible for manually starting the server. More advanced users might want to do this in order to have more control over which projects have a clojure-lsp server running for them. To manually start the clojure-lsp server you can run the calva.clojureLsp.start or the calva.clojureLsp.manage command and pick the project root. You can also click the clojure-lsp status bar icon to open the Management Menu.

    Additionally Calva has commands for:

    • Inspecting the clojure-lsp server information
    • Read the clojure-lsp server log
    • Stopping any running clojure-lsp processes
    • Starting clojure-lsp
    • Restarting any running clojure-lsp processes
    • Downloading the configured clojure-lsp version

    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.

    "},{"location":"clojure-lsp/#fallback-server","title":"Fallback Server","text":"

    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).

    "},{"location":"clojure-lsp/#status-bar","title":"Status bar","text":"

    In the status bar Calva will show an indicator with the clojure-lsp status. This status will track the currently open project, showing the status (stopped, starting or active) for the relevant clojure-lsp server.

    You can click on the status-bar item to open the clojure-lsp management menu which will look as follows:

    The menu shows which clojure-lsp servers are active and which are stopped. Selecting a project will allow you to start/stop/restart the server for that project.

    "},{"location":"clojure-lsp/#ignoring-lsp-cache-files","title":"Ignoring LSP cache files","text":"

    Clojure-lsp stores its project analysis information in your project. Git users can add these lines to their project root directory .gitignore:

    .lsp/.cache/\n.lsp/sqlite.*.db\n
    "},{"location":"clojure-lsp/#configuration","title":"Configuration","text":"

    For information about how to configure clojure-lsp, see the settings page of the clojure-lsp docs.

    "},{"location":"clojure-lsp/#changing-the-version-of-clojure-lsp-used-by-calva","title":"Changing the Version of Clojure-lsp Used by Calva","text":"

    By default, Calva will use the latest released clojure-lsp. You can change the version of clojure-lsp used by Calva by setting the calva.clojureLspVersion property to a version of clojure-lsp found in its GitHub releases. This can be helpful if you're debugging an issue with clojure-lsp or you want to try out a feature of a new release that Calva does not yet use. However, you must remember to reset this setting in order for Calva to automatically use newer versions of clojure-lsp that are released with new versions of Calva.

    Example:

    \"calva.clojureLspVersion\": \"2021.04.07-16.34.10\"\n

    Special \u201dversion\u201d values

    Apart from the actual versions you can use two special values for this setting:

    • latest: Will download and use the latest stable build of clojure-lsp, when one becomes available. This is the default
    • nightly: Will always download and use the latest nightly build, whether there is a new version available or not.
    "},{"location":"clojure-lsp/#using-a-custom-clojure-lsp","title":"Using a Custom Clojure-lsp","text":"

    You can set a path to a custom clojure-lsp to be used by Calva by configuring the calva.clojureLspPath setting. This should be an absolute path to a native binary or JAR file.

    Example:

    \"calva.clojureLspPath\": \"/usr/local/bin/clojure-lsp\"\n

    Will override any calva.clojureLspVersion setting

    When calva.clojureLspPath is set, the binary at the path will be used uncoditionally, and the calva.clojureLspVersion setting will be ignored.

    "},{"location":"clojure-lsp/#extra-commands","title":"Extra commands","text":"

    clojure-lsp provides many useful [commands], and Calva has configuration for most of them. The clojure-lsp team works fast and sometimes Calva might miss some command. And Calva's configuration only really work for clojure-lsp commands that take no argument, or where it makes sense to prompt for the argument. Therefore Calva provides a generic command id, clojure-lsp.command which can be used with keyboard shortcuts and that allow for providing arguments that way. (The command can be used from Joyride too, of course.)

    When using the command, provide the args as an tuple of [command-name, arguments], where arguments is an array of any arguments after file-uri, row, col which are common for all clojure-lsp extra commands and are provided automatically by Calva, based on active text editor and where the cursor is. It can look like so when binding a shortcut for extract-function:

        {\n        \"key\": \"ctrl+alt+r f\",\n        \"command\": \"clojure-lsp.command\",\n        \"args\": [\"extract-function\", [\"new-function\"]]\n    },\n

    Note that even though extract-function takes only one argument, you should still provide it via an array.

    "},{"location":"clojure-lsp/#troubleshooting","title":"Troubleshooting","text":""},{"location":"clojure-lsp/#viewing-the-logs-between-the-client-and-server","title":"Viewing the Logs Between the Client and Server","text":"

    If something doesn't seem to be working correctly, and you suspect the issue is related to clojure-lsp, a good place to start investigating is the request and response logs between the LSP client and server. In your settings, set clojure.trace.server to verbose, then in the VS Code output tab, select the Clojure Language Client output channel.

    It may be helpful to clear the output channel, then perform the action with which you're experiencing a problem, then read through the log for clues or paste the logs into a related issue in the Calva repo.

    "},{"location":"clojure-lsp/#server-info-command","title":"Server Info Command","text":"

    You can run the Clojure-lsp Server Info command to get information about the running clojure-lsp server, such as the version the server being used, the version of clj-kondo it's using, and more. This info is printed to the \"Calva says\" output channel.

    "},{"location":"clojure-lsp/#opening-the-server-log-file","title":"Opening the Server Log File","text":"

    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.

    "},{"location":"clojure-lsp/#server-initialization-failed","title":"Server initialization failed","text":"

    If clojure-lsp fails to start with \u201cServer initialization failed\u201d messages, it could be because the path to your project contains non-ASCII characters, or that the system PATH variable has been corrupted. (Or something else, of course.)

    See this issue for some findings about it: Issue #2251: Server initialization failed error

    "},{"location":"clojure-lsp/#related","title":"Related","text":"

    See also:

    • Connecting the REPL
    • Refactoring
    "},{"location":"clojuredart/","title":"Using Calva with ClojureDart","text":"

    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.

    ","boost":4},{"location":"clojuredart/#dart-clojure-conversion","title":"Dart->Clojure Conversion","text":"

    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:

    • DartClojure

    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:

    1. Open a new untitled file/tab
    2. Paste your Dart/Flutter code in this file (VS Code will probably automatically figure out that it is Dart code, even if that doesn't matter for the converter.)
    3. Run Calva: Convert Dart code to Clojure/ClojureDart
    4. An, untitled, Clojure tab will open with the converted code in it.

    NB: The conversion will not always work. DartCLojure is work in progress. See the project repo for limitations and scope. Often when conversion, the error message will give you a clue to what is problematic. Try adjust your code selection and you will probably be able to get at least some help from the converter.

    Speaking of WIP...

    ","boost":4},{"location":"clojuredart/#work-in-progress","title":"Work in Progress","text":"

    ClojureDart is very new and being super actively developed. Some feature are still missing. Like a REPL. Once that is added we will also add ClojureDart jack-in and connect support to Calva.

    ","boost":4},{"location":"clojuredart/#happy-clojuredart-hacking","title":"Happy ClojureDart Hacking!","text":"

    Please feel welcome to the #clojuredart and #calva channel at the Clojurians Slack for questions, suggestions and support.

    ","boost":4},{"location":"clojuredocs/","title":"ClojureDocs integration","text":"

    clojuredocs.org is the goto place #1 for finding out more about Clojure core(-ish) functions, macros, etcetera. It contains the doc strings from the functions and adds crowd sourced examples of usage and see alsos. You can surf for quite long on that site without getting bored. \ud83d\ude04

    You can surf ClojureDocs in Calva

    Calva integrates this information in two ways:

    1. Commands for requesting the ClojureDocs information for a symbol under the cursor:
      • Print clojuredocs.org examples to Rich Comment, default keybinding: ctrl+alt+r d
      • Print clojuredocs.org examples to OutputWindow, ctrl+alt+o d
    2. ClojureDocs information is included in the symbol lookup hovers, where each example has two buttons:
      • To Rich Comment
      • To Output Window

    That means that if you just want to glance at the examples, you look in the hover. And when you want to bring the examples to the REPL to play with them, you can do so very easily.

    ClojureScript support

    ClojureDocs information is available both for Clojure and ClojureScript files. However, clojuredocs.org only keeps info for Clojure. Thus: All information Calva shows about a symbol will be about the Clojure respresentation of that symbol. (The symbol might not even exist in ClojureScript.)

    ","boost":4},{"location":"clojuredocs/#clojuredocs-repl-surfing","title":"ClojureDocs REPL Surfing","text":"

    Since the ClojureDocs information includes see-alsos, you can go for super interactive ClojureDocs surfing right in the file you are editing. Say you have this function:

    (defn trim-text\n  \"Returns text without surrounding whitespace if not empty, otherwise nil\"\n  [text]\n  (let [trimmed-text (clojure.string/trim text)]\n    (when-not (empty? trimmed-text)\n      trimmed-text)))\n

    Then you hover on when-not and scroll down a bit in the hover:

    That first example would be interesting to play with, right? Click To Rich Comment and you will get:

    (defn trim-text\n  \"Returns text without surrounding whitespace if not empty, otherwise nil\"\n  [text]\n  (let [trimmed-text (clojure.string/trim text)]\n    (when-not (empty? trimmed-text)\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

    There you can evaluate the (map ...) form using alt+enter, modify it and evaluate again. You can also hover over map, iterate, or any of the \u201dSee also:\u201d symbols to find more fun examples to play with. And so on and so forth.

    See these two tweets for some videos of early versions of this functionality:

    • Rich Comments surfing ClojureDocs Examples
    • Clojuredocs in #Calva WIP 2: Hover examples -> RFC

    Please retweet!

    ","boost":4},{"location":"clojuredocs/#quirks","title":"Quirks","text":"

    Some of the ClojureDocs entries have text that is not really Clojure code, and sometimes even structural errors. This can break the structural integrity of your Clojure file. If you run into trouble trying to heal things, you can always use Undo until the Rich Comment is gone.

    ","boost":4},{"location":"commands-top10/","title":"The Top 10 Calva Commands","text":"

    There are not all that many Calva commands. You can learn them all if you like, but here are the most important ones to know about for effective Clojure/ClojureScript coding:

    • Grow/expand selection: ctrl+w (shift+alt+right on Windows and Linux)
    • Load/Evaluate Current File and its Requires/Dependencies: alt+ctrl+c enter, evaluates the namespace code in the active editor tab. This also loads any required namespaces, and generally gives Calva what it needs to work.
    • Evaluate current form: ctrl+enter finds the form from the cursor position, evaluates it and displays the result inline. Hit esc to dismiss the results display.
    • Evaluate current top-level form: alt+enter: inline evaluate the current top-level form. This also works inside (comment) forms. Use it to (re)define vars and then inside comment forms you can verify that they do what you want them to do.
    • Dismiss the display of results: escape: (VIM Extension users should read Using Calva with the VIM Extension).

    There are also two commands for bringing over the current form and the current top level form over to the repl window:

    • ctrl+alt+c ctrl+alt+e (ctrl+alt+c ctrl+alt+v on Windows): to paste the current form in the REPL window.
    • ctrl+alt+c ctrl+alt+space: to paste the current top-level form in this window

    You can also switch the name space of the output/repl window to that of the current file: alt+ctrl+c alt+n

    • Toggle pretty printing of results on and off: ctrl+alt+c p. It's on by default. There is a status bar button showing the status and that also can be used to toggle the setting.
    "},{"location":"commands-top10/#some-more-commands-to-try","title":"Some More Commands to Try","text":"
    • Code evaluation
      • Evaluate code and add as comment: ctrl+alt+c c (current form), ctrl+alt+c ctrl+space (current top level form)
      • Evaluate code and replace it in the editor, inline: ctrl+alt+c r
    • Integrated REPLs
      • Send current editor form to the REPL window: ctrl+alt+c ctrl+alt+e (ctrl+alt+c ctrl+alt+v on Windows)
      • Send current editor top level form to the REPL window: ctrl+alt+c ctrl+alt+space
    • Run tests and mark failures and errors in the Problems pane
      • Run namespace tests: ctrl+alt+c t
      • Run all tests: ctrl+alt+c shift+t
      • Run current test: ctrl+alt+c ctrl+alt+t
      • Rerun previously failing tests: ctrl+alt+c ctrl+t
      • Caveat: Right now the tests are reported only when all are run, making it painful to run all tests in larger projects. I'll fix it. Promise!
    • Select current form: ctrl+alt+c s.
    • Run custom commands, i.e. code snippets, at will: ctrl+alt+c .

    See also:

    • Code Evaluation Tips
    • Finding Calva Commands and Shortcuts
    "},{"location":"connect-sequences/","title":"REPL Jack-in and Connect Sequences","text":"

    Many projects grow out of the template phase and call for custom developer workflows involving application start commands, customized REPLs, and what have you. Even some templates add this kind of complexity. To make Jack-in usable for a broader set of projects, Calva has a setting keyed calva.replConnectSequences which lets you configure one ore more connect sequences.

    NB: Connect sequence configuration affects Calva's Jack-in menu in the following ways:

    1. With no sequence configured, Calva will prompt for the built-in sequences it has that seems to match your project.
    2. When any number of connection sequences are configured, Calva will prompt for your custom sequences, as well as the built-in sequences. Whether built-in or custom, only sequences relevant to your project will be included in the prompt.
    ","boost":6},{"location":"connect-sequences/#settings-for-adding-custom-sequences","title":"Settings for adding Custom Sequences","text":"

    A connect sequence configures the following:

    • name: (required) This will show up in the Jack-in quick-pick menu when you start Jack-in (see above).
    • projectType: (required) This is either \"Leiningen\u201d, \"deps.edn\", \"shadow-cljs\", \"lein-shadow\", \"Gradle\", \u201dgeneric\u201d, or \"custom\".
    • autoSelectForJackIn: A boolean. If true, this sequence will be automatically selected at Jack-in, suppressing the Project Type. Use together with projectRootPath to also suppress the Project Root menu. Add usage of menuSelections to go for a prompt-less REPL Jack-in. If you have more than one sequence with autoSelectForJackIn set to true, the first one will be used.
    • autoSelectForConnect: A boolean. If true, this sequence will be automatically selected at Connect, suppressing the Project Type menu. Use together with projectRootPath to also suppress the Project Root menu. If you have more than one sequence with autoSelectForConnect set to true, the first one will be used.
    • projectRootPath: An array of path segments leading to the root of the project to which this connect sequence corresponds. Use together with autoSelectForJackIn/autoSelectForConnect to suppress the Project Root menu. The path can be absolute or relative to the workspace root. If there are several Workspace Folders, the workspace root is the path of the first folder, so relative paths will only work for this first folder.
    • nReplPortFile: An array of path segments with the project root-relative path to the nREPL port file for this connect sequence. E.g. For shadow-cljs this would be [\".shadow-cljs\", \"nrepl.port\"].
    • afterCLJReplJackInCode: Code to evaluate in the CLJ REPL once it has been created. You can use either a string or an array of strings. If you use an array, the strings will be joined with a newline character to form the resulting code.
    • customJackInCommandLine: A string with a command line that should be used to launch the REPL. See Custom Command Line, below.
    • cljsType: This can be either \"Figwheel Main\", \"shadow-cljs\", \"ClojureScript built-in for browser\", \"ClojureScript built-in for node\", \"lein-figwheel\", \"none\", or a dictionary configuring a custom type. If set to \"none\", Calva will skip connecting a ClojureScript repl. A custom type has the following fields:
      • dependsOn: (required) Calva will use this to determine which dependencies it will add when starting the project (Jacking in). This can be either \"Figwheel Main\", \"shadow-cljs\", \"ClojureScript built-in for browser\", \"ClojureScript built-in for node\", \"lein-figwheel\", or \u201dUser provided\u201d. If it is \"User provided\", then you need to provide the dependencies in the project or launch with an alias (deps.edn), profile (Leiningen), or build (shadow-cljs) that provides the dependencies needed.
      • isStarted: Boolean. For CLJS REPLs that Calva does not need to start, set this to true. (If you base your custom cljs repl on a shadow-cljs workflow, for instance.)
      • startCode: Clojure code to be evaluated to create and/or start your custom CLJS REPL.
      • isReadyToStartRegExp: A regular expression which, when matched in the stdout from the startCode evaluation, will make Calva continue with connecting the REPL, and to prompt the user to start the application. If omitted and there is startCode Calva will continue when that code is evaluated.
      • openUrlRegExp: A regular expression, matched against the stdout of cljsType evaluations, for extracting the URL with which the app can be started. The expression should have a capturing group named url. E.g. \"Open URL: (?\\<url>S+)\"
      • shouldOpenUrl: Choose if Calva should automatically open the URL for you or not.
      • connectCode: (required) Clojure code to be evaluated to convert the REPL to a CLJS REPL that Calva can use to connect to the application. (For some setups this could also conditionally start the CLJS REPL. If so: startCode should be omitted.)
      • isConnectedRegExp: (required) A regular expression which, when matched in the stdout from the connectCode evaluation, will tell Calva that the application is connected. The default is To quit, type: :cljs/quit and you should leave it at that unless you know it won't work.
      • printThisLineRegExp: regular expression which, when matched in the stdout from any code evaluations in the cljsType, will make the matched text be printed to the Output window.
      • buildsRequired: Boolean. If the repl type requires that builds are started in order to connect to them, set this to true.
    • menuSelections: a dictionary with pre-filled-in selections for the Jack-in and Connect prompts, making Calva not prompt for that particular selection:
      • leinProfiles: At Jack-in to a Leiningen project, use these profiles to launch the repl.
      • leinAlias: At Jack-in to a Leiningen project, launch with this alias. Set to null to launch with Calva's default task (a headless repl), w/o prompting.
      • cljAliases: At Jack-in to a deps.edn project, use these aliases to launch the repl.
      • cljsLaunchBuilds: The cljs builds to start/watch at Jack-in/connect.
      • cljsDefaultBuild: Which cljs build to attach to at the initial connect.
    • jackInEnv: An object with environment variables that will be merged with the global calva.jackInEnv and then applied to the Jack-in process. The merge is very similar to how Clojure's merge works. So for any common keys between the global setting and this one, the ones from this setting will win.

    The Calva built-in sequences also use this format, check them out to get a clearer picture of how these settings work.

    Force the project type menu to show

    The convenience of autoSelectForJackIn/Connect can be an inconvenience when you want to use another project type/sequence for a project. For this reason, the calva.connect and calva.jackIn can be provided with an option disableAutoSelect, which forces the project root and project type menus to show. See Options for the Connect Command and Options for the Jack-in Command for more on this.

    Path segments

    projectRootPath and nReplPortFile both take an array of path segments. This is to make the paths work cross-platform. If you can't be bothered splitting up the path in segments, put the whole path in the first segment, though please note that if you use Windows path separators, these will not work for users with Linux or macOS.

    ","boost":6},{"location":"connect-sequences/#custom-command-line","title":"Custom Command Line","text":"

    Custom command lines are there to bridge the gap to those situations where standard Jack-in command lines don't reach. Like:

    1. You want to provide command line options to a supported tool, which Jack-in does not provide
    2. Your project has some script through which it is started
    3. The REPL is provided by some tool that Calva does not know of
    4. Any other reason...

    A custom command line is executed from same directory as the REPL project root (See projectRootPath, above), and can be as simple as my-repl-jack-in-command. You can use a relative or absolute path to your command line.

    If your custom command line starts a REPL of a project type that is not \u201dknown\u201d/built-in to Calva, use custom as the projectType for the connect sequence.

    ","boost":6},{"location":"connect-sequences/#custom-command-line-substitutionsplaceholdersenvironment-variables","title":"Custom Command Line Substitutions/Placeholders/Environment variables","text":"

    You can use placeholders in your command line, and Calva will substitute them before executing the command. All these placeholders will also be provided to your script via environment variables with the same names (except dashes will be underscores in the env variable names):

    nREPL dependency versions:

    • JACK-IN-NREPL-VERSION
    • JACK-IN-CIDER-NREPL-VERSION
    • JACK-IN-CIDER-PIGGIEBACK-VERSION

    Paths:

    • JACK-IN-PROJECT-ROOT-PATH: (See projectRootPath, above)
    • JACK-IN-NREPL-PORT-FILE: The path of the nREPL port file (see nReplPortFile above)

    Depending on the project type Calva will also look for these placeholders:

    • JACK-IN-CLJ-MIDDLEWARE: The nREPL middleware to be used for the Clojure REPL
    • JACK-IN-CLJS-MIDDLEWARE: The nREPL middleware to be used for the ClojureScript REPL
    • JACK-IN-LEIN-PROFILES: For Leiningen projects, the profiles selected by the user
    • JACK-IN-LEIN-LAUNCH-ALIAS: For Leiningen projects, the launch alias selected by the user
    • JACK-IN-CLI-ALIASES: For deps.edn projects, the aliases selected by the user
    • JACK-IN-CLJS-LAUNCH-BUILDS: For ClojureScript REPLs that configures builds, the builds selected by the user
    • JACK-IN-NREPL-PORT: For some project types (currently nbb and Babashka) Calva provided the TCP port they should use.
    ","boost":6},{"location":"connect-sequences/#example-custom-jack-in-command-lines","title":"Example Custom Jack-in Command lines","text":"","boost":6},{"location":"connect-sequences/#start-a-babashka-repl-via-wsl","title":"Start a Babashka REPL via WSL","text":"

    Calva has a built-in jack-in sequence for starting a Babashka REPL and connect to it. It works as long as the bb process is on the same host as VS Code/Calva is running. So if you want it to run in WSL, but VS Code is running on your computer you need to start bb slightly differently. These settings in your VS Code settings file will give you a jack-in option that works for this:

      \"calva.replConnectSequences\": [\n    {\n        \"name\": \"Bashbabka (WSL)\",\n        \"projectType\": \"custom\",\n        \"customJackInCommandLine\": \"bash -c 'bb --nrepl-server JACK-IN-NREPL-PORT'\",\n    },\n  ],\n

    If you place it in your user settings you will have access to it from any workspace.

    ","boost":6},{"location":"connect-sequences/#an-exampleskeleton-script","title":"An example/skeleton script","text":"

    This script doesn't actually start a REPL, it's provided more for giving you an idea about what it could look like, and as a starting point for your real scripts:

    #!/usr/bin/env bb\n\n(require '[clojure.string :as str])\n\n(defn parse-args [args]\n  (loop [args args\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

    It's written in Babashka to encourage you to write your shell scripts in a civilized language. \ud83d\ude00 See the article Changing my mind: Converting a script from bash to Babashka for a small success-story about this mindset. See also bash2bb.

    The script reads JACK-IN-CLJS-LAUNCH-BUILDS and JACK-IN-CIDER-NREPL-VERSION from the command line, and JACK_IN_PROJECT_ROOT_PATH from the environment. It could be configured for use in a custom connect sequence like this:

        \"customJackInCommandLine\": \"../../custom-jack-in.bb --aliases JACK-IN-CLJS-LAUNCH-BUILDS --cider-nrepl-version JACK-IN-CIDER-NREPL-VERSION\",\n

    Note how in this case the REPL is started two directories \u201ddown\u201d from the workspace root where the script resides.

    ","boost":6},{"location":"connect-sequences/#example-sequences","title":"Example Sequences","text":"

    Whether you just want to speed up your workflow or encode some workflow/mechanics into it, it's often the case that you can create a custom sequence that helps.

    ","boost":6},{"location":"connect-sequences/#minimal-menus-with-full-stack-shadow-cljs-repls","title":"Minimal menus with full stack shadow-cljs REPLs","text":"

    Minimize the amount of selecting from the Jack-in/Connect menu when working with a full-stack shadow-cljs + deps/lein project:

        {\n      \"name\": \"backend + frontend\",\n      \"projectType\": \"shadow-cljs\",\n      \"cljsType\": \"shadow-cljs\",\n      \"menuSelections\": {\n        \"cljsLaunchBuilds\": [\n          \":app\",\n          \":test\",\n        ],\n        \"cljsDefaultBuild\": \":app\"\n      }\n    }\n

    See shadow-cljs + Clojure with Calva: The basics for how Calva and nREPL work with ClojureScript.

    ","boost":6},{"location":"connect-sequences/#polylith","title":"Polylith","text":"

    This is the connect sequences used in the Polylith Real World App. The (start) sequence lets you jack-in to the project, and starts the Real World App without any prompts. The (connect) sequence can be used if you prefer to start the REPL manually, and want to connect without prompts.

        \"calva.replConnectSequences\": [\n        {\n            \"projectType\": \"deps.edn\",\n            \"afterCLJReplJackInCode\": \"(require '[dev.server] :reload) (in-ns 'dev.server) (start! 6003)\",\n            \"name\": \"Polylith RealWorld Server REPL (start)\",\n            \"autoSelectForJackIn\": true,\n            \"projectRootPath\": [\".\"],\n            \"cljsType\": \"none\",\n            \"menuSelections\": {\n                \"cljAliases\": [\"dev\", \"test\"]\n            }\n        },\n        {\n            \"projectType\": \"deps.edn\",\n            \"name\": \"Polylith RealWorld Server REPL (connect)\",\n            \"autoSelectForConnect\": true,\n            \"projectRootPath\": [\".\"],\n            \"cljsType\": \"none\",\n        }\n    ],\n    \"calva.autoConnectRepl\": true,\n

    The calva.autoConnectRepl, when set to true, makes Calva, at project open, look for the nRepl port file and automatically connect the repl if the file exists. Therefore, you can leave the app running when you close the project in VS Code, and Calva will reconnect when you open the project again. (Alternatively, maybe you just need to reload the VS Code window and not lose the REPL state.)

    ","boost":6},{"location":"connect-sequences/#minimal-menus-with-full-stack-depsedn-and-figwheel-main-repls","title":"Minimal menus with full stack deps.edn and Figwheel Main REPLs","text":"

    Setting for a full-stack application. It starts the backend server when the CLJ REPL has started. Then proceeds to create a custom CLJS REPL (calling in to the application code for this). And then connects to it.

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Example Sequence\",\n            \"projectType\": \"Clojure-CLI\",\n            \"afterCLJReplJackInCode\": \"(go)\",\n            \"cljsType\": {\n                \"startCode\": \"(do (require '[cljs-test.main :refer :all])(start-nrepl+fig))\",\n                \"isReadyToStartRegExp\": \"Prompt will show\",\n                \"connectCode\": \"(do (use 'cljs-test.main) (cljs-repl))\",\n                \"isConnectedRegExp\": \"To quit, type: :cljs/quit\",\n                \"printThisLineRegExp\": \"\\\\[Figwheel\\\\] Starting Server at.*\"\n            }\n        }\n    ]\n}\n
    ","boost":6},{"location":"connect-sequences/#juxt-edge","title":"JUXT Edge","text":"

    Here is an example from the JUXT Edge project template. It adds two sequences, one for when only the Clojure REPL should be launched and one for when the customized Edge cljs repl should also be connected. The Edge backend + frontend sequence specifies that the web app should be opened by Calva, making cljs repl connection more stable, and also adds menuSelections to skip the launch aliases prompt.

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Edge backend only\",\n            \"projectType\": \"deps.edn\"\n        },\n        {\n            \"name\": \"Edge backend + frontend\",\n            \"projectType\": \"deps.edn\",\n            \"cljsType\": {\n                \"dependsOn\": \"Figwheel Main\",\n                \"startCode\": \"(do (require 'dev-extras) (dev-extras/go) (println \\\"Edge Figwheel Main started\\\") ((resolve 'dev-extras/cljs-repl)))\",\n                \"isReadyToStartRegExp\": \"Edge Figwheel Main started\",\n                \"openUrlRegExp\": \"Website listening on: (?<url>\\\\S+)\",\n                \"printThisLineRegExp\": \"\\\\[Edge\\\\]\",\n                \"shouldOpenUrl\": true,\n                \"connectCode\": \"(do (require 'dev-extras) ((resolve 'dev-extras/cljs-repl)))\",\n                \"isConnectedRegExp\": \"To quit, type: :cljs/quit\",\n                \"buildsRequired\": false\n            },\n            \"menuSelections\": {\n                \"cljAliases\": [\n                    \"dev\",\n                    \"build\",\n                    \"dev/build\"\n                ],\n            }\n        }\n    ]\n}\n
    ","boost":6},{"location":"connect-sequences/#plain-depsedn","title":"Plain deps.edn","text":"

    A deps.edn sequence that does not promote the ClojureScript repl at all (leaving it a Clojure REPL), and leaves that up to you to do interactively. (Could be useful while you are developing a custom cljs repl.) The example is for when adapting a Figwheel Main repl.

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Do not promote to cljs\",\n            \"projectType\": \"deps.edn\",\n            \"cljsType\": {\n                \"dependsOn\": \"Figwheel Main\",\n                \"connectCode\": \"\\\"Don't promote me bro!\\\"\",\n                \"isConnectedRegExp\": \"Don't promote me bro!\"\n            }\n        }\n    ]\n}\n
    ","boost":6},{"location":"connect/","title":"Connect Calva to Your Project","text":"

    When connected to your project's REPL Calva lets you evaluate code, supporting Interactive Programming. The REPL connection is also used to provide IDE functionality through the dynamic knowledge about the project that the REPL enables. The REPL communication depends on that your project has an nREPL server running, and that the cider-nrepl middleware is enabled.

    For the easiest way to provide your project with these dependencies, the recommended way to connect is to use the so called Jack-in command.

    ","boost":7},{"location":"connect/#jack-in-let-calva-start-the-repl-for-you","title":"Jack-in: Let Calva Start the REPL For You","text":"

    This way Calva can make sure it is started with the dependencies needed for a working Clojure and/or ClojureScript session. This is often referred to as Jack in (because that is what it is called in CIDER).

    Jack-in supports both CLJ and for CLJS, and has built-in configurations for Leiningen, deps.edn, shadow-cljs, Gradle projects, as well as for the CLJS repl types: Figwheel Main, lein-figwheel (legacy Figwheel), shadow-cljs, and ClojureScript built-ins for both browser and node.js. Using jack-in provides your development environment with all the dependencies you need for Calva to work.

    It works like so:

    1. Open your project in VS Code.
    2. Issue the command Start a Project REPL and Connect: ctrl+alt+c ctrl+alt+j.
    3. Answer the quick-pick prompts telling Calva about project types and what profiles to start. (See the Jack-in Project Types and Profiles wiki page for more info if needed.)

    See also: Workspace Layouts

    About project roots

    You must have a project file, such as project.clj for Leiningen, or deps.edn for deps.edn, or shadow-cljs.edn for shadow-cljs, or settings.gradle/settings.gradle.kts for Gradle in the directory opened in VS Code in order for jack-in to work. If, after adding the project file, you experience an error during jack-in that says something could not be located, make sure you have the correct dependencies in your project file. For example, when using the Figwheel Main project type, you should have com.bhauman/figwheel-main in your project dependencies.

    See also below, regarding multiple projects in a workspace

    ","boost":7},{"location":"connect/#aliases-profiles-builds","title":"Aliases, Profiles, Builds","text":"

    When Jack-in starts it will depend on the project type, and whether ClojureScript is involved or not, and if it is, what kind of ClojureScript project, what will happen next. Calva will analyze the project files and will then give you prompts with selections based on what is found there.

    You will need some basic knowledge about the project and the project type terminologies to answer the prompts.

    There are ways to tell Calva the answers to these prompts beforehand, so that Jack-in can be a zero-prompting command. Read on.

    ","boost":7},{"location":"connect/#customizing-jack-in","title":"Customizing Jack-in","text":"

    The main mechanism for customizing your Jack-in, including automating menu selections, and custom CLJS REPL types is Custom Connect Sequences. See also Customizing Jack-in and Connect

    ","boost":7},{"location":"connect/#connecting-without-jack-in","title":"Connecting Without Jack-in","text":"

    If, for whatever reasons, you can't use Jack-in with your project (possibly because the REPL is started as part of some other job) all is not lost. Old fashioned Connect to a running REPL is still there for you. For all features to work in Calva while connecting to a running REPL, your environment needs to have REPL related dependencies set up.

    However, just as before it can be tricky to get the dependencies right. Consider using Jack in to inform yourself on how to start your REPL to Calva's satisfaction. When you use Jack in, Calva starts a VS Code task for it and the command line used is displayed in the terminal pane used to handle the task. Reading that command line tells you what dependencies are needed for your project.

    Even better: Copying that command line gives you the command to start the REPL with the correct dependencies.

    All this said, I still recommend you challenge the conclusion that you can't use Jack-in.

    Copy the Jack-in command line

    There is a Calva command for copying the Jack-in command line to the clipboard. It will copy the command line including commands to change to the current REPL project root, avoiding hard-to-detect errors when starting the REPL in the wrong directory.

    The Generic Project Type

    A reason to use the connect to a running REPL way, can be that Calva does not have a built in connect sequence/project type for the particular REPL you want to connect to. Maybe it is something like Lingy which doesn't yet have a built in Calva connect sequence. As long as there is an nREPL server to connect to, you can Connect with Calva, using the Generic connect sequence/project type. (You can also create a connect sequence with a custom command line, and use Jack-in anyway.)

    See also Customizing Jack-in and Connect

    ","boost":7},{"location":"connect/#starting-the-repl-from-application-code","title":"Starting the REPL from application code?","text":"

    If your project is setup so that the REPL server is started by the application code, you will need to get the cider-nrepl middleware in place. See the cider-nrepl docs about embedding nREPL in your application.

    ","boost":7},{"location":"connect/#auto-select-project-type-and-project-root","title":"Auto-select Project Type and Project Root","text":"

    You can make both Jack-in and Connect stop prompting you for project type and project root path in projects where you always want to use the same. See Connect Sequences.

    ","boost":7},{"location":"connect/#monorepos-multiple-clojure-projects-in-one-workspace","title":"Monorepos / multiple Clojure projects in one workspace","text":"

    If the workspace is a monorepo, Polylith repo or just a repository with more than one Clojure project, Calva will start the connect sequence with prompting for which project to start/connect to.

    ","boost":7},{"location":"connect/#shadow-cljs","title":"shadow-cljs","text":"

    Please see the shadow-cljs page.

    ","boost":7},{"location":"connect/#troubleshooting","title":"Troubleshooting","text":"","boost":7},{"location":"connect/#jack-in-and-main-opts","title":"Jack-in and :main-opts","text":"

    When Calva starts the project REPL and connects to it (a.k.a. Jack-in), this is done by starting an nREPL server. For deps.edn projects this by default means that Calva will add -m ... with options that starts the server.

    However: If you choose an alias at Jack-in that specifies :main-opts, it will make the Clojure CLI to add main opts and Calva will then not override these by adding -m ... to the command line. This means that an alias that specify :main-opts must result in an nREPL server being started, or else Calva won't have a server to connect to. Calva won't further analyze this, but will just warn you at Jack-in.

    If you don't know if an alias starts an nREPL server or not, by all means, try it, if you have reasons for using that alias. You will notice if Jack-in works or not. If it doesn't work, you will need to run without that alias, or fix what happens when that alias is used so that an nREPL server is started. See https://nrepl.org/nrepl/usage/server.html about ways to do this.

    ","boost":7},{"location":"connect/#command-not-found-errors-when-jacking-in","title":"Command Not Found Errors When Jacking In","text":"

    If you get command not found error when Calva tries to start your project, and you know you have the command installed, it's probably because VS Code starts from an environment where the command is not on the $PATH. It can look like so:

    lein update-in :dependencies conj '[nrepl,\"0.8.3\"]' -- update-in :plugins conj '[cider/cider-nrepl,\"0.25.8\"]' -- update-in '[:repl-options,:nrepl-middleware]' conj '[\"cider.nrepl/cider-middleware\"]' -- repl :headless\n/bin/sh: lein: command not found\nJack-in process exited. Status: 127\n

    The fix is to always start VS Code from the command line:

    $ code\n

    You might need to first run the Shell Command: Install code command in PATH.

    This will also make sure your REPL has access to the environment you probably expect it to have access to. See below.

    ","boost":7},{"location":"connect/#go-to-definition-not-working-for-java-definitions","title":"Go to Definition Not Working for Java Definitions","text":"

    On some systems, the Java source may not be installed along with the JDK. The source must be present on your system in order to navigate to Java definitions. See this comment for more details.

    ","boost":7},{"location":"connect/#environment-variables-are-not-readable-from-repl","title":"Environment Variables Are Not Readable From REPL","text":"

    If you've added environment variables in your OS, such as in your ~/.bashrc file (Linux), in order for them to be read in a REPL created by Calva's jackin command, VS Code must be started from a shell where the environment variables are defined. For example, if you can open a bash terminal and run echo $SOME_VAR and see the value there, then open VS Code from that terminal with code <project path>.

    ","boost":7},{"location":"connect/#viewing-the-communication-between-nrepl-and-calva","title":"Viewing the Communication Between nREPL and Calva","text":"

    It may be helpful to view the messages sent between nREPL and Calva when troubleshooting an issue related to the REPL. See how to do that here.

    ","boost":7},{"location":"contribute/","title":"Contribute to Calva","text":"

    There are many ways to contribute:

    • Become a sponsor
    • Give us feedback:
    • File issues
    • Talk to us via the #calva channel at the Clojurians Slack (use the latter link to grab an invite)
    • Provide PRs, see the Calva wiki about How to Hack on Calva
    • Give us feedback, preferably via that #calva channel
    • Cheer us on. (Same channel)
    • Help us test things like reported issues, new features, etcetera. See Testing VSIX Packages and Smoke Testing
    • Make tutorials, write blog articles, spread the word
    • Star the Calva repository
    • Help us help beginners with Calva and Clojure, on Slack as well as IRL and wherever.

    Be creative!

    "},{"location":"contribute/#please-star-the-calva-repo","title":"Please star the Calva repo!","text":"

    Happy Coding! \u2764\ufe0f

    "},{"location":"custom-commands/","title":"Custom REPL Commands","text":"

    Calva supports configuration of custom command snippets that you can evaluate in the REPL at will. This is useful if your workflow has you repeatedly evaluating a particular piece of code. There are two ways to use these:

    1. You can use the setting calva.customREPLCommandSnippets to configure it. Then either bind keyboard shortcuts to them or use the command Run Custom REPL Command to access it. The command will give you a menu with the snippets you have configured.
    2. You can bind a keyboard shortcut directly to a custom command snippet by inlining it in the shortcut definition. See Binding Keyboard Shortcuts

    Joyride

    For some use cases you might be better served by/want to combine these with using the VS Code Extension API, and that of Calva, or any other extension, through Joyride.

    The calva.customREPLCommandSnippets is an array of objects with the following fields (required fields in bold):

    • name: The name of the snippet as it will appear in the picker menu
    • snippet: The code that will be evaluated
    • key: A key can be used to reference the snippet from Run Custom REPL Command keyboard shortcut arguments. It will also be used in the quick-pick menu.
    • ns: A namespace to evaluate the command in. If omitted the command will be executed in the namespace of the current editor.
    • repl: Which repl session to use for the evaluation. Either \"clj\" or \"cljs\". Omit if you want to use the session of the current editor.
    • evaluationSendCodeToOutputWindow: (default true) Whether the evaluated code should be echoed to the Output/REPL window.

    There are also substitutions available, which will take elements from the current state of Calva and splice them in to the text of your command before executing it. They are

    • $line: Current line number in editor
    • $column: Current column number in editor
    • $file: Full name of the current file edited
    • $file-text: The text of the current file edited
    • $ns: The namespace used for evaluating the command
    • $editor-ns: The namespace of the editor from which the command was run
    • $selection: The currently selected text
    • $current-form: The text of the current form
    • $current-pair: The text of the current pair if in a binding, otherwise empty string
    • $enclosing-form: The text of the current enclosing form
    • $top-level-form The text of the current top level form
    • $current-fn: The sexpr/form at call position in the current list, e.g. str with (defn foo [] (str \"foo\" \"bar|\"))
    • $top-level-defined-symbol: The second symbol of the top level form, e.g. foo with (defn foo [] (str \"foo\" \"bar|\"))
    • $head: The text between the start of the current list to the cursor
    • $tail: The text between the cursor and the end of the current list
    ","boost":4},{"location":"custom-commands/#user-and-workspace-settings","title":"User and Workspace Settings","text":"

    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.)

    ","boost":4},{"location":"custom-commands/#binding-keyboard-shortcuts","title":"Binding Keyboard Shortcuts","text":"

    There are four ways to bind shortcuts to custom commands:

    1. Use a predefined key shortcut. These are predefined as ctrl+alt+space <something>, where <something> is one of:
      • The digits 0 through 9
      • The English letters a through z
      • Arrow keys right, left, up, or down
      • One of tab, backspace, ,, ., or -
    2. Bind calva.runCustomREPLCommand to a shortcut with whatever code you want to evaluate in the args slot. You have access to the substitution variables here as well.
    3. Bind calva.runCustomREPLCommand to a keyboard shortcut referencing the key of one of your calva.customREPLCommandSnippets. (If not using any of the keys mentioned in 1.)
    4. Bind calva.runCustomREPLCommand to a shortcut with a customREPLCommandSnippets in the args slot. You have access to the substitution variables here as well.

    Here's an example shortcut entry for the 4th option:

        {\n        \"key\": \"ctrl+cmd+u alt+enter\",\n        \"command\": \"calva.runCustomREPLCommand\",\n        \"args\": {\n            \"ns\": \"user\",\n            \"snippet\": \"$current-form\",\n        }\n    },\n

    This would evaluate the current form in the user namespace. Please note that this Custom REPL Command will not show up in the custom commands menu mentioned above.

    ","boost":4},{"location":"custom-commands/#custom-repl-hover-snippets","title":"Custom REPL Hover Snippets","text":"

    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.

    ","boost":4},{"location":"custom-commands/#configedn","title":"config.edn","text":"

    :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:

    1. None of these two configs get synced through VS Code Settings Sync.
    2. Changes to workspace .calva/config.edn will be automatically noticed by Calva, and refresh the config. This will not happen with the user config file.
    3. Internally in Calva, the settings are keyed on the snippet :name entry, and if you change the name, the old entry won't be removed until the VS Code window is reloaded.

    As for 2.: There is a command Calva: Refresh REPL snippets from User config.edn.

    There is also a command to open the User config.edn, for convenience: Calva: Open REPL snippets User config.edn. This command creates the file if it doesn't previously exist.

    ","boost":4},{"location":"custom-commands/#snippets-inside-deps","title":"Snippets Inside Deps","text":"

    A new experimental feature lets library authors ship snippets inside their jar files. These accept the same options as above but should be placed in \"resources/calva.exports/config.edn\" inside the jar.

    {:customREPLCommandSnippets\n [{:name \"edn test\"\n   :key \"a\"\n   :snippet ($current-form)}]\n :customREPLHoverSnippets\n [{:name \"edn hover\"\n   :snippet (str \"$hover-tex\")}\n  {:name \"edn hover show val\"\n   :snippet (str \"### EDN show val\\n```clojure\\n\" (pr-str (eval (symbol (str \"$ns\" \"/\" \"$hover-top-level-defined-symbol\")))) \"\\n```\")}]}\n
    ","boost":4},{"location":"customizing-jack-in-and-connect/","title":"Customize Jack-in and Connect","text":"

    Since Jack-in and connect both are about connecting the REPL, and only differ in how the REPL is started, many settings and configuration points are shared between the two concepts. A major customization point is Custom Connect Sequences, which are relevant for both Jack-in and Standalone Connect scenarios.

    This page lists some more Jack-in and Connect configuration options.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#auto-evaluate-code-on-connect","title":"Auto-evaluate Code on Connect","text":"

    You can have Calva evaluate code whenever a REPL has been connected via the calva.autoEvaluateCode.onConnect setting. It has two entries clj and cljs:

    • clj: \"Code to evaluate when the Clojure REPL has been connected.
      • The default is code that refer in the repl-requires/REPL utilities (like source, doc, etcetera). (Note that there is also a command to do this on demand.).
      • Overriding the default replaces it. If you want to add code to be evaluated on connect this way, and keep the behaviour of auto-refering REPL utilities, you need to provide code for the latter (copy/pasting the default code will do). See also note below about concatenation of configurations.
      • The code will be evaluated before the afterCLJReplJackInCode in any connect sequence used.
    • cljs: Code to evaluate when the ClojureScript REPL has been connected.
      • The default is code that refer in the repl-requires/REPL utilities (like source, doc, etcetera). (Note that there is also a command to do this on demand.).
      • Same deal with overriding the default as with clj.

    Set either of these to null to disable the feature for that REPL type. (The Settings linter will complain, but it works.)

    For Clojure this is in addition to afterCLJReplJackInCode

    There are two mechanisms for evaluating code when a Clojure REPL is connected. The afterCLJReplJackInCode setting of custom connect sequences, and this calva.autoEvaluateCode.onConnect.clj setting. There is no fundamental difference between them. This one has a default function of auto-refering in the Clojure REPL utilities. And it will be run before the connect sequence after-Jack-in code.

    All configured code is concatenated

    If you configure this both in User/global settings and in a Workspace, the workspace configured code will be concatenated on the user level code. Meaning both code snippets will be evaluated, first the User level code, then the Workspace level code. Also null disables the feature:

    • If you use null in the User level code, you will disable the onConnect code evaluation for all workspaces that do not configure code for this.
    • If you configure code on the User level it will be evaluated in all workspaces, except those that disable the feature by configuring null.
    ","boost":7},{"location":"customizing-jack-in-and-connect/#auto-evaluate-code-at-filenamespace-loadevaluation","title":"Auto-evaluate Code at file/namespace load/evaluation","text":"

    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.

    • Note that custom commands substitutions are in play here as well.
    • Calva's does not provide defaults for this setting.
    • Merging works the same as with onConnect.
    ","boost":7},{"location":"customizing-jack-in-and-connect/#customizing-connect","title":"Customizing Connect","text":"

    If there is an nRepl port file, Calva will use it and not prompt for host:port when connecting. You can make Calva prompt for this by setting the boolean config calva.autoSelectNReplPortFromPortFile to false.

    With the setting calva.autoConnectRepl you can make Calva automatically connect the REPL if there is an nRepl port file present when the project is opened.

    With this and the below mentioned auto-select options you can make connect a prompt-less experience. See: Connect Sequences.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#options-for-the-connect-command","title":"Options for the Connect Command","text":"

    The calva.connect command takes an optional options argument defined like so:

      options?: {\n    host?: string;\n    port?: string;\n    connectSequence?: string | ReplConnectSequence;\n    disableAutoSelect?: boolean;\n  }\n

    Where ReplConnectSequence is a Connect Sequences. If you provide a string it needs to match against a built-in or custom connect sequence. With disableAutoSelect you can force the connect menus to be provided even if a custom connect sequence is set to be autoSelected.

    You can provide these options from keyboard shortcuts or from Joyride scripts.

    Here's a keyboard shortcut for connecting to a running REPL bypassing any connect sequence with autoSelectForConnect.

        {\n        \"command\": \"calva.connect\",\n        \"args\": {\"disableAutoSelect\": true},\n        \"key\": \"ctrl+alt+c shift+c\",\n    },\n

    A Joyride command for connecting to a REPL on port 55555, without being asked for project type:

    (vscode/commands.executeCommand \"calva.connect\" (clj->js {:port \"55555\" :connectSequence \"Generic\"}))\n
    ","boost":7},{"location":"customizing-jack-in-and-connect/#customizing-jack-in","title":"Customizing Jack-in","text":"

    The main mechanism for customizing your Jack-in, including automating menu selections, and custom CLJS REPL types is Custom Connect Sequences.

    There are also these settings:

    • calva.jackInEnv: An object with environment variables that will be added to the environment of the Jack-in process.
    • calva.myCljAliases: An array of deps.edn aliases not found in the project file. Use this to tell Calva Jack-in to launch your REPL using your user defined aliases.
    • calva.myLeinProfiles: An array of Leiningen profiles not found in project.clj. Use this to tell Calva Jack-in to launch your REPL using your user defined profiles.
    • calva.openBrowserWhenFigwheelStarted: For Legacy Figwheel only. A boolean controlling if Calva should automatically launch your ClojureScript app, once it is compiled by Figwheel. Defaults to true.
    • calva.depsEdnJackInExecutable: A string which should either be clojure or deps.clj, or clojure or deps.clj (default). It determines which executable Calva Jack-in should use for starting a deps.edn project. With this setting at its default, clojure or deps.clj, Calva will test if the clojure executable works, and use it if it does, otherwise deps.clj will be used, which is bundled with Calva.
    • calva.jackInDependencyVersions: See below

    Note

    When processing the calva.jackInEnv setting you can refer to existing ENV variables with ${env:VARIABLE}.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#jack-in-dependency-versions","title":"Jack-in Dependency Versions","text":"

    Calva Jack-in injects the following dependencies in order for the REPL session to support IDE features

    • nrepl: nREPL is the wonderful piece of software that gives Calva a structured and extensible connection to the REPL in your Clojure and ClojureScript projects.
    • cider-nrepl: cider-nrepl is middleware that extends the nREPL connection with all sorts of nice stuff that Calva uses to give you a delightful IDE experience.
    • cider/piggieback: Piggieback is used to create nREPL sessions in ClojureScript projects. (Not with shadow-cljs projects though, which provides its own middleware for this.)

    The versions used are configurable via the VS Code settings calva.jackInDependencyVersions.

    Java 1.8 compatible versions

    The default dependency versions are not compatible with Java 1.8. If your project needs that version of Java you can use these settings in your Workspace .vscode/settings.json:

    \"calva.jackInDependencyVersions\": {\n  \"nrepl\": \"1.0.0\",\n  \"cider-nrepl\": \"0.28.5\",\n  \"cider/piggieback\": \"0.5.3\"\n}\n
    ","boost":7},{"location":"customizing-jack-in-and-connect/#options-for-the-jack-in-command","title":"Options for the Jack-in Command","text":"

    The calva.jackIn command takes an optional options argument defined like so:

      options?: {\n    connectSequence?: string | ReplConnectSequence;\n    disableAutoSelect?: boolean;\n  }\n

    Where ReplConnectSequence is a Connect Sequences. If you provide a string it needs to match against a built-in or custom connect sequence. With disableAutoSelect you can force the jack-in menus to be provided even if a custom connect sequence is set to be autoSelected.

    You can provide these options from keyboard shortcuts or from Joyride scripts.

    Here's a keyboard shortcut for connecting to a running REPL bypassing any connect sequence with autoSelectForConnect.

        {\n        \"command\": \"calva.jackIn\",\n        \"args\": {\"disableAutoSelect\": true},\n        \"key\": \"ctrl+alt+c shift+j\",\n    },\n

    A Joyride command for starting a deps.edn REPL for a project in the root of the workspace.

    (vscode/commands.executeCommand\n \"calva.jackIn\"\n (clj->js {:connectSequence {:projectType \"deps.edn\"\n                             :projectRootPath [\".\"]}}))\n

    It will prompt for any aliases it finds in the deps.edn file.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#starting-the-repl-from-application-code","title":"Starting the REPL from application code?","text":"

    If your project is setup so that the REPL server is started by the application code, you will need to get the cider-nrepl middleware in place. See the cider-nrepl docs about embedding nREPL in your application.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#auto-select-project-type-and-project-root","title":"Auto-select Project Type and Project Root","text":"

    You can make both Jack-in and Connect stop prompting you for project type and project root path in projects where you always want to use the same. See Connect Sequences.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#project-roots-search-globing","title":"Project roots search globing","text":"

    When searching for project roots in your workspace, Calva will glob for all files matching project.clj, deps.edn, or shadow-cljs.edn. This is done using VS Code's workspace search engine, and is very efficient. However, in a large monorepo, it is still a substantial task. In order to not waste resources Calva will exclude any directories in the setting calva.projectRootsSearchExclude.

    Exclude entry globs

    Each entry is a partial glob and will be part of a resulting glob of the form **/{glob1,glob2,...,globN}. This means that all directories in the workspace matching an entry will be excluded, regardless of where in the workspace they reside.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#viewing-the-communication-between-nrepl-and-calva","title":"Viewing the Communication Between nREPL and Calva","text":"

    It may be helpful to view the messages sent between nREPL and Calva when troubleshooting an issue related to the REPL. See how to do that here.

    ","boost":7},{"location":"customizing/","title":"Customizing Calva","text":"

    Don't like the defaults? On this page we can collect some of the customizations that people have done, and maybe write a thing or two about it some day.

    Tip for VS Code newcomers: The search box in Settings is your friend. Also, some Calva settings are more complex than the Settings UI can handle. VS Code will then show you a link to settings.json. And VS Code's built-in json extension is awesome. To add settings for Calva's Pretty Printing, for example, search for \u201dprettyprint\u201d in VS Code Settings and follow the link to settings.json. Start typing \u201dcalvapretty\u201d until auto-complete suggests calva.prettyPrintingOptions. Press ENTER and VS Code will fill in these defaults:

        \"calva.prettyPrintingOptions\": {\n        \"enabled\": true,\n        \"printEngine\": \"pprint\",\n        \"width\": 40\n    },\n
    "},{"location":"customizing/#clojure-defaults","title":"Clojure Defaults","text":"

    Calva sets some VS Code settings for all Clojure files. Some of these are needed for Calva to function correctly, which should not be tampered with unless you really know what you are doing, and some of them are convenient defaults. If you add a setting to your settings.json and accept the snippet help you get when you type \"[clojure]\", you will get the Calva defaults pasted:

          \"[clojure]\": {\n        \"editor.wordSeparators\": \"\\t ()\\\"':,;~@#$%^&{}[]`\",\n        \"editor.autoClosingBrackets\": \"always\",\n        \"editor.autoClosingOvertype\": \"always\",\n        \"editor.autoClosingQuotes\": \"always\",\n        \"editor.formatOnType\": true,\n        \"editor.autoIndent\": \"full\",\n        \"editor.formatOnPaste\": true,\n        \"editor.matchBrackets\": \"never\",\n        \"editor.guides.indentation\": false,\n        \"editor.parameterHints.enabled\": false,\n        \"editor.unicodeHighlight.allowedCharacters\": {\n          \"\u00a0\": true,\n          \"\ua789\": true\n        },\n        \"editor.foldingStrategy\": \"indentation\"\n      }\n

    editor.wordSeparators

    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.foldingStrategy

    To use the folding levels provided by clojure-lsp, set this to auto. Though at the time of this writing there is a bug in clojure-lsp making folding stop working with this setting.

    "},{"location":"customizing/#pretty-printing","title":"Pretty Printing","text":"

    Calva's pretty printing mode can be configured a bit. See Pretty Printing.

    "},{"location":"customizing/#calva-highlight","title":"Calva Highlight","text":"

    This is highly customizable. See Syntax highlighting

    "},{"location":"customizing/#color-customizations","title":"Color customizations","text":"

    Calva defines a set of themable colors which can be provided by the user using workbench.colorCustomizations.

        \"workbench.colorCustomizations\": {\n        \"calva.inlineErrorForegroundColor\": \"#ff0000\",\n        \"calva.inlineForegroundColor\": \"#ff9000\"\n    }\n

    "},{"location":"customizing/#automatic-parameter-hints-poppup","title":"Automatic Parameter Hints Poppup","text":"

    Calva has helpful parameter hints to aid when typing function calls. They look like so:

    To have the hints automatically pop up when you are typing, set editor.parameterHints.enabled to true in the above [clojure] scoped setting. (To call them up on demand the default VS Code keybindings are cmd+shift+space on Mac and ctrl+shift+space on Linux/Windows.)

    "},{"location":"customizing/#code-formatting","title":"Code Formatting","text":"

    See Formatting for information on how to configure this.

    "},{"location":"customizing/#jack-in-and-connect","title":"Jack-in and Connect","text":"

    Jack-in and Connect are very customizable through Custom Connect Sequences.

    See also Customizing Jack-in and Connect

    "},{"location":"customizing/#key-bindings","title":"Key bindings","text":"

    Most of Calva's commands have default keybindings. They are only defaults, though, and you can change keybindings as you wish. To facilitate precision in binding keys Calva keeps some when clause contexts updated.

    "},{"location":"customizing/#when-clause-contexts","title":"When Clause Contexts","text":"

    The following contexts are available with Calva:

    • calva:keybindingsEnabled: a master switch that you find in the settings
    • paredit:keyMap: strict, original, or none from the corresponding Calva setting (see Paredit)
    • calva:connected: true when Calva is connected to a REPL (there is also calva:connecting || calva:launching)
    • calva:outputWindowActive: true when the Output/REPL window has input focus
    • calva:replHistoryCommandsActive: true when the cursor is in the Output/REPL window at the top level after the last prompt
    • calva:replWindowSubmitOnEnter: true when the cursor is adjacent after the last top level form in the Output/REPL window
    • calva:cursorInString: true when the cursor/caret is in a string or a regexp
    • calva:cursorInComment: true when the cursor is in, or adjacent to a line comment
    • calva:cursorBeforeComment: true when the cursor is adjacent before a line comment
    • calva:cursorAfterComment: true when the cursor is adjacent after a line comment
    • calva:cursorAtStartOfLine: true when the cursor is at the start of a line including any leading whitespace
    • calva:cursorAtEndOfLine: true when the cursor is at the end of a line including any trailing whitespace
    "},{"location":"customizing/#some-custom-bindings","title":"Some Custom Bindings","text":"

    Here is a collection of custom keybindings from here and there.

    • Replace all Calva ctrl+alt+... key bindings with ctrl+shift+..., for keyboards lacking alt key: this gist
    • Replace the default Calva \u201dprefix\u201d, ctrl+alt+c to just alt+v: WebWItch's keybindings.json (Please note, that alt+v does not work for some locales, but for when it works it is much less clunky than the default prefix).
    • Here the Calva key is switched for ctrl+,: manas_marthi's keybindings
    • Keybindings for Emacs users
    • Use modifiers and WASD keys for movement and manipulation: isaksky's keybindings

    Are you a vim extension user? See: Using with VIM extension.

    "},{"location":"customizing/#move-by-word","title":"Move by word","text":"

    By default Calva changes the move-by-word key bindings to move by sexpr/form when the cursor is in structural Clojure code. Within line comments the editor default word movement is active.

    If you want the VS Code default word movement shortcuts, use these settings:

        {\n        \"key\": \"ctrl+right\",\n        \"win\": \"ctrl+right\",\n        \"mac\": \"alt+right\",\n        \"command\": \"cursorWordRight\"\n    },\n    {\n        \"key\": \"ctrl+left\",\n        \"win\": \"ctrl+left\",\n        \"mac\": \"alt+left\",\n        \"command\": \"cursorWordLeft\"\n    },\n    {\n        \"key\": \"ctrl+right\",\n        \"mac\": \"ctrl+right\",\n        \"win\": \"alt+right\",\n        \"command\": \"paredit.forwardSexp\",\n        \"when\": \"calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+left\",\n        \"mac\": \"ctrl+left\",\n        \"win\": \"alt+left\",\n        \"command\": \"paredit.backwardSexp\",\n        \"when\": \"calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/\"\n    }\n

    Use it as an inspiration for customizing things to your own liking. \ud83d\ude04

    "},{"location":"customizing/#wrap-using-like-cursive","title":"Wrap using (, [, { (like Cursive)","text":"

    Something I use in IntelliJ/Cursive is the ability to select an expression and hit one of (, [, { to wrap it. And after wrapping the expression I don't want the selection anymore, so if I were wrapping (foo) then I would want to get ( | (foo)) where | would be my cursor.

    Here's how you can make this work with Calva Paredit: Update all of the Paredit: Wrap Around ... commands so that their respective shortcuts are the wrappers themselves and update the when clause to include editorHasSelection (otherwise when you open a paren the next expression would get slurped in).

    The change would look like this in your keybindings.json:

        {\n        \"key\": \"shift+9\",\n        \"command\": \"paredit.wrapAroundParens\",\n        \"when\": \"editorTextFocus && editorHasSelection && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"[\",\n        \"command\": \"paredit.wrapAroundSquare\",\n        \"when\": \"editorHasSelection && editorTextFocus && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"shift+[\",\n        \"command\": \"paredit.wrapAroundCurly\",\n        \"when\": \"editorHasSelection && editorTextFocus && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n    }\n
    "},{"location":"debugger/","title":"Debugger","text":"

    Calva comes with a powerful expression-based debugger, inspired by Cider's debugger, and using the same underlying library, cider-nrepl. We hope you love it!

    Note

    The debugger currently does not support ClojureScript. Calva's debugger utilizes cider-nrepl for debugging. See this Cider issue for more information.

    "},{"location":"debugger/#features","title":"Features","text":""},{"location":"debugger/#current","title":"Current","text":"
    • Instrument functions for debugging with ctrl+alt+c i
    • Instrument a function manually with #dbg (as opposed to the above command)
    • Set individual breakpoints with #break
    • Continue to next breakpoint
    • Step over form
    • Step into form
    • Step out of form
    • Evaluate code in the debug context
    • See variable values in the debugger side pane
    • See variable values on hover in the editor
    "},{"location":"debugger/#future-goals","title":"Future goals","text":"
    • See structured variables in the debugger side pane (currently maps and collections are just shown as strings)
    • Inject values into the debug context
    • Trace: continue, printing expressions and their values
    "},{"location":"debugger/#dependencies","title":"Dependencies","text":"

    The debugger itself relies pretty heavily on cider-nrepl, as do other parts of Calva. This library is loaded as a dependency when you use Calva Jack-in. If you are not using Calva Jack-in, you can add these dependencies in your project definition or user profile. See the Calva Jack-in guide for more information.

    "},{"location":"debugger/#using-the-debugger","title":"Using the Debugger","text":"

    If you're new to Clojure or expression-based debuggers, this debugger may function differently than what you're used to. Instead of placing breakpoints in the side margin and then hitting F5 to start debugging, you instead use Clojure reader tags, #break and #dbg, to denote breakpoints anywhere in a Clojure form. When you evaluate a call to a function that has been evaluated with that reader tag, the debugger will start when execution reaches the first breakpoint. There's also a convenience command to instrument functions. Read below about both options.

    Note

    The debugger is not configured via a launch.json file, and is not started in the same way as you may be used to when working with other languages in VS Code. The debugger is used by way of the REPL. If you are new to Clojure, please visit the Getting Started section of the documentation and get familiar with evaluating code using the REPL before using the debugger.

    "},{"location":"debugger/#instrumenting-a-function","title":"Instrumenting a Function","text":"

    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.

    "},{"location":"debugger/#setting-breakpoints-with-break","title":"Setting Breakpoints with #break","text":"

    You can insert a breakpoint manually into any code by placing a #break in front of the form where you want execution to pause, and then evaluating the top level form with alt+enter. When you evaluate a call to this code the VS Code debugger will start, the cursor will move to right after the form that's preceded by #break, and the line will be highlighted to show execution is paused there.

    Note

    Code will be executed up to and including the form after the breakpoint.

    "},{"location":"debugger/#conditional-breakpoints","title":"Conditional Breakpoints","text":"

    You can set conditional breakpoints by adding metadata before the form that the #break applies to.

    (defn print-nums [n]\n  (dotimes [i n]\n    #break ^{:break/when (= i 7)} ;; This breakpoint will only be hit when i equals 7\n    (prn i)))\n
    "},{"location":"debugger/#instrumenting-a-form-with-dbg","title":"Instrumenting a Form with #dbg","text":"

    Adding #dbg before a form then evaluating the form with alt+enter will instrument the form. This has the same effect as using the instrument command.

    "},{"location":"debugger/#evaluating-code-in-the-paused-context","title":"Evaluating Code in the Paused Context","text":"

    When execution is paused at a breakpoint, you can evaluate code in that context. This can be done in the editor or in the REPL window, as usual.

    "},{"location":"debugger/#viewing-variable-values","title":"Viewing Variable Values","text":"

    While debugging, you can view the values of variables in VS Code's debugger side pane. You can also view values by hovering over the variables in the editor.

    Metadata not available

    The variable viewer does not have access to any metadata attached to the variable values.

    "},{"location":"debugger/#viewing-the-call-stack","title":"Viewing the Call Stack","text":"

    While debugging, you can view the call stack in VS Code's call stack side pane. Clicking the stack frames will show the related line of code in an editor.

    Note

    You may only see one stack frame in the call stack side pane, as the change for adding additional frames was rolled back due to an issue. You can follow the change for this at #1150.

    "},{"location":"debugger/#stepping-commands","title":"Stepping Commands","text":"

    You can use VS Code's debugger UI to advance execution while debugging.

    Note

    Clicking restart does nothing, since this functionality does not make sense for our debugger.

    • Continue - Continues without stopping for the current breakpoint
    • Step over - Continues to the next breakpoint
    • Step in - Steps in to the function about to be called. If the next breakpoint is not around a function call, does the same as next. Note that not all functions can be stepped in to - only normal functions stored in vars, for which cider-nrepl can find the source. You cannot currently step in to multimethods, protocol functions, or functions in clojure.core (although multimethods and protocols can be instrumented manually).
    • Step out - Steps to the next breakpoint that is outside of the current sexp
    • Restart - Does nothing. To restart debugging, you can hit disconnect or continue execution through the final result, then re-evaluate the expression that started the debugger.
    • Disconnect - Disconnects the debugger
    "},{"location":"debugger/#caveats","title":"Caveats","text":""},{"location":"debugger/#breakpoints-in-looprecur","title":"Breakpoints in loop/recur","text":"

    One construct where the debugger is limited is loop/recur. As recur always has to appear in a tail-position inside a loop or a fn and the debugger uses macros to interleave breakpoints in the forms, it might happen that a recur no longer appears in a tail position. In that case we have to avoid setting up the breakpoint. An example of such a case is:

    (loop [i 0]\n  #break\n  (when (< i 10)\n    (println i)\n    (recur (inc i))))\n

    Here the breakpoint is exactly in front of a form that contains as its last expression a recur which is wrapped in a loop. This breakpoint has no effect. This does not mean you cannot use the debugger with loop, it just means you have to set your debug statements more carefully.

    "},{"location":"debugger/#loading-the-file-and-eval-on-save","title":"Loading the File and \"Eval On Save\"","text":"

    When you load a file, any breakpoints that were previously set in functions will be unset. If you have the \"Eval On Save\" setting enabled, your file is also loaded with each save, therefore saving the file will remove breakpoints previously set.

    "},{"location":"debugger/#clashes-with-emacscider-debugger","title":"Clashes with Emacs/CIDER debugger","text":"

    When both CIDER and Calva is connected to the same REPL, stepping the debugger in one editor may have it stop on the breakpoint in the other one. Reported here: https://github.com/BetterThanTomorrow/calva/issues/2496

    "},{"location":"debugger/#troubleshooting","title":"Troubleshooting","text":""},{"location":"debugger/#debugger-hangs-when-stepping-over-infinite-seqs","title":"Debugger hangs when stepping over infinite seqs","text":"

    This is because the debugger tries to evaluate the form when it's stepped over, and if clojure.core/*print-length* is set to nil as it is by default, evaluation will never complete. If you want to debug a form with an infinite seq, make sure to set *print-length* beforehand. For example:

    (set! *print-length* 3)\n;; Or, to be more precise\n(set! clojure.core/*print-length* 3)\n

    Calva does not set this for you during debug mode, instead leaving it up to you to decide the value.

    "},{"location":"debugger/#my-breakpoint-isnt-being-hit","title":"My breakpoint isn't being hit","text":"

    It's likely that your breakpoint is in a place that cider-nrepl does not see as an appropriate place to break execution. For example, if you put a breakpoint before a literal number, it will not be hit, because there's no need to show the value of a literal.

    (defn simple [x]\n  (+ 1 #break 1)) ;; This breakpoint will not be hit\n

    Another possible issue is that you're loading the file again after setting breakpoints, which unsets them. See Loading the File and \"Eval On Save\" under Caveats.

    "},{"location":"debugger/#my-breakpoint-in-a-test-isnt-being-hit","title":"My breakpoint in a test isn't being hit","text":"

    If you're using the test commands like \"Run current test\" to run your tests, breakpoints will not be hit. This is because Calva loads the file before running the tests to make sure the latest version of test code is being run, and when the file is loaded, breakpoints are unset.

    If you want a breakpoint to work within the test, evaluate the test form with a breakpoint tag in it, then call the test directly.

    "},{"location":"debugger/#no-reader-function-for-tag-error","title":"\"No reader function for tag\" error","text":"

    If you get an error like this, it's likely that you connected to a REPL instead of jacking in, and you don't have the proper dependencies loaded in your REPL. You can run the command \"Copy Jack-in Command Line to Clipboard\" to see what command would be run if you jacked in.

    Most importantly, make sure you have cider/cider-nrepl as a dependency, and cider.nrepl/cider-middleware as middleware loaded in your REPL. For example, this is a jack-in command line for a deps.edn project:

    clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,\"0.8.3\"},cider/cider-nrepl {:mvn/version,\"0.25.8\"}}}' -m nrepl.cmdline --middleware \"[cider.nrepl/cider-middleware]\"\n
    "},{"location":"debugger/#passing-options-to-the-repl-jvm","title":"Passing options to the REPL JVM","text":"

    There are times when Clojure debugging tools are not enough or not right for the job. This is usually true when use an (open source) Java library and you want to set some breakpoints in Java code. For those cases and others, you need to start the JVM in debug mode.

    Typical use cases:

    • Change Java logger configuration for the REPL via java system properties: e.g -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE
    • Enable JVM debugger, change VM memory size, etc.

    Calva supports passing environment variables via jackInEnv. You can set that option inside VSCode settings.json file.

    You can configure global settings.json file or a project wide version, inside <project-root>/.vscode/settings.json.

    Configuring the global option will impact all projects you work on using Calva, so be aware. See the documentation for settings.json for more information.

    The bellow snippet configures JAVA_TOOL_OPTIONS environment variable. We configure slf4j-simple logging level via a Java system property (-D) and JVM specific options (-X).

    NOTE: You can of course pass other env variables here.

    .vscode/settings.json

    {\n    \"calva.jackInEnv\": {\n        \"JAVA_TOOL_OPTIONS\": \"${env:JAVA_TOOL_OPTIONS} -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896\"\n    }\n}\n

    Once you saved the file, the next time you Jack in the project, this variable is read by the JVM and the configuration is applied accordingly.

    You should see something like the message below in the Calva terminal output window:

    clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,\"0.8.3\"},cider/cider-nrepl {:mvn/version,\"0.26.0\"}}}' -A:debug -m nrepl.cmdline --middleware \"[cider.nrepl/cider-middleware]\"\nPicked up JAVA_TOOL_OPTIONS:  -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896\nListening for transport dt_socket at address: 7896\nnREPL server started on port 46691 on host localhost - nrepl://localhost:46691\n
    "},{"location":"emacs-keybindings/","title":"Emacs Keybindings","text":"

    Some keybindings to make it easier for Emacs users

    [\n    {\n        \"key\": \"ctrl+cmd+b\",\n        \"command\": \"paredit.backwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+alt+left\",\n        \"command\": \"-paredit.backwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"shift+cmd+]\",\n        \"command\": \"-workbench.action.nextEditor\"\n    },\n    {\n        \"key\": \"ctrl+shift+]\",\n        \"command\": \"paredit.barfSexpBackward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+right\",\n        \"command\": \"-paredit.barfSexpBackward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+[\",\n        \"command\": \"paredit.barfSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+left\",\n        \"command\": \"-paredit.barfSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+cmd+f\",\n        \"command\": \"paredit.forwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+alt+right\",\n        \"command\": \"-paredit.forwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+cmd+f\",\n        \"command\": \"-workbench.action.toggleFullScreen\"\n    },\n    {\n        \"key\": \"ctrl+shift+backspace\",\n        \"command\": \"-paredit.killSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"shift+cmd+k\",\n        \"command\": \"-editor.action.deleteLines\",\n        \"when\": \"textInputFocus && !editorReadonly\"\n    },\n    {\n        \"key\": \"ctrl+shift+0\",\n        \"command\": \"paredit.slurpSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+right\",\n        \"command\": \"-paredit.slurpSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+9\",\n        \"command\": \"paredit.slurpSexpBackward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+left\",\n        \"command\": \"-paredit.slurpSexpBackward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+c ctrl+c\",\n        \"command\": \"calva.evaluateCurrentTopLevelForm\",\n        \"when\": \"calva:activated\"\n    },\n    {\n        \"key\": \"ctrl+alt+c space\",\n        \"command\": \"-calva.evaluateCurrentTopLevelForm\",\n        \"when\": \"calva:activated\"\n    },\n    {\n        \"key\": \"ctrl+x ctrl+e\",\n        \"command\": \"calva.evalCurrentTopLevelFormInREPLWindow\",\n        \"when\": \"calva:activated\"\n    },\n    {\n        \"key\": \"ctrl+alt+c ctrl+alt+space\",\n        \"command\": \"-calva.evalCurrentTopLevelFormInREPLWindow\",\n        \"when\": \"calva:activated\"\n    },\n    {\n        \"key\": \"ctrl+x ctrl+s\",\n        \"command\": \"workbench.action.files.save\"\n    },\n    {\n        \"key\": \"cmd+s\",\n        \"command\": \"-workbench.action.files.save\"\n    },\n    {\n        \"key\": \"cmd+s\",\n        \"command\": \"paredit.spliceSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+alt+s\",\n        \"command\": \"-paredit.spliceSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+cmd+k\",\n        \"command\": \"paredit.cutForwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+x right\",\n        \"command\": \"-paredit.cutForwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+cmd+backspace\",\n        \"command\": \"paredit.cutBackwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+x left\",\n        \"command\": \"-paredit.cutBackwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+1\",\n        \"command\": \"-workbench.action.openEditorAtIndex1\"\n    },\n    {\n        \"key\": \"ctrl+1\",\n        \"command\": \"editor.action.quickFix\",\n        \"when\": \"editorHasCodeActionsProvider && editorTextFocus && !editorReadonly\"\n    },\n    {\n        \"key\": \"cmd+.\",\n        \"command\": \"-editor.action.quickFix\",\n        \"when\": \"editorHasCodeActionsProvider && editorTextFocus && !editorReadonly\"\n    },\n    {\n        \"key\": \"cmd+.\",\n        \"command\": \"editor.action.revealDefinition\",\n        \"when\": \"editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor\"\n    },\n    {\n        \"key\": \"f12\",\n        \"command\": \"-editor.action.revealDefinition\",\n        \"when\": \"editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor\"\n    }\n]\n

    "},{"location":"eval-tips/","title":"Code Evaluation","text":"

    Calva tries to make it easy to evaluate code, supporting interactive development. The fastest path to learning about it is to use the Fire up the Getting Started REPL command, which you can learn more about in the Getting Started section.

    NB: The below assumes you have read about Finding Calva Commands and Shortcuts.

    ","boost":7},{"location":"eval-tips/#interruptingstopping-running-evaluations","title":"Interrupting/stopping running evaluations","text":"

    Sometimes you evaluate things that take a very long time to complete, or might not even ever complete (infinite loops, lazy sequences, things like that). Calva has a command for interrupting running evaluations. You find it in the VS Code command palette, as well as in the REPL status bar item menu, when the REPL is connected.

    ","boost":7},{"location":"eval-tips/#evaluation-in-a-file-editor","title":"Evaluation in a File Editor","text":"

    Calva has many commands for evaluating forms, including the current form and the current top-level form.

    Some of the commands also let you choose what should happen with the results:

    1. Inline. This will display the results (or some of it, if it is long) inline in the editor.
    2. This also creates a hover pane including the full results and a button which will copy the results to the clipboard.
    3. There is also a command for copying the last result to the clipboard.
    4. The full results are always available in the output window.
      • There is a command for showing the output window, allowing for a workflow where you either generally have it closed, or have it as one of the tabs in the same editor group as the files you are working with.
    5. To comments. This will add the results as line comments below the current line.
    6. Replace the evaluated code. This will do what it says, the evaluated code will be replaced with its results.
    ","boost":7},{"location":"eval-tips/#wait-current-form-top-level-form","title":"Wait, Current Form? Top-level Form?","text":"

    These are important concepts in Calva in order for you to create your most effective workflow. This video explains it a bit:

    ","boost":7},{"location":"eval-tips/#current-form","title":"Current Form","text":"

    Default shortcut for evaluating the current form: ctrl+enter.

    The current form either means the current selection, or otherwise is based on the cursor position. Play some with the command Calva: Select current form, ctrl+alt+c s, to figure out what Calva thinks is the current form for some different situations. Try it inside a symbol, adjacent to a symbol (both sides) and adjacent to an opening or closing bracket (again, both sides). Generally the current form is determined like so:

    1. If text is selected, then that text
    2. If the cursor is \u201din\u201d a symbol, then that symbol
      foob|ar ; foobar\n
    3. If the cursor is adjacent to a form (a symbol or a list of some kind), then that form
      (foo bar |(baz)) ; (baz)\n
    4. If the cursor is between to forms, then the left side form
      (foo bar | (baz)) ; bar\n
    5. If the cursor is before the first form of a line, then that form
      (foo\n| bar (baz)) ; bar\n
    ","boost":7},{"location":"eval-tips/#current-top-level-form","title":"Current Top-level Form","text":"

    Default shortcut for evaluating the current top level form: alt+enter.

    The current top-level form means top-level in a structural sense. It is not the topmost form in the file. Typically in a Clojure file you will find def and defn (and defwhatever) forms at the top level, which also is one major intended use for evaluating top level form: to define and redefine variables. However, Calva does not check the contents of the form in order to determine it as a top-level forms: all forms not enclosed in any other form are top level forms.

    An \u201dexception\u201d is introduced by the comment form. It will create a new top level context, so that any forms immediately inside a (comment ...) form will be considered top-level by Calva. This is to support a workflow with what is often referred to the Rich Comments.

    At the top level the selection of which form is the current top level form follows the same rules as those for the current form.

    ","boost":7},{"location":"eval-tips/#evaluate-enclosing-form","title":"Evaluate Enclosing Form","text":"

    The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter.

    (let [foo :bar]\n  (when false (str| foo))) ; => \":bar\"\n
    ","boost":7},{"location":"eval-tips/#evaluate-to-cursor","title":"Evaluate to Cursor","text":"

    There are several commands for evaluating a piece of code, closing brackets. It's good, especially in threads, but can also come in handy in other situations, for instance when you want to evaluate something that depends on bindings, such as in a let form.

    ","boost":7},{"location":"eval-tips/#evaluate-from-start-of-list-to-cursor-closing-brackets","title":"Evaluate From Start of List to Cursor, Closing Brackets","text":"

    This command evaluates the text from the start of the current enclosing list to where the cursor is, and it adds the missing closing bracket for you. Convenient for checking intermediate results in thread or doto, or similar pipelines. The cursor is right behind :d in this form:

      (->> [1 1 2 3 5 8 13 21]\n       (partition 2)\n       (zipmap [:a :b :c :d])\n       :d| ; => (13 21)\n       (apply -)\n       (Math/abs))\n

    The default shortcut for this command is ctrl+alt+enter.

    ","boost":7},{"location":"eval-tips/#evaluate-selection-closing-brackets","title":"Evaluate Selection, Closing Brackets","text":"

    This is the most versatile of the \u201devaluation, closing brackets\u201d commands. It will do what it says. \ud83d\ude04 It's extra handy in combination with the command Paredit: Select Backward Up Sexp/Form (shift+ctrl+up). Consider this contrieved form (buggy code, because it was supposed to result in 42, not -42):

    (defn fortytwo-from-thirty\n  []\n  (let [thirty 30]\n    (-> thirty\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

    At ;1, you can do backward up sexp (shift+ctrl+up) twice to select up to the (let ..), then issue Evaluate Selection, Closing Brackets. It has the same default keybinding as the command for evaluating the current list up to the cursor: ctrl+alt+enter.

    At ;2 you need select backwards up three times.

    ;3 is included because it is close to the bug. (Which was introduced when the thread-last, ->> was added to make this example.) Please practice the Evaluate Selection, Closing Brackets command to fix the bug.

    ","boost":7},{"location":"eval-tips/#evaluate-from-start-of-top-level-form-to-cursor-closing-brackets","title":"Evaluate From Start of Top Level Form to Cursor, Closing Brackets","text":"

    This command has a default shortcut keybinding of shift+alt+enter. It will create a form from the start of the current top level form, up to the cursor, close all brackets, and this will then be evaluated. Good for examining code blocks up to a certain point. Often comes in handy in Rich comments ((comment ...)).

    Take this example and paste it in a file loaded into the REPL, then place the cursor in front of each line comment and try the command.

    (comment\n (do\n   (def colt-express\n     {:name \"Colt Express\"\n      :categories [\"Family\"\n                   \"Strategy\"]\n      :play-time 40\n      :ratings {:pez 5.0\n                :kat 5.0\n                :wiw 5.0   ; 1, then eval `colt-express`\n                :vig 3.0\n                :rex 5.0\n                :lun 4.0}})\n\n   (defn average [coll]\n     (/ (apply + coll) (count coll)))\n\n   (let [foo-express (-> colt-express\n                         (assoc :name \"Foo Express\")\n                         (assoc-in [:ratings :lyr] 5.0)\n                         (update-in [:ratings :vig] inc))]\n     (->> foo-express   ; 2\n          :ratings      ; 3\n          vals          ; 4\n          average       ; 5\n          ))))\n
    ","boost":7},{"location":"eval-tips/#evaluate-from-start-of-file-to-cursor-closing-brackets","title":"Evaluate From Start of File to Cursor, Closing Brackets","text":"

    Yup, that command also exists. \ud83d\ude04

    ","boost":7},{"location":"eval-tips/#copying-the-inline-results","title":"Copying the inline results","text":"

    There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c.

    This works regardless if you have evaluated in a file editor or in a REPL window.

    ","boost":7},{"location":"eval-tips/#evaluating-in-a-repl-window","title":"Evaluating in a REPL window","text":"

    Since the REPL Window is mostly just a regular file, things work pretty similar at the REPL prompt. You use alt+enter to evaluate. Selecting the current form (default key binding ctrl+w on Mac and shift+alt+right on Windows and Linux) after evaluating will select the result.

    ","boost":7},{"location":"evaluation/","title":"Code Evaluation","text":"

    Calva tries to make it easy to evaluate code, supporting interactive development. The fastest path to learning about it is to use the Fire up the Getting Started REPL command, which you can learn more about in the Getting Started section.

    NB: The below assumes you have read about Finding Calva Commands and Shortcuts.

    ","boost":7},{"location":"evaluation/#interruptingstopping-running-evaluations","title":"Interrupting/stopping running evaluations","text":"

    Sometimes you evaluate things that take a very long time to complete, or might not even ever complete (infinite loops, lazy sequences, things like that). Calva has a command for interrupting running evaluations. You find it in the VS Code command palette, as well as in the REPL status bar item menu, when the REPL is connected.

    ","boost":7},{"location":"evaluation/#evaluation-in-a-file-editor","title":"Evaluation in a File Editor","text":"

    Calva has many commands for evaluating forms, including the current form and the current top-level form.

    Some of the commands also let you choose what should happen with the results:

    1. Inline. This will display the results (or some of it, if it is long) inline in the editor.
    2. This also creates a hover pane including the full results and a button which will copy the results to the clipboard.
    3. There is also a command for copying the last result to the clipboard.
    4. The full results are always available in the output window.
      • There is a command for showing the output window, allowing for a workflow where you either generally have it closed, or have it as one of the tabs in the same editor group as the files you are working with.
    5. To comments. This will add the results as line comments below the current line.
    6. Replace the evaluated code. This will do what it says, the evaluated code will be replaced with its results.
    ","boost":7},{"location":"evaluation/#wait-current-form-top-level-form","title":"Wait, Current Form? Top-level Form?","text":"

    These are important concepts in Calva in order for you to create your most effective workflow. This video explains it a bit:

    ","boost":7},{"location":"evaluation/#current-form","title":"Current Form","text":"

    Default shortcut for evaluating the current form: ctrl+enter.

    The current form either means the current selection, or otherwise is based on the cursor position. Play some with the command Calva: Select current form, ctrl+alt+c s, to figure out what Calva thinks is the current form for some different situations. Try it inside a symbol, adjacent to a symbol (both sides) and adjacent to an opening or closing bracket (again, both sides). Generally the current form is determined like so:

    1. If text is selected, then that text
    2. If the cursor is \u201din\u201d a symbol, then that symbol
      foob|ar ; foobar\n
    3. If the cursor is adjacent to a form (a symbol or a list of some kind), then that form
      (foo bar |(baz)) ; (baz)\n
    4. If the cursor is between to forms, then the left side form
      (foo bar | (baz)) ; bar\n
    5. If the cursor is before the first form of a line, then that form
      (foo\n| bar (baz)) ; bar\n
    ","boost":7},{"location":"evaluation/#current-top-level-form","title":"Current Top-level Form","text":"

    Default shortcut for evaluating the current top level form: alt+enter.

    The current top-level form means top-level in a structural sense. It is not the topmost form in the file. Typically in a Clojure file you will find def and defn (and defwhatever) forms at the top level, which also is one major intended use for evaluating top level form: to define and redefine variables. However, Calva does not check the contents of the form in order to determine it as a top-level forms: all forms not enclosed in any other form are top level forms.

    An \u201dexception\u201d is introduced by the comment form. It will create a new top level context, so that any forms immediately inside a (comment ...) form will be considered top-level by Calva. This is to support a workflow with what is often referred to the Rich Comments.

    At the top level the selection of which form is the current top level form follows the same rules as those for the current form.

    ","boost":7},{"location":"evaluation/#evaluate-enclosing-form","title":"Evaluate Enclosing Form","text":"

    The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter.

    (let [foo :bar]\n  (when false (str| foo))) ; => \":bar\"\n
    ","boost":7},{"location":"evaluation/#evaluate-to-cursor","title":"Evaluate to Cursor","text":"

    There are several commands for evaluating a piece of code, closing brackets. It's good, especially in threads, but can also come in handy in other situations, for instance when you want to evaluate something that depends on bindings, such as in a let form.

    ","boost":7},{"location":"evaluation/#evaluate-from-start-of-list-to-cursor-closing-brackets","title":"Evaluate From Start of List to Cursor, Closing Brackets","text":"

    This command evaluates the text from the start of the current enclosing list to where the cursor is, and it adds the missing closing bracket for you. Convenient for checking intermediate results in thread or doto, or similar pipelines. The cursor is right behind :d in this form:

      (->> [1 1 2 3 5 8 13 21]\n       (partition 2)\n       (zipmap [:a :b :c :d])\n       :d| ; => (13 21)\n       (apply -)\n       (Math/abs))\n

    The default shortcut for this command is ctrl+alt+enter.

    ","boost":7},{"location":"evaluation/#evaluate-selection-closing-brackets","title":"Evaluate Selection, Closing Brackets","text":"

    This is the most versatile of the \u201devaluation, closing brackets\u201d commands. It will do what it says. \ud83d\ude04 It's extra handy in combination with the command Paredit: Select Backward Up Sexp/Form (shift+ctrl+up). Consider this contrieved form (buggy code, because it was supposed to result in 42, not -42):

    (defn fortytwo-from-thirty\n  []\n  (let [thirty 30]\n    (-> thirty\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

    At ;1, you can do backward up sexp (shift+ctrl+up) twice to select up to the (let ..), then issue Evaluate Selection, Closing Brackets. It has the same default keybinding as the command for evaluating the current list up to the cursor: ctrl+alt+enter.

    At ;2 you need select backwards up three times.

    ;3 is included because it is close to the bug. (Which was introduced when the thread-last, ->> was added to make this example.) Please practice the Evaluate Selection, Closing Brackets command to fix the bug.

    ","boost":7},{"location":"evaluation/#evaluate-from-start-of-top-level-form-to-cursor-closing-brackets","title":"Evaluate From Start of Top Level Form to Cursor, Closing Brackets","text":"

    This command has a default shortcut keybinding of shift+alt+enter. It will create a form from the start of the current top level form, up to the cursor, close all brackets, and this will then be evaluated. Good for examining code blocks up to a certain point. Often comes in handy in Rich comments ((comment ...)).

    Take this example and paste it in a file loaded into the REPL, then place the cursor in front of each line comment and try the command.

    (comment\n (do\n   (def colt-express\n     {:name \"Colt Express\"\n      :categories [\"Family\"\n                   \"Strategy\"]\n      :play-time 40\n      :ratings {:pez 5.0\n                :kat 5.0\n                :wiw 5.0   ; 1, then eval `colt-express`\n                :vig 3.0\n                :rex 5.0\n                :lun 4.0}})\n\n   (defn average [coll]\n     (/ (apply + coll) (count coll)))\n\n   (let [foo-express (-> colt-express\n                         (assoc :name \"Foo Express\")\n                         (assoc-in [:ratings :lyr] 5.0)\n                         (update-in [:ratings :vig] inc))]\n     (->> foo-express   ; 2\n          :ratings      ; 3\n          vals          ; 4\n          average       ; 5\n          ))))\n
    ","boost":7},{"location":"evaluation/#evaluate-from-start-of-file-to-cursor-closing-brackets","title":"Evaluate From Start of File to Cursor, Closing Brackets","text":"

    Yup, that command also exists. \ud83d\ude04

    ","boost":7},{"location":"evaluation/#copying-the-inline-results","title":"Copying the inline results","text":"

    There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c.

    This works regardless if you have evaluated in a file editor or in a REPL window.

    ","boost":7},{"location":"evaluation/#evaluating-in-a-repl-window","title":"Evaluating in a REPL window","text":"

    Since the REPL Window is mostly just a regular file, things work pretty similar at the REPL prompt. You use alt+enter to evaluate. Selecting the current form (default key binding ctrl+w on Mac and shift+alt+right on Windows and Linux) after evaluating will select the result.

    ","boost":7},{"location":"fiddle-files/","title":"Fiddle Files Support","text":"

    In the podcast Functional Design in Clojure, Episode 014: Fiddle with the REPL, they discuss a workflow in which you keep some of your exploratory code in separate files, which they call Fiddle Files. It's like Rich Comments, and the files often consist of such comments. The Fiddle files are typically not on the classpath, and are only loaded in the REPL by you when you are developing your project. Some developers keep personal fiddle files. In some projects they are meant to be shared, and in other projects it's a combination.

    Calva has some extra support for the fiddle file workflow, beyond what VS Code offers in terms of navigating between files. The support comes in the form of three commands supported by a little configuration.

    ","boost":5},{"location":"fiddle-files/#the-three-fiddle-file-commands","title":"The Three Fiddle File Commands","text":"

    The commands let you quickly navigate between your implementation code (called Source here) and your Fiddle file, and to evaluate the Fiddle file without leaving the Source file.

    Command Action Shortcut Active Calva: Open Fiddle File for Current File Opens the Fiddle file corresponding to the current Clojure Source file. ctrl+alt+cf When the currently active file is not a Fiddle file. Calva: Open Source File for Current Fiddle File Opens the Source file corresponding to the current Fiddle file. ctrl+alt+cf When the currently active file is a Fiddle file + there is an existing, and corresponding, source file. Calva: Evaluate Fiddle File for Current File Evaluates the Fiddle file corresponding to the current Clojure Source file. ctrl+alt+cctrl+alt+f When the currently active file is not a Fiddle file.

    The commands for opening and evaluating corresponding Fiddle files will offer to Create the Fiddle file if it does not already exist. But the Calva: Open Source File for Current Fiddle File command will not offer to create the target file.

    What does corresponding mean here? Without any configuration Calva will look for \u201csibling\u201d files, where files with Clojure file extensions (E.g. .clj, .cljs, .bb) will be treated as Source files, and files with the .fiddle extension will be treated as Fiddle files. \"Sibling file\" here means residing side by side in the file system. If this default behaviour is not your cup of tea, there is some flexibility added by configuration.

    ","boost":5},{"location":"fiddle-files/#the-fiddle-file-configuration","title":"The Fiddle File Configuration","text":"

    To know how to map between Fiddle <-> Source files, Calva has three different modes of operation:

    1. The sibling files, as described above. This is the default. Example:
      • src/a/b/c.cljc corresponding to:
      • src/a/b/c.fiddle
    2. Parallel directory structures. Mapping a Source directory tree to a Fiddle directory tree. Example:
      • src/a/b/c.cljc corresponding to:
      • env/dev/fiddles/a/b/c.cljc
    3. A dedicated Fiddle file for a Source directory tree. E.g. both:
      • src/a/b/c.cljc and:
      • src/d/e/f.cljc corresponding to:
      • env/dev/fiddles/x.cljc

    The setting is named calva.fiddleFilePaths and is an array of source and fiddle root paths, relative to the project root.

    The Project Root

    It is important to note that the project root depends on whether you are connected to a REPL or not, and to which project you are connected, in case the workspace contains several projects.

    Without a REPL connection (disregarding that fiddle files are not very interesting then) the project root is the same as the first workspace root. And if you have a regular VS Code window open, it is the root of the folder you have opened in that window.

    With a REPL connection, the project root will be the root of the project, i.e. where the project file (deps.edn, project.clj, shadow-cljs.edn) is.

    ","boost":5},{"location":"fiddle-files/#example-configurations","title":"Example Configurations","text":"","boost":5},{"location":"fiddle-files/#single-parallel-directory-structure","title":"Single Parallel Directory Structure","text":"
    \"calva.fiddleFilePaths\": [\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n  }\n]\n

    This will make any file in the src directory tree correspond to a matching file with the same relative path. E.g.:

    • src/a/b/c.clj -> env/dev/fiddles/a/b/c.clj, for both the open and evaluate commands
    • env/dev/fiddles/a/b/c.clj -> src/a/b/c.clj
    ","boost":5},{"location":"fiddle-files/#single-dedicated-fiddle-file","title":"Single Dedicated Fiddle File","text":"

    If you generally work with one Fiddle file at a time, you can configure a mapping to a Dedicated Fiddle file. E.g.:

    \"calva.fiddleFilePaths\": [\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n  },\n]\n

    This will make any file in the src directory tree correspond to the same Fiddle file. E.g.:

    • src/a/b/c.clj -> env/dev/fiddle.clj, for both the open and evaluate commands
    • src/d/e/f.clj -> env/dev/fiddle.clj, ditto
    • env/dev/fiddle.clj -> Won't correspond to a Source file in this case

    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.

    ","boost":5},{"location":"fiddle-files/#multiple-mappings","title":"Multiple Mappings","text":"

    The configuration is an array so that you can configure different mappings for different Source directories. Given several mappings with overlapping Source, the longest mapping will win. Given several mappings with the same Source, the first one will win, unless one of them is a dedicated Fiddle, in which case that one will win.

    \"calva.fiddleFilePaths\": [\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n  },\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n  },\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddle.cljs\"]\n  },\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddle.bb\"]\n  },\n  {\n    \"source\": [\"src\", \"b\"],\n    \"fiddle\": [\"env\", \"dev\", \"b-fiddles\"]\n  },\n]\n

    With this configuration we would get a behaviour like so:

    • src/a/b/c.clj -> env/dev/fiddle.clj, because all four first [\"src\"] mappings match, but the second one is a dedicated fiddle file, and matches the .clj extension.
    • src/a/b/c/d.bb -> env/dev/fiddle.bb, because all four first [\"src\"] mappings match, but the second one is a dedicated fiddle file, and matches the .bb extension.
    • src/a/b/c/d.cljc -> env/dev/fiddle.clj, because all four first [\"src\"] mappings match, but the second one is a dedicated fiddle file, without a matching file extension, (so the first dedicated fiddle file is picked).
    • src/b/c/d.clj -> env/dev/b-fiddles/c/d.clj, because the [\"src\", \"b\"] mapping is longer than the also matching [\"src\"] mappings.
    ","boost":5},{"location":"fiddle-files/#tips","title":"Tips","text":"

    Organize your Fiddle files such that they do not get automatically loaded as part of your application. This can lead to strange errors and hard-to-detect bugs. Most often it should only be you manually loading the fiddle file, not clj/clojure or Leiningen or any such system which loads your application.

    When you want your fiddle code to be evaluated in the same workspace as its corresponding Source file, you can use the same namespace declaration for both files. The linter might complain, but the REPL will happily comply.

    If you primarily evaluate the fiddle file using the provided command for it, from the Source files, you can omit the namespace declaration, and Calva will evaluate it in the namespace of the Source file.

    The linter and fiddle files

    For some fiddle files you will get a lot of linter warnings, because clj-kondo doesn't know about fiddle files, and they are often not on the classpath. You might find yourself wanting to silence some linters for some fiddle files. E.g. like this:

    (ns main.core\n  {:clj-kondo/config\n   '{:linters {:unresolved-symbol {:level :off}}}})\n

    See clj-kondo Configuration for more on what options you have for this.

    ","boost":5},{"location":"fiddle-files/#see-also","title":"See Also","text":"
    • Rich Comments
    • Functional Design in Clojure Episode 014: Fiddle with the REPL
    • The Polylith Development page mentions good practice for where to put your fiddle files (not called fiddle files there, but it is the same concept).
    ","boost":5},{"location":"finding-commands/","title":"Finding Calva Commands","text":"

    Calva relies a lot on that VS Code makes it really easy to find commands by opening the command palette: ctrl+shift+p (Windows/Linux), cmd+shift+p (Mac), and then start typing some words (or parts of words) that you think might be in the command.

    To leverage this, all Calva commands are prefixed with Calva. As an example, say you want to find commands related to evaluating the top level form. Then you can do this:

    1. Open the command palette
    2. Type calevtop

    VS Code will match cal to \u201dCalva\u201d, ev to \u201dEvaluate\u201d, and top to \u201dTop\u201d. It looks like so:

    As you can see on the screenshot, VS Code will also reveal the keyboard shortcut for each command. My advice is to make it a habit to try to remember those shortcuts and use them for a more effective workflow.

    Now might be a good time to see Calva Top 10 Commands

    "},{"location":"finding-commands/#all-the-settings-and-commands","title":"All the Settings and Commands","text":"

    Did you know? There is a complete list of Calva settings and commands in the Contributions tab of the Calva entry in the Extensions pane in VS Code.

    "},{"location":"finding-commands/#toggling-keyboard-shortcuts-onoff","title":"Toggling Keyboard Shortcuts On/Off","text":"

    The command calva.toggleKeybindingsEnabled can be used to quickly enable and disable (almost) all keyboard shortcuts. This allows you to quickly toggle between Calva keybindings and other keybindings which would otherwise not be available when Calva is enabled. This is particularly useful with the Paredit keyboard shortcuts, whose default shortcuts conflict with the default VS Code shortcuts for textual (non-structural) editing.

    By default it is not bound to a shortcut so as not to cause confusion by users unwittingly pressing it, but if this is something you'd like to use often, you may want to bind it to a shortcut.

    "},{"location":"formatting/","title":"Formatting","text":"

    We have tried to make Calva's formatter so that it just works. It is enabled by default for Clojure files, and with the default configuration it mostly follows Bozhidar Batsov's Clojure Style Guide. Calva uses cljfmt for the formatting.

    Tab formats the current surrounding form

    Calva's code formatter sets the default keybinding of its Format Current Form command to tab. Meaning that most often when things look a bit untidy, you can press tab to make things look pretty. Good to know, right? For performance reasons it only formats the current enclosing form, so sometimes you want to move the cursor up/out a form (ctrl+up) first. See The Paredit Guide for more on moving the cursor structurally through your code.

    With the default settings, Calva's formatting behaves like so:

    • indents as you type (when entering new lines)
    • formats the current enclosing form when you hit tab
    • formats pasted code
    • formats according to community standards
    • formats the current form, aligning map keys and values, when you press ctrl+alt+l
    • formats (comment ...) forms special, see rich comments

    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.

    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):

    • trims whitespace at the end of the line
    • trims whitespace inside brackets
      • this also folds trailing brackets (a k a the paren trail) up on the same line
    • inserts whitespace between forms

    Not a fan of some default setting? The formatter is quite configurable.

    "},{"location":"formatting/#format-current-form-command-variants","title":"Format current form command variants","text":"

    There are three special commands for formatting the current form:

    "},{"location":"formatting/#1-format-and-align-current-form","title":"1. Format and Align Current Form","text":"

    Aligns associative structures and bindings in two columns. See more below.

    "},{"location":"formatting/#2-format-current-form-and-trim-space-between-forms","title":"2. Format Current Form and trim space between forms","text":"

    This formats the text, and trims consecutive, non-indent, whitespace on a line to just one space. Something like:

    (let [a    :b]\n(str \"foo\"     \"bar\" \"baz\"\n\"a\"    a))\n

    Becomes:

    (let [a :b]\n  (str \"foo\" \"bar\" \"baz\"\n       \"a\" a))\n

    Basically, it behaves like if :remove-multiple-non-indenting-spaces? true was added to the cljfmt config. Which, in fact, is what happens. Calva merges that onto your cljfmt config when this command is used.

    "},{"location":"formatting/#3-replace-current-form-or-selection-with-pretty-printed-form","title":"3. Replace Current Form (or Selection) with Pretty Printed Form","text":"

    This command will run the code of the Current Form through Calva's pretty printer (the engine named calva, which is using zprint) and replace the current form inline in the editor with the pretty printed results.

    Unlike with the \u201dreal\u201d Calva Formatter, which never breaks up lines, this one will follow your pretty printing options and break up lines if you have set maxWidth to something that calls for breaking up lines.

    Applies to the other Current Form

    Unlike the other Format commands, which applies to the current enclosing form, this one applies to the Current Form, same as with evaluations. That is because this is not really part of the Calva formatter, but rather is a convenience command for tidying up code or data.

    "},{"location":"formatting/#provide-zprint-config-via-keyboard-shortcuts-or-joyride","title":"Provide zprint config via keyboard shortcuts (or Joyride)","text":"

    The default options for the command are to not sort maps and to not insert commas between map entries. However, the command takes a map as an argument, expecting this map to be a zprint configuration map. You can provide the argument map via keyboard shortcuts. In VS Code settings, you use JSON, but it will be converted to EDN before handed to zprint.

    Say you want to have maps sorted by their keys, and generally use community standard formating + justify maps and bindings. This keyboard shortcut does that.

        {\n        \"key\": \"ctrl+alt+p enter\",\n        \"command\": \"calva.prettyPrintReplaceCurrentForm\",\n        \"args\": {\n            \"style\": [\"community\", \"justified\"],\n            \"map\": {\n                \"comma?\": false,\n                \"sort?\": true,\n            }\n        }\n    }\n

    Note that we have to specify \"comma?\": false here, because this argument will replace the default options maps for the command.

    "},{"location":"formatting/#configuration","title":"Configuration","text":"

    You can adjust the above mentioned defaults, and the default indents, by configuring the formatting using cljfmt's configuration EDN.

    This configuration can either be provided via a file or via clojure-lsp. See Providing configuration via clojure-lsp below.

    "},{"location":"formatting/#providing-configuration-via-a-config-file","title":"Providing configuration via a config file","text":"

    Calva will look for the configuration in one of the default cljfmt paths ('.cljfmt.edn', '.cljfmt.clj', 'cljfmt.edn', or 'cljfmt.clj' in the workspace root). If your file is somewhere else use the calva.fmt.configPath to tell Calva where to find it. The path should either be absolute, or relative to the workspace root directory. If your config file is somewhere in the workspace root, Calva will hot reload it when you update it.

    Wherever the config file is, a suggested path for providing your configuration is to start changing the Calva formatting defaults by pasting the following map into a file and save it.

    {:remove-surrounding-whitespace? true\n :remove-trailing-whitespace? true\n :remove-consecutive-blank-lines? false\n :insert-missing-whitespace? true\n :remove-multiple-non-indenting-spaces? false}\n

    If the file is in the workspace, you can quickly test how different settings affect the formatting. Try:

    1. Adding :align-associative? true to the config
    2. then save
    3. then hit tab, and see what happens.
    :align-associative? is experimental

    This particular setting is experimental and known to cause trouble together with namespaced keywords. Consider using ctrl+alt+l instead of tab as your formatting command, instead of enabling this setting. See below for more info about this. See more below about this.

    No Leiningen config support

    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.

    "},{"location":"formatting/#providing-configuration-via-clojure-lsp","title":"Providing configuration via clojure-lsp","text":"

    If you work in a team where some members use clojure-lsp for formatting, you can make Calva format using the same configuration by telling setting calva.fmt.configPath to CLOJURE-LSP (case sensitive). See Clojure LSP Settings) for how to provide the configuration. (It might not be provided from where you think it is, specifically check clojure-lsp's global config in you user home directory.) Use the command Calva Diagnostics: Clojure-lsp Server Info to see what cljfmt configuration is being used (under the cljfmt-raw key).

    Note that doing this you will not have hot reload of the formatting configuration, and of course you will be depending on that clojure-lsp is running and functioning.

    "},{"location":"formatting/#indentation-rules","title":"Indentation rules","text":"

    The cljfmt indents are highly configurable. They, and the rest of the configuration options, are masterly detailed here.

    :extra-indents vs :indents

    Since Calva v2.0.383 we are using cljfmt 0.11.x which has a breaking configuration change. From the cljfmt README:

    The :indents key has been split into :indents and :extra-indents. The :indents key replaces all default indents, while the :extra-indents key will append to the default indents.

    If something prevents you from using a config with :extra-indents, there's an escape hatch to keep using the :indents key as before, by adding :legacy/merge-indents? true to the config map.

    Calva is an extra good tool for experimenting with these settings. cljfmt doesn't care about keys in the map that it doesn't know about so you can sneak in test code there to quickly see how it will get formatted by certain rules. Try this, for instance:

    {:remove-surrounding-whitespace? true\n :remove-trailing-whitespace? true\n :remove-consecutive-blank-lines? false\n :insert-missing-whitespace? false\n :indents {#re \"^\\w\" [[:inner 0]]}\n :test-code\n (concat [2]\n         (map #(inc (* % 2))\n              (filter #(aget sieved %)\n                      (range 1 hn))))}\n

    Save, then hit tab, and the code should get formatted like so:

     :test-code\n (concat [2]\n    (map #(inc (* % 2))\n      (filter #(aget sieved %)\n        (range 1 hn))))\n

    That's somewhat similar to Nikita Prokopov's Better Clojure Formatting suggestion. (Please be aware that this setting might not be sufficient to get complete Tonsky Formatting, please share any settings you use to get full compliance.)

    "},{"location":"formatting/#rich-comments","title":"Rich Comments","text":"

    To encourage use of (comment ...) forms for development, the default settings give these forms get a special treatment when formatting. Use the calva.fmt.keepCommentTrailParenOnOwnLine setting to control this behaviour. See Rich Comments first.

    "},{"location":"formatting/#etecetera","title":"Etecetera","text":""},{"location":"formatting/#about-aligning-associative-forms","title":"About aligning associative forms","text":"

    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:

    • The implementation is a bit buggy and can do a bit crazy formatting on certain forms.
    • The older version of cljfmt lacks updates for some new Clojure features and also some bugs fixed since the fork are not applied.

    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.

    "},{"location":"get-started-with-clojure/","title":"Get Started with Clojure","text":"

    Welcome to a zero-install, interactive, guide to get you started with Clojure using:

    • Clojure
    • Gitpod (A development environment delivered via the web browser)
    • VS Code (Or Gitpod Code, actually. In your web browser.)
    • Calva (A Clojure extension to VS Code. The thing this site is about.)
    • Calva's Getting Started REPL
    I have VS Code and Java

    Clojure runs on the JVM. How to install it is a big topic. Since you have already done that, you can, if you want, choose to install Calva in your local VS Code and fire up the Getting Started REPL. By all means read this page anyway, you can just skip the Gitpod parts.

    Also: If you are using Windows your Java might have a bug that prevents things from working. Then you might want to defer fixing that and use the zero-install option first.

    Is Gitpod Code exactly as VS Code?

    Almost! But, yeah, there are some difference between regular VS Code and Gitpod's ditto. Most of it doesn't matter, but finding the main menu can be a bit tricky:

    ","boost":10},{"location":"get-started-with-clojure/#what-youll-learn","title":"What you'll learn","text":"
    • The basics of the Clojure language (at least the start of the basics)
    • The basics of the ClojureScript language (we won't be using ClojureScript, but it is same language \ud83d\ude00)
    • The basics of Calva (It's a bit as a side effect. You need it to learn Clojure this way, and by learning Clojure this way, Calva knowledge trickles in.)
    • What is meant by, and some ways to perform, Interactive Programming (aka REPL Driven Development)
    • Where to find Clojurians, i.e. folks who use Clojure and care about it (you will thus find help, the friendliest help you have ever seen a community provide)
    I am not convinced I should spend time on learning Clojure

    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:

    • Solving Problems the Clojure Way - with Rafal Dittwald (using JavaScript, so no new syntax to grasp to get the message)
    • Developer Ergonomics with VS Code, Clojure, and ClojureScript - with Peter Str\u00f6mberg
    • Clojure in VS Code Workflow using FizzBuzz - with Peter Str\u00f6mberg
    ","boost":10},{"location":"get-started-with-clojure/#what-you-wont-learn","title":"What you won't learn","text":"
    • How to install Clojure for your operating system of choice
    • About various old and new build and dependency tools
    • How to create projects and do real stuff
    Why won't I learn about this?

    All in due time. \ud83d\ude04 It can be a bit confusing with all the things you find out about installing Clojure and creating projects when searching for information about it. We want you to relax about all that and just enjoy learning a bit about this fantastic programming language and the wonderful mode of development it offers.

    There is a lot of info about this out there already. And since you will learn where to find Clojurians, you will also find guidance. But we suggest do these things later. First, let's focus on having fun with Interactive Programming!

    ","boost":10},{"location":"get-started-with-clojure/#what-you-need","title":"What you need","text":"
    • Curiosity about Clojure
    • A web browser
    The browser ate my keyboard shortcuts!

    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:

    • Undo (undoing something web browser related)
    • Select the line (focusing the browser URL input)
    • Open the command palette (opening a private browsing window. Looking at you Firefox.)
    • Escape key shortcuts (are you using VIM bindings in your browser?)

    Sometimes the workaround is to redefine the shortcuts in VS Code, sometimes making your web browser stop catching the shortcut.

    I am new to VS Code

    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.

    ","boost":10},{"location":"get-started-with-clojure/#how-it-works","title":"How it works","text":"
    1. You will open an instance of VS Code in a development environment running in the browser. The environment will have Java, Clojure tools, and Calva installed.
      • Gitpod Sign-in You will be asked to sign in to Gitpod, if you aren't already. You need to use the \u201dSign in with GitHub\u201d option.
    2. Instructions will be automatically displayed (very brief such, because it is mainly about firing up the Getting Started REPL)
    3. The guides are a mix of prose (in Clojure line comments), Clojure code, and exercises. What's extra poetic is that you will use Calva and Clojure to learn Calva and Clojure.

    Use a desktop/laptop computer. Even if it actually works on the phone, it is far from convenient.

    It sometimes takes a while (several minutes) for the environment to initialize. Take some deep breaths and be patient. \ud83d\ude0e

    ","boost":10},{"location":"get-started-with-clojure/#lets-go","title":"Let's go!","text":"

    Ready? Awesome. Click this button to start the guide in a new browser tab.

    https://gitpod.io/#https://github.com/PEZ/get-started-with-clojure Stuck? Something not working? Or just unclear?

    Please don't hesitate to reach out for help, should you get stuck. See below for where to find Clojurians. As for the Calva team, we are almost always (true story) to be found at the Clojurians Slack, especially in the #calva Channel. We are @pez and @bringe there.

    Happy Interactive Programming! \u2764\ufe0f

    ","boost":10},{"location":"get-started-with-clojure/#and-where-do-i-find-those-clojurians","title":"And where do I find those Clojurians?","text":"

    We Clojurians inhabit a lot of community platforms. I'll list some of the more popular ones here in some order of popularity.

    • The Clojurians Slack - by far the largest and most active Clojure community, the #beginners channel is spectacularly fantastic
    • ClojureVerse - a web forum. Lots of Clojurians, lots of Clojure knowledge collected, easy to search, easy to join
    • /r/Clojure - Reddit when Reddit is at its best, lots of Clojurians here
    • Clojurians on Zulip - An other web forum using the Zulip platform
    • On Discord there are two active servers: Clojurians and Discord

    You can also ask questions, and find answers, about Clojure at ask.clojure.org

    ","boost":10},{"location":"get-started-with-clojure/#learn-and-practice-clojure-using-rich-4clojure","title":"Learn and Practice Clojure using Rich 4Clojure","text":"

    If you like the style of interactive learning that this guide provides, you should definitely check Rich 4Clojure out. It also can be used in the zero-installed way.

    You can regard it as a companion to this guide. It is aimed at practicing Clojure, starting at the elementary levels, bringing you to advanced stuff.

    Can I use Rich 4Clojure instead of this guide?

    We suggest you start by opening up this guide and do the Calva part of the excerises. Then use the welcome_to_clojure.clj guide in combination with Rich 4Clojure..

    ","boost":10},{"location":"get-started-with-clojure/#run-the-clojure-exercism-track-in-your-browser","title":"Run the Clojure Exercism Track in your browser","text":"

    In a similar manner to the Get Started with Clojure project, you can run the Clojure Exercism Track in your browser without installing anything and with full Interactive Programming enabled using this Template project.

    ","boost":10},{"location":"get-started-with-clojure/#clojuredocs","title":"ClojureDocs","text":"

    Clojurians draw tremendous value from ClojureDocs. At ClojureDocs the concise documentation for Clojure core functions, etcetera, are amended with examples and advice from fellow Clojurians. Crowdsourcing at its very best! It is a big part of the reason why you won't find an abundance of Clojure information at StackOverflow.

    ","boost":10},{"location":"get-started-with-clojure/#other-learning-resources","title":"Other learning resources","text":"
    • CalvaTV - Calva's YouTube channel often focuses on beginning with Clojure and ClojureScript. Subscribe, please!
    • Clojure Beginner Resources - a much more comprehensive list than this one
    • clojure.org Getting Started - the source of truth, includes installing and stuff
    • The Exercism Clojure track - Learn solving carefully crafted Clojure exercises, get mentor feedback if you like.
    • Clojure for the Brave and True - helping you from beginner to pretty advanced stuff, very popular among Clojurians
    • on the code again - often features Clojure concepts, with snappy, well communicated, and entertaining videos
    • Clojure Koans with VS Code/Calva instructions
    ","boost":10},{"location":"get-started-with-clojure/#help-us-help-beginners","title":"Help us help beginners","text":"

    Give us feedback. Spread the word. Please consider:

    • Join the #improve-getting-started channel at the Clojurian Slack
    • Linking to this page from your blog
    • Tweeting about this guide
    • Contributing to the Calva project
    • Wearing Calva and RFC T-shirts
    • Starring these repositories:
      • Get Started with Clojure - (the repository powering this guide)
      • Rich 4Clojure
      • Clojure Exercism Track Template
      • Calva
      • Dram - Where this guide (the Getting Started REPL) is authored
    • What do beginners struggle with? - a ClojureVerse thread, where you can tell us about what you have found hard in picking up Clojure. It's what spawned the creation of this guide.

    Please also consider other ways to contribute.

    Thanks! \ud83d\ude4f

    ","boost":10},{"location":"getting-started/","title":"Getting Started","text":"

    Depending on wether you want to just start a Clojure REPL or you have a project you want to work with, getting started looks similar but a bit different. Regardless, you need to first:

    ","boost":10},{"location":"getting-started/#install-vs-code-and-calva","title":"Install VS Code and Calva","text":"
    1. Downloading VS Code and run the installer.
      • Also get aquainted to the basics of VS Code, if you aren't already. Here's an excellent intro: Getting Started with VS Code
    2. Install Calva. The easiest way to do that is to start VS Code and search for Calva in the VS Code Extension pane, then click Install.
    ","boost":10},{"location":"getting-started/#say-hello-to-calva","title":"Say hello to Calva","text":"

    If you have a Clojure or ClojureScript project, you will be interested in how to get Calva connected to the REPL of your project. But before you run over there, you might want to familiarize yourself with Calva a bit, which you can do without a project.

    The demo tells you about the command (and some about the Clojure Beginner's material that it makes available).

    I am completely new to Clojure

    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.

    I don't have Java installed

    If you like, you can defer installing anything at all and still get started with Calva (not kidding).

    See Get Started with Clojure.

    ","boost":10},{"location":"getting-started/#theres-a-getting-started-repl","title":"There's a \u201dGetting Started\u201d REPL","text":"

    If you are new to Calva, a good place to start is using the command Fire up the \u201dGetting Started\u201d REPL. (You can open the command palette using the VS Code top menu by going to View -> Command Palette... or by running the associated keyboard shortcut for your OS.) Demo:

    It will open up a three files in a temporary directory, and start and connect a REPL. The files are:

    • hello_repl.clj \u2013 The basics of how to evaluate code in Calva
    • hello_paredit.clj - A super brief intro to Calva structural editing
    • welcome_to_clojure.clj - The very basics of the Clojure language

    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.)

    Note

    On Windows the Oracle Java installer sets Java up in some funny way so that the Getting Started REPL fails to start. We are figuring about workarounds for this, but for now, if you are on Windows, you will need to make VS Code have some other Java in the PATH of its environment for this feature to work. See this issue on the Calva repo for more on this, including any progress.

    ","boost":10},{"location":"getting-started/#there-are-standalone-clojurescript-quick-start-repls","title":"There are standalone \u201dClojureScript Quick Start\u201d REPLs","text":"

    Without creating a project structure or installing anything but Calva, you can start standalone ClojureScript REPLs both in a browser and for node:

    • Fire up the ClojureScript Quick Start Browser REPL
      • Opens the files core.cljs and index.html and starts the ClojureScript app, opening it in the browser.
    • Fire up the ClojureScript Quick Start Node REPL
      • Opens a file, core.cljs, and starts a nodejs REPL where it loads the file.

    The browser REPL app looks like so:

    ","boost":10},{"location":"getting-started/#you-have-a-project","title":"You have a Project?","text":"

    If you are new to Calva, please consider the above option first. Then when it will be time to get Calva connected to the REPL of your project.

    ","boost":10},{"location":"getting-started/#clojure-resources","title":"Clojure Resources","text":"

    If you are new to Clojure or ClojureScript altogether, please check out the guide material on the respective official sites:

    • Getting Started with Clojure
    • ClojureScript Quick Start

    There are also many great books on Clojure. Clojure for the Brave and True can be read for free online. It is a great resource for beginners.

    ","boost":10},{"location":"getting-started/#there-is-also-standalone-repl","title":"There is also Standalone REPL","text":"

    When you are more familiar with Calva, and want a standalone REPL, there is a separate command: Start a standalone REPL (not in project). It will open up a user.clj in a temporary directory, containing only an (ns user) form, and start and connect the REPL.

    ","boost":10},{"location":"getting-started/#dram-where-the-guides-live","title":"Dram - Where the Guides Live","text":"

    The command for starting the Getting Started REPL will download the files from this repository. It is very much work in progress, and there is not even a finished Clojure Beginner's Guide there yet. When you run the command again, and from then on, you will get the option to download new files or keep using your existing. Downloading new ones will not overwrite your existing ones, because they will be downloaded to a new temp directory. You can find the directory easily using VS Codes context menu command for revealing a file in the Explorer/Finder.

    ","boost":10},{"location":"getting-started/#one-last-thing","title":"One Last Thing","text":"

    Happy coding! \u2665\ufe0f

    ","boost":10},{"location":"hiccup/","title":"Converting HTML to Hiccup","text":"

    Calva can help you convert HTML to Hiccup.

    ","boost":7},{"location":"hiccup/#features","title":"Features","text":"","boost":7},{"location":"hiccup/#three-commands","title":"Three commands","text":"
    • Convert HTML to Hiccup, will convert the selected text, or the entire file, to Hiccup and open up an Untitled Clojure file with the result.
    • Copy HTML as Hiccup, will convert the selected text, or the entire file, to Hiccup and copy it to the clipboard.
    • Paste HTML as Hiccup, will convert the contents of the clipboard to Hiccup and paste it. (The clipboard will then be restored to the original content.)

    The resulting data structure is formatted with zprint using it's :style :hiccup configuration.

    ","boost":7},{"location":"hiccup/#conversion-capabilities","title":"Conversion capabilities","text":"

    In addition to, optionally, being able to convert style attributes to maps and kebab-case attributes, the conversion:

    • Opts for producing compact Hiccup:
      • The id attribute and classes are made part of the tag, CSS selector style
        • <foo id=\"bar\"></foo> => [:foo#bar]
        • <foo class=\"c1 c2\"></foo> => [:foo.c1.c2]
        • <foo id=\"bar\" class=\"c1 c2\"></foo> => [:foo#bar.c1.c2]
      • Though, if the id or any class is not valid as part of a keyword, they remain in the props/attributes map)
        • <foo id='foo-[id]'></foo> => [:foo {:id \"foo-[id]\"}]
        • <foo class='clz1 clz[2]'></foo> => [:foo.clz1 {:class [\"clz[2]\"]}]
      • Whitespace is trimmed
        • <foo> \\nbar\\n </foo> => [:foo \"bar\"]
        • <foo> \\n </foo> => [:foo]
    • Handles boolean attributes
      • <foo disabled></foo> => [:foo {:disabled true}]
      • <foo disabled=disabled></foo> => [:foo {:disabled \"disabled\"}]
    • Special case for camelCasing attributes viewBox and baseProfile (SVG is picky about it)
      • <foo bAsePROFilE=bar viewbox=\"0 0 1 1\"></foo> => [:foo {:baseProfile \"bar\" :viewBox \"0 0 1 1\"}]
    • Comments are retained
      • <foo><!-- ... --></foo> => [:foo (comment \"...\")]
    • You can have several top level tags
      • <foo></foo><foo></foo> => [:foo]\\n[:foo]
    ","boost":7},{"location":"hiccup/#it-is-somewhat-configurable","title":"It is somewhat configurable","text":"

    The Hiccup converstion can be tweaked with two options using the setting calva.html2HiccupOptions, which is a map/object:

    • mapify-style: boolean, default false. When true any style attribute will be converted to a map (Reagent supports this)
    • kebab-attrs?: boolean, default false. When true attribute names will be converted from camelCase, or snake_case/SNAKE_CASE to kebab-case. (Reagent wants most attribute names like this.)
    • add-classes-to-tag-keyword?: boolean, default true. When true all class names will be added CSS-style to the tag keyword ([:tag.clz1.clz2]), as opposed to being kept in the class attribute. Keeping the class names in the attribute may be preferable with elements having a lot of class names, such as when using Tailwind CSS.
    ","boost":7},{"location":"hiccup/#copy-as-menus-copy-html-as-hiccup","title":"Copy as menus: Copy HTML as Hiccup","text":"

    The Copy HTML as Hiccup command is available from VS Code's Edit menu, as well as the editor context menu, in both cases under the Copy as sub menu.

    ","boost":7},{"location":"hiccup/#the-commands-take-arguments","title":"The commands take arguments","text":"

    This options map can also be provided as an argument to the commands, so you can bind keyboard shortcuts to a particular configuration for the conversion.

    The command calva.convertHtml2Hiccup takes a map as an argument:

    • toUntitled: boolean, default false. When false the result of the conversion will be returned to the caller (This is intended for Joyride, or some other VS Code extension). When true it will behave like the default command does, placing the result of the conversion in an Untitled Clojure file.
    • options: Same as those calva.html2HiccupOptions mentioned above.

    The calva.pasteHtmlAsHiccup and calva.copyHtmlAsHiccup commands takes only a calva.html2HiccupOptions map.

    ","boost":7},{"location":"hiccup/#example-keyboard-shortcuts","title":"Example keyboard shortcuts","text":"

    The commands have no default keyboard shortcuts, you use the Command Palette to execute them, or you bind your own shortcuts. Here are some examples:

        // calva.convertHtml2Hiccup\n    {\n        // With args, `\"toUntitled\": true` is necessary for keyboard shortcuts\n        // without it, the command just returns the result to the caller\n        \"key\": \"ctrl+alt+c ctrl+h\",\n        \"command\": \"calva.convertHtml2Hiccup\",\n        \"args\": {\"toUntitled\": true, \"options\": {\"mapify-style?\": false}}\n    },\n    {\n        // Only for completeness, providing the HTML is only useful from e.g. Joyride \n        \"key\": \"ctrl+alt+c shift+h\",\n        \"command\": \"calva.convertHtml2Hiccup\",\n        \"args\": {\"html\": \"<foo style='a: b' bar='baz'>gaz<foo>\", \"toUntitled\": true}\n    },\n    {\n        // Without args, the command uses the `calva.html2HiccupOptions` configuration\n        // And writes the results to an Untitled document\n        \"key\": \"ctrl+alt+c h\",\n        \"command\": \"calva.convertHtml2Hiccup\",\n    },\n\n    // calva.pasteHtmlAsHiccup\n    {\n        // Override the `calva.html2HiccupOptions` configuration\n        \"key\": \"ctrl+alt+h ctrl+v\",\n        \"command\": \"calva.pasteHtmlAsHiccup\",\n        \"args\": {\"mapify-style?\": true, \"kebab-attrs?\": true}\n    },\n    {\n        // Without args, the command uses the `calva.html2HiccupOptions` configuration\n        \"key\": \"ctrl+alt+h v\",\n        \"command\": \"calva.pasteHtmlAsHiccup\"\n    },\n\n    // calva.copyHtmlAsHiccup\n    {\n        // Override the `calva.html2HiccupOptions` configuration\n        \"key\": \"ctrl+alt+h ctrl+c\",\n        \"command\": \"calva.copyHtmlAsHiccup\",\n        \"args\": {\"mapify-style?\": false, \"kebab-attrs?\": true}\n    },\n    {\n        // Without args, the command uses the `calva.html2HiccupOptions` configuration\n        \"key\": \"ctrl+alt+h c\",\n        \"command\": \"calva.copyHtmlAsHiccup\"\n    },\n

    The default/args-less bindings are placed last because reasons.

    ","boost":7},{"location":"hiccup/#using-from-joyride-or-some-other-vs-code-extension","title":"Using from Joyride (or some other VS Code extension)","text":"

    As with any VS Code command using these from Joyride is a matter of calling executeCommand.

    ","boost":7},{"location":"hiccup/#calvapastehtmlashiccup-and-calvapastehtmlashiccup","title":"calva.pasteHtmlAsHiccup and calva.pasteHtmlAsHiccup","text":"
    (-> (vscode/commands.executeCommand \"calva.pasteHtmlAsHiccup\"\n                                    #js {:mapify-style? true})\n    (.then ...))\n\n(-> (vscode/commands.executeCommand \"calva.copyHtmlAsHiccup\"\n                                    #js {:mapify-style? true})\n    (.then ...))\n
    ","boost":7},{"location":"hiccup/#calvaconverthtml2hiccup","title":"calva.convertHtml2Hiccup","text":"

    Without options the command behaves just like selecting the command from the command palette. If there is a selection it will be converted, otherwise the whole file. The result will be opened in a new Untitled document.

    (-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\")\n    (.then ...))\n

    Called with arguments it will by default return an object with a .-result member which is a string with the Hiccup.

    (-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" \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

    To make it put the text in a new Untitled document instead, provide the argument option :toUntitled true

    (-> (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
    ","boost":7},{"location":"inspector/","title":"Unfold that data","text":"

    All REPL evaluation results are added to the Calva Inspector, a tree view that lets you expand and collapse Clojure data structures. (This happens in addition to results being printed to the configured Output Destination.)

    Only for realized data

    Results are added to the inspector after they have been processed by your pretty printer (if you have pretty printing enabled). This means that maxLength and maxDepth applies. The inspector can't be used to explore infinite sequences. Also, any metadata is lost in the translation.

    "},{"location":"inspector/#uifeatures","title":"UI/Features","text":"

    The inspector view can be placed in the left or right side bars, or in the bottom panel. It can also be placed as a section in an existing side bar view, or in split with any existing bottom panel view.

    Inspector items are not expandable until you make them so with the Inspect Result Item button. This is because parsing and building the structure for the tree can take a little while and we don't want it to lock the UI for you when you edit and evaluate code.

    Speaking of buttons. Items in the view have context commands that show up as buttons on hover. The Inspect Result Item button is one of them. All rows in the inspector have a Copy button, letting you copy the data at any folding level to the clipboard. All root items also have a Clear button for removing the item from the inspector.

    The view itself has two buttons, one for clearing all results and one for pasting whatever is on the clipboard as an inspector item.

    "},{"location":"inspector/#commands","title":"Commands","text":"

    These are the commands available for the inspector:

    • Calva: Reveal Inspector. Reveals/shows the inspector without focusing it. Default keybinding is ctrl+alt+o i
    • This command, when used from keyboard shortcuts or Joyride, has the command ID of calva.revealInspector, and takes an object argument: { focus: boolean, select: boolean, expand: boolean | number }. focus lets you focus the inspector view (or not), select and expand lets you select or expand the current item which, like with several of the inspector commands, will be the already selected item, or the topmost item if none is selected. It is passed to the TreeView backing the inspector, see the VS Code API docs regarding revealing tree view items for details.
    • Calva: Add Selection or Current Form to Inspector. Adds the current form (without evaluating it) to the inspector. If there is text selected, the command will add that text instead. (Only the first selection, if there are multiple). There is no default keybinding for this command.
    • This command has the ID of calva.addToInspector. The command takes an optional argument, a string to be added. This is meant for Joyride scripts that want to add things to the inspector.
    • Calva: Clear All Inspector Items. You can use the command or the button for this in the view. No default keybinding.
    • Calva: Paste as Inspector Item. Same as the view button. No default keybinding.
    • Calva: Inspect Item. Makes the selected item inspectable, expands it one level, selects it, and focuses the inspector. Works on the topmost item if none is selected. No default keybinding.
    • Calva: Copy Inspector Item. Copies the text of the selected inspector item, or the topmost item if none are selected. No default keybinding.
    • Calva: Clear Inspector Item. Clears the selected inspector item, or the topmost item if none are selected. No default keybinding.

    The VS Code Shortcuts editor is a good tool for looking up command IDs and, duh, register custom shortcuts for these commands.

    "},{"location":"inspector/#configuration","title":"Configuration","text":"

    The settings for the inspector are:

    • calva.autoOpenInspector: controls wether the view is revealed as part of connecting the REPL to Calva. It defaults to false.
    • calva.enableInspectorRainbow: when enabled, the inspector items representing collection types will be colored using the theme colors used by VS Code to color bracket pair levels.
    "},{"location":"inspector/#calvaenableinspectorrainbow-example","title":"calva.enableInspectorRainbow example","text":"

    Depending on your theme, enabling the inspector rainbow can make some items not display at all. This is because not all themes provide all (or any) bracket level colorings. You can define the missing ones, or all, levels in your settings JSON file. Here's an example harmonizing the levels coloring with the default Calva Highlight rainbow (included in the example for easy comparison):

      \"workbench.colorCustomizations\": {\n    \"[GitHub Light Default]\": {\n      \"editorBracketHighlight.foreground1\": \"#000\",\n    },\n    \"[GitHub Dark Default]\": {\n      \"editorBracketHighlight.foreground1\": \"#cccccc\",\n    },\n    \"editorBracketHighlight.foreground2\": \"#0098e6\",\n    \"editorBracketHighlight.foreground3\": \"#e16d6d\",\n    \"editorBracketHighlight.foreground4\": \"#3fa455\",\n    \"editorBracketHighlight.foreground5\": \"#c968e6\",\n    \"editorBracketHighlight.foreground6\": \"#999\",\n    \"terminal.ansiRed\": \"#ff7a5a\",\n  },\n  \"calva.highlight.bracketColors\": [\n    [\n      \"#000\",\n      \"#ccc\"\n    ],\n    \"#0098e6\",\n    \"#e16d6d\",\n    \"#3fa455\",\n    \"#c968e6\",\n    \"#999\",\n    \"#ce7e00\"\n  ],\n

    This is the setting used for the screenshot above. Here's a rainbow-only screenshot:

    Note that with the Calva Highlight rainbow colors, we use a tuple for light and dark theme colors. The VS Code theme color settings do not allow this, so if you need different colors for light and dark themes, you need to specify the exact theme. We do this in the example, since the default Calva Highlight rainbow needs different light/dark colors for the top level brackets.

    "},{"location":"jack-in-guide/","title":"Learn about Calva Jack-in","text":"

    The Calva Jack-In Academy, by @pez

    Like with CIDER Jack-in, Calva's let-me-help-you-start-your-project-and-connect feature might seem a bit mysterious. It really is helpful, but also really isn't mysterious. Here are a few things about it that is good to know about.

    Note

    If you came here to find out how to configure the versions of the dependencies that Calva Jack-in injects, see Customizing Calva - Jack-in Dependency Versions.

    ","boost":6},{"location":"jack-in-guide/#what-it-solves","title":"What it Solves","text":"

    At first it might seem that something like lein repl in a terminal and then connecting Calva is enough. It sometimes might be, but only if you are in luck. To provide many of its IDE features, Calva relies on nREPL middleware, mainly cider-nrepl and, for ClojureScript, piggieback. When starting your Clojure(Script) app and its REPL, it needs to be started with these dependencies satisfied. There are mainly three ways this can be achieved.

    1. In the project definition (files like project.clj, deps.edn, shadow-cljs.edn, and combination of these).
    2. In your user profile (files like ~/.lein/profiles.clj and ~/.clojure/deps.edn).
    3. On the command line.

    Because 1 and 2 are hard to keep in sync with the various editor environments people in your project might be using, Calva Jack-In is about 3.

    Ideally, you will be able to rid your project files completely of editor dependencies when people working on the project can rely on the Jack-In features of their Clojure editor.

    ","boost":6},{"location":"jack-in-guide/#a-controlled-shell-command","title":"A Controlled Shell Command","text":"

    At its core Calva Jack-In is just a glorified, REPL-starting, command-line. No, it is more than that, but anyway. The command line can look like so for a Leiningen project using legacy Figwheel for its ClojureScript assistance:

    lein update-in :dependencies conj '[nrepl\"0.6.0\"]' -- update-in :dependencies conj '[cider/piggieback\"0.4.1\"]' -- update-in :dependencies conj '[figwheel-sidecar\"0.5.18\"]' -- update-in :plugins conj '[cider/cider-nrepl\"0.22.4\"]' -- update-in '[:repl-options :nrepl-middleware]' conj '[\"cider.nrepl/cider-middleware\"]' -- update-in '[:repl-options :nrepl-middleware]' conj '[\"cider.piggieback/wrap-cljs-repl\"]' -- with-profile +dev repl :headless\n

    Even if a bit long, it might look simple enough. But actually it has taken quite some effort to make Calva craft it. Shell quoting can be really tricky. Look at how '[nrepl\"0.6.0\"]' doesn't have a space between nrepl and the version. That was the only way I could find that was cross platform enough to make all supported shells parse the command line. (The trick relies on that the string is read by the super reliable Clojure Reader, which does not need that space to tokenize it.)

    It is awesome that Clojure is used on so many platforms, but for a tool smith this also means more work. (I think Windows and its shell hell ate up about 95% of the many hours spent on getting the quoting good enough.)

    The command-line crafted is then used to start a shell command that Calva controls, but we are getting ahead of ourselves...

    ","boost":6},{"location":"jack-in-guide/#project-types-builds-aliases-profiles-etcetera","title":"Project Types, Builds, Aliases, Profiles, etcetera","text":"

    In order to cook the right command for your project, Calva looks for project files, reads them, and figures out what possible project types and ClojureScript tools could be involved. Then Calva presents you with a menu with the options it has found. You need to know enough about your project to answer this question. It looks like this in a shadow-cljs project that uses a deps.edn file for setting up its classpath.

    (I know enough about this particular project to know that I should choose the shadow-cljs project type.)

    But Calva isn't ready to cook the command-line just yet. Depending on the project type, and contents of your project files, more info is needed. E.g. in the case of shadow-cljs projects, Calva needs to know what builds to start.

    Here you can select any combination of builds defined in the project, and Calva will cook a command line that starts them.

    You might get more prompts from Calva before it issues the command, but for this example project, Calva goes ahead, cooks the command line, and issues it. On my Mac, it looks like so:

    npx shadow-cljs -d cider/piggieback:0.4.1 -d cider/cider-nrepl:0.22.4 watch :app\n

    (Much shorter than the one with lein-figwheel, right? It is because shadow-cljs is aware of CIDER dependencies, so it doesn't need as many dependencies specified as some other project types do.)

    ","boost":6},{"location":"jack-in-guide/#connecting","title":"Connecting","text":"

    When the command is issued Calva needs to wait until the REPL Server is started, before connecting to it and possibly continuing with starting a ClojureScript REPL and connecting to that as well. It also needs to know which port to connect to.

    Because reasons, Calva can't yet read the stdout of the shell command it has issued, so to know when the REPL server is started, and on which port, Calva monitors the filesystem for the .nrepl-port file. (This file is not always named like that. shadow-cljs, for instance, creates the file .shadow-cljs/nrepl.port.)

    When the port file is created, Calva picks up the port number from it and connects to the nREPL server. At this point you have a Clojure REPL backing your Calva session, providing all sorts of nice IDE help for you.

    ","boost":6},{"location":"jack-in-guide/#starting-your-clojure-app","title":"Starting Your Clojure App","text":"

    Once you have the Clojure REPL connected you can start your Clojure app/server. See Custom Connect Sequences for how to let Calva do this for you automatically. See the same article for ways to automate more of the Jack-In process. It can be brought down to a single Jack-In command/action, even for a full stack Clojure and ClojureScript application.

    ","boost":6},{"location":"jack-in-guide/#clojurescript","title":"ClojureScript","text":"

    For ClojureScript, things are not done yet, though, far from it. It turns out that cooking the command line was the easy part.

    In order for Calva to provide REPL power for ClojureScript projects, several things need to happen:

    1. A Clojure nREPL connection needs to be established. We've covered that above. Calva makes an nREPL session clone to use for the ClojureScript REPL and then:
    2. Your ClojureScript app needs to be compiled.
    3. Your ClojureScript app needs to be started.
    4. The Clojure nREPL session needs to be promoted to a ClojureScript nREPL session. (This is what piggieback helps with.)
    ","boost":6},{"location":"jack-in-guide/#compiling-the-app-and-watchers","title":"Compiling the App and Watchers","text":"

    Depending on ClojureScript project type, Calva uses different methods to start the compilation and the watcher:

    • Figwheel: The compilation and the watchers are started in the Clojure REPL session. (This is both for Figwheel Main and for lein-figwheel.)
    • shadow-cljs: The compilation and the watchers are started with the Jack-In command line.

    This results in a bit of difference in the user interaction. Mainly that for shadow-cljs, the user needs to check the Jack-In Terminal tab to follow what's going on.

    ","boost":6},{"location":"jack-in-guide/#starting-the-app","title":"Starting the App","text":"

    Number 3 above, the app needs to be started, might seem obvious, but it actually trips many people up. Because of this, Calva goes to quite some lengths to provide assistance. Many projects are configured not to spawn a browser session automatically, requesting the app once it has been compiled, so we can't rely on that.

    What Calva does instead is to monitor the output of the commands it uses for starting the compilation, looking for information that the app is ready to be requested/started. It then tells the user this, providing a URL, in case it is a browser app. (There are also settings that tell Calva to open the URL automatically for you, regardless what the project settings are.)

    ","boost":6},{"location":"jack-in-guide/#connecting_1","title":"Connecting","text":"

    Meanwhile, Calva is monitoring the output and when it sees that the app is started, it continues to hook up the REPL connection to the editor.

    This whole connection sequence is quite configurable, using Custom Connect Sequences. In fact, Calva's built in ClojureScript sequences (Figwheel Main, lein-figwheel, shadow-cljs, and ClojureScript built-ins for both Browser and Node) are all built using those same settings mechanisms.

    ","boost":6},{"location":"jack-in-guide/#shadow-cljs-is-less-managed-by-calva","title":"shadow-cljs is Less Managed by Calva","text":"

    NB: The managed way in which Calva creates and connects the ClojureScript REPL breaks apart a bit for shadow-cljs, which works a bit differently and also outputs most of the information Calva is looking for on the stdout of the REPL start command (where Calva can't see it, remember?). We'll figure out a better way to support shadow-cljs, but for now, the user needs to do more of this figuring out than is needed with Figwheel projects.

    ","boost":6},{"location":"jack-in-guide/#hack-away","title":"Hack Away","text":"

    So, there are things going on when you start Jack-In, and even more things for ClojureScript projects, but Calva tries to keep it together, so as a user it is a matter of paying attention and responding to a few prompts/menus with pre-populated options (prompts which can be configured away, even).

    ","boost":6},{"location":"jack-in-guide/#switch-clojurescript-builds","title":"Switch ClojureScript Builds","text":"

    Once the REPL is connected you might want to change which ClojureScript build you have Calva connected to. For this Calva has the Select CLJS Build Connection command. Please note that you can only switch between builds that you have started.

    ","boost":6},{"location":"jack-in-guide/#play-with-starting-the-cljs-repl-yourself","title":"Play With Starting the cljs-repl Yourself","text":"

    To get a good grip on what is going on when creating and connecting the ClojureScript REPL, I can recommend making a custom connect sequence which leaves the REPL unpromoted (e.g. give it nil as connectCode), and then evaluate the cljs-repl start commands yourself. So for instance, promoting it to a ClojureScript Node.js REPL looks something like so:

    user=> (require 'cljs.repl.node)\nuser=> (cider.piggieback/cljs-repl (cljs.repl.node/repl-env))\nClojureScript 1.10.844\nTo quit, type: :cljs/quit\nnil\ncljs.user=> |\n

    It is the piggieback middleware there telling you that you can unpromote the REPL by \u201devaluating\u201d :cljs/quit.

    ","boost":6},{"location":"jack-in-guide/#about-full-stack-applications","title":"About Full Stack Applications","text":"

    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.

    ","boost":6},{"location":"jack-in-guide/#please-grab-your-calva-jack-in-certificate","title":"Please Grab your Calva Jack-In Certificate","text":"

    There, you now know all there is to know about Calva Jack-In.

    Just kidding, there are a few more details to it, some of which might find their way into this article at a later time.

    To really get to know it all, you will need to spend some time with the Calva Jack-In code. Head over to the Calva Development Wiki to learn how to hack on Calva.

    ","boost":6},{"location":"joyride/","title":"Using Calva With Joyride","text":"

    Joyride is a VS Code extension for user space scripting of VS Code itself. You find the extension here. The scripting language for Joyride is the best you language imaginable: Clojure. And, as is proper for a Clojure implementation, it has a REPL, even an nREPL server.

    This means you can connect Calva to Joyride and interactively develop your VS Code scripts.

    This video shows Joyride in action, using Calva as the nREPL client.

    "},{"location":"joyride/#how-to-connect","title":"How to connect","text":"

    Once you have the Joyride extension installed you can start its REPL and connect Calva to it (a.k.a Jack-in).

    Start the Joyride REPL and Connect

    This 1 minute video shows the following steps:

    1. Installing the Joyride Extension
    2. Isssuing the command Calva: Start a REPL in your Project and (a.k.a Jack-in)
    3. Selecting joyride project type
    4. Isssuing the command Calva: Load/Evaluate Current File and its Requires/Dependencies
    5. Evaluating some non-vscode code
    6. Evaluating code exercising something from the VS Code API

    (Right-click the video and choose Full Screeen if it is too tiny embedded.)

    "},{"location":"joyride/#how-to-get-started-with-joyride","title":"How to Get Started with Joyride","text":"

    The Joyride README has some Quick Start pointers for you. Please feel invited to the #joyride channel on the Clojurians Slack and chat with us and other Joyride users.

    Come on, Join the Joyride! \u2764\ufe0f

    "},{"location":"krell/","title":"Using Calva With Krell","text":"

    Krell is \u00e0 la carte ClojureScript tooling for React Native.

    Even if Calva does not yet have built-in support, all is not lost. You can add support yourself by way of a Custom REPL Connect Sequence. Here's how;

    "},{"location":"krell/#starting-the-krell-clojurescript-repl","title":"Starting the Krell ClojureScript REPL","text":"

    Add this REPL Connect Sequence to your workspace settings.json:

        \"calva.replConnectSequences\": [\n        {\n            \"name\": \"deps.edn + Krell\",\n            \"projectType\": \"deps.edn\",\n            \"cljsType\": {\n                \"connectCode\": \"(require '[clojure.edn :as edn] \\n    '[clojure.java.io :as io]\\n    '[cider.piggieback] \\n    '[krell.api :as krell]\\n    '[krell.repl])\\n\\n(def config (edn/read-string (slurp (io/file \\\"build.edn\\\"))))\\n(apply cider.piggieback/cljs-repl (krell.repl/repl-env) (mapcat identity config))\",\n                \"dependsOn\": \"User provided\"\n            }\n        }\n    ]\n

    Then issue the command Start a Project REPL and Connect (aka Jack-In). It start the project and connect to the Krell REPL once the app is running on a device (wether real or virtual/emulated).

    "},{"location":"krell/#additional-vs-code-tips","title":"Additional VS Code Tips","text":"

    For a smooth workflow you can also:

    • Install the React Native Tools extension
    • Install the Debugger for Chrome extension, and add this Launch Configuration
              {\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:

    1. Open the project root in VS Code
    2. Issue the Jack-in command
    3. Issue the React Native; Run Android on Emulator (or Run iOS on Simulator) command. (Disable Fast Refresh from the *React Native dev menu, if it is enabled.)
    4. Issue the React Native: Run Element Inspector command (You might need to install the React Native inspector globally): ```sh yarn global add react-devtools ````
    5. Launch Debugger (F5)
    6. Hack away, with hot reload and interactive REPL

    Once the debugger (a Chrome session) is running, you probably will want to enable Custom Formatters in order for clojure structures to be logged conveniently.

    "},{"location":"linting/","title":"Linting","text":"

    Calva does no linting, yet with Calva you get excellent linting. That is because Calva uses clojure-lsp, which provides linting powered by clj-kondo.

    clj-kondo comes with great default rules, and the configuration can be customized. One of your options for the configuration file is to placed a config.edn file in .clj-kondo/ at the root of your project. This folder may or may not already exist. It is safe to create it manually if it doesn't.

    The configuration will be merged with the default set of rules, you can only specify the rules you want to override. The full list of available options can be found on clj-kondo's github

    clojure-lsp is customizable, see Clojure LSP Settings for your options. It is safe to manually create the .lsp folder if it doesn't exist.

    You might want to read about how to configure clj-kondo. These two sections might be of extra interest:

    • Unrecognized macros
    • Lint a custom macro like a built-in macro

    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.

    "},{"location":"linting/#resolve-macro-as","title":"Resolve Macro As","text":"

    When your cursor is on a macro form in the editor, you may notice a code action (click the light bulb that appears) called Resolve Macro As. Running this code action will ask you what macro you'd like to resolve the current macro as, and then what clj-kondo config file you want the macro to be saved to. This code action is also available as a command.

    "},{"location":"live-share/","title":"Using Calva with Live Share","text":"

    Live Share is a Microsoft provided VS Code extension. It allows you to share the workspace that you have open in your computer with somebody else. Everybody is then working on the same source code files, namely those on your computer. You can edit files at the same time, everyone has their own caret. You can follow each other (i.e. when someone switches to a different file, you will as well). This is great for remote pair programming, for example.

    An extra nice thing is that each participant is using their own VSCode configuration, including fonts, colors, keyboard shortcuts, etc.

    Disable Calva Spritz to get rid of Notebooks interference

    The headline below Calva Supports Live Share is true. However, due to a bug in LiveShare, guest participants always get their Clojure files opened in the Calva Clojure Notebooks editor. To workaround this issue Calva uses a \u201dside-car\u201d extension named Calva Spritz for the Notebooks associations of Clojure files. You can disable that extension when participating in LiveShare sessions.

    "},{"location":"live-share/#calva-supports-live-share","title":"Calva Supports Live Share","text":"

    When using Calva, you can use Live Share as well. Editing works exactly the same as for any other programming language. What makes Calva a bit special, is the REPL. When using Live Share, Calva allows the host to share the REPL with guests as well. If you use any of the supported configuration, this will be pretty much automatic.

    You need to enable the LiveShare support

    Due to an issue in the LiveShare API, for some users, this feature stops Calva from connecting the REPL. Therefore the support is disabled by default. The setting is calva.useLiveShare.

    This is what a typical scenario looks like:

    1. The host jacks-in.
    2. The host shares its workspace using Live Share. Calva will detect that the workspace is being shared, so it will offer to share the REPL port that was opened when jacking in. The host clicks \"Allow\" to start sharing the port. (Note: steps 1 and two can also be done in the reverse order.)
    3. The host sends the Live Share URL to the guest(s).
    4. The guest joins the Live Share session using the URL it received.
    5. The guest connects to the host's REPL using the command \"Connect to a running REPL server in the project\". If needed, the guest chooses the same build configuration as the host.

    Voila! Both the guest and the host can now use the REPL that is running on the host. Things like documentation lookup now also work on the guest's machine.

    "},{"location":"live-share/#control-visibility-of-calva-folder","title":"Control Visibility of .calva Folder","text":"

    Calva depends on the output.calva-repl file to be available. If you have the .calva folder listed in your .gitignore, this also causes the folder to be hidden from guests in Live Share by default. In order to make the folder visible, you can put a file called .vsls.json in your project. In its simplest form, the contents can be this:

    {\n  \"$schema\": \"http://json.schemastore.org/vsls\",\n  \"hideFiles\": [\n    \"!.calva\"\n  ]\n}\n

    Now the .calva folder is shared as well. But also any other file and folder that you may have in your .gitignore. If you want to have more fine-grained control, please refer to the section Controlling file access and visibility of the Live Share documentation.

    "},{"location":"live-share/#some-things-to-keep-in-mind","title":"Some Things To Keep In Mind","text":"
    • As a guest, you're connected to a REPL running on the host's machine. With power comes responsibility; be nice, and be careful!
    • There is only one output.calva-repl file, which all participants are sharing. It may work better to evaluate things in the source code editors instead of from the REPL window. Otherwise you will end up in a situation where one person is typing something in the output.calva-repl window, and somebody else is evaluating something (hence sending the output there) at the same time. That gets confusing quickly.
    • When you're working on a CLJS-based web development project, things may get extra confusing. By default, Live Share will share any HTTP ports on the host automatically, and also offer to open the URL on the guest. (You can disable using the setting \"Liveshare: Open Shared Servers\".) As a guest, you do not want to open that browser window normally. Think about it: where is the REPL running? Yes: in the browser! But Calva connects to the REPL running in the browser on the host's machine, so if you open a browser as a guest, you will also get a REPL there, but you won't be connected to it in Calva.
    • Currently Live Share does not allow Calva to know whether the workspace is shared read-only or read-write. If you share read-only, and you don't want the guests to have access to your REPL, don't click \"Allow\" when VSCode asks you to share the REPL port.
    "},{"location":"live-share/#calva-spritz","title":"Calva Spritz","text":"

    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 issue: LiveShare participants incorrectly opening every Clojure file as if via \"Open with Notebook\"
    • LiveShare issue: Guest opens Clojure file as a notebook (incorrectly)

    Calva Spritz can be disabled and enabled at will, and it will take immediate effect, without any reload of VS Code needed.

    "},{"location":"luminus/","title":"How to Use Calva with Luminus","text":"

    Luminus is a powerful and versatile Leiningen template for creating web development projects. It comes with built in configuration which makes it easy to use Calva as your Clojure(Script) editor.

    "},{"location":"luminus/#server-shadow-cljs","title":"Server + shadow-cljs","text":"

    Basically this is the same wokflow as with Server only. Behind the scenes there is more happening, though. Such as the ClojureScript app being built and the CLJS REPL connected once the web app is running.

    1. If you haven't created the project yet, create a new shadow-cljs Luminus project. E.g.:
      $ lein new luminus my-luminus-shadow +reagent +re-frame +shadow-cljs\n
    2. Install npm dependencies
      $ npm i\n
      (Or yarn if you prefer.)
    3. This creates the folder my-luminus-shadow. Open it in VS Code:
      $ code my-luminus-shadow\n
    4. Use the Calva command Start a Project REPL and Connect (aka Jack-in): ctrl+alt+c ctrl+alt+j
    5. Select to start my-luminus-shadow Server + Client, and wait for the Terminal Calva Jack-in output to say [:app] Build completed.
    6. Open 127.0.0.1:3000 in your web browser and start hacking.

    Note

    Currently Calva has troubles following the app-start with shadow-cljs, so Calva will report Jack-in done. in the output window before shadow-cljs is actually done building the app. If you open the app page at that stage, you will see a message to \u201cPlease run lein shadow watch app\u201d. Rest assured that this is already underway. Follow the Jack-in process in the Terminal tab in VS Code for the message that the app is built, then reload the app page in the web browser.

    "},{"location":"luminus/#server-only","title":"Server Only","text":"

    The workflow here is really just: Jack-in and start hacking. However, the first time it will involve these steps:

    1. If you haven't created the project yet, create a new server only Luminus project. For a all-defaults setup it is like so:
      $ lein new luminus my-luminus-server\n
    2. This creates the folder my-luminus-server. Open it in VS Code:
      $ code my-luminus-server\n
    3. Use the Calva command Start a Project REPL and Connect (aka Jack-in): ctrl+alt+c ctrl+alt+j
      • Select to start my-luminus-shadow Server and wait until you see Jack-in done. in the output window.
    4. Open 127.0.0.1:3000 in your web browser and start hacking.
    "},{"location":"luminus/#server-figwheel","title":"Server + Figwheel","text":"

    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:

    1. If you haven't created the project yet, create a new server only Luminus project. E.g.:
      $ lein new luminus my-fw +reagent\n
    2. This creates the folder my-fw. Open it in VS Code:
      $ code my-fw\n
    3. Use the Calva command Start a Project REPL and Connect (aka Jack-in): ctrl+alt+c ctrl+alt+j, select Server + Client - my-fw in the Project type picker menu, and wait for the web app to pop open in your web browser.
    4. Start hacking.

    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.

    "},{"location":"luminus/#etcetera","title":"Etcetera","text":"

    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:

    1. Start <project> Server
    2. Stop <project> Server
    3. Restart <project> Server

    When used, Calva will open its REPL window and execute the command, if it is not already opened. You can close this window if you prefer to use the REPL directly from the Clojure files.

    Calva also opens the REPL window, and starts the Luminus server, as part of the Jack-in process.

    "},{"location":"merch/","title":"Calva Merch","text":"

    In this video, there is a question about where you can buy the Calva T-shirt:

    You couldn't, then. But now you can! On Amazon.

    Zero profit

    To keep the admin of this shop to a minimum the merch is sold at production prize (or as close to production prize as the respective store allows). There is no royalty going to anyone in the Calva team when you buy one of these t-shirts. You will represent, which is certainly a way to support the project. You are of course encouraged to support us via sponsoring as well:

    • Sponsor Peter Str\u00f6mberg
    • Sponsor Brandon Ringe

    Calva Merch is available on Zazzle and on Amazon

    ","boost":10},{"location":"merch/#zazzle","title":"Zazzle","text":"","boost":10},{"location":"merch/#calva-symbol-sticker","title":"Calva Symbol Sticker","text":"Calva Symbol Sticker by BetterThanTomorrow","boost":10},{"location":"merch/#joyride-symbol-sticker","title":"Joyride Symbol Sticker","text":"Joyride Symbol Sticker by BetterThanTomorrow","boost":10},{"location":"merch/#amazon-merch","title":"Amazon Merch","text":"","boost":10},{"location":"merch/#the-designs","title":"The designs","text":"

    There are four design, all featuring the Calva symbol (the Calva glass), which are all available for a Standard T-shirt, in men's, women's and kid's cut, and in some different colors. In the .com store there are also Premium T-shirts**.

    ","boost":10},{"location":"merch/#symbol-logo","title":"Symbol + Logo","text":"

    Available at:

    • https://www.amazon.com/dp/B09BCVH9SC (Premium T-shirt)
    • https://www.amazon.com/dp/B097TB5QFW
    • https://www.amazon.de/dp/B098GWQC6M
    • https://www.amazon.co.uk/dp/B098KM9XMF
    • https://www.amazon.fr/dp/B0994TYXTN
    • https://www.amazon.it/dp/B099KLJJV1
    • https://www.amazon.es/dp/B099NXR71Y
    • https://www.amazon.co.jp/dp/B097YZVMC4
    ","boost":10},{"location":"merch/#symbol-logo-we-do-it-with-rich-comments","title":"Symbol + Logo + We do it with Rich Comments","text":"

    The Calva symbol and Logo front, Rich Comments back.

    Available at:

    • https://www.amazon.com/dp/B09C4PBH5N (Premium T-shirt)
    • https://www.amazon.com/dp/B09BFMRCHL
    • https://www.amazon.de/dp/B09C3VYZH8
    • https://www.amazon.co.uk/dp/B09BLD2BVJ
    • https://www.amazon.fr/dp/B09C3X1H7K
    • https://www.amazon.it/dp/B09C3WV2JQ
    • https://www.amazon.es/dp/B09C4P1GD1
    • https://www.amazon.co.jp/dp/B09C4P45MR
    ","boost":10},{"location":"merch/#symbol-only","title":"Symbol Only","text":"

    Available at:

    • https://www.amazon.com/dp/B09B83481D (Premium T-shirt)
    • https://www.amazon.com/dp/B097TB5QFW
    • https://www.amazon.de/dp/B098434W9M
    • https://www.amazon.co.uk/dp/B098KNGPBB
    • https://www.amazon.fr/dp/B099RZGNN7
    • https://www.amazon.it/dp/B099WYH94Z
    • https://www.amazon.es/dp/B09B2TFCSR
    • https://www.amazon.co.jp/dp/B09B4XN3HY
    ","boost":10},{"location":"merch/#symbol-we-do-it-with-rich-comments","title":"Symbol + We do it with Rich Comments","text":"

    The Calva symbol front, Rich Comments Back.

    Available at:

    • https://www.amazon.com/dp/B098M34FKJ (Premium T-shirt)
    • https://www.amazon.com/dp/B0993VCG7P
    • https://www.amazon.de/dp/B098MF14PV
    • https://www.amazon.co.uk/dp/B098P1MV44
    • https://www.amazon.fr/dp/B098TPQFCJ
    • https://www.amazon.it/dp/B098YP33ZL
    • https://www.amazon.es/dp/B098RDPK55
    • https://www.amazon.co.jp/dp/B0992MQYG6

    Note

    What's available on this or that Amazon site will vary a bit and it is a bit slow to add a particular design to a particular market. Eventually I hope to have both designs up on these markets: .com, .co.uk, .de, .fr, .it, .es, and .co.jp

    ","boost":10},{"location":"namespace-form-auto-creation/","title":"Namespace Form Auto-creation","text":"

    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.

    "},{"location":"nbb/","title":"Using Calva with nbb","text":"

    Since nbb can be started such that it is an nREPL server, Calva can connect to it and a lot of the features will work.

    Calva can also start nbb and connect its REPL for you, using the Jack-in command. This will start an nbb nREPL server on a random port and connect Calva to it. Check out this video where they use Calva and nbb to create a CLI tool as an executable npm module:

    In that video they ask for a JavaScript to ClojureScript converter. And there is one: https://mauricioszabo.gitlab.io/js2cljs/

    Though if you are using Calva, this converter is easier to use directly via the command Calva: Convert JavaScript to ClojureScript:

    Errors jacking in to nbb on Windows?

    On some machines it seems necessary to first run npx nbb from the CMD prompt to make jack-in work. Or try first install it npm i -g nbb. (You probabl want nbb installed globally anyway.)

    Don't expect complete support

    nbb's nREPL server is completely new and and WIP. It will be a bit limited compared to a full cider-nrepl enhanced \"regular\" Clojure nREPL server. Things like function signatures, and more do not work.

    It's a bit hacky

    The nbb nREPL server is the first ClojureScript nREPL server around and throws Calva's assumption that an nREPL server is always started in a Clojure process out the window. The nbb Jack-in/connect option \u201dpretends\u201d it is connecting to a Clojure nREPL and then the code fro promoting the nREPL session to a ClojureScript one is just dummy code.

    This means that if you open a Clojure (.clj) file while connected to an nbb nREPL server, it will still be a ClojureScript session serving even though Calva will indicate that it is a Clojure one. Bare with us until we can fix this properly in Calva.

    ","boost":4},{"location":"notebooks/","title":"Clojure Notebooks","text":"

    WIP: Notebook support is very basic and experimental

    • You might experience loss of file contents when saving a Clojure Notebook. Have backups of any files you open as notebooks.
    • Tooling around autocomplete, go to def, linting and such does not work at all yet.
    • There is no Markdown support.
    • Etcetera. As if this was not enough, notebooks can also interfere with LiveShare support.

    Please help test the feature. We're looking forward to your feedback!

    You can open any Clojure file as a notebook by right clicking the file -> Open with... -> Clojure Notebook.

    Running cells sends them to the REPL and pretty prints the results. If the return is a string that starts with <html it will be displayed in an html webview.

    Forms inside (comment) blocks get shown as their own cells. When adding code blocks in between those cells they get saved with the same indentation as the first form.

    ","boost":1},{"location":"notebooks/#calva-spritz","title":"Calva Spritz","text":"

    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:

    • Calva issue: LiveShare participants incorrectly opening every Clojure file as if via \"Open with Notebook\"
    • LiveShare issue: Guest opens Clojure file as a notebook (incorrectly)
    ","boost":1},{"location":"nrepl_and_cider-nrepl/","title":"nREPL and cider-nrepl","text":"

    nREPL and cider-nrepl middleware enable Calva to support full Interactive Programming.

    ","boost":2},{"location":"nrepl_and_cider-nrepl/#about-nrepl","title":"About nREPL","text":"

    The REPL is a Clojurists quintessential tool, it\u2019s what we use to do Interactive Development, the hallmark of the LISP style of development.

    In Interactive Development (more commonly but somewhat imprecisely referred to as REPL-driven development), the programmer\u2019s editor has a direct connection with the running application process. This allows evaluating pieces of code in the context of a running program, directly from where the code is written (and so not in some separate \u201cREPL place\u201d), inspecting and manipulating the innards of the process. This is helped along by the dynamic nature of Clojure in which any var can be redefined at any point, allowing for quick incremental and iterative experimentation and development.

    This is why it\u2019s essential to the Clojure development experience to have proper editor support, a plugin which bridges the gap between where the code is written and where the code is run. So we have CIDER for Emacs, Calva for VS Code, Cursive for IntelliJ, Conjure or Iced for Vim, and so forth. Often these will also leverage the same (or a parallel) connection into the process for other editor affordances, like navigation and completion.

    But for these editor plugins to connect to the Clojure process something needs to be listening on the other side, accepting connections, allowing the initiation of a program-to-program dialogue. The most common way to achieve this is by leveraging the nREPL protocol, an asynchronous message-based network protocol for driving interactive development. The application process is started with an embedded nREPL server, so that the editor can connect as an nREPL client.

    From: Lambda Island

    ","boost":2},{"location":"nrepl_and_cider-nrepl/#about-the-nrepl-server-and-middleware","title":"About the nREPL Server and Middleware","text":"

    nREPL is an extensible protocol, the reference server implementation understands certain core operation types like \"eval\". More operations can be supported, or existing operations can be modified or augmented, through nREPL middleware. For example: the Piggieback middleware can intercept \"eval\" messages, and forward them to a ClojureScript environment, rather than evaluating them in the Clojure process itself.

    Which middleware to use will mostly depend on the editor you are using. You\u2019ll typically find that the Clojure-specific functionality for a given editor is partly implemented as a typical editor extension, for instance CIDER written in Emacs LISP, or Calva written in Typescript, and partly as nREPL middleware, providing the functionality the editor extension relies on. For instance, both CIDER and Calva rely on functionality provided by cider-nrepl.

    Also from: Lambda Island

    ","boost":2},{"location":"nrepl_and_cider-nrepl/#viewing-the-communication-between-calva-and-nrepl","title":"Viewing the Communication Between Calva and nREPL","text":"

    You can view the messages sent between Calva and nREPL by running the command Toggle nREPL Logging Enabled. Enabling nREPL message logging triggers the creation of a VS Code output channel called nREPL Messages where the messages will be logged. Messages sent to nREPL from Calva will have -> sent above them, and messages sent from nREPL to Calva will have <- received above them. Disabling nREPL message logging causes the nREPL Messages channel to be removed and messages will no longer be logged.

    Each message is logged as JSON. If you find a need for the messages to be logged as EDN (for example, to transform and analyze them with Clojure) please open a GitHub issue for this change. A PR would be welcome too!

    The example below shows two messages logged when the cursor hovers over println in a Clojure file while a REPL is connected.

    -> sent\n{\n  op: 'info',\n  ns: 'test-lein.core',\n  symbol: 'println',\n  id: '7',\n  session: '1a080b66-b1b6-4b8c-8206-c4af2cc02747'\n}\n\n<- received\n{\n  added: '1.0',\n  'arglists-str': '[& more]',\n  column: 1,\n  doc: 'Same as print followed by (newline)',\n  file: 'jar:file:/Users/brandon/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar!/clojure/core.clj',\n  id: '7',\n  line: 3733,\n  name: 'println',\n  ns: 'clojure.core',\n  resource: 'clojure/core.clj',\n  'see-also': [\n    'clojure.core/prn',\n    'clojure.core/print',\n    'clojure.core/println-str',\n    'clojure.pprint/pprint'\n  ],\n  session: '1a080b66-b1b6-4b8c-8206-c4af2cc02747',\n  static: 'true',\n  status: [ 'done' ]\n}\n
    ","boost":2},{"location":"output/","title":"Output Destinations","text":"

    Calva categorizes output into three types:

    • evaluation results: Clojure data returned from an evaluation.
    • evaluation output: stdout/stderr from an evaluation
    • other output: Other messages, logs, etc

    With the setting calva.outputDestinations, you can configure where each category of output should go to:

    • the REPL Window
    • the Calva Says Output Channel
    • the Calva Output (pseudo) Terminal

    The reason there are several options for this is partly legacy and partly because VS Code restricts the placement of different views in different ways. We hope you will find a combination of output destinations that suits you.

    "},{"location":"output/#commands-for-showing-output-destinations","title":"Commands for showing output destinations","text":"

    These are the commands and their default keyboard shortcuts for revealing output destinations

    • Calva: Show/Open the result output destination - ctrl+alt+o o
    • Calva: Show/Open the Calva says Output Channel - ctrl+alt+o c
    • Calva: Show/Open the Calva Output Terminal - ctrl+alt+o t
    • Calva: Show/Open REPL Window - ctrl+alt+o r
    "},{"location":"output/#about-stdout-in-the-repl-window","title":"About stdout in the REPL Window","text":"

    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.

    "},{"location":"output/#repl-process-output-stdout-and-stderr","title":"REPL process output (stdout and stderr)","text":"

    When Calva is connected to the REPL, the Output window will by default print not only results of evaluations, but also:

    1. Things printed to stdout and stderr in the main thread of the evaluations
    2. Things printed to stdout and stderr from child threads of the evaluations
    3. Anything printed to stdout and stderr by the REPL process

    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).

    "},{"location":"output/#see-also","title":"See also","text":"
    • The Calva Results Inspector
    • The REPL Window
    "},{"location":"paredit/","title":"Paredit \u2013 a Visual Guide","text":"

    Structural editing and navigation for Clojure.

    ","boost":7},{"location":"paredit/#what-is-paredit","title":"What is Paredit?","text":"

    Calva Paredit helps you navigate, select and edit Clojure code in a structural way. LISP isn't line or character oriented, it is based around S-expressions, a.k.a forms. We strongly recommend that you take advantage of the structural nature of Clojure, and have therefore put a lot of work into making Calva Paredit extra awesome.

    If you are new to Paredit, consider starting with learning the Slurp Forward (pull in the next form into this form) and Barf Forward (push the last form out of this form). It will take you quite far.

    ","boost":7},{"location":"paredit/#strict-mode","title":"Strict Mode","text":"

    To protect the integrity of your code, Strict mode is enabled by default.

    Strict mode keybinding Action Description backspace Delete Backward Deletes one character backwards, unless it will unbalance a form. Otherwise moves past the character instead of deleting it. If the list is empty, it will remove both open and close brackets. delete Delete Forward Deletes one character forwards, unless it will unbalance a form. Otherwise moves past the character instead of deleting it. If the list is empty, it is removed. alt+backspace Force Delete Backward Deletes one character backwards, even if it will unbalance a form. alt+delete Force Delete Forward Deletes one character forwards, even if it will unbalance a form.

    Disable at your own peril. Strict mode can be toggled on/off using the Toggle Paredit Mode command, and there is a status bar indicator telling you:

    Indicator Paredit Mode [\u03bb] Strict (\u03bb) Cave Man (strict mode off) \u03bb No default key bindings

    Toggle between Strict and Cave Man using: ctrl+alt+p ctrl+alt+m

    ","boost":7},{"location":"paredit/#a-keybinding-for-protecting-the-structure-from-semi-colon","title":"A keybinding for protecting the structure from semi-colon","text":"

    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 together with the other Strict mode commands:

    {\n    \"command\": \"paredit.insertSemiColon\",\n    \"key\": \";\",\n    \"when\": \"calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap == strict && !editorReadOnly && !editorHasMultipleSelections && !calva:cursorInComment\"\n },\n
    ","boost":7},{"location":"paredit/#commands","title":"Commands","text":"

    The Paredit commands are sorted into Navigation, Selection, and Edit. As mentioned, Slurp and Barf are power commands, which go into the editing category. Learning to navigate structurally, using shortcuts, also saves time and adds precision to your editing. It has the double effect that you at the same time learn how to select structurally, because that is the same, just adding the shift key.

    To make the command descriptions a bit clearer, each entry is animated. When you try to figure out what is going on in the GIFs, focus on where the cursor is at the start of the animation loop.

    ","boost":7},{"location":"paredit/#command-args","title":"Command Args","text":"

    Some Paredit commands accept arguments. You can utilize this in keybindings and from Joyride.

    ","boost":7},{"location":"paredit/#copy-for-all-kill-commands","title":"copy for all kill* commands","text":"

    When specified, will control whether killed text will be copied to the clipboard. This is an alternative to, or supports binding-specific overrides for, calva.paredit.killAlsoCutsToClipboard.

    For example, here's 2 keybindings for paredit.killRight with different copy args, allowing you to choose when or if you want killed text copied at keypress-time, regardless of global calva.paredit.killAlsoCutsToClipboard setting:

    {\n  \"key\": \"ctrl+k\",\n  \"command\": \"paredit.killRight\",\n  \"when\": \"... your when conditions ...\",\n  \"args\": {\"copy\": false}\n},\n{\n  \"key\": \"cmd+k ctrl+k\",\n  \"command\": \"paredit.killRight\",\n  \"when\": \"... your when conditions ...\",\n  \"args\": {\"copy\": true}\n},\n

    Or, you can even have both of them use the same key, but separate when conditions to taste, to allow context-conditional copying.

    ","boost":7},{"location":"paredit/#strings-are-not-lists-but-anyway","title":"Strings are not Lists, but Anyway...","text":"

    In Calva Paredit, strings are treated in much the same way as lists are. Here's an example showing Slurp and Barf, Forward/Backward List, and Expand Selection.

    ","boost":7},{"location":"paredit/#navigating","title":"Navigating","text":"

    (Modify these with shift to select rather than move, see below.)

    Default keybinding Action Description ctrl+right (win/linux)alt+right (mac) Forward Sexp Moves the cursor forward, to the end of the current form. If at the end, moves to the end of the next form. Will not move out of lists. ctrl+left (win/linux)alt+left (mac) Backward Sexp Moves the cursor backward, to the start of the current form. If at the start, moves to the start of the previous form. Will not move out of lists. ctrl+down Forward Down Sexp Moves the cursor into the following list. ctrl+alt+up Backward Down Sexp Moves the cursor into the preceding list. ctrl+alt+down Forward Up Sexp Moves the cursor forwards, out of the current list. ctrl+up Backward Up Sexp Moves the cursor backwards, out of the current list. Unbound Forward Sexp Or Up Moves the cursor forward, to the end of the current form. If at the end, moves to the end of the next form. Moves out of the lists if at the end of it. Unbound Backward Sexp Or Up Moves the cursor backward, to the start of the current form. If at the start, moves to the start of the previous form. Moves out of the list if at the start of it. ctrl+end Forward to List End/Close Moves the cursor forwards, staying within the current list. ctrl+home Backward to List Start/Open Moves the cursor backwards, staying within the current list.","boost":7},{"location":"paredit/#selecting","title":"Selecting","text":"

    Most of these commands are selecting \u201dversions\u201d of the navigation commands above. Repeated use will grow the current selection step by step.

    Default keybinding Action Description shift+alt+right (win/linux)ctrl+w (mac) Expand Selection Starts from the cursor and selects the current form. Then will keep expanding to enclosing forms. shift+alt+left (win/linux)ctrl+shift+w (mac) Shrink Selection Contracts back from an expanded selection performed by any Paredit selection command. (In the animation the selection is first grown using a combination of Expand Selection and some lateral selection commands, then shrunk all the way back down to no selection.) ctrl+alt+w space Select Top Level Form Top level in a structural sense. Typically where your(def ...)/(defn ...) type forms. Please note that(comment ...) forms create a new top level. shift+ctrl+right (win/linux)shift+alt+right (mac) Select Forward Sexp ctrl+shift+k Select Right Select forward to the end of the current form or the first newline. See Kill right below. (The animation also shows Shrink Selection). shift+ctrl+left (win/linux)shift+alt+left(mac) Select Backward Sexp ctrl+shift+down Select Forward Down Sexp (You probably do not need to select like this, but you can!) ctrl+shift+alt+up Select Backward Down Sexp (You probably do not need to select like this, but you can!) ctrl+shift+alt+down Select Forward Up Sexp (You probably do not need to select like this, but you can!) ctrl+shift+up Select Backward Up Sexp (You probably do not need to select like this, but you can!) Unbound Select Forward Sexp Or Up (You probably do not need to select like this, but you can!) Unbound Select Backward Sexp Or Up (You probably do not need to select like this, but you can!) ctrl+shift+end Select Forward to List End/Close ctrl+shift+home Select Backward to List Start/Open","boost":7},{"location":"paredit/#editing","title":"Editing","text":"Default keybinding Action Description ctrl+alt+right (mac/win)ctrl+alt+. (linux) Slurp Forward Moves the closing bracket forward, away from the cursor, past the following form, if any. ctrl+alt+left (mac/win)ctrl+alt+, (linux) Barf Forward Moves the closing bracket backward, towards the cursor, past the preceding form. ctrl+alt+shift+left Slurp Backward Moves the opening bracket backward, away from the cursor, past the preceding form, if any. ctrl+alt+shift+right Barf Backward Moves the opening bracket forward, towards the cursor, past the following form. ctrl+alt+s Splice Sexp Remove enclosing brackets. ctrl+shift+s Split Sexp Splits a string, or a list, into two strings, or lists of the same type as the current. ctrl+shift+j Join Sexps/Forms Joins two strings, or two lists of the same type, into one form (string/list). ctrl+alt+p ctrl+alt+r Raise Sexp Replaces the enclosing list with the current form. ctrl+alt+t Transpose Sexps/Forms Swaps place of the two forms surrounding the cursor. alt+upalt+down Drag Sexp Backward/Forward Moves the current form to the behind/in front of the previous/next one. (See below about behavior in maps and binding boxes.) ctrl+alt+shift uctrl+alt+shift d Drag Sexp Backward UpDrag Sexp Forward Down Moves the current form up/out of the current list, backwards, and down/in to the following list, forwards, keeping the cursor within the sexpr being dragged. ctrl+alt+shift kctrl+alt+shift j Drag Sexp Forward UpDrag Sexp Backward Down Moves the current form up/out of the current list, forwards, and down/in to the preceding list, backwards, keeping the cursor within the sexpr being dragged. ctrl+shift+c Convolute \u00af\\_(\u30c4)_/\u00af ctrl+shift+delete Kill Sexp Forward Deletes the next form in the same enclosing form as the cursor. ctrl+k ctrl+k (win/linux)ctrl+k (mac) Kill Right Delete forward to the end of the current form or the first newline. ctrl+k ctrl+h (win/linux)cmd+backspace (mac) Kill Left Delete backward to the start of the current form or the start of the line. ctrl+alt+backspace Kill Sexp Backward Deletes the previous form in the same enclosing form as the cursor. ctrl+delete Kill List Forward Deletes everything from the cursor to the closing of the current enclosing form. ctrl+backspace Kill List Backward Deletes everything from the cursor to the opening of the current enclosing form. ctrl+alt+shift+delete Splice Killing Forward Delete forward to end of the list, then Splice. ctrl+alt+shift+backspace Splice Killing Backwards Delete backward to the start of the list, then Splice. ctrl+alt+shift+p Wrap Around () Wraps the current form, or selection, with parens. ctrl+alt+shift+s Wrap Around [] Wraps the current form, or selection, with square brackets. ctrl+alt+shift+c Wrap Around {} Wraps the current form, or selection, with curlies. ctrl+alt+shift+q Wrap Around \"\" Wraps the current form, or selection, with double quotes. Inside strings it will quote the quotes. ctrl+alt+rctrl+alt+p/s/c/q/h Rewrap Changes enclosing brackets of the current form to parens/square brackets/curlies/double quotes and set (#{})

    Copy to Clipboard when killing text

    You can have the kill commands always copy the deleted code to the clipboard by setting calva.paredit.killAlsoCutsToClipboard to true. If you want to do this more on-demand, you can kill text by using the selection commands and then Cut once you have the selection.

    clojure-lsp drag fwd/back overlap

    As an experimental feature, the two commands for dragging forms forward and backward have clojure-lsp alternatives. See the clojure-lsp page.

    ","boost":7},{"location":"paredit/#drag-bindings-forwardbackward","title":"Drag bindings forward/backward","text":"

    When dragging forms inside maps and binding boxes, such as with let, for, binding, etcetera, it often makes most sense to drag each binding as a pair. And this is what Calva will do. Like so:

    And like so (wait for it):

    ","boost":7},{"location":"paredit/#about-the-keyboard-shortcuts","title":"About the Keyboard Shortcuts","text":"

    Care has been put in to making the default keybindings somewhat logical, easy to use, and work with most keyboard layouts. Slurp and barf forward are extra accessible to go with the recommendation to learn using these two super handy editing commands.

    You can relax how Paredit's shortcuts replace VS Code built in shortcuts a bit by setting calva.paredit.hijackVSCodeDefaults to false.

    There are some context keys you can utilize to configure keyboard shortcuts with precision. See Customizing Keyboard Shortcuts.

    The Nuclear Option: You can choose to disable all default key bindings by configuring calva.paredit.defaultKeyMap to none. (Then you probably also want to register your own shortcuts for the commands you often use.)

    ","boost":7},{"location":"paredit/#when-clauses-and-vscode-default-bindings","title":"When Clauses and VSCode Default Bindings","text":"

    There are instances where VSCode's built-in command binding defaults are the same as Paredit's, where Paredit's version has less functionality. For example, Calva's Expand Selection and Shrink Selection doesn't support multiple selections (though this may change in the future - see Multicursor section below). In this particular case, adding !editorHasMultipleSelections to the when clause of the binding makes up for this gap by letting the binding fall back to VSCode's native grow/shrink selection.

    For example, here's the JSON version of the keybindings settings demonstrating the above. Note this can also specified in the Keyboard Shortcuts UI:

    {\n  \"key\": \"shift+alt+right\",\n  \"command\": \"paredit.sexpRangeExpansion\",\n  \"when\": \"calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap =~ /original|strict/ && !calva:cursorInComment\"\n}\n

    to

    {\n  \"key\": \"shift+alt+right\",\n  \"command\": \"paredit.sexpRangeExpansion\",\n  \"when\": \"!editorHasMultipleSelections && calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap =~ /original|strict/ && !calva:cursorInComment\"\n}\n

    The point is that when the bindings overlap and default functionality is desired peaceful integration can be achieved with the right when clause. This is left out of Paredit's defaults to respect user preference, and ease of maintenance.

    Happy Editing! \u2764\ufe0f

    ","boost":7},{"location":"paredit/#experimental-feature-multicursor-support","title":"Experimental Feature: Multicursor support","text":"

    There is an ongoing effort to support simultaneous multicursor editing with Paredit. This is an experimental feature and is not enabled by default. To enable it, set calva.paredit.multicursor to true. This feature is still in development and may not work as expected in all cases. Currently, this supports the following categories:

    • Movement
    • Selection (except for Select Current Form - coming soon!)
    • Rewrap
    ","boost":7},{"location":"paredit/#toggling-multicursor-per-command","title":"Toggling Multicursor per command","text":"

    The experimental multicursor-supported commands support an optional command arg - like copy for the kill* commands mentioned above - to control whether multicursor is enabled for that command. This is an alternative to, or supports binding-specific overrides for, calva.paredit.multicursor.

    For example:

    {\n  \"key\": \"ctrl+k\",\n  \"command\": \"paredit.sexpRangeExpansion\",\n  \"when\": \"... your when conditions ...\",\n  \"args\": {\"multicursor\": false}\n}\n
    ","boost":7},{"location":"parinfer/","title":"Calva Parinfer Mode is Reverted","text":"

    Reverted in Calva v2.0.228

    The changes in v2.0.227 seemed to cause problems for some users. Unclear yet if and why. But to not risk causing problems for more users these changes where reverted and Calva v2.0.228 does not contain them. Please consider using v2.0.227 and help find what the problems are about! Please note: Even in v2.0.227 this feature is currently disabled by default.

    Parinfer is a system for editing the structure of LISP text without explicit commands. The structure can be regarded as already being expressed through indentation. With Parinfer you can use your intuition about the structure inferred from the indentation to perform surprisingly many structural edits.

    "},{"location":"parinfer/#quirks","title":"Quirks","text":"

    There are some known quirks, of varying severity, with this feature. Some of them will need to be fixed before we move this feature out of Experimental status.

    For the most times you can always Undo to get back to where the document was fine. You just need to pay some attention and be aware when undo is needed.

    "},{"location":"parinfer/#no-multi-cursor-support","title":"No multi-cursor support","text":"

    The bracket inference will remove all cursors but the first one. So for instance if you edit with multiple cursors and it causes brackets to move, you'll end up with just one cursor and the subsequent edits will not be what you intended. This is particularly important to note when you have cursors that are not in the viewport. In such cases it might be better to turn Parinfer off while you do the edits, fix formatting and such manually and then switch Parinfer on again.

    "},{"location":"parinfer/#wrong-inferences","title":"Wrong inferences","text":"

    For yet unknown reasons an edit such as the following does the wrong thing (the cursor indicated by the vertical bar):

    (foo| (bar)\n      (baz))\n

    backspace =>

    (fo| (bar\n      (baz)))\n

    That is (baz) is slurped. When what should happen is:

    (fo| (bar)\n     (baz))\n
    "},{"location":"parinfer/#lag-causing-errors-when-fast-typing","title":"Lag causing errors when fast typing","text":"

    The way that Calva Parinfer works is that for any edit of the document it first reformats the code around the cursor, then infer brackets. Currently these two steps are not atomic to VS Code, so if you type fast bracket inference might happen on the yet unformatted code, and thus not be correct. You might also see the cursor end up at the wrong position at times.

    "},{"location":"parinfer/#infer-parens","title":"Infer Parens","text":"

    This is no longer available in Calva

    See above about how to try this build anyway, warts and all.

    When you enable Calva's Parinfer it is all about infering brackets from indentation. There are no further Parinfer modes. Calva's auto-formatter will take care of keeping the code correctly indented.

    Enable it with from this setting: calva.fmt.experimental.inferParensAsYouType or from the status bar item.

    "},{"location":"parinfer/#parinfer-status-bar-items","title":"Parinfer Status bar items","text":"

    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.

    1. Parinfer ON/OFF indicator/button. \u2022() (The dot/circle indicates ON/OFF)
    2. Structure and indentation health indicator. \u2714\ufe0f/\u26a0/\u2298

    When Parinfer is ON, the health indicator will have three states:

    1. \u2714\ufe0f Healthy - meaning both structure and indentation is OK
    2. \u2298 Structure broken - you need to fix the the structure of the code
    3. \u26a0 Bad indentation - meaning that to Parinfer the structure and indentation do not match, _the item is now also a button with which you can fix the indentation.

    Parinfer will be disabled in both the unhealthy states.

    When Parinfer is OFF, only the first two states above are used.

    "},{"location":"parinfer/#some-vs-code-settings-automatically-changed","title":"Some VS Code Settings automatically changed","text":"

    In order for some automatic VS Code behaviour not to interfere with Parinfer the following settings are automatically configured when you toggle Parinfer ON:

        \"[clojure]\": {\n        \"editor.autoClosingBrackets\": \"never\",\n        \"editor.autoClosingOvertype\": \"never\",\n        \"editor.formatOnPaste\": false\n    },\n

    And when you toggle Parinfer OFF:

        \"[clojure]\": {\n        \"editor.autoClosingBrackets\": \"always\",\n        \"editor.autoClosingOvertype\": \"always\",\n        \"editor.formatOnPaste\": true\n    },\n

    It is recommended that you let Calva handle these settings to avoid weird behaviour.

    "},{"location":"parinfer/#no-tab-indenting","title":"No Tab indenting","text":"

    As the tab key is used for formatting the current form in Calva, it is \u201dtaken\u201d. The closest equivalents you have are space and backspace. At least for now. We'll see if we can find out a good way for supporting tab and shift+tab for indent and dedent.

    tab for formatting is of course just a default key binding and you can assign it to something else to get it to do indenting. However, it will not be a very smart indent anyway, there is no Clojure awareness about it. You are hereby adviced to instead use some more spaces.

    "},{"location":"parinfer/#paredit-is-still-there","title":"Paredit is still there","text":"

    In Calva, Parinfer and Paredit are designed to coexist and both be there to let you edit the structure easily and efficiently. Since Paredit commands are always formatted, they leave the code in a state where Parinfer has what it needs to infer bracket placement as you either edit the indentation, or remove/add brackets.

    "},{"location":"parinfer/#disable-the-parinfer-extension","title":"Disable the Parinfer Extension","text":"

    If you want to have Parinfer you are probably best served by Calva's built-in version. It is designed, and will continue to be improved to function well together with Calva's other structural editing and formatting features. It will also probably conflict with the Parinfer Extension.

    "},{"location":"parinfer/#see-also","title":"See also","text":"
    • Paredit
    • Formatting
    "},{"location":"polylith/","title":"How to Use Calva with Polylith","text":"

    Polylith is an architecture for backend projects that maximizes development ergonomics and code reuse.

    When developing a Polylith application you use one REPL for everything. And as such it is a rather vanilla deps.edn project, so there is really not much more to using Calva with Polylith than:

    1. Jack in, selecting the deps.edn project type
    2. Select aliases, most often :dev and :test
    3. Hack away!
    "},{"location":"polylith/#the-realworld-example","title":"The RealWorld Example","text":"

    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:

    1. Fork the project and open it in VS Code
    2. Jack-in, selecting the Polylith RealWorld Server REPL project type
    3. Wait for the REPL prompt to read clj\ua789dev.server\ua789>
    4. Evaluate (start! 6003)
    5. Hack away!
    "},{"location":"polylith/#try-it-with-a-frontend","title":"Try it with a Frontend","text":"

    A ClojureScript frontend, of course:

    1. Fork the jacekschae/conduit project and open it in VS Code
    2. Edit the api-url definition in events.cljs file to be
      (def api-url \"http://localhost:6003/api\")\n
    3. Jack-in, selecting to start and connect to the :app build
    4. Wait for it to compile and then open http://localhost:3000
    5. Hack away!
    "},{"location":"pprint/","title":"Pretty Printing","text":"

    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.

    "},{"location":"pprint/#toggle-it","title":"Toggle it","text":"

    There is a pprint indicator to the right in the status bar which shows the status of the mode. Click the indicator to toggle prettification on and off. There is also a Calva: Toggle Pretty Printing for All Evaluations command.

    Tip: If you have evaluated something time consuming, or that is not idempotent, with pretty printing mistakenly off: toggle it on and evaluate *1.

    "},{"location":"pprint/#configuration","title":"Configuration","text":"

    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:

    Setting Type Effect enabled boolean So this is a third way you can change this mode \ud83d\ude04 printEngine enum Which printer function that will be used. Default is pprint, more about this setting below printFn object You can configure Calva to use a custom nREPL compatible print function, more below. width number The maximum line length of printed output (or at least the printers will try) maxLength number The maximum number of elements printed in nested nodes, good for evaluating something like (iterate inc 0), which you shouldn't do without setting maxLength. Most printers will indicate truncated lists with ... at the end. maxDepth number The maximum number of levels deep that will get printed. Different printers mark a stop different ways. puget doesn't support it at all.

    See Customizing Calva for some tips on adding settings like these.

    Here's an example of how zprint handles maxDepth (from the Calva implementation of it's client side pretty printing.).

      (pretty-print [[[[[[[[:deeper]]]]]]]] {:max-depth 4})\n  ;; => {:value \"[[[[##]]]]\"}\n
    "},{"location":"pprint/#your-selection-of-prettifiers","title":"Your Selection of Prettifiers","text":"

    Pretty printing can happen on the server (i.e. in the JVM, via nREPL), or on the client (i.e. in node, via VS Code/Calva). Client side always uses zprint. Server side you can choose from these printers:

    Print Engine Client or Server Side Comments calva client The nREPL server will plain print the results, and then Calva will pretty it (using zprint). pprint server Current Calva default. clojure.core/pprint is a bit basic, but it's tried and tested, and doesn't suffer from the issues with the other server side printing options, mentioned below. fipp server puget server Lacks maxDepth option. zprint server A very good option. However, it will need to be configured before Jack-in if you want Calva's help to inject its dependencies. (If you are not using Jack-in, you'll need to supply this dependency yourself.)

    These particular server side functions were chosen because they have pre-configured print-functions in cider-nrepl.

    "},{"location":"pprint/#or-configure-printfn","title":"Or configure printFn","text":"

    If the selection of built-in printEngine support doesn't cut it, you can configure a custom function. This function will need to conform to the requirements of nREPL print functions. The VS Code settings editor will help you configure this one. (This is also a bit experimental, please consider giving feedback about how it works for you if you try it.)

    "},{"location":"pprint/#why-does-server-or-client-side-matter","title":"Why does Server or Client Side Matter?","text":"

    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.

    "},{"location":"pprint/#need-more-configurability","title":"Need More Configurability?","text":"

    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.

    "},{"location":"pprint/#troubleshooting","title":"Troubleshooting","text":""},{"location":"pprint/#pprint-is-not-working","title":"pprint is not working","text":"

    If pprint is not working, try a different pprint engine or use Calva's jack-in to make sure the necessary dependencies are loaded in your REPL. If you are starting your REPL without jack-in and want to continue doing so, you can use the command Copy Jack-in Command Line to Clipboard then paste the command somewhere to see what dependencies it injects. You can then add these dependencies to your REPL in whatever way suits your needs.

    Enjoy Prettiful Printing! \u2764\ufe0f

    "},{"location":"quirks/","title":"Quirks","text":"

    Here's a shocker for ya': Calva isn't perfect. \ud83d\ude04

    There are quirks and things that flat out do not work. We'll try to collect info about such things here, providing workarounds when available (or, rather, known to us).

    "},{"location":"quirks/#test-features-not-available-with-clojurescript","title":"Test features not available with ClojureScript","text":"

    Currently cider-nrepl does not provide its test functionality for ClojureScript code. Please consider contributing to fixing that.

    "},{"location":"quirks/#using-with-parinfer","title":"Using with Parinfer","text":"

    See Using with Parinfer

    "},{"location":"quirks/#calva-and-the-vim-extension","title":"Calva and the VIM Extension","text":"

    See Using Calva with the VIM Extension.

    "},{"location":"quirks/#command-not-found-errors-on-jack-in","title":"\u201dCommand not found\u201d Errors on Jack-in","text":"

    Jack-in starts by running a command in a new terminal. You will need the commands used installed on your computer:

    • clojure for tools.deps/deps.edn
    • lein for Leiningen
    • npx for shadow-cljs
    • gradlew for Gradle (in your project)

    Also, in some circumstances VS Code is not spawned from a shell with the environment variables, especially $PATH, which might mean that even though you have the tools installed, they are not found when VS Code/Calva tries to execute them. To fix this you will need to do one of these two things:

    1. Figure out from where VS Code is spawned, and make sure the $PATH there includes the directory with the needed binary.
    2. Start VS Code from a terminal where the $PATH is correctly configured. (Using the code command.)

    See this issue for more clues on this problem.

    "},{"location":"quirks/#strange-linting-errors","title":"Strange linting errors?","text":"

    This is not really a quirk, and most linting errors are not strange when you learn about why they are there. Calva does not do any linting, btw, see also linting.

    "},{"location":"quirks/#consider-uninstalling-these-extensions","title":"Consider uninstalling these extensions","text":"

    Without Calva, many users install other nifty extensions (some of which are old pieces of Calva) that help with this or that problem. It might sometimes work together with Calva, sometimes not. Here's a list of some common extensions you should consider to at least disable:

    • Strict Paredit - Calva Paredit has evolved a lot since that version
    • Calva-fmt/Calva Formatter - Same here, evolution
    • Clojure Warrior - Calva includes it, in a much evolved way
    • Parinfer - This one you can actually keep, at some cost, see Using Calva with Parinfer.
    "},{"location":"re-frame-template/","title":"How to use Calva with the re-frame template","text":"

    The re-frame template creates a shadow-cljs project, making it easy to use with Calva.

    1. npm install
    2. From VS Code, issue the command Calva: Start a Project REPL and Connect (a.k.a Jack-in), ctrl+alt+c ctrl+alt+j.
    3. Calva will auto-detect that this is a shadow-cljs project and ask for which build to compile.
    4. Calva's output window will open and log some progress information.
    5. When prompted for which build to start, select :app.
    6. :app is the only configured build, but the VS Code menu for this is a bit strange so make sure the :app checkbox is really ticked before proceeding.
    7. This will start the app, so in this workflow you don't do the Run application steps outlined below.
    8. When prompted for which build to connect to, select :app.
      • In the View menu of VS Code, you can tell it to show the Terminal view, where you see which command the jack-in process is started with, and it's output. Ctrl+C in this pane will kill your app and free up all resources it has allocated.
    9. When the app is compiled
      1. Open http://localhost:8280 in your browser.
      2. Confirm that it says Hello from re-frame. (Depending on how long the app takes to compile, you might need to reload the page a few times.)
    10. Open the views.cljs file from src/<your-project-name> and issue Calva: Load/Evaluate Current File and its Requires/Dependencies. ctrl+alt+c enter.
      1. Confirm that you are connected by adding evaluating (js/alert \"Hello from Calva\") (alt+enter and ctrl+enter are your friends).
      2. Confirm that Shadow is hot reloading by changing the greeting message.
    "},{"location":"rebl/","title":"How to Use Calva and REBL Together","text":"

    REBL is a graphical, interactive tool for browsing Clojure data.

    "},{"location":"rebl/#depsedn","title":"deps.edn","text":"

    Add the following aliases to your deps.edn file. Use the deps.edn file in the ~/.clojure directory to enable alias reuse across multiple projects. This is the configuration for REBL on openjdk 12. Check out the REBL github page for more info.

    ;; REBL Base\n:rebl\n{:extra-deps {org.clojure/core.async {:mvn/version \"0.4.490\"}\n                ;; deps for file datafication (0.9.149 or later)\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

    Create a Calva custom connect sequence for your VSCode editor. (Read Custom REPL Connect Sequences if you haven't.) Add the following to your vscode settings.json:

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Rebl Connect\",\n            \"projectType\": \"deps.edn\",\n            \"menuSelections\": {\n                \"cljAliases\": [\n                    \"rebl\",\n                    \"rebl-12\",\n                    \"nrebl\"\n                ]\n            }\n        }\n    ]\n}\n
    "},{"location":"rebl/#leiningen","title":"Leiningen","text":"

    Add rebl profiles to your user-wide profiles so that they will be available for all your projects. Here's a sample user profile (located at ~/.lein/profiles.clj on mac):

    {:user {:plugins [[lein-ancient \"0.6.15\"]]}\n\n ;; REBL Base\n :rebl {:resource-paths [\"/Users/ozimos/REBL/latest/REBL.jar\"]\n        :dependencies [[org.clojure/core.async \"0.4.490\"]\n                       [org.clojure/data.csv \"0.1.4\"]\n                       [org.clojure/data.json \"0.2.3\"]\n                       [cljfmt \"0.6.4\"]\n                       [org.yaml/snakeyaml \"1.23\"]]}\n\n ;; REBL 12 for JDK 12.0.1. Swap out for your JDK version\n :rebl-12 {:dependencies [[org.openjfx/javafx-fxml  \"12.0.1\"]\n                          [org.openjfx/javafx-controls \"12.0.1\"]\n                          [org.openjfx/javafx-graphics \"12.0.1\"]\n                          [org.openjfx/javafx-media \"12.0.1\"]\n                          [org.openjfx/javafx-swing \"12.0.1\"]\n                          [org.openjfx/javafx-base  \"12.0.1\"]\n                          [org.openjfx/javafx-web \"12.0.1\"]]}\n\n;; NREBL https://github.com/RickMoynihan/nrebl.middleware\n :nrebl {:repl-options {:nrepl-middleware [nrebl.middleware/wrap-nrebl]}\n        :dependencies [[rickmoynihan/nrebl.middleware \"0.3.1\"]]}}\n
    More info here

    Create a Calva custom connect sequence for your VSCode editor. (Read Custom REPL Connect Sequences if you haven't.) Add the following to your vscode settings.json:

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Lein REBL\",\n            \"projectType\": \"Leiningen\",\n            \"menuSelections\": {\n                \"leinProfiles\": [\"rebl\", \"rebl-12\", \":nrebl\"]\n            },\n            \"afterCLJReplJackInCode\": \"((requiring-resolve 'cognitect.rebl/ui))\"\n        }\n    ]\n}\n
    "},{"location":"rebl/#shadow-cljs-tbd","title":"shadow-cljs (TBD)","text":"

    TBD. If you know how to do it, please update this page.

    "},{"location":"refactoring/","title":"Refactoring","text":"

    There are two \u201dflavours\u201d to refactoring support. Some (just a few) refactorings are made available as Quick Fix suggestions (the light bulb), the rest are regular commands in the clojure-lsp Refactoring category.

    You can enable or disable the Quick Fix suggestion lightbulb using the VS Code setting editor.lightbulb.enabled.

    The refactoring commands do not have default keyboard shortcuts. You find them all by typing \u201dclojure-lsp Refactor\u201d in the Command Palette.

    "},{"location":"refactoring/#commands","title":"Commands","text":"Command Title Command Key Description Clean NS Form clojureLsp.refactor.cleanNs Add Missing Require clojureLsp.refactor.addMissingLibspec Extract to New Function clojureLsp.refactor.extractFunction Cycle/Toggle Privacy clojureLsp.refactor.cyclePrivacy Inline Symbol clojureLsp.refactor.inlineSymbol Introduce let clojureLsp.refactor.introduceLet Creates a new let box with the binding. Follow up with \u201dExpand let\u201d to move it upwards. Expand Let clojureLsp.refactor.expandLet Move to Previous let Box clojureLsp.refactor.moveToLet Thread First clojureLsp.refactor.threadFirst Thread First All clojureLsp.refactor.threadFirstAll Thread Last clojureLsp.refactor.threadLast Thread Last All clojureLsp.refactor.threadLastAll Unwind All clojureLsp.refactor.unwindAll Unwind Thread clojureLsp.refactor.unwindThread

    Formatting

    The way that some of the refactorings are applied to the document, makes it difficult for Calva to format the results. So, sometimes you'll need to navigate the cursor to the enclosing form and hit tab to tidy up the formatting after a refactoring. See also Formatting.

    "},{"location":"refactoring/#thanks-to-clojure-lsp","title":"Thanks to clojure-lsp","text":"

    Most of Calva's refactoring support is sourced directly from clojure-lsp. This also means that most often, if you find issues with refactoring, or have suggestions about it, the clojure-lsp repo is where to direct your reporting.

    "},{"location":"remote-development/","title":"Using Calva with Remote Development","text":"

    VS Code Remote Development is a new feature in version 1.35 of VS Code that allows a developer to use a container, remote machine, or the Windows Subsystem for Linux (WSL) as a full-featured development environment.

    I would recommend reading the introductory blog post and watching the videos. I find the feature extremely exciting and wish more IDEs would implement something like it.

    From a Clojure perspective it allows you to have VS Code installed on your Java-less, Clojure-less hardware and still use it to develop Clojure through it.

    "},{"location":"remote-development/#a-use-case","title":"A use-case","text":"
    • For some reason your physical computer has to be running Windows (organizational rules etc.)
    • Your deployment environment is Linux
    • You want to edit files in an editor running on your physical computer
    • Most Clojure tooling is made with *nix first in mind and there are incompatibilities with Windows
    "},{"location":"remote-development/#how-to","title":"How to","text":"

    Run Remote-Containers: Add Development Container Configuration Files... and pick a suitable Java base image. Then:

    "},{"location":"remote-development/#modify-dockerfile-to-install-clojure-cli-and-optionally-lein","title":"Modify Dockerfile to install Clojure CLI (and optionally lein)","text":"

    Add:

    # ...\n\n# Install Clojure - see https://github.com/Quantisan/docker-clojure/blob/master/target/openjdk-14-slim-buster/tools-deps/Dockerfile\nENV CLOJURE_VERSION=1.10.1.619\nWORKDIR /tmp\nRUN \\\napt-get update && \\\napt-get install -y curl make rlwrap wget && \\\nrm -rf /var/lib/apt/lists/* && \\\nwget https://download.clojure.org/install/linux-install-$CLOJURE_VERSION.sh && \\\nsha256sum linux-install-$CLOJURE_VERSION.sh && \\\necho \"28b1652686426cdf856f83551b8ca01ff949b03bc9a533d270204d6511a8ca9d *linux-install-$CLOJURE_VERSION.sh\" | sha256sum -c - && \\\nchmod +x linux-install-$CLOJURE_VERSION.sh && \\\n./linux-install-$CLOJURE_VERSION.sh\nRUN \\\nsu vscode -c \"clojure -e '(clojure-version)'\" && \\\nrm ./linux-install-$CLOJURE_VERSION.sh\n\n# Install Lein\nRUN \\\nwget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein -O /bin/lein && \\\nchmod uog+x /bin/lein\nRUN su vscode -c \"/bin/lein\"\n\n# Cleanup\nRUN apt-get purge -y --auto-remove curl wget\n\n# ...\n
    "},{"location":"remote-development/#modify-devcontainerjson","title":"Modify devcontainer.json","text":"

    Add Calva and, optionally, forward some ports to the host::

    \"extensions\": [\"betterthantomorrow.calva\"],\n\"forwardPorts\": [8088, 52162], // example: your webapp, your nREPL\n
    "},{"location":"remote-development/#build-and-start","title":"Build and start","text":"

    Run Remote-Containers: Rebuild and Reopen in container

    "},{"location":"remote-development/#wsl","title":"WSL","text":"

    See Using Calva with WSL

    "},{"location":"repl-window/","title":"The REPL Window/File","text":"

    The Calva REPL Window is actually a regular file with some extra treatment from Calva, like displaying a prompt, offering evaluation history recall and generally \u201cfollowing\u201d the current namespace. This file is created and opened when Calva is connected to a REPL. You can use it for experimental code (though there are also Rich Comments and Fiddle Files for this).

    In ClojureScript projects, the window will be associated with the cljs REPL once it is connected. It will then look something like this:

    The first prompt is from when the clj REPL is connected, and the second from cljs. The first part of the prompt tells you which REPL type the window is currently connected to.

    "},{"location":"repl-window/#using-the-repl-window-for-output","title":"Using the REPL Window for output","text":"

    By default the REPL Window doubles as the place where Calva sends output like stdout/stderr and other messages. See Calva Output for more about this and how to change this behaviour.

    "},{"location":"repl-window/#finding-the-repl-window","title":"Finding the REPL Window","text":"

    If you quickly want to open and/or switch to the REPL Window there is the command Calva: Show/Open REPL Window, ctrl+alt+o r.

    To sync the REPL window namespace with the current file before switching, use the Switch Namespace of the REPL Window to Current Namespace command, ctrl+alt+c alt+n.

    "},{"location":"repl-window/#find-the-file-for-the-current-repl-window-namespace","title":"Find the File for the Current REPL Window Namespace","text":"

    When you are editing things in the REPL window, and want to open the file that defines its current namespace, use the Show File for the Current REPL Window Namespace command, ctrl+alt+o r.

    Note

    This also works for Clojure core and library namespaces.

    "},{"location":"repl-window/#evaluating-code","title":"Evaluating Code","text":"

    The window will be automatically associated with the REPL and the namespace of any project Clojure/ClojureScript file you evaluate code in. So for instance if you evaluate this code in a clj file with the namespace fresh-reagent.handler:

    (def mount-target\n  [:div#app\n   [:h2 \"Welcome to fresh-reagent\"]\n   [:p \"please wait while Figwheel is waking up ...\"]\n   [:p \"(Check the js console for hints if nothing exciting happens.)\"]])\n

    If the REPL Window is the configured destination for evaluation results, the defined var will be printed there. Otherwise, it will be printed to the destination you've configured. In either case, the REPL window will print a new prompt reflecting the current REPL connection and namespace:

    If you then switch to the output window (ctrl+alt+o r), and enter this at the prompt:

    mount-target\n

    then evaluate it using alt+enter, you'll get this:

    ... because the namespace \u201dfollowed\u201d the first evaluation in the REPL window.

    "},{"location":"repl-window/#repl-history","title":"REPL History","text":"

    Recently evaluated forms in the REPL file are persisted and can easily be shown again for modifying and re-evaluating.

    "},{"location":"repl-window/#navigate-repl-history","title":"Navigate REPL History","text":"

    You can navigate up and down the history of evaluated forms in the REPL file by pressing alt+up and alt+down, provided your cursor is at the end of the last form after the prompt. If the cursor is not at the end of the last form, then alt+up and alt+down will do whatever they are mapped to, which is by default \"Move Line Up\" and \"Move Line Down,\" respectively.

    If you have typed some text after the prompt before you start traversing up the history, this text will be preserved and will display when you traverse back down the history. If you modify some text in the history while traversing, the modification will be saved at that location in history.

    "},{"location":"repl-window/#clear-repl-history","title":"Clear REPL History","text":"

    You can clear the repl history by running the command \"Clear REPL History\" from the command palette.

    "},{"location":"repl-window/#stack-traces","title":"Stack Traces","text":"

    When an evaluation produces an error, it will automatically be printed in the REPL Window. If there is a stack trace associated with the error, it can now be printed on demand using the Calva: Print Last Stacktrace to the Output Window command. You can also print the stack trace for any error message printed to the REPL Window via the Codelens button below it.

    For printed stacktraces, when source locations are available (Clojure files), you will be able to navigate to them by pressing ctrl+click (cmd+click on Mac) on the file name. You can also hover over symbols in the stack trace to see the symbol's documentation, and ctrl+click (cmd+click on Mac) the symbol to Peek Definition.

    Output destinations

    If you have configured some other destination for stderr output, the error message will be printed there as well. But it will also be printed to the REPL Window, because the augmented stack traces need this (because reasons).

    "},{"location":"repl-window/#load-current-namespace","title":"Load Current Namespace","text":"

    When navigating namespaces it is easy to forget to first require them and that can be tricky to debug. To help with this, Calva's command Load/Evaluate Current File and its Requires/Dependencies also works in the REPL Window, but there, it acts like Load Current Namespace.

    Suppose you have two files, pez/xxx.clj and pez/yyy.clj, where pez.yyy requires pez.xxx.

    (ns pez.xxx)\n\n(def a :xxx-a)\n\n(def b :xxx-b)\n
    (ns pez.yyy\n  (:require [pez.xxx]))\n\n(def a :yyy-a)\n\n(println \"Hello\" pez.xxx/a)\n

    Then, with a freshly jacked-in REPL, you evaluate (ns pez.yyy) and want to work with the vars defined there, Clojure will complain. But if you Load/Evaluate Current File and its Requires/Dependencies, it will start working. Something like so:

    Note

    This currently suffers from a limitation in Calva where it won't reload dependencies, so you will sometimes have to do this \u201dmanually\u201d anyways (by opening the files and loading them yourself). See Calva issue #907

    "},{"location":"repl-window/#peek-current-namespace","title":"Peek Current Namespace","text":"

    A somewhat hidden feature: You can peek, see documentation for, and navigate to a namespace by hovering on the namespace symbol in one of the REPL Window prompts (just like you would if it was not in the prompt \ud83d\ude04).

    "},{"location":"repl-window/#paredit-enabled","title":"Paredit Enabled","text":"

    The REPL Window is mostly a regular Calva Clojure/ClojureScript file, which makes everything that works in a regular file work in this file, including Paredit. This makes it easy to navigate the input and output there. For instance, to select the last evaluation results, you can press ctrl+w (shift+alt+right on Windows and Linux):

    "},{"location":"repl-window/#debugger-enabled","title":"Debugger Enabled","text":"

    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.

    "},{"location":"repl-window/#it-is-ephemeral","title":"It is Ephemeral","text":"

    The contents of the output/REPL window is written to a file named output.repl in the .calva/output-window directory of your project. The file is recreated every new session, so you should copy or save anything you want to preserve between sessions.

    You probably want to add .calva/output-window/ to your .<something>ignore files. (There are some more files in that directory that you shouldn't keep under source control.)

    "},{"location":"repl-window/#choose-clj-or-cljs-repl-connection","title":"Choose CLJ or CLJS REPL Connection","text":"

    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:

    "},{"location":"repl-window/#known-quirks-and-caveats","title":"Known Quirks and Caveats","text":"

    Due to limitations in the VS Code API it is hard for Calva to know if the REPL file is open, and if it was opened more than once. Therefore, we suggest you make it a habit to leave this window open, or even pinned. And if it is open in several tabs, expect evaluation printouts to be a bit unpredictable.

    If you save the REPL file (which most often does not make much sense, but anyway) you will sometimes be presented with a message about VS Code being confused about the file contents being out of sync. Just choose to Overwrite the currently saved version and you should be fine.

    "},{"location":"reveal/","title":"How to use Calva and Reveal together","text":"

    Reveal is a \"Read Eval Visualize Loop for Clojure\". This page describes how to use Reveal in your development setup based on Calva.

    Note

    See https://vlaaad.github.io/reveal for the latest version and use that wherever this page says <version>.

    "},{"location":"reveal/#when-using-toolsdeps","title":"When using tools.deps","text":"

    You can go for the nrepl middleware or just add the dependency.

    Please see the Calva test-data project minimal-reveal for an example.

    "},{"location":"reveal/#middleware","title":"Middleware","text":"

    This will make Reveal to start together with your project.

    Note

    This will make all Calva evaluations go to Reveal. Too chatty for you? Take the dependencies only approach.

    Add this alias deps.edn:

    :aliases\n{:reveal-nrepl-middleware\n    {:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}\n     :main-opts  [\"-m\" \"nrepl.cmdline\"\n                  \"--middleware\" \"[vlaaad.reveal.nrepl/middleware,cider.nrepl/cider-middleware]\"]}}\n

    And then jack-in choosing the deps.edn option and then pick the :reveal-nrepl-middleware alias.

    "},{"location":"reveal/#dependencies-only","title":"Dependencies only","text":"

    If you don't want to use the nrepl-middleware you can configure just the dependency and then start Reveal yourself.

    The alias:

    :reveal-dep-only\n  {:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}}\n

    A custom REPL command for starting Reveal in your project:

        \"calva.customREPLCommandSnippets\": [\n        ...\n        {\n            \"name\": \"Start Reveal Tapper\",\n            \"snippet\": \"(require '[vlaaad.reveal :as reveal])(add-tap (reveal/ui))\",\n            \"key\": \"sr\"\n        },\n        ...\n    ]\n

    See Custom REPL Command for how to configure more commands, and bind shortcuts to them, to make Reveal integration nice for you.

    "},{"location":"reveal/#when-using-leiningen","title":"When using Leiningen","text":"

    In your project.clj, add a profile named \"reveal\":

    :profiles {:reveal {:dependencies [[vlaaad/reveal \"<version>\"]]\n                    :repl-options {:nrepl-middleware [vlaaad.reveal.nrepl/middleware]}}}\n

    Now when you jack-in using Calva, you enable this profile and Reveal will be started automatically. Please note that Reveal requires Java 8 or higher, and uses JavaFX. Depending on your setup, you may need to make sure it is available.

    "},{"location":"reveal/#tips-about-font-size","title":"Tips about font size","text":"

    If you find the font to small you can add a :jvm-opts key to make it a little bigger:

    :aliases\n{:reveal\n    {:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}\n     :jvm-opts   [\"-Dvlaaad.reveal.prefs={:font-size,17}\"]\n     :main-opts  [\"-m\" \"nrepl.cmdline\"\n                  \"--middleware\" \"[vlaaad.reveal.nrepl/middleware,cider.nrepl/cider-middleware]\"]}}\n
    "},{"location":"reveal/#using-java-11","title":"Using Java > 11?","text":"

    Reveal needs some reflective access to internal classes that has since Java 11 been restricted. You can relax this and get things working via JVM options. Tuck this into your reveal alias:

    :jvm-opts [\"--add-opens\" \"javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED\"]\n

    (If you are using the font size tips, just add the options into the :jvm-opts vector.)

    See https://github.com/vlaaad/reveal/issues/1 for some more context around this issue.

    "},{"location":"rich-comments/","title":"Rich Comments Support","text":"

    Why bother with Rich comments? Read on. Consider watching this Youtube video for a demo of the workflow using the (in?)famous FizzBuzz problem as an example.

    ","boost":5},{"location":"rich-comments/#things-in-comment-are-not-evaluated","title":"Things in comment are not evaluated","text":"

    The Clojure comment macro is defined like so:

    (defmacro comment\n  \"Ignores body, yields nil\"\n  {:added \"1.0\"}\n  [& body])\n

    It has no forms in its body and will therefore always (as long as the Clojure Reader can read it) evaluate to nil. That is: nothing in the (comment ...) form will get evaluated when the file is loaded.

    This makes it a very good \u201dplace\u201d where you can develop code, experiment with code, and keep example code. Since you will be able to load/evaluate the current file without worrying that the code in the comment form will get evaluated. This also holds true when using tools that hot-reload the code on save, such as Figwheel, shadow-cljs and Krell.

    To develop or refine a function you might:

    1. Open up a (comment ...) form
    2. Inside this form, type a first, super simple, version (or refinement) of your function and evaluate it
    3. Inside the same comment form, type some code to test your function and evaluate that
      • Or type and evaluate some code you might need for your function
    4. Repeat from 2., until the function does what you want it to do
    5. Move the function definition out of the comment form
    6. Clean up the comment form to keep some of the test code as example use, or \u201ddesign decision log\u201d for the function.

    Note

    Using (comment ...) forms for developing code is very common among Clojure coders. Rich Hickey is known for using it, which is why they are called Rich comments to begin with (even if it also is a very rich experience).

    ","boost":5},{"location":"rich-comments/#calva-encourages-rich-comments","title":"Calva encourages Rich comments","text":"

    Calva has several features to facilitate the Rich comments workflow, e.g.

    1. A command that helps you create a new Rich comment form quickly: Calva: Add Rich Comment, ctrl+alt+r c
    2. A snippet for creating Rich comment form quickly. Typing (rcf, will make it appear.
    3. Special Syntax highlight. By default comment forms are rendered in italics
    4. Special top-level form context
    5. Special formatting

    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.

    ","boost":5},{"location":"rich-comments/#comment-is-top-level","title":"comment is top-level","text":"

    To make it easy to evaluate forms in (comment ...) forms, they create a new top-level context. Instead of you having to place the cursor with precision before evaluating the current form, you can have the cursor anywhere within a comment enclosed form and Evaluate Top-Level Form.

    This carries over to all commands in Calva which deal with the top level form. Including custom command snippets.

    ","boost":5},{"location":"rich-comments/#special-formatting","title":"Special formatting","text":"

    To invite a Rich comments workflow, the Calva command Format Current Form will not fold the closing bracket of the (comment ...) form. Instead it will place this bracket on a line of its own (or keep it there).

    (comment\n  )\n

    With the cursor somewhere directly inside the comment form (denoted with a |):

    (comment\n  (def foo\n:foo)|)\n

    tab

    (comment\n  (def foo\n    :foo)\n  |)\n

    !!! Note \"Only for the current comment form\u201d The special formatting only applies in the current comment form. When outside it, formatting tucks the closing paren in again. That's why fold when done, below works like it does. This also applies to VS Code commands like Format Document, or when you have Format On Save enabled. There are several reasons for this, and one is that there is no cljfmt config for it and leaving the closing comment un-tucked might give you troubles with CI pipelines that enforce some cljfmt config be followed. (Another reason is that it would be pretty hard to do on the whole document.)

    ","boost":5},{"location":"rich-comments/#special-formatting-disabled-for-trailing-rcf","title":"Special formatting disabled for trailing :rcf","text":"

    If the Rich comment ends with :rcf (or an ignored form), the special formatting doesn't happen. So if you have:

    (comment\n  (def foo\n:foo)\n  |\n  :rcf)\n

    And hit tab, you will get:

    (comment\n  (def foo\n    :foo)\n  |\n  :rcf)\n
    ","boost":5},{"location":"rich-comments/#thinking-space-is-kept","title":"Thinking space is kept","text":"

    The formatter will not remove newlines between the cursor and the closing bracket. So if you have entered a few lines to get \u201dthinking\u201d room:

    (comment\n  (def foo\n:foo)\n\n|\n\n)\n

    tab

    (comment\n  (def foo\n    :foo)\n\n  |\n\n  )\n
    ","boost":5},{"location":"rich-comments/#fold-when-done","title":"Fold when done","text":"

    To fold the trailing paren automatically, place the cursor immediately outside (before or after) the form:

    (comment\n  (def foo\n:foo))|\n

    tab

    (comment\n  (def foo\n    :foo))|\n
    ","boost":5},{"location":"rich-comments/#enabled-by-default","title":"Enabled by default","text":"

    You can disable this behavior with the setting: calva.fmt.keepCommentTrailParenOnOwnLine.

    ","boost":5},{"location":"rich-comments/#only-for-the-current-form","title":"Only for the Current Form","text":"

    Note

    This treatment only applies to formatting of the current form. With fold when done as an exception.

    ","boost":5},{"location":"shadow-cljs/","title":"shadow-cljs","text":"

    Calva supports most any JVM hosted ClojureScript environment (and some others, including SCI based, too), but shadow-cljs gets some special treatment to try make it extra convenient to use.

    With many shadow-cljs projects, Calva's connect project type shadow-cljs, is the right choice. Projects that use Leiningen or deps.edn can be used both with the Leiningen/deps.edn and shadow-cljs type, depending on configuration see below for more on this.

    ","boost":7},{"location":"shadow-cljs/#shadow-cljs-browser-quickstart","title":"shadow-cljs - browser quickstart","text":"

    Here's how you start a shadow-cljs ClojureScript REPL and connect Calva with the shadow-cljs - browser quickstart example project:

    Prep:

    1. Clone the project to your machine and open its root folder in VS Code.
    2. Open a terminal and run npm install

    Connect Calva:

    1. Run the command Calva: Start a Project REPL and Connect (a.k.a. Jack-in)
    2. Select project type shadow-cljs
    3. Select to start the build :app
    4. Select to connect to the build :app
    5. Wait for the build to complete
    6. Open http://localhost:8020/ in the browser
    7. Open browser.cljs file and load it in the REPL: Calva: Load/Evaluate Current File and Dependencies

    Now you can should be able to evaluate forms, e.g.:

    • The current form or selection with ctrl+enter, or
    • Top-level forms with alt/option+enter.

    (See Code Evaluation)

    ","boost":7},{"location":"shadow-cljs/#shadow-cljs-in-full-stack-projects","title":"shadow-cljs in full stack projects","text":"

    shadow-cljs is a bit special in regards to Calva REPL connection. Mainly because you can start shadow-cljs and it's nREPL server in two ways:

    1. Using the shadow-cljs npm executable
    2. Via the Clojure REPL in your Leiningen or deps.edn project

    These options show up as project types when connecting or jacking in:

    1. Project type: shadow-cljs
    2. Project type: deps.edn + shadow-cljs or Leiningen + shadow-cljs

    The technical difference here is wether you let shadow-cljs start clojure/Leiningen (the first option) or if you let Calva do it (the second option). If you let Calva do it, Calva will then start the shadow-cljs watcher from the Clojure process. From a usage perspective the two approaches will result in different channeling of shadow-cljs output, e.g. test runner results. With the first option (the shadow-cljs project type), shadow-cljs output will be channeled to the Jack-in terminal. With the deps.edn/Leiningen option, that output will be channeled to the Output/REPL window.

    See shadow-cljs + Clojure with Calva: The basics for some more discussion on how the REPL connection works.

    shadow-cljs and clojure aliases

    The shadow-cljs project type will not prompt you for any aliases found in the deps.edn file. Usually you should provide such aliases in shadow-cljs.edn like :deps {:aliases [...]}. If, for whatever reason you can't provide the aliases that way, you can configure a Custom REPL Connect Sequence and provide the aliases as menuSelections -> cljAliases.

    Leiningen + shadow-cljs middleware issue

    Please note that for Leiningen, the command line dependency injection of the shadow-cljs nrepl middleware doesn't work. You need to add it to your project.clj:

    :repl-options {:nrepl-middleware [shadow.cljs.devtools.server.nrepl/middleware]}\n
    ","boost":7},{"location":"shadow-cljs/#see-also","title":"See also:","text":"
    • Connect the REPL
    • Custom REPL Connect Sequences
    • shadow-cljs + Clojure with Calva: The basics
    ","boost":7},{"location":"sponsors/","title":"Calva Sponsors","text":"

    Calva is open source and free to use. It is actively maintained during our free time, and it keeps improving. You can contribute in many different ways, one of which is sponsoring. You can sponsor Calva by directly sponsoring any of us.

    If you are working at a company which benefits from Calva's existence and continued development, please consider sponsoring at the Calva Gold Sponsor tier.

    Please see this statement from Cognitect about the importance of supporting open source developers.

    ","boost":7},{"location":"sponsors/#patrons","title":"Patrons","text":"The right kind of different","boost":7},{"location":"sponsors/#gold-sponsors","title":"Gold Sponsors","text":"Scale your growth on mobile MAKE. DO. SHIP.","boost":7},{"location":"sponsors/#silver-sponsors","title":"Silver Sponsors","text":"","boost":7},{"location":"sponsors/#clojurists-together","title":"Clojurists Together","text":"

    Significant additions to Calva have been made possible by funding from Clojurists Together. And this has often been transformational for the whole project. Calva would not be where it is today without Clojurists Together.

    ","boost":7},{"location":"sponsors/#our-sponsoring-profiles","title":"Our Sponsoring Profiles","text":"

    These are the sponsoring profiles for the active maintainers of Calva (a.k.a. The Calva Team).

    • Peter Str\u00f6mberg
    • Brandon Ringe
    • Cora Sutton
    • Lukas Domagala
    • Rayat Rahman
    ","boost":7},{"location":"sponsors/#readme-visibility","title":"README visibility","text":"

    There is also a sponsors section in the README of the Calva project (which means it is also displayed in the VS Code Extension Marketlace).

    ","boost":7},{"location":"syntax-highlighting/","title":"Calva Highlight","text":"

    Calva takes care of syntax highlighting, and also provides some features not available through VS Code's highlighting mechanism. These extras include rainbow parens, sane bracket matching, and comment form dimming/highlighting.

    "},{"location":"syntax-highlighting/#syntax-highlighting","title":"Syntax Highlighting","text":"

    When using Calva, you are also using its TMLanguage grammar (the core mechanism VS Code uses for syntax highlighting).

    Our grammar tokenizes Clojure keywords as constant.keyword.clojure. Since it is pretty uncommon with keyword constants in the programming languages out there, your theme might not have a highlight defined for this scope. Try find a grammar that highlights keywords! If you are very fond of some theme lacking this, you can help it with a setting:

    \"editor.tokenColorCustomizations\": {\n    \"[Default Dark+]\": {\n        \"textMateRules\": [\n            {\n                \"scope\": [\n                    \"constant.keyword.clojure\"\n                ],\n                \"settings\": {\n                    \"foreground\": \"#6fbfff\"\n                }\n            }\n        ]\n    }\n},\n

    Instead of Default Dark+ you should use your theme's name/key. And choose a color you like, of course.

    "},{"location":"syntax-highlighting/#extra-highlighting","title":"Extra Highlighting","text":"

    You are in charge of how brackets and comments are highlighted via the calva.highlight.<setting> settings:

    Setting Meaning Example enableBracketColors Enable rainbow colors true rainbowIndentGuides Enable rainbow indent guides true highlightActiveIndent Highlight the active indent guide true bracketColors Which colors to use [\"#000\", \"#999\"] cycleBracketColors Whether same colors should be reused for deeply nested brackets true misplacedBracketStyle Style of misplaced bracket { \"border\": \"2px solid #c33\" } matchedBracketStyle Style of bracket pair highlight {\"backgroundColor\": \"#E0E0E0\"} ignoredFormStyle Style of #_... form {\"textDecoration\": \"none; opacity: 0.5\"} commentFormStyle Style of (comment ...) form {\"fontStyle\": \"italic\"}

    Calva disables the VS Code built-in indent guides

    The VS Code built-in settings editor.renderIndentGuides and editor.highlightActiveIndent do not have any effect, since the former is switched off by the Clojure Defaults, mentioned above. Use Calva Highlight's rainbowIndentGuides and highlightActiveIndent instead. They are different from the built in ones in that they are independent, meaning you can choose to have active indent highlighted while the guides generally are not rendered (this is the default, even).

    VS Code bracket coloring vs Calva's

    Calva's bracket coloring is more Clojure aware than VS Code's built-in coloring. And also will chime better with Calva's indent guides. If you like to have bracket coloring outside Clojure code, by all means enable it. Calva's bracket coloring will \u201dover paint\u201d in Clojure files, when enabled. These settings work nicely:

    \"calva.highlight.highlightActiveIndent\": true,\n\"editor.bracketPairColorization.enabled\": true,\n

    The calva.highlight.bracketColors setting can be used to harmonize the coloring between VS Code and Calva.

    "},{"location":"tao/","title":"The Tao of Calva","text":"

    Calva, the spirit, gains much of its taste and color from the Cider it is distilled from, and the oak it is matured in. I started to wonder what it is that shapes Calva, the VS Code Clojure Extension. I should know, being the master distiller, right?. Indeed. Poking some at the question, I do find that I have some answers.

    Please read the following to learn what Calva is, and, to some extent, is not, about. Read it to get an idea about which path Calva is following, where we are headed with the project, and how you can contribute to the journey.

    "},{"location":"tao/#why-calva","title":"Why Calva?","text":"

    Calva's raison d\u00b4\u00eatre is to provide Visual Studio Code users with an easy to use and productive environment for Clojure and ClojureScript development. See the Why Calva? page for some evidence that we are succeeding.

    While Calva draws a lot of inspiration from CIDER, Cursive, Fireplace, and other Clojure development environments, it does not try to compete with them. Reading r/Clojure and elsewhere, it is easy to get the impression that the most common question is \"Which editor should I use for Clojure development?\u201d. I think a much more common question is \u201dHow do I use my favorite editor for Clojure development?\u201d. For VS Code users, that is where Calva should be a good choice.

    I also have an ambition to leverage VS Code for easing the path to Clojure. Given that it is the favorite editor for so many developers, it is important to have a good development environment in place on this platform, and to make it as easy to use as we possibly can, while also being productive and something that you want to stick with, once you are hooked on Clojure.

    That said, and therefore: For people who want to start out with Clojure, and do ask about what development environment would make it the most enjoyable, I'd like for Calva to be a really good option, an option so good that Clojurians feel they can recommend it.

    "},{"location":"tao/#design-goals","title":"Design Goals","text":"

    Calva should be easy to start with and productive enough to stick with. It should support Clojure Best Practices, and be pleasant and enjoyable to use. It should also be easy to hack on, and to contribute to. The ClojureScript story keeps getting more important. Calva should contribute to making the development experience with ClojureScript delightful.

    "},{"location":"tao/#easy-to-start-with","title":"Easy to Start With","text":"

    There are reasons as to why VS Code is so popular. Among those, one stands out to me: It is the most approachable code editor out there. There is nothing you need to learn when you start using it. The editor makes it obvious that you can start typing, deleting, cutting, pasting and undoing, without having to figure anything out. Then you learn how to bring up the command palette and get a boost few other environments can provide with such immediacy.

    A language extension for VS Code can leverage this, by recognizing that what's old is old, and that what's new should be as easy as possible to pick up. Coming to a new language, people bring with them a lot of expectations from the languages they are used to. This is also true for the editor support. Syntax highlighting and formatting should just work, as should documentation lookup, linting and other IDE commodities.

    Clojure brings some new concepts to the table. Chief among these: The REPL. It does take some time to grasp it. Calva needs to remove any obstacles it can when it comes to helping the user to reach the REPL, in order to help getting it, and start loving it.

    To help the users to quickly focus on Clojure, we provide a package that is all-inclusive, with few knobs to turn, and with sane defaults for the knobs that still need to be there.

    "},{"location":"tao/#productive-enough-to-stick-with","title":"Productive Enough to Stick With","text":"

    I think VS Code brings inspiration also when it comes to following up its excellent Getting Started story. You do not have to dig very deep under its surface to find that there is a lot more power to be unleashed. VS Code makes it easy to pick up more features as you get ready for it, and each little piece makes you more productive. To me, only Vim beats VS Code in this game.

    Most often there should be no contradiction between Easy to Start With and Productive. Quite the contrary. This story is mainly about being feature complete with the most important tools. As beginners start to pick up the first few features, they should be rewarded with finding more productive tools when they go looking for them. The VS Code way is Calva's way.

    "},{"location":"tao/#pleasant-and-enjoyable","title":"Pleasant and Enjoyable","text":"

    Enjoyable starts with that Calva shouldn't be an experience full of pains. I think Calva is living up to this first bar of enjoyability. The next step is making it delightful!

    Calva has two main assets it can leverage for being delightful to use: Clojure and VS Code:

    Clojure is plain wonderful and also has this totally awesome REPL thing. Wherever we can, Calva should use the REPL to make the editor spark and bring joy to the developer.

    VS Code is a sweet development environment, offering its power in a consistent way across languages. Even if Clojure is very special, most of Calva's features are surfaced in the ways that VS Code encourages. It makes for less to learn for the user, and most often also makes it easier to implement functionality.

    "},{"location":"tao/#support-clojure-best-practices","title":"Support Clojure Best Practices","text":"

    Mainly, I think Stuart Halloway is right about the REPL being best used from inside the files you are editing rather than from the prompt. It doesn't mean that Calva's REPL window should be neglected, but efforts should be directed such that the file editor REPL is our first way to improve the experience. Expect the Calva REPL window to get much less \u201din your face\u201d, than it is today, as the editor REPL gets stronger.

    Halloway also gives me some peace of mind with his reasoning of keeping a spartan setup. Calva does not need to pack every feature imaginable. If we can get the right features in place, in the right way, the mission is accomplished.

    Clojure is data centric. Calva should make it easy to examine data and how our code affects it. Today, this is not good enough when it comes to data structures larger than a few elements.

    Clojure is a LISP. Thus Structural Editing is possible, and TBH, desirable. Calva should support this and encourage it. There is little we can do about Parinfer not playing well with VS Code, but there is Paredit, and Paredit rocks! Calva's Paredit plays in the top league of Paredits, for this reason.

    "},{"location":"tao/#made-from-the-produce-of-the-orchard","title":"Made from the Produce of the Orchard","text":"

    Calva is distilled from CIDER, which in turn is brewed from the products of The Orchard. This makes a lot of Calva's features thin wrappers around cider-nrepl and related middleware. It also should mean that we strive for adding features by thinking \u201dThe Orchard\u201d first. If it lacks what we need, we should assist in providing it there. We need to up this game a bit from where we are today, I think.

    "},{"location":"tao/#leveraging-clojure-lsp","title":"Leveraging clojure-lsp","text":"

    Today, Calva draws a lot of its static power from clojure-lsp. As does a lot of other Clojure tooling out there. The Calva and the clojure-lsp teams work very nicely together, which is something we cherish and should take care to maintain.

    "},{"location":"tao/#project-stewardship","title":"Project Stewardship","text":"

    Here Calva takes inspiration from many Clojure related projects, and perhaps most so from CIDER,shadow-cljs, and clojure-lsp. Bozhidar Batsov, Thomas Heller, and Eric Dallo all lead their projects with clarity and with gusto. You can feel how they really care about their products and their users. They are there. They listen. They respond. And they relentlessly keep improving their products.

    So we are there. We listen. We respond. And we keep trying to improve Calva.

    The Calva team cares deeply about the user experience. That is a major part of why we do this. When implementing a new feature, or changing a feature, Ux is always the first thing on our mind. Personally, to keep that direction I often start with the documentation of the feature. Reading the documentation before implementation reveals a lot about if the Ux design is within the ballpark or not.

    We have limited time on our hands, however, and we must cut some corners. We can't afford to spend very much time in Ux design. Rather we will use our Ux intuition, iterate the documentation quickly, and be fast to get things out. Then we are responsive in tweaking those things, based on user feedback. This also has impact on general quality at times. We only can do so much QA, and it happens that some releases of Calva cause disruptions in people's workflow because of things we haven't thought of, or not found during our testing. Again, we try to be attentive to feedback and quick to fix. Apologies in advance for any inconveniences caused!

    A super major part of our love for Ux is that Calva should be serving its users. That's why we treat feedback as a gift, listen intently, and use the feedback as a major ingredient in shaping Calva.

    Calva develops from user feedback in more direct ways as well. It is quite astonishing how many people have decided to improve on it by hacking it to do some small or big thing differently. That's great! We should make sure Calva is super easy to contribute to.

    There has been quite a lot of work put into improving the development process. Starting to hack on Calva is just a few steps, taking less than three minutes from cloning to running a dev version in the VS Code debugger. We encourage contributions, from the tiniest typo to whole new features. And we are ready to spend time helping people get their contributions integrated.

    However, Calva can't be what everyone wants it to be, that would make it useless. It needs direction and aim. And it is we, the Calva Team, who are the stewards. We need to be in charge of what Calva is about, and what it is not about.

    "},{"location":"tao/#the-road-ahead","title":"The Road Ahead","text":"

    Tying back to Stuart Halloway, I don't think he means that spartan needs to also mean poor. The products he helps to bring to the market tell another story. VS Code and Clojure brought together has the capacity to create something amazingly rich and luxurious. And I want Calva to tap into that potential.

    On the Calva journey we will allow ourselves to change our minds about how things work. Calva is not a library. Its an interface between Clojure and human beings. Human beings can adapt. And they will need to enjoy adapting in order to enjoy Calva. \ud83d\ude04

    By now it should be clear that you can expect Calva to keep evolving, keep being tended and maintained, and keep getting ever more enjoyable to use. Lately we have been improving Calva pretty rapidly. It would be great to keep it up like that, but I think it is good to expect a more humble and sustainable pace.

    Calva is still quite new. A bit like freshly distilled Calvados. It will need time in those oak barrels to develop its full bouquet of flavors. And time is what we will give it. Our time, our creativity, and our passion.

    "},{"location":"test-runner/","title":"Test Runner","text":"

    Calva provides commands that make running your Clojure tests easier.

    Note

    Since the test commands utilize cider-nrepl, they only work with Clojure, not ClojureScript. See this issue for more details.

    "},{"location":"test-runner/#test-commands","title":"Test Commands","text":"Command Shortcut Description Run All Tests ctrl+alt+c shift+t Runs all tests Run Failing Tests ctrl+alt+c ctrl+t Runs the tests that failed Run Tests for Current Namespace ctrl+alt+c t Runs the tests for the current namespace. If not a -test namespace, tests for the current namespace plus its corresponding <current-namespace>-test namespace will be run. Run Current Test ctrl+alt+c ctrl+alt+t Runs the test at the cursor. This includes a defn with a :test in its metadata, a defn defined in a with-test, and a deftest. Toggle between implementation and test - Switches the file between implementation and test, prompts to create a new file if not found."},{"location":"test-runner/#test-on-save","title":"Test on Save","text":"

    You can enable the Calva setting \"Test on Save\" to have tests for the current namespace run on file save.

    "},{"location":"test-runner/#vs-code-test-ui","title":"VS Code Test UI","text":"

    Calva has experimental support for showing test results in VS Code's Test UI. You can enable this support by setting calva.useTestExplorer to true. When you enable this setting, the Testing icon will appear in the Testing tab of VS Code's Activity Bar.

    With this feature enabled you will be able to browse and run tests directly from the Testing tab.

    Please join the #calva channel on the Clojurians Slack if you have any feedback on this new feature.

    "},{"location":"test-runner/#troubleshooting","title":"Troubleshooting","text":""},{"location":"test-runner/#tests-are-not-found","title":"Tests Are Not Found","text":"

    Calva will not load namespaces in the REPL that you haven't loaded. This is so that you can be in control of what is loaded in the REPL. However, it also means that commands like Run All tests actually mean Run All Tests That are Loaded in the REPL, since the test-runner only runs tests that it knows about, i.e. are loaded in the REPL. Some developers choose to make sure all test namespaces are loaded as part of starting their REPL. Others register a custom REPL command for loading test namepaces. (Yet others use test-runners such as Cognitect's test-runner, Kaocha, poly test, or some other that runner allows for tests being run automatically, separate from the REPL used for development.)

    If you have tests in a test directory separate from your source directory, and those tests are not being found by the test runner, make sure the test directory is included in your paths. This will not be the case by default with a tools.deps (deps.edn) project. If your project is a tools.deps project, you can create an alias in your deps.edn file with :extra-paths that includes \"test\" (or the name of your test directory).

    {:aliases {:dev {:extra-paths [\"test\"]}}}\n
    "},{"location":"test-runner/#changes-arent-taking-effect-when-running-tests","title":"Changes Aren't Taking Effect When Running Tests","text":"

    In order for changes in code to take effect, you need to load the file or evaluate the changed code before running a test command. Prior to version 2.0.301, Calva would load the file for you when running some test commands, but that behavior was removed in favor of leaving control to the user, and to avoid a potential issue.

    Having added the above to your deps.edn, when you jack-in, choose the :dev alias and the test directory will be added to your paths, which will allow tests located in the directory to be found by the test runner.

    "},{"location":"test-runner/#toggle-between-implementation-and-test-command-not-working-as-intended","title":"Toggle between implementation and test command not working as intended","text":"

    This feature mostly works with projects that has leiningen style folder structure and makes some assumption about your folder structure and test file names.

    • It assumes that the test files ends with _test prefix.
    • It assumes that your implementation files are in src folder and the test files are in test folder.

    If you are using any non leiningen style folder structure, you may have to add source paths inside .lsp/config.edn.

    "},{"location":"try-first/","title":"Something to Try First (After Connecting)","text":"

    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:

    • On a new line, type a comment form and put some code inside it:
    (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

    Then:

    1. Place the cursor behind the form (* 2 2) and issue the command Calva: Evaluate Current Form, ctrl+enter.
      • You should see the result being displayed inline. Press esc to dismiss it.
    2. Now issue the command Evaluate Current Top Level Form (defun), alt+enter.
      • You should see the whole form (+ (* 2 2) 2) getting highlighted and the result of that expression being displayed inline.
    3. Evaluate each form inside the comment form using the Top Level command.
      • You should see each one of them evaluated.
      • Evaluating the (hello \"Calva REPL\") form before the (defn hello... form should result in an error/exception. A stacktrace is then printed in the output window
      • Try it again after having evaluated the defnform.

    Demo:

    "},{"location":"try-first/#how-does-this-work","title":"How does this work?","text":"

    Calva has this notion about the current form. Issue the Evaluate Current Form command, with the cursor placed in different locations to get a feeling for how the current form is determined.

    There is also a concept about the current top level form. Good for evaluating various defs defn, defthis, defthat. With your cursor placed anywhere inside such a form.

    The Top Level command also works inside (comment ...) forms, treating the comment as creating a new top level context. It is good for in-file code experimentation.

    "},{"location":"try-first/#see-also","title":"See also","text":"
    • Calva Top 10 Commands.
    • Code Evaluation Tips
    "},{"location":"vim/","title":"Calva and the VIM Extension","text":"

    First thing first. The VIM Extension and Calva has a history of friction between them. Less so these days, but you might still encounter some rough edges. Please don't hesitate to reach out to the Calva team, as we might be able to fix things if only we are aware of them.

    "},{"location":"vim/#key-bindings","title":"Key bindings","text":"

    In general Calva's default key bindings are not very VI-ish.

    "},{"location":"vim/#expand-selection-on-mac","title":"Expand selection on Mac","text":"

    On Mac, Calva binds expand selection to ctrl+w. This conflicts with the VIM Extension's default mapping of window splitting shortcuts. You'll need to remap it either with Calva or with the VIM Extension.

    "},{"location":"vim/#the-esc-key","title":"The esc key","text":"

    While showing inline evaluation results, Calva binds the esc key to dismiss the display of inline results. If you want to be able to use the esc key to enter command mode while inline results are showing, you'll need to rebind Calva's command for dismissing the inline results.

    "},{"location":"vim/#remap-calvas-clearinlineresults","title":"Remap Calva's clearInlineResults","text":"
    • Open the Keyboard Shortcuts JSON file from the Command Palette
    • Disable clearInlineResults and remap the command e.g.
    // Place your key bindings in this file to override the defaults\n[\n  {\n    \"key\": \"escape\",\n    \"command\": \"-calva.clearInlineResults\"\n  },\n  {\n    \"key\": \"shift+escape\",\n    \"command\": \"calva.clearInlineResults\",\n    \"when\": \"editorTextFocus && !editorHasMultipleSelections && !editorReadOnly && !hasOtherSuggestions && !suggestWidgetVisible && editorLangId == 'clojure'\"\n  }\n]\n

    If you run into issues, refer to the commands in the default Keyboard Shortcuts JSON file.

    "},{"location":"vim/#remap-vims-insert-mode","title":"Remap Vim's Insert Mode","text":"

    Remap vim's insert mode keybinding to go into command mode by adding the following to your user settings:

    \"vim.insertModeKeyBindings\": [\n    {\n        \"before\": [\"j\", \"k\"],\n        \"after\": [\"<esc>\"]\n    }\n]\n

    (Change before to whatever keybinding you are comfortable with!)

    "},{"location":"vim/#vim-fireplace-ish-keybindings","title":"Vim Fireplace-ish keybindings","text":"

    You can add these keybindings to your init.vim if you are using the VSCode Neovim extension. It is inspired by and tries to emulate the keybindings found in vim-fireplace which is the most popular vim plugin for Clojure.

    nmap cqp :call VSCodeNotify('calva.jackIn')<CR>\nnmap cqq :call VSCodeNotify('calva.disconnect')<CR>\nnmap cpr :call VSCodeNotify('calva.loadFile')<CR>\nnmap cpR :call VSCodeNotify('calva.loadNamespace')<CR>\nnmap cpp :call VSCodeNotify('calva.evaluateSelection')<CR>\nnmap cqc :call VSCodeNotify('calva.evalCurrentFormInREPLWindow')<CR>\n

    Unfortunately these key combinations will not work in the normal VIM extension as c is an operator key and cannot be remapped. This is a call for someone to share their VIM re-mappings.

    "},{"location":"when-clauses/","title":"Calva When Clause Contexts","text":"

    When clause contexts is a powerful customization mechanism in VS Code. The most common use for end users is with keyboard shortcut bindings. Extensions can provide their own. The following contexts are available with Calva:

    • calva:keybindingsEnabled: a master switch that you find in the settings
    • paredit:keyMap: strict, original, or none from the corresponding Calva setting (see Paredit)
    • calva:connected: true when Calva is connected to a REPL (there is also calva:connecting || calva:launching)
    • calva:outputWindowActive: true when the Output/REPL window has input focus
    • calva:replHistoryCommandsActive: true when the cursor is in the Output/REPL window at the top level after the last prompt
    • calva:replWindowSubmitOnEnter: true when the cursor is adjacent after the last top level form in the Output/REPL window
    • calva:cursorInString: true when the cursor/caret is in a string or a regexp
    • calva:cursorInComment: true when the cursor is in, or adjacent to a line comment
    • calva:cursorBeforeComment: true when the cursor is adjacent before a line comment
    • calva:cursorAfterComment: true when the cursor is adjacent after a line comment
    • calva:cursorAtStartOfLine: true when the cursor is at the start of a line including any leading whitespace
    • calva:cursorAtEndOfLine: true when the cursor is at the end of a line including any trailing whitespace
    "},{"location":"why-calva/","title":"Why Calva?","text":"

    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

    "},{"location":"why-calva/#nick-cernis-on-clojureverse","title":"Nick Cernis on ClojureVerse","text":"

    My advice to anyone starting their Clojure journey who is unsure about what editor to use:

    • Pick something today and start writing Clojure.
    • Probably pick an editor you are familiar with already.
    • If you\u2019re not familiar with any editor yet or you don\u2019t have a strong allegiance to one, choose VS Code and Calva.
    • Switch to something else only if you encounter persistent annoyances that you can\u2019t remove with plugins, code/config changes, help from the community, or more sleep.

    I now use VS Code with Calva every day but went through a long journey trying almost every other editor and plugin combo first. I switched from Emacs to VS Code, which might make my perspective different to others here.

    \u2026

    I started with the jaded assumption that VS Code was probably bad because it's built by committee at Microsoft on a web-tech based Electron stack, only to find that it succeeds in embodying the spirit of a \u201chacker's editor\u201d more than even Emacs does in many ways:

    \u2026

    On the benefits of Calva:

    • Of all the amazing Clojure community projects, Calva seems most likely to encourage new users to try Clojure and ClojureScript. A lot of developers use VS Code. It\u2019s been tricky to convince frontend developer friends to try ClojureScript, but at least they don\u2019t have the excuse that they\u2019ll need to switch editors to even try it now. I think as a community we should try to support the projects that encourage Clojure\u2019s adoption and ease of use, including by using those products ourselves.

    • Calva provides a better first-time experience than any other editor/plugin combo whether you\u2019re new to Clojure or not. You can install the plugin and be chatting with your REPL in under a minute without any knowledge of Elisp or VimScript/Lua or how to configure Run Configurations in IntelliJ.

    • The default key bindings are good and the commands are easily discoverable.
    • For its age it\u2019s surprisingly feature rich.
    "},{"location":"why-calva/#100-five-star-marketplace-reviews","title":"100% Five-star Marketplace Reviews","text":"

    We are super proud of the Calva reviews on the Visual Studio Code Marketplace. Please read them all. \ud83d\ude04 Here's a selection that we think captures what we focus on in when developing Calva:

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f Calva has become an essential part of my Clojure workflow.

    It's an incredible piece of work by the team behind it.

    Sean Corfield

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f Calva hits the sweet spot of being both approachable for new users and powerful for seasoned ones.

    The creators/maintainers are fantastic individuals that care deeply about streamlining the user experience, and it shows.

    Good stuff, check it out.

    Clay Hopperdietzel

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f I switched from IntelliJ / Cursive to VS Code and Calva and it's been amazing.

    ...

    That is the biggest thing I can say for Calva, it just works. I was never a fan of VS Code before, but VS Code + Calva for Clojure is now my favorite language / IDE experience.

    Plus, the #calva on the clojurians slack is brilliant, always someone there to help if you have issues (although any issue I've had has been squarely on me, and never Calva itself).

    I often feel we live in an age where so much software is badly written, without care, slow, buggy and just generally awful. Calva is the complete opposite. I think the maintainers want to, and have, made a wonderful piece of software for Clojure developers.

    Stuart Stein

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f This is great, and makes VS Code a truly viable IDE/editor for clojure development.

    It already has great REPL support (including inline evaluation), an extensive Paredit implementation, and excellent linting (care of the bundled clj-kondo). Calva is being improved on at an impressive clip by maintainers who appear solidly committed to its ongoing development. It's well-documented, and manages to be both approachable and capable.

    A no-brainer if you're already a VS Code user, and well worth a look if you're not.

    Crispin Bennett

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f I'm using Calva now for a few months and I'm loving it.

    I joined the Slack channel about 2 wks ago and I must say that I'm very impressed by how active and responsive this community is. Already 2 of my issues fixed and I really like Calva (and the extensions it uses!).

    These are professional people and they make me very happy!

    Uitbeijerse, E (Eric)

    "},{"location":"workspace-layouts/","title":"Workspace Layouts","text":"

    Project directory layouts can vary quite a lot. From the \u201dtemplate\u201d projects where the Clojure project files are at the root, to, well, let's just say that the project files are not always at the root. And sometimes there is more than one project (read here how to get clojure-lsp support with a Leiningen project in a subfolder).

    Calva only really supports working with one project at a time per VS Code window. Here's a short guide for some different setups:

    1. You have one project in the workspace, the project files are in there somewhere.
      • Use a regular VS Code \u201dfolder window\u201d or a Workspace proper, both will totally work.
    2. You have more than one project in the repository, but only really work with one at a tine.
      • Use a Workspace proper and add the different project directories as separate Workspace Folders.
      • You can only jack-in/connect to one project at a time.
    3. You have more than one project in the repository, and need to work with them in parallell.
      • Open each project you want to work with in a separate VS Code window.
    "},{"location":"workspace-layouts/#one-folder-two-windows","title":"One Folder - Two Windows?","text":"

    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:

    1. Open a new VS Code window.
    2. Select File->Add Folder to Workspace.... Save the workspace as, say, Server.code-workspace.
    3. Open a new VS Code window.
    4. Select File->Add Folder to Workspace.... Save the workspace as, say, Client.code-workspace.

    Now, whenever you want to Jack-in to the backend and/or frontend, do it from the Server and/or Client workspace, respectively.

    "},{"location":"wsl/","title":"Calva \u2764\ufe0f WSL","text":"

    The use of Calva with WSL (Windows Subsystem for Linux) is fully supported through the Remote - WSL extension. Simply install the extension and open your project with one of the Remote-WSL commands. Calva will run directly in the WSL environment and no further configuration is required.

    "},{"location":"wsl/#steps-involved","title":"Steps Involved","text":"
    1. Enable WSL
    2. Install Ubuntu in WSL
    3. Install Java in WSL
    4. Install latest Clojure in WSL
    5. Install the Remote - WSL extension in VS Code
    6. Launch remote window
    7. Install Calva (gets installed into the WSL instance)
    8. Work away

    See also Remote Development.

    "}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-\\._]","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome!","text":"

    Calva is an integrated, REPL powered, development environment for enjoyable and productive Clojure and ClojureScript programming in Visual Studio Code. It is feature rich and turnkey. A lot of effort has been put into making Calva a good choice if you are new to Clojure. Calva is open source and free to use.

    "},{"location":"#getting-started","title":"Getting Started","text":"

    Let's start a REPL!. \ud83d\ude80 Also see Get Started with Clojure

    "},{"location":"#how-to-contribute-to-calva","title":"How to Contribute to Calva?","text":"

    I'm glad you asked! Please see How to Contribute and The Tao of Calva

    "},{"location":"#calva-patrons","title":"Calva Patrons","text":"The right kind of different"},{"location":"#calva-gold-sponsors","title":"Calva Gold Sponsors \u2665\ufe0f","text":"Scale your growth on mobile MAKE. DO. SHIP.

    Please see this statement from Cognitect about the importance of supporting open source developers.

    See Sponsors for information about sponsoring Calva.

    If your Company benefits from Calva's existence and you see it as an important in the Clojure and ClojureScript ecosystem. please consider sponsoring!

    "},{"location":"#features","title":"Features","text":"

    Calva includes inline code evaluation, structural editing, code formatting, code navigation, a debugger, linting, syntax highlighting, Clojure aware rainbow brackets, a test runner, refactoring support, and more.

    "},{"location":"#have-questions-and-feedback-need-help","title":"Have Questions and Feedback? Need Help?","text":"

    Easiest way is to chat with us and other Calva users. Please join the #calva channel on the Clojurians Slack. If you haven't joined that slack workspace, you can get an invite here.

    If you're a beginner to Clojure(Script), the #beginners channel of the Clojurians Slack is very active and helpful.

    "},{"location":"#please-star-the-calva-repo","title":"Please star the Calva repo!","text":"

    Happy coding!

    "},{"location":"api/","title":"The Calva Extension API","text":"

    Calva exposes an API for use from other VS Code extensions (such as Joyride). The API is in an experimental state, while we are figuring out what is a good shape for this API. It is also rather small, and will grow to expose more of Calva's functionality.

    ","boost":7},{"location":"api/#accessing","title":"Accessing","text":"

    To access the API the Calva extension needs to be activated. The API is exposed under the v1 key on the extension's exports, and split up into submodules, like repl, and ranges.

    When using Joyride you can use its unique require API, for which one of the benefits is better lookup IDE support. When using the API from regular ClojureScript, you'll pick it up from the Calva extension instance. (Which you can do from Joyride as well, but why would you?). Here is how you access the API, with an example of usage as a bonus:

    JoyrideClojureScriptJavaScript
    (ns ... (:require [\"ext://betterthantomorrow.calva$v1\" :as calva]))\n;; OR\n(require '[\"ext://betterthantomorrow.calva$v1\" :as calva])\n\n(calva/repl.currentSessionKey) => \"cljs\" ; or \"clj\", depending\n
    (def calvaExt (vscode/extensions.getExtension \"betterthantomorrow.calva\"))\n\n(def calva (-> calvaExt\n             .-exports\n             .-v1\n             (js->clj :keywordize-keys true)))\n\n((get-in calva [:repl :currentSessionKey])) => \"cljs\" ; or \"clj\", depending\n
    const calvaExt = vscode.extensions.getExtension(\"betterthantomorrow.calva\");\n\nconst calva = calvaExt.exports.v1;\n\nconst sessionKey = calva.repl.currentSessionKey()\n
    ","boost":7},{"location":"api/#repl","title":"repl","text":"

    The repl module provides access to Calva's REPL connection.

    ","boost":7},{"location":"api/#replcurrentsessionkey","title":"repl.currentSessionKey()","text":"

    Use repl.currentSessionKey() find out which REPL/session Calva's REPL is currently connected to (depends on the active file). Returns either \"clj\", or \"cljs\", or nil if no REPL is connected.

    JoyrideClojureScriptJavaScript
    (def session-key (calva/repl.currentSessionKey))\n
    (def session-key ((get-in [:repl :currentSessionKey] calvaApi)))\n
    const sessionKey = calva.repl.currentSessionKey()\n
    ","boost":7},{"location":"api/#replevaluatecode","title":"repl.evaluateCode()","text":"

    This function lets you evaluate Clojure code through Calva's nREPL connection. Calling it returns a promise that resolves to a Result object. It's signature looks like so (TypeScript):

    export async function evaluateCode(\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

    Where Result is:

    type Result = {\n  result: string;\n  ns: string;\n  output: string;\n  errorOutput: string;\n};\n

    As you can see, the required arguments to the function are sessionKey and code. sessionKey should be \"clj\", \"cljs\", \"cljc\", or undefined depending on which of Calva's REPL sessions/connections that should be used. It will depend on your project, and how you connect to it, which session keys are valid. Use cljc to request whatever REPL session \"cljc\" files are connected to. Use undefined to use the current REPL connection Calva would use (depends on which file is active).

    An example:

    JoyrideClojureScriptJavaScript
    (-> (p/let [evaluation (calva/repl.evaluateCode \"clj\" \"(+ 2 40)\")]\n      (println (.-result evaluation)))\n    (p/catch (fn [e]\n               (println \"Evaluation error:\" e))))\n
    (def evaluate (get-in [:repl :evaluateCode] calvaApi))\n(-> (p/let [evaluation (evaluate \"clj\" \"(+ 2 40)\")]\n      (println (.-result evaluation)))\n    (p/catch (fn [e]\n               (println \"Evaluation error:\" e))))\n
    try {\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
    ","boost":7},{"location":"api/#handling-output","title":"Handling Output","text":"

    The output member on the Result object will have any output produced during evaluation. (The errorOutput member should contain error output produced, but currently some Calva bug makes this not work.) By default the stdout and stderr output is not printed anywhere.

    If you want to do something with either regular output or error output during, or after, evaluation, you'll need to provide the output argument to evaluateCode(). (The stderr callback function works, so this is the only way to get at any error output, until the above mentioned Calva bug is fixed.)

    An example:

    JoyrideClojureScriptJavaScript
    (def oc (joyride.core/output-channel)) ;; Assuming Joyride is used\n(def evaluate (fn [code]\n                (calva/repl.evaluateCode\n                 \"clj\"\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
    ","boost":7},{"location":"api/#ranges","title":"ranges","text":"

    The ranges module contains functions for retreiving vscode.Ranges and text for pieces of interest in a Clojure document.

    All functions in this module have the following TypeScript signature:

    (editor = vscode.window.activeTextEditor, position = editor?.selection?.active) => [vscode.Range, string];\n

    I.e. they expect a vscode.TextEditor \u2013 defaulting to the currently active editor \u2013 and a vscode.Position \u2013 defaulting to the current active position in the editor (or the first active position if multiple selections/positions exist, and will return a tuple with the range, and the text for the piece of interest requested.

    Custom REPL Commands

    The ranges function have corresponding REPL Snippets/Commands substitution variables. It is the same implementation functions used in both cases.

    The functions available are:

    ","boost":7},{"location":"api/#rangescurrentform","title":"ranges.currentForm()","text":"

    Retrieves information about the current form, as determined from the editor and position.

    Corresponding REPL Snippet variable: $current-form.

    See also about Calva's Current Form on YouTube.

    ","boost":7},{"location":"api/#rangescurrentenclosingform","title":"ranges.currentEnclosingForm()","text":"

    The list/vector/etcetera form comtaining the current form.

    Corresponding REPL Snippet variable: $enclosing-form.

    ","boost":7},{"location":"api/#rangescurrenttoplevelform","title":"ranges.currentTopLevelForm()","text":"

    The current top level form. Outside (comment ...) (Rich comments) forms this is most often ((def ...), (defgn ...), etcetera. Inside Rich comments it will be the current immediate child to the (comment ...) form.

    Corresponding REPL Snippet variable: $top-level-form.

    ","boost":7},{"location":"api/#rangescurrentfunction","title":"ranges.currentFunction()","text":"

    The current function, i.e. the form in \u201dcall position\u201d of the closest enclosing list.

    Corresponding REPL Snippet variable: $current-fn.

    ","boost":7},{"location":"api/#rangescurrenttopleveldef","title":"ranges.currentTopLevelDef()","text":"

    The symbol being defined by the current top level form. NB: Will stupidly assume it is the second form. I.e. it does not check that it is an actual definition, and will often return nonsense if used in Rich comments.

    Corresponding REPL Snippet variable: $top-level-defined-symbol.

    ","boost":7},{"location":"api/#example-rangescurrenttoplevelform","title":"Example: ranges.currentTopLevelForm()","text":"JoyrideClojureScriptJavaScript
    (let [[range text] (calva/ranges.currentTopLevelForm)]\n  ...)\n
    (let [[range text] ((get-in [:ranges :currentTopLevelForm]))]\n  ...)\n
    const [range, text] = ranges.currentTopLevelForm();\n
    ","boost":7},{"location":"api/#editor","title":"editor","text":"

    The editor module has facilites (well, a facility, so far) for editing Clojure documents.

    ","boost":7},{"location":"api/#editorreplace","title":"editor.replace()","text":"

    With editor.replace() you can replace a range in a Clojure editor with new text. The arguments are:

    • editor, a vscode.TextEditor
    • range, a vscode.Range
    • newText, a string
    JoyrideJavaScript
    (-> (p/let [top-level-form-range (first (calva/ranges.currentTopLevelForm))\n            _ (calva/editor.replace vscode/window.activeTextEditor top-level-form-range \"Some new text\")]\n      (println \"Text replaced!\"))\n    (p/catch (fn [e]\n               (println \"Error replacing text:\" e))))\n
    const topLevelRange = calvaApi.ranges.currentTopLevelForm();\ncalva.editor.replace(topLevelRange, \"Some new text\")\n  .then((_) => console.log(\"Text replaced!\"))\n  .catch((e) => console.log(\"Error replacing text:\", e));\n
    ","boost":7},{"location":"api/#document","title":"document","text":"

    The document module provides access to the Clojure/Calva aspects of VS Code TextDocuments.

    ","boost":7},{"location":"api/#documentgetnamespacedocument-vscodetextdocument-string","title":"document.getNamespace(document?: vscode.TextDocument): string","text":"

    document.getNamespace() returns the namespace of a document.

    • document, a vscode.TextDocument (defaults to the current active document)

    Example usage. To evaluate some code in the namespace of the current document:

    JoyrideJavaScript
    (calva/repl.evaluateCode \"clj\" \"(+ 1 2 39)\" (calva/document.getNamespace))\n
    calva.repl.evaluateCode(\"clj\",  \"(+ 1 2 39)\", calva.document.getNamespace());\n
    ","boost":7},{"location":"api/#documentgetnamespaceandnsformdocument-vscodetextdocument-ns-string-nsform-string","title":"document.getNamespaceAndNsForm(document?: vscode.TextDocument): [ns: string, nsForm: string]","text":"

    document.getNamespaceAndNsForm() returns the namespace and the ns form of a document as a tuple.

    • document, a vscode.TextDocument (defaults to the current active document)

    Example usage. To evaluate the ns form of the current document:

    JoyrideJavaScript
    (calva/repl.evaluateCode \"clj\" (second (calva/document.getNamespaceAndNsForm)))\n
    calva.repl.evaluateCode(\"clj\", calva.document.getNamespaceAndNsForm()[1]);\n
    ","boost":7},{"location":"api/#pprint","title":"pprint","text":"

    The pprint module lets you pretty print Clojure code/data using Calva's pretty printing engine (which in turn uses zprint).

    ","boost":7},{"location":"api/#pprintprettyprint","title":"pprint.prettyPrint()","text":"

    Use pprint.prettyPrint() to pretty print some Clojure data using your Calva pretty printing options. It accepts these arguments:

    • text, a string with the text to pretty print
    • options, a JavaScript object with pretty printing options, this is optional and will default to the current settings.

    The function is synchronous and returns the prettified text.

    JoyrideJavaScript
    (println (calva/pprint.prettyPrint \"Some text\")))\n
    console.log(calvaApi.pprint.prettyPrint();\n
    ","boost":7},{"location":"api/#pprintprettyprintingoptions","title":"pprint.prettyPrintingOptions()","text":"

    Use to get the current pretty printint options:

    ","boost":7},{"location":"api/#vscode","title":"vscode","text":"

    In the its vscode submodule, Calva exposes access to things from its own vscode module instance. It gets important in some situations.

    ","boost":7},{"location":"api/#vscoderegisterdocumentsymbolprovider","title":"vscode.registerDocumentSymbolProvider()","text":"

    This is the [vscode.languages](https://code.visualstudio.com/api/references/vscode-api#languages).registerDocumentSymbolProvider() function from the Calva extension. Use it if you want to provide symbols for Clojure files together with the ones that Calva provides. (If you use the vscode.languages.registerDocumentSymbolProvider() function from your extension (or Joyride) you will provide a separate group.)

    JoyrideClojureScriptJavaScript
    (-> (joyride/extension-context)\n  .-subscriptions\n  (.push (calva/vscode.registerDocumentSymbolProvider ...)))\n
    (-> yourExtensionContext\n  .-subscriptions\n  (.push ((get-in calva [:vscode :registerDocumentSymbolProvider]) ...)))\n
    yourExtensionContext.subscriptions.push(calva.vscode.registerDocumentSymbolProvider(...));\n

    Deprecation candidate

    VS Code is still creating a separate group, just with the same name as Calva's, so this API is not good for anything, and we will probably remove it.

    ","boost":7},{"location":"api/#feedback-welcome","title":"Feedback Welcome","text":"

    Please let us know how you fare using this API. Either in the #calva or #joyride channels on Slack or via the issues/discussions sections on the repositories. (Whichever seems to apply best.)

    ","boost":7},{"location":"async-out/","title":"Viewing Async Output While Working On Node Projects with shadow-cljs","text":"

    When working on NodeJS projects with shadow-cljs and Calva, async output does not always appear in the Calva output window. To work around this problem, follow these steps:

    1. Run the command \"Calva: Copy Jack-in Command Line to Clipboard\", then paste the command in a terminal and run it.
    2. Wait for the message shadow-cljs - nREPL server started on port <some-port>
    3. Issue the command Calva: Connect to a running REPL server in your project, ctrl+alt+c ctrl+alt+c. For project type select shadow-cljs, accept the proposed localhost:<some-port>, and for build select node-repl.
    4. Load a file from your project with the command ctrl+alt+c Enter. Evaluating forms in Calva will show results in the output window. Synchronous stdout output will be printed in both the output window and in the terminal where you started the repl. Some asynchronous output may show up in the output window, but all will appear in the terminal.

    If you use an integrated VSCode terminal to start shadow-cljs, all stdout will appear in the Calva window with your code. Alternatively, you can use an external terminal, which is especially nice when using a second monitor.

    For a discussion of this problem and other connection options, see issue #1468.

    "},{"location":"babashka/","title":"Using Calva with Babashka","text":"

    Since Babashka can be started such that it is an nREPL server, Calva can connect to it and a lot of the features will work.

    Calva can also start Babashka and connect its REPL for you, using the Jack-in command.

    Don't expect complete support

    Babashka's nREPL server is still a bit limited compared to a full cider-nrepl enhanced \"regular\" Clojure nREPL server. Things like function signatures, and more do not work.

    This might of course improve in the future, especially if you provide some PRs towards the Babashka nREPL.

    ","boost":5},{"location":"clj-java-decompiler/","title":"Decompiling and disassembly made easy","text":"

    If you need some piece of Clojure code to execute as fast as possible you will often benefit from examining the code generated by the Clojure compiler from your code. There is a really easy to use tool for that: clj-java-decompiler. You can make the use of this tool super convenient with Calva custom command snippets.

    "},{"location":"clj-java-decompiler/#prerequisites","title":"Prerequisites","text":"

    Add com.clojure-goes-fast/clj-java-decompiler as a dependency to the project.

    "},{"location":"clj-java-decompiler/#the-custom-snippets","title":"The custom snippets","text":"

    You can add some Calva custom commands configuration to be able to decompile or disassemble any Clojure code in your editor with a keyboard shortcut. Here's an example configuration:

        \"calva.customREPLCommandSnippets\": [\n        {\n            \"name\": \"Decompile current top level form\",\n            \"key\": \"d\",\n            \"snippet\": \"(require '[clj-java-decompiler.core :refer [decompile]]) (spit \\\"decompiled-$top-level-defined-symbol.java\\\" (with-out-str (decompile $top-level-form)))\"\n        },\n        {\n            \"name\": \"Decompile current form\",\n            \"snippet\": \"(require '[clj-java-decompiler.core :refer [decompile]]) (spit \\\"decompiled.java\\\" (with-out-str (decompile $current-form)))\"\n        },\n        {\n            \"name\": \"Disassemble current top level form\",\n            \"key\": \"b\",\n            \"snippet\": \"(require '[clj-java-decompiler.core :refer [disassemble]]) (spit \\\"bytecode-$top-level-defined-symbol.class\\\" (with-out-str (disassemble $top-level-form)))\"\n        },\n        {\n            \"name\": \"Disassemble current current form\",\n            \"snippet\": \"(require '[clj-java-decompiler.core :refer [disassemble]]) (spit \\\"bytecode.class\\\" (with-out-str (disassemble $current-form)))\"\n        }\n    ],\n

    Now, with the cursor anywhere in a top level defined function, you can spit out a file with the Java code generated for that function by pressing ctrl+alt+space d. For the byte code, press ctrl+alt+space b. The files will be generated in the same folder as the Clojure file and be named decompiled-<function name>.java and bytecode-<function name>.class, respectively.

    To decompile or disassemble the current form (or selection) press ctrl+alt+space space and pick the desired command from the quick pick menu that pops up. You can add key to these too if you want even quicker access, of course. The filenames for the results will here be named without any function name suffix, because there is often no function name that can be used.

    See this video for a demo.

    "},{"location":"clojure-lsp/","title":"Clojure-lsp","text":"

    Calva uses a mix of static and dynamic analysis to power the experience. A lot of the static abilities come from clojure-lsp. This enables you to check something up in a project, with a lot of navigational and contextual support, without starting a REPL for it. (And once you do start a REPL you'll get even more capabilities, enabled by the dynamic analysis.)

    Which clojure-lsp does Calva use?

    Calva defaults to using the latest clojure-lsp released. To use a different version of clojure-lsp, see the configuration section. Calva does not use the clojure-lsp installed on your system, unless you set the path for clojure-lsp to the installed binary in your settings. You can see what version is being used by running the Clojure-lsp Server Info command, which will also show the version of clj-kondo that's being used as well as other info.

    "},{"location":"clojure-lsp/#the-lsp-server-lifecycle","title":"The LSP server lifecycle","text":"

    By default you won't need to install/setup anything as Calva handles that for you by automatically downloading the latest clojure-lsp binary. It can take a while for clojure-lsp to start, especially the first time opening a new project, as clojure-lsp (via clj-kondo) indexes the project files.

    Calva is able to automatically start the clojure-lsp server for you and can be configured to start the server under various different conditions. These behaviours can be configured through the calva.enableClojureLspOnStart setting, which takes the following options:

    • \"always-use-first-workspace-root\"
    • \"when-workspace-opened-use-workspace-root\"
    • \"when-file-opened-use-furthest-project\"
    • \"never\"
    "},{"location":"clojure-lsp/#always-use-first-workspace-root-default","title":"\"always-use-first-workspace-root\" [default]","text":"

    When set to \"always-use-first-workspace-root\" Calva will attempt to start the clojure-lsp in the root of the first workspace folder if it is a valid clojure project. If it is not a valid clojure project it will fall back to starting the fallback server.

    This is the default auto-start behaviour.

    "},{"location":"clojure-lsp/#when-workspace-opened-use-workspace-root","title":"\"when-workspace-opened-use-workspace-root\"","text":"

    When set to \"when-workspace-opened-use-workspace-root\" Calva will start the clojure-lsp in the root of all opened vscode workspaces. All Clojure files in a workspace will be serviced by the clojure-lsp server running in that workspace. This behavior requires that you are opening workspaces with a valid Clojure project in the root (the directory must contain a deps.edn, project.clj or shadow-cljs.edn file).

    "},{"location":"clojure-lsp/#when-file-opened-use-furthest-project","title":"\"when-file-opened-use-furthest-project\"","text":"

    When set to \"when-file-opened-use-furthest-project\" Calva will attempt to start the clojure-lsp server whenever a Clojure file is opened. The LSP server will be started in the outermost valid Clojure project or will fall back to starting in the workspace root if no valid Clojure project can be found. A directory is considered a Clojure project if it contains typical Clojure project files such as a deps.edn, project.clj, or shadow-cljs.edn file. When working in a mono-repo style project or in a multi-workspace VS Code configuration you may have multiple LSP servers running, one for each independent Clojure project opened.

    Opening files that do not belong to a workspace folder

    When opening files that do not belong to any of the workspace folders currently open then Calva will fallback to starting the fallback clojure-lsp server

    "},{"location":"clojure-lsp/#never","title":"\"never\"","text":"

    When set to \"never\" Calva will never attempt to automatically start the clojure-lsp server. In this case you are responsible for manually starting the server. More advanced users might want to do this in order to have more control over which projects have a clojure-lsp server running for them. To manually start the clojure-lsp server you can run the calva.clojureLsp.start or the calva.clojureLsp.manage command and pick the project root. You can also click the clojure-lsp status bar icon to open the Management Menu.

    Additionally Calva has commands for:

    • Inspecting the clojure-lsp server information
    • Read the clojure-lsp server log
    • Stopping any running clojure-lsp processes
    • Starting clojure-lsp
    • Restarting any running clojure-lsp processes
    • Downloading the configured clojure-lsp version

    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.

    "},{"location":"clojure-lsp/#fallback-server","title":"Fallback Server","text":"

    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).

    "},{"location":"clojure-lsp/#status-bar","title":"Status bar","text":"

    In the status bar Calva will show an indicator with the clojure-lsp status. This status will track the currently open project, showing the status (stopped, starting or active) for the relevant clojure-lsp server.

    You can click on the status-bar item to open the clojure-lsp management menu which will look as follows:

    The menu shows which clojure-lsp servers are active and which are stopped. Selecting a project will allow you to start/stop/restart the server for that project.

    "},{"location":"clojure-lsp/#ignoring-lsp-cache-files","title":"Ignoring LSP cache files","text":"

    Clojure-lsp stores its project analysis information in your project. Git users can add these lines to their project root directory .gitignore:

    .lsp/.cache/\n.lsp/sqlite.*.db\n
    "},{"location":"clojure-lsp/#configuration","title":"Configuration","text":"

    For information about how to configure clojure-lsp, see the settings page of the clojure-lsp docs.

    "},{"location":"clojure-lsp/#changing-the-version-of-clojure-lsp-used-by-calva","title":"Changing the Version of Clojure-lsp Used by Calva","text":"

    By default, Calva will use the latest released clojure-lsp. You can change the version of clojure-lsp used by Calva by setting the calva.clojureLspVersion property to a version of clojure-lsp found in its GitHub releases. This can be helpful if you're debugging an issue with clojure-lsp or you want to try out a feature of a new release that Calva does not yet use. However, you must remember to reset this setting in order for Calva to automatically use newer versions of clojure-lsp that are released with new versions of Calva.

    Example:

    \"calva.clojureLspVersion\": \"2021.04.07-16.34.10\"\n

    Special \u201dversion\u201d values

    Apart from the actual versions you can use two special values for this setting:

    • latest: Will download and use the latest stable build of clojure-lsp, when one becomes available. This is the default
    • nightly: Will always download and use the latest nightly build, whether there is a new version available or not.
    "},{"location":"clojure-lsp/#using-a-custom-clojure-lsp","title":"Using a Custom Clojure-lsp","text":"

    You can set a path to a custom clojure-lsp to be used by Calva by configuring the calva.clojureLspPath setting. This should be an absolute path to a native binary or JAR file.

    Example:

    \"calva.clojureLspPath\": \"/usr/local/bin/clojure-lsp\"\n

    Will override any calva.clojureLspVersion setting

    When calva.clojureLspPath is set, the binary at the path will be used uncoditionally, and the calva.clojureLspVersion setting will be ignored.

    "},{"location":"clojure-lsp/#extra-commands","title":"Extra commands","text":"

    clojure-lsp provides many useful [commands], and Calva has configuration for most of them. The clojure-lsp team works fast and sometimes Calva might miss some command. And Calva's configuration only really work for clojure-lsp commands that take no argument, or where it makes sense to prompt for the argument. Therefore Calva provides a generic command id, clojure-lsp.command which can be used with keyboard shortcuts and that allow for providing arguments that way. (The command can be used from Joyride too, of course.)

    When using the command, provide the args as an tuple of [command-name, arguments], where arguments is an array of any arguments after file-uri, row, col which are common for all clojure-lsp extra commands and are provided automatically by Calva, based on active text editor and where the cursor is. It can look like so when binding a shortcut for extract-function:

        {\n        \"key\": \"ctrl+alt+r f\",\n        \"command\": \"clojure-lsp.command\",\n        \"args\": [\"extract-function\", [\"new-function\"]]\n    },\n

    Note that even though extract-function takes only one argument, you should still provide it via an array.

    "},{"location":"clojure-lsp/#troubleshooting","title":"Troubleshooting","text":""},{"location":"clojure-lsp/#viewing-the-logs-between-the-client-and-server","title":"Viewing the Logs Between the Client and Server","text":"

    If something doesn't seem to be working correctly, and you suspect the issue is related to clojure-lsp, a good place to start investigating is the request and response logs between the LSP client and server. In your settings, set clojure.trace.server to verbose, then in the VS Code output tab, select the Clojure Language Client output channel.

    It may be helpful to clear the output channel, then perform the action with which you're experiencing a problem, then read through the log for clues or paste the logs into a related issue in the Calva repo.

    "},{"location":"clojure-lsp/#server-info-command","title":"Server Info Command","text":"

    You can run the Clojure-lsp Server Info command to get information about the running clojure-lsp server, such as the version the server being used, the version of clj-kondo it's using, and more. This info is printed to the \"Calva says\" output channel.

    "},{"location":"clojure-lsp/#opening-the-server-log-file","title":"Opening the Server Log File","text":"

    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.

    "},{"location":"clojure-lsp/#server-initialization-failed","title":"Server initialization failed","text":"

    If clojure-lsp fails to start with \u201cServer initialization failed\u201d messages, it could be because the path to your project contains non-ASCII characters, or that the system PATH variable has been corrupted. (Or something else, of course.)

    See this issue for some findings about it: Issue #2251: Server initialization failed error

    "},{"location":"clojure-lsp/#related","title":"Related","text":"

    See also:

    • Connecting the REPL
    • Refactoring
    "},{"location":"clojuredart/","title":"Using Calva with ClojureDart","text":"

    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.

    ","boost":4},{"location":"clojuredart/#dart-clojure-conversion","title":"Dart->Clojure Conversion","text":"

    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:

    • DartClojure

    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:

    1. Open a new untitled file/tab
    2. Paste your Dart/Flutter code in this file (VS Code will probably automatically figure out that it is Dart code, even if that doesn't matter for the converter.)
    3. Run Calva: Convert Dart code to Clojure/ClojureDart
    4. An, untitled, Clojure tab will open with the converted code in it.

    NB: The conversion will not always work. DartCLojure is work in progress. See the project repo for limitations and scope. Often when conversion, the error message will give you a clue to what is problematic. Try adjust your code selection and you will probably be able to get at least some help from the converter.

    Speaking of WIP...

    ","boost":4},{"location":"clojuredart/#work-in-progress","title":"Work in Progress","text":"

    ClojureDart is very new and being super actively developed. Some feature are still missing. Like a REPL. Once that is added we will also add ClojureDart jack-in and connect support to Calva.

    ","boost":4},{"location":"clojuredart/#happy-clojuredart-hacking","title":"Happy ClojureDart Hacking!","text":"

    Please feel welcome to the #clojuredart and #calva channel at the Clojurians Slack for questions, suggestions and support.

    ","boost":4},{"location":"clojuredocs/","title":"ClojureDocs integration","text":"

    clojuredocs.org is the goto place #1 for finding out more about Clojure core(-ish) functions, macros, etcetera. It contains the doc strings from the functions and adds crowd sourced examples of usage and see alsos. You can surf for quite long on that site without getting bored. \ud83d\ude04

    You can surf ClojureDocs in Calva

    Calva integrates this information in two ways:

    1. Commands for requesting the ClojureDocs information for a symbol under the cursor:
      • Print clojuredocs.org examples to Rich Comment, default keybinding: ctrl+alt+r d
      • Print clojuredocs.org examples to OutputWindow, ctrl+alt+o d
    2. ClojureDocs information is included in the symbol lookup hovers, where each example has two buttons:
      • To Rich Comment
      • To Output Window

    That means that if you just want to glance at the examples, you look in the hover. And when you want to bring the examples to the REPL to play with them, you can do so very easily.

    ClojureScript support

    ClojureDocs information is available both for Clojure and ClojureScript files. However, clojuredocs.org only keeps info for Clojure. Thus: All information Calva shows about a symbol will be about the Clojure respresentation of that symbol. (The symbol might not even exist in ClojureScript.)

    ","boost":4},{"location":"clojuredocs/#clojuredocs-repl-surfing","title":"ClojureDocs REPL Surfing","text":"

    Since the ClojureDocs information includes see-alsos, you can go for super interactive ClojureDocs surfing right in the file you are editing. Say you have this function:

    (defn trim-text\n  \"Returns text without surrounding whitespace if not empty, otherwise nil\"\n  [text]\n  (let [trimmed-text (clojure.string/trim text)]\n    (when-not (empty? trimmed-text)\n      trimmed-text)))\n

    Then you hover on when-not and scroll down a bit in the hover:

    That first example would be interesting to play with, right? Click To Rich Comment and you will get:

    (defn trim-text\n  \"Returns text without surrounding whitespace if not empty, otherwise nil\"\n  [text]\n  (let [trimmed-text (clojure.string/trim text)]\n    (when-not (empty? trimmed-text)\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

    There you can evaluate the (map ...) form using alt+enter, modify it and evaluate again. You can also hover over map, iterate, or any of the \u201dSee also:\u201d symbols to find more fun examples to play with. And so on and so forth.

    See these two tweets for some videos of early versions of this functionality:

    • Rich Comments surfing ClojureDocs Examples
    • Clojuredocs in #Calva WIP 2: Hover examples -> RFC

    Please retweet!

    ","boost":4},{"location":"clojuredocs/#quirks","title":"Quirks","text":"

    Some of the ClojureDocs entries have text that is not really Clojure code, and sometimes even structural errors. This can break the structural integrity of your Clojure file. If you run into trouble trying to heal things, you can always use Undo until the Rich Comment is gone.

    ","boost":4},{"location":"commands-top10/","title":"The Top 10 Calva Commands","text":"

    There are not all that many Calva commands. You can learn them all if you like, but here are the most important ones to know about for effective Clojure/ClojureScript coding:

    • Grow/expand selection: ctrl+w (shift+alt+right on Windows and Linux)
    • Load/Evaluate Current File and its Requires/Dependencies: alt+ctrl+c enter, evaluates the namespace code in the active editor tab. This also loads any required namespaces, and generally gives Calva what it needs to work.
    • Evaluate current form: ctrl+enter finds the form from the cursor position, evaluates it and displays the result inline. Hit esc to dismiss the results display.
    • Evaluate current top-level form: alt+enter: inline evaluate the current top-level form. This also works inside (comment) forms. Use it to (re)define vars and then inside comment forms you can verify that they do what you want them to do.
    • Dismiss the display of results: escape: (VIM Extension users should read Using Calva with the VIM Extension).

    There are also two commands for bringing over the current form and the current top level form over to the repl window:

    • ctrl+alt+c ctrl+alt+e (ctrl+alt+c ctrl+alt+v on Windows): to paste the current form in the REPL window.
    • ctrl+alt+c ctrl+alt+space: to paste the current top-level form in this window

    You can also switch the name space of the output/repl window to that of the current file: alt+ctrl+c alt+n

    • Toggle pretty printing of results on and off: ctrl+alt+c p. It's on by default. There is a status bar button showing the status and that also can be used to toggle the setting.
    "},{"location":"commands-top10/#some-more-commands-to-try","title":"Some More Commands to Try","text":"
    • Code evaluation
      • Evaluate code and add as comment: ctrl+alt+c c (current form), ctrl+alt+c ctrl+space (current top level form)
      • Evaluate code and replace it in the editor, inline: ctrl+alt+c r
    • Integrated REPLs
      • Send current editor form to the REPL window: ctrl+alt+c ctrl+alt+e (ctrl+alt+c ctrl+alt+v on Windows)
      • Send current editor top level form to the REPL window: ctrl+alt+c ctrl+alt+space
    • Run tests and mark failures and errors in the Problems pane
      • Run namespace tests: ctrl+alt+c t
      • Run all tests: ctrl+alt+c shift+t
      • Run current test: ctrl+alt+c ctrl+alt+t
      • Rerun previously failing tests: ctrl+alt+c ctrl+t
      • Caveat: Right now the tests are reported only when all are run, making it painful to run all tests in larger projects. I'll fix it. Promise!
    • Select current form: ctrl+alt+c s.
    • Run custom commands, i.e. code snippets, at will: ctrl+alt+c .

    See also:

    • Code Evaluation Tips
    • Finding Calva Commands and Shortcuts
    "},{"location":"connect-sequences/","title":"REPL Jack-in and Connect Sequences","text":"

    Many projects grow out of the template phase and call for custom developer workflows involving application start commands, customized REPLs, and what have you. Even some templates add this kind of complexity. To make Jack-in usable for a broader set of projects, Calva has a setting keyed calva.replConnectSequences which lets you configure one ore more connect sequences.

    NB: Connect sequence configuration affects Calva's Jack-in menu in the following ways:

    1. With no sequence configured, Calva will prompt for the built-in sequences it has that seems to match your project.
    2. When any number of connection sequences are configured, Calva will prompt for your custom sequences, as well as the built-in sequences. Whether built-in or custom, only sequences relevant to your project will be included in the prompt.
    ","boost":6},{"location":"connect-sequences/#settings-for-adding-custom-sequences","title":"Settings for adding Custom Sequences","text":"

    A connect sequence configures the following:

    • name: (required) This will show up in the Jack-in quick-pick menu when you start Jack-in (see above).
    • projectType: (required) This is either \"Leiningen\u201d, \"deps.edn\", \"shadow-cljs\", \"lein-shadow\", \"Gradle\", \u201dgeneric\u201d, or \"custom\".
    • autoSelectForJackIn: A boolean. If true, this sequence will be automatically selected at Jack-in, suppressing the Project Type. Use together with projectRootPath to also suppress the Project Root menu. Add usage of menuSelections to go for a prompt-less REPL Jack-in. If you have more than one sequence with autoSelectForJackIn set to true, the first one will be used.
    • autoSelectForConnect: A boolean. If true, this sequence will be automatically selected at Connect, suppressing the Project Type menu. Use together with projectRootPath to also suppress the Project Root menu. If you have more than one sequence with autoSelectForConnect set to true, the first one will be used.
    • projectRootPath: An array of path segments leading to the root of the project to which this connect sequence corresponds. Use together with autoSelectForJackIn/autoSelectForConnect to suppress the Project Root menu. The path can be absolute or relative to the workspace root. If there are several Workspace Folders, the workspace root is the path of the first folder, so relative paths will only work for this first folder.
    • nReplPortFile: An array of path segments with the project root-relative path to the nREPL port file for this connect sequence. E.g. For shadow-cljs this would be [\".shadow-cljs\", \"nrepl.port\"].
    • afterCLJReplJackInCode: Code to evaluate in the CLJ REPL once it has been created. You can use either a string or an array of strings. If you use an array, the strings will be joined with a newline character to form the resulting code.
    • customJackInCommandLine: A string with a command line that should be used to launch the REPL. See Custom Command Line, below.
    • cljsType: This can be either \"Figwheel Main\", \"shadow-cljs\", \"ClojureScript built-in for browser\", \"ClojureScript built-in for node\", \"lein-figwheel\", \"none\", or a dictionary configuring a custom type. If set to \"none\", Calva will skip connecting a ClojureScript repl. A custom type has the following fields:
      • dependsOn: (required) Calva will use this to determine which dependencies it will add when starting the project (Jacking in). This can be either \"Figwheel Main\", \"shadow-cljs\", \"ClojureScript built-in for browser\", \"ClojureScript built-in for node\", \"lein-figwheel\", or \u201dUser provided\u201d. If it is \"User provided\", then you need to provide the dependencies in the project or launch with an alias (deps.edn), profile (Leiningen), or build (shadow-cljs) that provides the dependencies needed.
      • isStarted: Boolean. For CLJS REPLs that Calva does not need to start, set this to true. (If you base your custom cljs repl on a shadow-cljs workflow, for instance.)
      • startCode: Clojure code to be evaluated to create and/or start your custom CLJS REPL.
      • isReadyToStartRegExp: A regular expression which, when matched in the stdout from the startCode evaluation, will make Calva continue with connecting the REPL, and to prompt the user to start the application. If omitted and there is startCode Calva will continue when that code is evaluated.
      • openUrlRegExp: A regular expression, matched against the stdout of cljsType evaluations, for extracting the URL with which the app can be started. The expression should have a capturing group named url. E.g. \"Open URL: (?\\<url>S+)\"
      • shouldOpenUrl: Choose if Calva should automatically open the URL for you or not.
      • connectCode: (required) Clojure code to be evaluated to convert the REPL to a CLJS REPL that Calva can use to connect to the application. (For some setups this could also conditionally start the CLJS REPL. If so: startCode should be omitted.)
      • isConnectedRegExp: (required) A regular expression which, when matched in the stdout from the connectCode evaluation, will tell Calva that the application is connected. The default is To quit, type: :cljs/quit and you should leave it at that unless you know it won't work.
      • printThisLineRegExp: regular expression which, when matched in the stdout from any code evaluations in the cljsType, will make the matched text be printed to the Output window.
      • buildsRequired: Boolean. If the repl type requires that builds are started in order to connect to them, set this to true.
    • menuSelections: a dictionary with pre-filled-in selections for the Jack-in and Connect prompts, making Calva not prompt for that particular selection:
      • leinProfiles: At Jack-in to a Leiningen project, use these profiles to launch the repl.
      • leinAlias: At Jack-in to a Leiningen project, launch with this alias. Set to null to launch with Calva's default task (a headless repl), w/o prompting.
      • cljAliases: At Jack-in to a deps.edn project, use these aliases to launch the repl.
      • cljsLaunchBuilds: The cljs builds to start/watch at Jack-in/connect.
      • cljsDefaultBuild: Which cljs build to attach to at the initial connect.
    • jackInEnv: An object with environment variables that will be merged with the global calva.jackInEnv and then applied to the Jack-in process. The merge is very similar to how Clojure's merge works. So for any common keys between the global setting and this one, the ones from this setting will win.

    The Calva built-in sequences also use this format, check them out to get a clearer picture of how these settings work.

    Force the project type menu to show

    The convenience of autoSelectForJackIn/Connect can be an inconvenience when you want to use another project type/sequence for a project. For this reason, the calva.connect and calva.jackIn can be provided with an option disableAutoSelect, which forces the project root and project type menus to show. See Options for the Connect Command and Options for the Jack-in Command for more on this.

    Path segments

    projectRootPath and nReplPortFile both take an array of path segments. This is to make the paths work cross-platform. If you can't be bothered splitting up the path in segments, put the whole path in the first segment, though please note that if you use Windows path separators, these will not work for users with Linux or macOS.

    ","boost":6},{"location":"connect-sequences/#custom-command-line","title":"Custom Command Line","text":"

    Custom command lines are there to bridge the gap to those situations where standard Jack-in command lines don't reach. Like:

    1. You want to provide command line options to a supported tool, which Jack-in does not provide
    2. Your project has some script through which it is started
    3. The REPL is provided by some tool that Calva does not know of
    4. Any other reason...

    A custom command line is executed from same directory as the REPL project root (See projectRootPath, above), and can be as simple as my-repl-jack-in-command. You can use a relative or absolute path to your command line.

    If your custom command line starts a REPL of a project type that is not \u201dknown\u201d/built-in to Calva, use custom as the projectType for the connect sequence.

    ","boost":6},{"location":"connect-sequences/#custom-command-line-substitutionsplaceholdersenvironment-variables","title":"Custom Command Line Substitutions/Placeholders/Environment variables","text":"

    You can use placeholders in your command line, and Calva will substitute them before executing the command. All these placeholders will also be provided to your script via environment variables with the same names (except dashes will be underscores in the env variable names):

    nREPL dependency versions:

    • JACK-IN-NREPL-VERSION
    • JACK-IN-CIDER-NREPL-VERSION
    • JACK-IN-CIDER-PIGGIEBACK-VERSION

    Paths:

    • JACK-IN-PROJECT-ROOT-PATH: (See projectRootPath, above)
    • JACK-IN-NREPL-PORT-FILE: The path of the nREPL port file (see nReplPortFile above)

    Depending on the project type Calva will also look for these placeholders:

    • JACK-IN-CLJ-MIDDLEWARE: The nREPL middleware to be used for the Clojure REPL
    • JACK-IN-CLJS-MIDDLEWARE: The nREPL middleware to be used for the ClojureScript REPL
    • JACK-IN-LEIN-PROFILES: For Leiningen projects, the profiles selected by the user
    • JACK-IN-LEIN-LAUNCH-ALIAS: For Leiningen projects, the launch alias selected by the user
    • JACK-IN-CLI-ALIASES: For deps.edn projects, the aliases selected by the user
    • JACK-IN-CLJS-LAUNCH-BUILDS: For ClojureScript REPLs that configures builds, the builds selected by the user
    • JACK-IN-NREPL-PORT: For some project types (currently nbb and Babashka) Calva provided the TCP port they should use.
    ","boost":6},{"location":"connect-sequences/#example-custom-jack-in-command-lines","title":"Example Custom Jack-in Command lines","text":"","boost":6},{"location":"connect-sequences/#start-a-babashka-repl-via-wsl","title":"Start a Babashka REPL via WSL","text":"

    Calva has a built-in jack-in sequence for starting a Babashka REPL and connect to it. It works as long as the bb process is on the same host as VS Code/Calva is running. So if you want it to run in WSL, but VS Code is running on your computer you need to start bb slightly differently. These settings in your VS Code settings file will give you a jack-in option that works for this:

      \"calva.replConnectSequences\": [\n    {\n        \"name\": \"Bashbabka (WSL)\",\n        \"projectType\": \"custom\",\n        \"customJackInCommandLine\": \"bash -c 'bb --nrepl-server JACK-IN-NREPL-PORT'\",\n    },\n  ],\n

    If you place it in your user settings you will have access to it from any workspace.

    ","boost":6},{"location":"connect-sequences/#an-exampleskeleton-script","title":"An example/skeleton script","text":"

    This script doesn't actually start a REPL, it's provided more for giving you an idea about what it could look like, and as a starting point for your real scripts:

    #!/usr/bin/env bb\n\n(require '[clojure.string :as str])\n\n(defn parse-args [args]\n  (loop [args args\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

    It's written in Babashka to encourage you to write your shell scripts in a civilized language. \ud83d\ude00 See the article Changing my mind: Converting a script from bash to Babashka for a small success-story about this mindset. See also bash2bb.

    The script reads JACK-IN-CLJS-LAUNCH-BUILDS and JACK-IN-CIDER-NREPL-VERSION from the command line, and JACK_IN_PROJECT_ROOT_PATH from the environment. It could be configured for use in a custom connect sequence like this:

        \"customJackInCommandLine\": \"../../custom-jack-in.bb --aliases JACK-IN-CLJS-LAUNCH-BUILDS --cider-nrepl-version JACK-IN-CIDER-NREPL-VERSION\",\n

    Note how in this case the REPL is started two directories \u201ddown\u201d from the workspace root where the script resides.

    ","boost":6},{"location":"connect-sequences/#example-sequences","title":"Example Sequences","text":"

    Whether you just want to speed up your workflow or encode some workflow/mechanics into it, it's often the case that you can create a custom sequence that helps.

    ","boost":6},{"location":"connect-sequences/#minimal-menus-with-full-stack-shadow-cljs-repls","title":"Minimal menus with full stack shadow-cljs REPLs","text":"

    Minimize the amount of selecting from the Jack-in/Connect menu when working with a full-stack shadow-cljs + deps/lein project:

        {\n      \"name\": \"backend + frontend\",\n      \"projectType\": \"shadow-cljs\",\n      \"cljsType\": \"shadow-cljs\",\n      \"menuSelections\": {\n        \"cljsLaunchBuilds\": [\n          \":app\",\n          \":test\",\n        ],\n        \"cljsDefaultBuild\": \":app\"\n      }\n    }\n

    See shadow-cljs + Clojure with Calva: The basics for how Calva and nREPL work with ClojureScript.

    ","boost":6},{"location":"connect-sequences/#polylith","title":"Polylith","text":"

    This is the connect sequences used in the Polylith Real World App. The (start) sequence lets you jack-in to the project, and starts the Real World App without any prompts. The (connect) sequence can be used if you prefer to start the REPL manually, and want to connect without prompts.

        \"calva.replConnectSequences\": [\n        {\n            \"projectType\": \"deps.edn\",\n            \"afterCLJReplJackInCode\": \"(require '[dev.server] :reload) (in-ns 'dev.server) (start! 6003)\",\n            \"name\": \"Polylith RealWorld Server REPL (start)\",\n            \"autoSelectForJackIn\": true,\n            \"projectRootPath\": [\".\"],\n            \"cljsType\": \"none\",\n            \"menuSelections\": {\n                \"cljAliases\": [\"dev\", \"test\"]\n            }\n        },\n        {\n            \"projectType\": \"deps.edn\",\n            \"name\": \"Polylith RealWorld Server REPL (connect)\",\n            \"autoSelectForConnect\": true,\n            \"projectRootPath\": [\".\"],\n            \"cljsType\": \"none\",\n        }\n    ],\n    \"calva.autoConnectRepl\": true,\n

    The calva.autoConnectRepl, when set to true, makes Calva, at project open, look for the nRepl port file and automatically connect the repl if the file exists. Therefore, you can leave the app running when you close the project in VS Code, and Calva will reconnect when you open the project again. (Alternatively, maybe you just need to reload the VS Code window and not lose the REPL state.)

    ","boost":6},{"location":"connect-sequences/#minimal-menus-with-full-stack-depsedn-and-figwheel-main-repls","title":"Minimal menus with full stack deps.edn and Figwheel Main REPLs","text":"

    Setting for a full-stack application. It starts the backend server when the CLJ REPL has started. Then proceeds to create a custom CLJS REPL (calling in to the application code for this). And then connects to it.

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Example Sequence\",\n            \"projectType\": \"Clojure-CLI\",\n            \"afterCLJReplJackInCode\": \"(go)\",\n            \"cljsType\": {\n                \"startCode\": \"(do (require '[cljs-test.main :refer :all])(start-nrepl+fig))\",\n                \"isReadyToStartRegExp\": \"Prompt will show\",\n                \"connectCode\": \"(do (use 'cljs-test.main) (cljs-repl))\",\n                \"isConnectedRegExp\": \"To quit, type: :cljs/quit\",\n                \"printThisLineRegExp\": \"\\\\[Figwheel\\\\] Starting Server at.*\"\n            }\n        }\n    ]\n}\n
    ","boost":6},{"location":"connect-sequences/#juxt-edge","title":"JUXT Edge","text":"

    Here is an example from the JUXT Edge project template. It adds two sequences, one for when only the Clojure REPL should be launched and one for when the customized Edge cljs repl should also be connected. The Edge backend + frontend sequence specifies that the web app should be opened by Calva, making cljs repl connection more stable, and also adds menuSelections to skip the launch aliases prompt.

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Edge backend only\",\n            \"projectType\": \"deps.edn\"\n        },\n        {\n            \"name\": \"Edge backend + frontend\",\n            \"projectType\": \"deps.edn\",\n            \"cljsType\": {\n                \"dependsOn\": \"Figwheel Main\",\n                \"startCode\": \"(do (require 'dev-extras) (dev-extras/go) (println \\\"Edge Figwheel Main started\\\") ((resolve 'dev-extras/cljs-repl)))\",\n                \"isReadyToStartRegExp\": \"Edge Figwheel Main started\",\n                \"openUrlRegExp\": \"Website listening on: (?<url>\\\\S+)\",\n                \"printThisLineRegExp\": \"\\\\[Edge\\\\]\",\n                \"shouldOpenUrl\": true,\n                \"connectCode\": \"(do (require 'dev-extras) ((resolve 'dev-extras/cljs-repl)))\",\n                \"isConnectedRegExp\": \"To quit, type: :cljs/quit\",\n                \"buildsRequired\": false\n            },\n            \"menuSelections\": {\n                \"cljAliases\": [\n                    \"dev\",\n                    \"build\",\n                    \"dev/build\"\n                ],\n            }\n        }\n    ]\n}\n
    ","boost":6},{"location":"connect-sequences/#plain-depsedn","title":"Plain deps.edn","text":"

    A deps.edn sequence that does not promote the ClojureScript repl at all (leaving it a Clojure REPL), and leaves that up to you to do interactively. (Could be useful while you are developing a custom cljs repl.) The example is for when adapting a Figwheel Main repl.

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Do not promote to cljs\",\n            \"projectType\": \"deps.edn\",\n            \"cljsType\": {\n                \"dependsOn\": \"Figwheel Main\",\n                \"connectCode\": \"\\\"Don't promote me bro!\\\"\",\n                \"isConnectedRegExp\": \"Don't promote me bro!\"\n            }\n        }\n    ]\n}\n
    ","boost":6},{"location":"connect/","title":"Connect Calva to Your Project","text":"

    When connected to your project's REPL Calva lets you evaluate code, supporting Interactive Programming. The REPL connection is also used to provide IDE functionality through the dynamic knowledge about the project that the REPL enables. The REPL communication depends on that your project has an nREPL server running, and that the cider-nrepl middleware is enabled.

    For the easiest way to provide your project with these dependencies, the recommended way to connect is to use the so called Jack-in command.

    ","boost":7},{"location":"connect/#jack-in-let-calva-start-the-repl-for-you","title":"Jack-in: Let Calva Start the REPL For You","text":"

    This way Calva can make sure it is started with the dependencies needed for a working Clojure and/or ClojureScript session. This is often referred to as Jack in (because that is what it is called in CIDER).

    Jack-in supports both CLJ and for CLJS, and has built-in configurations for Leiningen, deps.edn, shadow-cljs, Gradle projects, as well as for the CLJS repl types: Figwheel Main, lein-figwheel (legacy Figwheel), shadow-cljs, and ClojureScript built-ins for both browser and node.js. Using jack-in provides your development environment with all the dependencies you need for Calva to work.

    It works like so:

    1. Open your project in VS Code.
    2. Issue the command Start a Project REPL and Connect: ctrl+alt+c ctrl+alt+j.
    3. Answer the quick-pick prompts telling Calva about project types and what profiles to start. (See the Jack-in Project Types and Profiles wiki page for more info if needed.)

    See also: Workspace Layouts

    About project roots

    You must have a project file, such as project.clj for Leiningen, or deps.edn for deps.edn, or shadow-cljs.edn for shadow-cljs, or settings.gradle/settings.gradle.kts for Gradle in the directory opened in VS Code in order for jack-in to work. If, after adding the project file, you experience an error during jack-in that says something could not be located, make sure you have the correct dependencies in your project file. For example, when using the Figwheel Main project type, you should have com.bhauman/figwheel-main in your project dependencies.

    See also below, regarding multiple projects in a workspace

    ","boost":7},{"location":"connect/#aliases-profiles-builds","title":"Aliases, Profiles, Builds","text":"

    When Jack-in starts it will depend on the project type, and whether ClojureScript is involved or not, and if it is, what kind of ClojureScript project, what will happen next. Calva will analyze the project files and will then give you prompts with selections based on what is found there.

    You will need some basic knowledge about the project and the project type terminologies to answer the prompts.

    There are ways to tell Calva the answers to these prompts beforehand, so that Jack-in can be a zero-prompting command. Read on.

    ","boost":7},{"location":"connect/#customizing-jack-in","title":"Customizing Jack-in","text":"

    The main mechanism for customizing your Jack-in, including automating menu selections, and custom CLJS REPL types is Custom Connect Sequences. See also Customizing Jack-in and Connect

    ","boost":7},{"location":"connect/#connecting-without-jack-in","title":"Connecting Without Jack-in","text":"

    If, for whatever reasons, you can't use Jack-in with your project (possibly because the REPL is started as part of some other job) all is not lost. Old fashioned Connect to a running REPL is still there for you. For all features to work in Calva while connecting to a running REPL, your environment needs to have REPL related dependencies set up.

    However, just as before it can be tricky to get the dependencies right. Consider using Jack in to inform yourself on how to start your REPL to Calva's satisfaction. When you use Jack in, Calva starts a VS Code task for it and the command line used is displayed in the terminal pane used to handle the task. Reading that command line tells you what dependencies are needed for your project.

    Even better: Copying that command line gives you the command to start the REPL with the correct dependencies.

    All this said, I still recommend you challenge the conclusion that you can't use Jack-in.

    Copy the Jack-in command line

    There is a Calva command for copying the Jack-in command line to the clipboard. It will copy the command line including commands to change to the current REPL project root, avoiding hard-to-detect errors when starting the REPL in the wrong directory.

    The Generic Project Type

    A reason to use the connect to a running REPL way, can be that Calva does not have a built in connect sequence/project type for the particular REPL you want to connect to. Maybe it is something like Lingy which doesn't yet have a built in Calva connect sequence. As long as there is an nREPL server to connect to, you can Connect with Calva, using the Generic connect sequence/project type. (You can also create a connect sequence with a custom command line, and use Jack-in anyway.)

    See also Customizing Jack-in and Connect

    ","boost":7},{"location":"connect/#starting-the-repl-from-application-code","title":"Starting the REPL from application code?","text":"

    If your project is setup so that the REPL server is started by the application code, you will need to get the cider-nrepl middleware in place. See the cider-nrepl docs about embedding nREPL in your application.

    ","boost":7},{"location":"connect/#auto-select-project-type-and-project-root","title":"Auto-select Project Type and Project Root","text":"

    You can make both Jack-in and Connect stop prompting you for project type and project root path in projects where you always want to use the same. See Connect Sequences.

    ","boost":7},{"location":"connect/#monorepos-multiple-clojure-projects-in-one-workspace","title":"Monorepos / multiple Clojure projects in one workspace","text":"

    If the workspace is a monorepo, Polylith repo or just a repository with more than one Clojure project, Calva will start the connect sequence with prompting for which project to start/connect to.

    ","boost":7},{"location":"connect/#shadow-cljs","title":"shadow-cljs","text":"

    Please see the shadow-cljs page.

    ","boost":7},{"location":"connect/#troubleshooting","title":"Troubleshooting","text":"","boost":7},{"location":"connect/#jack-in-and-main-opts","title":"Jack-in and :main-opts","text":"

    When Calva starts the project REPL and connects to it (a.k.a. Jack-in), this is done by starting an nREPL server. For deps.edn projects this by default means that Calva will add -m ... with options that starts the server.

    However: If you choose an alias at Jack-in that specifies :main-opts, it will make the Clojure CLI to add main opts and Calva will then not override these by adding -m ... to the command line. This means that an alias that specify :main-opts must result in an nREPL server being started, or else Calva won't have a server to connect to. Calva won't further analyze this, but will just warn you at Jack-in.

    If you don't know if an alias starts an nREPL server or not, by all means, try it, if you have reasons for using that alias. You will notice if Jack-in works or not. If it doesn't work, you will need to run without that alias, or fix what happens when that alias is used so that an nREPL server is started. See https://nrepl.org/nrepl/usage/server.html about ways to do this.

    ","boost":7},{"location":"connect/#command-not-found-errors-when-jacking-in","title":"Command Not Found Errors When Jacking In","text":"

    If you get command not found error when Calva tries to start your project, and you know you have the command installed, it's probably because VS Code starts from an environment where the command is not on the $PATH. It can look like so:

    lein update-in :dependencies conj '[nrepl,\"0.8.3\"]' -- update-in :plugins conj '[cider/cider-nrepl,\"0.25.8\"]' -- update-in '[:repl-options,:nrepl-middleware]' conj '[\"cider.nrepl/cider-middleware\"]' -- repl :headless\n/bin/sh: lein: command not found\nJack-in process exited. Status: 127\n

    The fix is to always start VS Code from the command line:

    $ code\n

    You might need to first run the Shell Command: Install code command in PATH.

    This will also make sure your REPL has access to the environment you probably expect it to have access to. See below.

    ","boost":7},{"location":"connect/#go-to-definition-not-working-for-java-definitions","title":"Go to Definition Not Working for Java Definitions","text":"

    On some systems, the Java source may not be installed along with the JDK. The source must be present on your system in order to navigate to Java definitions. See this comment for more details.

    ","boost":7},{"location":"connect/#environment-variables-are-not-readable-from-repl","title":"Environment Variables Are Not Readable From REPL","text":"

    If you've added environment variables in your OS, such as in your ~/.bashrc file (Linux), in order for them to be read in a REPL created by Calva's jackin command, VS Code must be started from a shell where the environment variables are defined. For example, if you can open a bash terminal and run echo $SOME_VAR and see the value there, then open VS Code from that terminal with code <project path>.

    ","boost":7},{"location":"connect/#viewing-the-communication-between-nrepl-and-calva","title":"Viewing the Communication Between nREPL and Calva","text":"

    It may be helpful to view the messages sent between nREPL and Calva when troubleshooting an issue related to the REPL. See how to do that here.

    ","boost":7},{"location":"contribute/","title":"Contribute to Calva","text":"

    There are many ways to contribute:

    • Become a sponsor
    • Give us feedback:
    • File issues
    • Talk to us via the #calva channel at the Clojurians Slack (use the latter link to grab an invite)
    • Provide PRs, see the Calva wiki about How to Hack on Calva
    • Give us feedback, preferably via that #calva channel
    • Cheer us on. (Same channel)
    • Help us test things like reported issues, new features, etcetera. See Testing VSIX Packages and Smoke Testing
    • Make tutorials, write blog articles, spread the word
    • Star the Calva repository
    • Help us help beginners with Calva and Clojure, on Slack as well as IRL and wherever.

    Be creative!

    "},{"location":"contribute/#please-star-the-calva-repo","title":"Please star the Calva repo!","text":"

    Happy Coding! \u2764\ufe0f

    "},{"location":"custom-commands/","title":"Custom REPL Commands","text":"

    Calva supports configuration of custom command snippets that you can evaluate in the REPL at will. This is useful if your workflow has you repeatedly evaluating a particular piece of code. There are two ways to use these:

    1. You can use the setting calva.customREPLCommandSnippets to configure it. Then either bind keyboard shortcuts to them or use the command Run Custom REPL Command to access it. The command will give you a menu with the snippets you have configured.
    2. You can bind a keyboard shortcut directly to a custom command snippet by inlining it in the shortcut definition. See Binding Keyboard Shortcuts

    Joyride

    For some use cases you might be better served by/want to combine these with using the VS Code Extension API, and that of Calva, or any other extension, through Joyride.

    The calva.customREPLCommandSnippets is an array of objects with the following fields (required fields in bold):

    • name: The name of the snippet as it will appear in the picker menu
    • snippet: The code that will be evaluated
    • key: A key can be used to reference the snippet from Run Custom REPL Command keyboard shortcut arguments. It will also be used in the quick-pick menu.
    • ns: A namespace to evaluate the command in. If omitted the command will be executed in the namespace of the current editor.
    • repl: Which repl session to use for the evaluation. Either \"clj\" or \"cljs\". Omit if you want to use the session of the current editor.
    • evaluationSendCodeToOutputWindow: (default true) Whether the evaluated code should be echoed to the Output/REPL window.

    There are also substitutions available, which will take elements from the current state of Calva and splice them in to the text of your command before executing it. They are

    • $line: Current line number in editor
    • $column: Current column number in editor
    • $file: Full name of the current file edited
    • $file-text: The text of the current file edited
    • $ns: The namespace used for evaluating the command
    • $editor-ns: The namespace of the editor from which the command was run
    • $selection: The currently selected text
    • $current-form: The text of the current form
    • $current-pair: The text of the current pair if in a binding, otherwise empty string
    • $enclosing-form: The text of the current enclosing form
    • $top-level-form The text of the current top level form
    • $current-fn: The sexpr/form at call position in the current list, e.g. str with (defn foo [] (str \"foo\" \"bar|\"))
    • $top-level-defined-symbol: The second symbol of the top level form, e.g. foo with (defn foo [] (str \"foo\" \"bar|\"))
    • $head: The text between the start of the current list to the cursor
    • $tail: The text between the cursor and the end of the current list
    ","boost":4},{"location":"custom-commands/#user-and-workspace-settings","title":"User and Workspace Settings","text":"

    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.)

    ","boost":4},{"location":"custom-commands/#binding-keyboard-shortcuts","title":"Binding Keyboard Shortcuts","text":"

    There are four ways to bind shortcuts to custom commands:

    1. Use a predefined key shortcut. These are predefined as ctrl+alt+space <something>, where <something> is one of:
      • The digits 0 through 9
      • The English letters a through z
      • Arrow keys right, left, up, or down
      • One of tab, backspace, ,, ., or -
    2. Bind calva.runCustomREPLCommand to a shortcut with whatever code you want to evaluate in the args slot. You have access to the substitution variables here as well.
    3. Bind calva.runCustomREPLCommand to a keyboard shortcut referencing the key of one of your calva.customREPLCommandSnippets. (If not using any of the keys mentioned in 1.)
    4. Bind calva.runCustomREPLCommand to a shortcut with a customREPLCommandSnippets in the args slot. You have access to the substitution variables here as well.

    Here's an example shortcut entry for the 4th option:

        {\n        \"key\": \"ctrl+cmd+u alt+enter\",\n        \"command\": \"calva.runCustomREPLCommand\",\n        \"args\": {\n            \"ns\": \"user\",\n            \"snippet\": \"$current-form\",\n        }\n    },\n

    This would evaluate the current form in the user namespace. Please note that this Custom REPL Command will not show up in the custom commands menu mentioned above.

    ","boost":4},{"location":"custom-commands/#custom-repl-hover-snippets","title":"Custom REPL Hover Snippets","text":"

    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.

    ","boost":4},{"location":"custom-commands/#configedn","title":"config.edn","text":"

    :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:

    1. None of these two configs get synced through VS Code Settings Sync.
    2. Changes to workspace .calva/config.edn will be automatically noticed by Calva, and refresh the config. This will not happen with the user config file.
    3. Internally in Calva, the settings are keyed on the snippet :name entry, and if you change the name, the old entry won't be removed until the VS Code window is reloaded.

    As for 2.: There is a command Calva: Refresh REPL snippets from User config.edn.

    There is also a command to open the User config.edn, for convenience: Calva: Open REPL snippets User config.edn. This command creates the file if it doesn't previously exist.

    ","boost":4},{"location":"custom-commands/#snippets-inside-deps","title":"Snippets Inside Deps","text":"

    A new experimental feature lets library authors ship snippets inside their jar files. These accept the same options as above but should be placed in \"resources/calva.exports/config.edn\" inside the jar.

    {:customREPLCommandSnippets\n [{:name \"edn test\"\n   :key \"a\"\n   :snippet ($current-form)}]\n :customREPLHoverSnippets\n [{:name \"edn hover\"\n   :snippet (str \"$hover-tex\")}\n  {:name \"edn hover show val\"\n   :snippet (str \"### EDN show val\\n```clojure\\n\" (pr-str (eval (symbol (str \"$ns\" \"/\" \"$hover-top-level-defined-symbol\")))) \"\\n```\")}]}\n
    ","boost":4},{"location":"customizing-jack-in-and-connect/","title":"Customize Jack-in and Connect","text":"

    Since Jack-in and connect both are about connecting the REPL, and only differ in how the REPL is started, many settings and configuration points are shared between the two concepts. A major customization point is Custom Connect Sequences, which are relevant for both Jack-in and Standalone Connect scenarios.

    This page lists some more Jack-in and Connect configuration options.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#auto-evaluate-code-on-connect","title":"Auto-evaluate Code on Connect","text":"

    You can have Calva evaluate code whenever a REPL has been connected via the calva.autoEvaluateCode.onConnect setting. It has two entries clj and cljs:

    • clj: \"Code to evaluate when the Clojure REPL has been connected.
      • The default is code that refer in the repl-requires/REPL utilities (like source, doc, etcetera). (Note that there is also a command to do this on demand.).
      • Overriding the default replaces it. If you want to add code to be evaluated on connect this way, and keep the behaviour of auto-refering REPL utilities, you need to provide code for the latter (copy/pasting the default code will do). See also note below about concatenation of configurations.
      • The code will be evaluated before the afterCLJReplJackInCode in any connect sequence used.
    • cljs: Code to evaluate when the ClojureScript REPL has been connected.
      • The default is code that refer in the repl-requires/REPL utilities (like source, doc, etcetera). (Note that there is also a command to do this on demand.).
      • Same deal with overriding the default as with clj.

    Set either of these to null to disable the feature for that REPL type. (The Settings linter will complain, but it works.)

    For Clojure this is in addition to afterCLJReplJackInCode

    There are two mechanisms for evaluating code when a Clojure REPL is connected. The afterCLJReplJackInCode setting of custom connect sequences, and this calva.autoEvaluateCode.onConnect.clj setting. There is no fundamental difference between them. This one has a default function of auto-refering in the Clojure REPL utilities. And it will be run before the connect sequence after-Jack-in code.

    All configured code is concatenated

    If you configure this both in User/global settings and in a Workspace, the workspace configured code will be concatenated on the user level code. Meaning both code snippets will be evaluated, first the User level code, then the Workspace level code. Also null disables the feature:

    • If you use null in the User level code, you will disable the onConnect code evaluation for all workspaces that do not configure code for this.
    • If you configure code on the User level it will be evaluated in all workspaces, except those that disable the feature by configuring null.
    ","boost":7},{"location":"customizing-jack-in-and-connect/#auto-evaluate-code-at-filenamespace-loadevaluation","title":"Auto-evaluate Code at file/namespace load/evaluation","text":"

    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.

    • Note that custom commands substitutions are in play here as well.
    • Calva's does not provide defaults for this setting.
    • Merging works the same as with onConnect.
    ","boost":7},{"location":"customizing-jack-in-and-connect/#customizing-connect","title":"Customizing Connect","text":"

    If there is an nRepl port file, Calva will use it and not prompt for host:port when connecting. You can make Calva prompt for this by setting the boolean config calva.autoSelectNReplPortFromPortFile to false.

    With the setting calva.autoConnectRepl you can make Calva automatically connect the REPL if there is an nRepl port file present when the project is opened.

    With this and the below mentioned auto-select options you can make connect a prompt-less experience. See: Connect Sequences.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#options-for-the-connect-command","title":"Options for the Connect Command","text":"

    The calva.connect command takes an optional options argument defined like so:

      options?: {\n    host?: string;\n    port?: string;\n    connectSequence?: string | ReplConnectSequence;\n    disableAutoSelect?: boolean;\n  }\n

    Where ReplConnectSequence is a Connect Sequences. If you provide a string it needs to match against a built-in or custom connect sequence. With disableAutoSelect you can force the connect menus to be provided even if a custom connect sequence is set to be autoSelected.

    You can provide these options from keyboard shortcuts or from Joyride scripts.

    Here's a keyboard shortcut for connecting to a running REPL bypassing any connect sequence with autoSelectForConnect.

        {\n        \"command\": \"calva.connect\",\n        \"args\": {\"disableAutoSelect\": true},\n        \"key\": \"ctrl+alt+c shift+c\",\n    },\n

    A Joyride command for connecting to a REPL on port 55555, without being asked for project type:

    (vscode/commands.executeCommand \"calva.connect\" (clj->js {:port \"55555\" :connectSequence \"Generic\"}))\n
    ","boost":7},{"location":"customizing-jack-in-and-connect/#customizing-jack-in","title":"Customizing Jack-in","text":"

    The main mechanism for customizing your Jack-in, including automating menu selections, and custom CLJS REPL types is Custom Connect Sequences.

    There are also these settings:

    • calva.jackInEnv: An object with environment variables that will be added to the environment of the Jack-in process.
    • calva.myCljAliases: An array of deps.edn aliases not found in the project file. Use this to tell Calva Jack-in to launch your REPL using your user defined aliases.
    • calva.myLeinProfiles: An array of Leiningen profiles not found in project.clj. Use this to tell Calva Jack-in to launch your REPL using your user defined profiles.
    • calva.openBrowserWhenFigwheelStarted: For Legacy Figwheel only. A boolean controlling if Calva should automatically launch your ClojureScript app, once it is compiled by Figwheel. Defaults to true.
    • calva.depsEdnJackInExecutable: A string which should either be clojure or deps.clj, or clojure or deps.clj (default). It determines which executable Calva Jack-in should use for starting a deps.edn project. With this setting at its default, clojure or deps.clj, Calva will test if the clojure executable works, and use it if it does, otherwise deps.clj will be used, which is bundled with Calva.
    • calva.jackInDependencyVersions: See below

    Note

    When processing the calva.jackInEnv setting you can refer to existing ENV variables with ${env:VARIABLE}.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#jack-in-dependency-versions","title":"Jack-in Dependency Versions","text":"

    Calva Jack-in injects the following dependencies in order for the REPL session to support IDE features

    • nrepl: nREPL is the wonderful piece of software that gives Calva a structured and extensible connection to the REPL in your Clojure and ClojureScript projects.
    • cider-nrepl: cider-nrepl is middleware that extends the nREPL connection with all sorts of nice stuff that Calva uses to give you a delightful IDE experience.
    • cider/piggieback: Piggieback is used to create nREPL sessions in ClojureScript projects. (Not with shadow-cljs projects though, which provides its own middleware for this.)

    The versions used are configurable via the VS Code settings calva.jackInDependencyVersions.

    Java 1.8 compatible versions

    The default dependency versions are not compatible with Java 1.8. If your project needs that version of Java you can use these settings in your Workspace .vscode/settings.json:

    \"calva.jackInDependencyVersions\": {\n  \"nrepl\": \"1.0.0\",\n  \"cider-nrepl\": \"0.28.5\",\n  \"cider/piggieback\": \"0.5.3\"\n}\n
    ","boost":7},{"location":"customizing-jack-in-and-connect/#options-for-the-jack-in-command","title":"Options for the Jack-in Command","text":"

    The calva.jackIn command takes an optional options argument defined like so:

      options?: {\n    connectSequence?: string | ReplConnectSequence;\n    disableAutoSelect?: boolean;\n  }\n

    Where ReplConnectSequence is a Connect Sequences. If you provide a string it needs to match against a built-in or custom connect sequence. With disableAutoSelect you can force the jack-in menus to be provided even if a custom connect sequence is set to be autoSelected.

    You can provide these options from keyboard shortcuts or from Joyride scripts.

    Here's a keyboard shortcut for connecting to a running REPL bypassing any connect sequence with autoSelectForConnect.

        {\n        \"command\": \"calva.jackIn\",\n        \"args\": {\"disableAutoSelect\": true},\n        \"key\": \"ctrl+alt+c shift+j\",\n    },\n

    A Joyride command for starting a deps.edn REPL for a project in the root of the workspace.

    (vscode/commands.executeCommand\n \"calva.jackIn\"\n (clj->js {:connectSequence {:projectType \"deps.edn\"\n                             :projectRootPath [\".\"]}}))\n

    It will prompt for any aliases it finds in the deps.edn file.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#starting-the-repl-from-application-code","title":"Starting the REPL from application code?","text":"

    If your project is setup so that the REPL server is started by the application code, you will need to get the cider-nrepl middleware in place. See the cider-nrepl docs about embedding nREPL in your application.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#auto-select-project-type-and-project-root","title":"Auto-select Project Type and Project Root","text":"

    You can make both Jack-in and Connect stop prompting you for project type and project root path in projects where you always want to use the same. See Connect Sequences.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#project-roots-search-globing","title":"Project roots search globing","text":"

    When searching for project roots in your workspace, Calva will glob for all files matching project.clj, deps.edn, or shadow-cljs.edn. This is done using VS Code's workspace search engine, and is very efficient. However, in a large monorepo, it is still a substantial task. In order to not waste resources Calva will exclude any directories in the setting calva.projectRootsSearchExclude.

    Exclude entry globs

    Each entry is a partial glob and will be part of a resulting glob of the form **/{glob1,glob2,...,globN}. This means that all directories in the workspace matching an entry will be excluded, regardless of where in the workspace they reside.

    ","boost":7},{"location":"customizing-jack-in-and-connect/#viewing-the-communication-between-nrepl-and-calva","title":"Viewing the Communication Between nREPL and Calva","text":"

    It may be helpful to view the messages sent between nREPL and Calva when troubleshooting an issue related to the REPL. See how to do that here.

    ","boost":7},{"location":"customizing/","title":"Customizing Calva","text":"

    Don't like the defaults? On this page we can collect some of the customizations that people have done, and maybe write a thing or two about it some day.

    Tip for VS Code newcomers: The search box in Settings is your friend. Also, some Calva settings are more complex than the Settings UI can handle. VS Code will then show you a link to settings.json. And VS Code's built-in json extension is awesome. To add settings for Calva's Pretty Printing, for example, search for \u201dprettyprint\u201d in VS Code Settings and follow the link to settings.json. Start typing \u201dcalvapretty\u201d until auto-complete suggests calva.prettyPrintingOptions. Press ENTER and VS Code will fill in these defaults:

        \"calva.prettyPrintingOptions\": {\n        \"enabled\": true,\n        \"printEngine\": \"pprint\",\n        \"width\": 40\n    },\n
    "},{"location":"customizing/#clojure-defaults","title":"Clojure Defaults","text":"

    Calva sets some VS Code settings for all Clojure files. Some of these are needed for Calva to function correctly, which should not be tampered with unless you really know what you are doing, and some of them are convenient defaults. If you add a setting to your settings.json and accept the snippet help you get when you type \"[clojure]\", you will get the Calva defaults pasted:

          \"[clojure]\": {\n        \"editor.wordSeparators\": \"\\t ()\\\"':,;~@#$%^&{}[]`\",\n        \"editor.autoClosingBrackets\": \"always\",\n        \"editor.autoClosingOvertype\": \"always\",\n        \"editor.autoClosingQuotes\": \"always\",\n        \"editor.formatOnType\": true,\n        \"editor.autoIndent\": \"full\",\n        \"editor.formatOnPaste\": true,\n        \"editor.matchBrackets\": \"never\",\n        \"editor.guides.indentation\": false,\n        \"editor.parameterHints.enabled\": false,\n        \"editor.unicodeHighlight.allowedCharacters\": {\n          \"\u00a0\": true,\n          \"\ua789\": true\n        },\n        \"editor.foldingStrategy\": \"indentation\"\n      }\n

    editor.wordSeparators

    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.foldingStrategy

    To use the folding levels provided by clojure-lsp, set this to auto. Though at the time of this writing there is a bug in clojure-lsp making folding stop working with this setting.

    "},{"location":"customizing/#pretty-printing","title":"Pretty Printing","text":"

    Calva's pretty printing mode can be configured a bit. See Pretty Printing.

    "},{"location":"customizing/#calva-highlight","title":"Calva Highlight","text":"

    This is highly customizable. See Syntax highlighting

    "},{"location":"customizing/#color-customizations","title":"Color customizations","text":"

    Calva defines a set of themable colors which can be provided by the user using workbench.colorCustomizations.

        \"workbench.colorCustomizations\": {\n        \"calva.inlineErrorForegroundColor\": \"#ff0000\",\n        \"calva.inlineForegroundColor\": \"#ff9000\"\n    }\n

    "},{"location":"customizing/#automatic-parameter-hints-poppup","title":"Automatic Parameter Hints Poppup","text":"

    Calva has helpful parameter hints to aid when typing function calls. They look like so:

    To have the hints automatically pop up when you are typing, set editor.parameterHints.enabled to true in the above [clojure] scoped setting. (To call them up on demand the default VS Code keybindings are cmd+shift+space on Mac and ctrl+shift+space on Linux/Windows.)

    "},{"location":"customizing/#code-formatting","title":"Code Formatting","text":"

    See Formatting for information on how to configure this.

    "},{"location":"customizing/#jack-in-and-connect","title":"Jack-in and Connect","text":"

    Jack-in and Connect are very customizable through Custom Connect Sequences.

    See also Customizing Jack-in and Connect

    "},{"location":"customizing/#key-bindings","title":"Key bindings","text":"

    Most of Calva's commands have default keybindings. They are only defaults, though, and you can change keybindings as you wish. To facilitate precision in binding keys Calva keeps some when clause contexts updated.

    "},{"location":"customizing/#when-clause-contexts","title":"When Clause Contexts","text":"

    The following contexts are available with Calva:

    • calva:keybindingsEnabled: a master switch that you find in the settings
    • paredit:keyMap: strict, original, or none from the corresponding Calva setting (see Paredit)
    • calva:connected: true when Calva is connected to a REPL (there is also calva:connecting || calva:launching)
    • calva:outputWindowActive: true when the Output/REPL window has input focus
    • calva:replHistoryCommandsActive: true when the cursor is in the Output/REPL window at the top level after the last prompt
    • calva:replWindowSubmitOnEnter: true when the cursor is adjacent after the last top level form in the Output/REPL window
    • calva:cursorInString: true when the cursor/caret is in a string or a regexp
    • calva:cursorInComment: true when the cursor is in, or adjacent to a line comment
    • calva:cursorBeforeComment: true when the cursor is adjacent before a line comment
    • calva:cursorAfterComment: true when the cursor is adjacent after a line comment
    • calva:cursorAtStartOfLine: true when the cursor is at the start of a line including any leading whitespace
    • calva:cursorAtEndOfLine: true when the cursor is at the end of a line including any trailing whitespace
    "},{"location":"customizing/#some-custom-bindings","title":"Some Custom Bindings","text":"

    Here is a collection of custom keybindings from here and there.

    • Replace all Calva ctrl+alt+... key bindings with ctrl+shift+..., for keyboards lacking alt key: this gist
    • Replace the default Calva \u201dprefix\u201d, ctrl+alt+c to just alt+v: WebWItch's keybindings.json (Please note, that alt+v does not work for some locales, but for when it works it is much less clunky than the default prefix).
    • Here the Calva key is switched for ctrl+,: manas_marthi's keybindings
    • Keybindings for Emacs users
    • Use modifiers and WASD keys for movement and manipulation: isaksky's keybindings

    Are you a vim extension user? See: Using with VIM extension.

    "},{"location":"customizing/#move-by-word","title":"Move by word","text":"

    By default Calva changes the move-by-word key bindings to move by sexpr/form when the cursor is in structural Clojure code. Within line comments the editor default word movement is active.

    If you want the VS Code default word movement shortcuts, use these settings:

        {\n        \"key\": \"ctrl+right\",\n        \"win\": \"ctrl+right\",\n        \"mac\": \"alt+right\",\n        \"command\": \"cursorWordRight\"\n    },\n    {\n        \"key\": \"ctrl+left\",\n        \"win\": \"ctrl+left\",\n        \"mac\": \"alt+left\",\n        \"command\": \"cursorWordLeft\"\n    },\n    {\n        \"key\": \"ctrl+right\",\n        \"mac\": \"ctrl+right\",\n        \"win\": \"alt+right\",\n        \"command\": \"paredit.forwardSexp\",\n        \"when\": \"calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+left\",\n        \"mac\": \"ctrl+left\",\n        \"win\": \"alt+left\",\n        \"command\": \"paredit.backwardSexp\",\n        \"when\": \"calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/\"\n    }\n

    Use it as an inspiration for customizing things to your own liking. \ud83d\ude04

    "},{"location":"customizing/#wrap-using-like-cursive","title":"Wrap using (, [, { (like Cursive)","text":"

    Something I use in IntelliJ/Cursive is the ability to select an expression and hit one of (, [, { to wrap it. And after wrapping the expression I don't want the selection anymore, so if I were wrapping (foo) then I would want to get ( | (foo)) where | would be my cursor.

    Here's how you can make this work with Calva Paredit: Update all of the Paredit: Wrap Around ... commands so that their respective shortcuts are the wrappers themselves and update the when clause to include editorHasSelection (otherwise when you open a paren the next expression would get slurped in).

    The change would look like this in your keybindings.json:

        {\n        \"key\": \"shift+9\",\n        \"command\": \"paredit.wrapAroundParens\",\n        \"when\": \"editorTextFocus && editorHasSelection && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"[\",\n        \"command\": \"paredit.wrapAroundSquare\",\n        \"when\": \"editorHasSelection && editorTextFocus && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"shift+[\",\n        \"command\": \"paredit.wrapAroundCurly\",\n        \"when\": \"editorHasSelection && editorTextFocus && !editorReadOnly && editorLangId =~ /clojure|scheme|lisp/ && paredit:keyMap =~ /original|strict/\"\n    }\n
    "},{"location":"debugger/","title":"Debugger","text":"

    Calva comes with a powerful expression-based debugger, inspired by Cider's debugger, and using the same underlying library, cider-nrepl. We hope you love it!

    Note

    The debugger currently does not support ClojureScript. Calva's debugger utilizes cider-nrepl for debugging. See this Cider issue for more information.

    "},{"location":"debugger/#features","title":"Features","text":""},{"location":"debugger/#current","title":"Current","text":"
    • Instrument functions for debugging with ctrl+alt+c i
    • Instrument a function manually with #dbg (as opposed to the above command)
    • Set individual breakpoints with #break
    • Continue to next breakpoint
    • Step over form
    • Step into form
    • Step out of form
    • Evaluate code in the debug context
    • See variable values in the debugger side pane
    • See variable values on hover in the editor
    "},{"location":"debugger/#future-goals","title":"Future goals","text":"
    • See structured variables in the debugger side pane (currently maps and collections are just shown as strings)
    • Inject values into the debug context
    • Trace: continue, printing expressions and their values
    "},{"location":"debugger/#dependencies","title":"Dependencies","text":"

    The debugger itself relies pretty heavily on cider-nrepl, as do other parts of Calva. This library is loaded as a dependency when you use Calva Jack-in. If you are not using Calva Jack-in, you can add these dependencies in your project definition or user profile. See the Calva Jack-in guide for more information.

    "},{"location":"debugger/#using-the-debugger","title":"Using the Debugger","text":"

    If you're new to Clojure or expression-based debuggers, this debugger may function differently than what you're used to. Instead of placing breakpoints in the side margin and then hitting F5 to start debugging, you instead use Clojure reader tags, #break and #dbg, to denote breakpoints anywhere in a Clojure form. When you evaluate a call to a function that has been evaluated with that reader tag, the debugger will start when execution reaches the first breakpoint. There's also a convenience command to instrument functions. Read below about both options.

    Note

    The debugger is not configured via a launch.json file, and is not started in the same way as you may be used to when working with other languages in VS Code. The debugger is used by way of the REPL. If you are new to Clojure, please visit the Getting Started section of the documentation and get familiar with evaluating code using the REPL before using the debugger.

    "},{"location":"debugger/#instrumenting-a-function","title":"Instrumenting a Function","text":"

    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.

    "},{"location":"debugger/#setting-breakpoints-with-break","title":"Setting Breakpoints with #break","text":"

    You can insert a breakpoint manually into any code by placing a #break in front of the form where you want execution to pause, and then evaluating the top level form with alt+enter. When you evaluate a call to this code the VS Code debugger will start, the cursor will move to right after the form that's preceded by #break, and the line will be highlighted to show execution is paused there.

    Note

    Code will be executed up to and including the form after the breakpoint.

    "},{"location":"debugger/#conditional-breakpoints","title":"Conditional Breakpoints","text":"

    You can set conditional breakpoints by adding metadata before the form that the #break applies to.

    (defn print-nums [n]\n  (dotimes [i n]\n    #break ^{:break/when (= i 7)} ;; This breakpoint will only be hit when i equals 7\n    (prn i)))\n
    "},{"location":"debugger/#instrumenting-a-form-with-dbg","title":"Instrumenting a Form with #dbg","text":"

    Adding #dbg before a form then evaluating the form with alt+enter will instrument the form. This has the same effect as using the instrument command.

    "},{"location":"debugger/#evaluating-code-in-the-paused-context","title":"Evaluating Code in the Paused Context","text":"

    When execution is paused at a breakpoint, you can evaluate code in that context. This can be done in the editor or in the REPL window, as usual.

    "},{"location":"debugger/#viewing-variable-values","title":"Viewing Variable Values","text":"

    While debugging, you can view the values of variables in VS Code's debugger side pane. You can also view values by hovering over the variables in the editor.

    Metadata not available

    The variable viewer does not have access to any metadata attached to the variable values.

    "},{"location":"debugger/#viewing-the-call-stack","title":"Viewing the Call Stack","text":"

    While debugging, you can view the call stack in VS Code's call stack side pane. Clicking the stack frames will show the related line of code in an editor.

    Note

    You may only see one stack frame in the call stack side pane, as the change for adding additional frames was rolled back due to an issue. You can follow the change for this at #1150.

    "},{"location":"debugger/#stepping-commands","title":"Stepping Commands","text":"

    You can use VS Code's debugger UI to advance execution while debugging.

    Note

    Clicking restart does nothing, since this functionality does not make sense for our debugger.

    • Continue - Continues without stopping for the current breakpoint
    • Step over - Continues to the next breakpoint
    • Step in - Steps in to the function about to be called. If the next breakpoint is not around a function call, does the same as next. Note that not all functions can be stepped in to - only normal functions stored in vars, for which cider-nrepl can find the source. You cannot currently step in to multimethods, protocol functions, or functions in clojure.core (although multimethods and protocols can be instrumented manually).
    • Step out - Steps to the next breakpoint that is outside of the current sexp
    • Restart - Does nothing. To restart debugging, you can hit disconnect or continue execution through the final result, then re-evaluate the expression that started the debugger.
    • Disconnect - Disconnects the debugger
    "},{"location":"debugger/#caveats","title":"Caveats","text":""},{"location":"debugger/#breakpoints-in-looprecur","title":"Breakpoints in loop/recur","text":"

    One construct where the debugger is limited is loop/recur. As recur always has to appear in a tail-position inside a loop or a fn and the debugger uses macros to interleave breakpoints in the forms, it might happen that a recur no longer appears in a tail position. In that case we have to avoid setting up the breakpoint. An example of such a case is:

    (loop [i 0]\n  #break\n  (when (< i 10)\n    (println i)\n    (recur (inc i))))\n

    Here the breakpoint is exactly in front of a form that contains as its last expression a recur which is wrapped in a loop. This breakpoint has no effect. This does not mean you cannot use the debugger with loop, it just means you have to set your debug statements more carefully.

    "},{"location":"debugger/#loading-the-file-and-eval-on-save","title":"Loading the File and \"Eval On Save\"","text":"

    When you load a file, any breakpoints that were previously set in functions will be unset. If you have the \"Eval On Save\" setting enabled, your file is also loaded with each save, therefore saving the file will remove breakpoints previously set.

    "},{"location":"debugger/#clashes-with-emacscider-debugger","title":"Clashes with Emacs/CIDER debugger","text":"

    When both CIDER and Calva is connected to the same REPL, stepping the debugger in one editor may have it stop on the breakpoint in the other one. Reported here: https://github.com/BetterThanTomorrow/calva/issues/2496

    "},{"location":"debugger/#troubleshooting","title":"Troubleshooting","text":""},{"location":"debugger/#debugger-hangs-when-stepping-over-infinite-seqs","title":"Debugger hangs when stepping over infinite seqs","text":"

    This is because the debugger tries to evaluate the form when it's stepped over, and if clojure.core/*print-length* is set to nil as it is by default, evaluation will never complete. If you want to debug a form with an infinite seq, make sure to set *print-length* beforehand. For example:

    (set! *print-length* 3)\n;; Or, to be more precise\n(set! clojure.core/*print-length* 3)\n

    Calva does not set this for you during debug mode, instead leaving it up to you to decide the value.

    "},{"location":"debugger/#my-breakpoint-isnt-being-hit","title":"My breakpoint isn't being hit","text":"

    It's likely that your breakpoint is in a place that cider-nrepl does not see as an appropriate place to break execution. For example, if you put a breakpoint before a literal number, it will not be hit, because there's no need to show the value of a literal.

    (defn simple [x]\n  (+ 1 #break 1)) ;; This breakpoint will not be hit\n

    Another possible issue is that you're loading the file again after setting breakpoints, which unsets them. See Loading the File and \"Eval On Save\" under Caveats.

    "},{"location":"debugger/#my-breakpoint-in-a-test-isnt-being-hit","title":"My breakpoint in a test isn't being hit","text":"

    If you're using the test commands like \"Run current test\" to run your tests, breakpoints will not be hit. This is because Calva loads the file before running the tests to make sure the latest version of test code is being run, and when the file is loaded, breakpoints are unset.

    If you want a breakpoint to work within the test, evaluate the test form with a breakpoint tag in it, then call the test directly.

    "},{"location":"debugger/#no-reader-function-for-tag-error","title":"\"No reader function for tag\" error","text":"

    If you get an error like this, it's likely that you connected to a REPL instead of jacking in, and you don't have the proper dependencies loaded in your REPL. You can run the command \"Copy Jack-in Command Line to Clipboard\" to see what command would be run if you jacked in.

    Most importantly, make sure you have cider/cider-nrepl as a dependency, and cider.nrepl/cider-middleware as middleware loaded in your REPL. For example, this is a jack-in command line for a deps.edn project:

    clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,\"0.8.3\"},cider/cider-nrepl {:mvn/version,\"0.25.8\"}}}' -m nrepl.cmdline --middleware \"[cider.nrepl/cider-middleware]\"\n
    "},{"location":"debugger/#passing-options-to-the-repl-jvm","title":"Passing options to the REPL JVM","text":"

    There are times when Clojure debugging tools are not enough or not right for the job. This is usually true when use an (open source) Java library and you want to set some breakpoints in Java code. For those cases and others, you need to start the JVM in debug mode.

    Typical use cases:

    • Change Java logger configuration for the REPL via java system properties: e.g -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE
    • Enable JVM debugger, change VM memory size, etc.

    Calva supports passing environment variables via jackInEnv. You can set that option inside VSCode settings.json file.

    You can configure global settings.json file or a project wide version, inside <project-root>/.vscode/settings.json.

    Configuring the global option will impact all projects you work on using Calva, so be aware. See the documentation for settings.json for more information.

    The bellow snippet configures JAVA_TOOL_OPTIONS environment variable. We configure slf4j-simple logging level via a Java system property (-D) and JVM specific options (-X).

    NOTE: You can of course pass other env variables here.

    .vscode/settings.json

    {\n    \"calva.jackInEnv\": {\n        \"JAVA_TOOL_OPTIONS\": \"${env:JAVA_TOOL_OPTIONS} -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896\"\n    }\n}\n

    Once you saved the file, the next time you Jack in the project, this variable is read by the JVM and the configuration is applied accordingly.

    You should see something like the message below in the Calva terminal output window:

    clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,\"0.8.3\"},cider/cider-nrepl {:mvn/version,\"0.26.0\"}}}' -A:debug -m nrepl.cmdline --middleware \"[cider.nrepl/cider-middleware]\"\nPicked up JAVA_TOOL_OPTIONS:  -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896\nListening for transport dt_socket at address: 7896\nnREPL server started on port 46691 on host localhost - nrepl://localhost:46691\n
    "},{"location":"emacs-keybindings/","title":"Emacs Keybindings","text":"

    Some keybindings to make it easier for Emacs users

    [\n    {\n        \"key\": \"ctrl+cmd+b\",\n        \"command\": \"paredit.backwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+alt+left\",\n        \"command\": \"-paredit.backwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"shift+cmd+]\",\n        \"command\": \"-workbench.action.nextEditor\"\n    },\n    {\n        \"key\": \"ctrl+shift+]\",\n        \"command\": \"paredit.barfSexpBackward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+right\",\n        \"command\": \"-paredit.barfSexpBackward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+[\",\n        \"command\": \"paredit.barfSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+left\",\n        \"command\": \"-paredit.barfSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+cmd+f\",\n        \"command\": \"paredit.forwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+alt+right\",\n        \"command\": \"-paredit.forwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+cmd+f\",\n        \"command\": \"-workbench.action.toggleFullScreen\"\n    },\n    {\n        \"key\": \"ctrl+shift+backspace\",\n        \"command\": \"-paredit.killSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"shift+cmd+k\",\n        \"command\": \"-editor.action.deleteLines\",\n        \"when\": \"textInputFocus && !editorReadonly\"\n    },\n    {\n        \"key\": \"ctrl+shift+0\",\n        \"command\": \"paredit.slurpSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+right\",\n        \"command\": \"-paredit.slurpSexpForward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+9\",\n        \"command\": \"paredit.slurpSexpBackward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+left\",\n        \"command\": \"-paredit.slurpSexpBackward\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+c ctrl+c\",\n        \"command\": \"calva.evaluateCurrentTopLevelForm\",\n        \"when\": \"calva:activated\"\n    },\n    {\n        \"key\": \"ctrl+alt+c space\",\n        \"command\": \"-calva.evaluateCurrentTopLevelForm\",\n        \"when\": \"calva:activated\"\n    },\n    {\n        \"key\": \"ctrl+x ctrl+e\",\n        \"command\": \"calva.evalCurrentTopLevelFormInREPLWindow\",\n        \"when\": \"calva:activated\"\n    },\n    {\n        \"key\": \"ctrl+alt+c ctrl+alt+space\",\n        \"command\": \"-calva.evalCurrentTopLevelFormInREPLWindow\",\n        \"when\": \"calva:activated\"\n    },\n    {\n        \"key\": \"ctrl+x ctrl+s\",\n        \"command\": \"workbench.action.files.save\"\n    },\n    {\n        \"key\": \"cmd+s\",\n        \"command\": \"-workbench.action.files.save\"\n    },\n    {\n        \"key\": \"cmd+s\",\n        \"command\": \"paredit.spliceSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+alt+s\",\n        \"command\": \"-paredit.spliceSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+cmd+k\",\n        \"command\": \"paredit.cutForwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+x right\",\n        \"command\": \"-paredit.cutForwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+cmd+backspace\",\n        \"command\": \"paredit.cutBackwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+shift+x left\",\n        \"command\": \"-paredit.cutBackwardSexp\",\n        \"when\": \"calva:activated && calva:pareditValid && paredit:keyMap =~ /original|strict/\"\n    },\n    {\n        \"key\": \"ctrl+1\",\n        \"command\": \"-workbench.action.openEditorAtIndex1\"\n    },\n    {\n        \"key\": \"ctrl+1\",\n        \"command\": \"editor.action.quickFix\",\n        \"when\": \"editorHasCodeActionsProvider && editorTextFocus && !editorReadonly\"\n    },\n    {\n        \"key\": \"cmd+.\",\n        \"command\": \"-editor.action.quickFix\",\n        \"when\": \"editorHasCodeActionsProvider && editorTextFocus && !editorReadonly\"\n    },\n    {\n        \"key\": \"cmd+.\",\n        \"command\": \"editor.action.revealDefinition\",\n        \"when\": \"editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor\"\n    },\n    {\n        \"key\": \"f12\",\n        \"command\": \"-editor.action.revealDefinition\",\n        \"when\": \"editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor\"\n    }\n]\n

    "},{"location":"eval-tips/","title":"Code Evaluation","text":"

    Calva tries to make it easy to evaluate code, supporting interactive development. The fastest path to learning about it is to use the Fire up the Getting Started REPL command, which you can learn more about in the Getting Started section.

    NB: The below assumes you have read about Finding Calva Commands and Shortcuts.

    ","boost":7},{"location":"eval-tips/#interruptingstopping-running-evaluations","title":"Interrupting/stopping running evaluations","text":"

    Sometimes you evaluate things that take a very long time to complete, or might not even ever complete (infinite loops, lazy sequences, things like that). Calva has a command for interrupting running evaluations. You find it in the VS Code command palette, as well as in the REPL status bar item menu, when the REPL is connected.

    ","boost":7},{"location":"eval-tips/#evaluation-in-a-file-editor","title":"Evaluation in a File Editor","text":"

    Calva has many commands for evaluating forms, including the current form and the current top-level form.

    Some of the commands also let you choose what should happen with the results:

    1. Inline. This will display the results (or some of it, if it is long) inline in the editor.
    2. This also creates a hover pane including the full results and a button which will copy the results to the clipboard.
    3. There is also a command for copying the last result to the clipboard.
    4. The full results are always available in the output window.
      • There is a command for showing the output window, allowing for a workflow where you either generally have it closed, or have it as one of the tabs in the same editor group as the files you are working with.
    5. To comments. This will add the results as line comments below the current line.
    6. Replace the evaluated code. This will do what it says, the evaluated code will be replaced with its results.
    ","boost":7},{"location":"eval-tips/#wait-current-form-top-level-form","title":"Wait, Current Form? Top-level Form?","text":"

    These are important concepts in Calva in order for you to create your most effective workflow. This video explains it a bit:

    ","boost":7},{"location":"eval-tips/#current-form","title":"Current Form","text":"

    Default shortcut for evaluating the current form: ctrl+enter.

    The current form either means the current selection, or otherwise is based on the cursor position. Play some with the command Calva: Select current form, ctrl+alt+c s, to figure out what Calva thinks is the current form for some different situations. Try it inside a symbol, adjacent to a symbol (both sides) and adjacent to an opening or closing bracket (again, both sides). Generally the current form is determined like so:

    1. If text is selected, then that text
    2. If the cursor is \u201din\u201d a symbol, then that symbol
      foob|ar ; foobar\n
    3. If the cursor is adjacent to a form (a symbol or a list of some kind), then that form
      (foo bar |(baz)) ; (baz)\n
    4. If the cursor is between to forms, then the left side form
      (foo bar | (baz)) ; bar\n
    5. If the cursor is before the first form of a line, then that form
      (foo\n| bar (baz)) ; bar\n
    ","boost":7},{"location":"eval-tips/#current-top-level-form","title":"Current Top-level Form","text":"

    Default shortcut for evaluating the current top level form: alt+enter.

    The current top-level form means top-level in a structural sense. It is not the topmost form in the file. Typically in a Clojure file you will find def and defn (and defwhatever) forms at the top level, which also is one major intended use for evaluating top level form: to define and redefine variables. However, Calva does not check the contents of the form in order to determine it as a top-level forms: all forms not enclosed in any other form are top level forms.

    An \u201dexception\u201d is introduced by the comment form. It will create a new top level context, so that any forms immediately inside a (comment ...) form will be considered top-level by Calva. This is to support a workflow with what is often referred to the Rich Comments.

    At the top level the selection of which form is the current top level form follows the same rules as those for the current form.

    ","boost":7},{"location":"eval-tips/#evaluate-enclosing-form","title":"Evaluate Enclosing Form","text":"

    The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter.

    (let [foo :bar]\n  (when false (str| foo))) ; => \":bar\"\n
    ","boost":7},{"location":"eval-tips/#evaluate-to-cursor","title":"Evaluate to Cursor","text":"

    There are several commands for evaluating a piece of code, closing brackets. It's good, especially in threads, but can also come in handy in other situations, for instance when you want to evaluate something that depends on bindings, such as in a let form.

    ","boost":7},{"location":"eval-tips/#evaluate-from-start-of-list-to-cursor-closing-brackets","title":"Evaluate From Start of List to Cursor, Closing Brackets","text":"

    This command evaluates the text from the start of the current enclosing list to where the cursor is, and it adds the missing closing bracket for you. Convenient for checking intermediate results in thread or doto, or similar pipelines. The cursor is right behind :d in this form:

      (->> [1 1 2 3 5 8 13 21]\n       (partition 2)\n       (zipmap [:a :b :c :d])\n       :d| ; => (13 21)\n       (apply -)\n       (Math/abs))\n

    The default shortcut for this command is ctrl+alt+enter.

    ","boost":7},{"location":"eval-tips/#evaluate-selection-closing-brackets","title":"Evaluate Selection, Closing Brackets","text":"

    This is the most versatile of the \u201devaluation, closing brackets\u201d commands. It will do what it says. \ud83d\ude04 It's extra handy in combination with the command Paredit: Select Backward Up Sexp/Form (shift+ctrl+up). Consider this contrieved form (buggy code, because it was supposed to result in 42, not -42):

    (defn fortytwo-from-thirty\n  []\n  (let [thirty 30]\n    (-> thirty\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

    At ;1, you can do backward up sexp (shift+ctrl+up) twice to select up to the (let ..), then issue Evaluate Selection, Closing Brackets. It has the same default keybinding as the command for evaluating the current list up to the cursor: ctrl+alt+enter.

    At ;2 you need select backwards up three times.

    ;3 is included because it is close to the bug. (Which was introduced when the thread-last, ->> was added to make this example.) Please practice the Evaluate Selection, Closing Brackets command to fix the bug.

    ","boost":7},{"location":"eval-tips/#evaluate-from-start-of-top-level-form-to-cursor-closing-brackets","title":"Evaluate From Start of Top Level Form to Cursor, Closing Brackets","text":"

    This command has a default shortcut keybinding of shift+alt+enter. It will create a form from the start of the current top level form, up to the cursor, close all brackets, and this will then be evaluated. Good for examining code blocks up to a certain point. Often comes in handy in Rich comments ((comment ...)).

    Take this example and paste it in a file loaded into the REPL, then place the cursor in front of each line comment and try the command.

    (comment\n (do\n   (def colt-express\n     {:name \"Colt Express\"\n      :categories [\"Family\"\n                   \"Strategy\"]\n      :play-time 40\n      :ratings {:pez 5.0\n                :kat 5.0\n                :wiw 5.0   ; 1, then eval `colt-express`\n                :vig 3.0\n                :rex 5.0\n                :lun 4.0}})\n\n   (defn average [coll]\n     (/ (apply + coll) (count coll)))\n\n   (let [foo-express (-> colt-express\n                         (assoc :name \"Foo Express\")\n                         (assoc-in [:ratings :lyr] 5.0)\n                         (update-in [:ratings :vig] inc))]\n     (->> foo-express   ; 2\n          :ratings      ; 3\n          vals          ; 4\n          average       ; 5\n          ))))\n
    ","boost":7},{"location":"eval-tips/#evaluate-from-start-of-file-to-cursor-closing-brackets","title":"Evaluate From Start of File to Cursor, Closing Brackets","text":"

    Yup, that command also exists. \ud83d\ude04

    ","boost":7},{"location":"eval-tips/#copying-the-inline-results","title":"Copying the inline results","text":"

    There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c.

    This works regardless if you have evaluated in a file editor or in a REPL window.

    ","boost":7},{"location":"eval-tips/#evaluating-in-a-repl-window","title":"Evaluating in a REPL window","text":"

    Since the REPL Window is mostly just a regular file, things work pretty similar at the REPL prompt. You use alt+enter to evaluate. Selecting the current form (default key binding ctrl+w on Mac and shift+alt+right on Windows and Linux) after evaluating will select the result.

    ","boost":7},{"location":"evaluation/","title":"Code Evaluation","text":"

    Calva tries to make it easy to evaluate code, supporting interactive development. The fastest path to learning about it is to use the Fire up the Getting Started REPL command, which you can learn more about in the Getting Started section.

    NB: The below assumes you have read about Finding Calva Commands and Shortcuts.

    ","boost":7},{"location":"evaluation/#interruptingstopping-running-evaluations","title":"Interrupting/stopping running evaluations","text":"

    Sometimes you evaluate things that take a very long time to complete, or might not even ever complete (infinite loops, lazy sequences, things like that). Calva has a command for interrupting running evaluations. You find it in the VS Code command palette, as well as in the REPL status bar item menu, when the REPL is connected.

    ","boost":7},{"location":"evaluation/#evaluation-in-a-file-editor","title":"Evaluation in a File Editor","text":"

    Calva has many commands for evaluating forms, including the current form and the current top-level form.

    Some of the commands also let you choose what should happen with the results:

    1. Inline. This will display the results (or some of it, if it is long) inline in the editor.
    2. This also creates a hover pane including the full results and a button which will copy the results to the clipboard.
    3. There is also a command for copying the last result to the clipboard.
    4. The full results are always available in the output window.
      • There is a command for showing the output window, allowing for a workflow where you either generally have it closed, or have it as one of the tabs in the same editor group as the files you are working with.
    5. To comments. This will add the results as line comments below the current line.
    6. Replace the evaluated code. This will do what it says, the evaluated code will be replaced with its results.
    ","boost":7},{"location":"evaluation/#wait-current-form-top-level-form","title":"Wait, Current Form? Top-level Form?","text":"

    These are important concepts in Calva in order for you to create your most effective workflow. This video explains it a bit:

    ","boost":7},{"location":"evaluation/#current-form","title":"Current Form","text":"

    Default shortcut for evaluating the current form: ctrl+enter.

    The current form either means the current selection, or otherwise is based on the cursor position. Play some with the command Calva: Select current form, ctrl+alt+c s, to figure out what Calva thinks is the current form for some different situations. Try it inside a symbol, adjacent to a symbol (both sides) and adjacent to an opening or closing bracket (again, both sides). Generally the current form is determined like so:

    1. If text is selected, then that text
    2. If the cursor is \u201din\u201d a symbol, then that symbol
      foob|ar ; foobar\n
    3. If the cursor is adjacent to a form (a symbol or a list of some kind), then that form
      (foo bar |(baz)) ; (baz)\n
    4. If the cursor is between to forms, then the left side form
      (foo bar | (baz)) ; bar\n
    5. If the cursor is before the first form of a line, then that form
      (foo\n| bar (baz)) ; bar\n
    ","boost":7},{"location":"evaluation/#current-top-level-form","title":"Current Top-level Form","text":"

    Default shortcut for evaluating the current top level form: alt+enter.

    The current top-level form means top-level in a structural sense. It is not the topmost form in the file. Typically in a Clojure file you will find def and defn (and defwhatever) forms at the top level, which also is one major intended use for evaluating top level form: to define and redefine variables. However, Calva does not check the contents of the form in order to determine it as a top-level forms: all forms not enclosed in any other form are top level forms.

    An \u201dexception\u201d is introduced by the comment form. It will create a new top level context, so that any forms immediately inside a (comment ...) form will be considered top-level by Calva. This is to support a workflow with what is often referred to the Rich Comments.

    At the top level the selection of which form is the current top level form follows the same rules as those for the current form.

    ","boost":7},{"location":"evaluation/#evaluate-enclosing-form","title":"Evaluate Enclosing Form","text":"

    The default keyboard shortcut for evaluating the current enclosing form (the list the cursor is in) is ctrl+shift+enter.

    (let [foo :bar]\n  (when false (str| foo))) ; => \":bar\"\n
    ","boost":7},{"location":"evaluation/#evaluate-to-cursor","title":"Evaluate to Cursor","text":"

    There are several commands for evaluating a piece of code, closing brackets. It's good, especially in threads, but can also come in handy in other situations, for instance when you want to evaluate something that depends on bindings, such as in a let form.

    ","boost":7},{"location":"evaluation/#evaluate-from-start-of-list-to-cursor-closing-brackets","title":"Evaluate From Start of List to Cursor, Closing Brackets","text":"

    This command evaluates the text from the start of the current enclosing list to where the cursor is, and it adds the missing closing bracket for you. Convenient for checking intermediate results in thread or doto, or similar pipelines. The cursor is right behind :d in this form:

      (->> [1 1 2 3 5 8 13 21]\n       (partition 2)\n       (zipmap [:a :b :c :d])\n       :d| ; => (13 21)\n       (apply -)\n       (Math/abs))\n

    The default shortcut for this command is ctrl+alt+enter.

    ","boost":7},{"location":"evaluation/#evaluate-selection-closing-brackets","title":"Evaluate Selection, Closing Brackets","text":"

    This is the most versatile of the \u201devaluation, closing brackets\u201d commands. It will do what it says. \ud83d\ude04 It's extra handy in combination with the command Paredit: Select Backward Up Sexp/Form (shift+ctrl+up). Consider this contrieved form (buggy code, because it was supposed to result in 42, not -42):

    (defn fortytwo-from-thirty\n  []\n  (let [thirty 30]\n    (-> thirty\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

    At ;1, you can do backward up sexp (shift+ctrl+up) twice to select up to the (let ..), then issue Evaluate Selection, Closing Brackets. It has the same default keybinding as the command for evaluating the current list up to the cursor: ctrl+alt+enter.

    At ;2 you need select backwards up three times.

    ;3 is included because it is close to the bug. (Which was introduced when the thread-last, ->> was added to make this example.) Please practice the Evaluate Selection, Closing Brackets command to fix the bug.

    ","boost":7},{"location":"evaluation/#evaluate-from-start-of-top-level-form-to-cursor-closing-brackets","title":"Evaluate From Start of Top Level Form to Cursor, Closing Brackets","text":"

    This command has a default shortcut keybinding of shift+alt+enter. It will create a form from the start of the current top level form, up to the cursor, close all brackets, and this will then be evaluated. Good for examining code blocks up to a certain point. Often comes in handy in Rich comments ((comment ...)).

    Take this example and paste it in a file loaded into the REPL, then place the cursor in front of each line comment and try the command.

    (comment\n (do\n   (def colt-express\n     {:name \"Colt Express\"\n      :categories [\"Family\"\n                   \"Strategy\"]\n      :play-time 40\n      :ratings {:pez 5.0\n                :kat 5.0\n                :wiw 5.0   ; 1, then eval `colt-express`\n                :vig 3.0\n                :rex 5.0\n                :lun 4.0}})\n\n   (defn average [coll]\n     (/ (apply + coll) (count coll)))\n\n   (let [foo-express (-> colt-express\n                         (assoc :name \"Foo Express\")\n                         (assoc-in [:ratings :lyr] 5.0)\n                         (update-in [:ratings :vig] inc))]\n     (->> foo-express   ; 2\n          :ratings      ; 3\n          vals          ; 4\n          average       ; 5\n          ))))\n
    ","boost":7},{"location":"evaluation/#evaluate-from-start-of-file-to-cursor-closing-brackets","title":"Evaluate From Start of File to Cursor, Closing Brackets","text":"

    Yup, that command also exists. \ud83d\ude04

    ","boost":7},{"location":"evaluation/#copying-the-inline-results","title":"Copying the inline results","text":"

    There is a command called Copy last evaluation results, ctrl+alt+c ctrl+c.

    This works regardless if you have evaluated in a file editor or in a REPL window.

    ","boost":7},{"location":"evaluation/#evaluating-in-a-repl-window","title":"Evaluating in a REPL window","text":"

    Since the REPL Window is mostly just a regular file, things work pretty similar at the REPL prompt. You use alt+enter to evaluate. Selecting the current form (default key binding ctrl+w on Mac and shift+alt+right on Windows and Linux) after evaluating will select the result.

    ","boost":7},{"location":"fiddle-files/","title":"Fiddle Files Support","text":"

    In the podcast Functional Design in Clojure, Episode 014: Fiddle with the REPL, they discuss a workflow in which you keep some of your exploratory code in separate files, which they call Fiddle Files. It's like Rich Comments, and the files often consist of such comments. The Fiddle files are typically not on the classpath, and are only loaded in the REPL by you when you are developing your project. Some developers keep personal fiddle files. In some projects they are meant to be shared, and in other projects it's a combination.

    Calva has some extra support for the fiddle file workflow, beyond what VS Code offers in terms of navigating between files. The support comes in the form of three commands supported by a little configuration.

    ","boost":5},{"location":"fiddle-files/#the-three-fiddle-file-commands","title":"The Three Fiddle File Commands","text":"

    The commands let you quickly navigate between your implementation code (called Source here) and your Fiddle file, and to evaluate the Fiddle file without leaving the Source file.

    Command Action Shortcut Active Calva: Open Fiddle File for Current File Opens the Fiddle file corresponding to the current Clojure Source file. ctrl+alt+cf When the currently active file is not a Fiddle file. Calva: Open Source File for Current Fiddle File Opens the Source file corresponding to the current Fiddle file. ctrl+alt+cf When the currently active file is a Fiddle file + there is an existing, and corresponding, source file. Calva: Evaluate Fiddle File for Current File Evaluates the Fiddle file corresponding to the current Clojure Source file. ctrl+alt+cctrl+alt+f When the currently active file is not a Fiddle file.

    The commands for opening and evaluating corresponding Fiddle files will offer to Create the Fiddle file if it does not already exist. But the Calva: Open Source File for Current Fiddle File command will not offer to create the target file.

    What does corresponding mean here? Without any configuration Calva will look for \u201csibling\u201d files, where files with Clojure file extensions (E.g. .clj, .cljs, .bb) will be treated as Source files, and files with the .fiddle extension will be treated as Fiddle files. \"Sibling file\" here means residing side by side in the file system. If this default behaviour is not your cup of tea, there is some flexibility added by configuration.

    ","boost":5},{"location":"fiddle-files/#the-fiddle-file-configuration","title":"The Fiddle File Configuration","text":"

    To know how to map between Fiddle <-> Source files, Calva has three different modes of operation:

    1. The sibling files, as described above. This is the default. Example:
      • src/a/b/c.cljc corresponding to:
      • src/a/b/c.fiddle
    2. Parallel directory structures. Mapping a Source directory tree to a Fiddle directory tree. Example:
      • src/a/b/c.cljc corresponding to:
      • env/dev/fiddles/a/b/c.cljc
    3. A dedicated Fiddle file for a Source directory tree. E.g. both:
      • src/a/b/c.cljc and:
      • src/d/e/f.cljc corresponding to:
      • env/dev/fiddles/x.cljc

    The setting is named calva.fiddleFilePaths and is an array of source and fiddle root paths, relative to the project root.

    The Project Root

    It is important to note that the project root depends on whether you are connected to a REPL or not, and to which project you are connected, in case the workspace contains several projects.

    Without a REPL connection (disregarding that fiddle files are not very interesting then) the project root is the same as the first workspace root. And if you have a regular VS Code window open, it is the root of the folder you have opened in that window.

    With a REPL connection, the project root will be the root of the project, i.e. where the project file (deps.edn, project.clj, shadow-cljs.edn) is.

    ","boost":5},{"location":"fiddle-files/#example-configurations","title":"Example Configurations","text":"","boost":5},{"location":"fiddle-files/#single-parallel-directory-structure","title":"Single Parallel Directory Structure","text":"
    \"calva.fiddleFilePaths\": [\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n  }\n]\n

    This will make any file in the src directory tree correspond to a matching file with the same relative path. E.g.:

    • src/a/b/c.clj -> env/dev/fiddles/a/b/c.clj, for both the open and evaluate commands
    • env/dev/fiddles/a/b/c.clj -> src/a/b/c.clj
    ","boost":5},{"location":"fiddle-files/#single-dedicated-fiddle-file","title":"Single Dedicated Fiddle File","text":"

    If you generally work with one Fiddle file at a time, you can configure a mapping to a Dedicated Fiddle file. E.g.:

    \"calva.fiddleFilePaths\": [\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n  },\n]\n

    This will make any file in the src directory tree correspond to the same Fiddle file. E.g.:

    • src/a/b/c.clj -> env/dev/fiddle.clj, for both the open and evaluate commands
    • src/d/e/f.clj -> env/dev/fiddle.clj, ditto
    • env/dev/fiddle.clj -> Won't correspond to a Source file in this case

    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.

    ","boost":5},{"location":"fiddle-files/#multiple-mappings","title":"Multiple Mappings","text":"

    The configuration is an array so that you can configure different mappings for different Source directories. Given several mappings with overlapping Source, the longest mapping will win. Given several mappings with the same Source, the first one will win, unless one of them is a dedicated Fiddle, in which case that one will win.

    \"calva.fiddleFilePaths\": [\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddles\"]\n  },\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddle.clj\"]\n  },\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddle.cljs\"]\n  },\n  {\n    \"source\": [\"src\"],\n    \"fiddle\": [\"env\", \"dev\", \"fiddle.bb\"]\n  },\n  {\n    \"source\": [\"src\", \"b\"],\n    \"fiddle\": [\"env\", \"dev\", \"b-fiddles\"]\n  },\n]\n

    With this configuration we would get a behaviour like so:

    • src/a/b/c.clj -> env/dev/fiddle.clj, because all four first [\"src\"] mappings match, but the second one is a dedicated fiddle file, and matches the .clj extension.
    • src/a/b/c/d.bb -> env/dev/fiddle.bb, because all four first [\"src\"] mappings match, but the second one is a dedicated fiddle file, and matches the .bb extension.
    • src/a/b/c/d.cljc -> env/dev/fiddle.clj, because all four first [\"src\"] mappings match, but the second one is a dedicated fiddle file, without a matching file extension, (so the first dedicated fiddle file is picked).
    • src/b/c/d.clj -> env/dev/b-fiddles/c/d.clj, because the [\"src\", \"b\"] mapping is longer than the also matching [\"src\"] mappings.
    ","boost":5},{"location":"fiddle-files/#tips","title":"Tips","text":"

    Organize your Fiddle files such that they do not get automatically loaded as part of your application. This can lead to strange errors and hard-to-detect bugs. Most often it should only be you manually loading the fiddle file, not clj/clojure or Leiningen or any such system which loads your application.

    When you want your fiddle code to be evaluated in the same workspace as its corresponding Source file, you can use the same namespace declaration for both files. The linter might complain, but the REPL will happily comply.

    If you primarily evaluate the fiddle file using the provided command for it, from the Source files, you can omit the namespace declaration, and Calva will evaluate it in the namespace of the Source file.

    The linter and fiddle files

    For some fiddle files you will get a lot of linter warnings, because clj-kondo doesn't know about fiddle files, and they are often not on the classpath. You might find yourself wanting to silence some linters for some fiddle files. E.g. like this:

    (ns main.core\n  {:clj-kondo/config\n   '{:linters {:unresolved-symbol {:level :off}}}})\n

    See clj-kondo Configuration for more on what options you have for this.

    ","boost":5},{"location":"fiddle-files/#see-also","title":"See Also","text":"
    • Rich Comments
    • Functional Design in Clojure Episode 014: Fiddle with the REPL
    • The Polylith Development page mentions good practice for where to put your fiddle files (not called fiddle files there, but it is the same concept).
    ","boost":5},{"location":"finding-commands/","title":"Finding Calva Commands","text":"

    Calva relies a lot on that VS Code makes it really easy to find commands by opening the command palette: ctrl+shift+p (Windows/Linux), cmd+shift+p (Mac), and then start typing some words (or parts of words) that you think might be in the command.

    To leverage this, all Calva commands are prefixed with Calva. As an example, say you want to find commands related to evaluating the top level form. Then you can do this:

    1. Open the command palette
    2. Type calevtop

    VS Code will match cal to \u201dCalva\u201d, ev to \u201dEvaluate\u201d, and top to \u201dTop\u201d. It looks like so:

    As you can see on the screenshot, VS Code will also reveal the keyboard shortcut for each command. My advice is to make it a habit to try to remember those shortcuts and use them for a more effective workflow.

    Now might be a good time to see Calva Top 10 Commands

    "},{"location":"finding-commands/#all-the-settings-and-commands","title":"All the Settings and Commands","text":"

    Did you know? There is a complete list of Calva settings and commands in the Contributions tab of the Calva entry in the Extensions pane in VS Code.

    "},{"location":"finding-commands/#toggling-keyboard-shortcuts-onoff","title":"Toggling Keyboard Shortcuts On/Off","text":"

    The command calva.toggleKeybindingsEnabled can be used to quickly enable and disable (almost) all keyboard shortcuts. This allows you to quickly toggle between Calva keybindings and other keybindings which would otherwise not be available when Calva is enabled. This is particularly useful with the Paredit keyboard shortcuts, whose default shortcuts conflict with the default VS Code shortcuts for textual (non-structural) editing.

    By default it is not bound to a shortcut so as not to cause confusion by users unwittingly pressing it, but if this is something you'd like to use often, you may want to bind it to a shortcut.

    "},{"location":"formatting/","title":"Formatting","text":"

    We have tried to make Calva's formatter so that it just works. It is enabled by default for Clojure files, and with the default configuration it mostly follows Bozhidar Batsov's Clojure Style Guide. Calva uses cljfmt for the formatting.

    Tab formats the current surrounding form

    Calva's code formatter sets the default keybinding of its Format Current Form command to tab. Meaning that most often when things look a bit untidy, you can press tab to make things look pretty. Good to know, right? For performance reasons it only formats the current enclosing form, so sometimes you want to move the cursor up/out a form (ctrl+up) first. See The Paredit Guide for more on moving the cursor structurally through your code.

    With the default settings, Calva's formatting behaves like so:

    • indents as you type (when entering new lines)
    • formats the current enclosing form when you hit tab
    • formats pasted code
    • formats according to community standards
    • formats the current form, aligning map keys and values, when you press ctrl+alt+l
    • formats (comment ...) forms special, see rich comments

    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.

    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):

    • trims whitespace at the end of the line
    • trims whitespace inside brackets
      • this also folds trailing brackets (a k a the paren trail) up on the same line
    • inserts whitespace between forms

    Not a fan of some default setting? The formatter is quite configurable.

    "},{"location":"formatting/#format-current-form-command-variants","title":"Format current form command variants","text":"

    There are three special commands for formatting the current form:

    "},{"location":"formatting/#1-format-and-align-current-form","title":"1. Format and Align Current Form","text":"

    Aligns associative structures and bindings in two columns. See more below.

    "},{"location":"formatting/#2-format-current-form-and-trim-space-between-forms","title":"2. Format Current Form and trim space between forms","text":"

    This formats the text, and trims consecutive, non-indent, whitespace on a line to just one space. Something like:

    (let [a    :b]\n(str \"foo\"     \"bar\" \"baz\"\n\"a\"    a))\n

    Becomes:

    (let [a :b]\n  (str \"foo\" \"bar\" \"baz\"\n       \"a\" a))\n

    Basically, it behaves like if :remove-multiple-non-indenting-spaces? true was added to the cljfmt config. Which, in fact, is what happens. Calva merges that onto your cljfmt config when this command is used.

    "},{"location":"formatting/#3-replace-current-form-or-selection-with-pretty-printed-form","title":"3. Replace Current Form (or Selection) with Pretty Printed Form","text":"

    This command will run the code of the Current Form through Calva's pretty printer (the engine named calva, which is using zprint) and replace the current form inline in the editor with the pretty printed results.

    Unlike with the \u201dreal\u201d Calva Formatter, which never breaks up lines, this one will follow your pretty printing options and break up lines if you have set maxWidth to something that calls for breaking up lines.

    Applies to the other Current Form

    Unlike the other Format commands, which applies to the current enclosing form, this one applies to the Current Form, same as with evaluations. That is because this is not really part of the Calva formatter, but rather is a convenience command for tidying up code or data.

    "},{"location":"formatting/#provide-zprint-config-via-keyboard-shortcuts-or-joyride","title":"Provide zprint config via keyboard shortcuts (or Joyride)","text":"

    The default options for the command are to not sort maps and to not insert commas between map entries. However, the command takes a map as an argument, expecting this map to be a zprint configuration map. You can provide the argument map via keyboard shortcuts. In VS Code settings, you use JSON, but it will be converted to EDN before handed to zprint.

    Say you want to have maps sorted by their keys, and generally use community standard formating + justify maps and bindings. This keyboard shortcut does that.

        {\n        \"key\": \"ctrl+alt+p enter\",\n        \"command\": \"calva.prettyPrintReplaceCurrentForm\",\n        \"args\": {\n            \"style\": [\"community\", \"justified\"],\n            \"map\": {\n                \"comma?\": false,\n                \"sort?\": true,\n            }\n        }\n    }\n

    Note that we have to specify \"comma?\": false here, because this argument will replace the default options maps for the command.

    "},{"location":"formatting/#configuration","title":"Configuration","text":"

    You can adjust the above mentioned defaults, and the default indents, by configuring the formatting using cljfmt's configuration EDN.

    This configuration can either be provided via a file or via clojure-lsp. See Providing configuration via clojure-lsp below.

    "},{"location":"formatting/#providing-configuration-via-a-config-file","title":"Providing configuration via a config file","text":"

    Calva will look for the configuration in one of the default cljfmt paths ('.cljfmt.edn', '.cljfmt.clj', 'cljfmt.edn', or 'cljfmt.clj' in the workspace root). If your file is somewhere else use the calva.fmt.configPath to tell Calva where to find it. The path should either be absolute, or relative to the workspace root directory. If your config file is somewhere in the workspace root, Calva will hot reload it when you update it.

    Wherever the config file is, a suggested path for providing your configuration is to start changing the Calva formatting defaults by pasting the following map into a file and save it.

    {:remove-surrounding-whitespace? true\n :remove-trailing-whitespace? true\n :remove-consecutive-blank-lines? false\n :insert-missing-whitespace? true\n :remove-multiple-non-indenting-spaces? false}\n

    If the file is in the workspace, you can quickly test how different settings affect the formatting. Try:

    1. Adding :align-associative? true to the config
    2. then save
    3. then hit tab, and see what happens.
    :align-associative? is experimental

    This particular setting is experimental and known to cause trouble together with namespaced keywords. Consider using ctrl+alt+l instead of tab as your formatting command, instead of enabling this setting. See below for more info about this. See more below about this.

    No Leiningen config support

    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.

    "},{"location":"formatting/#providing-configuration-via-clojure-lsp","title":"Providing configuration via clojure-lsp","text":"

    If you work in a team where some members use clojure-lsp for formatting, you can make Calva format using the same configuration by telling setting calva.fmt.configPath to CLOJURE-LSP (case sensitive). See Clojure LSP Settings) for how to provide the configuration. (It might not be provided from where you think it is, specifically check clojure-lsp's global config in you user home directory.) Use the command Calva Diagnostics: Clojure-lsp Server Info to see what cljfmt configuration is being used (under the cljfmt-raw key).

    Note that doing this you will not have hot reload of the formatting configuration, and of course you will be depending on that clojure-lsp is running and functioning.

    "},{"location":"formatting/#indentation-rules","title":"Indentation rules","text":"

    The cljfmt indents are highly configurable. They, and the rest of the configuration options, are masterly detailed here.

    :extra-indents vs :indents

    Since Calva v2.0.383 we are using cljfmt 0.11.x which has a breaking configuration change. From the cljfmt README:

    The :indents key has been split into :indents and :extra-indents. The :indents key replaces all default indents, while the :extra-indents key will append to the default indents.

    If something prevents you from using a config with :extra-indents, there's an escape hatch to keep using the :indents key as before, by adding :legacy/merge-indents? true to the config map.

    Calva is an extra good tool for experimenting with these settings. cljfmt doesn't care about keys in the map that it doesn't know about so you can sneak in test code there to quickly see how it will get formatted by certain rules. Try this, for instance:

    {:remove-surrounding-whitespace? true\n :remove-trailing-whitespace? true\n :remove-consecutive-blank-lines? false\n :insert-missing-whitespace? false\n :indents {#re \"^\\w\" [[:inner 0]]}\n :test-code\n (concat [2]\n         (map #(inc (* % 2))\n              (filter #(aget sieved %)\n                      (range 1 hn))))}\n

    Save, then hit tab, and the code should get formatted like so:

     :test-code\n (concat [2]\n    (map #(inc (* % 2))\n      (filter #(aget sieved %)\n        (range 1 hn))))\n

    That's somewhat similar to Nikita Prokopov's Better Clojure Formatting suggestion. (Please be aware that this setting might not be sufficient to get complete Tonsky Formatting, please share any settings you use to get full compliance.)

    "},{"location":"formatting/#rich-comments","title":"Rich Comments","text":"

    To encourage use of (comment ...) forms for development, the default settings give these forms get a special treatment when formatting. Use the calva.fmt.keepCommentTrailParenOnOwnLine setting to control this behaviour. See Rich Comments first.

    "},{"location":"formatting/#etecetera","title":"Etecetera","text":""},{"location":"formatting/#about-aligning-associative-forms","title":"About aligning associative forms","text":"

    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:

    • The implementation is a bit buggy and can do a bit crazy formatting on certain forms.
    • The older version of cljfmt lacks updates for some new Clojure features and also some bugs fixed since the fork are not applied.

    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.

    "},{"location":"get-started-with-clojure/","title":"Get Started with Clojure","text":"

    Welcome to a zero-install, interactive, guide to get you started with Clojure using:

    • Clojure
    • Gitpod (A development environment delivered via the web browser)
    • VS Code (Or Gitpod Code, actually. In your web browser.)
    • Calva (A Clojure extension to VS Code. The thing this site is about.)
    • Calva's Getting Started REPL
    I have VS Code and Java

    Clojure runs on the JVM. How to install it is a big topic. Since you have already done that, you can, if you want, choose to install Calva in your local VS Code and fire up the Getting Started REPL. By all means read this page anyway, you can just skip the Gitpod parts.

    Also: If you are using Windows your Java might have a bug that prevents things from working. Then you might want to defer fixing that and use the zero-install option first.

    Is Gitpod Code exactly as VS Code?

    Almost! But, yeah, there are some difference between regular VS Code and Gitpod's ditto. Most of it doesn't matter, but finding the main menu can be a bit tricky:

    ","boost":10},{"location":"get-started-with-clojure/#what-youll-learn","title":"What you'll learn","text":"
    • The basics of the Clojure language (at least the start of the basics)
    • The basics of the ClojureScript language (we won't be using ClojureScript, but it is same language \ud83d\ude00)
    • The basics of Calva (It's a bit as a side effect. You need it to learn Clojure this way, and by learning Clojure this way, Calva knowledge trickles in.)
    • What is meant by, and some ways to perform, Interactive Programming (aka REPL Driven Development)
    • Where to find Clojurians, i.e. folks who use Clojure and care about it (you will thus find help, the friendliest help you have ever seen a community provide)
    I am not convinced I should spend time on learning Clojure

    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:

    • Solving Problems the Clojure Way - with Rafal Dittwald (using JavaScript, so no new syntax to grasp to get the message)
    • Developer Ergonomics with VS Code, Clojure, and ClojureScript - with Peter Str\u00f6mberg
    • Clojure in VS Code Workflow using FizzBuzz - with Peter Str\u00f6mberg
    ","boost":10},{"location":"get-started-with-clojure/#what-you-wont-learn","title":"What you won't learn","text":"
    • How to install Clojure for your operating system of choice
    • About various old and new build and dependency tools
    • How to create projects and do real stuff
    Why won't I learn about this?

    All in due time. \ud83d\ude04 It can be a bit confusing with all the things you find out about installing Clojure and creating projects when searching for information about it. We want you to relax about all that and just enjoy learning a bit about this fantastic programming language and the wonderful mode of development it offers.

    There is a lot of info about this out there already. And since you will learn where to find Clojurians, you will also find guidance. But we suggest do these things later. First, let's focus on having fun with Interactive Programming!

    ","boost":10},{"location":"get-started-with-clojure/#what-you-need","title":"What you need","text":"
    • Curiosity about Clojure
    • A web browser
    The browser ate my keyboard shortcuts!

    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:

    • Undo (undoing something web browser related)
    • Select the line (focusing the browser URL input)
    • Open the command palette (opening a private browsing window. Looking at you Firefox.)
    • Escape key shortcuts (are you using VIM bindings in your browser?)

    Sometimes the workaround is to redefine the shortcuts in VS Code, sometimes making your web browser stop catching the shortcut.

    I am new to VS Code

    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.

    ","boost":10},{"location":"get-started-with-clojure/#how-it-works","title":"How it works","text":"
    1. You will open an instance of VS Code in a development environment running in the browser. The environment will have Java, Clojure tools, and Calva installed.
      • Gitpod Sign-in You will be asked to sign in to Gitpod, if you aren't already. You need to use the \u201dSign in with GitHub\u201d option.
    2. Instructions will be automatically displayed (very brief such, because it is mainly about firing up the Getting Started REPL)
    3. The guides are a mix of prose (in Clojure line comments), Clojure code, and exercises. What's extra poetic is that you will use Calva and Clojure to learn Calva and Clojure.

    Use a desktop/laptop computer. Even if it actually works on the phone, it is far from convenient.

    It sometimes takes a while (several minutes) for the environment to initialize. Take some deep breaths and be patient. \ud83d\ude0e

    ","boost":10},{"location":"get-started-with-clojure/#lets-go","title":"Let's go!","text":"

    Ready? Awesome. Click this button to start the guide in a new browser tab.

    https://gitpod.io/#https://github.com/PEZ/get-started-with-clojure Stuck? Something not working? Or just unclear?

    Please don't hesitate to reach out for help, should you get stuck. See below for where to find Clojurians. As for the Calva team, we are almost always (true story) to be found at the Clojurians Slack, especially in the #calva Channel. We are @pez and @bringe there.

    Happy Interactive Programming! \u2764\ufe0f

    ","boost":10},{"location":"get-started-with-clojure/#and-where-do-i-find-those-clojurians","title":"And where do I find those Clojurians?","text":"

    We Clojurians inhabit a lot of community platforms. I'll list some of the more popular ones here in some order of popularity.

    • The Clojurians Slack - by far the largest and most active Clojure community, the #beginners channel is spectacularly fantastic
    • ClojureVerse - a web forum. Lots of Clojurians, lots of Clojure knowledge collected, easy to search, easy to join
    • /r/Clojure - Reddit when Reddit is at its best, lots of Clojurians here
    • Clojurians on Zulip - An other web forum using the Zulip platform
    • On Discord there are two active servers: Clojurians and Discord

    You can also ask questions, and find answers, about Clojure at ask.clojure.org

    ","boost":10},{"location":"get-started-with-clojure/#learn-and-practice-clojure-using-rich-4clojure","title":"Learn and Practice Clojure using Rich 4Clojure","text":"

    If you like the style of interactive learning that this guide provides, you should definitely check Rich 4Clojure out. It also can be used in the zero-installed way.

    You can regard it as a companion to this guide. It is aimed at practicing Clojure, starting at the elementary levels, bringing you to advanced stuff.

    Can I use Rich 4Clojure instead of this guide?

    We suggest you start by opening up this guide and do the Calva part of the excerises. Then use the welcome_to_clojure.clj guide in combination with Rich 4Clojure..

    ","boost":10},{"location":"get-started-with-clojure/#run-the-clojure-exercism-track-in-your-browser","title":"Run the Clojure Exercism Track in your browser","text":"

    In a similar manner to the Get Started with Clojure project, you can run the Clojure Exercism Track in your browser without installing anything and with full Interactive Programming enabled using this Template project.

    ","boost":10},{"location":"get-started-with-clojure/#clojuredocs","title":"ClojureDocs","text":"

    Clojurians draw tremendous value from ClojureDocs. At ClojureDocs the concise documentation for Clojure core functions, etcetera, are amended with examples and advice from fellow Clojurians. Crowdsourcing at its very best! It is a big part of the reason why you won't find an abundance of Clojure information at StackOverflow.

    ","boost":10},{"location":"get-started-with-clojure/#other-learning-resources","title":"Other learning resources","text":"
    • CalvaTV - Calva's YouTube channel often focuses on beginning with Clojure and ClojureScript. Subscribe, please!
    • Clojure Beginner Resources - a much more comprehensive list than this one
    • clojure.org Getting Started - the source of truth, includes installing and stuff
    • The Exercism Clojure track - Learn solving carefully crafted Clojure exercises, get mentor feedback if you like.
    • Clojure for the Brave and True - helping you from beginner to pretty advanced stuff, very popular among Clojurians
    • on the code again - often features Clojure concepts, with snappy, well communicated, and entertaining videos
    • Clojure Koans with VS Code/Calva instructions
    ","boost":10},{"location":"get-started-with-clojure/#help-us-help-beginners","title":"Help us help beginners","text":"

    Give us feedback. Spread the word. Please consider:

    • Join the #improve-getting-started channel at the Clojurian Slack
    • Linking to this page from your blog
    • Tweeting about this guide
    • Contributing to the Calva project
    • Wearing Calva and RFC T-shirts
    • Starring these repositories:
      • Get Started with Clojure - (the repository powering this guide)
      • Rich 4Clojure
      • Clojure Exercism Track Template
      • Calva
      • Dram - Where this guide (the Getting Started REPL) is authored
    • What do beginners struggle with? - a ClojureVerse thread, where you can tell us about what you have found hard in picking up Clojure. It's what spawned the creation of this guide.

    Please also consider other ways to contribute.

    Thanks! \ud83d\ude4f

    ","boost":10},{"location":"getting-started/","title":"Getting Started","text":"

    Depending on wether you want to just start a Clojure REPL or you have a project you want to work with, getting started looks similar but a bit different. Regardless, you need to first:

    ","boost":10},{"location":"getting-started/#install-vs-code-and-calva","title":"Install VS Code and Calva","text":"
    1. Downloading VS Code and run the installer.
      • Also get aquainted to the basics of VS Code, if you aren't already. Here's an excellent intro: Getting Started with VS Code
    2. Install Calva. The easiest way to do that is to start VS Code and search for Calva in the VS Code Extension pane, then click Install.
    ","boost":10},{"location":"getting-started/#say-hello-to-calva","title":"Say hello to Calva","text":"

    If you have a Clojure or ClojureScript project, you will be interested in how to get Calva connected to the REPL of your project. But before you run over there, you might want to familiarize yourself with Calva a bit, which you can do without a project.

    The demo tells you about the command (and some about the Clojure Beginner's material that it makes available).

    I am completely new to Clojure

    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.

    I don't have Java installed

    If you like, you can defer installing anything at all and still get started with Calva (not kidding).

    See Get Started with Clojure.

    ","boost":10},{"location":"getting-started/#theres-a-getting-started-repl","title":"There's a \u201dGetting Started\u201d REPL","text":"

    If you are new to Calva, a good place to start is using the command Fire up the \u201dGetting Started\u201d REPL. (You can open the command palette using the VS Code top menu by going to View -> Command Palette... or by running the associated keyboard shortcut for your OS.) Demo:

    It will open up a three files in a temporary directory, and start and connect a REPL. The files are:

    • hello_repl.clj \u2013 The basics of how to evaluate code in Calva
    • hello_paredit.clj - A super brief intro to Calva structural editing
    • welcome_to_clojure.clj - The very basics of the Clojure language

    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.)

    Note

    On Windows the Oracle Java installer sets Java up in some funny way so that the Getting Started REPL fails to start. We are figuring about workarounds for this, but for now, if you are on Windows, you will need to make VS Code have some other Java in the PATH of its environment for this feature to work. See this issue on the Calva repo for more on this, including any progress.

    ","boost":10},{"location":"getting-started/#there-are-standalone-clojurescript-quick-start-repls","title":"There are standalone \u201dClojureScript Quick Start\u201d REPLs","text":"

    Without creating a project structure or installing anything but Calva, you can start standalone ClojureScript REPLs both in a browser and for node:

    • Fire up the ClojureScript Quick Start Browser REPL
      • Opens the files core.cljs and index.html and starts the ClojureScript app, opening it in the browser.
    • Fire up the ClojureScript Quick Start Node REPL
      • Opens a file, core.cljs, and starts a nodejs REPL where it loads the file.

    The browser REPL app looks like so:

    ","boost":10},{"location":"getting-started/#you-have-a-project","title":"You have a Project?","text":"

    If you are new to Calva, please consider the above option first. Then when it will be time to get Calva connected to the REPL of your project.

    ","boost":10},{"location":"getting-started/#clojure-resources","title":"Clojure Resources","text":"

    If you are new to Clojure or ClojureScript altogether, please check out the guide material on the respective official sites:

    • Getting Started with Clojure
    • ClojureScript Quick Start

    There are also many great books on Clojure. Clojure for the Brave and True can be read for free online. It is a great resource for beginners.

    ","boost":10},{"location":"getting-started/#there-is-also-standalone-repl","title":"There is also Standalone REPL","text":"

    When you are more familiar with Calva, and want a standalone REPL, there is a separate command: Start a standalone REPL (not in project). It will open up a user.clj in a temporary directory, containing only an (ns user) form, and start and connect the REPL.

    ","boost":10},{"location":"getting-started/#dram-where-the-guides-live","title":"Dram - Where the Guides Live","text":"

    The command for starting the Getting Started REPL will download the files from this repository. It is very much work in progress, and there is not even a finished Clojure Beginner's Guide there yet. When you run the command again, and from then on, you will get the option to download new files or keep using your existing. Downloading new ones will not overwrite your existing ones, because they will be downloaded to a new temp directory. You can find the directory easily using VS Codes context menu command for revealing a file in the Explorer/Finder.

    ","boost":10},{"location":"getting-started/#one-last-thing","title":"One Last Thing","text":"

    Happy coding! \u2665\ufe0f

    ","boost":10},{"location":"hiccup/","title":"Converting HTML to Hiccup","text":"

    Calva can help you convert HTML to Hiccup.

    ","boost":7},{"location":"hiccup/#features","title":"Features","text":"","boost":7},{"location":"hiccup/#three-commands","title":"Three commands","text":"
    • Convert HTML to Hiccup, will convert the selected text, or the entire file, to Hiccup and open up an Untitled Clojure file with the result.
    • Copy HTML as Hiccup, will convert the selected text, or the entire file, to Hiccup and copy it to the clipboard.
    • Paste HTML as Hiccup, will convert the contents of the clipboard to Hiccup and paste it. (The clipboard will then be restored to the original content.)

    The resulting data structure is formatted with zprint using it's :style :hiccup configuration.

    ","boost":7},{"location":"hiccup/#conversion-capabilities","title":"Conversion capabilities","text":"

    In addition to, optionally, being able to convert style attributes to maps and kebab-case attributes, the conversion:

    • Opts for producing compact Hiccup:
      • The id attribute and classes are made part of the tag, CSS selector style
        • <foo id=\"bar\"></foo> => [:foo#bar]
        • <foo class=\"c1 c2\"></foo> => [:foo.c1.c2]
        • <foo id=\"bar\" class=\"c1 c2\"></foo> => [:foo#bar.c1.c2]
      • Though, if the id or any class is not valid as part of a keyword, they remain in the props/attributes map)
        • <foo id='foo-[id]'></foo> => [:foo {:id \"foo-[id]\"}]
        • <foo class='clz1 clz[2]'></foo> => [:foo.clz1 {:class [\"clz[2]\"]}]
      • Whitespace is trimmed
        • <foo> \\nbar\\n </foo> => [:foo \"bar\"]
        • <foo> \\n </foo> => [:foo]
    • Handles boolean attributes
      • <foo disabled></foo> => [:foo {:disabled true}]
      • <foo disabled=disabled></foo> => [:foo {:disabled \"disabled\"}]
    • Special case for camelCasing attributes viewBox and baseProfile (SVG is picky about it)
      • <foo bAsePROFilE=bar viewbox=\"0 0 1 1\"></foo> => [:foo {:baseProfile \"bar\" :viewBox \"0 0 1 1\"}]
    • Comments are retained
      • <foo><!-- ... --></foo> => [:foo (comment \"...\")]
    • You can have several top level tags
      • <foo></foo><foo></foo> => [:foo]\\n[:foo]
    ","boost":7},{"location":"hiccup/#it-is-somewhat-configurable","title":"It is somewhat configurable","text":"

    The Hiccup converstion can be tweaked with two options using the setting calva.html2HiccupOptions, which is a map/object:

    • mapify-style: boolean, default false. When true any style attribute will be converted to a map (Reagent supports this)
    • kebab-attrs?: boolean, default false. When true attribute names will be converted from camelCase, or snake_case/SNAKE_CASE to kebab-case. (Reagent wants most attribute names like this.)
    • add-classes-to-tag-keyword?: boolean, default true. When true all class names will be added CSS-style to the tag keyword ([:tag.clz1.clz2]), as opposed to being kept in the class attribute. Keeping the class names in the attribute may be preferable with elements having a lot of class names, such as when using Tailwind CSS.
    ","boost":7},{"location":"hiccup/#copy-as-menus-copy-html-as-hiccup","title":"Copy as menus: Copy HTML as Hiccup","text":"

    The Copy HTML as Hiccup command is available from VS Code's Edit menu, as well as the editor context menu, in both cases under the Copy as sub menu.

    ","boost":7},{"location":"hiccup/#the-commands-take-arguments","title":"The commands take arguments","text":"

    This options map can also be provided as an argument to the commands, so you can bind keyboard shortcuts to a particular configuration for the conversion.

    The command calva.convertHtml2Hiccup takes a map as an argument:

    • toUntitled: boolean, default false. When false the result of the conversion will be returned to the caller (This is intended for Joyride, or some other VS Code extension). When true it will behave like the default command does, placing the result of the conversion in an Untitled Clojure file.
    • options: Same as those calva.html2HiccupOptions mentioned above.

    The calva.pasteHtmlAsHiccup and calva.copyHtmlAsHiccup commands takes only a calva.html2HiccupOptions map.

    ","boost":7},{"location":"hiccup/#example-keyboard-shortcuts","title":"Example keyboard shortcuts","text":"

    The commands have no default keyboard shortcuts, you use the Command Palette to execute them, or you bind your own shortcuts. Here are some examples:

        // calva.convertHtml2Hiccup\n    {\n        // With args, `\"toUntitled\": true` is necessary for keyboard shortcuts\n        // without it, the command just returns the result to the caller\n        \"key\": \"ctrl+alt+c ctrl+h\",\n        \"command\": \"calva.convertHtml2Hiccup\",\n        \"args\": {\"toUntitled\": true, \"options\": {\"mapify-style?\": false}}\n    },\n    {\n        // Only for completeness, providing the HTML is only useful from e.g. Joyride \n        \"key\": \"ctrl+alt+c shift+h\",\n        \"command\": \"calva.convertHtml2Hiccup\",\n        \"args\": {\"html\": \"<foo style='a: b' bar='baz'>gaz<foo>\", \"toUntitled\": true}\n    },\n    {\n        // Without args, the command uses the `calva.html2HiccupOptions` configuration\n        // And writes the results to an Untitled document\n        \"key\": \"ctrl+alt+c h\",\n        \"command\": \"calva.convertHtml2Hiccup\",\n    },\n\n    // calva.pasteHtmlAsHiccup\n    {\n        // Override the `calva.html2HiccupOptions` configuration\n        \"key\": \"ctrl+alt+h ctrl+v\",\n        \"command\": \"calva.pasteHtmlAsHiccup\",\n        \"args\": {\"mapify-style?\": true, \"kebab-attrs?\": true}\n    },\n    {\n        // Without args, the command uses the `calva.html2HiccupOptions` configuration\n        \"key\": \"ctrl+alt+h v\",\n        \"command\": \"calva.pasteHtmlAsHiccup\"\n    },\n\n    // calva.copyHtmlAsHiccup\n    {\n        // Override the `calva.html2HiccupOptions` configuration\n        \"key\": \"ctrl+alt+h ctrl+c\",\n        \"command\": \"calva.copyHtmlAsHiccup\",\n        \"args\": {\"mapify-style?\": false, \"kebab-attrs?\": true}\n    },\n    {\n        // Without args, the command uses the `calva.html2HiccupOptions` configuration\n        \"key\": \"ctrl+alt+h c\",\n        \"command\": \"calva.copyHtmlAsHiccup\"\n    },\n

    The default/args-less bindings are placed last because reasons.

    ","boost":7},{"location":"hiccup/#using-from-joyride-or-some-other-vs-code-extension","title":"Using from Joyride (or some other VS Code extension)","text":"

    As with any VS Code command using these from Joyride is a matter of calling executeCommand.

    ","boost":7},{"location":"hiccup/#calvapastehtmlashiccup-and-calvapastehtmlashiccup","title":"calva.pasteHtmlAsHiccup and calva.pasteHtmlAsHiccup","text":"
    (-> (vscode/commands.executeCommand \"calva.pasteHtmlAsHiccup\"\n                                    #js {:mapify-style? true})\n    (.then ...))\n\n(-> (vscode/commands.executeCommand \"calva.copyHtmlAsHiccup\"\n                                    #js {:mapify-style? true})\n    (.then ...))\n
    ","boost":7},{"location":"hiccup/#calvaconverthtml2hiccup","title":"calva.convertHtml2Hiccup","text":"

    Without options the command behaves just like selecting the command from the command palette. If there is a selection it will be converted, otherwise the whole file. The result will be opened in a new Untitled document.

    (-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\")\n    (.then ...))\n

    Called with arguments it will by default return an object with a .-result member which is a string with the Hiccup.

    (-> (vscode/commands.executeCommand \"calva.convertHtml2Hiccup\" \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

    To make it put the text in a new Untitled document instead, provide the argument option :toUntitled true

    (-> (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
    ","boost":7},{"location":"inspector/","title":"Unfold that data","text":"

    All REPL evaluation results are added to the Calva Inspector, a tree view that lets you expand and collapse Clojure data structures. (This happens in addition to results being printed to the configured Output Destination.)

    Only for realized data

    Results are added to the inspector after they have been processed by your pretty printer (if you have pretty printing enabled). This means that maxLength and maxDepth applies. The inspector can't be used to explore infinite sequences. Also, any metadata is lost in the translation.

    "},{"location":"inspector/#uifeatures","title":"UI/Features","text":"

    The inspector view can be placed in the left or right side bars, or in the bottom panel. It can also be placed as a section in an existing side bar view, or in split with any existing bottom panel view.

    Inspector items are not expandable until you make them so with the Inspect Result Item button. This is because parsing and building the structure for the tree can take a little while and we don't want it to lock the UI for you when you edit and evaluate code.

    Speaking of buttons. Items in the view have context commands that show up as buttons on hover. The Inspect Result Item button is one of them. All rows in the inspector have a Copy button, letting you copy the data at any folding level to the clipboard. All root items also have a Clear button for removing the item from the inspector.

    The view itself has two buttons, one for clearing all results and one for pasting whatever is on the clipboard as an inspector item.

    "},{"location":"inspector/#commands","title":"Commands","text":"

    These are the commands available for the inspector:

    • Calva: Reveal Inspector. Reveals/shows the inspector without focusing it. Default keybinding is ctrl+alt+o i
    • This command, when used from keyboard shortcuts or Joyride, has the command ID of calva.revealInspector, and takes an object argument: { focus: boolean, select: boolean, expand: boolean | number }. focus lets you focus the inspector view (or not), select and expand lets you select or expand the current item which, like with several of the inspector commands, will be the already selected item, or the topmost item if none is selected. It is passed to the TreeView backing the inspector, see the VS Code API docs regarding revealing tree view items for details.
    • Calva: Add Selection or Current Form to Inspector. Adds the current form (without evaluating it) to the inspector. If there is text selected, the command will add that text instead. (Only the first selection, if there are multiple). There is no default keybinding for this command.
    • This command has the ID of calva.addToInspector. The command takes an optional argument, a string to be added. This is meant for Joyride scripts that want to add things to the inspector.
    • Calva: Clear All Inspector Items. You can use the command or the button for this in the view. No default keybinding.
    • Calva: Paste as Inspector Item. Same as the view button. No default keybinding.
    • Calva: Inspect Item. Makes the selected item inspectable, expands it one level, selects it, and focuses the inspector. Works on the topmost item if none is selected. No default keybinding.
    • Calva: Copy Inspector Item. Copies the text of the selected inspector item, or the topmost item if none are selected. No default keybinding.
    • Calva: Clear Inspector Item. Clears the selected inspector item, or the topmost item if none are selected. No default keybinding.

    The VS Code Shortcuts editor is a good tool for looking up command IDs and, duh, register custom shortcuts for these commands.

    "},{"location":"inspector/#configuration","title":"Configuration","text":"

    The settings for the inspector are:

    • calva.autoOpenInspector: controls wether the view is revealed as part of connecting the REPL to Calva. It defaults to false.
    • calva.enableInspectorRainbow: when enabled, the inspector items representing collection types will be colored using the theme colors used by VS Code to color bracket pair levels.
    "},{"location":"inspector/#calvaenableinspectorrainbow-example","title":"calva.enableInspectorRainbow example","text":"

    Depending on your theme, enabling the inspector rainbow can make some items not display at all. This is because not all themes provide all (or any) bracket level colorings. You can define the missing ones, or all, levels in your settings JSON file. Here's an example harmonizing the levels coloring with the default Calva Highlight rainbow (included in the example for easy comparison):

      \"workbench.colorCustomizations\": {\n    \"[GitHub Light Default]\": {\n      \"editorBracketHighlight.foreground1\": \"#000\",\n    },\n    \"[GitHub Dark Default]\": {\n      \"editorBracketHighlight.foreground1\": \"#cccccc\",\n    },\n    \"editorBracketHighlight.foreground2\": \"#0098e6\",\n    \"editorBracketHighlight.foreground3\": \"#e16d6d\",\n    \"editorBracketHighlight.foreground4\": \"#3fa455\",\n    \"editorBracketHighlight.foreground5\": \"#c968e6\",\n    \"editorBracketHighlight.foreground6\": \"#999\",\n    \"terminal.ansiRed\": \"#ff7a5a\",\n  },\n  \"calva.highlight.bracketColors\": [\n    [\n      \"#000\",\n      \"#ccc\"\n    ],\n    \"#0098e6\",\n    \"#e16d6d\",\n    \"#3fa455\",\n    \"#c968e6\",\n    \"#999\",\n    \"#ce7e00\"\n  ],\n

    This is the setting used for the screenshot above. Here's a rainbow-only screenshot:

    Note that with the Calva Highlight rainbow colors, we use a tuple for light and dark theme colors. The VS Code theme color settings do not allow this, so if you need different colors for light and dark themes, you need to specify the exact theme. We do this in the example, since the default Calva Highlight rainbow needs different light/dark colors for the top level brackets.

    "},{"location":"jack-in-guide/","title":"Learn about Calva Jack-in","text":"

    The Calva Jack-In Academy, by @pez

    Like with CIDER Jack-in, Calva's let-me-help-you-start-your-project-and-connect feature might seem a bit mysterious. It really is helpful, but also really isn't mysterious. Here are a few things about it that is good to know about.

    Note

    If you came here to find out how to configure the versions of the dependencies that Calva Jack-in injects, see Customizing Calva - Jack-in Dependency Versions.

    ","boost":6},{"location":"jack-in-guide/#what-it-solves","title":"What it Solves","text":"

    At first it might seem that something like lein repl in a terminal and then connecting Calva is enough. It sometimes might be, but only if you are in luck. To provide many of its IDE features, Calva relies on nREPL middleware, mainly cider-nrepl and, for ClojureScript, piggieback. When starting your Clojure(Script) app and its REPL, it needs to be started with these dependencies satisfied. There are mainly three ways this can be achieved.

    1. In the project definition (files like project.clj, deps.edn, shadow-cljs.edn, and combination of these).
    2. In your user profile (files like ~/.lein/profiles.clj and ~/.clojure/deps.edn).
    3. On the command line.

    Because 1 and 2 are hard to keep in sync with the various editor environments people in your project might be using, Calva Jack-In is about 3.

    Ideally, you will be able to rid your project files completely of editor dependencies when people working on the project can rely on the Jack-In features of their Clojure editor.

    ","boost":6},{"location":"jack-in-guide/#a-controlled-shell-command","title":"A Controlled Shell Command","text":"

    At its core Calva Jack-In is just a glorified, REPL-starting, command-line. No, it is more than that, but anyway. The command line can look like so for a Leiningen project using legacy Figwheel for its ClojureScript assistance:

    lein update-in :dependencies conj '[nrepl\"0.6.0\"]' -- update-in :dependencies conj '[cider/piggieback\"0.4.1\"]' -- update-in :dependencies conj '[figwheel-sidecar\"0.5.18\"]' -- update-in :plugins conj '[cider/cider-nrepl\"0.22.4\"]' -- update-in '[:repl-options :nrepl-middleware]' conj '[\"cider.nrepl/cider-middleware\"]' -- update-in '[:repl-options :nrepl-middleware]' conj '[\"cider.piggieback/wrap-cljs-repl\"]' -- with-profile +dev repl :headless\n

    Even if a bit long, it might look simple enough. But actually it has taken quite some effort to make Calva craft it. Shell quoting can be really tricky. Look at how '[nrepl\"0.6.0\"]' doesn't have a space between nrepl and the version. That was the only way I could find that was cross platform enough to make all supported shells parse the command line. (The trick relies on that the string is read by the super reliable Clojure Reader, which does not need that space to tokenize it.)

    It is awesome that Clojure is used on so many platforms, but for a tool smith this also means more work. (I think Windows and its shell hell ate up about 95% of the many hours spent on getting the quoting good enough.)

    The command-line crafted is then used to start a shell command that Calva controls, but we are getting ahead of ourselves...

    ","boost":6},{"location":"jack-in-guide/#project-types-builds-aliases-profiles-etcetera","title":"Project Types, Builds, Aliases, Profiles, etcetera","text":"

    In order to cook the right command for your project, Calva looks for project files, reads them, and figures out what possible project types and ClojureScript tools could be involved. Then Calva presents you with a menu with the options it has found. You need to know enough about your project to answer this question. It looks like this in a shadow-cljs project that uses a deps.edn file for setting up its classpath.

    (I know enough about this particular project to know that I should choose the shadow-cljs project type.)

    But Calva isn't ready to cook the command-line just yet. Depending on the project type, and contents of your project files, more info is needed. E.g. in the case of shadow-cljs projects, Calva needs to know what builds to start.

    Here you can select any combination of builds defined in the project, and Calva will cook a command line that starts them.

    You might get more prompts from Calva before it issues the command, but for this example project, Calva goes ahead, cooks the command line, and issues it. On my Mac, it looks like so:

    npx shadow-cljs -d cider/piggieback:0.4.1 -d cider/cider-nrepl:0.22.4 watch :app\n

    (Much shorter than the one with lein-figwheel, right? It is because shadow-cljs is aware of CIDER dependencies, so it doesn't need as many dependencies specified as some other project types do.)

    ","boost":6},{"location":"jack-in-guide/#connecting","title":"Connecting","text":"

    When the command is issued Calva needs to wait until the REPL Server is started, before connecting to it and possibly continuing with starting a ClojureScript REPL and connecting to that as well. It also needs to know which port to connect to.

    Because reasons, Calva can't yet read the stdout of the shell command it has issued, so to know when the REPL server is started, and on which port, Calva monitors the filesystem for the .nrepl-port file. (This file is not always named like that. shadow-cljs, for instance, creates the file .shadow-cljs/nrepl.port.)

    When the port file is created, Calva picks up the port number from it and connects to the nREPL server. At this point you have a Clojure REPL backing your Calva session, providing all sorts of nice IDE help for you.

    ","boost":6},{"location":"jack-in-guide/#starting-your-clojure-app","title":"Starting Your Clojure App","text":"

    Once you have the Clojure REPL connected you can start your Clojure app/server. See Custom Connect Sequences for how to let Calva do this for you automatically. See the same article for ways to automate more of the Jack-In process. It can be brought down to a single Jack-In command/action, even for a full stack Clojure and ClojureScript application.

    ","boost":6},{"location":"jack-in-guide/#clojurescript","title":"ClojureScript","text":"

    For ClojureScript, things are not done yet, though, far from it. It turns out that cooking the command line was the easy part.

    In order for Calva to provide REPL power for ClojureScript projects, several things need to happen:

    1. A Clojure nREPL connection needs to be established. We've covered that above. Calva makes an nREPL session clone to use for the ClojureScript REPL and then:
    2. Your ClojureScript app needs to be compiled.
    3. Your ClojureScript app needs to be started.
    4. The Clojure nREPL session needs to be promoted to a ClojureScript nREPL session. (This is what piggieback helps with.)
    ","boost":6},{"location":"jack-in-guide/#compiling-the-app-and-watchers","title":"Compiling the App and Watchers","text":"

    Depending on ClojureScript project type, Calva uses different methods to start the compilation and the watcher:

    • Figwheel: The compilation and the watchers are started in the Clojure REPL session. (This is both for Figwheel Main and for lein-figwheel.)
    • shadow-cljs: The compilation and the watchers are started with the Jack-In command line.

    This results in a bit of difference in the user interaction. Mainly that for shadow-cljs, the user needs to check the Jack-In Terminal tab to follow what's going on.

    ","boost":6},{"location":"jack-in-guide/#starting-the-app","title":"Starting the App","text":"

    Number 3 above, the app needs to be started, might seem obvious, but it actually trips many people up. Because of this, Calva goes to quite some lengths to provide assistance. Many projects are configured not to spawn a browser session automatically, requesting the app once it has been compiled, so we can't rely on that.

    What Calva does instead is to monitor the output of the commands it uses for starting the compilation, looking for information that the app is ready to be requested/started. It then tells the user this, providing a URL, in case it is a browser app. (There are also settings that tell Calva to open the URL automatically for you, regardless what the project settings are.)

    ","boost":6},{"location":"jack-in-guide/#connecting_1","title":"Connecting","text":"

    Meanwhile, Calva is monitoring the output and when it sees that the app is started, it continues to hook up the REPL connection to the editor.

    This whole connection sequence is quite configurable, using Custom Connect Sequences. In fact, Calva's built in ClojureScript sequences (Figwheel Main, lein-figwheel, shadow-cljs, and ClojureScript built-ins for both Browser and Node) are all built using those same settings mechanisms.

    ","boost":6},{"location":"jack-in-guide/#shadow-cljs-is-less-managed-by-calva","title":"shadow-cljs is Less Managed by Calva","text":"

    NB: The managed way in which Calva creates and connects the ClojureScript REPL breaks apart a bit for shadow-cljs, which works a bit differently and also outputs most of the information Calva is looking for on the stdout of the REPL start command (where Calva can't see it, remember?). We'll figure out a better way to support shadow-cljs, but for now, the user needs to do more of this figuring out than is needed with Figwheel projects.

    ","boost":6},{"location":"jack-in-guide/#hack-away","title":"Hack Away","text":"

    So, there are things going on when you start Jack-In, and even more things for ClojureScript projects, but Calva tries to keep it together, so as a user it is a matter of paying attention and responding to a few prompts/menus with pre-populated options (prompts which can be configured away, even).

    ","boost":6},{"location":"jack-in-guide/#switch-clojurescript-builds","title":"Switch ClojureScript Builds","text":"

    Once the REPL is connected you might want to change which ClojureScript build you have Calva connected to. For this Calva has the Select CLJS Build Connection command. Please note that you can only switch between builds that you have started.

    ","boost":6},{"location":"jack-in-guide/#play-with-starting-the-cljs-repl-yourself","title":"Play With Starting the cljs-repl Yourself","text":"

    To get a good grip on what is going on when creating and connecting the ClojureScript REPL, I can recommend making a custom connect sequence which leaves the REPL unpromoted (e.g. give it nil as connectCode), and then evaluate the cljs-repl start commands yourself. So for instance, promoting it to a ClojureScript Node.js REPL looks something like so:

    user=> (require 'cljs.repl.node)\nuser=> (cider.piggieback/cljs-repl (cljs.repl.node/repl-env))\nClojureScript 1.10.844\nTo quit, type: :cljs/quit\nnil\ncljs.user=> |\n

    It is the piggieback middleware there telling you that you can unpromote the REPL by \u201devaluating\u201d :cljs/quit.

    ","boost":6},{"location":"jack-in-guide/#about-full-stack-applications","title":"About Full Stack Applications","text":"

    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.

    ","boost":6},{"location":"jack-in-guide/#please-grab-your-calva-jack-in-certificate","title":"Please Grab your Calva Jack-In Certificate","text":"

    There, you now know all there is to know about Calva Jack-In.

    Just kidding, there are a few more details to it, some of which might find their way into this article at a later time.

    To really get to know it all, you will need to spend some time with the Calva Jack-In code. Head over to the Calva Development Wiki to learn how to hack on Calva.

    ","boost":6},{"location":"joyride/","title":"Using Calva With Joyride","text":"

    Joyride is a VS Code extension for user space scripting of VS Code itself. You find the extension here. The scripting language for Joyride is the best you language imaginable: Clojure. And, as is proper for a Clojure implementation, it has a REPL, even an nREPL server.

    This means you can connect Calva to Joyride and interactively develop your VS Code scripts.

    This video shows Joyride in action, using Calva as the nREPL client.

    "},{"location":"joyride/#how-to-connect","title":"How to connect","text":"

    Once you have the Joyride extension installed you can start its REPL and connect Calva to it (a.k.a Jack-in).

    Start the Joyride REPL and Connect

    This 1 minute video shows the following steps:

    1. Installing the Joyride Extension
    2. Issuing the command Calva: Start a REPL in your Project and (a.k.a Jack-in)
    3. Selecting joyride project type
    4. Issuing the command Calva: Load/Evaluate Current File and its Requires/Dependencies
    5. Evaluating some non-vscode code
    6. Evaluating code exercising something from the VS Code API

    (Right-click the video and choose Full Screeen if it is too tiny embedded.)

    "},{"location":"joyride/#how-to-get-started-with-joyride","title":"How to Get Started with Joyride","text":"

    The Joyride README has some Quick Start pointers for you. Please feel invited to the #joyride channel on the Clojurians Slack and chat with us and other Joyride users.

    Come on, Join the Joyride! \u2764\ufe0f

    "},{"location":"krell/","title":"Using Calva With Krell","text":"

    Krell is \u00e0 la carte ClojureScript tooling for React Native.

    Even if Calva does not yet have built-in support, all is not lost. You can add support yourself by way of a Custom REPL Connect Sequence. Here's how;

    "},{"location":"krell/#starting-the-krell-clojurescript-repl","title":"Starting the Krell ClojureScript REPL","text":"

    Add this REPL Connect Sequence to your workspace settings.json:

        \"calva.replConnectSequences\": [\n        {\n            \"name\": \"deps.edn + Krell\",\n            \"projectType\": \"deps.edn\",\n            \"cljsType\": {\n                \"connectCode\": \"(require '[clojure.edn :as edn] \\n    '[clojure.java.io :as io]\\n    '[cider.piggieback] \\n    '[krell.api :as krell]\\n    '[krell.repl])\\n\\n(def config (edn/read-string (slurp (io/file \\\"build.edn\\\"))))\\n(apply cider.piggieback/cljs-repl (krell.repl/repl-env) (mapcat identity config))\",\n                \"dependsOn\": \"User provided\"\n            }\n        }\n    ]\n

    Then issue the command Start a Project REPL and Connect (aka Jack-In). It start the project and connect to the Krell REPL once the app is running on a device (wether real or virtual/emulated).

    "},{"location":"krell/#additional-vs-code-tips","title":"Additional VS Code Tips","text":"

    For a smooth workflow you can also:

    • Install the React Native Tools extension
    • Install the Debugger for Chrome extension, and add this Launch Configuration
              {\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:

    1. Open the project root in VS Code
    2. Issue the Jack-in command
    3. Issue the React Native; Run Android on Emulator (or Run iOS on Simulator) command. (Disable Fast Refresh from the *React Native dev menu, if it is enabled.)
    4. Issue the React Native: Run Element Inspector command (You might need to install the React Native inspector globally): ```sh yarn global add react-devtools ````
    5. Launch Debugger (F5)
    6. Hack away, with hot reload and interactive REPL

    Once the debugger (a Chrome session) is running, you probably will want to enable Custom Formatters in order for clojure structures to be logged conveniently.

    "},{"location":"linting/","title":"Linting","text":"

    Calva does no linting, yet with Calva you get excellent linting. That is because Calva uses clojure-lsp, which provides linting powered by clj-kondo.

    clj-kondo comes with great default rules, and the configuration can be customized. One of your options for the configuration file is to placed a config.edn file in .clj-kondo/ at the root of your project. This folder may or may not already exist. It is safe to create it manually if it doesn't.

    The configuration will be merged with the default set of rules, you can only specify the rules you want to override. The full list of available options can be found on clj-kondo's github

    clojure-lsp is customizable, see Clojure LSP Settings for your options. It is safe to manually create the .lsp folder if it doesn't exist.

    You might want to read about how to configure clj-kondo. These two sections might be of extra interest:

    • Unrecognized macros
    • Lint a custom macro like a built-in macro

    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.

    "},{"location":"linting/#resolve-macro-as","title":"Resolve Macro As","text":"

    When your cursor is on a macro form in the editor, you may notice a code action (click the light bulb that appears) called Resolve Macro As. Running this code action will ask you what macro you'd like to resolve the current macro as, and then what clj-kondo config file you want the macro to be saved to. This code action is also available as a command.

    "},{"location":"live-share/","title":"Using Calva with Live Share","text":"

    Live Share is a Microsoft provided VS Code extension. It allows you to share the workspace that you have open in your computer with somebody else. Everybody is then working on the same source code files, namely those on your computer. You can edit files at the same time, everyone has their own caret. You can follow each other (i.e. when someone switches to a different file, you will as well). This is great for remote pair programming, for example.

    An extra nice thing is that each participant is using their own VSCode configuration, including fonts, colors, keyboard shortcuts, etc.

    Disable Calva Spritz to get rid of Notebooks interference

    The headline below Calva Supports Live Share is true. However, due to a bug in LiveShare, guest participants always get their Clojure files opened in the Calva Clojure Notebooks editor. To workaround this issue Calva uses a \u201dside-car\u201d extension named Calva Spritz for the Notebooks associations of Clojure files. You can disable that extension when participating in LiveShare sessions.

    "},{"location":"live-share/#calva-supports-live-share","title":"Calva Supports Live Share","text":"

    When using Calva, you can use Live Share as well. Editing works exactly the same as for any other programming language. What makes Calva a bit special, is the REPL. When using Live Share, Calva allows the host to share the REPL with guests as well. If you use any of the supported configuration, this will be pretty much automatic.

    You need to enable the LiveShare support

    Due to an issue in the LiveShare API, for some users, this feature stops Calva from connecting the REPL. Therefore the support is disabled by default. The setting is calva.useLiveShare.

    This is what a typical scenario looks like:

    1. The host jacks-in.
    2. The host shares its workspace using Live Share. Calva will detect that the workspace is being shared, so it will offer to share the REPL port that was opened when jacking in. The host clicks \"Allow\" to start sharing the port. (Note: steps 1 and two can also be done in the reverse order.)
    3. The host sends the Live Share URL to the guest(s).
    4. The guest joins the Live Share session using the URL it received.
    5. The guest connects to the host's REPL using the command \"Connect to a running REPL server in the project\". If needed, the guest chooses the same build configuration as the host.

    Voila! Both the guest and the host can now use the REPL that is running on the host. Things like documentation lookup now also work on the guest's machine.

    "},{"location":"live-share/#control-visibility-of-calva-folder","title":"Control Visibility of .calva Folder","text":"

    Calva depends on the output.calva-repl file to be available. If you have the .calva folder listed in your .gitignore, this also causes the folder to be hidden from guests in Live Share by default. In order to make the folder visible, you can put a file called .vsls.json in your project. In its simplest form, the contents can be this:

    {\n  \"$schema\": \"http://json.schemastore.org/vsls\",\n  \"hideFiles\": [\n    \"!.calva\"\n  ]\n}\n

    Now the .calva folder is shared as well. But also any other file and folder that you may have in your .gitignore. If you want to have more fine-grained control, please refer to the section Controlling file access and visibility of the Live Share documentation.

    "},{"location":"live-share/#some-things-to-keep-in-mind","title":"Some Things To Keep In Mind","text":"
    • As a guest, you're connected to a REPL running on the host's machine. With power comes responsibility; be nice, and be careful!
    • There is only one output.calva-repl file, which all participants are sharing. It may work better to evaluate things in the source code editors instead of from the REPL window. Otherwise you will end up in a situation where one person is typing something in the output.calva-repl window, and somebody else is evaluating something (hence sending the output there) at the same time. That gets confusing quickly.
    • When you're working on a CLJS-based web development project, things may get extra confusing. By default, Live Share will share any HTTP ports on the host automatically, and also offer to open the URL on the guest. (You can disable using the setting \"Liveshare: Open Shared Servers\".) As a guest, you do not want to open that browser window normally. Think about it: where is the REPL running? Yes: in the browser! But Calva connects to the REPL running in the browser on the host's machine, so if you open a browser as a guest, you will also get a REPL there, but you won't be connected to it in Calva.
    • Currently Live Share does not allow Calva to know whether the workspace is shared read-only or read-write. If you share read-only, and you don't want the guests to have access to your REPL, don't click \"Allow\" when VSCode asks you to share the REPL port.
    "},{"location":"live-share/#calva-spritz","title":"Calva Spritz","text":"

    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 issue: LiveShare participants incorrectly opening every Clojure file as if via \"Open with Notebook\"
    • LiveShare issue: Guest opens Clojure file as a notebook (incorrectly)

    Calva Spritz can be disabled and enabled at will, and it will take immediate effect, without any reload of VS Code needed.

    "},{"location":"luminus/","title":"How to Use Calva with Luminus","text":"

    Luminus is a powerful and versatile Leiningen template for creating web development projects. It comes with built in configuration which makes it easy to use Calva as your Clojure(Script) editor.

    "},{"location":"luminus/#server-shadow-cljs","title":"Server + shadow-cljs","text":"

    Basically this is the same wokflow as with Server only. Behind the scenes there is more happening, though. Such as the ClojureScript app being built and the CLJS REPL connected once the web app is running.

    1. If you haven't created the project yet, create a new shadow-cljs Luminus project. E.g.:
      $ lein new luminus my-luminus-shadow +reagent +re-frame +shadow-cljs\n
    2. Install npm dependencies
      $ npm i\n
      (Or yarn if you prefer.)
    3. This creates the folder my-luminus-shadow. Open it in VS Code:
      $ code my-luminus-shadow\n
    4. Use the Calva command Start a Project REPL and Connect (aka Jack-in): ctrl+alt+c ctrl+alt+j
    5. Select to start my-luminus-shadow Server + Client, and wait for the Terminal Calva Jack-in output to say [:app] Build completed.
    6. Open 127.0.0.1:3000 in your web browser and start hacking.

    Note

    Currently Calva has troubles following the app-start with shadow-cljs, so Calva will report Jack-in done. in the output window before shadow-cljs is actually done building the app. If you open the app page at that stage, you will see a message to \u201cPlease run lein shadow watch app\u201d. Rest assured that this is already underway. Follow the Jack-in process in the Terminal tab in VS Code for the message that the app is built, then reload the app page in the web browser.

    "},{"location":"luminus/#server-only","title":"Server Only","text":"

    The workflow here is really just: Jack-in and start hacking. However, the first time it will involve these steps:

    1. If you haven't created the project yet, create a new server only Luminus project. For a all-defaults setup it is like so:
      $ lein new luminus my-luminus-server\n
    2. This creates the folder my-luminus-server. Open it in VS Code:
      $ code my-luminus-server\n
    3. Use the Calva command Start a Project REPL and Connect (aka Jack-in): ctrl+alt+c ctrl+alt+j
      • Select to start my-luminus-shadow Server and wait until you see Jack-in done. in the output window.
    4. Open 127.0.0.1:3000 in your web browser and start hacking.
    "},{"location":"luminus/#server-figwheel","title":"Server + Figwheel","text":"

    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:

    1. If you haven't created the project yet, create a new server only Luminus project. E.g.:
      $ lein new luminus my-fw +reagent\n
    2. This creates the folder my-fw. Open it in VS Code:
      $ code my-fw\n
    3. Use the Calva command Start a Project REPL and Connect (aka Jack-in): ctrl+alt+c ctrl+alt+j, select Server + Client - my-fw in the Project type picker menu, and wait for the web app to pop open in your web browser.
    4. Start hacking.

    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.

    "},{"location":"luminus/#etcetera","title":"Etcetera","text":"

    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:

    1. Start <project> Server
    2. Stop <project> Server
    3. Restart <project> Server

    When used, Calva will open its REPL window and execute the command, if it is not already opened. You can close this window if you prefer to use the REPL directly from the Clojure files.

    Calva also opens the REPL window, and starts the Luminus server, as part of the Jack-in process.

    "},{"location":"merch/","title":"Calva Merch","text":"

    In this video, there is a question about where you can buy the Calva T-shirt:

    You couldn't, then. But now you can! On Amazon.

    Zero profit

    To keep the admin of this shop to a minimum the merch is sold at production prize (or as close to production prize as the respective store allows). There is no royalty going to anyone in the Calva team when you buy one of these t-shirts. You will represent, which is certainly a way to support the project. You are of course encouraged to support us via sponsoring as well:

    • Sponsor Peter Str\u00f6mberg
    • Sponsor Brandon Ringe

    Calva Merch is available on Zazzle and on Amazon

    ","boost":10},{"location":"merch/#zazzle","title":"Zazzle","text":"","boost":10},{"location":"merch/#calva-symbol-sticker","title":"Calva Symbol Sticker","text":"Calva Symbol Sticker by BetterThanTomorrow","boost":10},{"location":"merch/#joyride-symbol-sticker","title":"Joyride Symbol Sticker","text":"Joyride Symbol Sticker by BetterThanTomorrow","boost":10},{"location":"merch/#amazon-merch","title":"Amazon Merch","text":"","boost":10},{"location":"merch/#the-designs","title":"The designs","text":"

    There are four design, all featuring the Calva symbol (the Calva glass), which are all available for a Standard T-shirt, in men's, women's and kid's cut, and in some different colors. In the .com store there are also Premium T-shirts**.

    ","boost":10},{"location":"merch/#symbol-logo","title":"Symbol + Logo","text":"

    Available at:

    • https://www.amazon.com/dp/B09BCVH9SC (Premium T-shirt)
    • https://www.amazon.com/dp/B097TB5QFW
    • https://www.amazon.de/dp/B098GWQC6M
    • https://www.amazon.co.uk/dp/B098KM9XMF
    • https://www.amazon.fr/dp/B0994TYXTN
    • https://www.amazon.it/dp/B099KLJJV1
    • https://www.amazon.es/dp/B099NXR71Y
    • https://www.amazon.co.jp/dp/B097YZVMC4
    ","boost":10},{"location":"merch/#symbol-logo-we-do-it-with-rich-comments","title":"Symbol + Logo + We do it with Rich Comments","text":"

    The Calva symbol and Logo front, Rich Comments back.

    Available at:

    • https://www.amazon.com/dp/B09C4PBH5N (Premium T-shirt)
    • https://www.amazon.com/dp/B09BFMRCHL
    • https://www.amazon.de/dp/B09C3VYZH8
    • https://www.amazon.co.uk/dp/B09BLD2BVJ
    • https://www.amazon.fr/dp/B09C3X1H7K
    • https://www.amazon.it/dp/B09C3WV2JQ
    • https://www.amazon.es/dp/B09C4P1GD1
    • https://www.amazon.co.jp/dp/B09C4P45MR
    ","boost":10},{"location":"merch/#symbol-only","title":"Symbol Only","text":"

    Available at:

    • https://www.amazon.com/dp/B09B83481D (Premium T-shirt)
    • https://www.amazon.com/dp/B097TB5QFW
    • https://www.amazon.de/dp/B098434W9M
    • https://www.amazon.co.uk/dp/B098KNGPBB
    • https://www.amazon.fr/dp/B099RZGNN7
    • https://www.amazon.it/dp/B099WYH94Z
    • https://www.amazon.es/dp/B09B2TFCSR
    • https://www.amazon.co.jp/dp/B09B4XN3HY
    ","boost":10},{"location":"merch/#symbol-we-do-it-with-rich-comments","title":"Symbol + We do it with Rich Comments","text":"

    The Calva symbol front, Rich Comments Back.

    Available at:

    • https://www.amazon.com/dp/B098M34FKJ (Premium T-shirt)
    • https://www.amazon.com/dp/B0993VCG7P
    • https://www.amazon.de/dp/B098MF14PV
    • https://www.amazon.co.uk/dp/B098P1MV44
    • https://www.amazon.fr/dp/B098TPQFCJ
    • https://www.amazon.it/dp/B098YP33ZL
    • https://www.amazon.es/dp/B098RDPK55
    • https://www.amazon.co.jp/dp/B0992MQYG6

    Note

    What's available on this or that Amazon site will vary a bit and it is a bit slow to add a particular design to a particular market. Eventually I hope to have both designs up on these markets: .com, .co.uk, .de, .fr, .it, .es, and .co.jp

    ","boost":10},{"location":"namespace-form-auto-creation/","title":"Namespace Form Auto-creation","text":"

    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.

    "},{"location":"nbb/","title":"Using Calva with nbb","text":"

    Since nbb can be started such that it is an nREPL server, Calva can connect to it and a lot of the features will work.

    Calva can also start nbb and connect its REPL for you, using the Jack-in command. This will start an nbb nREPL server on a random port and connect Calva to it. Check out this video where they use Calva and nbb to create a CLI tool as an executable npm module:

    In that video they ask for a JavaScript to ClojureScript converter. And there is one: https://mauricioszabo.gitlab.io/js2cljs/

    Though if you are using Calva, this converter is easier to use directly via the command Calva: Convert JavaScript to ClojureScript:

    Errors jacking in to nbb on Windows?

    On some machines it seems necessary to first run npx nbb from the CMD prompt to make jack-in work. Or try first install it npm i -g nbb. (You probabl want nbb installed globally anyway.)

    Don't expect complete support

    nbb's nREPL server is completely new and and WIP. It will be a bit limited compared to a full cider-nrepl enhanced \"regular\" Clojure nREPL server. Things like function signatures, and more do not work.

    It's a bit hacky

    The nbb nREPL server is the first ClojureScript nREPL server around and throws Calva's assumption that an nREPL server is always started in a Clojure process out the window. The nbb Jack-in/connect option \u201dpretends\u201d it is connecting to a Clojure nREPL and then the code fro promoting the nREPL session to a ClojureScript one is just dummy code.

    This means that if you open a Clojure (.clj) file while connected to an nbb nREPL server, it will still be a ClojureScript session serving even though Calva will indicate that it is a Clojure one. Bare with us until we can fix this properly in Calva.

    ","boost":4},{"location":"notebooks/","title":"Clojure Notebooks","text":"

    WIP: Notebook support is very basic and experimental

    • You might experience loss of file contents when saving a Clojure Notebook. Have backups of any files you open as notebooks.
    • Tooling around autocomplete, go to def, linting and such does not work at all yet.
    • There is no Markdown support.
    • Etcetera. As if this was not enough, notebooks can also interfere with LiveShare support.

    Please help test the feature. We're looking forward to your feedback!

    You can open any Clojure file as a notebook by right clicking the file -> Open with... -> Clojure Notebook.

    Running cells sends them to the REPL and pretty prints the results. If the return is a string that starts with <html it will be displayed in an html webview.

    Forms inside (comment) blocks get shown as their own cells. When adding code blocks in between those cells they get saved with the same indentation as the first form.

    ","boost":1},{"location":"notebooks/#calva-spritz","title":"Calva Spritz","text":"

    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:

    • Calva issue: LiveShare participants incorrectly opening every Clojure file as if via \"Open with Notebook\"
    • LiveShare issue: Guest opens Clojure file as a notebook (incorrectly)
    ","boost":1},{"location":"nrepl_and_cider-nrepl/","title":"nREPL and cider-nrepl","text":"

    nREPL and cider-nrepl middleware enable Calva to support full Interactive Programming.

    ","boost":2},{"location":"nrepl_and_cider-nrepl/#about-nrepl","title":"About nREPL","text":"

    The REPL is a Clojurists quintessential tool, it\u2019s what we use to do Interactive Development, the hallmark of the LISP style of development.

    In Interactive Development (more commonly but somewhat imprecisely referred to as REPL-driven development), the programmer\u2019s editor has a direct connection with the running application process. This allows evaluating pieces of code in the context of a running program, directly from where the code is written (and so not in some separate \u201cREPL place\u201d), inspecting and manipulating the innards of the process. This is helped along by the dynamic nature of Clojure in which any var can be redefined at any point, allowing for quick incremental and iterative experimentation and development.

    This is why it\u2019s essential to the Clojure development experience to have proper editor support, a plugin which bridges the gap between where the code is written and where the code is run. So we have CIDER for Emacs, Calva for VS Code, Cursive for IntelliJ, Conjure or Iced for Vim, and so forth. Often these will also leverage the same (or a parallel) connection into the process for other editor affordances, like navigation and completion.

    But for these editor plugins to connect to the Clojure process something needs to be listening on the other side, accepting connections, allowing the initiation of a program-to-program dialogue. The most common way to achieve this is by leveraging the nREPL protocol, an asynchronous message-based network protocol for driving interactive development. The application process is started with an embedded nREPL server, so that the editor can connect as an nREPL client.

    From: Lambda Island

    ","boost":2},{"location":"nrepl_and_cider-nrepl/#about-the-nrepl-server-and-middleware","title":"About the nREPL Server and Middleware","text":"

    nREPL is an extensible protocol, the reference server implementation understands certain core operation types like \"eval\". More operations can be supported, or existing operations can be modified or augmented, through nREPL middleware. For example: the Piggieback middleware can intercept \"eval\" messages, and forward them to a ClojureScript environment, rather than evaluating them in the Clojure process itself.

    Which middleware to use will mostly depend on the editor you are using. You\u2019ll typically find that the Clojure-specific functionality for a given editor is partly implemented as a typical editor extension, for instance CIDER written in Emacs LISP, or Calva written in Typescript, and partly as nREPL middleware, providing the functionality the editor extension relies on. For instance, both CIDER and Calva rely on functionality provided by cider-nrepl.

    Also from: Lambda Island

    ","boost":2},{"location":"nrepl_and_cider-nrepl/#viewing-the-communication-between-calva-and-nrepl","title":"Viewing the Communication Between Calva and nREPL","text":"

    You can view the messages sent between Calva and nREPL by running the command Toggle nREPL Logging Enabled. Enabling nREPL message logging triggers the creation of a VS Code output channel called nREPL Messages where the messages will be logged. Messages sent to nREPL from Calva will have -> sent above them, and messages sent from nREPL to Calva will have <- received above them. Disabling nREPL message logging causes the nREPL Messages channel to be removed and messages will no longer be logged.

    Each message is logged as JSON. If you find a need for the messages to be logged as EDN (for example, to transform and analyze them with Clojure) please open a GitHub issue for this change. A PR would be welcome too!

    The example below shows two messages logged when the cursor hovers over println in a Clojure file while a REPL is connected.

    -> sent\n{\n  op: 'info',\n  ns: 'test-lein.core',\n  symbol: 'println',\n  id: '7',\n  session: '1a080b66-b1b6-4b8c-8206-c4af2cc02747'\n}\n\n<- received\n{\n  added: '1.0',\n  'arglists-str': '[& more]',\n  column: 1,\n  doc: 'Same as print followed by (newline)',\n  file: 'jar:file:/Users/brandon/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar!/clojure/core.clj',\n  id: '7',\n  line: 3733,\n  name: 'println',\n  ns: 'clojure.core',\n  resource: 'clojure/core.clj',\n  'see-also': [\n    'clojure.core/prn',\n    'clojure.core/print',\n    'clojure.core/println-str',\n    'clojure.pprint/pprint'\n  ],\n  session: '1a080b66-b1b6-4b8c-8206-c4af2cc02747',\n  static: 'true',\n  status: [ 'done' ]\n}\n
    ","boost":2},{"location":"output/","title":"Output Destinations","text":"

    Calva categorizes output into three types:

    • evaluation results: Clojure data returned from an evaluation.
    • evaluation output: stdout/stderr from an evaluation
    • other output: Other messages, logs, etc

    With the setting calva.outputDestinations, you can configure where each category of output should go to:

    • the REPL Window
    • the Calva Says Output Channel
    • the Calva Output (pseudo) Terminal

    The reason there are several options for this is partly legacy and partly because VS Code restricts the placement of different views in different ways. We hope you will find a combination of output destinations that suits you.

    "},{"location":"output/#commands-for-showing-output-destinations","title":"Commands for showing output destinations","text":"

    These are the commands and their default keyboard shortcuts for revealing output destinations

    • Calva: Show/Open the result output destination - ctrl+alt+o o
    • Calva: Show/Open the Calva says Output Channel - ctrl+alt+o c
    • Calva: Show/Open the Calva Output Terminal - ctrl+alt+o t
    • Calva: Show/Open REPL Window - ctrl+alt+o r
    "},{"location":"output/#about-stdout-in-the-repl-window","title":"About stdout in the REPL Window","text":"

    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.

    "},{"location":"output/#repl-process-output-stdout-and-stderr","title":"REPL process output (stdout and stderr)","text":"

    When Calva is connected to the REPL, the Output window will by default print not only results of evaluations, but also:

    1. Things printed to stdout and stderr in the main thread of the evaluations
    2. Things printed to stdout and stderr from child threads of the evaluations
    3. Anything printed to stdout and stderr by the REPL process

    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).

    "},{"location":"output/#see-also","title":"See also","text":"
    • The Calva Results Inspector
    • The REPL Window
    "},{"location":"paredit/","title":"Paredit \u2013 a Visual Guide","text":"

    Structural editing and navigation for Clojure.

    ","boost":7},{"location":"paredit/#what-is-paredit","title":"What is Paredit?","text":"

    Calva Paredit helps you navigate, select and edit Clojure code in a structural way. LISP isn't line or character oriented, it is based around S-expressions, a.k.a forms. We strongly recommend that you take advantage of the structural nature of Clojure, and have therefore put a lot of work into making Calva Paredit extra awesome.

    If you are new to Paredit, consider starting with learning the Slurp Forward (pull in the next form into this form) and Barf Forward (push the last form out of this form). It will take you quite far.

    ","boost":7},{"location":"paredit/#strict-mode","title":"Strict Mode","text":"

    To protect the integrity of your code, Strict mode is enabled by default.

    Strict mode keybinding Action Description backspace Delete Backward Deletes one character backwards, unless it will unbalance a form. Otherwise moves past the character instead of deleting it. If the list is empty, it will remove both open and close brackets. delete Delete Forward Deletes one character forwards, unless it will unbalance a form. Otherwise moves past the character instead of deleting it. If the list is empty, it is removed. alt+backspace Force Delete Backward Deletes one character backwards, even if it will unbalance a form. alt+delete Force Delete Forward Deletes one character forwards, even if it will unbalance a form.

    Disable at your own peril. Strict mode can be toggled on/off using the Toggle Paredit Mode command, and there is a status bar indicator telling you:

    Indicator Paredit Mode [\u03bb] Strict (\u03bb) Cave Man (strict mode off) \u03bb No default key bindings

    Toggle between Strict and Cave Man using: ctrl+alt+p ctrl+alt+m

    ","boost":7},{"location":"paredit/#a-keybinding-for-protecting-the-structure-from-semi-colon","title":"A keybinding for protecting the structure from semi-colon","text":"

    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 together with the other Strict mode commands:

    {\n    \"command\": \"paredit.insertSemiColon\",\n    \"key\": \";\",\n    \"when\": \"calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap == strict && !editorReadOnly && !editorHasMultipleSelections && !calva:cursorInComment\"\n },\n
    ","boost":7},{"location":"paredit/#commands","title":"Commands","text":"

    The Paredit commands are sorted into Navigation, Selection, and Edit. As mentioned, Slurp and Barf are power commands, which go into the editing category. Learning to navigate structurally, using shortcuts, also saves time and adds precision to your editing. It has the double effect that you at the same time learn how to select structurally, because that is the same, just adding the shift key.

    To make the command descriptions a bit clearer, each entry is animated. When you try to figure out what is going on in the GIFs, focus on where the cursor is at the start of the animation loop.

    ","boost":7},{"location":"paredit/#command-args","title":"Command Args","text":"

    Some Paredit commands accept arguments. You can utilize this in keybindings and from Joyride.

    ","boost":7},{"location":"paredit/#copy-for-all-kill-commands","title":"copy for all kill* commands","text":"

    When specified, will control whether killed text will be copied to the clipboard. This is an alternative to, or supports binding-specific overrides for, calva.paredit.killAlsoCutsToClipboard.

    For example, here's 2 keybindings for paredit.killRight with different copy args, allowing you to choose when or if you want killed text copied at keypress-time, regardless of global calva.paredit.killAlsoCutsToClipboard setting:

    {\n  \"key\": \"ctrl+k\",\n  \"command\": \"paredit.killRight\",\n  \"when\": \"... your when conditions ...\",\n  \"args\": {\"copy\": false}\n},\n{\n  \"key\": \"cmd+k ctrl+k\",\n  \"command\": \"paredit.killRight\",\n  \"when\": \"... your when conditions ...\",\n  \"args\": {\"copy\": true}\n},\n

    Or, you can even have both of them use the same key, but separate when conditions to taste, to allow context-conditional copying.

    ","boost":7},{"location":"paredit/#strings-are-not-lists-but-anyway","title":"Strings are not Lists, but Anyway...","text":"

    In Calva Paredit, strings are treated in much the same way as lists are. Here's an example showing Slurp and Barf, Forward/Backward List, and Expand Selection.

    ","boost":7},{"location":"paredit/#navigating","title":"Navigating","text":"

    (Modify these with shift to select rather than move, see below.)

    Default keybinding Action Description ctrl+right (win/linux)alt+right (mac) Forward Sexp Moves the cursor forward, to the end of the current form. If at the end, moves to the end of the next form. Will not move out of lists. ctrl+left (win/linux)alt+left (mac) Backward Sexp Moves the cursor backward, to the start of the current form. If at the start, moves to the start of the previous form. Will not move out of lists. ctrl+down Forward Down Sexp Moves the cursor into the following list. ctrl+alt+up Backward Down Sexp Moves the cursor into the preceding list. ctrl+alt+down Forward Up Sexp Moves the cursor forwards, out of the current list. ctrl+up Backward Up Sexp Moves the cursor backwards, out of the current list. Unbound Forward Sexp Or Up Moves the cursor forward, to the end of the current form. If at the end, moves to the end of the next form. Moves out of the lists if at the end of it. Unbound Backward Sexp Or Up Moves the cursor backward, to the start of the current form. If at the start, moves to the start of the previous form. Moves out of the list if at the start of it. ctrl+end Forward to List End/Close Moves the cursor forwards, staying within the current list. ctrl+home Backward to List Start/Open Moves the cursor backwards, staying within the current list.","boost":7},{"location":"paredit/#selecting","title":"Selecting","text":"

    Most of these commands are selecting \u201dversions\u201d of the navigation commands above. Repeated use will grow the current selection step by step.

    Default keybinding Action Description shift+alt+right (win/linux)ctrl+w (mac) Expand Selection Starts from the cursor and selects the current form. Then will keep expanding to enclosing forms. shift+alt+left (win/linux)ctrl+shift+w (mac) Shrink Selection Contracts back from an expanded selection performed by any Paredit selection command. (In the animation the selection is first grown using a combination of Expand Selection and some lateral selection commands, then shrunk all the way back down to no selection.) ctrl+alt+w space Select Top Level Form Top level in a structural sense. Typically where your(def ...)/(defn ...) type forms. Please note that(comment ...) forms create a new top level. shift+ctrl+right (win/linux)shift+alt+right (mac) Select Forward Sexp ctrl+shift+k Select Right Select forward to the end of the current form or the first newline. See Kill right below. (The animation also shows Shrink Selection). shift+ctrl+left (win/linux)shift+alt+left(mac) Select Backward Sexp ctrl+shift+down Select Forward Down Sexp (You probably do not need to select like this, but you can!) ctrl+shift+alt+up Select Backward Down Sexp (You probably do not need to select like this, but you can!) ctrl+shift+alt+down Select Forward Up Sexp (You probably do not need to select like this, but you can!) ctrl+shift+up Select Backward Up Sexp (You probably do not need to select like this, but you can!) Unbound Select Forward Sexp Or Up (You probably do not need to select like this, but you can!) Unbound Select Backward Sexp Or Up (You probably do not need to select like this, but you can!) ctrl+shift+end Select Forward to List End/Close ctrl+shift+home Select Backward to List Start/Open","boost":7},{"location":"paredit/#editing","title":"Editing","text":"Default keybinding Action Description ctrl+alt+right (mac/win)ctrl+alt+. (linux) Slurp Forward Moves the closing bracket forward, away from the cursor, past the following form, if any. ctrl+alt+left (mac/win)ctrl+alt+, (linux) Barf Forward Moves the closing bracket backward, towards the cursor, past the preceding form. ctrl+alt+shift+left Slurp Backward Moves the opening bracket backward, away from the cursor, past the preceding form, if any. ctrl+alt+shift+right Barf Backward Moves the opening bracket forward, towards the cursor, past the following form. ctrl+alt+s Splice Sexp Remove enclosing brackets. ctrl+shift+s Split Sexp Splits a string, or a list, into two strings, or lists of the same type as the current. ctrl+shift+j Join Sexps/Forms Joins two strings, or two lists of the same type, into one form (string/list). ctrl+alt+p ctrl+alt+r Raise Sexp Replaces the enclosing list with the current form. ctrl+alt+t Transpose Sexps/Forms Swaps place of the two forms surrounding the cursor. alt+upalt+down Drag Sexp Backward/Forward Moves the current form to the behind/in front of the previous/next one. (See below about behavior in maps and binding boxes.) ctrl+alt+shift uctrl+alt+shift d Drag Sexp Backward UpDrag Sexp Forward Down Moves the current form up/out of the current list, backwards, and down/in to the following list, forwards, keeping the cursor within the sexpr being dragged. ctrl+alt+shift kctrl+alt+shift j Drag Sexp Forward UpDrag Sexp Backward Down Moves the current form up/out of the current list, forwards, and down/in to the preceding list, backwards, keeping the cursor within the sexpr being dragged. ctrl+shift+c Convolute \u00af\\_(\u30c4)_/\u00af ctrl+shift+delete Kill Sexp Forward Deletes the next form in the same enclosing form as the cursor. ctrl+k ctrl+k (win/linux)ctrl+k (mac) Kill Right Delete forward to the end of the current form or the first newline. ctrl+k ctrl+h (win/linux)cmd+backspace (mac) Kill Left Delete backward to the start of the current form or the start of the line. ctrl+alt+backspace Kill Sexp Backward Deletes the previous form in the same enclosing form as the cursor. ctrl+delete Kill List Forward Deletes everything from the cursor to the closing of the current enclosing form. ctrl+backspace Kill List Backward Deletes everything from the cursor to the opening of the current enclosing form. ctrl+alt+shift+delete Splice Killing Forward Delete forward to end of the list, then Splice. ctrl+alt+shift+backspace Splice Killing Backwards Delete backward to the start of the list, then Splice. ctrl+alt+shift+p Wrap Around () Wraps the current form, or selection, with parens. ctrl+alt+shift+s Wrap Around [] Wraps the current form, or selection, with square brackets. ctrl+alt+shift+c Wrap Around {} Wraps the current form, or selection, with curlies. ctrl+alt+shift+q Wrap Around \"\" Wraps the current form, or selection, with double quotes. Inside strings it will quote the quotes. ctrl+alt+rctrl+alt+p/s/c/q/h Rewrap Changes enclosing brackets of the current form to parens/square brackets/curlies/double quotes and set (#{})

    Copy to Clipboard when killing text

    You can have the kill commands always copy the deleted code to the clipboard by setting calva.paredit.killAlsoCutsToClipboard to true. If you want to do this more on-demand, you can kill text by using the selection commands and then Cut once you have the selection.

    clojure-lsp drag fwd/back overlap

    As an experimental feature, the two commands for dragging forms forward and backward have clojure-lsp alternatives. See the clojure-lsp page.

    ","boost":7},{"location":"paredit/#drag-bindings-forwardbackward","title":"Drag bindings forward/backward","text":"

    When dragging forms inside maps and binding boxes, such as with let, for, binding, etcetera, it often makes most sense to drag each binding as a pair. And this is what Calva will do. Like so:

    And like so (wait for it):

    ","boost":7},{"location":"paredit/#about-the-keyboard-shortcuts","title":"About the Keyboard Shortcuts","text":"

    Care has been put in to making the default keybindings somewhat logical, easy to use, and work with most keyboard layouts. Slurp and barf forward are extra accessible to go with the recommendation to learn using these two super handy editing commands.

    You can relax how Paredit's shortcuts replace VS Code built in shortcuts a bit by setting calva.paredit.hijackVSCodeDefaults to false.

    There are some context keys you can utilize to configure keyboard shortcuts with precision. See Customizing Keyboard Shortcuts.

    The Nuclear Option: You can choose to disable all default key bindings by configuring calva.paredit.defaultKeyMap to none. (Then you probably also want to register your own shortcuts for the commands you often use.)

    ","boost":7},{"location":"paredit/#when-clauses-and-vscode-default-bindings","title":"When Clauses and VSCode Default Bindings","text":"

    There are instances where VSCode's built-in command binding defaults are the same as Paredit's, where Paredit's version has less functionality. For example, Calva's Expand Selection and Shrink Selection doesn't support multiple selections (though this may change in the future - see Multicursor section below). In this particular case, adding !editorHasMultipleSelections to the when clause of the binding makes up for this gap by letting the binding fall back to VSCode's native grow/shrink selection.

    For example, here's the JSON version of the keybindings settings demonstrating the above. Note this can also specified in the Keyboard Shortcuts UI:

    {\n  \"key\": \"shift+alt+right\",\n  \"command\": \"paredit.sexpRangeExpansion\",\n  \"when\": \"calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap =~ /original|strict/ && !calva:cursorInComment\"\n}\n

    to

    {\n  \"key\": \"shift+alt+right\",\n  \"command\": \"paredit.sexpRangeExpansion\",\n  \"when\": \"!editorHasMultipleSelections && calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap =~ /original|strict/ && !calva:cursorInComment\"\n}\n

    The point is that when the bindings overlap and default functionality is desired peaceful integration can be achieved with the right when clause. This is left out of Paredit's defaults to respect user preference, and ease of maintenance.

    Happy Editing! \u2764\ufe0f

    ","boost":7},{"location":"paredit/#experimental-feature-multicursor-support","title":"Experimental Feature: Multicursor support","text":"

    There is an ongoing effort to support simultaneous multicursor editing with Paredit. This is an experimental feature and is not enabled by default. To enable it, set calva.paredit.multicursor to true. This feature is still in development and may not work as expected in all cases. Currently, this supports the following categories:

    • Movement
    • Selection (except for Select Current Form - coming soon!)
    • Rewrap
    ","boost":7},{"location":"paredit/#toggling-multicursor-per-command","title":"Toggling Multicursor per command","text":"

    The experimental multicursor-supported commands support an optional command arg - like copy for the kill* commands mentioned above - to control whether multicursor is enabled for that command. This is an alternative to, or supports binding-specific overrides for, calva.paredit.multicursor.

    For example:

    {\n  \"key\": \"ctrl+k\",\n  \"command\": \"paredit.sexpRangeExpansion\",\n  \"when\": \"... your when conditions ...\",\n  \"args\": {\"multicursor\": false}\n}\n
    ","boost":7},{"location":"parinfer/","title":"Calva Parinfer Mode is Reverted","text":"

    Reverted in Calva v2.0.228

    The changes in v2.0.227 seemed to cause problems for some users. Unclear yet if and why. But to not risk causing problems for more users these changes where reverted and Calva v2.0.228 does not contain them. Please consider using v2.0.227 and help find what the problems are about! Please note: Even in v2.0.227 this feature is currently disabled by default.

    Parinfer is a system for editing the structure of LISP text without explicit commands. The structure can be regarded as already being expressed through indentation. With Parinfer you can use your intuition about the structure inferred from the indentation to perform surprisingly many structural edits.

    "},{"location":"parinfer/#quirks","title":"Quirks","text":"

    There are some known quirks, of varying severity, with this feature. Some of them will need to be fixed before we move this feature out of Experimental status.

    For the most times you can always Undo to get back to where the document was fine. You just need to pay some attention and be aware when undo is needed.

    "},{"location":"parinfer/#no-multi-cursor-support","title":"No multi-cursor support","text":"

    The bracket inference will remove all cursors but the first one. So for instance if you edit with multiple cursors and it causes brackets to move, you'll end up with just one cursor and the subsequent edits will not be what you intended. This is particularly important to note when you have cursors that are not in the viewport. In such cases it might be better to turn Parinfer off while you do the edits, fix formatting and such manually and then switch Parinfer on again.

    "},{"location":"parinfer/#wrong-inferences","title":"Wrong inferences","text":"

    For yet unknown reasons an edit such as the following does the wrong thing (the cursor indicated by the vertical bar):

    (foo| (bar)\n      (baz))\n

    backspace =>

    (fo| (bar\n      (baz)))\n

    That is (baz) is slurped. When what should happen is:

    (fo| (bar)\n     (baz))\n
    "},{"location":"parinfer/#lag-causing-errors-when-fast-typing","title":"Lag causing errors when fast typing","text":"

    The way that Calva Parinfer works is that for any edit of the document it first reformats the code around the cursor, then infer brackets. Currently these two steps are not atomic to VS Code, so if you type fast bracket inference might happen on the yet unformatted code, and thus not be correct. You might also see the cursor end up at the wrong position at times.

    "},{"location":"parinfer/#infer-parens","title":"Infer Parens","text":"

    This is no longer available in Calva

    See above about how to try this build anyway, warts and all.

    When you enable Calva's Parinfer it is all about infering brackets from indentation. There are no further Parinfer modes. Calva's auto-formatter will take care of keeping the code correctly indented.

    Enable it with from this setting: calva.fmt.experimental.inferParensAsYouType or from the status bar item.

    "},{"location":"parinfer/#parinfer-status-bar-items","title":"Parinfer Status bar items","text":"

    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.

    1. Parinfer ON/OFF indicator/button. \u2022() (The dot/circle indicates ON/OFF)
    2. Structure and indentation health indicator. \u2714\ufe0f/\u26a0/\u2298

    When Parinfer is ON, the health indicator will have three states:

    1. \u2714\ufe0f Healthy - meaning both structure and indentation is OK
    2. \u2298 Structure broken - you need to fix the the structure of the code
    3. \u26a0 Bad indentation - meaning that to Parinfer the structure and indentation do not match, _the item is now also a button with which you can fix the indentation.

    Parinfer will be disabled in both the unhealthy states.

    When Parinfer is OFF, only the first two states above are used.

    "},{"location":"parinfer/#some-vs-code-settings-automatically-changed","title":"Some VS Code Settings automatically changed","text":"

    In order for some automatic VS Code behaviour not to interfere with Parinfer the following settings are automatically configured when you toggle Parinfer ON:

        \"[clojure]\": {\n        \"editor.autoClosingBrackets\": \"never\",\n        \"editor.autoClosingOvertype\": \"never\",\n        \"editor.formatOnPaste\": false\n    },\n

    And when you toggle Parinfer OFF:

        \"[clojure]\": {\n        \"editor.autoClosingBrackets\": \"always\",\n        \"editor.autoClosingOvertype\": \"always\",\n        \"editor.formatOnPaste\": true\n    },\n

    It is recommended that you let Calva handle these settings to avoid weird behaviour.

    "},{"location":"parinfer/#no-tab-indenting","title":"No Tab indenting","text":"

    As the tab key is used for formatting the current form in Calva, it is \u201dtaken\u201d. The closest equivalents you have are space and backspace. At least for now. We'll see if we can find out a good way for supporting tab and shift+tab for indent and dedent.

    tab for formatting is of course just a default key binding and you can assign it to something else to get it to do indenting. However, it will not be a very smart indent anyway, there is no Clojure awareness about it. You are hereby adviced to instead use some more spaces.

    "},{"location":"parinfer/#paredit-is-still-there","title":"Paredit is still there","text":"

    In Calva, Parinfer and Paredit are designed to coexist and both be there to let you edit the structure easily and efficiently. Since Paredit commands are always formatted, they leave the code in a state where Parinfer has what it needs to infer bracket placement as you either edit the indentation, or remove/add brackets.

    "},{"location":"parinfer/#disable-the-parinfer-extension","title":"Disable the Parinfer Extension","text":"

    If you want to have Parinfer you are probably best served by Calva's built-in version. It is designed, and will continue to be improved to function well together with Calva's other structural editing and formatting features. It will also probably conflict with the Parinfer Extension.

    "},{"location":"parinfer/#see-also","title":"See also","text":"
    • Paredit
    • Formatting
    "},{"location":"polylith/","title":"How to Use Calva with Polylith","text":"

    Polylith is an architecture for backend projects that maximizes development ergonomics and code reuse.

    When developing a Polylith application you use one REPL for everything. And as such it is a rather vanilla deps.edn project, so there is really not much more to using Calva with Polylith than:

    1. Jack in, selecting the deps.edn project type
    2. Select aliases, most often :dev and :test
    3. Hack away!
    "},{"location":"polylith/#the-realworld-example","title":"The RealWorld Example","text":"

    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:

    1. Fork the project and open it in VS Code
    2. Jack-in, selecting the Polylith RealWorld Server REPL project type
    3. Wait for the REPL prompt to read clj\ua789dev.server\ua789>
    4. Evaluate (start! 6003)
    5. Hack away!
    "},{"location":"polylith/#try-it-with-a-frontend","title":"Try it with a Frontend","text":"

    A ClojureScript frontend, of course:

    1. Fork the jacekschae/conduit project and open it in VS Code
    2. Edit the api-url definition in events.cljs file to be
      (def api-url \"http://localhost:6003/api\")\n
    3. Jack-in, selecting to start and connect to the :app build
    4. Wait for it to compile and then open http://localhost:3000
    5. Hack away!
    "},{"location":"pprint/","title":"Pretty Printing","text":"

    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.

    "},{"location":"pprint/#toggle-it","title":"Toggle it","text":"

    There is a pprint indicator to the right in the status bar which shows the status of the mode. Click the indicator to toggle prettification on and off. There is also a Calva: Toggle Pretty Printing for All Evaluations command.

    Tip: If you have evaluated something time consuming, or that is not idempotent, with pretty printing mistakenly off: toggle it on and evaluate *1.

    "},{"location":"pprint/#configuration","title":"Configuration","text":"

    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:

    Setting Type Effect enabled boolean So this is a third way you can change this mode \ud83d\ude04 printEngine enum Which printer function that will be used. Default is pprint, more about this setting below printFn object You can configure Calva to use a custom nREPL compatible print function, more below. width number The maximum line length of printed output (or at least the printers will try) maxLength number The maximum number of elements printed in nested nodes, good for evaluating something like (iterate inc 0), which you shouldn't do without setting maxLength. Most printers will indicate truncated lists with ... at the end. maxDepth number The maximum number of levels deep that will get printed. Different printers mark a stop different ways. puget doesn't support it at all.

    See Customizing Calva for some tips on adding settings like these.

    Here's an example of how zprint handles maxDepth (from the Calva implementation of it's client side pretty printing.).

      (pretty-print [[[[[[[[:deeper]]]]]]]] {:max-depth 4})\n  ;; => {:value \"[[[[##]]]]\"}\n
    "},{"location":"pprint/#your-selection-of-prettifiers","title":"Your Selection of Prettifiers","text":"

    Pretty printing can happen on the server (i.e. in the JVM, via nREPL), or on the client (i.e. in node, via VS Code/Calva). Client side always uses zprint. Server side you can choose from these printers:

    Print Engine Client or Server Side Comments calva client The nREPL server will plain print the results, and then Calva will pretty it (using zprint). pprint server Current Calva default. clojure.core/pprint is a bit basic, but it's tried and tested, and doesn't suffer from the issues with the other server side printing options, mentioned below. fipp server puget server Lacks maxDepth option. zprint server A very good option. However, it will need to be configured before Jack-in if you want Calva's help to inject its dependencies. (If you are not using Jack-in, you'll need to supply this dependency yourself.)

    These particular server side functions were chosen because they have pre-configured print-functions in cider-nrepl.

    "},{"location":"pprint/#or-configure-printfn","title":"Or configure printFn","text":"

    If the selection of built-in printEngine support doesn't cut it, you can configure a custom function. This function will need to conform to the requirements of nREPL print functions. The VS Code settings editor will help you configure this one. (This is also a bit experimental, please consider giving feedback about how it works for you if you try it.)

    "},{"location":"pprint/#why-does-server-or-client-side-matter","title":"Why does Server or Client Side Matter?","text":"

    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.

    "},{"location":"pprint/#need-more-configurability","title":"Need More Configurability?","text":"

    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.

    "},{"location":"pprint/#troubleshooting","title":"Troubleshooting","text":""},{"location":"pprint/#pprint-is-not-working","title":"pprint is not working","text":"

    If pprint is not working, try a different pprint engine or use Calva's jack-in to make sure the necessary dependencies are loaded in your REPL. If you are starting your REPL without jack-in and want to continue doing so, you can use the command Copy Jack-in Command Line to Clipboard then paste the command somewhere to see what dependencies it injects. You can then add these dependencies to your REPL in whatever way suits your needs.

    Enjoy Prettiful Printing! \u2764\ufe0f

    "},{"location":"quirks/","title":"Quirks","text":"

    Here's a shocker for ya': Calva isn't perfect. \ud83d\ude04

    There are quirks and things that flat out do not work. We'll try to collect info about such things here, providing workarounds when available (or, rather, known to us).

    "},{"location":"quirks/#test-features-not-available-with-clojurescript","title":"Test features not available with ClojureScript","text":"

    Currently cider-nrepl does not provide its test functionality for ClojureScript code. Please consider contributing to fixing that.

    "},{"location":"quirks/#using-with-parinfer","title":"Using with Parinfer","text":"

    See Using with Parinfer

    "},{"location":"quirks/#calva-and-the-vim-extension","title":"Calva and the VIM Extension","text":"

    See Using Calva with the VIM Extension.

    "},{"location":"quirks/#command-not-found-errors-on-jack-in","title":"\u201dCommand not found\u201d Errors on Jack-in","text":"

    Jack-in starts by running a command in a new terminal. You will need the commands used installed on your computer:

    • clojure for tools.deps/deps.edn
    • lein for Leiningen
    • npx for shadow-cljs
    • gradlew for Gradle (in your project)

    Also, in some circumstances VS Code is not spawned from a shell with the environment variables, especially $PATH, which might mean that even though you have the tools installed, they are not found when VS Code/Calva tries to execute them. To fix this you will need to do one of these two things:

    1. Figure out from where VS Code is spawned, and make sure the $PATH there includes the directory with the needed binary.
    2. Start VS Code from a terminal where the $PATH is correctly configured. (Using the code command.)

    See this issue for more clues on this problem.

    "},{"location":"quirks/#strange-linting-errors","title":"Strange linting errors?","text":"

    This is not really a quirk, and most linting errors are not strange when you learn about why they are there. Calva does not do any linting, btw, see also linting.

    "},{"location":"quirks/#consider-uninstalling-these-extensions","title":"Consider uninstalling these extensions","text":"

    Without Calva, many users install other nifty extensions (some of which are old pieces of Calva) that help with this or that problem. It might sometimes work together with Calva, sometimes not. Here's a list of some common extensions you should consider to at least disable:

    • Strict Paredit - Calva Paredit has evolved a lot since that version
    • Calva-fmt/Calva Formatter - Same here, evolution
    • Clojure Warrior - Calva includes it, in a much evolved way
    • Parinfer - This one you can actually keep, at some cost, see Using Calva with Parinfer.
    "},{"location":"re-frame-template/","title":"How to use Calva with the re-frame template","text":"

    The re-frame template creates a shadow-cljs project, making it easy to use with Calva.

    1. npm install
    2. From VS Code, issue the command Calva: Start a Project REPL and Connect (a.k.a Jack-in), ctrl+alt+c ctrl+alt+j.
    3. Calva will auto-detect that this is a shadow-cljs project and ask for which build to compile.
    4. Calva's output window will open and log some progress information.
    5. When prompted for which build to start, select :app.
    6. :app is the only configured build, but the VS Code menu for this is a bit strange so make sure the :app checkbox is really ticked before proceeding.
    7. This will start the app, so in this workflow you don't do the Run application steps outlined below.
    8. When prompted for which build to connect to, select :app.
      • In the View menu of VS Code, you can tell it to show the Terminal view, where you see which command the jack-in process is started with, and it's output. Ctrl+C in this pane will kill your app and free up all resources it has allocated.
    9. When the app is compiled
      1. Open http://localhost:8280 in your browser.
      2. Confirm that it says Hello from re-frame. (Depending on how long the app takes to compile, you might need to reload the page a few times.)
    10. Open the views.cljs file from src/<your-project-name> and issue Calva: Load/Evaluate Current File and its Requires/Dependencies. ctrl+alt+c enter.
      1. Confirm that you are connected by adding evaluating (js/alert \"Hello from Calva\") (alt+enter and ctrl+enter are your friends).
      2. Confirm that Shadow is hot reloading by changing the greeting message.
    "},{"location":"rebl/","title":"How to Use Calva and REBL Together","text":"

    REBL is a graphical, interactive tool for browsing Clojure data.

    "},{"location":"rebl/#depsedn","title":"deps.edn","text":"

    Add the following aliases to your deps.edn file. Use the deps.edn file in the ~/.clojure directory to enable alias reuse across multiple projects. This is the configuration for REBL on openjdk 12. Check out the REBL github page for more info.

    ;; REBL Base\n:rebl\n{:extra-deps {org.clojure/core.async {:mvn/version \"0.4.490\"}\n                ;; deps for file datafication (0.9.149 or later)\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

    Create a Calva custom connect sequence for your VSCode editor. (Read Custom REPL Connect Sequences if you haven't.) Add the following to your vscode settings.json:

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Rebl Connect\",\n            \"projectType\": \"deps.edn\",\n            \"menuSelections\": {\n                \"cljAliases\": [\n                    \"rebl\",\n                    \"rebl-12\",\n                    \"nrebl\"\n                ]\n            }\n        }\n    ]\n}\n
    "},{"location":"rebl/#leiningen","title":"Leiningen","text":"

    Add rebl profiles to your user-wide profiles so that they will be available for all your projects. Here's a sample user profile (located at ~/.lein/profiles.clj on mac):

    {:user {:plugins [[lein-ancient \"0.6.15\"]]}\n\n ;; REBL Base\n :rebl {:resource-paths [\"/Users/ozimos/REBL/latest/REBL.jar\"]\n        :dependencies [[org.clojure/core.async \"0.4.490\"]\n                       [org.clojure/data.csv \"0.1.4\"]\n                       [org.clojure/data.json \"0.2.3\"]\n                       [cljfmt \"0.6.4\"]\n                       [org.yaml/snakeyaml \"1.23\"]]}\n\n ;; REBL 12 for JDK 12.0.1. Swap out for your JDK version\n :rebl-12 {:dependencies [[org.openjfx/javafx-fxml  \"12.0.1\"]\n                          [org.openjfx/javafx-controls \"12.0.1\"]\n                          [org.openjfx/javafx-graphics \"12.0.1\"]\n                          [org.openjfx/javafx-media \"12.0.1\"]\n                          [org.openjfx/javafx-swing \"12.0.1\"]\n                          [org.openjfx/javafx-base  \"12.0.1\"]\n                          [org.openjfx/javafx-web \"12.0.1\"]]}\n\n;; NREBL https://github.com/RickMoynihan/nrebl.middleware\n :nrebl {:repl-options {:nrepl-middleware [nrebl.middleware/wrap-nrebl]}\n        :dependencies [[rickmoynihan/nrebl.middleware \"0.3.1\"]]}}\n
    More info here

    Create a Calva custom connect sequence for your VSCode editor. (Read Custom REPL Connect Sequences if you haven't.) Add the following to your vscode settings.json:

    {\n    \"calva.replConnectSequences\": [\n        {\n            \"name\": \"Lein REBL\",\n            \"projectType\": \"Leiningen\",\n            \"menuSelections\": {\n                \"leinProfiles\": [\"rebl\", \"rebl-12\", \":nrebl\"]\n            },\n            \"afterCLJReplJackInCode\": \"((requiring-resolve 'cognitect.rebl/ui))\"\n        }\n    ]\n}\n
    "},{"location":"rebl/#shadow-cljs-tbd","title":"shadow-cljs (TBD)","text":"

    TBD. If you know how to do it, please update this page.

    "},{"location":"refactoring/","title":"Refactoring","text":"

    There are two \u201dflavours\u201d to refactoring support. Some (just a few) refactorings are made available as Quick Fix suggestions (the light bulb), the rest are regular commands in the clojure-lsp Refactoring category.

    You can enable or disable the Quick Fix suggestion lightbulb using the VS Code setting editor.lightbulb.enabled.

    The refactoring commands do not have default keyboard shortcuts. You find them all by typing \u201dclojure-lsp Refactor\u201d in the Command Palette.

    "},{"location":"refactoring/#commands","title":"Commands","text":"Command Title Command Key Description Clean NS Form clojureLsp.refactor.cleanNs Add Missing Require clojureLsp.refactor.addMissingLibspec Extract to New Function clojureLsp.refactor.extractFunction Cycle/Toggle Privacy clojureLsp.refactor.cyclePrivacy Inline Symbol clojureLsp.refactor.inlineSymbol Introduce let clojureLsp.refactor.introduceLet Creates a new let box with the binding. Follow up with \u201dExpand let\u201d to move it upwards. Expand Let clojureLsp.refactor.expandLet Move to Previous let Box clojureLsp.refactor.moveToLet Thread First clojureLsp.refactor.threadFirst Thread First All clojureLsp.refactor.threadFirstAll Thread Last clojureLsp.refactor.threadLast Thread Last All clojureLsp.refactor.threadLastAll Unwind All clojureLsp.refactor.unwindAll Unwind Thread clojureLsp.refactor.unwindThread

    Formatting

    The way that some of the refactorings are applied to the document, makes it difficult for Calva to format the results. So, sometimes you'll need to navigate the cursor to the enclosing form and hit tab to tidy up the formatting after a refactoring. See also Formatting.

    "},{"location":"refactoring/#thanks-to-clojure-lsp","title":"Thanks to clojure-lsp","text":"

    Most of Calva's refactoring support is sourced directly from clojure-lsp. This also means that most often, if you find issues with refactoring, or have suggestions about it, the clojure-lsp repo is where to direct your reporting.

    "},{"location":"remote-development/","title":"Using Calva with Remote Development","text":"

    VS Code Remote Development is a new feature in version 1.35 of VS Code that allows a developer to use a container, remote machine, or the Windows Subsystem for Linux (WSL) as a full-featured development environment.

    I would recommend reading the introductory blog post and watching the videos. I find the feature extremely exciting and wish more IDEs would implement something like it.

    From a Clojure perspective it allows you to have VS Code installed on your Java-less, Clojure-less hardware and still use it to develop Clojure through it.

    "},{"location":"remote-development/#a-use-case","title":"A use-case","text":"
    • For some reason your physical computer has to be running Windows (organizational rules etc.)
    • Your deployment environment is Linux
    • You want to edit files in an editor running on your physical computer
    • Most Clojure tooling is made with *nix first in mind and there are incompatibilities with Windows
    "},{"location":"remote-development/#how-to","title":"How to","text":"

    Run Remote-Containers: Add Development Container Configuration Files... and pick a suitable Java base image. Then:

    "},{"location":"remote-development/#modify-dockerfile-to-install-clojure-cli-and-optionally-lein","title":"Modify Dockerfile to install Clojure CLI (and optionally lein)","text":"

    Add:

    # ...\n\n# Install Clojure - see https://github.com/Quantisan/docker-clojure/blob/master/target/openjdk-14-slim-buster/tools-deps/Dockerfile\nENV CLOJURE_VERSION=1.10.1.619\nWORKDIR /tmp\nRUN \\\napt-get update && \\\napt-get install -y curl make rlwrap wget && \\\nrm -rf /var/lib/apt/lists/* && \\\nwget https://download.clojure.org/install/linux-install-$CLOJURE_VERSION.sh && \\\nsha256sum linux-install-$CLOJURE_VERSION.sh && \\\necho \"28b1652686426cdf856f83551b8ca01ff949b03bc9a533d270204d6511a8ca9d *linux-install-$CLOJURE_VERSION.sh\" | sha256sum -c - && \\\nchmod +x linux-install-$CLOJURE_VERSION.sh && \\\n./linux-install-$CLOJURE_VERSION.sh\nRUN \\\nsu vscode -c \"clojure -e '(clojure-version)'\" && \\\nrm ./linux-install-$CLOJURE_VERSION.sh\n\n# Install Lein\nRUN \\\nwget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein -O /bin/lein && \\\nchmod uog+x /bin/lein\nRUN su vscode -c \"/bin/lein\"\n\n# Cleanup\nRUN apt-get purge -y --auto-remove curl wget\n\n# ...\n
    "},{"location":"remote-development/#modify-devcontainerjson","title":"Modify devcontainer.json","text":"

    Add Calva and, optionally, forward some ports to the host::

    \"extensions\": [\"betterthantomorrow.calva\"],\n\"forwardPorts\": [8088, 52162], // example: your webapp, your nREPL\n
    "},{"location":"remote-development/#build-and-start","title":"Build and start","text":"

    Run Remote-Containers: Rebuild and Reopen in container

    "},{"location":"remote-development/#wsl","title":"WSL","text":"

    See Using Calva with WSL

    "},{"location":"repl-window/","title":"The REPL Window/File","text":"

    The Calva REPL Window is actually a regular file with some extra treatment from Calva, like displaying a prompt, offering evaluation history recall and generally \u201cfollowing\u201d the current namespace. This file is created and opened when Calva is connected to a REPL. You can use it for experimental code (though there are also Rich Comments and Fiddle Files for this).

    In ClojureScript projects, the window will be associated with the cljs REPL once it is connected. It will then look something like this:

    The first prompt is from when the clj REPL is connected, and the second from cljs. The first part of the prompt tells you which REPL type the window is currently connected to.

    "},{"location":"repl-window/#using-the-repl-window-for-output","title":"Using the REPL Window for output","text":"

    By default the REPL Window doubles as the place where Calva sends output like stdout/stderr and other messages. See Calva Output for more about this and how to change this behaviour.

    "},{"location":"repl-window/#finding-the-repl-window","title":"Finding the REPL Window","text":"

    If you quickly want to open and/or switch to the REPL Window there is the command Calva: Show/Open REPL Window, ctrl+alt+o r.

    To sync the REPL window namespace with the current file before switching, use the Switch Namespace of the REPL Window to Current Namespace command, ctrl+alt+c alt+n.

    "},{"location":"repl-window/#find-the-file-for-the-current-repl-window-namespace","title":"Find the File for the Current REPL Window Namespace","text":"

    When you are editing things in the REPL window, and want to open the file that defines its current namespace, use the Show File for the Current REPL Window Namespace command, ctrl+alt+o r.

    Note

    This also works for Clojure core and library namespaces.

    "},{"location":"repl-window/#evaluating-code","title":"Evaluating Code","text":"

    The window will be automatically associated with the REPL and the namespace of any project Clojure/ClojureScript file you evaluate code in. So for instance if you evaluate this code in a clj file with the namespace fresh-reagent.handler:

    (def mount-target\n  [:div#app\n   [:h2 \"Welcome to fresh-reagent\"]\n   [:p \"please wait while Figwheel is waking up ...\"]\n   [:p \"(Check the js console for hints if nothing exciting happens.)\"]])\n

    If the REPL Window is the configured destination for evaluation results, the defined var will be printed there. Otherwise, it will be printed to the destination you've configured. In either case, the REPL window will print a new prompt reflecting the current REPL connection and namespace:

    If you then switch to the output window (ctrl+alt+o r), and enter this at the prompt:

    mount-target\n

    then evaluate it using alt+enter, you'll get this:

    ... because the namespace \u201dfollowed\u201d the first evaluation in the REPL window.

    "},{"location":"repl-window/#repl-history","title":"REPL History","text":"

    Recently evaluated forms in the REPL file are persisted and can easily be shown again for modifying and re-evaluating.

    "},{"location":"repl-window/#navigate-repl-history","title":"Navigate REPL History","text":"

    You can navigate up and down the history of evaluated forms in the REPL file by pressing alt+up and alt+down, provided your cursor is at the end of the last form after the prompt. If the cursor is not at the end of the last form, then alt+up and alt+down will do whatever they are mapped to, which is by default \"Move Line Up\" and \"Move Line Down,\" respectively.

    If you have typed some text after the prompt before you start traversing up the history, this text will be preserved and will display when you traverse back down the history. If you modify some text in the history while traversing, the modification will be saved at that location in history.

    "},{"location":"repl-window/#clear-repl-history","title":"Clear REPL History","text":"

    You can clear the repl history by running the command \"Clear REPL History\" from the command palette.

    "},{"location":"repl-window/#stack-traces","title":"Stack Traces","text":"

    When an evaluation produces an error, it will automatically be printed in the REPL Window. If there is a stack trace associated with the error, it can now be printed on demand using the Calva: Print Last Stacktrace to the Output Window command. You can also print the stack trace for any error message printed to the REPL Window via the Codelens button below it.

    For printed stacktraces, when source locations are available (Clojure files), you will be able to navigate to them by pressing ctrl+click (cmd+click on Mac) on the file name. You can also hover over symbols in the stack trace to see the symbol's documentation, and ctrl+click (cmd+click on Mac) the symbol to Peek Definition.

    Output destinations

    If you have configured some other destination for stderr output, the error message will be printed there as well. But it will also be printed to the REPL Window, because the augmented stack traces need this (because reasons).

    "},{"location":"repl-window/#load-current-namespace","title":"Load Current Namespace","text":"

    When navigating namespaces it is easy to forget to first require them and that can be tricky to debug. To help with this, Calva's command Load/Evaluate Current File and its Requires/Dependencies also works in the REPL Window, but there, it acts like Load Current Namespace.

    Suppose you have two files, pez/xxx.clj and pez/yyy.clj, where pez.yyy requires pez.xxx.

    (ns pez.xxx)\n\n(def a :xxx-a)\n\n(def b :xxx-b)\n
    (ns pez.yyy\n  (:require [pez.xxx]))\n\n(def a :yyy-a)\n\n(println \"Hello\" pez.xxx/a)\n

    Then, with a freshly jacked-in REPL, you evaluate (ns pez.yyy) and want to work with the vars defined there, Clojure will complain. But if you Load/Evaluate Current File and its Requires/Dependencies, it will start working. Something like so:

    Note

    This currently suffers from a limitation in Calva where it won't reload dependencies, so you will sometimes have to do this \u201dmanually\u201d anyways (by opening the files and loading them yourself). See Calva issue #907

    "},{"location":"repl-window/#peek-current-namespace","title":"Peek Current Namespace","text":"

    A somewhat hidden feature: You can peek, see documentation for, and navigate to a namespace by hovering on the namespace symbol in one of the REPL Window prompts (just like you would if it was not in the prompt \ud83d\ude04).

    "},{"location":"repl-window/#paredit-enabled","title":"Paredit Enabled","text":"

    The REPL Window is mostly a regular Calva Clojure/ClojureScript file, which makes everything that works in a regular file work in this file, including Paredit. This makes it easy to navigate the input and output there. For instance, to select the last evaluation results, you can press ctrl+w (shift+alt+right on Windows and Linux):

    "},{"location":"repl-window/#debugger-enabled","title":"Debugger Enabled","text":"

    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.

    "},{"location":"repl-window/#it-is-ephemeral","title":"It is Ephemeral","text":"

    The contents of the output/REPL window is written to a file named output.repl in the .calva/output-window directory of your project. The file is recreated every new session, so you should copy or save anything you want to preserve between sessions.

    You probably want to add .calva/output-window/ to your .<something>ignore files. (There are some more files in that directory that you shouldn't keep under source control.)

    "},{"location":"repl-window/#choose-clj-or-cljs-repl-connection","title":"Choose CLJ or CLJS REPL Connection","text":"

    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:

    "},{"location":"repl-window/#known-quirks-and-caveats","title":"Known Quirks and Caveats","text":"

    Due to limitations in the VS Code API it is hard for Calva to know if the REPL file is open, and if it was opened more than once. Therefore, we suggest you make it a habit to leave this window open, or even pinned. And if it is open in several tabs, expect evaluation printouts to be a bit unpredictable.

    If you save the REPL file (which most often does not make much sense, but anyway) you will sometimes be presented with a message about VS Code being confused about the file contents being out of sync. Just choose to Overwrite the currently saved version and you should be fine.

    "},{"location":"reveal/","title":"How to use Calva and Reveal together","text":"

    Reveal is a \"Read Eval Visualize Loop for Clojure\". This page describes how to use Reveal in your development setup based on Calva.

    Note

    See https://vlaaad.github.io/reveal for the latest version and use that wherever this page says <version>.

    "},{"location":"reveal/#when-using-toolsdeps","title":"When using tools.deps","text":"

    You can go for the nrepl middleware or just add the dependency.

    Please see the Calva test-data project minimal-reveal for an example.

    "},{"location":"reveal/#middleware","title":"Middleware","text":"

    This will make Reveal to start together with your project.

    Note

    This will make all Calva evaluations go to Reveal. Too chatty for you? Take the dependencies only approach.

    Add this alias deps.edn:

    :aliases\n{:reveal-nrepl-middleware\n    {:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}\n     :main-opts  [\"-m\" \"nrepl.cmdline\"\n                  \"--middleware\" \"[vlaaad.reveal.nrepl/middleware,cider.nrepl/cider-middleware]\"]}}\n

    And then jack-in choosing the deps.edn option and then pick the :reveal-nrepl-middleware alias.

    "},{"location":"reveal/#dependencies-only","title":"Dependencies only","text":"

    If you don't want to use the nrepl-middleware you can configure just the dependency and then start Reveal yourself.

    The alias:

    :reveal-dep-only\n  {:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}}\n

    A custom REPL command for starting Reveal in your project:

        \"calva.customREPLCommandSnippets\": [\n        ...\n        {\n            \"name\": \"Start Reveal Tapper\",\n            \"snippet\": \"(require '[vlaaad.reveal :as reveal])(add-tap (reveal/ui))\",\n            \"key\": \"sr\"\n        },\n        ...\n    ]\n

    See Custom REPL Command for how to configure more commands, and bind shortcuts to them, to make Reveal integration nice for you.

    "},{"location":"reveal/#when-using-leiningen","title":"When using Leiningen","text":"

    In your project.clj, add a profile named \"reveal\":

    :profiles {:reveal {:dependencies [[vlaaad/reveal \"<version>\"]]\n                    :repl-options {:nrepl-middleware [vlaaad.reveal.nrepl/middleware]}}}\n

    Now when you jack-in using Calva, you enable this profile and Reveal will be started automatically. Please note that Reveal requires Java 8 or higher, and uses JavaFX. Depending on your setup, you may need to make sure it is available.

    "},{"location":"reveal/#tips-about-font-size","title":"Tips about font size","text":"

    If you find the font to small you can add a :jvm-opts key to make it a little bigger:

    :aliases\n{:reveal\n    {:extra-deps {vlaaad/reveal {:mvn/version \"<version>\"}}\n     :jvm-opts   [\"-Dvlaaad.reveal.prefs={:font-size,17}\"]\n     :main-opts  [\"-m\" \"nrepl.cmdline\"\n                  \"--middleware\" \"[vlaaad.reveal.nrepl/middleware,cider.nrepl/cider-middleware]\"]}}\n
    "},{"location":"reveal/#using-java-11","title":"Using Java > 11?","text":"

    Reveal needs some reflective access to internal classes that has since Java 11 been restricted. You can relax this and get things working via JVM options. Tuck this into your reveal alias:

    :jvm-opts [\"--add-opens\" \"javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED\"]\n

    (If you are using the font size tips, just add the options into the :jvm-opts vector.)

    See https://github.com/vlaaad/reveal/issues/1 for some more context around this issue.

    "},{"location":"rich-comments/","title":"Rich Comments Support","text":"

    Why bother with Rich comments? Read on. Consider watching this Youtube video for a demo of the workflow using the (in?)famous FizzBuzz problem as an example.

    ","boost":5},{"location":"rich-comments/#things-in-comment-are-not-evaluated","title":"Things in comment are not evaluated","text":"

    The Clojure comment macro is defined like so:

    (defmacro comment\n  \"Ignores body, yields nil\"\n  {:added \"1.0\"}\n  [& body])\n

    It has no forms in its body and will therefore always (as long as the Clojure Reader can read it) evaluate to nil. That is: nothing in the (comment ...) form will get evaluated when the file is loaded.

    This makes it a very good \u201dplace\u201d where you can develop code, experiment with code, and keep example code. Since you will be able to load/evaluate the current file without worrying that the code in the comment form will get evaluated. This also holds true when using tools that hot-reload the code on save, such as Figwheel, shadow-cljs and Krell.

    To develop or refine a function you might:

    1. Open up a (comment ...) form
    2. Inside this form, type a first, super simple, version (or refinement) of your function and evaluate it
    3. Inside the same comment form, type some code to test your function and evaluate that
      • Or type and evaluate some code you might need for your function
    4. Repeat from 2., until the function does what you want it to do
    5. Move the function definition out of the comment form
    6. Clean up the comment form to keep some of the test code as example use, or \u201ddesign decision log\u201d for the function.

    Note

    Using (comment ...) forms for developing code is very common among Clojure coders. Rich Hickey is known for using it, which is why they are called Rich comments to begin with (even if it also is a very rich experience).

    ","boost":5},{"location":"rich-comments/#calva-encourages-rich-comments","title":"Calva encourages Rich comments","text":"

    Calva has several features to facilitate the Rich comments workflow, e.g.

    1. A command that helps you create a new Rich comment form quickly: Calva: Add Rich Comment, ctrl+alt+r c
    2. A snippet for creating Rich comment form quickly. Typing (rcf, will make it appear.
    3. Special Syntax highlight. By default comment forms are rendered in italics
    4. Special top-level form context
    5. Special formatting

    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.

    ","boost":5},{"location":"rich-comments/#comment-is-top-level","title":"comment is top-level","text":"

    To make it easy to evaluate forms in (comment ...) forms, they create a new top-level context. Instead of you having to place the cursor with precision before evaluating the current form, you can have the cursor anywhere within a comment enclosed form and Evaluate Top-Level Form.

    This carries over to all commands in Calva which deal with the top level form. Including custom command snippets.

    ","boost":5},{"location":"rich-comments/#special-formatting","title":"Special formatting","text":"

    To invite a Rich comments workflow, the Calva command Format Current Form will not fold the closing bracket of the (comment ...) form. Instead it will place this bracket on a line of its own (or keep it there).

    (comment\n  )\n

    With the cursor somewhere directly inside the comment form (denoted with a |):

    (comment\n  (def foo\n:foo)|)\n

    tab

    (comment\n  (def foo\n    :foo)\n  |)\n

    !!! Note \"Only for the current comment form\u201d The special formatting only applies in the current comment form. When outside it, formatting tucks the closing paren in again. That's why fold when done, below works like it does. This also applies to VS Code commands like Format Document, or when you have Format On Save enabled. There are several reasons for this, and one is that there is no cljfmt config for it and leaving the closing comment un-tucked might give you troubles with CI pipelines that enforce some cljfmt config be followed. (Another reason is that it would be pretty hard to do on the whole document.)

    ","boost":5},{"location":"rich-comments/#special-formatting-disabled-for-trailing-rcf","title":"Special formatting disabled for trailing :rcf","text":"

    If the Rich comment ends with :rcf (or an ignored form), the special formatting doesn't happen. So if you have:

    (comment\n  (def foo\n:foo)\n  |\n  :rcf)\n

    And hit tab, you will get:

    (comment\n  (def foo\n    :foo)\n  |\n  :rcf)\n
    ","boost":5},{"location":"rich-comments/#thinking-space-is-kept","title":"Thinking space is kept","text":"

    The formatter will not remove newlines between the cursor and the closing bracket. So if you have entered a few lines to get \u201dthinking\u201d room:

    (comment\n  (def foo\n:foo)\n\n|\n\n)\n

    tab

    (comment\n  (def foo\n    :foo)\n\n  |\n\n  )\n
    ","boost":5},{"location":"rich-comments/#fold-when-done","title":"Fold when done","text":"

    To fold the trailing paren automatically, place the cursor immediately outside (before or after) the form:

    (comment\n  (def foo\n:foo))|\n

    tab

    (comment\n  (def foo\n    :foo))|\n
    ","boost":5},{"location":"rich-comments/#enabled-by-default","title":"Enabled by default","text":"

    You can disable this behavior with the setting: calva.fmt.keepCommentTrailParenOnOwnLine.

    ","boost":5},{"location":"rich-comments/#only-for-the-current-form","title":"Only for the Current Form","text":"

    Note

    This treatment only applies to formatting of the current form. With fold when done as an exception.

    ","boost":5},{"location":"shadow-cljs/","title":"shadow-cljs","text":"

    Calva supports most any JVM hosted ClojureScript environment (and some others, including SCI based, too), but shadow-cljs gets some special treatment to try make it extra convenient to use.

    With many shadow-cljs projects, Calva's connect project type shadow-cljs, is the right choice. Projects that use Leiningen or deps.edn can be used both with the Leiningen/deps.edn and shadow-cljs type, depending on configuration see below for more on this.

    ","boost":7},{"location":"shadow-cljs/#shadow-cljs-browser-quickstart","title":"shadow-cljs - browser quickstart","text":"

    Here's how you start a shadow-cljs ClojureScript REPL and connect Calva with the shadow-cljs - browser quickstart example project:

    Prep:

    1. Clone the project to your machine and open its root folder in VS Code.
    2. Open a terminal and run npm install

    Connect Calva:

    1. Run the command Calva: Start a Project REPL and Connect (a.k.a. Jack-in)
    2. Select project type shadow-cljs
    3. Select to start the build :app
    4. Select to connect to the build :app
    5. Wait for the build to complete
    6. Open http://localhost:8020/ in the browser
    7. Open browser.cljs file and load it in the REPL: Calva: Load/Evaluate Current File and Dependencies

    Now you can should be able to evaluate forms, e.g.:

    • The current form or selection with ctrl+enter, or
    • Top-level forms with alt/option+enter.

    (See Code Evaluation)

    ","boost":7},{"location":"shadow-cljs/#shadow-cljs-in-full-stack-projects","title":"shadow-cljs in full stack projects","text":"

    shadow-cljs is a bit special in regards to Calva REPL connection. Mainly because you can start shadow-cljs and it's nREPL server in two ways:

    1. Using the shadow-cljs npm executable
    2. Via the Clojure REPL in your Leiningen or deps.edn project

    These options show up as project types when connecting or jacking in:

    1. Project type: shadow-cljs
    2. Project type: deps.edn + shadow-cljs or Leiningen + shadow-cljs

    The technical difference here is wether you let shadow-cljs start clojure/Leiningen (the first option) or if you let Calva do it (the second option). If you let Calva do it, Calva will then start the shadow-cljs watcher from the Clojure process. From a usage perspective the two approaches will result in different channeling of shadow-cljs output, e.g. test runner results. With the first option (the shadow-cljs project type), shadow-cljs output will be channeled to the Jack-in terminal. With the deps.edn/Leiningen option, that output will be channeled to the Output/REPL window.

    See shadow-cljs + Clojure with Calva: The basics for some more discussion on how the REPL connection works.

    shadow-cljs and clojure aliases

    The shadow-cljs project type will not prompt you for any aliases found in the deps.edn file. Usually you should provide such aliases in shadow-cljs.edn like :deps {:aliases [...]}. If, for whatever reason you can't provide the aliases that way, you can configure a Custom REPL Connect Sequence and provide the aliases as menuSelections -> cljAliases.

    Leiningen + shadow-cljs middleware issue

    Please note that for Leiningen, the command line dependency injection of the shadow-cljs nrepl middleware doesn't work. You need to add it to your project.clj:

    :repl-options {:nrepl-middleware [shadow.cljs.devtools.server.nrepl/middleware]}\n
    ","boost":7},{"location":"shadow-cljs/#see-also","title":"See also:","text":"
    • Connect the REPL
    • Custom REPL Connect Sequences
    • shadow-cljs + Clojure with Calva: The basics
    ","boost":7},{"location":"sponsors/","title":"Calva Sponsors","text":"

    Calva is open source and free to use. It is actively maintained during our free time, and it keeps improving. You can contribute in many different ways, one of which is sponsoring. You can sponsor Calva by directly sponsoring any of us.

    If you are working at a company which benefits from Calva's existence and continued development, please consider sponsoring at the Calva Gold Sponsor tier.

    Please see this statement from Cognitect about the importance of supporting open source developers.

    ","boost":7},{"location":"sponsors/#patrons","title":"Patrons","text":"The right kind of different","boost":7},{"location":"sponsors/#gold-sponsors","title":"Gold Sponsors","text":"Scale your growth on mobile MAKE. DO. SHIP.","boost":7},{"location":"sponsors/#silver-sponsors","title":"Silver Sponsors","text":"","boost":7},{"location":"sponsors/#clojurists-together","title":"Clojurists Together","text":"

    Significant additions to Calva have been made possible by funding from Clojurists Together. And this has often been transformational for the whole project. Calva would not be where it is today without Clojurists Together.

    ","boost":7},{"location":"sponsors/#our-sponsoring-profiles","title":"Our Sponsoring Profiles","text":"

    These are the sponsoring profiles for the active maintainers of Calva (a.k.a. The Calva Team).

    • Peter Str\u00f6mberg
    • Brandon Ringe
    • Cora Sutton
    • Lukas Domagala
    • Rayat Rahman
    ","boost":7},{"location":"sponsors/#readme-visibility","title":"README visibility","text":"

    There is also a sponsors section in the README of the Calva project (which means it is also displayed in the VS Code Extension Marketlace).

    ","boost":7},{"location":"syntax-highlighting/","title":"Calva Highlight","text":"

    Calva takes care of syntax highlighting, and also provides some features not available through VS Code's highlighting mechanism. These extras include rainbow parens, sane bracket matching, and comment form dimming/highlighting.

    "},{"location":"syntax-highlighting/#syntax-highlighting","title":"Syntax Highlighting","text":"

    When using Calva, you are also using its TMLanguage grammar (the core mechanism VS Code uses for syntax highlighting).

    Our grammar tokenizes Clojure keywords as constant.keyword.clojure. Since it is pretty uncommon with keyword constants in the programming languages out there, your theme might not have a highlight defined for this scope. Try find a grammar that highlights keywords! If you are very fond of some theme lacking this, you can help it with a setting:

    \"editor.tokenColorCustomizations\": {\n    \"[Default Dark+]\": {\n        \"textMateRules\": [\n            {\n                \"scope\": [\n                    \"constant.keyword.clojure\"\n                ],\n                \"settings\": {\n                    \"foreground\": \"#6fbfff\"\n                }\n            }\n        ]\n    }\n},\n

    Instead of Default Dark+ you should use your theme's name/key. And choose a color you like, of course.

    "},{"location":"syntax-highlighting/#extra-highlighting","title":"Extra Highlighting","text":"

    You are in charge of how brackets and comments are highlighted via the calva.highlight.<setting> settings:

    Setting Meaning Example enableBracketColors Enable rainbow colors true rainbowIndentGuides Enable rainbow indent guides true highlightActiveIndent Highlight the active indent guide true bracketColors Which colors to use [\"#000\", \"#999\"] cycleBracketColors Whether same colors should be reused for deeply nested brackets true misplacedBracketStyle Style of misplaced bracket { \"border\": \"2px solid #c33\" } matchedBracketStyle Style of bracket pair highlight {\"backgroundColor\": \"#E0E0E0\"} ignoredFormStyle Style of #_... form {\"textDecoration\": \"none; opacity: 0.5\"} commentFormStyle Style of (comment ...) form {\"fontStyle\": \"italic\"}

    Calva disables the VS Code built-in indent guides

    The VS Code built-in settings editor.renderIndentGuides and editor.highlightActiveIndent do not have any effect, since the former is switched off by the Clojure Defaults, mentioned above. Use Calva Highlight's rainbowIndentGuides and highlightActiveIndent instead. They are different from the built in ones in that they are independent, meaning you can choose to have active indent highlighted while the guides generally are not rendered (this is the default, even).

    VS Code bracket coloring vs Calva's

    Calva's bracket coloring is more Clojure aware than VS Code's built-in coloring. And also will chime better with Calva's indent guides. If you like to have bracket coloring outside Clojure code, by all means enable it. Calva's bracket coloring will \u201dover paint\u201d in Clojure files, when enabled. These settings work nicely:

    \"calva.highlight.highlightActiveIndent\": true,\n\"editor.bracketPairColorization.enabled\": true,\n

    The calva.highlight.bracketColors setting can be used to harmonize the coloring between VS Code and Calva.

    "},{"location":"tao/","title":"The Tao of Calva","text":"

    Calva, the spirit, gains much of its taste and color from the Cider it is distilled from, and the oak it is matured in. I started to wonder what it is that shapes Calva, the VS Code Clojure Extension. I should know, being the master distiller, right?. Indeed. Poking some at the question, I do find that I have some answers.

    Please read the following to learn what Calva is, and, to some extent, is not, about. Read it to get an idea about which path Calva is following, where we are headed with the project, and how you can contribute to the journey.

    "},{"location":"tao/#why-calva","title":"Why Calva?","text":"

    Calva's raison d\u00b4\u00eatre is to provide Visual Studio Code users with an easy to use and productive environment for Clojure and ClojureScript development. See the Why Calva? page for some evidence that we are succeeding.

    While Calva draws a lot of inspiration from CIDER, Cursive, Fireplace, and other Clojure development environments, it does not try to compete with them. Reading r/Clojure and elsewhere, it is easy to get the impression that the most common question is \"Which editor should I use for Clojure development?\u201d. I think a much more common question is \u201dHow do I use my favorite editor for Clojure development?\u201d. For VS Code users, that is where Calva should be a good choice.

    I also have an ambition to leverage VS Code for easing the path to Clojure. Given that it is the favorite editor for so many developers, it is important to have a good development environment in place on this platform, and to make it as easy to use as we possibly can, while also being productive and something that you want to stick with, once you are hooked on Clojure.

    That said, and therefore: For people who want to start out with Clojure, and do ask about what development environment would make it the most enjoyable, I'd like for Calva to be a really good option, an option so good that Clojurians feel they can recommend it.

    "},{"location":"tao/#design-goals","title":"Design Goals","text":"

    Calva should be easy to start with and productive enough to stick with. It should support Clojure Best Practices, and be pleasant and enjoyable to use. It should also be easy to hack on, and to contribute to. The ClojureScript story keeps getting more important. Calva should contribute to making the development experience with ClojureScript delightful.

    "},{"location":"tao/#easy-to-start-with","title":"Easy to Start With","text":"

    There are reasons as to why VS Code is so popular. Among those, one stands out to me: It is the most approachable code editor out there. There is nothing you need to learn when you start using it. The editor makes it obvious that you can start typing, deleting, cutting, pasting and undoing, without having to figure anything out. Then you learn how to bring up the command palette and get a boost few other environments can provide with such immediacy.

    A language extension for VS Code can leverage this, by recognizing that what's old is old, and that what's new should be as easy as possible to pick up. Coming to a new language, people bring with them a lot of expectations from the languages they are used to. This is also true for the editor support. Syntax highlighting and formatting should just work, as should documentation lookup, linting and other IDE commodities.

    Clojure brings some new concepts to the table. Chief among these: The REPL. It does take some time to grasp it. Calva needs to remove any obstacles it can when it comes to helping the user to reach the REPL, in order to help getting it, and start loving it.

    To help the users to quickly focus on Clojure, we provide a package that is all-inclusive, with few knobs to turn, and with sane defaults for the knobs that still need to be there.

    "},{"location":"tao/#productive-enough-to-stick-with","title":"Productive Enough to Stick With","text":"

    I think VS Code brings inspiration also when it comes to following up its excellent Getting Started story. You do not have to dig very deep under its surface to find that there is a lot more power to be unleashed. VS Code makes it easy to pick up more features as you get ready for it, and each little piece makes you more productive. To me, only Vim beats VS Code in this game.

    Most often there should be no contradiction between Easy to Start With and Productive. Quite the contrary. This story is mainly about being feature complete with the most important tools. As beginners start to pick up the first few features, they should be rewarded with finding more productive tools when they go looking for them. The VS Code way is Calva's way.

    "},{"location":"tao/#pleasant-and-enjoyable","title":"Pleasant and Enjoyable","text":"

    Enjoyable starts with that Calva shouldn't be an experience full of pains. I think Calva is living up to this first bar of enjoyability. The next step is making it delightful!

    Calva has two main assets it can leverage for being delightful to use: Clojure and VS Code:

    Clojure is plain wonderful and also has this totally awesome REPL thing. Wherever we can, Calva should use the REPL to make the editor spark and bring joy to the developer.

    VS Code is a sweet development environment, offering its power in a consistent way across languages. Even if Clojure is very special, most of Calva's features are surfaced in the ways that VS Code encourages. It makes for less to learn for the user, and most often also makes it easier to implement functionality.

    "},{"location":"tao/#support-clojure-best-practices","title":"Support Clojure Best Practices","text":"

    Mainly, I think Stuart Halloway is right about the REPL being best used from inside the files you are editing rather than from the prompt. It doesn't mean that Calva's REPL window should be neglected, but efforts should be directed such that the file editor REPL is our first way to improve the experience. Expect the Calva REPL window to get much less \u201din your face\u201d, than it is today, as the editor REPL gets stronger.

    Halloway also gives me some peace of mind with his reasoning of keeping a spartan setup. Calva does not need to pack every feature imaginable. If we can get the right features in place, in the right way, the mission is accomplished.

    Clojure is data centric. Calva should make it easy to examine data and how our code affects it. Today, this is not good enough when it comes to data structures larger than a few elements.

    Clojure is a LISP. Thus Structural Editing is possible, and TBH, desirable. Calva should support this and encourage it. There is little we can do about Parinfer not playing well with VS Code, but there is Paredit, and Paredit rocks! Calva's Paredit plays in the top league of Paredits, for this reason.

    "},{"location":"tao/#made-from-the-produce-of-the-orchard","title":"Made from the Produce of the Orchard","text":"

    Calva is distilled from CIDER, which in turn is brewed from the products of The Orchard. This makes a lot of Calva's features thin wrappers around cider-nrepl and related middleware. It also should mean that we strive for adding features by thinking \u201dThe Orchard\u201d first. If it lacks what we need, we should assist in providing it there. We need to up this game a bit from where we are today, I think.

    "},{"location":"tao/#leveraging-clojure-lsp","title":"Leveraging clojure-lsp","text":"

    Today, Calva draws a lot of its static power from clojure-lsp. As does a lot of other Clojure tooling out there. The Calva and the clojure-lsp teams work very nicely together, which is something we cherish and should take care to maintain.

    "},{"location":"tao/#project-stewardship","title":"Project Stewardship","text":"

    Here Calva takes inspiration from many Clojure related projects, and perhaps most so from CIDER,shadow-cljs, and clojure-lsp. Bozhidar Batsov, Thomas Heller, and Eric Dallo all lead their projects with clarity and with gusto. You can feel how they really care about their products and their users. They are there. They listen. They respond. And they relentlessly keep improving their products.

    So we are there. We listen. We respond. And we keep trying to improve Calva.

    The Calva team cares deeply about the user experience. That is a major part of why we do this. When implementing a new feature, or changing a feature, Ux is always the first thing on our mind. Personally, to keep that direction I often start with the documentation of the feature. Reading the documentation before implementation reveals a lot about if the Ux design is within the ballpark or not.

    We have limited time on our hands, however, and we must cut some corners. We can't afford to spend very much time in Ux design. Rather we will use our Ux intuition, iterate the documentation quickly, and be fast to get things out. Then we are responsive in tweaking those things, based on user feedback. This also has impact on general quality at times. We only can do so much QA, and it happens that some releases of Calva cause disruptions in people's workflow because of things we haven't thought of, or not found during our testing. Again, we try to be attentive to feedback and quick to fix. Apologies in advance for any inconveniences caused!

    A super major part of our love for Ux is that Calva should be serving its users. That's why we treat feedback as a gift, listen intently, and use the feedback as a major ingredient in shaping Calva.

    Calva develops from user feedback in more direct ways as well. It is quite astonishing how many people have decided to improve on it by hacking it to do some small or big thing differently. That's great! We should make sure Calva is super easy to contribute to.

    There has been quite a lot of work put into improving the development process. Starting to hack on Calva is just a few steps, taking less than three minutes from cloning to running a dev version in the VS Code debugger. We encourage contributions, from the tiniest typo to whole new features. And we are ready to spend time helping people get their contributions integrated.

    However, Calva can't be what everyone wants it to be, that would make it useless. It needs direction and aim. And it is we, the Calva Team, who are the stewards. We need to be in charge of what Calva is about, and what it is not about.

    "},{"location":"tao/#the-road-ahead","title":"The Road Ahead","text":"

    Tying back to Stuart Halloway, I don't think he means that spartan needs to also mean poor. The products he helps to bring to the market tell another story. VS Code and Clojure brought together has the capacity to create something amazingly rich and luxurious. And I want Calva to tap into that potential.

    On the Calva journey we will allow ourselves to change our minds about how things work. Calva is not a library. Its an interface between Clojure and human beings. Human beings can adapt. And they will need to enjoy adapting in order to enjoy Calva. \ud83d\ude04

    By now it should be clear that you can expect Calva to keep evolving, keep being tended and maintained, and keep getting ever more enjoyable to use. Lately we have been improving Calva pretty rapidly. It would be great to keep it up like that, but I think it is good to expect a more humble and sustainable pace.

    Calva is still quite new. A bit like freshly distilled Calvados. It will need time in those oak barrels to develop its full bouquet of flavors. And time is what we will give it. Our time, our creativity, and our passion.

    "},{"location":"test-runner/","title":"Test Runner","text":"

    Calva provides commands that make running your Clojure tests easier.

    Note

    Since the test commands utilize cider-nrepl, they only work with Clojure, not ClojureScript. See this issue for more details.

    "},{"location":"test-runner/#test-commands","title":"Test Commands","text":"Command Shortcut Description Run All Tests ctrl+alt+c shift+t Runs all tests Run Failing Tests ctrl+alt+c ctrl+t Runs the tests that failed Run Tests for Current Namespace ctrl+alt+c t Runs the tests for the current namespace. If not a -test namespace, tests for the current namespace plus its corresponding <current-namespace>-test namespace will be run. Run Current Test ctrl+alt+c ctrl+alt+t Runs the test at the cursor. This includes a defn with a :test in its metadata, a defn defined in a with-test, and a deftest. Toggle between implementation and test - Switches the file between implementation and test, prompts to create a new file if not found."},{"location":"test-runner/#test-on-save","title":"Test on Save","text":"

    You can enable the Calva setting \"Test on Save\" to have tests for the current namespace run on file save.

    "},{"location":"test-runner/#vs-code-test-ui","title":"VS Code Test UI","text":"

    Calva has experimental support for showing test results in VS Code's Test UI. You can enable this support by setting calva.useTestExplorer to true. When you enable this setting, the Testing icon will appear in the Testing tab of VS Code's Activity Bar.

    With this feature enabled you will be able to browse and run tests directly from the Testing tab.

    Please join the #calva channel on the Clojurians Slack if you have any feedback on this new feature.

    "},{"location":"test-runner/#troubleshooting","title":"Troubleshooting","text":""},{"location":"test-runner/#tests-are-not-found","title":"Tests Are Not Found","text":"

    Calva will not load namespaces in the REPL that you haven't loaded. This is so that you can be in control of what is loaded in the REPL. However, it also means that commands like Run All tests actually mean Run All Tests That are Loaded in the REPL, since the test-runner only runs tests that it knows about, i.e. are loaded in the REPL. Some developers choose to make sure all test namespaces are loaded as part of starting their REPL. Others register a custom REPL command for loading test namepaces. (Yet others use test-runners such as Cognitect's test-runner, Kaocha, poly test, or some other that runner allows for tests being run automatically, separate from the REPL used for development.)

    If you have tests in a test directory separate from your source directory, and those tests are not being found by the test runner, make sure the test directory is included in your paths. This will not be the case by default with a tools.deps (deps.edn) project. If your project is a tools.deps project, you can create an alias in your deps.edn file with :extra-paths that includes \"test\" (or the name of your test directory).

    {:aliases {:dev {:extra-paths [\"test\"]}}}\n
    "},{"location":"test-runner/#changes-arent-taking-effect-when-running-tests","title":"Changes Aren't Taking Effect When Running Tests","text":"

    In order for changes in code to take effect, you need to load the file or evaluate the changed code before running a test command. Prior to version 2.0.301, Calva would load the file for you when running some test commands, but that behavior was removed in favor of leaving control to the user, and to avoid a potential issue.

    Having added the above to your deps.edn, when you jack-in, choose the :dev alias and the test directory will be added to your paths, which will allow tests located in the directory to be found by the test runner.

    "},{"location":"test-runner/#toggle-between-implementation-and-test-command-not-working-as-intended","title":"Toggle between implementation and test command not working as intended","text":"

    This feature mostly works with projects that has leiningen style folder structure and makes some assumption about your folder structure and test file names.

    • It assumes that the test files ends with _test prefix.
    • It assumes that your implementation files are in src folder and the test files are in test folder.

    If you are using any non leiningen style folder structure, you may have to add source paths inside .lsp/config.edn.

    "},{"location":"try-first/","title":"Something to Try First (After Connecting)","text":"

    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:

    • On a new line, type a comment form and put some code inside it:
    (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

    Then:

    1. Place the cursor behind the form (* 2 2) and issue the command Calva: Evaluate Current Form, ctrl+enter.
      • You should see the result being displayed inline. Press esc to dismiss it.
    2. Now issue the command Evaluate Current Top Level Form (defun), alt+enter.
      • You should see the whole form (+ (* 2 2) 2) getting highlighted and the result of that expression being displayed inline.
    3. Evaluate each form inside the comment form using the Top Level command.
      • You should see each one of them evaluated.
      • Evaluating the (hello \"Calva REPL\") form before the (defn hello... form should result in an error/exception. A stacktrace is then printed in the output window
      • Try it again after having evaluated the defnform.

    Demo:

    "},{"location":"try-first/#how-does-this-work","title":"How does this work?","text":"

    Calva has this notion about the current form. Issue the Evaluate Current Form command, with the cursor placed in different locations to get a feeling for how the current form is determined.

    There is also a concept about the current top level form. Good for evaluating various defs defn, defthis, defthat. With your cursor placed anywhere inside such a form.

    The Top Level command also works inside (comment ...) forms, treating the comment as creating a new top level context. It is good for in-file code experimentation.

    "},{"location":"try-first/#see-also","title":"See also","text":"
    • Calva Top 10 Commands.
    • Code Evaluation Tips
    "},{"location":"vim/","title":"Calva and the VIM Extension","text":"

    First thing first. The VIM Extension and Calva has a history of friction between them. Less so these days, but you might still encounter some rough edges. Please don't hesitate to reach out to the Calva team, as we might be able to fix things if only we are aware of them.

    "},{"location":"vim/#key-bindings","title":"Key bindings","text":"

    In general Calva's default key bindings are not very VI-ish.

    "},{"location":"vim/#expand-selection-on-mac","title":"Expand selection on Mac","text":"

    On Mac, Calva binds expand selection to ctrl+w. This conflicts with the VIM Extension's default mapping of window splitting shortcuts. You'll need to remap it either with Calva or with the VIM Extension.

    "},{"location":"vim/#the-esc-key","title":"The esc key","text":"

    While showing inline evaluation results, Calva binds the esc key to dismiss the display of inline results. If you want to be able to use the esc key to enter command mode while inline results are showing, you'll need to rebind Calva's command for dismissing the inline results.

    "},{"location":"vim/#remap-calvas-clearinlineresults","title":"Remap Calva's clearInlineResults","text":"
    • Open the Keyboard Shortcuts JSON file from the Command Palette
    • Disable clearInlineResults and remap the command e.g.
    // Place your key bindings in this file to override the defaults\n[\n  {\n    \"key\": \"escape\",\n    \"command\": \"-calva.clearInlineResults\"\n  },\n  {\n    \"key\": \"shift+escape\",\n    \"command\": \"calva.clearInlineResults\",\n    \"when\": \"editorTextFocus && !editorHasMultipleSelections && !editorReadOnly && !hasOtherSuggestions && !suggestWidgetVisible && editorLangId == 'clojure'\"\n  }\n]\n

    If you run into issues, refer to the commands in the default Keyboard Shortcuts JSON file.

    "},{"location":"vim/#remap-vims-insert-mode","title":"Remap Vim's Insert Mode","text":"

    Remap vim's insert mode keybinding to go into command mode by adding the following to your user settings:

    \"vim.insertModeKeyBindings\": [\n    {\n        \"before\": [\"j\", \"k\"],\n        \"after\": [\"<esc>\"]\n    }\n]\n

    (Change before to whatever keybinding you are comfortable with!)

    "},{"location":"vim/#vim-fireplace-ish-keybindings","title":"Vim Fireplace-ish keybindings","text":"

    You can add these keybindings to your init.vim if you are using the VSCode Neovim extension. It is inspired by and tries to emulate the keybindings found in vim-fireplace which is the most popular vim plugin for Clojure.

    nmap cqp :call VSCodeNotify('calva.jackIn')<CR>\nnmap cqq :call VSCodeNotify('calva.disconnect')<CR>\nnmap cpr :call VSCodeNotify('calva.loadFile')<CR>\nnmap cpR :call VSCodeNotify('calva.loadNamespace')<CR>\nnmap cpp :call VSCodeNotify('calva.evaluateSelection')<CR>\nnmap cqc :call VSCodeNotify('calva.evalCurrentFormInREPLWindow')<CR>\n

    Unfortunately these key combinations will not work in the normal VIM extension as c is an operator key and cannot be remapped. This is a call for someone to share their VIM re-mappings.

    "},{"location":"when-clauses/","title":"Calva When Clause Contexts","text":"

    When clause contexts is a powerful customization mechanism in VS Code. The most common use for end users is with keyboard shortcut bindings. Extensions can provide their own. The following contexts are available with Calva:

    • calva:keybindingsEnabled: a master switch that you find in the settings
    • paredit:keyMap: strict, original, or none from the corresponding Calva setting (see Paredit)
    • calva:connected: true when Calva is connected to a REPL (there is also calva:connecting || calva:launching)
    • calva:outputWindowActive: true when the Output/REPL window has input focus
    • calva:replHistoryCommandsActive: true when the cursor is in the Output/REPL window at the top level after the last prompt
    • calva:replWindowSubmitOnEnter: true when the cursor is adjacent after the last top level form in the Output/REPL window
    • calva:cursorInString: true when the cursor/caret is in a string or a regexp
    • calva:cursorInComment: true when the cursor is in, or adjacent to a line comment
    • calva:cursorBeforeComment: true when the cursor is adjacent before a line comment
    • calva:cursorAfterComment: true when the cursor is adjacent after a line comment
    • calva:cursorAtStartOfLine: true when the cursor is at the start of a line including any leading whitespace
    • calva:cursorAtEndOfLine: true when the cursor is at the end of a line including any trailing whitespace
    "},{"location":"why-calva/","title":"Why Calva?","text":"

    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

    "},{"location":"why-calva/#nick-cernis-on-clojureverse","title":"Nick Cernis on ClojureVerse","text":"

    My advice to anyone starting their Clojure journey who is unsure about what editor to use:

    • Pick something today and start writing Clojure.
    • Probably pick an editor you are familiar with already.
    • If you\u2019re not familiar with any editor yet or you don\u2019t have a strong allegiance to one, choose VS Code and Calva.
    • Switch to something else only if you encounter persistent annoyances that you can\u2019t remove with plugins, code/config changes, help from the community, or more sleep.

    I now use VS Code with Calva every day but went through a long journey trying almost every other editor and plugin combo first. I switched from Emacs to VS Code, which might make my perspective different to others here.

    \u2026

    I started with the jaded assumption that VS Code was probably bad because it's built by committee at Microsoft on a web-tech based Electron stack, only to find that it succeeds in embodying the spirit of a \u201chacker's editor\u201d more than even Emacs does in many ways:

    \u2026

    On the benefits of Calva:

    • Of all the amazing Clojure community projects, Calva seems most likely to encourage new users to try Clojure and ClojureScript. A lot of developers use VS Code. It\u2019s been tricky to convince frontend developer friends to try ClojureScript, but at least they don\u2019t have the excuse that they\u2019ll need to switch editors to even try it now. I think as a community we should try to support the projects that encourage Clojure\u2019s adoption and ease of use, including by using those products ourselves.

    • Calva provides a better first-time experience than any other editor/plugin combo whether you\u2019re new to Clojure or not. You can install the plugin and be chatting with your REPL in under a minute without any knowledge of Elisp or VimScript/Lua or how to configure Run Configurations in IntelliJ.

    • The default key bindings are good and the commands are easily discoverable.
    • For its age it\u2019s surprisingly feature rich.
    "},{"location":"why-calva/#100-five-star-marketplace-reviews","title":"100% Five-star Marketplace Reviews","text":"

    We are super proud of the Calva reviews on the Visual Studio Code Marketplace. Please read them all. \ud83d\ude04 Here's a selection that we think captures what we focus on in when developing Calva:

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f Calva has become an essential part of my Clojure workflow.

    It's an incredible piece of work by the team behind it.

    Sean Corfield

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f Calva hits the sweet spot of being both approachable for new users and powerful for seasoned ones.

    The creators/maintainers are fantastic individuals that care deeply about streamlining the user experience, and it shows.

    Good stuff, check it out.

    Clay Hopperdietzel

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f I switched from IntelliJ / Cursive to VS Code and Calva and it's been amazing.

    ...

    That is the biggest thing I can say for Calva, it just works. I was never a fan of VS Code before, but VS Code + Calva for Clojure is now my favorite language / IDE experience.

    Plus, the #calva on the clojurians slack is brilliant, always someone there to help if you have issues (although any issue I've had has been squarely on me, and never Calva itself).

    I often feel we live in an age where so much software is badly written, without care, slow, buggy and just generally awful. Calva is the complete opposite. I think the maintainers want to, and have, made a wonderful piece of software for Clojure developers.

    Stuart Stein

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f This is great, and makes VS Code a truly viable IDE/editor for clojure development.

    It already has great REPL support (including inline evaluation), an extensive Paredit implementation, and excellent linting (care of the bundled clj-kondo). Calva is being improved on at an impressive clip by maintainers who appear solidly committed to its ongoing development. It's well-documented, and manages to be both approachable and capable.

    A no-brainer if you're already a VS Code user, and well worth a look if you're not.

    Crispin Bennett

    \u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\u2605\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f I'm using Calva now for a few months and I'm loving it.

    I joined the Slack channel about 2 wks ago and I must say that I'm very impressed by how active and responsive this community is. Already 2 of my issues fixed and I really like Calva (and the extensions it uses!).

    These are professional people and they make me very happy!

    Uitbeijerse, E (Eric)

    "},{"location":"workspace-layouts/","title":"Workspace Layouts","text":"

    Project directory layouts can vary quite a lot. From the \u201dtemplate\u201d projects where the Clojure project files are at the root, to, well, let's just say that the project files are not always at the root. And sometimes there is more than one project (read here how to get clojure-lsp support with a Leiningen project in a subfolder).

    Calva only really supports working with one project at a time per VS Code window. Here's a short guide for some different setups:

    1. You have one project in the workspace, the project files are in there somewhere.
      • Use a regular VS Code \u201dfolder window\u201d or a Workspace proper, both will totally work.
    2. You have more than one project in the repository, but only really work with one at a tine.
      • Use a Workspace proper and add the different project directories as separate Workspace Folders.
      • You can only jack-in/connect to one project at a time.
    3. You have more than one project in the repository, and need to work with them in parallell.
      • Open each project you want to work with in a separate VS Code window.
    "},{"location":"workspace-layouts/#one-folder-two-windows","title":"One Folder - Two Windows?","text":"

    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:

    1. Open a new VS Code window.
    2. Select File->Add Folder to Workspace.... Save the workspace as, say, Server.code-workspace.
    3. Open a new VS Code window.
    4. Select File->Add Folder to Workspace.... Save the workspace as, say, Client.code-workspace.

    Now, whenever you want to Jack-in to the backend and/or frontend, do it from the Server and/or Client workspace, respectively.

    "},{"location":"wsl/","title":"Calva \u2764\ufe0f WSL","text":"

    The use of Calva with WSL (Windows Subsystem for Linux) is fully supported through the Remote - WSL extension. Simply install the extension and open your project with one of the Remote-WSL commands. Calva will run directly in the WSL environment and no further configuration is required.

    "},{"location":"wsl/#steps-involved","title":"Steps Involved","text":"
    1. Enable WSL
    2. Install Ubuntu in WSL
    3. Install Java in WSL
    4. Install latest Clojure in WSL
    5. Install the Remote - WSL extension in VS Code
    6. Launch remote window
    7. Install Calva (gets installed into the WSL instance)
    8. Work away

    See also Remote Development.

    "}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index cf91c6bd1..d07ae7930 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,307 +2,307 @@ https://calva.io/ - 2024-04-26 + 2024-04-27 daily https://calva.io/api/ - 2024-04-26 + 2024-04-27 daily https://calva.io/async-out/ - 2024-04-26 + 2024-04-27 daily https://calva.io/babashka/ - 2024-04-26 + 2024-04-27 daily https://calva.io/clj-java-decompiler/ - 2024-04-26 + 2024-04-27 daily https://calva.io/clojure-lsp/ - 2024-04-26 + 2024-04-27 daily https://calva.io/clojuredart/ - 2024-04-26 + 2024-04-27 daily https://calva.io/clojuredocs/ - 2024-04-26 + 2024-04-27 daily https://calva.io/commands-top10/ - 2024-04-26 + 2024-04-27 daily https://calva.io/connect-sequences/ - 2024-04-26 + 2024-04-27 daily https://calva.io/connect/ - 2024-04-26 + 2024-04-27 daily https://calva.io/contribute/ - 2024-04-26 + 2024-04-27 daily https://calva.io/custom-commands/ - 2024-04-26 + 2024-04-27 daily https://calva.io/customizing-jack-in-and-connect/ - 2024-04-26 + 2024-04-27 daily https://calva.io/customizing/ - 2024-04-26 + 2024-04-27 daily https://calva.io/debugger/ - 2024-04-26 + 2024-04-27 daily https://calva.io/emacs-keybindings/ - 2024-04-26 + 2024-04-27 daily https://calva.io/eval-tips/ - 2024-04-26 + 2024-04-27 daily https://calva.io/evaluation/ - 2024-04-26 + 2024-04-27 daily https://calva.io/fiddle-files/ - 2024-04-26 + 2024-04-27 daily https://calva.io/finding-commands/ - 2024-04-26 + 2024-04-27 daily https://calva.io/formatting/ - 2024-04-26 + 2024-04-27 daily https://calva.io/get-started-with-clojure/ - 2024-04-26 + 2024-04-27 daily https://calva.io/getting-started/ - 2024-04-26 + 2024-04-27 daily https://calva.io/hiccup/ - 2024-04-26 + 2024-04-27 daily https://calva.io/inspector/ - 2024-04-26 + 2024-04-27 daily https://calva.io/jack-in-guide/ - 2024-04-26 + 2024-04-27 daily https://calva.io/joyride/ - 2024-04-26 + 2024-04-27 daily https://calva.io/krell/ - 2024-04-26 + 2024-04-27 daily https://calva.io/linting/ - 2024-04-26 + 2024-04-27 daily https://calva.io/live-share/ - 2024-04-26 + 2024-04-27 daily https://calva.io/luminus/ - 2024-04-26 + 2024-04-27 daily https://calva.io/merch/ - 2024-04-26 + 2024-04-27 daily https://calva.io/namespace-form-auto-creation/ - 2024-04-26 + 2024-04-27 daily https://calva.io/nbb/ - 2024-04-26 + 2024-04-27 daily https://calva.io/notebooks/ - 2024-04-26 + 2024-04-27 daily https://calva.io/nrepl_and_cider-nrepl/ - 2024-04-26 + 2024-04-27 daily https://calva.io/output/ - 2024-04-26 + 2024-04-27 daily https://calva.io/paredit/ - 2024-04-26 + 2024-04-27 daily https://calva.io/parinfer/ - 2024-04-26 + 2024-04-27 daily https://calva.io/polylith/ - 2024-04-26 + 2024-04-27 daily https://calva.io/pprint/ - 2024-04-26 + 2024-04-27 daily https://calva.io/quirks/ - 2024-04-26 + 2024-04-27 daily https://calva.io/re-frame-template/ - 2024-04-26 + 2024-04-27 daily https://calva.io/rebl/ - 2024-04-26 + 2024-04-27 daily https://calva.io/refactoring/ - 2024-04-26 + 2024-04-27 daily https://calva.io/remote-development/ - 2024-04-26 + 2024-04-27 daily https://calva.io/repl-window/ - 2024-04-26 + 2024-04-27 daily https://calva.io/reveal/ - 2024-04-26 + 2024-04-27 daily https://calva.io/rich-comments/ - 2024-04-26 + 2024-04-27 daily https://calva.io/shadow-cljs/ - 2024-04-26 + 2024-04-27 daily https://calva.io/sponsors/ - 2024-04-26 + 2024-04-27 daily https://calva.io/syntax-highlighting/ - 2024-04-26 + 2024-04-27 daily https://calva.io/tao/ - 2024-04-26 + 2024-04-27 daily https://calva.io/test-runner/ - 2024-04-26 + 2024-04-27 daily https://calva.io/try-first/ - 2024-04-26 + 2024-04-27 daily https://calva.io/vim/ - 2024-04-26 + 2024-04-27 daily https://calva.io/when-clauses/ - 2024-04-26 + 2024-04-27 daily https://calva.io/why-calva/ - 2024-04-26 + 2024-04-27 daily https://calva.io/workspace-layouts/ - 2024-04-26 + 2024-04-27 daily https://calva.io/wsl/ - 2024-04-26 + 2024-04-27 daily \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 36d0ce4595be6d57ab9525905afadd1f9c42076d..d1389c5a1cb109551fee2049511b5c3d143f687d 100644 GIT binary patch delta 667 zcmV;M0%ZNI1+4`JABzYGinx&mAb&s~aGYJfpj`(PHIiua6+Wb>U*D0Ev{`mlTmgba zf}jq_!JRwQ>G9Rs-NY%I;2-w4hvR<7UWd;3;bH&t#}j?sKb~(+HQCH%Cxd-{*pH>e z?@cq$^C6qUPQ`o(X=t(@rIDNW&gOXdwm;wOEqjzB}IC)A63}zQ~aGzE8vSsQkcv;+J!$j9pI6r=GXZH-EnWPb4ZDB$~W< zO`#SbrdG8ok5>hRr0s<+YEsm(4lWwY35qUUYGSfE;!$-f6+o(>GZIyBPWdiV3Gwy_ z1?D~LLYZHxh&N|EHY}o&On+MoBSF<%f}@WRgCjG)#1M$O>MI#ff=GZH`BR{d1;MbjUH0C@uVyj6VaHeD&mlVpnB7FmZ=w;lcBJ-kU~_lJ|w3~!IFo8 zC2tq8U)<4b%1H0t2Mcjsv=2-mve9T=k?gebIZ9FtNNWF)w1;Xsq<^rwge74ST@zai z#AA&IQ!8sGraUSreX`XVUy(A6tJ delta 667 zcmV;M0%ZNI1+4`JABzYG#uJeSAb%*@!f|%_f_5EH)JUSuSNM>ketkzu(q`FJaRmqx z34%Hx2Y2pJr^i=kcN3> zwfplZm5U4A`R;gkPse+@`yxZ$`#ufRqw)jyiC@m0GIlvNpL*Ut-~9RhKar?tkZAJa zHHBJ$m|E4UJYE$LlC~GRs7X=BI=E;oCn&mbsfo$vh)30_Q~;@h&PY_jIpw=dCB)k! z6qxs{3uS((BHo|atKs*c+_ z3{a^^yqV5)<)t-#HF`+l#*?yCOhjX$DI>jmA1uUm(LOMN$VQ`eMY7Yz=O{@rAgTRF(jKbmkblDJ5|)HTbWLn6 z5RWw;Os%Y$nDVHg^vPCdd_~GMj*}jNc)W6)qtap*BnOhJC6G>xW@&ueBGH7xZ3tJS z!19TseHLH!tVKE#ZEYaFP)me5ri>z0odF{yIWtEV&?WLLoB?U>u zJc+JTVHd4}I?YPlT7M{>O!(fuf4R=a8U~7GKmWjb<3F++gKaQAj_<3+FF9JhB%lP&GrH6wl*ATLXzHh{@XuWvdn`W}wz9|A)-CJq$9J^KUnMdb1fM0066! BK$8Ff