Liking cljdoc? Tell your friends :D

vis-lang-clojure

Clojure tools for Vis: zprint/cljfmt formatting, clj-kondo lint with the reflection and boxed-math pass, Lazytest and clojure.test runs, and nREPL evaluation with a managed REPL.

Vis knows nothing about Clojure. This extension does. The work happens in a Clojure library published to Clojars, so it runs on the JVM with your project's own classpath, deps.edn aliases, .zprint.edn and .clj-kondo configuration. A small Python package starts that library through the clojure CLI and speaks to it over stdio.

Install

vis-agent extension install Blockether/vis-lang-clojure --subdirectory extension --global --trust

You need the Clojure CLI and a JDK on PATH. The library itself is fetched from Clojars the first time a tool runs.

Tools

clj.format_code(["src"])                         # zprint, or cljfmt when that is the project's config
clj.format_code(source="(defn f [x](* x 2))")    # format a snippet, nothing written
clj.lint_code(["src"])                           # clj-kondo + reflection warnings
clj.run_tests(["test"])                          # Lazytest and clojure.test
clj.run_tests(["test/app/core_test.clj::adds"])  # one test
clj.repl_start(cwd="~/app", aliases=["dev"])     # a project nREPL for this session
clj.repl_eval("(+ 1 1)", cwd="~/app")            # evaluate in that REPL
clj.repl_connect(cwd="~/app", port=7888)         # or attach to an nREPL you already run
clj.repl_stop(cwd="~/app")

Tests reuse a running REPL when there is one, and otherwise run in a clean JVM.

How it works

extension/ is the Python side. It resolves the library's classpath once, in a cache directory of its own —

clojure -Sdeps '{:deps {com.blockether/vis-lang-clojure {:mvn/version "1.2.1"}}}' -Spath

— and then runs

java -cp "$classpath" clojure.main -m com.blockether.vis.lang.clojure.cli

once per project root, inside that project. Resolving away from the project is deliberate: your deps.edn decides what your REPL and your test runs see, never what these tools themselves run on, so a project pinning an older Clojure — or one whose dependencies come from a repository the tools cannot reach — still formats, lints and tests. The two sides exchange one JSON object per line with each other. The Clojure side (src/com/blockether/vis/lang/clojure/) does the real work and returns plain data, which the Python side turns into the result types from vis-lang-interface.

Inside a Vis sandbox

When Vis confines a session, a tool may write to the workspace and to Vis' own state directory, and everything it sends leaves through a local proxy that asks for a credential and terminates TLS with its own certificate authority. Programs that read https_proxy need nothing more, but a JVM takes its proxy from system properties and Maven takes its from settings.xml, so a confined Clojure run would fail to reach Clojars or Maven Central at all.

This extension prepares both before the JVM starts. You do not configure anything: it points the JVM at the proxy, builds a trust store from the sandbox's certificate bundle, and writes a settings.xml with the proxy and its credential. That settings.xml and the Maven repository a confined run downloads into live under ~/.vis/lang/vis-lang-clojure/<version>/jail, never in your own ~/.m2, so a sandboxed run neither reads your Maven setup nor writes to it — and the first confined build of a project downloads its dependencies again, into that directory.

Outside a sandbox there is no proxy in the environment, nothing is prepared, and your ~/.m2 is used exactly as before.

Development

clojure -M:test                                  # the Clojure library
vis-agent python -m pytest extension/tests -q    # the Python glue

To run the extension against this checkout instead of the released jar:

export VIS_LANG_CLOJURE_COMMAND="clojure -Sdeps '{:deps {com.blockether/vis-lang-clojure {:local/root \"$PWD\"}}}' -M -m com.blockether.vis.lang.clojure.cli"

That override brings its own classpath and is run as written, in the project directory, so — unlike the default command — it takes its classpath from that project's deps.edn too.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close