Liking cljdoc? Tell your friends :D

Settings

clojure-lsp settings are picked up only on server start and can be configured in 4 ways:

Project

clojure-lsp will look for project specific settings in a file called .lsp/config.edn. It will search from your project root folder up the directory structure so you can have multiple projects share the same settings.

Example:

{:cljfmt {:indents {#re ".*" ns [[:inner 0] [:inner 1]]}}
 :auto-add-ns-to-new-files? false}

Global

For global settings which should work for all the projects using clojure-lsp, you just need to add the same configs to ~/.config/clojure-lsp/config.edn or $XDG_CONFIG_HOME/clojure-lsp/config.edn.

Note: ~/.lsp/config.edn is considered too but deprecated.

For an example of a global config.edn, check here.


InitializationOptions

This is specific for a client, which it sends to clojure-lsp on startup, check LSP spec for more information. This is useful if you are changing a default for a client/editor that will affect all users of that editor.

This is an example how Emacs lsp-mode pass custom information.

Another example, for neovim users, using coc.nvim and coc-clojure can be found here

If you are using a client which defines InitializationOptions as a json object, you can use json types instead:

  • keyword -> string or colon-prefixed string ("incremental" or ":incremental")
  • map -> object ({"unused-public-ns": {"level": "info"}})
  • set -> array (["src" "test"])
  • vector -> array (["src" "test"])

Classpath config paths

When starting the server, clojure-lsp will search for a specific path clojure-lsp.exports/<group-id>/<artifact-id>/config.edn for extra configurations in the classpath, only if you set the setting :classpath-config-paths containing that group/artifact. Example:

Lib my-org/my-lib could have a clojure-lsp config edn that makes sense for the usages of that lib, making available on the classpath:

my-lib/resources/clojure-lsp.exports/my-org/my-lib/config.edn

{:cljfmt {:indents {foo [[:block 0]]}}}

and then if your project use/has the my-org/my-lib inside your classpath, you could add the setting

your-project/.lsp/config.edn

{:classpath-config-paths ["my-org/my-lib"]}

And then clojure-lsp will merge the configuration from the lib with the other configurations from your project.

This is useful if you have some rule to apply to clojure-lsp for multiple projects, mostly using via API for linting for example, and want to move the common configuration to some place instead of adding to each project that needs that.

All settings

You can find all settings and its default values here and below the docs for each one:

namedescriptiondefault
:cleanSettings related to clean-ns refactoring. Check Clean settings below.
:additional-snippetsAdditional user snippets to be available during completing, check the snippets section below[]
:api :exit-on-errors?Whether to exit the clojure-lsp process during api/cli call if any error is found, like classpath scan failuretrue
:auto-add-ns-to-new-files?Whether to automatically add the ns form in new blank files.true
:cache-pathWhere to store the project's analysis cache, used to speed up next clojure-lsp startup. A path relative to project root or an absolute path..lsp/.cache
:classpath-config-pathsList of extra configurations to load from classpath, for more info, check Classpath config paths section.[]
:cljfmt-config-pathWhere to find cljfmt configuration for formatting. A path relative to project root or an absolute path. Use #re for regex inside the cljfmt configuration file..cljfmt.edn
:cljfmtIf no :cljfmt-config-path is provided, used this for formatting, json encoded configuration for cljfmt{}
:code-lens :segregate-test-referencesSegregate main references from test references with option to disabletrue
:completion :additional-edits-warning-textA warning to show when the completion will perform additional edits, such as requiring a new alias. Appears in the completion items' documentation.nil
:copy-kondo-configs?Whether to copy clj-kondo hooks configs exported by libs on classpath during startup lint.true
:dependency-schemeDefines the format that the client and server should use for URLs of dependencies in jars. The two valid values are "jar" and "zipfile". Different editors may handle these URLs differently. For example, in nvim when a "zipfile" URI is opened, the file will be editable, but "jar" URIs will not be. (This can be powerful, but if you edit a jar in your .m2 directory, you may break other projects.) "jar" will make urls compatible with java's JarURLConnection. Clients that can't extract the jar natively can make an LSP extension request of clojure/dependencyContents with the jar uri and the server will return the jar entry's contents, an approach used by some Java clients"zipfile"
:document-formatting?if true or not present, document formatting is provided.true
:document-range-formatting?if true or not present, document range formatting is provided.true
:hover :arity-on-same-line?Whether to keep the arity on the same line of the function on hover, useful for Emacs users.false
:hover :clojuredocsWhether to get clojuredocs information on hover, the clojuredocs content is cached.true
:hover :hide-file-location?Whether to show the full filename and path on hover.false
:source-paths-ignore-regexlist of regex to filter source-paths. By default, source-paths are retrieved from classpath, and usually the classpath contains folders that are not directly project code or it's auto-generated like cljs resources or target folders but it's inside your project. Replace old :ignore-classpath-directories setting.["resources.*" "target.*"]
:java :download-jdk-source?Whether to download JDK source from :java :jdk-source-download-uri and cache after startup for JDK classes java support.false
:java :home-pathWhether to use this path to find JDK source and cache after startup for JDK classes java support.nil
:java :jdk-source-uriURI containing the JDK source to be used. If :download-jdk-source? is enabled and URI is NOT file:// then download the source. Check https://github.com/clojure-lsp/jdk-sourcefor more sources.https://raw.githubusercontent.com/clojure-lsp/jdk-source/main/openjdk-19/reduced/source.zip
:java :decompile-jar-as-project?Whether to decompile the whole jar as a java project when finding the definition of a java class, useful to navigate to other classes from that java class.true
:keep-parens-when-threading?Whether to keep parenthesis when threading single arity functions.false
:lint-project-files-after-startup?Whether to async lint all project only files after startup to make features like List project errors work.true
:lintersclojure-lsp custom linters, check the diagnostics settings section below
:log-pathA absolute path to a file where clojure-lsp should log.A JVM tmp path, usually /tmp/clojure-lsp.*.out
:notify-references-on-file-changeWhether to update diagnostics of the changed references when editing files, avoiding outdated diagnostics in other files.true
:project-specsA vector of a map with :project-path and :classpath-cmd, defining how clojure-lsp should find your project classpath. The :project-path should be a file and the :classpath-cmd the command to run to get the classpathCheck Classpath scan section below
:semantic-tokens?Whether to enable LSP semantic tokens server support for syntax highlighting.true
:source-aliasesUsed for deps.edn or project.clj projects, the aliases which clojure-lsp should get the source-paths besides the root level :paths and :extra-paths. Check the Source paths discovery section below.#{:dev :test}
:source-pathsproject-local directories to look for clj/cljc/cljs files, if using deps.edn, project.clj or bb.edn, use :source-aliases instead.#{"src" "test"}
:stubsStub generation related settings, check the Stub generation section below.
:text-document-sync-kindThe sync kind during document changes, if client should send whole buffer or just related changes. Should be :full or :incremental:full
:use-metadata-for-privacy?Whether to use ^:private metadata for refactorings instead of defn-false

Classpath scan

clojure-lsp needs to analyze the whole project and its dependencies to understand your code for most features, during the startup clojure-lsp will try to find the classpath of your project to pass to clj-kondo later.

You can configure how clojure-lsp should find the classpath with the project-specs setting, but keep in mind that usually the default is enough, it will also consider the :source-aliases setting if any to find the classpath using those aliases.

Supported project types at the moment are:

  • leiningen: If a project.clj is found at the project root, clojure-lsp will run lein classpath with :source-aliases specified if any.
  • deps: If a deps.edn is found at the project root, clojure-lsp will run clojure -Spath with :source-aliases specified if any.
  • boot: If a build.boot is found at the project root, clojure-lsp will run boot show --fake-classpath.
  • shadow-cljs: If a shadow-cljs.edn is found at the project root, clojure-lsp will run npx shadow-cljs classpath.
  • babashka: If a bb.edn is found at the project root, clojure-lsp will run bb print-deps --format classpath.

Note that it's possible to have more and one project type at the same time e.g. deps + babashka, clojure-lsp will merge the classpath and everything should works fine.

Make sure to have these programs available on the PATH environment variable used by your editor, otherwise clojure-lsp will warn about a classpath scan fail, causing a lot of features to not work properly.

Alternatively, you can configure the project-specs specific for your project, for example:

.lsp/config.edn

{:project-specs [{:project-path "deps.edn"
                  :classpath-cmd ["clojure" "-A:my-custom-alias" "-Spath"]}]}

Note that clojure-lsp will make this scan to save the cache when:

  • The project has no cache (.lsp/.cache)
  • The project deps file (project.clj for example) changed.
  • The clj-kondo config has changed.

Diagnostics (linter)

Default: Check :linters in all-available-settings.edn.

clj-kondo

clojure-lsp uses clj-kondo under the hood to lint the code and retrieve the analysis to make most of features work, you don't have to install clj-kondo to make it work.

clojure-lsp will use a specific clj-kondo version that can be retrieved via clojure-lsp --version, but make sure you have it properly configured in your .clj-kondo/config.edn file.

It has the possible key/values:

  • :clj-kondo
    • :level with available values: :off, :on with default value of :on
    • :report-duplicates which will show all linters of the same symbol instead of showing only the first spot. Available values: true, false with default value of true
    • ns-exclude-regex which will exclude the diagnostics/findings for namespaces that match this regex.

Example:

.lsp/config.edn

{:linters {:clj-kondo {:level :on
                       :report-duplicates true
                       :ns-exclude-regex "some-ns.*"}}}
Note for vim users

If you are a (neo)vim user and have ale installed as a plugin, you should not have this configured as a linter let g:ale_linters = {'clojure': ['clj-kondo']} in your vimrc. Having this linter enabled via ale will only conflict with the built-in clj-kondo bundled with clojure-lsp.

Also, clojure-lsp by default pass copy-configs flag as true to clj-kondo to copy configurations exported from libs on classpath, to disable this behavior, set copy-kondo-configs? setting to false.

For more information about all clj-kondo available configurations, check the clj-kondo configuration section

Custom clj-kondo linters

Clojure-lsp register custom linters in clj-kondo, for specifically those linters, configurations should be done on clj-kondo config files, e.g. (<project>/.clj-kondo/config.edn), below are the custom linters used:

clojure-lsp/unused-public-var

A custom linter that reports public functions/vars not used over the project.

It has the possible key/values:

  • :level with available values: :info, :warning, :error or :off with default value of :info.
  • :exclude a whole namespace with #{my-ns} or a specific var #{my-ns/foo}.
  • :exclude-when-defined-by excludes this linter when your var is defined by a macro for example, like #{my-ns/deftest}.

Example:

.clj-kondo/config.edn

{:linters {:clojure-lsp/unused-public-var {:level :warning
                                           :exclude #{my-ns/foo
                                                      my-ns/bar
                                                      other-ns
                                                      my-func}
                                           :exclude-regex #{"my-integration-tests.*"}
                                           :exclude-when-defined-by #{my-ns/defflow}
                                           :exclude-when-defined-by-regex #{"my.custom/macro-.*"}}}}

clj-depend

clojure-lsp uses clj-depend when any clj-depend config is found either on clojure-lsp config or as a .clj-depend/config.edn file.

Disable linter

It's not recommended to disable a linter as it provides helpful smart checks/suggestions for your code, even so it's possible via the following config:

.lsp/config.edn

{:linters {:clj-kondo {:level :off}
           :clj-depend {:level :off}}}

For information on how to troubleshoot the linter, check the troubleshooting section

Source paths discovery

Some features require know the available source paths of your project, where your code lives, clojure-lsp has some settings for that.

  • By default, clojure-lsp will infer source-paths from the classpath, excluding files that are jar and not under project-root, this usually works for most cases, if not, check next items.

  • You can specify a source-aliases setting, making clojure-lsp use those alias when conmputing the classpath, e.g. #{:src :test :my-alias}

  • If that is not enough, for example you have source-paths that are not included on any project profile (not recommended), you can manually specify via the :source-paths settings. e.g ["src" "test" "my/other/folder"].

Clean

Default: Check :clean in all-available-settings.edn.

automatically-after-ns-refactor

Whether to call clean-ns on the namespace after applying any refactor to it like adding missing require/imports/refers.

ns-inner-blocks-indentation

How to indent ns children forms like require,import.

next-line

Keep first child on the next line of :require/:import and next children following the same indentation. Recommended by how-to-ns guide too. Check ;; better on Clojure Style Guide.

same-line

Keep first child on the same line of :require/:import and next children following the same indentation. Check ;; good on Clojure Style Guide.

keep

Don't change indentation at all, keeping the one user selected first.

ns-import-classes-indentation

How to indent classes inside package imports from :import form. Note: package imports with only one class will keep indentation: Ex: [java.io File]

next-line

Keep the first class inside a package import on the next line and next children following the same indentation. Ex:

(:import 
  [java.io
    File
    Foo])
same-line

Keep the first class inside a package import on the same line and next children following the same indentation. Ex:

(:import 
  [java.io File
           Foo])

sort

to disable a specific import you can set it to nil, example:

{:clean {:sort {:import-classes nil}}}
ns

Whether to enable sort of ns children like require, import forms following Clojure Style Guide.

require

Whether to enable sort of :require form. true to sort according to the Clojure Style Guide, :lexicographically to do a lexicographic sort that places unwrapped namespaces last.

import

Whether to enable sort of :import form.

import-classes

Whether to enable sort of package classes inside :import form.

  • :classes-per-line: the max classes allowed to keep in a single line, if more than this value, clojure-lsp will move all classes to :next-line or :same-line following :ns-import-classes-indentation.
refer

Whether to enable sort of :refer form.

  • :max-line-length: the max refers to keep at same line before breaking the line. Default 80.

Snippets

Besides the 19 built-in snippets, it's possible to configure custom additional snippets via :additional-snippets setting:

  • :name the name to use while completing to reach that snippet.
  • :detail Custom text to show along with the completion name.
  • :snippet The body of the snippet, besides any text it can contains:
    • $1, $2, ... as the tabstops representing each place where user may change the content.
    • $0 as the last tabstop.
    • $current-form to replace the current form in the snippet.

Example:

{:additional-snippets [{:name "wrap-let-sexpr"
                        :detail "Wrap current sexpr in let"
                        :snippet "(let [$1] $0$current-form)"}]}

when completion is called on the code below with the cursor as |

wrap|(+ 1 2)

It should return a completion item that after applied should result in:

(let [|] (+ 1 2))

Java support

At the moment, clojure-lsp supports find definition of java classes only, methods, completion and other features are not supported yet.

When a find-definition of a java class is triggered, clojure-lsp checks the following:

  • If the java source(.java) is available on classpath, clojure-lsp just return that file location.
  • If the java source is not available, only the .class, clojure-lsp decompiles it.
    • If :java :decompile-jar-as-project? is enabled, clojure-lsp decompiles the whole jar at the global cache folder (~/.cache/clojure-lsp/java)
    • If :java :decompile-jar-as-project? is disabled, clojure-lsp decompiles the class file at the local cache folder (.lsp/.cache/java)
  • If the java class is from JDK (e.g. java.util.UUID), clojure-lsp tries a few things to be able to sucessfully find the definition, following this waterfall decision:
    • Most JRE installations contains the java source code in a src.zip, clojure-lsp tries to find it via :java :home-path setting if provided, JAVA_HOME env var or java command on PATH, if found clojure-lsp extracts to its global cache config (XDG_CONFIG or ~/.config/clojure-lsp) to be used in other projects.
    • If src.zip is not found or user specified a custom :java :jdk-source-uri, clojure-lsp tries to download the source from that uri, only if :java :download-jdk-source? is enabled, disabled by default, extracting to the global cache dir later.

Stub generation

It's possible to configure clojure-lsp to generate and analyze stubs for specific namespaces available on your project classpath, this is useful for closed source dependencies like datomic.api, with that clojure-lsp will be able to make most features work with those dependencies. The available settings inside :stubs are:

  • :generation for auto stubs generation:
    • :namespaces the namespaces to generate and analyze stubs, empty by default disabling stub generation.
    • :output-dir the output where to generate the stubs, by default .lsp/.cache/stubs
    • :java-command the path to java command to spawn the stub process, default use java from $PATH.
  • :extra-dirs, dirs to analyze to consider as part of manual generated stubs. Empty by default.

Example:

{:stubs {:generation {:namespaces #{"datomic.api"}}}}

This should generate stubs for datomic.api namespace only on .lsp/.cache/stubs and clojure-lsp should analyze that during startup to provide completion, hover and other features.

Or to use manual generated stubs:

{:stubs {:extra-dirs [".my-stubs"]}}

clojure-lsp will generate no stubs with that, but analyze that folder and consider it as manual generated stubs.

Can you improve this documentation? These fine people already did:
Eric Dallo, Jacob Maine, David Harrigan, Noah, John Practicalli, rvlo, Cora Sutton, dcfrankel, Case Nelson, Matthew Steedman & Oliver George
Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close