├── .github
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ ├── release.yml
│ └── upgrade-server.yml
├── .gitignore
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── build.rs
├── download-server
├── download-server-project
├── NuGet.config
└── ServerDownload.csproj
├── src
├── download_server.rs
├── lib.rs
├── main.rs
├── notification.rs
├── server.rs
└── server_version.rs
├── tests
└── integration_tests.rs
└── upgrade-server
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "cargo"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | pull_request:
5 | types: [ opened, reopened, synchronize ]
6 | branches:
7 | - main
8 |
9 | jobs:
10 | download-server:
11 | name: Download server
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v2
16 |
17 | - uses: actions/setup-dotnet@v4
18 | with:
19 | dotnet-version: '9.0.x'
20 |
21 | - name: Download language server
22 | run: ./download-server
23 |
24 | - name: Upload language server artifact
25 | uses: actions/upload-artifact@v4
26 | with:
27 | name: language-server
28 | path: language-server.zip
29 |
30 | build:
31 | name: Build
32 | needs: download-server
33 | runs-on: ${{ matrix.os }}
34 | strategy:
35 | matrix:
36 | os: [ubuntu-latest, macos-latest, windows-latest]
37 |
38 | steps:
39 | - name: Checkout code
40 | uses: actions/checkout@v4
41 |
42 | - name: Download language server artifact
43 | uses: actions/download-artifact@v4
44 | with:
45 | name: language-server
46 |
47 | - uses: actions/setup-dotnet@v4
48 | with:
49 | dotnet-version: '9.0.x'
50 |
51 | - name: Set up Rust
52 | uses: actions-rs/toolchain@v1
53 | with:
54 | toolchain: stable
55 | profile: minimal
56 | override: true
57 |
58 | - name: Check format
59 | run: cargo fmt --check
60 |
61 | - name: Clippy
62 | run: cargo clippy
63 |
64 | - name: Build
65 | run: cargo build
66 |
67 | - name: Run tests
68 | run: cargo test
69 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | release:
5 | types: [created]
6 |
7 | jobs:
8 | download-server:
9 | name: Download server
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout code
13 | uses: actions/checkout@v2
14 |
15 | - uses: actions/setup-dotnet@v4
16 | with:
17 | dotnet-version: '9.0.x'
18 |
19 | - name: Download language server
20 | run: ./download-server
21 |
22 | - name: Upload language server artifact
23 | uses: actions/upload-artifact@v4
24 | with:
25 | name: language-server
26 | path: language-server.zip
27 |
28 | release:
29 | needs: download-server
30 | name: release ${{ matrix.target }}
31 | strategy:
32 | matrix:
33 | include:
34 | - target: x86_64-unknown-linux-gnu
35 | os: ubuntu-latest
36 | - target: x86_64-apple-darwin
37 | os: macos-latest
38 | - target: aarch64-apple-darwin
39 | os: macos-latest
40 | - target: x86_64-pc-windows-msvc
41 | os: windows-latest
42 | runs-on: ${{ matrix.os }}
43 | steps:
44 | - uses: actions/checkout@v4
45 |
46 | - name: Download language server artifact
47 | uses: actions/download-artifact@v4
48 | with:
49 | name: language-server
50 |
51 | - uses: actions/setup-dotnet@v4
52 | with:
53 | dotnet-version: '9.0.x'
54 |
55 | - name: Download language server
56 | run: ./download-server
57 |
58 | - uses: taiki-e/upload-rust-binary-action@v1
59 | with:
60 | bin: csharp-language-server
61 | target: ${{ matrix.target }}
62 | zip: all
63 | token: ${{ secrets.GITHUB_TOKEN }}
64 |
--------------------------------------------------------------------------------
/.github/workflows/upgrade-server.yml:
--------------------------------------------------------------------------------
1 | name: Upgrade Server
2 |
3 | on:
4 | schedule:
5 | - cron: '0 10 * * 0'
6 | workflow_dispatch:
7 |
8 | jobs:
9 | upgrade:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Checkout repository
14 | uses: actions/checkout@v2
15 |
16 | - uses: actions/setup-dotnet@v4
17 | with:
18 | dotnet-version: '9.0.x'
19 |
20 | - name: Run upgrade script
21 | id: upgrade
22 | run: |
23 | new_version=$(./upgrade-server)
24 | echo "new_version=$new_version" >> $GITHUB_ENV
25 |
26 | - name: Configure Git
27 | run: |
28 | git config --global user.name 'SofusA'
29 | git config --global user.email '${{ secrets.SOFUSAEMAIL}}'
30 |
31 | - name: Commit changes
32 | run: |
33 | git add .
34 | git commit -m "Automated server upgrade"
35 |
36 | - name: Create Pull Request
37 | uses: peter-evans/create-pull-request@v7
38 | with:
39 | token: ${{ secrets.REPO_SCOPED_TOKEN }}
40 | commit-message: Automated server upgrade
41 | branch: upgrade-server-branch
42 | title: "Automated Server Upgrade"
43 | body: "Upgrade the server to ${{ env.new_version }}"
44 |
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | out/
3 | language-server.zip
4 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 4
4 |
5 | [[package]]
6 | name = "addr2line"
7 | version = "0.24.2"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
10 | dependencies = [
11 | "gimli",
12 | ]
13 |
14 | [[package]]
15 | name = "adler2"
16 | version = "2.0.0"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
19 |
20 | [[package]]
21 | name = "aes"
22 | version = "0.8.4"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
25 | dependencies = [
26 | "cfg-if",
27 | "cipher",
28 | "cpufeatures",
29 | ]
30 |
31 | [[package]]
32 | name = "aho-corasick"
33 | version = "1.1.3"
34 | source = "registry+https://github.com/rust-lang/crates.io-index"
35 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
36 | dependencies = [
37 | "memchr",
38 | ]
39 |
40 | [[package]]
41 | name = "anstream"
42 | version = "0.6.18"
43 | source = "registry+https://github.com/rust-lang/crates.io-index"
44 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
45 | dependencies = [
46 | "anstyle",
47 | "anstyle-parse",
48 | "anstyle-query",
49 | "anstyle-wincon",
50 | "colorchoice",
51 | "is_terminal_polyfill",
52 | "utf8parse",
53 | ]
54 |
55 | [[package]]
56 | name = "anstyle"
57 | version = "1.0.10"
58 | source = "registry+https://github.com/rust-lang/crates.io-index"
59 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
60 |
61 | [[package]]
62 | name = "anstyle-parse"
63 | version = "0.2.6"
64 | source = "registry+https://github.com/rust-lang/crates.io-index"
65 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
66 | dependencies = [
67 | "utf8parse",
68 | ]
69 |
70 | [[package]]
71 | name = "anstyle-query"
72 | version = "1.1.2"
73 | source = "registry+https://github.com/rust-lang/crates.io-index"
74 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
75 | dependencies = [
76 | "windows-sys 0.59.0",
77 | ]
78 |
79 | [[package]]
80 | name = "anstyle-wincon"
81 | version = "3.0.7"
82 | source = "registry+https://github.com/rust-lang/crates.io-index"
83 | checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
84 | dependencies = [
85 | "anstyle",
86 | "once_cell",
87 | "windows-sys 0.59.0",
88 | ]
89 |
90 | [[package]]
91 | name = "anyhow"
92 | version = "1.0.98"
93 | source = "registry+https://github.com/rust-lang/crates.io-index"
94 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
95 |
96 | [[package]]
97 | name = "arbitrary"
98 | version = "1.4.1"
99 | source = "registry+https://github.com/rust-lang/crates.io-index"
100 | checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
101 | dependencies = [
102 | "derive_arbitrary",
103 | ]
104 |
105 | [[package]]
106 | name = "assert_cmd"
107 | version = "2.0.17"
108 | source = "registry+https://github.com/rust-lang/crates.io-index"
109 | checksum = "2bd389a4b2970a01282ee455294913c0a43724daedcd1a24c3eb0ec1c1320b66"
110 | dependencies = [
111 | "anstyle",
112 | "bstr",
113 | "doc-comment",
114 | "libc",
115 | "predicates",
116 | "predicates-core",
117 | "predicates-tree",
118 | "wait-timeout",
119 | ]
120 |
121 | [[package]]
122 | name = "autocfg"
123 | version = "1.4.0"
124 | source = "registry+https://github.com/rust-lang/crates.io-index"
125 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
126 |
127 | [[package]]
128 | name = "backtrace"
129 | version = "0.3.74"
130 | source = "registry+https://github.com/rust-lang/crates.io-index"
131 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
132 | dependencies = [
133 | "addr2line",
134 | "cfg-if",
135 | "libc",
136 | "miniz_oxide",
137 | "object",
138 | "rustc-demangle",
139 | "windows-targets",
140 | ]
141 |
142 | [[package]]
143 | name = "bitflags"
144 | version = "2.9.0"
145 | source = "registry+https://github.com/rust-lang/crates.io-index"
146 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
147 |
148 | [[package]]
149 | name = "block-buffer"
150 | version = "0.10.4"
151 | source = "registry+https://github.com/rust-lang/crates.io-index"
152 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
153 | dependencies = [
154 | "generic-array",
155 | ]
156 |
157 | [[package]]
158 | name = "bstr"
159 | version = "1.11.3"
160 | source = "registry+https://github.com/rust-lang/crates.io-index"
161 | checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
162 | dependencies = [
163 | "memchr",
164 | "regex-automata",
165 | "serde",
166 | ]
167 |
168 | [[package]]
169 | name = "bumpalo"
170 | version = "3.17.0"
171 | source = "registry+https://github.com/rust-lang/crates.io-index"
172 | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
173 |
174 | [[package]]
175 | name = "bytes"
176 | version = "1.10.1"
177 | source = "registry+https://github.com/rust-lang/crates.io-index"
178 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
179 |
180 | [[package]]
181 | name = "bzip2"
182 | version = "0.5.2"
183 | source = "registry+https://github.com/rust-lang/crates.io-index"
184 | checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
185 | dependencies = [
186 | "bzip2-sys",
187 | ]
188 |
189 | [[package]]
190 | name = "bzip2-sys"
191 | version = "0.1.13+1.0.8"
192 | source = "registry+https://github.com/rust-lang/crates.io-index"
193 | checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
194 | dependencies = [
195 | "cc",
196 | "pkg-config",
197 | ]
198 |
199 | [[package]]
200 | name = "cc"
201 | version = "1.2.24"
202 | source = "registry+https://github.com/rust-lang/crates.io-index"
203 | checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7"
204 | dependencies = [
205 | "jobserver",
206 | "libc",
207 | "shlex",
208 | ]
209 |
210 | [[package]]
211 | name = "cfg-if"
212 | version = "1.0.0"
213 | source = "registry+https://github.com/rust-lang/crates.io-index"
214 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
215 |
216 | [[package]]
217 | name = "cipher"
218 | version = "0.4.4"
219 | source = "registry+https://github.com/rust-lang/crates.io-index"
220 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
221 | dependencies = [
222 | "crypto-common",
223 | "inout",
224 | ]
225 |
226 | [[package]]
227 | name = "clap"
228 | version = "4.5.38"
229 | source = "registry+https://github.com/rust-lang/crates.io-index"
230 | checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
231 | dependencies = [
232 | "clap_builder",
233 | "clap_derive",
234 | ]
235 |
236 | [[package]]
237 | name = "clap_builder"
238 | version = "4.5.38"
239 | source = "registry+https://github.com/rust-lang/crates.io-index"
240 | checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
241 | dependencies = [
242 | "anstream",
243 | "anstyle",
244 | "clap_lex",
245 | "strsim 0.11.1",
246 | ]
247 |
248 | [[package]]
249 | name = "clap_derive"
250 | version = "4.5.32"
251 | source = "registry+https://github.com/rust-lang/crates.io-index"
252 | checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
253 | dependencies = [
254 | "heck",
255 | "proc-macro2",
256 | "quote",
257 | "syn",
258 | ]
259 |
260 | [[package]]
261 | name = "clap_lex"
262 | version = "0.7.4"
263 | source = "registry+https://github.com/rust-lang/crates.io-index"
264 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
265 |
266 | [[package]]
267 | name = "colorchoice"
268 | version = "1.0.3"
269 | source = "registry+https://github.com/rust-lang/crates.io-index"
270 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
271 |
272 | [[package]]
273 | name = "constant_time_eq"
274 | version = "0.3.1"
275 | source = "registry+https://github.com/rust-lang/crates.io-index"
276 | checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
277 |
278 | [[package]]
279 | name = "cpufeatures"
280 | version = "0.2.17"
281 | source = "registry+https://github.com/rust-lang/crates.io-index"
282 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
283 | dependencies = [
284 | "libc",
285 | ]
286 |
287 | [[package]]
288 | name = "crc32fast"
289 | version = "1.4.2"
290 | source = "registry+https://github.com/rust-lang/crates.io-index"
291 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
292 | dependencies = [
293 | "cfg-if",
294 | ]
295 |
296 | [[package]]
297 | name = "crossbeam-deque"
298 | version = "0.8.6"
299 | source = "registry+https://github.com/rust-lang/crates.io-index"
300 | checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
301 | dependencies = [
302 | "crossbeam-epoch",
303 | "crossbeam-utils",
304 | ]
305 |
306 | [[package]]
307 | name = "crossbeam-epoch"
308 | version = "0.9.18"
309 | source = "registry+https://github.com/rust-lang/crates.io-index"
310 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
311 | dependencies = [
312 | "crossbeam-utils",
313 | ]
314 |
315 | [[package]]
316 | name = "crossbeam-utils"
317 | version = "0.8.21"
318 | source = "registry+https://github.com/rust-lang/crates.io-index"
319 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
320 |
321 | [[package]]
322 | name = "crypto-common"
323 | version = "0.1.6"
324 | source = "registry+https://github.com/rust-lang/crates.io-index"
325 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
326 | dependencies = [
327 | "generic-array",
328 | "typenum",
329 | ]
330 |
331 | [[package]]
332 | name = "csharp-language-server"
333 | version = "0.6.0"
334 | dependencies = [
335 | "anyhow",
336 | "assert_cmd",
337 | "clap",
338 | "directories",
339 | "fs_extra",
340 | "futures",
341 | "rust_search",
342 | "serde",
343 | "serde_json",
344 | "tokio",
345 | "zip",
346 | ]
347 |
348 | [[package]]
349 | name = "deflate64"
350 | version = "0.1.9"
351 | source = "registry+https://github.com/rust-lang/crates.io-index"
352 | checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
353 |
354 | [[package]]
355 | name = "deranged"
356 | version = "0.4.0"
357 | source = "registry+https://github.com/rust-lang/crates.io-index"
358 | checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
359 | dependencies = [
360 | "powerfmt",
361 | ]
362 |
363 | [[package]]
364 | name = "derive_arbitrary"
365 | version = "1.4.1"
366 | source = "registry+https://github.com/rust-lang/crates.io-index"
367 | checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
368 | dependencies = [
369 | "proc-macro2",
370 | "quote",
371 | "syn",
372 | ]
373 |
374 | [[package]]
375 | name = "difflib"
376 | version = "0.4.0"
377 | source = "registry+https://github.com/rust-lang/crates.io-index"
378 | checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
379 |
380 | [[package]]
381 | name = "digest"
382 | version = "0.10.7"
383 | source = "registry+https://github.com/rust-lang/crates.io-index"
384 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
385 | dependencies = [
386 | "block-buffer",
387 | "crypto-common",
388 | "subtle",
389 | ]
390 |
391 | [[package]]
392 | name = "directories"
393 | version = "6.0.0"
394 | source = "registry+https://github.com/rust-lang/crates.io-index"
395 | checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
396 | dependencies = [
397 | "dirs-sys 0.5.0",
398 | ]
399 |
400 | [[package]]
401 | name = "dirs"
402 | version = "4.0.0"
403 | source = "registry+https://github.com/rust-lang/crates.io-index"
404 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
405 | dependencies = [
406 | "dirs-sys 0.3.7",
407 | ]
408 |
409 | [[package]]
410 | name = "dirs-sys"
411 | version = "0.3.7"
412 | source = "registry+https://github.com/rust-lang/crates.io-index"
413 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
414 | dependencies = [
415 | "libc",
416 | "redox_users 0.4.6",
417 | "winapi",
418 | ]
419 |
420 | [[package]]
421 | name = "dirs-sys"
422 | version = "0.5.0"
423 | source = "registry+https://github.com/rust-lang/crates.io-index"
424 | checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
425 | dependencies = [
426 | "libc",
427 | "option-ext",
428 | "redox_users 0.5.0",
429 | "windows-sys 0.59.0",
430 | ]
431 |
432 | [[package]]
433 | name = "doc-comment"
434 | version = "0.3.3"
435 | source = "registry+https://github.com/rust-lang/crates.io-index"
436 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
437 |
438 | [[package]]
439 | name = "equivalent"
440 | version = "1.0.2"
441 | source = "registry+https://github.com/rust-lang/crates.io-index"
442 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
443 |
444 | [[package]]
445 | name = "flate2"
446 | version = "1.1.1"
447 | source = "registry+https://github.com/rust-lang/crates.io-index"
448 | checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
449 | dependencies = [
450 | "crc32fast",
451 | "libz-rs-sys",
452 | "miniz_oxide",
453 | ]
454 |
455 | [[package]]
456 | name = "fs_extra"
457 | version = "1.3.0"
458 | source = "registry+https://github.com/rust-lang/crates.io-index"
459 | checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
460 |
461 | [[package]]
462 | name = "futures"
463 | version = "0.3.31"
464 | source = "registry+https://github.com/rust-lang/crates.io-index"
465 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
466 | dependencies = [
467 | "futures-channel",
468 | "futures-core",
469 | "futures-executor",
470 | "futures-io",
471 | "futures-sink",
472 | "futures-task",
473 | "futures-util",
474 | ]
475 |
476 | [[package]]
477 | name = "futures-channel"
478 | version = "0.3.31"
479 | source = "registry+https://github.com/rust-lang/crates.io-index"
480 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
481 | dependencies = [
482 | "futures-core",
483 | "futures-sink",
484 | ]
485 |
486 | [[package]]
487 | name = "futures-core"
488 | version = "0.3.31"
489 | source = "registry+https://github.com/rust-lang/crates.io-index"
490 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
491 |
492 | [[package]]
493 | name = "futures-executor"
494 | version = "0.3.31"
495 | source = "registry+https://github.com/rust-lang/crates.io-index"
496 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
497 | dependencies = [
498 | "futures-core",
499 | "futures-task",
500 | "futures-util",
501 | ]
502 |
503 | [[package]]
504 | name = "futures-io"
505 | version = "0.3.31"
506 | source = "registry+https://github.com/rust-lang/crates.io-index"
507 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
508 |
509 | [[package]]
510 | name = "futures-macro"
511 | version = "0.3.31"
512 | source = "registry+https://github.com/rust-lang/crates.io-index"
513 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
514 | dependencies = [
515 | "proc-macro2",
516 | "quote",
517 | "syn",
518 | ]
519 |
520 | [[package]]
521 | name = "futures-sink"
522 | version = "0.3.31"
523 | source = "registry+https://github.com/rust-lang/crates.io-index"
524 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
525 |
526 | [[package]]
527 | name = "futures-task"
528 | version = "0.3.31"
529 | source = "registry+https://github.com/rust-lang/crates.io-index"
530 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
531 |
532 | [[package]]
533 | name = "futures-util"
534 | version = "0.3.31"
535 | source = "registry+https://github.com/rust-lang/crates.io-index"
536 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
537 | dependencies = [
538 | "futures-channel",
539 | "futures-core",
540 | "futures-io",
541 | "futures-macro",
542 | "futures-sink",
543 | "futures-task",
544 | "memchr",
545 | "pin-project-lite",
546 | "pin-utils",
547 | "slab",
548 | ]
549 |
550 | [[package]]
551 | name = "generic-array"
552 | version = "0.14.7"
553 | source = "registry+https://github.com/rust-lang/crates.io-index"
554 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
555 | dependencies = [
556 | "typenum",
557 | "version_check",
558 | ]
559 |
560 | [[package]]
561 | name = "getrandom"
562 | version = "0.2.15"
563 | source = "registry+https://github.com/rust-lang/crates.io-index"
564 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
565 | dependencies = [
566 | "cfg-if",
567 | "libc",
568 | "wasi 0.11.0+wasi-snapshot-preview1",
569 | ]
570 |
571 | [[package]]
572 | name = "getrandom"
573 | version = "0.3.3"
574 | source = "registry+https://github.com/rust-lang/crates.io-index"
575 | checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
576 | dependencies = [
577 | "cfg-if",
578 | "js-sys",
579 | "libc",
580 | "r-efi",
581 | "wasi 0.14.2+wasi-0.2.4",
582 | "wasm-bindgen",
583 | ]
584 |
585 | [[package]]
586 | name = "gimli"
587 | version = "0.31.1"
588 | source = "registry+https://github.com/rust-lang/crates.io-index"
589 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
590 |
591 | [[package]]
592 | name = "globset"
593 | version = "0.4.16"
594 | source = "registry+https://github.com/rust-lang/crates.io-index"
595 | checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
596 | dependencies = [
597 | "aho-corasick",
598 | "bstr",
599 | "log",
600 | "regex-automata",
601 | "regex-syntax",
602 | ]
603 |
604 | [[package]]
605 | name = "hashbrown"
606 | version = "0.15.3"
607 | source = "registry+https://github.com/rust-lang/crates.io-index"
608 | checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
609 |
610 | [[package]]
611 | name = "heck"
612 | version = "0.5.0"
613 | source = "registry+https://github.com/rust-lang/crates.io-index"
614 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
615 |
616 | [[package]]
617 | name = "hermit-abi"
618 | version = "0.3.9"
619 | source = "registry+https://github.com/rust-lang/crates.io-index"
620 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
621 |
622 | [[package]]
623 | name = "hmac"
624 | version = "0.12.1"
625 | source = "registry+https://github.com/rust-lang/crates.io-index"
626 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
627 | dependencies = [
628 | "digest",
629 | ]
630 |
631 | [[package]]
632 | name = "ignore"
633 | version = "0.4.23"
634 | source = "registry+https://github.com/rust-lang/crates.io-index"
635 | checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
636 | dependencies = [
637 | "crossbeam-deque",
638 | "globset",
639 | "log",
640 | "memchr",
641 | "regex-automata",
642 | "same-file",
643 | "walkdir",
644 | "winapi-util",
645 | ]
646 |
647 | [[package]]
648 | name = "indexmap"
649 | version = "2.9.0"
650 | source = "registry+https://github.com/rust-lang/crates.io-index"
651 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
652 | dependencies = [
653 | "equivalent",
654 | "hashbrown",
655 | ]
656 |
657 | [[package]]
658 | name = "inout"
659 | version = "0.1.4"
660 | source = "registry+https://github.com/rust-lang/crates.io-index"
661 | checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
662 | dependencies = [
663 | "generic-array",
664 | ]
665 |
666 | [[package]]
667 | name = "is_terminal_polyfill"
668 | version = "1.70.1"
669 | source = "registry+https://github.com/rust-lang/crates.io-index"
670 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
671 |
672 | [[package]]
673 | name = "itoa"
674 | version = "1.0.15"
675 | source = "registry+https://github.com/rust-lang/crates.io-index"
676 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
677 |
678 | [[package]]
679 | name = "jobserver"
680 | version = "0.1.33"
681 | source = "registry+https://github.com/rust-lang/crates.io-index"
682 | checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
683 | dependencies = [
684 | "getrandom 0.3.3",
685 | "libc",
686 | ]
687 |
688 | [[package]]
689 | name = "js-sys"
690 | version = "0.3.77"
691 | source = "registry+https://github.com/rust-lang/crates.io-index"
692 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
693 | dependencies = [
694 | "once_cell",
695 | "wasm-bindgen",
696 | ]
697 |
698 | [[package]]
699 | name = "libc"
700 | version = "0.2.171"
701 | source = "registry+https://github.com/rust-lang/crates.io-index"
702 | checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
703 |
704 | [[package]]
705 | name = "liblzma"
706 | version = "0.4.1"
707 | source = "registry+https://github.com/rust-lang/crates.io-index"
708 | checksum = "66352d7a8ac12d4877b6e6ea5a9b7650ee094257dc40889955bea5bc5b08c1d0"
709 | dependencies = [
710 | "liblzma-sys",
711 | ]
712 |
713 | [[package]]
714 | name = "liblzma-sys"
715 | version = "0.4.3"
716 | source = "registry+https://github.com/rust-lang/crates.io-index"
717 | checksum = "5839bad90c3cc2e0b8c4ed8296b80e86040240f81d46b9c0e9bc8dd51ddd3af1"
718 | dependencies = [
719 | "cc",
720 | "libc",
721 | "pkg-config",
722 | ]
723 |
724 | [[package]]
725 | name = "libredox"
726 | version = "0.1.3"
727 | source = "registry+https://github.com/rust-lang/crates.io-index"
728 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
729 | dependencies = [
730 | "bitflags",
731 | "libc",
732 | ]
733 |
734 | [[package]]
735 | name = "libz-rs-sys"
736 | version = "0.5.0"
737 | source = "registry+https://github.com/rust-lang/crates.io-index"
738 | checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
739 | dependencies = [
740 | "zlib-rs",
741 | ]
742 |
743 | [[package]]
744 | name = "lock_api"
745 | version = "0.4.12"
746 | source = "registry+https://github.com/rust-lang/crates.io-index"
747 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
748 | dependencies = [
749 | "autocfg",
750 | "scopeguard",
751 | ]
752 |
753 | [[package]]
754 | name = "log"
755 | version = "0.4.27"
756 | source = "registry+https://github.com/rust-lang/crates.io-index"
757 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
758 |
759 | [[package]]
760 | name = "memchr"
761 | version = "2.7.4"
762 | source = "registry+https://github.com/rust-lang/crates.io-index"
763 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
764 |
765 | [[package]]
766 | name = "miniz_oxide"
767 | version = "0.8.5"
768 | source = "registry+https://github.com/rust-lang/crates.io-index"
769 | checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
770 | dependencies = [
771 | "adler2",
772 | ]
773 |
774 | [[package]]
775 | name = "mio"
776 | version = "1.0.3"
777 | source = "registry+https://github.com/rust-lang/crates.io-index"
778 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
779 | dependencies = [
780 | "libc",
781 | "wasi 0.11.0+wasi-snapshot-preview1",
782 | "windows-sys 0.52.0",
783 | ]
784 |
785 | [[package]]
786 | name = "num-conv"
787 | version = "0.1.0"
788 | source = "registry+https://github.com/rust-lang/crates.io-index"
789 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
790 |
791 | [[package]]
792 | name = "num_cpus"
793 | version = "1.16.0"
794 | source = "registry+https://github.com/rust-lang/crates.io-index"
795 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
796 | dependencies = [
797 | "hermit-abi",
798 | "libc",
799 | ]
800 |
801 | [[package]]
802 | name = "object"
803 | version = "0.36.7"
804 | source = "registry+https://github.com/rust-lang/crates.io-index"
805 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
806 | dependencies = [
807 | "memchr",
808 | ]
809 |
810 | [[package]]
811 | name = "once_cell"
812 | version = "1.21.3"
813 | source = "registry+https://github.com/rust-lang/crates.io-index"
814 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
815 |
816 | [[package]]
817 | name = "option-ext"
818 | version = "0.2.0"
819 | source = "registry+https://github.com/rust-lang/crates.io-index"
820 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
821 |
822 | [[package]]
823 | name = "parking_lot"
824 | version = "0.12.3"
825 | source = "registry+https://github.com/rust-lang/crates.io-index"
826 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
827 | dependencies = [
828 | "lock_api",
829 | "parking_lot_core",
830 | ]
831 |
832 | [[package]]
833 | name = "parking_lot_core"
834 | version = "0.9.10"
835 | source = "registry+https://github.com/rust-lang/crates.io-index"
836 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
837 | dependencies = [
838 | "cfg-if",
839 | "libc",
840 | "redox_syscall",
841 | "smallvec",
842 | "windows-targets",
843 | ]
844 |
845 | [[package]]
846 | name = "pbkdf2"
847 | version = "0.12.2"
848 | source = "registry+https://github.com/rust-lang/crates.io-index"
849 | checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
850 | dependencies = [
851 | "digest",
852 | "hmac",
853 | ]
854 |
855 | [[package]]
856 | name = "pin-project-lite"
857 | version = "0.2.16"
858 | source = "registry+https://github.com/rust-lang/crates.io-index"
859 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
860 |
861 | [[package]]
862 | name = "pin-utils"
863 | version = "0.1.0"
864 | source = "registry+https://github.com/rust-lang/crates.io-index"
865 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
866 |
867 | [[package]]
868 | name = "pkg-config"
869 | version = "0.3.32"
870 | source = "registry+https://github.com/rust-lang/crates.io-index"
871 | checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
872 |
873 | [[package]]
874 | name = "powerfmt"
875 | version = "0.2.0"
876 | source = "registry+https://github.com/rust-lang/crates.io-index"
877 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
878 |
879 | [[package]]
880 | name = "predicates"
881 | version = "3.1.3"
882 | source = "registry+https://github.com/rust-lang/crates.io-index"
883 | checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573"
884 | dependencies = [
885 | "anstyle",
886 | "difflib",
887 | "predicates-core",
888 | ]
889 |
890 | [[package]]
891 | name = "predicates-core"
892 | version = "1.0.9"
893 | source = "registry+https://github.com/rust-lang/crates.io-index"
894 | checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa"
895 |
896 | [[package]]
897 | name = "predicates-tree"
898 | version = "1.0.12"
899 | source = "registry+https://github.com/rust-lang/crates.io-index"
900 | checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c"
901 | dependencies = [
902 | "predicates-core",
903 | "termtree",
904 | ]
905 |
906 | [[package]]
907 | name = "proc-macro2"
908 | version = "1.0.94"
909 | source = "registry+https://github.com/rust-lang/crates.io-index"
910 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
911 | dependencies = [
912 | "unicode-ident",
913 | ]
914 |
915 | [[package]]
916 | name = "quote"
917 | version = "1.0.40"
918 | source = "registry+https://github.com/rust-lang/crates.io-index"
919 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
920 | dependencies = [
921 | "proc-macro2",
922 | ]
923 |
924 | [[package]]
925 | name = "r-efi"
926 | version = "5.2.0"
927 | source = "registry+https://github.com/rust-lang/crates.io-index"
928 | checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
929 |
930 | [[package]]
931 | name = "redox_syscall"
932 | version = "0.5.10"
933 | source = "registry+https://github.com/rust-lang/crates.io-index"
934 | checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
935 | dependencies = [
936 | "bitflags",
937 | ]
938 |
939 | [[package]]
940 | name = "redox_users"
941 | version = "0.4.6"
942 | source = "registry+https://github.com/rust-lang/crates.io-index"
943 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
944 | dependencies = [
945 | "getrandom 0.2.15",
946 | "libredox",
947 | "thiserror 1.0.69",
948 | ]
949 |
950 | [[package]]
951 | name = "redox_users"
952 | version = "0.5.0"
953 | source = "registry+https://github.com/rust-lang/crates.io-index"
954 | checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
955 | dependencies = [
956 | "getrandom 0.2.15",
957 | "libredox",
958 | "thiserror 2.0.12",
959 | ]
960 |
961 | [[package]]
962 | name = "regex"
963 | version = "1.11.1"
964 | source = "registry+https://github.com/rust-lang/crates.io-index"
965 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
966 | dependencies = [
967 | "aho-corasick",
968 | "memchr",
969 | "regex-automata",
970 | "regex-syntax",
971 | ]
972 |
973 | [[package]]
974 | name = "regex-automata"
975 | version = "0.4.9"
976 | source = "registry+https://github.com/rust-lang/crates.io-index"
977 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
978 | dependencies = [
979 | "aho-corasick",
980 | "memchr",
981 | "regex-syntax",
982 | ]
983 |
984 | [[package]]
985 | name = "regex-syntax"
986 | version = "0.8.5"
987 | source = "registry+https://github.com/rust-lang/crates.io-index"
988 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
989 |
990 | [[package]]
991 | name = "rust_search"
992 | version = "2.1.0"
993 | source = "registry+https://github.com/rust-lang/crates.io-index"
994 | checksum = "d27d7be20245d289c9dde663f06521de08663d73cbaefc45785aa65d02022378"
995 | dependencies = [
996 | "dirs",
997 | "ignore",
998 | "num_cpus",
999 | "regex",
1000 | "strsim 0.10.0",
1001 | ]
1002 |
1003 | [[package]]
1004 | name = "rustc-demangle"
1005 | version = "0.1.24"
1006 | source = "registry+https://github.com/rust-lang/crates.io-index"
1007 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
1008 |
1009 | [[package]]
1010 | name = "ryu"
1011 | version = "1.0.20"
1012 | source = "registry+https://github.com/rust-lang/crates.io-index"
1013 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
1014 |
1015 | [[package]]
1016 | name = "same-file"
1017 | version = "1.0.6"
1018 | source = "registry+https://github.com/rust-lang/crates.io-index"
1019 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1020 | dependencies = [
1021 | "winapi-util",
1022 | ]
1023 |
1024 | [[package]]
1025 | name = "scopeguard"
1026 | version = "1.2.0"
1027 | source = "registry+https://github.com/rust-lang/crates.io-index"
1028 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
1029 |
1030 | [[package]]
1031 | name = "serde"
1032 | version = "1.0.219"
1033 | source = "registry+https://github.com/rust-lang/crates.io-index"
1034 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
1035 | dependencies = [
1036 | "serde_derive",
1037 | ]
1038 |
1039 | [[package]]
1040 | name = "serde_derive"
1041 | version = "1.0.219"
1042 | source = "registry+https://github.com/rust-lang/crates.io-index"
1043 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
1044 | dependencies = [
1045 | "proc-macro2",
1046 | "quote",
1047 | "syn",
1048 | ]
1049 |
1050 | [[package]]
1051 | name = "serde_json"
1052 | version = "1.0.140"
1053 | source = "registry+https://github.com/rust-lang/crates.io-index"
1054 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
1055 | dependencies = [
1056 | "itoa",
1057 | "memchr",
1058 | "ryu",
1059 | "serde",
1060 | ]
1061 |
1062 | [[package]]
1063 | name = "sha1"
1064 | version = "0.10.6"
1065 | source = "registry+https://github.com/rust-lang/crates.io-index"
1066 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
1067 | dependencies = [
1068 | "cfg-if",
1069 | "cpufeatures",
1070 | "digest",
1071 | ]
1072 |
1073 | [[package]]
1074 | name = "shlex"
1075 | version = "1.3.0"
1076 | source = "registry+https://github.com/rust-lang/crates.io-index"
1077 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
1078 |
1079 | [[package]]
1080 | name = "signal-hook-registry"
1081 | version = "1.4.2"
1082 | source = "registry+https://github.com/rust-lang/crates.io-index"
1083 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
1084 | dependencies = [
1085 | "libc",
1086 | ]
1087 |
1088 | [[package]]
1089 | name = "simd-adler32"
1090 | version = "0.3.7"
1091 | source = "registry+https://github.com/rust-lang/crates.io-index"
1092 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
1093 |
1094 | [[package]]
1095 | name = "slab"
1096 | version = "0.4.9"
1097 | source = "registry+https://github.com/rust-lang/crates.io-index"
1098 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
1099 | dependencies = [
1100 | "autocfg",
1101 | ]
1102 |
1103 | [[package]]
1104 | name = "smallvec"
1105 | version = "1.14.0"
1106 | source = "registry+https://github.com/rust-lang/crates.io-index"
1107 | checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
1108 |
1109 | [[package]]
1110 | name = "socket2"
1111 | version = "0.5.9"
1112 | source = "registry+https://github.com/rust-lang/crates.io-index"
1113 | checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
1114 | dependencies = [
1115 | "libc",
1116 | "windows-sys 0.52.0",
1117 | ]
1118 |
1119 | [[package]]
1120 | name = "strsim"
1121 | version = "0.10.0"
1122 | source = "registry+https://github.com/rust-lang/crates.io-index"
1123 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
1124 |
1125 | [[package]]
1126 | name = "strsim"
1127 | version = "0.11.1"
1128 | source = "registry+https://github.com/rust-lang/crates.io-index"
1129 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
1130 |
1131 | [[package]]
1132 | name = "subtle"
1133 | version = "2.6.1"
1134 | source = "registry+https://github.com/rust-lang/crates.io-index"
1135 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
1136 |
1137 | [[package]]
1138 | name = "syn"
1139 | version = "2.0.100"
1140 | source = "registry+https://github.com/rust-lang/crates.io-index"
1141 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
1142 | dependencies = [
1143 | "proc-macro2",
1144 | "quote",
1145 | "unicode-ident",
1146 | ]
1147 |
1148 | [[package]]
1149 | name = "termtree"
1150 | version = "0.5.1"
1151 | source = "registry+https://github.com/rust-lang/crates.io-index"
1152 | checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
1153 |
1154 | [[package]]
1155 | name = "thiserror"
1156 | version = "1.0.69"
1157 | source = "registry+https://github.com/rust-lang/crates.io-index"
1158 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
1159 | dependencies = [
1160 | "thiserror-impl 1.0.69",
1161 | ]
1162 |
1163 | [[package]]
1164 | name = "thiserror"
1165 | version = "2.0.12"
1166 | source = "registry+https://github.com/rust-lang/crates.io-index"
1167 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
1168 | dependencies = [
1169 | "thiserror-impl 2.0.12",
1170 | ]
1171 |
1172 | [[package]]
1173 | name = "thiserror-impl"
1174 | version = "1.0.69"
1175 | source = "registry+https://github.com/rust-lang/crates.io-index"
1176 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
1177 | dependencies = [
1178 | "proc-macro2",
1179 | "quote",
1180 | "syn",
1181 | ]
1182 |
1183 | [[package]]
1184 | name = "thiserror-impl"
1185 | version = "2.0.12"
1186 | source = "registry+https://github.com/rust-lang/crates.io-index"
1187 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
1188 | dependencies = [
1189 | "proc-macro2",
1190 | "quote",
1191 | "syn",
1192 | ]
1193 |
1194 | [[package]]
1195 | name = "time"
1196 | version = "0.3.41"
1197 | source = "registry+https://github.com/rust-lang/crates.io-index"
1198 | checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
1199 | dependencies = [
1200 | "deranged",
1201 | "num-conv",
1202 | "powerfmt",
1203 | "serde",
1204 | "time-core",
1205 | ]
1206 |
1207 | [[package]]
1208 | name = "time-core"
1209 | version = "0.1.4"
1210 | source = "registry+https://github.com/rust-lang/crates.io-index"
1211 | checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
1212 |
1213 | [[package]]
1214 | name = "tokio"
1215 | version = "1.45.1"
1216 | source = "registry+https://github.com/rust-lang/crates.io-index"
1217 | checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
1218 | dependencies = [
1219 | "backtrace",
1220 | "bytes",
1221 | "libc",
1222 | "mio",
1223 | "parking_lot",
1224 | "pin-project-lite",
1225 | "signal-hook-registry",
1226 | "socket2",
1227 | "tokio-macros",
1228 | "windows-sys 0.52.0",
1229 | ]
1230 |
1231 | [[package]]
1232 | name = "tokio-macros"
1233 | version = "2.5.0"
1234 | source = "registry+https://github.com/rust-lang/crates.io-index"
1235 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
1236 | dependencies = [
1237 | "proc-macro2",
1238 | "quote",
1239 | "syn",
1240 | ]
1241 |
1242 | [[package]]
1243 | name = "typenum"
1244 | version = "1.18.0"
1245 | source = "registry+https://github.com/rust-lang/crates.io-index"
1246 | checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
1247 |
1248 | [[package]]
1249 | name = "unicode-ident"
1250 | version = "1.0.18"
1251 | source = "registry+https://github.com/rust-lang/crates.io-index"
1252 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
1253 |
1254 | [[package]]
1255 | name = "utf8parse"
1256 | version = "0.2.2"
1257 | source = "registry+https://github.com/rust-lang/crates.io-index"
1258 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
1259 |
1260 | [[package]]
1261 | name = "version_check"
1262 | version = "0.9.5"
1263 | source = "registry+https://github.com/rust-lang/crates.io-index"
1264 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1265 |
1266 | [[package]]
1267 | name = "wait-timeout"
1268 | version = "0.2.1"
1269 | source = "registry+https://github.com/rust-lang/crates.io-index"
1270 | checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
1271 | dependencies = [
1272 | "libc",
1273 | ]
1274 |
1275 | [[package]]
1276 | name = "walkdir"
1277 | version = "2.5.0"
1278 | source = "registry+https://github.com/rust-lang/crates.io-index"
1279 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
1280 | dependencies = [
1281 | "same-file",
1282 | "winapi-util",
1283 | ]
1284 |
1285 | [[package]]
1286 | name = "wasi"
1287 | version = "0.11.0+wasi-snapshot-preview1"
1288 | source = "registry+https://github.com/rust-lang/crates.io-index"
1289 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1290 |
1291 | [[package]]
1292 | name = "wasi"
1293 | version = "0.14.2+wasi-0.2.4"
1294 | source = "registry+https://github.com/rust-lang/crates.io-index"
1295 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
1296 | dependencies = [
1297 | "wit-bindgen-rt",
1298 | ]
1299 |
1300 | [[package]]
1301 | name = "wasm-bindgen"
1302 | version = "0.2.100"
1303 | source = "registry+https://github.com/rust-lang/crates.io-index"
1304 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
1305 | dependencies = [
1306 | "cfg-if",
1307 | "once_cell",
1308 | "wasm-bindgen-macro",
1309 | ]
1310 |
1311 | [[package]]
1312 | name = "wasm-bindgen-backend"
1313 | version = "0.2.100"
1314 | source = "registry+https://github.com/rust-lang/crates.io-index"
1315 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
1316 | dependencies = [
1317 | "bumpalo",
1318 | "log",
1319 | "proc-macro2",
1320 | "quote",
1321 | "syn",
1322 | "wasm-bindgen-shared",
1323 | ]
1324 |
1325 | [[package]]
1326 | name = "wasm-bindgen-macro"
1327 | version = "0.2.100"
1328 | source = "registry+https://github.com/rust-lang/crates.io-index"
1329 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
1330 | dependencies = [
1331 | "quote",
1332 | "wasm-bindgen-macro-support",
1333 | ]
1334 |
1335 | [[package]]
1336 | name = "wasm-bindgen-macro-support"
1337 | version = "0.2.100"
1338 | source = "registry+https://github.com/rust-lang/crates.io-index"
1339 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
1340 | dependencies = [
1341 | "proc-macro2",
1342 | "quote",
1343 | "syn",
1344 | "wasm-bindgen-backend",
1345 | "wasm-bindgen-shared",
1346 | ]
1347 |
1348 | [[package]]
1349 | name = "wasm-bindgen-shared"
1350 | version = "0.2.100"
1351 | source = "registry+https://github.com/rust-lang/crates.io-index"
1352 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
1353 | dependencies = [
1354 | "unicode-ident",
1355 | ]
1356 |
1357 | [[package]]
1358 | name = "winapi"
1359 | version = "0.3.9"
1360 | source = "registry+https://github.com/rust-lang/crates.io-index"
1361 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1362 | dependencies = [
1363 | "winapi-i686-pc-windows-gnu",
1364 | "winapi-x86_64-pc-windows-gnu",
1365 | ]
1366 |
1367 | [[package]]
1368 | name = "winapi-i686-pc-windows-gnu"
1369 | version = "0.4.0"
1370 | source = "registry+https://github.com/rust-lang/crates.io-index"
1371 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1372 |
1373 | [[package]]
1374 | name = "winapi-util"
1375 | version = "0.1.9"
1376 | source = "registry+https://github.com/rust-lang/crates.io-index"
1377 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
1378 | dependencies = [
1379 | "windows-sys 0.59.0",
1380 | ]
1381 |
1382 | [[package]]
1383 | name = "winapi-x86_64-pc-windows-gnu"
1384 | version = "0.4.0"
1385 | source = "registry+https://github.com/rust-lang/crates.io-index"
1386 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1387 |
1388 | [[package]]
1389 | name = "windows-sys"
1390 | version = "0.52.0"
1391 | source = "registry+https://github.com/rust-lang/crates.io-index"
1392 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
1393 | dependencies = [
1394 | "windows-targets",
1395 | ]
1396 |
1397 | [[package]]
1398 | name = "windows-sys"
1399 | version = "0.59.0"
1400 | source = "registry+https://github.com/rust-lang/crates.io-index"
1401 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
1402 | dependencies = [
1403 | "windows-targets",
1404 | ]
1405 |
1406 | [[package]]
1407 | name = "windows-targets"
1408 | version = "0.52.6"
1409 | source = "registry+https://github.com/rust-lang/crates.io-index"
1410 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
1411 | dependencies = [
1412 | "windows_aarch64_gnullvm",
1413 | "windows_aarch64_msvc",
1414 | "windows_i686_gnu",
1415 | "windows_i686_gnullvm",
1416 | "windows_i686_msvc",
1417 | "windows_x86_64_gnu",
1418 | "windows_x86_64_gnullvm",
1419 | "windows_x86_64_msvc",
1420 | ]
1421 |
1422 | [[package]]
1423 | name = "windows_aarch64_gnullvm"
1424 | version = "0.52.6"
1425 | source = "registry+https://github.com/rust-lang/crates.io-index"
1426 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
1427 |
1428 | [[package]]
1429 | name = "windows_aarch64_msvc"
1430 | version = "0.52.6"
1431 | source = "registry+https://github.com/rust-lang/crates.io-index"
1432 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
1433 |
1434 | [[package]]
1435 | name = "windows_i686_gnu"
1436 | version = "0.52.6"
1437 | source = "registry+https://github.com/rust-lang/crates.io-index"
1438 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
1439 |
1440 | [[package]]
1441 | name = "windows_i686_gnullvm"
1442 | version = "0.52.6"
1443 | source = "registry+https://github.com/rust-lang/crates.io-index"
1444 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
1445 |
1446 | [[package]]
1447 | name = "windows_i686_msvc"
1448 | version = "0.52.6"
1449 | source = "registry+https://github.com/rust-lang/crates.io-index"
1450 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
1451 |
1452 | [[package]]
1453 | name = "windows_x86_64_gnu"
1454 | version = "0.52.6"
1455 | source = "registry+https://github.com/rust-lang/crates.io-index"
1456 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
1457 |
1458 | [[package]]
1459 | name = "windows_x86_64_gnullvm"
1460 | version = "0.52.6"
1461 | source = "registry+https://github.com/rust-lang/crates.io-index"
1462 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
1463 |
1464 | [[package]]
1465 | name = "windows_x86_64_msvc"
1466 | version = "0.52.6"
1467 | source = "registry+https://github.com/rust-lang/crates.io-index"
1468 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
1469 |
1470 | [[package]]
1471 | name = "wit-bindgen-rt"
1472 | version = "0.39.0"
1473 | source = "registry+https://github.com/rust-lang/crates.io-index"
1474 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
1475 | dependencies = [
1476 | "bitflags",
1477 | ]
1478 |
1479 | [[package]]
1480 | name = "zeroize"
1481 | version = "1.8.1"
1482 | source = "registry+https://github.com/rust-lang/crates.io-index"
1483 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
1484 | dependencies = [
1485 | "zeroize_derive",
1486 | ]
1487 |
1488 | [[package]]
1489 | name = "zeroize_derive"
1490 | version = "1.4.2"
1491 | source = "registry+https://github.com/rust-lang/crates.io-index"
1492 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
1493 | dependencies = [
1494 | "proc-macro2",
1495 | "quote",
1496 | "syn",
1497 | ]
1498 |
1499 | [[package]]
1500 | name = "zip"
1501 | version = "4.0.0"
1502 | source = "registry+https://github.com/rust-lang/crates.io-index"
1503 | checksum = "153a6fff49d264c4babdcfa6b4d534747f520e56e8f0f384f3b808c4b64cc1fd"
1504 | dependencies = [
1505 | "aes",
1506 | "arbitrary",
1507 | "bzip2",
1508 | "constant_time_eq",
1509 | "crc32fast",
1510 | "deflate64",
1511 | "flate2",
1512 | "getrandom 0.3.3",
1513 | "hmac",
1514 | "indexmap",
1515 | "liblzma",
1516 | "memchr",
1517 | "pbkdf2",
1518 | "sha1",
1519 | "time",
1520 | "zeroize",
1521 | "zopfli",
1522 | "zstd",
1523 | ]
1524 |
1525 | [[package]]
1526 | name = "zlib-rs"
1527 | version = "0.5.0"
1528 | source = "registry+https://github.com/rust-lang/crates.io-index"
1529 | checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
1530 |
1531 | [[package]]
1532 | name = "zopfli"
1533 | version = "0.8.2"
1534 | source = "registry+https://github.com/rust-lang/crates.io-index"
1535 | checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
1536 | dependencies = [
1537 | "bumpalo",
1538 | "crc32fast",
1539 | "log",
1540 | "simd-adler32",
1541 | ]
1542 |
1543 | [[package]]
1544 | name = "zstd"
1545 | version = "0.13.3"
1546 | source = "registry+https://github.com/rust-lang/crates.io-index"
1547 | checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
1548 | dependencies = [
1549 | "zstd-safe",
1550 | ]
1551 |
1552 | [[package]]
1553 | name = "zstd-safe"
1554 | version = "7.2.4"
1555 | source = "registry+https://github.com/rust-lang/crates.io-index"
1556 | checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
1557 | dependencies = [
1558 | "zstd-sys",
1559 | ]
1560 |
1561 | [[package]]
1562 | name = "zstd-sys"
1563 | version = "2.0.15+zstd.1.5.7"
1564 | source = "registry+https://github.com/rust-lang/crates.io-index"
1565 | checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
1566 | dependencies = [
1567 | "cc",
1568 | "pkg-config",
1569 | ]
1570 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "csharp-language-server"
3 | version = "0.6.0"
4 | edition = "2024"
5 | authors = ["Sofus Addington"]
6 | description = "A tool that simplifies installation and running C# language server"
7 |
8 | [dependencies]
9 | anyhow = "1"
10 | clap = { version = "4", features = ["derive"] }
11 | directories = "6"
12 | fs_extra = "1"
13 | futures = "0.3"
14 | rust_search = "2"
15 | serde = { version = "1", features = ["derive"] }
16 | serde_json = "1"
17 | tokio = { version = "1", features = ["full"] }
18 | zip = "4"
19 |
20 | [dev-dependencies]
21 | assert_cmd = "2"
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 SofusA
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # csharp-language-server
2 | A wrapper around the language server behind the C# Visual Studio Code extension, `Microsoft.CodeAnalysis.LanguageServer`, which makes it compatible with other editors, e.g., Helix or Neovim.
3 | This language server is more stable and faster than OmniSharp.
4 |
5 | This tool assists the use of Microsoft.CodeAnalysis.LanguageServer:
6 | - Downloads `Microsoft.CodeAnalysis.LanguageServer`
7 | - Launches `Microsoft.CodeAnalysis.LanguageServer` as a process
8 | - Waits for `capabilities` notification from the server, and forces `pull diagnostics` to be available. This forces the server respect clients who do not support dynamic registration of diagnostic capabilities.
9 | - Waits for an `initialize` notification from the client, and finds relevant `.sln` or `.csproj` files and sends them to the server as a custom `open` notification.
10 |
11 | ## Installation
12 | ### Binaries
13 | Download the binaries that match your platform under Releases
14 |
15 | ### Others
16 | Alternatively, install with `cargo`: `cargo install --git https://github.com/SofusA/csharp-language-server`
17 |
18 | ## Usage
19 |
20 | ### Helix
21 | Since `Microsoft.CodeAnalysis.LanguageServer` only supports `pull diagnostics` and Helix does not [yet](https://github.com/helix-editor/helix/pull/11315), you will need to use my branch: `github:sofusa/helix-pull-diagnostics`.
22 |
23 | ```toml
24 | [language-server.csharp]
25 | command = "csharp-language-server"
26 |
27 | [[language]]
28 | name = "c-sharp"
29 | language-servers = ["csharp"]
30 | ```
31 |
32 | ### Neovim
33 | ```lua
34 | vim.api.nvim_create_autocmd('FileType', {
35 | pattern = 'cs',
36 | callback = function(args)
37 | local root_dir = vim.fs.dirname(
38 | vim.fs.find({ '.sln', '.csproj', '.git' }, { upward = true })[1]
39 | )
40 | vim.lsp.start({
41 | name = 'csharp-language-server',
42 | cmd = {'csharp-language-server'},
43 | root_dir = root_dir,
44 | })
45 | end,
46 | })
47 | ```
48 |
--------------------------------------------------------------------------------
/build.rs:
--------------------------------------------------------------------------------
1 | use std::path::Path;
2 | use std::process::Command;
3 |
4 | fn main() {
5 | let marker_path = Path::new("language-server.zip");
6 |
7 | if !marker_path.exists() {
8 | let status = Command::new("./download-server")
9 | .status()
10 | .expect("Failed to run the setup script");
11 |
12 | if !status.success() {
13 | panic!("Setup script failed with status: {}", status);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/download-server:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | version=$(cat src/server_version.rs | sed -n 's/.*"\(.*\)".*/\1/p')
4 | cd ./download-server-project
5 |
6 | dotnet add package Microsoft.CodeAnalysis.LanguageServer.neutral -v $version
7 |
8 | cd out/microsoft.codeanalysis.languageserver.neutral/$version/content/LanguageServer/neutral
9 | zip -r language-server.zip ./*
10 |
11 | mv language-server.zip ../../../../../../..
12 | cd ../../../../../../
13 |
14 | rm -rf out
15 |
16 | cd ..
17 |
--------------------------------------------------------------------------------
/download-server-project/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/download-server-project/ServerDownload.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | out
4 | net9.0
5 | true
6 | false
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/download_server.rs:
--------------------------------------------------------------------------------
1 | use anyhow::Result;
2 | use std::{
3 | fs::File,
4 | io::Cursor,
5 | path::{Path, PathBuf},
6 | };
7 | use zip::ZipArchive;
8 |
9 | pub async fn ensure_server_is_installed(version: &str, cache_dir: &Path) -> Result {
10 | let server_dir = cache_dir.join("server");
11 |
12 | let dll_version_dir = server_dir.join(version);
13 |
14 | let dll_path = dll_version_dir.join("Microsoft.CodeAnalysis.LanguageServer.dll");
15 |
16 | if std::path::Path::new(&dll_path).exists() {
17 | return Ok(dll_path);
18 | }
19 |
20 | let language_server_zip = include_bytes!("../language-server.zip");
21 |
22 | // extract language server
23 | let reader = Cursor::new(language_server_zip);
24 | let mut archive = ZipArchive::new(reader)?;
25 |
26 | for i in 0..archive.len() {
27 | let mut file = archive.by_index(i)?;
28 | let outpath = dll_version_dir.join(file.name());
29 |
30 | if file.name().ends_with('/') {
31 | std::fs::create_dir_all(&outpath)?;
32 | } else {
33 | if let Some(p) = outpath.parent() {
34 | if !p.exists() {
35 | std::fs::create_dir_all(p)?;
36 | }
37 | }
38 | let mut outfile = File::create(&outpath)?;
39 | std::io::copy(&mut file, &mut outfile)?;
40 | }
41 | }
42 |
43 | Ok(dll_path)
44 | }
45 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod download_server;
2 | pub mod notification;
3 | pub mod server;
4 | pub mod server_version;
5 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | use ::futures::future::try_join;
2 | use anyhow::{Context, Result};
3 | use clap::Parser;
4 | use rust_search::SearchBuilder;
5 | use serde_json::{Value, json};
6 | use tokio::io::{self, AsyncReadExt, AsyncWriteExt, BufReader};
7 |
8 | use csharp_language_server::{
9 | notification::{Notification, Params, ProjectParams, add_content_length_header},
10 | server::start_server,
11 | server_version::SERVER_VERSION,
12 | };
13 |
14 | #[derive(Parser, Debug)]
15 | #[command(author, version, about, long_about = None)]
16 | struct Args {}
17 |
18 | #[tokio::main]
19 | async fn main() {
20 | let version = SERVER_VERSION;
21 |
22 | let (mut server_stdin, server_stdout) = start_server(version).await;
23 |
24 | let stdin = io::stdin();
25 | let mut stdout = io::stdout();
26 |
27 | let stream_to_stdout = async {
28 | let mut reader = BufReader::new(server_stdout);
29 | loop {
30 | let mut buffer = vec![0; 3048];
31 | let bytes_read = reader
32 | .read(&mut buffer)
33 | .await
34 | .expect("Unable to read incoming server notification");
35 |
36 | if bytes_read == 0 {
37 | break; // EOF reached
38 | }
39 |
40 | let notification = String::from_utf8(buffer[..bytes_read].to_vec())
41 | .expect("Unable to convert buffer to string");
42 |
43 | if notification.contains("capabilities") {
44 | let patched_result_notification = force_pull_diagnostics_hack(¬ification)?;
45 |
46 | stdout
47 | .write_all(patched_result_notification.as_bytes())
48 | .await?;
49 |
50 | break;
51 | }
52 |
53 | stdout
54 | .write_all(&buffer[..bytes_read])
55 | .await
56 | .expect("Unable to forward client notification to server");
57 | }
58 |
59 | io::copy(&mut reader, &mut stdout).await
60 | };
61 |
62 | let stdin_to_stream = async {
63 | let mut stdin = BufReader::new(stdin);
64 | loop {
65 | let mut buffer = vec![0; 6000];
66 | let bytes_read = stdin
67 | .read(&mut buffer)
68 | .await
69 | .expect("Unable to read incoming client notification");
70 |
71 | if bytes_read == 0 {
72 | break; // EOF reached
73 | }
74 |
75 | server_stdin
76 | .write_all(&buffer[..bytes_read])
77 | .await
78 | .expect("Unable to forward client notification to server");
79 |
80 | let notification = String::from_utf8(buffer[..bytes_read].to_vec())
81 | .expect("Unable to convert buffer to string");
82 |
83 | if notification.contains("initialize") {
84 | let root_path = parse_root_path(¬ification)
85 | .expect("Root path not part of initialize notification");
86 |
87 | // let solution_files = find_extension(&root_path, "sln");
88 | // let solution_to_open = solution_files.first().map(|found| found.to_owned());
89 |
90 | // if let Some(solution_to_open) = solution_to_open {
91 | // let open_solution_notification =
92 | // create_open_solution_notification(&solution_to_open);
93 |
94 | // server_stdin
95 | // .write_all(open_solution_notification.as_bytes())
96 | // .await
97 | // .expect("Unable to send open solution notification to server");
98 |
99 | // break;
100 | // }
101 |
102 | let project_files = find_extension(&root_path, "csproj");
103 | let open_projects_notification = create_open_projects_notification(project_files);
104 |
105 | server_stdin
106 | .write_all(open_projects_notification.as_bytes())
107 | .await
108 | .expect("Unable to send open projects notification to server");
109 |
110 | break;
111 | }
112 | }
113 | io::copy(&mut stdin, &mut server_stdin).await
114 | };
115 |
116 | try_join(stdin_to_stream, stream_to_stdout)
117 | .await
118 | .expect("Will never finish");
119 | }
120 |
121 | fn parse_root_path(notification: &str) -> Result {
122 | let json_start = notification
123 | .find('{')
124 | .context("Notification was not json")?;
125 |
126 | let parsed_notification: Value = serde_json::from_str(¬ification[json_start..])?;
127 |
128 | let root_path = (parsed_notification["params"]["rootUri"]
129 | .as_str()
130 | .map(uri_to_path))
131 | .or_else(|| parsed_notification["params"]["rootPath"].as_str())
132 | .context("Root URI/path was not given by the client")?;
133 |
134 | Ok(root_path.to_string())
135 | }
136 |
137 | fn find_extension(root_path: &str, extension: &str) -> Vec {
138 | SearchBuilder::default()
139 | .location(root_path)
140 | .ext(extension)
141 | .build()
142 | .collect()
143 | }
144 |
145 | // fn create_open_solution_notification(file_path: &str) -> String {
146 | // let notification = Notification {
147 | // jsonrpc: "2.0".to_string(),
148 | // method: "solution/open".to_string(),
149 | // params: Params::Solution(SolutionParams {
150 | // solution: path_to_uri(file_path),
151 | // }),
152 | // };
153 |
154 | // notification.serialize()
155 | // }
156 |
157 | fn path_to_uri(file_path: &str) -> String {
158 | format!("file://{file_path}")
159 | }
160 |
161 | fn uri_to_path(uri: &str) -> &str {
162 | uri.strip_prefix("file://")
163 | .expect("URI should start with \"file://\"")
164 | }
165 |
166 | fn create_open_projects_notification(file_paths: Vec) -> String {
167 | let uris: Vec = file_paths
168 | .iter()
169 | .map(|file_path| path_to_uri(file_path))
170 | .collect();
171 |
172 | let notification = Notification {
173 | jsonrpc: "2.0".to_string(),
174 | method: "project/open".to_string(),
175 | params: Params::Project(ProjectParams { projects: uris }),
176 | };
177 |
178 | notification.serialize()
179 | }
180 |
181 | fn force_pull_diagnostics_hack(notification: &str) -> Result {
182 | let json_start = notification.find('{').ok_or(std::io::Error::new(
183 | std::io::ErrorKind::NotFound,
184 | "No JSON start found",
185 | ))?;
186 | let mut parsed_notification: Value = serde_json::from_str(¬ification[json_start..])?;
187 |
188 | let diagnostic_provider = json!({
189 | "interFileDependencies": true,
190 | "workDoneProgress": true,
191 | "workspaceDiagnostics": true
192 | });
193 |
194 | parsed_notification["result"]["capabilities"]["diagnosticProvider"] = diagnostic_provider;
195 |
196 | Ok(add_content_length_header(&parsed_notification.to_string()))
197 | }
198 |
--------------------------------------------------------------------------------
/src/notification.rs:
--------------------------------------------------------------------------------
1 | use serde::Serialize;
2 |
3 | #[derive(Serialize, Debug)]
4 | #[serde(untagged)]
5 | pub enum Params {
6 | Solution(SolutionParams),
7 | Project(ProjectParams),
8 | }
9 |
10 | #[derive(Serialize, Debug)]
11 | pub struct Notification {
12 | pub jsonrpc: String,
13 | pub method: String,
14 | pub params: Params,
15 | }
16 |
17 | #[derive(Serialize, Debug)]
18 | pub struct SolutionParams {
19 | pub solution: String,
20 | }
21 |
22 | #[derive(Serialize, Debug)]
23 | pub struct ProjectParams {
24 | pub projects: Vec,
25 | }
26 |
27 | impl Notification {
28 | pub fn serialize(self) -> String {
29 | let body = serde_json::to_string(&self).expect("Unable to serialize notification");
30 | add_content_length_header(&body)
31 | }
32 | }
33 |
34 | pub fn add_content_length_header(body: &str) -> String {
35 | let header = format!("Content-Length: {}\r\n\r\n", body.len());
36 | let full_message = format!("{}{}", header, body);
37 |
38 | full_message
39 | }
40 |
--------------------------------------------------------------------------------
/src/server.rs:
--------------------------------------------------------------------------------
1 | use directories::ProjectDirs;
2 | use std::process::Stdio;
3 | use tokio::process::Command;
4 |
5 | use crate::download_server::ensure_server_is_installed;
6 |
7 | pub async fn start_server(
8 | version: &str,
9 | ) -> (tokio::process::ChildStdin, tokio::process::ChildStdout) {
10 | let cache_dir = ProjectDirs::from("com", "github", "csharp-language-server")
11 | .expect("Unable to find cache directory")
12 | .cache_dir()
13 | .to_path_buf();
14 |
15 | let log_dir = cache_dir.join("log");
16 |
17 | let server_dll = ensure_server_is_installed(version, &cache_dir)
18 | .await
19 | .expect("Unable to install server");
20 |
21 | let command = Command::new("dotnet")
22 | .arg(server_dll)
23 | .arg("--logLevel=Information")
24 | .arg("--extensionLogDirectory")
25 | .arg(log_dir)
26 | .arg("--stdio")
27 | .stdout(Stdio::piped())
28 | .stdin(Stdio::piped())
29 | .spawn()
30 | .expect("Failed to execute command");
31 |
32 | (command.stdin.unwrap(), command.stdout.unwrap())
33 | }
34 |
--------------------------------------------------------------------------------
/src/server_version.rs:
--------------------------------------------------------------------------------
1 | pub const SERVER_VERSION: &str = "5.0.0-1.25280.9";
2 |
--------------------------------------------------------------------------------
/tests/integration_tests.rs:
--------------------------------------------------------------------------------
1 | use assert_cmd::cargo::CommandCargoExt;
2 | use std::io::{BufRead, BufReader};
3 | use std::process::{Command, Stdio};
4 |
5 | #[test]
6 | fn first_line_is_jsonrpc() {
7 | #[allow(clippy::zombie_processes)]
8 | let mut cmd = Command::cargo_bin("csharp-language-server")
9 | .unwrap()
10 | .stdout(Stdio::piped())
11 | .spawn()
12 | .expect("Failed to start process");
13 |
14 | let stdout = cmd.stdout.take().expect("Failed to capture stdout");
15 | let reader = BufReader::new(stdout);
16 | let mut lines = reader.lines();
17 |
18 | let first_line = lines
19 | .next()
20 | .expect("No output received")
21 | .expect("Failed to read line");
22 |
23 | cmd.kill().unwrap();
24 |
25 | // language server responds with a jsonrpc message
26 | assert!(first_line.contains("Content-Length"));
27 | }
28 |
--------------------------------------------------------------------------------
/upgrade-server:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | version=$(dotnet package search Microsoft.CodeAnalysis.LanguageServer.neutral --source https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-impl/nuget/v3/index.json --prerelease --format json | jq -r ".searchResult[0].packages[0].latestVersion")
4 |
5 | echo "pub const SERVER_VERSION: &str = \"$version\";" > ./src/server_version.rs
6 |
--------------------------------------------------------------------------------