From 1a6cf3b12468f7bf277202cdc620c722cb5cfc14 Mon Sep 17 00:00:00 2001 From: nvarner Date: Sat, 2 Mar 2024 12:18:32 -0500 Subject: [PATCH 1/7] basic language server implementation --- .vscode-template/launch.json | 18 + .vscode-template/tasks.json | 49 +++ Cargo.lock | 358 ++++++++++++++++++- Cargo.toml | 1 + editor/code/zls/.gitignore | 5 +- editor/code/zls/package-lock.json | 553 ++++++++++++++++++++++++++++++ editor/code/zls/package.json | 16 + editor/code/zls/src/extension.ts | 43 +++ editor/code/zls/tsconfig.json | 13 + editor/zls/Cargo.toml | 11 + editor/zls/src/main.rs | 79 +++++ 11 files changed, 1128 insertions(+), 18 deletions(-) create mode 100644 .vscode-template/launch.json create mode 100644 .vscode-template/tasks.json create mode 100644 editor/code/zls/package-lock.json create mode 100644 editor/code/zls/src/extension.ts create mode 100644 editor/code/zls/tsconfig.json create mode 100644 editor/zls/Cargo.toml create mode 100644 editor/zls/src/main.rs diff --git a/.vscode-template/launch.json b/.vscode-template/launch.json new file mode 100644 index 00000000..420eb707 --- /dev/null +++ b/.vscode-template/launch.json @@ -0,0 +1,18 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/editor/code/zls" + ], + "outFiles": [ + "${workspaceFolder}/editor/code/zls/out/**/*.js" + ], + "preLaunchTask": "VS Code Extension Prelaunch" + } + ] +} diff --git a/.vscode-template/tasks.json b/.vscode-template/tasks.json new file mode 100644 index 00000000..4ecb27d0 --- /dev/null +++ b/.vscode-template/tasks.json @@ -0,0 +1,49 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "VS Code Extension Prelaunch", + "dependsOn": [ "Compile VS Code Extension", "Build Debug LSP Binary", "Copy Debug LSP Binary to VS Code Extension" ], + "dependsOrder": "sequence" + }, + { + "label": "Compile VS Code Extension", + "type": "npm", + "script": "compile", + "path": "editor/code/zls", + "group": "build" + }, + { + "label": "Build Debug LSP Binary", + "type": "cargo", + "command": "build", + "problemMatcher": [ "$rustc" ], + "group": "build" + }, + { + "label": "Copy Debug LSP Binary to VS Code Extension", + "type": "shell", + "windows": { + "command": "cp", + "args": [ + "${workspaceFolder}\\target\\debug\\zls.exe", + "${workspaceFolder}\\editor\\code\\zls\\out\\" + ] + }, + "linux": { + "command": "cp", + "args": [ + "${workspaceFolder}/target/debug/zls", + "${workspaceFolder}/editor/code/zls/out/" + ] + }, + "osx": { + "command": "cp", + "args": [ + "${workspaceFolder}/target/debug/zls", + "${workspaceFolder}/editor/code/zls/out/" + ] + } + } + ] +} diff --git a/Cargo.lock b/Cargo.lock index 2fd1cb92..890a9fd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -71,7 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -95,6 +95,26 @@ dependencies = [ "term", ] +[[package]] +name = "async-lsp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855d6246a5d31e6e469eeef718d9a098f2d99207985a00dfdd3f4b5c5003c09a" +dependencies = [ + "futures", + "lsp-types", + "pin-project-lite", + "rustix", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower-layer", + "tower-service", + "tracing", + "waitpid-any", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -375,7 +395,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -689,7 +709,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -703,6 +723,16 @@ dependencies = [ "itoa", ] +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "im" version = "15.1.0" @@ -754,7 +784,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -923,6 +953,19 @@ dependencies = [ "logos-codegen 0.14.0", ] +[[package]] +name = "lsp-types" +version = "0.95.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984" +dependencies = [ + "bitflags 1.3.2", + "serde", + "serde_json", + "serde_repr", + "url", +] + [[package]] name = "memchr" version = "2.6.4" @@ -938,12 +981,33 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -969,6 +1033,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -989,7 +1059,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1272,7 +1342,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1350,6 +1420,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1362,6 +1443,24 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -1403,6 +1502,16 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "string_cache" version = "0.8.7" @@ -1484,6 +1593,16 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -1493,14 +1612,49 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" -version = "1.33.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", ] [[package]] @@ -1523,12 +1677,36 @@ dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1552,6 +1730,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -1560,12 +1764,27 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-width" version = "0.1.11" @@ -1584,18 +1803,46 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waitpid-any" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0189157c93c54d86e5c61ddf0c1223baa25e5bfb2f6f9983c678985b028d7c12" +dependencies = [ + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "walkdir" version = "2.4.0" @@ -1734,7 +1981,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", ] [[package]] @@ -1743,13 +1999,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -1758,42 +2029,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "yew" version = "0.20.0" @@ -1834,6 +2147,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "zls" +version = "0.1.0" +dependencies = [ + "async-lsp", + "tokio", + "tower", + "tracing", + "tracing-subscriber", +] + [[package]] name = "zydeco-derive" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 5133de47..7df81d1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,5 @@ members = [ "zydeco-lang/statics", "cli", "web", + "editor/zls", ] diff --git a/editor/code/zls/.gitignore b/editor/code/zls/.gitignore index 7b84c549..a83096b6 100644 --- a/editor/code/zls/.gitignore +++ b/editor/code/zls/.gitignore @@ -1 +1,4 @@ -!.vscode/ \ No newline at end of file +!.vscode/ + +node_modules/ +out/ diff --git a/editor/code/zls/package-lock.json b/editor/code/zls/package-lock.json new file mode 100644 index 00000000..1304b692 --- /dev/null +++ b/editor/code/zls/package-lock.json @@ -0,0 +1,553 @@ +{ + "name": "zls", + "version": "0.0.6", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "zls", + "version": "0.0.6", + "dependencies": { + "vscode-languageclient": "^9.0.1" + }, + "devDependencies": { + "@types/node": "^20.11.24", + "@types/vscode": "^1.87.0", + "esbuild": "^0.20.1", + "typescript": "^5.3.3" + }, + "engines": { + "vscode": "^1.76.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", + "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", + "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", + "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", + "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", + "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", + "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", + "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", + "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", + "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", + "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", + "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", + "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", + "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", + "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", + "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", + "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", + "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", + "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", + "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", + "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", + "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", + "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/node": { + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/vscode": { + "version": "1.87.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.87.0.tgz", + "integrity": "sha512-y3yYJV2esWr8LNjp3VNbSMWG7Y43jC8pCldG8YwiHGAQbsymkkMMt0aDT1xZIOFM2eFcNiUc+dJMx1+Z0UT8fg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/esbuild": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", + "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.1", + "@esbuild/android-arm": "0.20.1", + "@esbuild/android-arm64": "0.20.1", + "@esbuild/android-x64": "0.20.1", + "@esbuild/darwin-arm64": "0.20.1", + "@esbuild/darwin-x64": "0.20.1", + "@esbuild/freebsd-arm64": "0.20.1", + "@esbuild/freebsd-x64": "0.20.1", + "@esbuild/linux-arm": "0.20.1", + "@esbuild/linux-arm64": "0.20.1", + "@esbuild/linux-ia32": "0.20.1", + "@esbuild/linux-loong64": "0.20.1", + "@esbuild/linux-mips64el": "0.20.1", + "@esbuild/linux-ppc64": "0.20.1", + "@esbuild/linux-riscv64": "0.20.1", + "@esbuild/linux-s390x": "0.20.1", + "@esbuild/linux-x64": "0.20.1", + "@esbuild/netbsd-x64": "0.20.1", + "@esbuild/openbsd-x64": "0.20.1", + "@esbuild/sunos-x64": "0.20.1", + "@esbuild/win32-arm64": "0.20.1", + "@esbuild/win32-ia32": "0.20.1", + "@esbuild/win32-x64": "0.20.1" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageclient": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", + "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", + "dependencies": { + "minimatch": "^5.1.0", + "semver": "^7.3.7", + "vscode-languageserver-protocol": "3.17.5" + }, + "engines": { + "vscode": "^1.82.0" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/editor/code/zls/package.json b/editor/code/zls/package.json index d4e6bdc4..e1acb42e 100644 --- a/editor/code/zls/package.json +++ b/editor/code/zls/package.json @@ -14,6 +14,7 @@ "categories": [ "Programming Languages" ], + "main": "./out/extension.js", "contributes": { "languages": [ { @@ -36,5 +37,20 @@ "path": "./syntaxes/zydeco.tmLanguage.json" } ] + }, + "scripts": { + "build-base": "esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node --target=node16", + "compile": "npm run build-base -- --sourcemap", + "watch": "npm run build-base -- --sourcemap --watch", + "check": "tsc --noEmit" + }, + "devDependencies": { + "@types/node": "^20.11.24", + "@types/vscode": "^1.87.0", + "esbuild": "^0.20.1", + "typescript": "^5.3.3" + }, + "dependencies": { + "vscode-languageclient": "^9.0.1" } } diff --git a/editor/code/zls/src/extension.ts b/editor/code/zls/src/extension.ts new file mode 100644 index 00000000..1f0f2403 --- /dev/null +++ b/editor/code/zls/src/extension.ts @@ -0,0 +1,43 @@ +import { type ExtensionContext, window } from "vscode"; +import * as path from "path"; + +import { LanguageClient, LanguageClientOptions, type ServerOptions } from "vscode-languageclient/node"; + +let client: LanguageClient | undefined = undefined; + +export function activate(context: ExtensionContext): Promise { + return startClient(context).catch((e) => { + window.showErrorMessage(`Failed to activate zls: ${e}`); + throw e; + }); +} + +function startClient(context: ExtensionContext): Promise { + const serverCommand = getServer(); + const run = { + command: serverCommand, + options: { env: Object.assign({}, process.env, { RUST_BACKTRACE: "1" }) }, + }; + const serverOptions: ServerOptions = { + run, + debug: run, + }; + + const clientOptions: LanguageClientOptions = { + documentSelector: [{ scheme: "file", language: "zydeco" }], + }; + + client = new LanguageClient("zls", "Zydeco Language Server", serverOptions, clientOptions); + + return client.start(); +} + +function getServer(): string { + const windows = process.platform == "win32"; + const suffix = windows ? ".exe" : ""; + const binaryName = "zls" + suffix; + + const bundledPath = path.resolve(__dirname, binaryName); + + return bundledPath; +} diff --git a/editor/code/zls/tsconfig.json b/editor/code/zls/tsconfig.json new file mode 100644 index 00000000..e74803f1 --- /dev/null +++ b/editor/code/zls/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2020", + "lib": [ "es2020" ], + "outDir": "out", + "rootDir": "src", + "sourceMap": true, + "strict": true + }, + "include": [ "src" ], + "exclude": [ "node_modules" ] +} diff --git a/editor/zls/Cargo.toml b/editor/zls/Cargo.toml new file mode 100644 index 00000000..e9c1f2aa --- /dev/null +++ b/editor/zls/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "zls" +version = "0.1.0" +edition = "2021" + +[dependencies] +async-lsp = { version = "0.2.0", features = ["tokio"] } +tokio = { version = "1.36.0", features = ["full"] } +tower = "0.4.13" +tracing = "0.1.40" +tracing-subscriber = "0.3.18" diff --git a/editor/zls/src/main.rs b/editor/zls/src/main.rs new file mode 100644 index 00000000..17df7497 --- /dev/null +++ b/editor/zls/src/main.rs @@ -0,0 +1,79 @@ +use std::ops::ControlFlow; + +use async_lsp::client_monitor::ClientProcessMonitorLayer; +use async_lsp::concurrency::ConcurrencyLayer; +use async_lsp::lsp_types::{ + notification, request, Hover, HoverContents, HoverProviderCapability, InitializeResult, + MarkedString, ServerCapabilities, +}; +use async_lsp::panic::CatchUnwindLayer; +use async_lsp::router::Router; +use async_lsp::server::LifecycleLayer; +use async_lsp::tracing::TracingLayer; +use async_lsp::ClientSocket; +use tower::ServiceBuilder; +use tracing::Level; + +struct ServerState { + client: ClientSocket, +} + +#[tokio::main(flavor = "current_thread")] +async fn main() { + let (server, _) = async_lsp::MainLoop::new_server(|client| { + let mut router = Router::new(ServerState { client: client.clone() }); + router + .request::(|_, _params| async move { + eprintln!("init language server"); + Ok(InitializeResult { + capabilities: ServerCapabilities { + hover_provider: Some(HoverProviderCapability::Simple(true)), + ..Default::default() + }, + ..Default::default() + }) + }) + .request::(|_, _| async move { + Ok(Some(Hover { + contents: HoverContents::Scalar(MarkedString::String( + "hover from zls!!".to_owned(), + )), + range: None, + })) + }) + .notification::(|_, _| ControlFlow::Continue(())) + .notification::(|_, _| ControlFlow::Continue(())) + .notification::(|_, _| ControlFlow::Continue(())) + .notification::(|_, _| ControlFlow::Continue(())) + .notification::(|_, _| ControlFlow::Continue(())); + + ServiceBuilder::new() + .layer(TracingLayer::default()) + .layer(LifecycleLayer::default()) + .layer(CatchUnwindLayer::default()) + .layer(ConcurrencyLayer::default()) + .layer(ClientProcessMonitorLayer::new(client)) + .service(router) + }); + + tracing_subscriber::fmt() + .with_max_level(Level::INFO) + .with_ansi(false) + .with_writer(std::io::stderr) + .init(); + + // Prefer truly asynchronous piped stdin/stdout without blocking tasks. + #[cfg(unix)] + let (stdin, stdout) = ( + async_lsp::stdio::PipeStdin::lock_tokio().unwrap(), + async_lsp::stdio::PipeStdout::lock_tokio().unwrap(), + ); + // Fallback to spawn blocking read/write otherwise. + #[cfg(not(unix))] + let (stdin, stdout) = ( + tokio_util::compat::TokioAsyncReadCompatExt::compat(tokio::io::stdin()), + tokio_util::compat::TokioAsyncWriteCompatExt::compat_write(tokio::io::stdout()), + ); + + server.run_buffered(stdin, stdout).await.unwrap() +} From d57aa7dd6b13c35e7cd175b17bf97983401a829c Mon Sep 17 00:00:00 2001 From: nvarner Date: Sat, 2 Mar 2024 12:44:03 -0500 Subject: [PATCH 2/7] document sync --- Cargo.lock | 79 +++++++++++++++++++++++++++--------------- editor/zls/Cargo.toml | 2 ++ editor/zls/src/main.rs | 36 ++++++++++++++++--- 3 files changed, 85 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 890a9fd0..bfcc5412 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,7 +102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "855d6246a5d31e6e469eeef718d9a098f2d99207985a00dfdd3f4b5c5003c09a" dependencies = [ "futures", - "lsp-types", + "lsp-types 0.95.0", "pin-project-lite", "rustix", "serde", @@ -260,7 +260,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -324,7 +324,7 @@ checksum = "146398d62142a0f35248a608f17edf0dde57338354966d6e41d0eb2d16980ccb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -463,7 +463,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -917,7 +917,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -932,7 +932,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.8.2", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -953,6 +953,29 @@ dependencies = [ "logos-codegen 0.14.0", ] +[[package]] +name = "lsp-textdocument" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62dcaf776a57a63c3baafa3ab0ae25943049865c862980522a5112b1fd849503" +dependencies = [ + "lsp-types 0.94.1", + "serde_json", +] + +[[package]] +name = "lsp-types" +version = "0.94.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1" +dependencies = [ + "bitflags 1.3.2", + "serde", + "serde_json", + "serde_repr", + "url", +] + [[package]] name = "lsp-types" version = "0.95.0" @@ -1110,7 +1133,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -1184,9 +1207,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -1210,9 +1233,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1380,9 +1403,9 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -1400,20 +1423,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -1428,7 +1451,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -1544,9 +1567,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -1590,7 +1613,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -1654,7 +1677,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -1720,7 +1743,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] @@ -1880,7 +1903,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", "wasm-bindgen-shared", ] @@ -1914,7 +1937,7 @@ checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2152,6 +2175,8 @@ name = "zls" version = "0.1.0" dependencies = [ "async-lsp", + "lsp-textdocument", + "serde_json", "tokio", "tower", "tracing", @@ -2163,7 +2188,7 @@ name = "zydeco-derive" version = "0.2.0" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.52", ] [[package]] diff --git a/editor/zls/Cargo.toml b/editor/zls/Cargo.toml index e9c1f2aa..6b5cd6af 100644 --- a/editor/zls/Cargo.toml +++ b/editor/zls/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" [dependencies] async-lsp = { version = "0.2.0", features = ["tokio"] } +lsp-textdocument = "0.3.2" +serde_json = "1.0.114" tokio = { version = "1.36.0", features = ["full"] } tower = "0.4.13" tracing = "0.1.40" diff --git a/editor/zls/src/main.rs b/editor/zls/src/main.rs index 17df7497..7548c1be 100644 --- a/editor/zls/src/main.rs +++ b/editor/zls/src/main.rs @@ -2,31 +2,45 @@ use std::ops::ControlFlow; use async_lsp::client_monitor::ClientProcessMonitorLayer; use async_lsp::concurrency::ConcurrencyLayer; +use async_lsp::lsp_types::notification::Notification; use async_lsp::lsp_types::{ notification, request, Hover, HoverContents, HoverProviderCapability, InitializeResult, - MarkedString, ServerCapabilities, + MarkedString, MessageType, ServerCapabilities, ShowMessageParams, TextDocumentSyncCapability, + TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, }; use async_lsp::panic::CatchUnwindLayer; use async_lsp::router::Router; use async_lsp::server::LifecycleLayer; use async_lsp::tracing::TracingLayer; use async_lsp::ClientSocket; +use lsp_textdocument::TextDocuments; use tower::ServiceBuilder; use tracing::Level; struct ServerState { client: ClientSocket, + documents: TextDocuments, } #[tokio::main(flavor = "current_thread")] async fn main() { let (server, _) = async_lsp::MainLoop::new_server(|client| { - let mut router = Router::new(ServerState { client: client.clone() }); + let mut router = + Router::new(ServerState { client: client.clone(), documents: TextDocuments::new() }); router .request::(|_, _params| async move { eprintln!("init language server"); Ok(InitializeResult { capabilities: ServerCapabilities { + text_document_sync: Some(TextDocumentSyncCapability::Options( + TextDocumentSyncOptions { + open_close: Some(false), + change: Some(TextDocumentSyncKind::INCREMENTAL), + will_save: Some(false), + will_save_wait_until: Some(false), + save: Some(TextDocumentSyncSaveOptions::Supported(false)), + }, + )), hover_provider: Some(HoverProviderCapability::Simple(true)), ..Default::default() }, @@ -43,9 +57,21 @@ async fn main() { }) .notification::(|_, _| ControlFlow::Continue(())) .notification::(|_, _| ControlFlow::Continue(())) - .notification::(|_, _| ControlFlow::Continue(())) - .notification::(|_, _| ControlFlow::Continue(())) - .notification::(|_, _| ControlFlow::Continue(())); + .notification::(|state, params| { + let value = serde_json::to_value(params).unwrap(); + state.documents.listen(notification::DidOpenTextDocument::METHOD, &value); + ControlFlow::Continue(()) + }) + .notification::(|state, params| { + let value = serde_json::to_value(params).unwrap(); + state.documents.listen(notification::DidChangeTextDocument::METHOD, &value); + ControlFlow::Continue(()) + }) + .notification::(|state, params| { + let value = serde_json::to_value(params).unwrap(); + state.documents.listen(notification::DidCloseTextDocument::METHOD, &value); + ControlFlow::Continue(()) + }); ServiceBuilder::new() .layer(TracingLayer::default()) From e36541a49fef5c8aaabf435764234769a2ad17b0 Mon Sep 17 00:00:00 2001 From: nvarner Date: Sat, 2 Mar 2024 17:50:18 -0500 Subject: [PATCH 3/7] custom document store --- editor/zls/src/documents.rs | 81 +++++++++++++++++++++++++++++++++++++ editor/zls/src/main.rs | 40 ++++++++++-------- 2 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 editor/zls/src/documents.rs diff --git a/editor/zls/src/documents.rs b/editor/zls/src/documents.rs new file mode 100644 index 00000000..39d4ce6c --- /dev/null +++ b/editor/zls/src/documents.rs @@ -0,0 +1,81 @@ +use std::collections::HashMap; +use std::future::Future; +use std::ops::Deref; +use std::sync::Arc; + +use async_lsp::lsp_types::{ + DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, Url, +}; +use lsp_textdocument::FullTextDocument; +use tokio::sync::{OwnedRwLockReadGuard, RwLock}; + +// TODO: virtual filesystem abstraction to handle on-disk and client-provided documents +#[derive(Default)] +pub struct DocumentStore { + inner: Arc>>, +} + +impl DocumentStore { + /// Returns a [`Future`] which, if the document at the requested [`Url`] exists, resolves to an + /// owned read lock providing access to that document. + pub fn get_document( + &self, url: Url, + ) -> impl Future>> + Send + 'static { + // Notes on the signature and implementation: + // - The `Future`s returned by the LSP router require `Send + 'static`, so for convenience, + // we want to provide a fully owned, thread safe `Future` given a reference to the + // document store. + // - For correctness reasons, it is nice to put an `RwLock` around everything, since this + // prevents modifications to the project from impacting ongoing analysis. A more complex, + // but potentially faster, approach would be to allow for limited forms of this, or to + // track and protect dependencies/dependents so that fined-grained locking can be used + // instead. + // - The `impl Deref<...>` type name is used because the actual type is an implementation + // detail (depends on our `RwLock` implementation) and is long and complex. + + let inner = Arc::clone(&self.inner); + async move { + let guard = inner.read_owned().await; + let doc = OwnedRwLockReadGuard::try_map(guard, move |doc_map| doc_map.get(&url)).ok(); + doc + } + } + + pub fn open_document(&self, params: DidOpenTextDocumentParams) -> impl Future { + let inner = Arc::clone(&self.inner); + async move { + let doc = FullTextDocument::new( + params.text_document.language_id, + params.text_document.version, + params.text_document.text, + ); + + let mut doc_map = inner.write().await; + doc_map.insert(params.text_document.uri, doc); + } + } + + pub fn change_document(&self, params: DidChangeTextDocumentParams) -> impl Future { + let inner = Arc::clone(&self.inner); + async move { + let mut doc_map = inner.write().await; + let Some(doc) = doc_map.get_mut(¶ms.text_document.uri) else { + return; + }; + + // hack around mismatched `lsp_types` version + let changes: Vec<_> = + serde_json::from_value(serde_json::to_value(params.content_changes).unwrap()) + .unwrap(); + doc.update(&changes, params.text_document.version); + } + } + + pub fn close_document(&self, params: DidCloseTextDocumentParams) -> impl Future { + let inner = Arc::clone(&self.inner); + async move { + let mut doc_map = inner.write().await; + doc_map.remove(¶ms.text_document.uri); + } + } +} diff --git a/editor/zls/src/main.rs b/editor/zls/src/main.rs index 7548c1be..bdad1d76 100644 --- a/editor/zls/src/main.rs +++ b/editor/zls/src/main.rs @@ -13,20 +13,22 @@ use async_lsp::router::Router; use async_lsp::server::LifecycleLayer; use async_lsp::tracing::TracingLayer; use async_lsp::ClientSocket; -use lsp_textdocument::TextDocuments; +use documents::DocumentStore; use tower::ServiceBuilder; use tracing::Level; +mod documents; + struct ServerState { client: ClientSocket, - documents: TextDocuments, + documents: DocumentStore, } #[tokio::main(flavor = "current_thread")] async fn main() { let (server, _) = async_lsp::MainLoop::new_server(|client| { let mut router = - Router::new(ServerState { client: client.clone(), documents: TextDocuments::new() }); + Router::new(ServerState { client: client.clone(), documents: Default::default() }); router .request::(|_, _params| async move { eprintln!("init language server"); @@ -34,7 +36,7 @@ async fn main() { capabilities: ServerCapabilities { text_document_sync: Some(TextDocumentSyncCapability::Options( TextDocumentSyncOptions { - open_close: Some(false), + open_close: Some(true), change: Some(TextDocumentSyncKind::INCREMENTAL), will_save: Some(false), will_save_wait_until: Some(false), @@ -47,29 +49,33 @@ async fn main() { ..Default::default() }) }) - .request::(|_, _| async move { - Ok(Some(Hover { - contents: HoverContents::Scalar(MarkedString::String( - "hover from zls!!".to_owned(), - )), - range: None, - })) + .request::(|state, params| { + let document = state + .documents + .get_document(params.text_document_position_params.text_document.uri); + + async move { + let document = document.await.unwrap(); + let content = document.get_content(None); + + Ok(Some(Hover { + contents: HoverContents::Scalar(MarkedString::String(content.to_owned())), + range: None, + })) + } }) .notification::(|_, _| ControlFlow::Continue(())) .notification::(|_, _| ControlFlow::Continue(())) .notification::(|state, params| { - let value = serde_json::to_value(params).unwrap(); - state.documents.listen(notification::DidOpenTextDocument::METHOD, &value); + tokio::spawn(state.documents.open_document(params)); ControlFlow::Continue(()) }) .notification::(|state, params| { - let value = serde_json::to_value(params).unwrap(); - state.documents.listen(notification::DidChangeTextDocument::METHOD, &value); + tokio::spawn(state.documents.change_document(params)); ControlFlow::Continue(()) }) .notification::(|state, params| { - let value = serde_json::to_value(params).unwrap(); - state.documents.listen(notification::DidCloseTextDocument::METHOD, &value); + tokio::spawn(state.documents.close_document(params)); ControlFlow::Continue(()) }); From 1e30a5a597f984b934f4ccaf5457b17951b79d97 Mon Sep 17 00:00:00 2001 From: nvarner Date: Sat, 2 Mar 2024 20:43:48 -0500 Subject: [PATCH 4/7] document symbols --- Cargo.lock | 1 + docs/parser_combinator/parser_revisited.zy | 2 +- editor/zls/Cargo.toml | 1 + editor/zls/src/document_symbols.rs | 122 +++++++++++++++++++ editor/zls/src/documents.rs | 14 ++- editor/zls/src/main.rs | 26 ++-- editor/zls/src/text_position.rs | 12 ++ zydeco-lang/src/statics/elab.rs | 4 +- zydeco-lang/src/surface/parse/parser.lalrpop | 4 +- zydeco-lang/src/surface/parse/syntax.rs | 4 +- zydeco-lang/utils/src/span.rs | 8 +- 11 files changed, 169 insertions(+), 29 deletions(-) create mode 100644 editor/zls/src/document_symbols.rs create mode 100644 editor/zls/src/text_position.rs diff --git a/Cargo.lock b/Cargo.lock index bfcc5412..a0016092 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2181,6 +2181,7 @@ dependencies = [ "tower", "tracing", "tracing-subscriber", + "zydeco-lang", ] [[package]] diff --git a/docs/parser_combinator/parser_revisited.zy b/docs/parser_combinator/parser_revisited.zy index af6bb285..8de19d49 100644 --- a/docs/parser_combinator/parser_revisited.zy +++ b/docs/parser_combinator/parser_revisited.zy @@ -24,4 +24,4 @@ alias ReaderM (M : VType -> CType) (S : VType) (A : VType) = S -> M A end main ! exit 0 -end \ No newline at end of file +end diff --git a/editor/zls/Cargo.toml b/editor/zls/Cargo.toml index 6b5cd6af..4e47a9c2 100644 --- a/editor/zls/Cargo.toml +++ b/editor/zls/Cargo.toml @@ -11,3 +11,4 @@ tokio = { version = "1.36.0", features = ["full"] } tower = "0.4.13" tracing = "0.1.40" tracing-subscriber = "0.3.18" +zydeco-lang = { path = "../../zydeco-lang" } diff --git a/editor/zls/src/document_symbols.rs b/editor/zls/src/document_symbols.rs new file mode 100644 index 00000000..7786f8c2 --- /dev/null +++ b/editor/zls/src/document_symbols.rs @@ -0,0 +1,122 @@ +use std::path::PathBuf; + +use async_lsp::lsp_types::{DocumentSymbol, DocumentSymbolResponse, SymbolKind}; +use async_lsp::{ErrorCode, ResponseError}; +use lsp_textdocument::FullTextDocument; +use zydeco_lang::surface::parse::syntax::Declaration; +use zydeco_lang::syntax::{CtorV, DeclSymbol, DtorV, NameT}; +use zydeco_lang::utils::span::{Sp, Span, SpanView}; +use zydeco_lang::zydeco::ZydecoFile; + +use crate::text_position::span_to_range; + +pub fn handle( + document: &FullTextDocument, +) -> Result, ResponseError> { + let ast = ZydecoFile::parse_src(document.get_content(None), PathBuf::new()).map_err(|err| { + ResponseError::new(ErrorCode::REQUEST_FAILED, format!("parsing error: {err}")) + })?; + + let symbols = ast.inner.declarations.iter().flat_map(declaration_to_symbol).collect(); + Ok(Some(DocumentSymbolResponse::Nested(symbols))) +} + +fn declaration_to_symbol(decl: &Sp>) -> Vec { + match &decl.inner.inner { + Declaration::Module(module_def) => { + let children = module_def.declarations.iter().flat_map(declaration_to_symbol).collect(); + + match &module_def.name { + Some(name_ref) => { + vec![name_to_symbol(name_ref, decl.span(), SymbolKind::MODULE, children)] + } + None => children, + } + } + Declaration::UseDef(_) => vec![], + Declaration::Data(data_def) => { + let children = data_def.ctors.iter().map(|ctor| ctorv_to_symbol(&ctor.ctorv)).collect(); + + vec![name_to_symbol(&data_def.name, decl.span(), SymbolKind::ENUM, children)] + } + Declaration::Codata(codata_def) => { + let children = + codata_def.dtors.iter().map(|dtor| dtorv_to_symbol(&dtor.dtorv)).collect(); + + vec![name_to_symbol(&codata_def.name, decl.span(), SymbolKind::CLASS, children)] + } + Declaration::Alias(alias_def) => { + // TODO: lookup symbol to display correct kind + vec![name_to_symbol(&alias_def.name, decl.span(), SymbolKind::ENUM, vec![])] + } + Declaration::Define(def) => { + // TODO: handle local definitions + let children = vec![]; + + let kind = match def.0.params.len() { + 0 => SymbolKind::CONSTANT, + _ => SymbolKind::FUNCTION, + }; + + vec![name_to_symbol(&def.0.name.0, decl.span(), kind, children)] + } + // TODO: handle main, local definitions + Declaration::Main(_) => vec![], + } +} + +#[allow(deprecated)] +fn name_to_symbol( + name: &impl NameT, item_span: &Span, kind: SymbolKind, children: Vec, +) -> DocumentSymbol { + let name_view = name.name(); + let name_str = name_view.ident.inner.clone(); + let name_range = span_to_range(name_view.ident.span()); + + let item_range = span_to_range(item_span); + + DocumentSymbol { + name: name_str, + detail: None, + kind, + tags: None, + deprecated: None, + range: item_range, + selection_range: name_range, + children: Some(children), + } +} + +#[allow(deprecated)] +fn ctorv_to_symbol(ctorv: &CtorV) -> DocumentSymbol { + let name_range = span_to_range(ctorv.span()); + + DocumentSymbol { + name: ctorv.name().to_owned(), + detail: None, + kind: SymbolKind::CONSTRUCTOR, + tags: None, + deprecated: None, + // TODO: get span of entire constructor + range: name_range, + selection_range: name_range, + children: None, + } +} + +#[allow(deprecated)] +fn dtorv_to_symbol(dtorv: &DtorV) -> DocumentSymbol { + let name_range = span_to_range(dtorv.span()); + + DocumentSymbol { + name: dtorv.name().to_owned(), + detail: None, + kind: SymbolKind::METHOD, + tags: None, + deprecated: None, + // TODO: get span of entire constructor + range: name_range, + selection_range: name_range, + children: None, + } +} diff --git a/editor/zls/src/documents.rs b/editor/zls/src/documents.rs index 39d4ce6c..c6633391 100644 --- a/editor/zls/src/documents.rs +++ b/editor/zls/src/documents.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use async_lsp::lsp_types::{ DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, Url, }; +use async_lsp::{ErrorCode, ResponseError}; use lsp_textdocument::FullTextDocument; use tokio::sync::{OwnedRwLockReadGuard, RwLock}; @@ -20,7 +21,9 @@ impl DocumentStore { /// owned read lock providing access to that document. pub fn get_document( &self, url: Url, - ) -> impl Future>> + Send + 'static { + ) -> impl Future, ResponseError>> + + Send + + 'static { // Notes on the signature and implementation: // - The `Future`s returned by the LSP router require `Send + 'static`, so for convenience, // we want to provide a fully owned, thread safe `Future` given a reference to the @@ -36,8 +39,13 @@ impl DocumentStore { let inner = Arc::clone(&self.inner); async move { let guard = inner.read_owned().await; - let doc = OwnedRwLockReadGuard::try_map(guard, move |doc_map| doc_map.get(&url)).ok(); - doc + let doc = OwnedRwLockReadGuard::try_map(guard, |doc_map| doc_map.get(&url)).ok(); + doc.ok_or_else(|| { + ResponseError::new( + ErrorCode::INVALID_PARAMS, + format!("could not find document {url}"), + ) + }) } } diff --git a/editor/zls/src/main.rs b/editor/zls/src/main.rs index bdad1d76..0c56073f 100644 --- a/editor/zls/src/main.rs +++ b/editor/zls/src/main.rs @@ -2,10 +2,8 @@ use std::ops::ControlFlow; use async_lsp::client_monitor::ClientProcessMonitorLayer; use async_lsp::concurrency::ConcurrencyLayer; -use async_lsp::lsp_types::notification::Notification; use async_lsp::lsp_types::{ - notification, request, Hover, HoverContents, HoverProviderCapability, InitializeResult, - MarkedString, MessageType, ServerCapabilities, ShowMessageParams, TextDocumentSyncCapability, + notification, request, InitializeResult, OneOf, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, }; use async_lsp::panic::CatchUnwindLayer; @@ -18,8 +16,10 @@ use tower::ServiceBuilder; use tracing::Level; mod documents; +mod document_symbols; +mod text_position; -struct ServerState { +pub struct ServerState { client: ClientSocket, documents: DocumentStore, } @@ -31,7 +31,6 @@ async fn main() { Router::new(ServerState { client: client.clone(), documents: Default::default() }); router .request::(|_, _params| async move { - eprintln!("init language server"); Ok(InitializeResult { capabilities: ServerCapabilities { text_document_sync: Some(TextDocumentSyncCapability::Options( @@ -43,25 +42,18 @@ async fn main() { save: Some(TextDocumentSyncSaveOptions::Supported(false)), }, )), - hover_provider: Some(HoverProviderCapability::Simple(true)), + document_symbol_provider: Some(OneOf::Left(true)), ..Default::default() }, ..Default::default() }) }) - .request::(|state, params| { - let document = state - .documents - .get_document(params.text_document_position_params.text_document.uri); + .request::(|state, params| { + let document = state.documents.get_document(params.text_document.uri); async move { - let document = document.await.unwrap(); - let content = document.get_content(None); - - Ok(Some(Hover { - contents: HoverContents::Scalar(MarkedString::String(content.to_owned())), - range: None, - })) + let document = document.await?; + document_symbols::handle(&document) } }) .notification::(|_, _| ControlFlow::Continue(())) diff --git a/editor/zls/src/text_position.rs b/editor/zls/src/text_position.rs new file mode 100644 index 00000000..41a160d9 --- /dev/null +++ b/editor/zls/src/text_position.rs @@ -0,0 +1,12 @@ +use async_lsp::lsp_types::{Position, Range}; +use zydeco_lang::utils::span::{Cursor2, Span}; + +pub fn span_to_range(span: &Span) -> Range { + let (l, r) = span.get_cursor2(); + Range::new(cursor2_to_position(l), cursor2_to_position(r)) +} + +// TODO: handle UTF-16 encoding +fn cursor2_to_position(cursor2: &Cursor2) -> Position { + Position::new(cursor2.line as u32 - 1, cursor2.column as u32 - 1) +} diff --git a/zydeco-lang/src/statics/elab.rs b/zydeco-lang/src/statics/elab.rs index e72ded26..768b6f87 100644 --- a/zydeco-lang/src/statics/elab.rs +++ b/zydeco-lang/src/statics/elab.rs @@ -537,7 +537,7 @@ impl Elaboration for Module { let mut define = Vec::new(); let mut define_ext = Vec::new(); for declaration in declarations { - let DeclSymbol { public, external, inner } = declaration; + let DeclSymbol { public, external, inner } = declaration.inner; match inner { ps::Declaration::Module(m) => { let Module { @@ -599,7 +599,7 @@ impl Elaboration for Program { let mut non_main = Vec::new(); let mut main_entry = None; for decl in declarations { - match decl.inner { + match decl.inner.inner { ps::Declaration::Main(ps::Main { entry }) => { if main_entry.is_some() { Err(TyckErrorItem::MultipleMainEntries)? diff --git a/zydeco-lang/src/surface/parse/parser.lalrpop b/zydeco-lang/src/surface/parse/parser.lalrpop index 3de74258..edcdeda8 100644 --- a/zydeco-lang/src/surface/parse/parser.lalrpop +++ b/zydeco-lang/src/surface/parse/parser.lalrpop @@ -11,7 +11,7 @@ grammar<'input>(input: &'input str); pub Zydeco: Sp = Sp; TopLevel: TopLevel = { - *> => { + >*> => { TopLevel { declarations: declarations, } @@ -28,7 +28,7 @@ DeclSymbol: DeclSymbol = { Declaration: Declaration = { "module" ?> "where" - *> + >*> "end" => Module { name, declarations }.into(), diff --git a/zydeco-lang/src/surface/parse/syntax.rs b/zydeco-lang/src/surface/parse/syntax.rs index 52fb0870..da95c3f1 100644 --- a/zydeco-lang/src/surface/parse/syntax.rs +++ b/zydeco-lang/src/surface/parse/syntax.rs @@ -112,7 +112,7 @@ pub enum Term { #[derive(SpanHolder, Clone, Debug)] pub struct Module { pub name: Option, - pub declarations: Vec>, + pub declarations: Vec>>, } #[derive(SpanHolder, Clone, Debug)] @@ -152,7 +152,7 @@ pub enum Declaration { #[derive(SpanHolder, Clone, Debug)] pub struct TopLevel { - pub declarations: Vec>, + pub declarations: Vec>>, } impl Monoid for TopLevel { diff --git a/zydeco-lang/utils/src/span.rs b/zydeco-lang/utils/src/span.rs index 8f8637b1..197c220c 100644 --- a/zydeco-lang/utils/src/span.rs +++ b/zydeco-lang/utils/src/span.rs @@ -84,6 +84,10 @@ impl Span { .expect("span2 is already set"); self.path.set(gen.path.clone()).expect("path is already set"); } + pub fn get_cursor2(&self) -> (&Cursor2, &Cursor2) { + let (l, r) = self.span2.get().expect("span2 is not set"); + (l, r) + } } impl Display for Span { @@ -241,7 +245,7 @@ impl Sp { } pub fn try_map(self, f: F) -> Result, E> where - F: FnOnce(T) -> Result, + F: FnOnce(T) -> Result, { Ok(self.info.make(f(self.inner)?)) } @@ -253,7 +257,7 @@ impl Sp { } pub fn try_map_ref(&self, f: F) -> Result, E> where - F: FnOnce(&T) -> Result, + F: FnOnce(&T) -> Result, { Ok(self.info.make(f(&self.inner)?)) } From 8ef2f1d0d4577b5c8933014310d079ddb34b8839 Mon Sep 17 00:00:00 2001 From: nvarner Date: Sun, 3 Mar 2024 14:28:46 -0500 Subject: [PATCH 5/7] utf-16 document positions --- editor/zls/src/document_symbols.rs | 66 +++++++++++++++++++++--------- editor/zls/src/text_position.rs | 15 +++---- zydeco-lang/utils/src/span.rs | 5 +-- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/editor/zls/src/document_symbols.rs b/editor/zls/src/document_symbols.rs index 7786f8c2..a685a516 100644 --- a/editor/zls/src/document_symbols.rs +++ b/editor/zls/src/document_symbols.rs @@ -17,37 +17,64 @@ pub fn handle( ResponseError::new(ErrorCode::REQUEST_FAILED, format!("parsing error: {err}")) })?; - let symbols = ast.inner.declarations.iter().flat_map(declaration_to_symbol).collect(); + let symbols = ast + .inner + .declarations + .iter() + .flat_map(|decl| declaration_to_symbol(decl, document)) + .collect(); Ok(Some(DocumentSymbolResponse::Nested(symbols))) } -fn declaration_to_symbol(decl: &Sp>) -> Vec { +fn declaration_to_symbol( + decl: &Sp>, document: &FullTextDocument, +) -> Vec { match &decl.inner.inner { Declaration::Module(module_def) => { - let children = module_def.declarations.iter().flat_map(declaration_to_symbol).collect(); + let children = module_def + .declarations + .iter() + .flat_map(|decl| declaration_to_symbol(decl, document)) + .collect(); match &module_def.name { Some(name_ref) => { - vec![name_to_symbol(name_ref, decl.span(), SymbolKind::MODULE, children)] + vec![name_to_symbol( + name_ref, + decl.span(), + document, + SymbolKind::MODULE, + children, + )] } None => children, } } Declaration::UseDef(_) => vec![], Declaration::Data(data_def) => { - let children = data_def.ctors.iter().map(|ctor| ctorv_to_symbol(&ctor.ctorv)).collect(); + let children = + data_def.ctors.iter().map(|ctor| ctorv_to_symbol(&ctor.ctorv, document)).collect(); - vec![name_to_symbol(&data_def.name, decl.span(), SymbolKind::ENUM, children)] + vec![name_to_symbol(&data_def.name, decl.span(), document, SymbolKind::ENUM, children)] } Declaration::Codata(codata_def) => { - let children = - codata_def.dtors.iter().map(|dtor| dtorv_to_symbol(&dtor.dtorv)).collect(); - - vec![name_to_symbol(&codata_def.name, decl.span(), SymbolKind::CLASS, children)] + let children = codata_def + .dtors + .iter() + .map(|dtor| dtorv_to_symbol(&dtor.dtorv, document)) + .collect(); + + vec![name_to_symbol( + &codata_def.name, + decl.span(), + document, + SymbolKind::CLASS, + children, + )] } Declaration::Alias(alias_def) => { // TODO: lookup symbol to display correct kind - vec![name_to_symbol(&alias_def.name, decl.span(), SymbolKind::ENUM, vec![])] + vec![name_to_symbol(&alias_def.name, decl.span(), document, SymbolKind::ENUM, vec![])] } Declaration::Define(def) => { // TODO: handle local definitions @@ -58,7 +85,7 @@ fn declaration_to_symbol(decl: &Sp>) -> Vec SymbolKind::FUNCTION, }; - vec![name_to_symbol(&def.0.name.0, decl.span(), kind, children)] + vec![name_to_symbol(&def.0.name.0, decl.span(), document, kind, children)] } // TODO: handle main, local definitions Declaration::Main(_) => vec![], @@ -67,13 +94,14 @@ fn declaration_to_symbol(decl: &Sp>) -> Vec, + name: &impl NameT, item_span: &Span, document: &FullTextDocument, kind: SymbolKind, + children: Vec, ) -> DocumentSymbol { let name_view = name.name(); let name_str = name_view.ident.inner.clone(); - let name_range = span_to_range(name_view.ident.span()); + let name_range = span_to_range(name_view.ident.span(), document); - let item_range = span_to_range(item_span); + let item_range = span_to_range(item_span, document); DocumentSymbol { name: name_str, @@ -88,8 +116,8 @@ fn name_to_symbol( } #[allow(deprecated)] -fn ctorv_to_symbol(ctorv: &CtorV) -> DocumentSymbol { - let name_range = span_to_range(ctorv.span()); +fn ctorv_to_symbol(ctorv: &CtorV, document: &FullTextDocument) -> DocumentSymbol { + let name_range = span_to_range(ctorv.span(), document); DocumentSymbol { name: ctorv.name().to_owned(), @@ -105,8 +133,8 @@ fn ctorv_to_symbol(ctorv: &CtorV) -> DocumentSymbol { } #[allow(deprecated)] -fn dtorv_to_symbol(dtorv: &DtorV) -> DocumentSymbol { - let name_range = span_to_range(dtorv.span()); +fn dtorv_to_symbol(dtorv: &DtorV, document: &FullTextDocument) -> DocumentSymbol { + let name_range = span_to_range(dtorv.span(), document); DocumentSymbol { name: dtorv.name().to_owned(), diff --git a/editor/zls/src/text_position.rs b/editor/zls/src/text_position.rs index 41a160d9..ef23fd25 100644 --- a/editor/zls/src/text_position.rs +++ b/editor/zls/src/text_position.rs @@ -1,12 +1,13 @@ use async_lsp::lsp_types::{Position, Range}; -use zydeco_lang::utils::span::{Cursor2, Span}; +use lsp_textdocument::FullTextDocument; +use zydeco_lang::utils::span::{Cursor1, Span}; -pub fn span_to_range(span: &Span) -> Range { - let (l, r) = span.get_cursor2(); - Range::new(cursor2_to_position(l), cursor2_to_position(r)) +pub fn span_to_range(span: &Span, document: &FullTextDocument) -> Range { + let (l, r) = span.get_cursor1(); + Range::new(cursor1_to_position(l, document), cursor1_to_position(r, document)) } -// TODO: handle UTF-16 encoding -fn cursor2_to_position(cursor2: &Cursor2) -> Position { - Position::new(cursor2.line as u32 - 1, cursor2.column as u32 - 1) +fn cursor1_to_position(cursor1: Cursor1, document: &FullTextDocument) -> Position { + serde_json::from_value(serde_json::to_value(document.position_at(cursor1 as u32)).unwrap()) + .unwrap() } diff --git a/zydeco-lang/utils/src/span.rs b/zydeco-lang/utils/src/span.rs index 197c220c..dd01c625 100644 --- a/zydeco-lang/utils/src/span.rs +++ b/zydeco-lang/utils/src/span.rs @@ -84,9 +84,8 @@ impl Span { .expect("span2 is already set"); self.path.set(gen.path.clone()).expect("path is already set"); } - pub fn get_cursor2(&self) -> (&Cursor2, &Cursor2) { - let (l, r) = self.span2.get().expect("span2 is not set"); - (l, r) + pub fn get_cursor1(&self) -> (Cursor1, Cursor1) { + self.span1 } } From 9bb89d354d4d9332bcbee5c371d18f8a4f0bace9 Mon Sep 17 00:00:00 2001 From: nvarner Date: Tue, 5 Mar 2024 11:50:33 -0500 Subject: [PATCH 6/7] move .vscode into editor/ --- editor/.gitignore | 1 + {.vscode-template => editor/.vscode}/launch.json | 4 ++-- {.vscode-template => editor/.vscode}/tasks.json | 14 +++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 editor/.gitignore rename {.vscode-template => editor/.vscode}/launch.json (71%) rename {.vscode-template => editor/.vscode}/tasks.json (72%) diff --git a/editor/.gitignore b/editor/.gitignore new file mode 100644 index 00000000..32926df7 --- /dev/null +++ b/editor/.gitignore @@ -0,0 +1 @@ +!.vscode/ diff --git a/.vscode-template/launch.json b/editor/.vscode/launch.json similarity index 71% rename from .vscode-template/launch.json rename to editor/.vscode/launch.json index 420eb707..68890339 100644 --- a/.vscode-template/launch.json +++ b/editor/.vscode/launch.json @@ -7,10 +7,10 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--extensionDevelopmentPath=${workspaceFolder}/editor/code/zls" + "--extensionDevelopmentPath=${workspaceFolder}/code/zls" ], "outFiles": [ - "${workspaceFolder}/editor/code/zls/out/**/*.js" + "${workspaceFolder}/code/zls/out/**/*.js" ], "preLaunchTask": "VS Code Extension Prelaunch" } diff --git a/.vscode-template/tasks.json b/editor/.vscode/tasks.json similarity index 72% rename from .vscode-template/tasks.json rename to editor/.vscode/tasks.json index 4ecb27d0..6432b50a 100644 --- a/.vscode-template/tasks.json +++ b/editor/.vscode/tasks.json @@ -10,7 +10,7 @@ "label": "Compile VS Code Extension", "type": "npm", "script": "compile", - "path": "editor/code/zls", + "path": "code/zls/", "group": "build" }, { @@ -26,22 +26,22 @@ "windows": { "command": "cp", "args": [ - "${workspaceFolder}\\target\\debug\\zls.exe", - "${workspaceFolder}\\editor\\code\\zls\\out\\" + "${workspaceFolder}\\..\\target\\debug\\zls.exe", + "${workspaceFolder}\\code\\zls\\out\\" ] }, "linux": { "command": "cp", "args": [ - "${workspaceFolder}/target/debug/zls", - "${workspaceFolder}/editor/code/zls/out/" + "${workspaceFolder}/../target/debug/zls", + "${workspaceFolder}/code/zls/out/" ] }, "osx": { "command": "cp", "args": [ - "${workspaceFolder}/target/debug/zls", - "${workspaceFolder}/editor/code/zls/out/" + "${workspaceFolder}/../target/debug/zls", + "${workspaceFolder}/code/zls/out/" ] } } From da625a9ef4e5c021bff8486818c14272971b9685 Mon Sep 17 00:00:00 2001 From: nvarner Date: Tue, 5 Mar 2024 14:16:09 -0500 Subject: [PATCH 7/7] minimize #[allow(deprecated)] --- editor/zls/src/document_symbols.rs | 58 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/editor/zls/src/document_symbols.rs b/editor/zls/src/document_symbols.rs index a685a516..8cffa50e 100644 --- a/editor/zls/src/document_symbols.rs +++ b/editor/zls/src/document_symbols.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use async_lsp::lsp_types::{DocumentSymbol, DocumentSymbolResponse, SymbolKind}; +use async_lsp::lsp_types::{DocumentSymbol, DocumentSymbolResponse, Range, SymbolKind}; use async_lsp::{ErrorCode, ResponseError}; use lsp_textdocument::FullTextDocument; use zydeco_lang::surface::parse::syntax::Declaration; @@ -92,7 +92,6 @@ fn declaration_to_symbol( } } -#[allow(deprecated)] fn name_to_symbol( name: &impl NameT, item_span: &Span, document: &FullTextDocument, kind: SymbolKind, children: Vec, @@ -103,48 +102,45 @@ fn name_to_symbol( let item_range = span_to_range(item_span, document); - DocumentSymbol { - name: name_str, - detail: None, - kind, - tags: None, - deprecated: None, - range: item_range, - selection_range: name_range, - children: Some(children), - } + document_symbol_new(name_str, kind, item_range, name_range, Some(children)) } -#[allow(deprecated)] fn ctorv_to_symbol(ctorv: &CtorV, document: &FullTextDocument) -> DocumentSymbol { let name_range = span_to_range(ctorv.span(), document); - DocumentSymbol { - name: ctorv.name().to_owned(), - detail: None, - kind: SymbolKind::CONSTRUCTOR, - tags: None, - deprecated: None, - // TODO: get span of entire constructor - range: name_range, - selection_range: name_range, - children: None, - } + // TODO: get span of entire constructor + document_symbol_new( + ctorv.name().to_owned(), + SymbolKind::CONSTRUCTOR, + name_range, + name_range, + None, + ) } -#[allow(deprecated)] fn dtorv_to_symbol(dtorv: &DtorV, document: &FullTextDocument) -> DocumentSymbol { let name_range = span_to_range(dtorv.span(), document); + // TODO: get span of entire destructor + document_symbol_new(dtorv.name().to_owned(), SymbolKind::METHOD, name_range, name_range, None) +} + +/// Constructs a [`DocumentSymbol`]. Since `DocumentSymbol::deprecated` is marked as +/// `#[deprecated]`, we must put `#[allow(deprecated)]` on any function directly constructing a +/// `DocumentSymbol`. We define this function to minimize where this happens. +#[allow(deprecated)] +fn document_symbol_new( + name: String, kind: SymbolKind, range: Range, selection_range: Range, + children: Option>, +) -> DocumentSymbol { DocumentSymbol { - name: dtorv.name().to_owned(), + name, detail: None, - kind: SymbolKind::METHOD, + kind, tags: None, deprecated: None, - // TODO: get span of entire constructor - range: name_range, - selection_range: name_range, - children: None, + range, + selection_range, + children, } }