├── .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 | --------------------------------------------------------------------------------