Skip to content

Commit 650c3d6

Browse files
authored
Merge pull request #11 from clojure-lsp/clojure-lsp-native
Use Clojure lsp native
2 parents 3c6359a + 134e3ca commit 650c3d6

File tree

7 files changed

+113
-34
lines changed

7 files changed

+113
-34
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
- Fix --settings flag
6+
- Replace clojure-lsp JVM with native binary for way better performance.
7+
58
## 1.4.21
69

710
## 1.4.20

project.clj

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,4 @@
99
:username :env/clojars_username
1010
:password :env/clojars_password
1111
:sign-releases false}]]
12-
:managed-dependencies [[com.fasterxml.jackson.core/jackson-core "2.18.0"]
13-
[org.clojure/tools.cli "1.1.230"]]
14-
:dependencies [[com.github.clojure-lsp/clojure-lsp-server "2025.03.27-20.21.36" :exclusions [babashka/fs
15-
cheshire
16-
org.jetbrains.kotlin/kotlin-stdlib-jdk7
17-
com.fasterxml.jackson.dataformat/jackson-dataformat-smile
18-
com.fasterxml.jackson.dataformat/jackson-dataformat-cbor
19-
org.jetbrains.kotlin/kotlin-stdlib
20-
org.jetbrains.kotlin/kotlin-stdlib-jdk8
21-
org.jetbrains.kotlin/kotlin-stdlib-jdk7
22-
io.opentelemetry/opentelemetry-context
23-
io.opentelemetry/opentelemetry-api
24-
org.clojure/tools.reader]]
25-
[cheshire/cheshire "5.13.0"]
26-
[babashka/fs "0.5.21"]
27-
[com.fasterxml.jackson.dataformat/jackson-dataformat-smile "2.18.0"]
28-
[com.fasterxml.jackson.dataformat/jackson-dataformat-cbor "2.18.0"]
29-
[org.clojure/tools.reader "1.5.0"]])
12+
:dependencies [[babashka/process "0.6.23"]])

resources/CLOJURE_LSP_VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2025.03.27-20.21.36

scripts/lein_clojure_lsp/ci.clj

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@
4646
(defn tag-patch-for-version [& [version]]
4747
(shell "git fetch origin")
4848
(shell "git pull origin HEAD")
49-
(replace-in-file "project.clj"
50-
#"com.github.clojure-lsp/clojure-lsp-server \".*\""
51-
(format "com.github.clojure-lsp/clojure-lsp-server \"%s\"" version))
49+
(spit "resources/CLOJURE_LSP_VERSION" version)
5250
(let [new-tag (get-patched-tag)]
5351
(replace-tag new-tag)
5452
(add-changelog-entry new-tag (str "Bump clojure-lsp to " version))

src/leiningen/clojure_lsp.clj

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
(:refer-clojure :exclude [run!])
33
(:require
44
[clojure.edn :as edn]
5-
[clojure-lsp.main :as lsp]
6-
[leiningen.core.main :as lein-core]))
5+
[leiningen.core.main :as lein-core]
6+
[leiningen.clojure-lsp.binary :as lsp-binary]))
77

88
(defn ^:private has-settings?
99
[command-and-options]
@@ -20,24 +20,22 @@
2020
(defn args
2121
[command-and-options project-settings]
2222
(cond
23-
(and (not-empty project-settings) (has-settings? command-and-options))
23+
(and (not-empty project-settings)
24+
(has-settings? command-and-options))
2425
(args-with-merged-settings command-and-options project-settings)
2526

2627
(not-empty project-settings)
27-
(concat command-and-options ["--settings" (str project-settings)])
28+
(concat command-and-options ["--settings" (str (:settings project-settings))])
2829

2930
:else
3031
command-and-options))
3132

3233
(defn ^:private run!
3334
[command-and-options project-settings]
34-
(let [result (apply lsp/run! (args command-and-options project-settings))]
35-
(when-let [message-fn (:message-fn result)]
36-
(println (message-fn)))
37-
(when (not= 0 (:result-code result))
38-
(lein-core/exit (:result-code result) "clojure-lsp found issues"))))
35+
(let [{:keys [exit]} (lsp-binary/run! (args command-and-options project-settings))]
36+
(when (not= 0 exit)
37+
(lein-core/exit exit "clojure-lsp found issues"))))
3938

40-
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
4139
(defn ^:no-project-needed clojure-lsp
4240
"Access clojure-lsp API features"
4341
[project & command-and-options]

src/leiningen/clojure_lsp/binary.clj

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
(ns leiningen.clojure-lsp.binary
2+
(:refer-clojure :exclude [run!])
3+
(:require
4+
[babashka.process :as process]
5+
[clojure.java.io :as io]
6+
[clojure.string :as string])
7+
(:import
8+
[java.io BufferedReader File]
9+
[java.util.zip ZipInputStream]))
10+
11+
(set! *warn-on-reflection* true)
12+
13+
(defn ^:private global-cache-dir []
14+
(let [cache-home (or (System/getenv "XDG_CACHE_HOME")
15+
(io/file (System/getProperty "user.home") ".cache"))]
16+
(io/file cache-home "lein-clojure-lsp")))
17+
18+
(def ^:private download-artifact-uri
19+
"https://github.com/clojure-lsp/clojure-lsp/releases/download/%s/%s")
20+
21+
(defn ^:private os-name []
22+
(let [os-name (string/lower-case (System/getProperty "os.name" "generic"))]
23+
(cond
24+
(string/includes? os-name "win") :windows
25+
(string/includes? os-name "mac") :macos
26+
:else :linux)))
27+
28+
(defn ^:private os-arch []
29+
(if (= "aarch64" (System/getProperty "os.arch"))
30+
:aarch64
31+
:amd64))
32+
33+
(def ^:private artifacts
34+
{:linux {:amd64 "clojure-lsp-native-static-linux-amd64.zip"
35+
:aarch64 "clojure-lsp-native-linux-aarch64.zip"}
36+
:macos {:amd64 "clojure-lsp-native-macos-amd64.zip"
37+
:aarch64 "clojure-lsp-native-macos-aarch64.zip"}
38+
:windows {:amd64 "clojure-lsp-native-windows-amd64.zip"}})
39+
40+
(defn ^:private unzip-file [input ^File dest-file]
41+
(with-open [stream (-> input io/input-stream ZipInputStream.)]
42+
(loop [entry (.getNextEntry stream)]
43+
(when entry
44+
(if (.isDirectory entry)
45+
(when-not (.exists dest-file)
46+
(.mkdirs dest-file))
47+
(clojure.java.io/copy stream dest-file))
48+
(recur (.getNextEntry stream))))))
49+
50+
(defn ^:private download! [^File download-path version]
51+
(let [platform (os-name)
52+
arch (os-arch)
53+
artifact-name (get-in artifacts [platform arch])
54+
uri (format download-artifact-uri version artifact-name)]
55+
(io/make-parents download-path)
56+
(unzip-file (io/input-stream uri) download-path)
57+
(doto download-path
58+
(.setWritable true)
59+
(.setReadable true)
60+
(.setExecutable true))))
61+
62+
(defn ^:private server-version []
63+
(string/trim (slurp (io/resource "CLOJURE_LSP_VERSION"))))
64+
65+
(defn ^:private server-path ^File []
66+
(io/file (global-cache-dir) "clojure-lsp"))
67+
68+
(defn ^:private run-lsp! [^File path args]
69+
(let [p (process/process {:cmd (concat [(.getAbsolutePath path)] args)})]
70+
(future
71+
(with-open [out-rdr ^BufferedReader (io/reader (:out p))]
72+
(loop []
73+
(when-let [line (.readLine out-rdr)]
74+
(println line)
75+
(recur)))))
76+
(future
77+
(with-open [out-rdr ^BufferedReader (io/reader (:err p))]
78+
(binding [*out* *err*]
79+
(loop []
80+
(when-let [line (.readLine out-rdr)]
81+
(println line)
82+
(recur))))))
83+
@p))
84+
85+
(defn run! [args]
86+
(let [server-path (server-path)
87+
server-version (server-version)]
88+
(when-not (.exists server-path)
89+
(binding [*out* *err*]
90+
(println "Downloading and caching clojure-lsp to" (str server-path)))
91+
(let [t (System/currentTimeMillis)]
92+
(download! server-path server-version)
93+
(binding [*out* *err*]
94+
(println (format "Downloaded clojure-lsp took %sms" (- (System/currentTimeMillis) t))))))
95+
(run-lsp! server-path args)))

test/leiningen/clojure_lsp_test.clj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(ns leiningen.clojure-lsp-test
2-
(:require [clojure.test :refer :all]
3-
[leiningen.clojure-lsp :as clojure-lsp]))
2+
(:require
3+
[clojure.test :refer :all]
4+
[leiningen.clojure-lsp :as clojure-lsp]))
45

56
(deftest args-test
67
(testing "Should return the arguments when project settings is an empty map"
@@ -13,7 +14,7 @@
1314

1415
(testing "Should return the arguments when there is project settings"
1516
(is (= ["diagnostics" "--settings" "{:foo 1}"]
16-
(clojure-lsp/args ["diagnostics"] {:foo 1}))))
17+
(clojure-lsp/args ["diagnostics"] {:settings {:foo 1}}))))
1718

1819
(testing "Should return the arguments when there is settings options and also project settings"
1920
(is (= ["diagnostics" "--settings" "{:foo 1, :bar \"Test\"}"]

0 commit comments

Comments
 (0)