Calva

repository·published·Indexed 24 days ago

https://github.com/betterthantomorrow/calva

A comprehensive, REPL-driven IDE for Clojure and ClojureScript development within Visual Studio Code. Powered by cider-nrepl and clojure-lsp, it provides features including inline evaluation, structural editing via Paredit, linting with clj-kondo, and support for tools.deps, Leiningen, shadow-cljs, and Figwheel Main. The extension includes Calva Formatter for Clojure Style Guide compliance and integrates with Clojure Warrior for rainbow brackets and form styling.

Tokens
78.6K
Snippets
139
Records
407
Agent score
84%

What's inside Calva

  1. Overview of Calva features

    published

    Calva provides a comprehensive suite of IDE features for Clojure and ClojureScript development, including:

    • Inline code evaluation: Evaluate code directly within your editor.
    • Structural editing: Advanced editing capabilities (e.g., Paredit).
    • Code formatting: Automatically format your code.
    • Code navigation: Move through your codebase efficiently.
    • Debugger: Step through your code to find bugs.
    • Linting: Identify potential errors and style issues.
    • Syntax highlighting: Visual cues for code structure.
    • Rainbow brackets: Clojure-aware color-coded parentheses for easier reading.
    • Test runner: Execute and manage your tests.
    • Refactoring support: Tools to safely restructure your code.
  2. Clojure Warrior Features Overview

    published

    Clojure Warrior enhances Clojure development in VS Code with the following features:

    • Rainbow Brackets: Assigns distinct colors to brackets based on their nesting level. It handles strings, comments, and escaped characters correctly and highlights misplaced brackets.
    • Bracket Pair Matching: Highlights the corresponding bracket pair when the cursor is positioned outside an expression.
    • Form Styling: Provides visual styles for (comment ...) forms and #_... (ignored) forms.
  3. Why use Calva for Clojure development

    published

    Calva is a comprehensive IDE for Clojure and ClojureScript built specifically for Visual Studio Code. It is designed to be approachable for beginners while remaining powerful for professional developers.

    Key benefits include:

    • Low Barrier to Entry: You can install the plugin and start interacting with a REPL in under a minute without needing to learn complex configuration languages like Elisp, VimScript, or Lua.
    • VS Code Integration: Leverages the existing VS Code ecosystem, making it easy for developers already using VS Code to adopt Clojure without switching editors.
    • Feature Rich: Provides essential Clojure development features such as REPL support (including inline evaluation), extensive Paredit implementation, and excellent linting via bundled clj-kondo.
    • Discoverability: Features good default keybindings and easily discoverable commands.
  4. Core features of Calva

    published

    Calva provides a comprehensive suite of IDE features for Clojure development, including:

    • Code Evaluation: Inline evaluation of forms.
    • Structural Editing: Powered by Paredit for intelligent Lisp-style editing.
    • Navigation & Intelligence: Go to/peek definition, find all references, rename symbol, and Intellisense (including signature help and docstrings on hover).
    • Code Quality: Linting (via bundled clj-kondo), code formatting (following The Clojure Style Guide), and autoindent.
    • Visual Aids: Syntax highlighting, rainbow parens, rainbow indent guides, and dimming of ignored forms (#_) or (comment) forms.
    • Debugging & Testing: A built-in debugger and a test runner.
    • Project Support: Support for tools.deps, Leiningen, shadow-cljs, Figwheel Main, lein-figwheel, Clojurephant (Gradle), and built-in ClojureScript browser/node REPLs.
  5. Monitor REPL status in the Status Bar

    published

    The Calva status bar provides real-time feedback on your connection state and session type.

    Connection States

    • Disconnected (REPL $(zap) in gray): Click to open the REPL menu and start Jack-in or Connect.
    • Launching (Launching REPL using <method> in white): Click to interrupt the launch process.
    • Connecting (REPL - trying to connect): Click to interrupt the connection attempt.
    • Connected (REPL $(zap) in ember): Click to open the REPL menu for connection management. The tooltip shows the nrepl://hostname:port address.

    Session and Build Indicators

    • Session Type: Shows the active session (e.g., .cljc → clj). Clicking this opens the REPL Sessions menu to pin sessions or toggle Auto-route.
    • CLJS Build Selector: For Figwheel or shadow-cljs, shows the connected build name (e.g., :app). Click to switch builds.
    • Shadow-CLJS Runtime Selector: Shows the selected runtime (e.g., rt: 3). Click to open the runtime selection menu.
    • Pretty Print Toggle (pprint): Shows if pretty printing is enabled. Click to toggle.
  6. What is Calva Paredit?

    published

    Calva Paredit provides structural editing, navigation, and selection for Clojure and ClojureScript. Instead of treating code as lines or characters, it operates on S-expressions (forms).

    For beginners, the most impactful commands to learn are:

    • Slurp Forward: Pulls the next form into the current form.
    • Barf Forward: Pushes the last form out of the current form.
  7. How Calva Jack-in connects to the REPL

    published

    When Calva issues the Jack-in shell command, it cannot read the stdout of that command to determine when the REPL is ready. Instead, it monitors the filesystem for specific port files to identify the nREPL port:

    • Standard: It looks for a .nrepl-port file.
    • shadow-cljs: It looks for .shadow-cljs/nrepl.port.

    Once the file is detected, Calva reads the port number and establishes the connection.

  8. Configure Connect Sequences

    published

    A Connect Sequence defines how Calva connects to a project. You can define custom sequences in your settings via calva.replConnectSequences to override defaults.

    Properties available for configuration:

    • name: The display name in menus.
    • projectType: The base configuration (e.g., deps.edn, Leiningen, shadow-cljs).
    • cljsType: The ClojureScript type (e.g., Figwheel Main, shadow-cljs, none).
    • replSessionNames: (Optional) Override default session names.
    • replSessionFilePatterns: (Optional) Override default file routing patterns.
    • nReplPortFile: (Optional) Override the port file location.
    • fallbackPort: (Optional) Override the fallback port.
  9. How session routing works in Calva

    published

    Calva uses a routing mechanism to determine which REPL session should handle a specific action (like evaluation or debugging) based on the current editor context. This allows users to interact with code without manually specifying which session to use.

    Resolution Priority

    When a command is triggered, Calva resolves the session in this order:

    1. Pinned Session: If the user has explicitly pinned a session to a file/context.
    2. REPL Window Session: If the active editor is a Calva REPL output window.
    3. Glob Pattern Matching: Matches the file path against session patterns (e.g., *.clj).
    4. First Available Session: A fallback to the first connected session.

    Glob Matching Tiers

    Glob patterns are categorized into three tiers that determine priority:

    • always-claim: Highest priority. Definitively claims files (e.g., *.clj for a Clojure session).
    • is-fallback-for: Middle priority. User-configured patterns used if no always-claim matches.
    • project-fallback: Lowest priority. Auto-generated catch-all patterns scoped to the project root.

    Note on Scoping: By default, patterns are scoped to the project root. To match files anywhere in the workspace (e.g., for Babashka), prefix the pattern with **/ (e.g., **/*.bb).

    import * as replSession from './nrepl/repl-session';
    
    // Gets session based on: pinned > repl window > glob match (with cljc-within-connection)
    const session = replSession.getSession();
    await session.eval(code, ns);
  10. How REPL session routing and file patterns work

    published

    Calva uses replSessionFilePatterns to route file evaluations to the correct REPL session. When multiple REPLs are connected, Calva determines which one should handle a file based on a hierarchy of specificity and tiering.

    Routing Logic

    1. Tiering: Patterns can be defined as simple strings (always always-claim) or as objects specifying always-claim and is-fallback-for tiers.
      • always-claim: Patterns in this tier take precedence.
      • is-fallback-for: Patterns in this tier are only used if no always-claim pattern matches.
    2. Specificity: Within a tier, Calva scores patterns. Literal path segments score higher than wildcards. The ** glob incurs a penalty.
    3. Connection Order: If specificity and tiering result in a tie, the first connected session wins.

    Workspace-wide Patterns

    By default, patterns are scoped to the project root of the connect sequence. To match files anywhere in the workspace, prefix the pattern with **/.

    Example: Babashka Fallback Configuration

    This configuration ensures Babashka handles .bb files primarily, but acts as a fallback for .clj files if no other REPL claims them:

    {
        "replSessionNames": { "primary": "bb" },
        "replSessionFilePatterns": {
            "primary": {
                "always-claim": ["*.bb", "bb.edn"],
                "is-fallback-for": ["**/*.clj", "**/*.bb", "**/bb.edn"]
            }
        }
    }
  11. How Alias Resolution works in Paredit

    published

    When Calva encounters an aliased form like p/let, it follows these steps:

    1. Extracts the alias ("p").
    2. Looks up the alias in the calva.paredit.aliasMap (e.g., "p" $\rightarrow$ "promesa.core").
    3. Resolves to the fully qualified form ("promesa.core/let").
    4. Matches against configured customPairForms.
    5. Enables pair-aware editing (selection, dragging, and structural navigation).