mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-25 19:03:30 +04:00
Merge branch 'master' into pull-diagnostics
This commit is contained in:
commit
d8fd20482b
230
Cargo.lock
generated
230
Cargo.lock
generated
@ -136,9 +136,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.6"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
|
||||
checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@ -272,7 +272,7 @@ dependencies = [
|
||||
"filedescriptor",
|
||||
"futures-core",
|
||||
"libc",
|
||||
"mio",
|
||||
"mio 0.8.11",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
@ -541,9 +541,9 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||
|
||||
[[package]]
|
||||
name = "gix"
|
||||
version = "0.63.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "984c5018adfa7a4536ade67990b3ebc6e11ab57b3d6cd9968de0947ca99b4b06"
|
||||
checksum = "d78414d29fcc82329080166077e0f7689f4016551fdb334d787c3d040fe2634f"
|
||||
dependencies = [
|
||||
"gix-actor",
|
||||
"gix-attributes",
|
||||
@ -584,16 +584,15 @@ dependencies = [
|
||||
"gix-validate",
|
||||
"gix-worktree",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-actor"
|
||||
version = "0.31.2"
|
||||
version = "0.31.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d69c59d392c7e6c94385b6fd6089d6df0fe945f32b4357687989f3aee253cd7f"
|
||||
checksum = "a0e454357e34b833cc3a00b6efbbd3dd4d18b24b9fb0c023876ec2645e8aa3f2"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-date",
|
||||
@ -605,9 +604,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-attributes"
|
||||
version = "0.22.2"
|
||||
version = "0.22.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eefb48f42eac136a4a0023f49a54ec31be1c7a9589ed762c45dcb9b953f7ecc8"
|
||||
checksum = "e37ce99c7e81288c28b703641b6d5d119aacc45c1a6b247156e6249afa486257"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-glob",
|
||||
@ -640,9 +639,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-command"
|
||||
version = "0.3.7"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c22e086314095c43ffe5cdc5c0922d5439da4fd726f3b0438c56147c34dc225"
|
||||
checksum = "0d76867867da891cbe32021ad454e8cae90242f6afb06762e4dd0d357afd1d7b"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-path",
|
||||
@ -652,9 +651,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-commitgraph"
|
||||
version = "0.24.2"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7b102311085da4af18823413b5176d7c500fb2272eaf391cfa8635d8bcb12c4"
|
||||
checksum = "133b06f67f565836ec0c473e2116a60fb74f80b6435e21d88013ac0e3c60fc78"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-chunk",
|
||||
@ -666,9 +665,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-config"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53fafe42957e11d98e354a66b6bd70aeea00faf2f62dd11164188224a507c840"
|
||||
checksum = "28f53fd03d1bf09ebcc2c8654f08969439c4556e644ca925f27cf033bc43e658"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-config-value",
|
||||
@ -687,9 +686,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-config-value"
|
||||
version = "0.14.6"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbd06203b1a9b33a78c88252a625031b094d9e1b647260070c25b09910c0a804"
|
||||
checksum = "b328997d74dd15dc71b2773b162cb4af9a25c424105e4876e6d0686ab41c383e"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bstr",
|
||||
@ -700,9 +699,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-date"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "367ee9093b0c2b04fd04c5c7c8b6a1082713534eab537597ae343663a518fa99"
|
||||
checksum = "9eed6931f21491ee0aeb922751bd7ec97b4b2fe8fbfedcb678e2a2dce5f3b8c0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"itoa",
|
||||
@ -712,9 +711,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-diff"
|
||||
version = "0.44.0"
|
||||
version = "0.44.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b9bd8b2d07b6675a840b56a6c177d322d45fa082672b0dad8f063b25baf0a4"
|
||||
checksum = "1996d5c8a305b59709467d80617c9fde48d9d75fd1f4179ea970912630886c9d"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-command",
|
||||
@ -732,9 +731,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-dir"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60c99f8c545abd63abe541d20ab6cda347de406c0a3f1c80aadc12d9b0e94974"
|
||||
checksum = "0c975679aa00dd2d757bfd3ddb232e8a188c0094c3306400575a0813858b1365"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-discover",
|
||||
@ -752,9 +751,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-discover"
|
||||
version = "0.32.0"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc27c699b63da66b50d50c00668bc0b7e90c3a382ef302865e891559935f3dbf"
|
||||
checksum = "67662731cec3cb31ba3ed2463809493f76d8e5d6c6d245de8b0560438c13450e"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"dunce",
|
||||
@ -787,9 +786,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-filter"
|
||||
version = "0.11.2"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00ce6ea5ac8fca7adbc63c48a1b9e0492c222c386aa15f513405f1003f2f4ab2"
|
||||
checksum = "e6547738da28275f4dff4e9f3a0f28509f53f94dd6bd822733c91cb306bca61a"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"encoding_rs",
|
||||
@ -808,9 +807,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-fs"
|
||||
version = "0.11.0"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f78f7d6dcda7a5809efd73a33b145e3dce7421c460df21f32126f9732736b0c"
|
||||
checksum = "6adf99c27cdf17b1c4d77680c917e0d94d8783d4e1c73d3be0d1d63107163d7a"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"gix-features",
|
||||
@ -819,9 +818,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-glob"
|
||||
version = "0.16.2"
|
||||
version = "0.16.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "682bdc43cb3c00dbedfcc366de2a849b582efd8d886215dbad2ea662ec156bb5"
|
||||
checksum = "fa7df15afa265cc8abe92813cd354d522f1ac06b29ec6dfa163ad320575cb447"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bstr",
|
||||
@ -852,9 +851,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-ignore"
|
||||
version = "0.11.2"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "640dbeb4f5829f9fc14d31f654a34a0350e43a24e32d551ad130d99bf01f63f1"
|
||||
checksum = "5e6afb8f98e314d4e1adc822449389ada863c174b5707cedd327d67b84dba527"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-glob",
|
||||
@ -865,9 +864,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-index"
|
||||
version = "0.33.0"
|
||||
version = "0.33.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d8c5a5f1c58edcbc5692b174cda2703aba82ed17d7176ff4c1752eb48b1b167"
|
||||
checksum = "9a9a44eb55bd84bb48f8a44980e951968ced21e171b22d115d1cdcef82a7d73f"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bstr",
|
||||
@ -915,9 +914,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-object"
|
||||
version = "0.42.2"
|
||||
version = "0.42.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fe2dc4a41191c680c942e6ebd630c8107005983c4679214fdb1007dcf5ae1df"
|
||||
checksum = "25da2f46b4e7c2fa7b413ce4dffb87f69eaf89c2057e386491f4c55cadbfe386"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-actor",
|
||||
@ -934,9 +933,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-odb"
|
||||
version = "0.61.0"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e92b9790e2c919166865d0825b26cc440a387c175bed1b43a2fa99c0e9d45e98"
|
||||
checksum = "20d384fe541d93d8a3bb7d5d5ef210780d6df4f50c4e684ccba32665a5e3bc9b"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"gix-date",
|
||||
@ -954,9 +953,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-pack"
|
||||
version = "0.51.0"
|
||||
version = "0.51.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a8da51212dbff944713edb2141ed7e002eea326b8992070374ce13a6cb610b3"
|
||||
checksum = "3e0594491fffe55df94ba1c111a6566b7f56b3f8d2e1efc750e77d572f5f5229"
|
||||
dependencies = [
|
||||
"clru",
|
||||
"gix-chunk",
|
||||
@ -965,9 +964,7 @@ dependencies = [
|
||||
"gix-hashtable",
|
||||
"gix-object",
|
||||
"gix-path",
|
||||
"gix-tempfile",
|
||||
"memmap2",
|
||||
"parking_lot",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
]
|
||||
@ -986,9 +983,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-path"
|
||||
version = "0.10.7"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23623cf0f475691a6d943f898c4d0b89f5c1a2a64d0f92bce0e0322ee6528783"
|
||||
checksum = "8d23d5bbda31344d8abc8de7c075b3cf26e5873feba7c4a15d916bce67382bd9"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-trace",
|
||||
@ -999,9 +996,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-pathspec"
|
||||
version = "0.7.5"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a76cab098dc10ba2d89f634f66bf196dea4d7db4bf10b75c7a9c201c55a2ee19"
|
||||
checksum = "d307d1b8f84dc8386c4aa20ce0cf09242033840e15469a3ecba92f10cfb5c046"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bstr",
|
||||
@ -1025,12 +1022,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-ref"
|
||||
version = "0.44.0"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b36752b448647acd59c9668fdd830b16d07db1e6d9c3b3af105c1605a6e23d9"
|
||||
checksum = "636e96a0a5562715153fee098c217110c33a6f8218f08f4687ff99afde159bb5"
|
||||
dependencies = [
|
||||
"gix-actor",
|
||||
"gix-date",
|
||||
"gix-features",
|
||||
"gix-fs",
|
||||
"gix-hash",
|
||||
@ -1047,9 +1043,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-refspec"
|
||||
version = "0.23.0"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde848865834a54fe4d9b4573f15d0e9a68eaf3d061b42d3ed52b4b8acf880b2"
|
||||
checksum = "6868f8cd2e62555d1f7c78b784bece43ace40dd2a462daf3b588d5416e603f37"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-hash",
|
||||
@ -1061,25 +1057,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-revision"
|
||||
version = "0.27.1"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63e08f8107ed1f93a83bcfbb4c38084c7cb3f6cd849793f1d5eec235f9b13b2b"
|
||||
checksum = "01b13e43c2118c4b0537ddac7d0821ae0dfa90b7b8dbf20c711e153fb749adce"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-date",
|
||||
"gix-hash",
|
||||
"gix-hashtable",
|
||||
"gix-object",
|
||||
"gix-revwalk",
|
||||
"gix-trace",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-revwalk"
|
||||
version = "0.13.1"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4181db9cfcd6d1d0fd258e91569dbb61f94cb788b441b5294dd7f1167a3e788f"
|
||||
checksum = "1b030ccaab71af141f537e0225f19b9e74f25fefdba0372246b844491cab43e0"
|
||||
dependencies = [
|
||||
"gix-commitgraph",
|
||||
"gix-date",
|
||||
@ -1092,9 +1086,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-sec"
|
||||
version = "0.10.6"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fddc27984a643b20dd03e97790555804f98cf07404e0e552c0ad8133266a79a1"
|
||||
checksum = "1547d26fa5693a7f34f05b4a3b59a90890972922172653bcb891ab3f09f436df"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"gix-path",
|
||||
@ -1104,9 +1098,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-status"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f4373d989713809554d136f51bc7da565adf45c91aa4d86ef6a79801621bfc8"
|
||||
checksum = "83f7b084cb65c3d007ce6bb479755ca13d602ca3cd91c4f08d7e59904de33736"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"filetime",
|
||||
@ -1121,14 +1115,15 @@ dependencies = [
|
||||
"gix-path",
|
||||
"gix-pathspec",
|
||||
"gix-worktree",
|
||||
"portable-atomic",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-submodule"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "921cd49924ac14b6611b22e5fb7bbba74d8780dc7ad26153304b64d1272460ac"
|
||||
checksum = "0f2e0f69aa00805e39d39ec80472a7e9da20ed5d73318b27925a2cc198e854fd"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-config",
|
||||
@ -1161,9 +1156,9 @@ checksum = "f924267408915fddcd558e3f37295cc7d6a3e50f8bd8b606cee0808c3915157e"
|
||||
|
||||
[[package]]
|
||||
name = "gix-traverse"
|
||||
version = "0.39.1"
|
||||
version = "0.39.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f20cb69b63eb3e4827939f42c05b7756e3488ef49c25c412a876691d568ee2a0"
|
||||
checksum = "e499a18c511e71cf4a20413b743b9f5bcf64b3d9e81e9c3c6cd399eae55a8840"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"gix-commitgraph",
|
||||
@ -1178,9 +1173,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-url"
|
||||
version = "0.27.3"
|
||||
version = "0.27.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0db829ebdca6180fbe32be7aed393591df6db4a72dbbc0b8369162390954d1cf"
|
||||
checksum = "e2eb9b35bba92ea8f0b5ab406fad3cf6b87f7929aa677ff10aa042c6da621156"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-features",
|
||||
@ -1213,9 +1208,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-worktree"
|
||||
version = "0.34.0"
|
||||
version = "0.34.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53f6b7de83839274022aff92157d7505f23debf739d257984a300a35972ca94e"
|
||||
checksum = "26f7326ebe0b9172220694ea69d344c536009a9b98fb0f9de092c440f3efe7a6"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-attributes",
|
||||
@ -1393,10 +1388,10 @@ dependencies = [
|
||||
"globset",
|
||||
"helix-core",
|
||||
"helix-loader",
|
||||
"helix-lsp-types",
|
||||
"helix-parsec",
|
||||
"helix-stdx",
|
||||
"log",
|
||||
"lsp-types",
|
||||
"parking_lot",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -1406,6 +1401,17 @@ dependencies = [
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "helix-lsp-types"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "helix-parsec"
|
||||
version = "24.7.0"
|
||||
@ -1455,6 +1461,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"open",
|
||||
"pulldown-cmark",
|
||||
"same-file",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"signal-hook",
|
||||
@ -1545,6 +1552,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.9"
|
||||
@ -1606,9 +1619,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "imara-diff"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af13c8ceb376860ff0c6a66d83a8cdd4ecd9e464da24621bbffcd02b49619434"
|
||||
checksum = "fc9da1a252bd44cd341657203722352efc9bc0c847d06ea6d2dc1cd1135e0a01"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"hashbrown 0.14.5",
|
||||
@ -1720,19 +1733,6 @@ version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "lsp-types"
|
||||
version = "0.95.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e34d33a8e9b006cd3fc4fe69a921affa097bae4bb65f76271f4644f9a334365"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.3"
|
||||
@ -1778,6 +1778,18 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.9",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nucleo"
|
||||
version = "0.5.0"
|
||||
@ -1820,7 +1832,7 @@ version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.2.6",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@ -1906,6 +1918,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
@ -2134,11 +2152,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.120"
|
||||
version = "1.0.121"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||
checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
@ -2156,9 +2175,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.6"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
|
||||
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -2192,7 +2211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"mio 0.8.11",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
@ -2422,28 +2441,27 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.1"
|
||||
version = "1.39.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df"
|
||||
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"mio 1.0.1",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2463,9 +2481,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.15"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
|
||||
checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
@ -2475,18 +2493,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.6"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
|
||||
checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.16"
|
||||
version = "0.22.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
||||
checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
|
@ -5,6 +5,7 @@ members = [
|
||||
"helix-view",
|
||||
"helix-term",
|
||||
"helix-tui",
|
||||
"helix-lsp-types",
|
||||
"helix-lsp",
|
||||
"helix-event",
|
||||
"helix-dap",
|
||||
|
@ -10,6 +10,7 @@ # Summary
|
||||
- [Surround](./surround.md)
|
||||
- [Textobjects](./textobjects.md)
|
||||
- [Syntax aware motions](./syntax-aware-motions.md)
|
||||
- [Pickers](./pickers.md)
|
||||
- [Keymap](./keymap.md)
|
||||
- [Commands](./commands.md)
|
||||
- [Language support](./lang-support.md)
|
||||
|
@ -69,7 +69,7 @@
|
||||
| glsl | ✓ | ✓ | ✓ | |
|
||||
| gn | ✓ | | | |
|
||||
| go | ✓ | ✓ | ✓ | `gopls`, `golangci-lint-langserver` |
|
||||
| godot-resource | ✓ | | | |
|
||||
| godot-resource | ✓ | ✓ | | |
|
||||
| gomod | ✓ | | | `gopls` |
|
||||
| gotmpl | ✓ | | | `gopls` |
|
||||
| gowork | ✓ | | | `gopls` |
|
||||
@ -96,6 +96,7 @@
|
||||
| java | ✓ | ✓ | ✓ | `jdtls` |
|
||||
| javascript | ✓ | ✓ | ✓ | `typescript-language-server` |
|
||||
| jinja | ✓ | | | |
|
||||
| jjdescription | ✓ | | | |
|
||||
| jsdoc | ✓ | | | |
|
||||
| json | ✓ | ✓ | ✓ | `vscode-json-language-server` |
|
||||
| json5 | ✓ | | | |
|
||||
|
@ -436,6 +436,8 @@ ## Select / extend mode
|
||||
## Picker
|
||||
|
||||
Keys to use within picker. Remapping currently not supported.
|
||||
See the documentation page on [pickers](./pickers.md) for more info.
|
||||
[Prompt](#prompt) keybinds also work in pickers, except where they conflict with picker keybinds.
|
||||
|
||||
| Key | Description |
|
||||
| ----- | ------------- |
|
||||
|
11
book/src/pickers.md
Normal file
11
book/src/pickers.md
Normal file
@ -0,0 +1,11 @@
|
||||
## Using pickers
|
||||
|
||||
Helix has a variety of pickers, which are interactive windows used to select various kinds of items. These include a file picker, global search picker, and more. Most pickers are accessed via keybindings in [space mode](./keymap.md#space-mode). Pickers have their own [keymap](./keymap.md#picker) for navigation.
|
||||
|
||||
### Filtering Picker Results
|
||||
|
||||
Most pickers perform fuzzy matching using [fzf syntax](https://github.com/junegunn/fzf?tab=readme-ov-file#search-syntax). Two exceptions are the global search picker, which uses regex, and the workspace symbol picker, which passes search terms to the LSP. Note that OR operations (`|`) are not currently supported.
|
||||
|
||||
If a picker shows multiple columns, you may apply the filter to a specific column by prefixing the column name with `%`. Column names can be shortened to any prefix, so `%p`, `%pa` or `%pat` all mean the same as `%path`. For example, a query of `helix %p .toml !lang` in the global search picker searches for the term "helix" within files with paths ending in ".toml" but not including "lang".
|
||||
|
||||
You can insert the contents of a [register](./registers.md) using `Ctrl-r` followed by a register name. For example, one could insert the currently selected text using `Ctrl-r`-`.`, or the directory of the current file using `Ctrl-r`-`%` followed by `Ctrl-w` to remove the last path section. The global search picker will use the contents of the [search register](./registers.md#default-registers) if you press `Enter` without typing a filter. For example, pressing `*`-`Space-/`-`Enter` will start a global search for the currently selected text.
|
@ -293,12 +293,13 @@ #### Interface
|
||||
| `ui.statusline.select` | Statusline mode during select mode ([only if `editor.color-modes` is enabled][editor-section]) |
|
||||
| `ui.statusline.separator` | Separator character in statusline |
|
||||
| `ui.bufferline` | Style for the buffer line |
|
||||
| `ui.bufferline.active` | Style for the active buffer in buffer line |
|
||||
| `ui.bufferline.active` | Style for the active buffer in buffer line |
|
||||
| `ui.bufferline.background` | Style for bufferline background |
|
||||
| `ui.popup` | Documentation popups (e.g. Space + k) |
|
||||
| `ui.popup.info` | Prompt for multiple key options |
|
||||
| `ui.picker.header` | Column names in pickers with multiple columns |
|
||||
| `ui.picker.header.active` | The column name in pickers with multiple columns where the cursor is entering into. |
|
||||
| `ui.picker.header` | Header row area in pickers with multiple columns |
|
||||
| `ui.picker.header.column` | Column names in pickers with multiple columns |
|
||||
| `ui.picker.header.column.active` | The column name in pickers with multiple columns where the cursor is entering into. |
|
||||
| `ui.window` | Borderlines separating splits |
|
||||
| `ui.help` | Description box for commands |
|
||||
| `ui.text` | Default text style, command prompts, popup text, etc. |
|
||||
|
@ -2,23 +2,31 @@
|
||||
# Bash completion script for Helix editor
|
||||
|
||||
_hx() {
|
||||
# $1 command name
|
||||
# $2 word being completed
|
||||
# $3 word preceding
|
||||
local cur prev languages
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD - 1]}"
|
||||
|
||||
case "$3" in
|
||||
-g | --grammar)
|
||||
COMPREPLY="$(compgen -W 'fetch build' -- $2)"
|
||||
;;
|
||||
--health)
|
||||
local languages=$(hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g')
|
||||
COMPREPLY="$(compgen -W """$languages""" -- $2)"
|
||||
;;
|
||||
*)
|
||||
COMPREPLY="$(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar --vsplit --hsplit -c --config --log" -- """$2""")"
|
||||
;;
|
||||
esac
|
||||
case "$prev" in
|
||||
-g | --grammar)
|
||||
COMPREPLY=($(compgen -W 'fetch build' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
--health)
|
||||
languages=$(hx --health | tail -n '+7' | awk '{print $1}' | sed 's/\x1b\[[0-9;]*m//g')
|
||||
COMPREPLY=($(compgen -W """$languages""" -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
local IFS=$'\n'
|
||||
COMPREPLY=($COMPREPLY)
|
||||
case "$2" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar --vsplit --hsplit -c --config --log" -- """$2"""))
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -fd -- """$2"""))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
} && complete -o filenames -F _hx hx
|
||||
|
@ -4,7 +4,11 @@
|
||||
# so it has not been specified here and will not be proposed in the autocompletion of Nushell.
|
||||
# The help message won't be overriden though, so it will still be present here
|
||||
|
||||
def health_categories [] { ["all", "clipboard", "languages"] }
|
||||
def health_categories [] {
|
||||
let languages = ^hx --health languages | detect columns | get Language | filter { $in != null }
|
||||
let completions = [ "all", "clipboard", "languages" ] | append $languages
|
||||
return $completions
|
||||
}
|
||||
|
||||
def grammar_categories [] { ["fetch", "build"] }
|
||||
|
||||
@ -12,7 +16,7 @@ def grammar_categories [] { ["fetch", "build"] }
|
||||
export extern hx [
|
||||
--help(-h), # Prints help information
|
||||
--tutor, # Loads the tutorial
|
||||
--health: string@health_categories = "all", # Checks for potential errors in editor setup
|
||||
--health: string@health_categories, # Checks for potential errors in editor setup
|
||||
--grammar(-g): string@grammar_categories, # Fetches or builds tree-sitter grammars listed in `languages.toml`
|
||||
--config(-c): glob, # Specifies a file to use for configuration
|
||||
-v, # Increases logging verbosity each use for up to 3 times
|
||||
|
@ -53,6 +53,10 @@ ## Integration tests
|
||||
[helpers.rs][helpers.rs]. The log level can be set with the `HELIX_LOG_LEVEL`
|
||||
environment variable, e.g. `HELIX_LOG_LEVEL=debug cargo integration-test`.
|
||||
|
||||
Contributors using MacOS might encounter `Too many open files (os error 24)`
|
||||
failures while running integration tests. This can be resolved by increasing
|
||||
the default value (e.g. to `10240` from `256`) by running `ulimit -n 10240`.
|
||||
|
||||
## Minimum Stable Rust Version (MSRV) Policy
|
||||
|
||||
Helix follows the MSRV of Firefox.
|
||||
|
@ -1,13 +1,14 @@
|
||||
|
||||
| Crate | Description |
|
||||
| ----------- | ----------- |
|
||||
| helix-core | Core editing primitives, functional. |
|
||||
| helix-lsp | Language server client |
|
||||
| helix-dap | Debug Adapter Protocol (DAP) client |
|
||||
| helix-loader | Functions for building, fetching, and loading external resources |
|
||||
| helix-view | UI abstractions for use in backends, imperative shell. |
|
||||
| helix-term | Terminal UI |
|
||||
| helix-tui | TUI primitives, forked from tui-rs, inspired by Cursive |
|
||||
| Crate | Description |
|
||||
| ----------- | ----------- |
|
||||
| helix-core | Core editing primitives, functional. |
|
||||
| helix-lsp | Language server client |
|
||||
| helix-lsp-types | Language Server Protocol type definitions |
|
||||
| helix-dap | Debug Adapter Protocol (DAP) client |
|
||||
| helix-loader | Functions for building, fetching, and loading external resources |
|
||||
| helix-view | UI abstractions for use in backends, imperative shell. |
|
||||
| helix-term | Terminal UI |
|
||||
| helix-tui | TUI primitives, forked from tui-rs, inspired by Cursive |
|
||||
|
||||
|
||||
This document contains a high-level overview of Helix internals.
|
||||
|
@ -23,7 +23,12 @@ ropey = { version = "1.6.1", default-features = false, features = ["simd"] }
|
||||
smallvec = "1.13"
|
||||
smartstring = "1.0.1"
|
||||
unicode-segmentation = "1.11"
|
||||
unicode-width = "0.1"
|
||||
# unicode-width is changing width definitions
|
||||
# that both break our logic and disagree with common
|
||||
# width definitions in terminals, we need to replace it.
|
||||
# For now lets lock the version to avoid rendering glitches
|
||||
# when installing without `--locked`
|
||||
unicode-width = "=0.1.12"
|
||||
unicode-general-category = "0.6"
|
||||
slotmap.workspace = true
|
||||
tree-sitter.workspace = true
|
||||
@ -41,7 +46,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
toml = "0.8"
|
||||
|
||||
imara-diff = "0.1.6"
|
||||
imara-diff = "0.1.7"
|
||||
|
||||
encoding_rs = "0.8"
|
||||
|
||||
|
@ -75,9 +75,9 @@ fn from((open, close): (&char, &char)) -> Self {
|
||||
|
||||
impl AutoPairs {
|
||||
/// Make a new AutoPairs set with the given pairs and default conditions.
|
||||
pub fn new<'a, V: 'a, A>(pairs: V) -> Self
|
||||
pub fn new<'a, V, A>(pairs: V) -> Self
|
||||
where
|
||||
V: IntoIterator<Item = A>,
|
||||
V: IntoIterator<Item = A> + 'a,
|
||||
A: Into<Pair>,
|
||||
{
|
||||
let mut auto_pairs = HashMap::new();
|
||||
|
@ -265,7 +265,7 @@ fn is_first_in_line(node: Node, text: RopeSlice, new_line_byte_pos: Option<usize
|
||||
/// This is usually constructed in one of 2 ways:
|
||||
/// - Successively add indent captures to get the (added) indent from a single line
|
||||
/// - Successively add the indent results for each line
|
||||
/// The string that this indentation defines starts with the string contained in the align field (unless it is None), followed by:
|
||||
/// The string that this indentation defines starts with the string contained in the align field (unless it is None), followed by:
|
||||
/// - max(0, indent - outdent) tabs, if tabs are used for indentation
|
||||
/// - max(0, indent - outdent)*indent_width spaces, if spaces are used for indentation
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone)]
|
||||
@ -457,7 +457,7 @@ fn query_indents<'a>(
|
||||
// Skip matches where not all custom predicates are fulfilled
|
||||
if !query.general_predicates(m.pattern_index).iter().all(|pred| {
|
||||
match pred.operator.as_ref() {
|
||||
"not-kind-eq?" => match (pred.args.get(0), pred.args.get(1)) {
|
||||
"not-kind-eq?" => match (pred.args.first(), pred.args.get(1)) {
|
||||
(
|
||||
Some(QueryPredicateArg::Capture(capture_idx)),
|
||||
Some(QueryPredicateArg::String(kind)),
|
||||
@ -473,7 +473,7 @@ fn query_indents<'a>(
|
||||
}
|
||||
},
|
||||
"same-line?" | "not-same-line?" => {
|
||||
match (pred.args.get(0), pred.args.get(1)) {
|
||||
match (pred.args.first(), pred.args.get(1)) {
|
||||
(
|
||||
Some(QueryPredicateArg::Capture(capt1)),
|
||||
Some(QueryPredicateArg::Capture(capt2))
|
||||
@ -495,7 +495,7 @@ fn query_indents<'a>(
|
||||
}
|
||||
}
|
||||
}
|
||||
"one-line?" | "not-one-line?" => match pred.args.get(0) {
|
||||
"one-line?" | "not-one-line?" => match pred.args.first() {
|
||||
Some(QueryPredicateArg::Capture(capture_idx)) => {
|
||||
let node = m.nodes_for_capture_index(*capture_idx).next();
|
||||
|
||||
@ -786,6 +786,7 @@ fn init_indent_query<'a, 'b>(
|
||||
/// - The line after the node. This is defined by:
|
||||
/// - The scope `tail`.
|
||||
/// - The scope `all` if this node is not the first node on its line.
|
||||
///
|
||||
/// Intuitively, `all` applies to everything contained in this node while `tail` applies to everything except for the first line of the node.
|
||||
/// The indents from different nodes for the same line are then combined.
|
||||
/// The result [Indentation] is simply the sum of the [Indentation] for all lines.
|
||||
|
@ -1027,9 +1027,10 @@ pub fn language_configuration_for_injection_string(
|
||||
match capture {
|
||||
InjectionLanguageMarker::Name(string) => self.language_config_for_name(string),
|
||||
InjectionLanguageMarker::Filename(file) => self.language_config_for_file_name(file),
|
||||
InjectionLanguageMarker::Shebang(shebang) => {
|
||||
self.language_config_for_language_id(shebang)
|
||||
}
|
||||
InjectionLanguageMarker::Shebang(shebang) => self
|
||||
.language_config_ids_by_shebang
|
||||
.get(shebang)
|
||||
.and_then(|&id| self.language_configs.get(id).cloned()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1432,8 +1433,11 @@ pub fn highlight_iter<'a>(
|
||||
// The `captures` iterator borrows the `Tree` and the `QueryCursor`, which
|
||||
// prevents them from being moved. But both of these values are really just
|
||||
// pointers, so it's actually ok to move them.
|
||||
let cursor_ref =
|
||||
unsafe { mem::transmute::<_, &'static mut QueryCursor>(&mut cursor) };
|
||||
let cursor_ref = unsafe {
|
||||
mem::transmute::<&mut tree_sitter::QueryCursor, &mut tree_sitter::QueryCursor>(
|
||||
&mut cursor,
|
||||
)
|
||||
};
|
||||
|
||||
// if reusing cursors & no range this resets to whole range
|
||||
cursor_ref.set_byte_range(range.clone().unwrap_or(0..usize::MAX));
|
||||
@ -1738,7 +1742,7 @@ fn traverse(point: Point, text: &Tendril) -> Point {
|
||||
}
|
||||
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::{iter, mem, ops, str, usize};
|
||||
use std::{iter, mem, ops, str};
|
||||
use tree_sitter::{
|
||||
Language as Grammar, Node, Parser, Point, Query, QueryCaptures, QueryCursor, QueryError,
|
||||
QueryMatch, Range, TextProvider, Tree,
|
||||
|
@ -204,7 +204,7 @@ fn layer_id_containing_byte_range(&self, start: usize, end: usize) -> LayerId {
|
||||
|
||||
self.injection_ranges[start_idx..]
|
||||
.iter()
|
||||
.take_while(|range| range.start < end)
|
||||
.take_while(|range| range.start < end || range.depth > 1)
|
||||
.find_map(|range| (range.start <= start).then_some(range.layer_id))
|
||||
.unwrap_or(self.root)
|
||||
}
|
||||
|
176
helix-lsp-types/Cargo.lock
generated
Normal file
176
helix-lsp-types/Cargo.lock
generated
Normal file
@ -0,0 +1,176 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||
|
||||
[[package]]
|
||||
name = "lsp-types"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
34
helix-lsp-types/Cargo.toml
Normal file
34
helix-lsp-types/Cargo.toml
Normal file
@ -0,0 +1,34 @@
|
||||
[package]
|
||||
name = "helix-lsp-types"
|
||||
version = "0.95.1"
|
||||
authors = [
|
||||
# Original authors
|
||||
"Markus Westerlind <marwes91@gmail.com>",
|
||||
"Bruno Medeiros <bruno.do.medeiros@gmail.com>",
|
||||
# Since forking
|
||||
"Helix contributors"
|
||||
]
|
||||
edition = "2018"
|
||||
description = "Types for interaction with a language server, using VSCode's Language Server Protocol"
|
||||
|
||||
repository = "https://github.com/gluon-lang/lsp-types"
|
||||
documentation = "https://docs.rs/lsp-types"
|
||||
|
||||
readme = "README.md"
|
||||
|
||||
keywords = ["language", "server", "lsp", "vscode", "lsif"]
|
||||
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0.1"
|
||||
serde = { version = "1.0.34", features = ["derive"] }
|
||||
serde_json = "1.0.50"
|
||||
serde_repr = "0.1"
|
||||
url = {version = "2.0.0", features = ["serde"]}
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# Enables proposed LSP extensions.
|
||||
# NOTE: No semver compatibility is guaranteed for types enabled by this feature.
|
||||
proposed = []
|
22
helix-lsp-types/LICENSE
Normal file
22
helix-lsp-types/LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Markus Westerlind
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
3
helix-lsp-types/README.md
Normal file
3
helix-lsp-types/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Helix's `lsp-types`
|
||||
|
||||
This is a fork of the [`lsp-types`](https://crates.io/crates/lsp-types) crate ([`gluon-lang/lsp-types`](https://github.com/gluon-lang/lsp-types)) taken at version v0.95.1 (commit [3e6daee](https://github.com/gluon-lang/lsp-types/commit/3e6daee771d14db4094a554b8d03e29c310dfcbe)). This fork focuses usability improvements that make the types easier to work with for the Helix codebase. For example the URL type - the `uri` crate at this version of `lsp-types` - will be replaced with a wrapper around a string.
|
127
helix-lsp-types/src/call_hierarchy.rs
Normal file
127
helix-lsp-types/src/call_hierarchy.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, PartialResultParams, Range, SymbolKind, SymbolTag,
|
||||
TextDocumentPositionParams, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type CallHierarchyClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Copy)]
|
||||
#[serde(untagged)]
|
||||
pub enum CallHierarchyServerCapability {
|
||||
Simple(bool),
|
||||
Options(CallHierarchyOptions),
|
||||
}
|
||||
|
||||
impl From<CallHierarchyOptions> for CallHierarchyServerCapability {
|
||||
fn from(from: CallHierarchyOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for CallHierarchyServerCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyPrepareParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyItem {
|
||||
/// The name of this item.
|
||||
pub name: String,
|
||||
|
||||
/// The kind of this item.
|
||||
pub kind: SymbolKind,
|
||||
|
||||
/// Tags for this item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<SymbolTag>>,
|
||||
|
||||
/// More detail for this item, e.g. the signature of a function.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
|
||||
/// The resource identifier of this item.
|
||||
pub uri: Url,
|
||||
|
||||
/// The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code.
|
||||
pub range: Range,
|
||||
|
||||
/// The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function.
|
||||
/// Must be contained by the [`range`](#CallHierarchyItem.range).
|
||||
pub selection_range: Range,
|
||||
|
||||
/// A data entry field that is preserved between a call hierarchy prepare and incoming calls or outgoing calls requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyIncomingCallsParams {
|
||||
pub item: CallHierarchyItem,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Represents an incoming call, e.g. a caller of a method or constructor.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyIncomingCall {
|
||||
/// The item that makes the call.
|
||||
pub from: CallHierarchyItem,
|
||||
|
||||
/// The range at which at which the calls appears. This is relative to the caller
|
||||
/// denoted by [`this.from`](#CallHierarchyIncomingCall.from).
|
||||
pub from_ranges: Vec<Range>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyOutgoingCallsParams {
|
||||
pub item: CallHierarchyItem,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyOutgoingCall {
|
||||
/// The item that is called.
|
||||
pub to: CallHierarchyItem,
|
||||
|
||||
/// The range at which this item is called. This is the range relative to the caller, e.g the item
|
||||
/// passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls)
|
||||
/// and not [`this.to`](#CallHierarchyOutgoingCall.to).
|
||||
pub from_ranges: Vec<Range>,
|
||||
}
|
395
helix-lsp-types/src/code_action.rs
Normal file
395
helix-lsp-types/src/code_action.rs
Normal file
@ -0,0 +1,395 @@
|
||||
use crate::{
|
||||
Command, Diagnostic, PartialResultParams, Range, TextDocumentIdentifier,
|
||||
WorkDoneProgressOptions, WorkDoneProgressParams, WorkspaceEdit,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use std::borrow::Cow;
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CodeActionProviderCapability {
|
||||
Simple(bool),
|
||||
Options(CodeActionOptions),
|
||||
}
|
||||
|
||||
impl From<CodeActionOptions> for CodeActionProviderCapability {
|
||||
fn from(from: CodeActionOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for CodeActionProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionClientCapabilities {
|
||||
///
|
||||
/// This capability supports dynamic registration.
|
||||
///
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The client support code action literals as a valid
|
||||
/// response of the `textDocument/codeAction` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code_action_literal_support: Option<CodeActionLiteralSupport>,
|
||||
|
||||
/// Whether code action supports the `isPreferred` property.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_preferred_support: Option<bool>,
|
||||
|
||||
/// Whether code action supports the `disabled` property.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disabled_support: Option<bool>,
|
||||
|
||||
/// Whether code action supports the `data` property which is
|
||||
/// preserved between a `textDocument/codeAction` and a
|
||||
/// `codeAction/resolve` request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data_support: Option<bool>,
|
||||
|
||||
/// Whether the client supports resolving additional code action
|
||||
/// properties via a separate `codeAction/resolve` request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_support: Option<CodeActionCapabilityResolveSupport>,
|
||||
|
||||
/// Whether the client honors the change annotations in
|
||||
/// text edits and resource operations returned via the
|
||||
/// `CodeAction#edit` property by for example presenting
|
||||
/// the workspace edit in the user interface and asking
|
||||
/// for confirmation.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub honors_change_annotations: Option<bool>,
|
||||
}
|
||||
|
||||
/// Whether the client supports resolving additional code action
|
||||
/// properties via a separate `codeAction/resolve` request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionCapabilityResolveSupport {
|
||||
/// The properties that a client can resolve lazily.
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionLiteralSupport {
|
||||
/// The code action kind is support with the following value set.
|
||||
pub code_action_kind: CodeActionKindLiteralSupport,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionKindLiteralSupport {
|
||||
/// The code action kind values the client supports. When this
|
||||
/// property exists the client also guarantees that it will
|
||||
/// handle values outside its set gracefully and falls back
|
||||
/// to a default value when unknown.
|
||||
pub value_set: Vec<String>,
|
||||
}
|
||||
|
||||
/// Params for the CodeActionRequest
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionParams {
|
||||
/// The document in which the command was invoked.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The range for which the command was invoked.
|
||||
pub range: Range,
|
||||
|
||||
/// Context carrying additional information.
|
||||
pub context: CodeActionContext,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// response for CodeActionRequest
|
||||
pub type CodeActionResponse = Vec<CodeActionOrCommand>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CodeActionOrCommand {
|
||||
Command(Command),
|
||||
CodeAction(CodeAction),
|
||||
}
|
||||
|
||||
impl From<Command> for CodeActionOrCommand {
|
||||
fn from(command: Command) -> Self {
|
||||
CodeActionOrCommand::Command(command)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CodeAction> for CodeActionOrCommand {
|
||||
fn from(action: CodeAction) -> Self {
|
||||
CodeActionOrCommand::CodeAction(action)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
pub struct CodeActionKind(Cow<'static, str>);
|
||||
|
||||
impl CodeActionKind {
|
||||
/// Empty kind.
|
||||
pub const EMPTY: CodeActionKind = CodeActionKind::new("");
|
||||
|
||||
/// Base kind for quickfix actions: 'quickfix'
|
||||
pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix");
|
||||
|
||||
/// Base kind for refactoring actions: 'refactor'
|
||||
pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor");
|
||||
|
||||
/// Base kind for refactoring extraction actions: 'refactor.extract'
|
||||
///
|
||||
/// Example extract actions:
|
||||
///
|
||||
/// - Extract method
|
||||
/// - Extract function
|
||||
/// - Extract variable
|
||||
/// - Extract interface from class
|
||||
/// - ...
|
||||
pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract");
|
||||
|
||||
/// Base kind for refactoring inline actions: 'refactor.inline'
|
||||
///
|
||||
/// Example inline actions:
|
||||
///
|
||||
/// - Inline function
|
||||
/// - Inline variable
|
||||
/// - Inline constant
|
||||
/// - ...
|
||||
pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline");
|
||||
|
||||
/// Base kind for refactoring rewrite actions: 'refactor.rewrite'
|
||||
///
|
||||
/// Example rewrite actions:
|
||||
///
|
||||
/// - Convert JavaScript function to class
|
||||
/// - Add or remove parameter
|
||||
/// - Encapsulate field
|
||||
/// - Make method static
|
||||
/// - Move method to base class
|
||||
/// - ...
|
||||
pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite");
|
||||
|
||||
/// Base kind for source actions: `source`
|
||||
///
|
||||
/// Source code actions apply to the entire file.
|
||||
pub const SOURCE: CodeActionKind = CodeActionKind::new("source");
|
||||
|
||||
/// Base kind for an organize imports source action: `source.organizeImports`
|
||||
pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind =
|
||||
CodeActionKind::new("source.organizeImports");
|
||||
|
||||
/// Base kind for a 'fix all' source action: `source.fixAll`.
|
||||
///
|
||||
/// 'Fix all' actions automatically fix errors that have a clear fix that
|
||||
/// do not require user input. They should not suppress errors or perform
|
||||
/// unsafe fixes such as generating new types or classes.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
pub const SOURCE_FIX_ALL: CodeActionKind = CodeActionKind::new("source.fixAll");
|
||||
|
||||
pub const fn new(tag: &'static str) -> Self {
|
||||
CodeActionKind(Cow::Borrowed(tag))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for CodeActionKind {
|
||||
fn from(from: String) -> Self {
|
||||
CodeActionKind(Cow::from(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for CodeActionKind {
|
||||
fn from(from: &'static str) -> Self {
|
||||
CodeActionKind::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeAction {
|
||||
/// A short, human-readable, title for this code action.
|
||||
pub title: String,
|
||||
|
||||
/// The kind of the code action.
|
||||
/// Used to filter code actions.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<CodeActionKind>,
|
||||
|
||||
/// The diagnostics that this code action resolves.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub diagnostics: Option<Vec<Diagnostic>>,
|
||||
|
||||
/// The workspace edit this code action performs.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub edit: Option<WorkspaceEdit>,
|
||||
|
||||
/// A command this code action executes. If a code action
|
||||
/// provides an edit and a command, first the edit is
|
||||
/// executed and then the command.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
|
||||
/// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted
|
||||
/// by keybindings.
|
||||
/// A quick fix should be marked preferred if it properly addresses the underlying error.
|
||||
/// A refactoring should be marked preferred if it is the most reasonable choice of actions to take.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_preferred: Option<bool>,
|
||||
|
||||
/// Marks that the code action cannot currently be applied.
|
||||
///
|
||||
/// Clients should follow the following guidelines regarding disabled code actions:
|
||||
///
|
||||
/// - Disabled code actions are not shown in automatic
|
||||
/// [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action)
|
||||
/// code action menu.
|
||||
///
|
||||
/// - Disabled actions are shown as faded out in the code action menu when the user request
|
||||
/// a more specific type of code action, such as refactorings.
|
||||
///
|
||||
/// - If the user has a keybinding that auto applies a code action and only a disabled code
|
||||
/// actions are returned, the client should show the user an error message with `reason`
|
||||
/// in the editor.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disabled: Option<CodeActionDisabled>,
|
||||
|
||||
/// A data entry field that is preserved on a code action between
|
||||
/// a `textDocument/codeAction` and a `codeAction/resolve` request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionDisabled {
|
||||
/// Human readable description of why the code action is currently disabled.
|
||||
///
|
||||
/// This is displayed in the code actions UI.
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
/// The reason why code actions were requested.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct CodeActionTriggerKind(i32);
|
||||
lsp_enum! {
|
||||
impl CodeActionTriggerKind {
|
||||
/// Code actions were explicitly requested by the user or by an extension.
|
||||
pub const INVOKED: CodeActionTriggerKind = CodeActionTriggerKind(1);
|
||||
|
||||
/// Code actions were requested automatically.
|
||||
///
|
||||
/// This typically happens when current selection in a file changes, but can
|
||||
/// also be triggered when file content changes.
|
||||
pub const AUTOMATIC: CodeActionTriggerKind = CodeActionTriggerKind(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains additional diagnostic information about the context in which
|
||||
/// a code action is run.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionContext {
|
||||
/// An array of diagnostics.
|
||||
pub diagnostics: Vec<Diagnostic>,
|
||||
|
||||
/// Requested kind of actions to return.
|
||||
///
|
||||
/// Actions not of this kind are filtered out by the client before being shown. So servers
|
||||
/// can omit computing them.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub only: Option<Vec<CodeActionKind>>,
|
||||
|
||||
/// The reason why code actions were requested.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_kind: Option<CodeActionTriggerKind>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionOptions {
|
||||
/// CodeActionKinds that this server may return.
|
||||
///
|
||||
/// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
|
||||
/// may list out every specific kind they provide.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
|
||||
/// The server provides support to resolve additional
|
||||
/// information for a code action.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_code_action_response() {
|
||||
test_serialization(
|
||||
&vec![
|
||||
CodeActionOrCommand::Command(Command {
|
||||
title: "title".to_string(),
|
||||
command: "command".to_string(),
|
||||
arguments: None,
|
||||
}),
|
||||
CodeActionOrCommand::CodeAction(CodeAction {
|
||||
title: "title".to_string(),
|
||||
kind: Some(CodeActionKind::QUICKFIX),
|
||||
command: None,
|
||||
diagnostics: None,
|
||||
edit: None,
|
||||
is_preferred: None,
|
||||
..CodeAction::default()
|
||||
}),
|
||||
],
|
||||
r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#,
|
||||
)
|
||||
}
|
||||
}
|
66
helix-lsp-types/src/code_lens.rs
Normal file
66
helix-lsp-types/src/code_lens.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
Command, DynamicRegistrationClientCapabilities, PartialResultParams, Range,
|
||||
TextDocumentIdentifier, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type CodeLensClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
/// Code Lens options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLensOptions {
|
||||
/// Code lens has a resolve provider as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLensParams {
|
||||
/// The document to request code lens for.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A code lens represents a command that should be shown along with
|
||||
/// source text, like the number of references, a way to run tests, etc.
|
||||
///
|
||||
/// A code lens is _unresolved_ when no command is associated to it. For performance
|
||||
/// reasons the creation of a code lens and resolving should be done in two stages.
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLens {
|
||||
/// The range in which this code lens is valid. Should only span a single line.
|
||||
pub range: Range,
|
||||
|
||||
/// The command this code lens represents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
|
||||
/// A data entry field that is preserved on a code lens item between
|
||||
/// a code lens and a code lens resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLensWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from the
|
||||
/// server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// code lenses currently shown. It should be used with absolute care and is
|
||||
/// useful for situation where a server for example detect a project wide
|
||||
/// change that requires such a calculation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
122
helix-lsp-types/src/color.rs
Normal file
122
helix-lsp-types/src/color.rs
Normal file
@ -0,0 +1,122 @@
|
||||
use crate::{
|
||||
DocumentSelector, DynamicRegistrationClientCapabilities, PartialResultParams, Range,
|
||||
TextDocumentIdentifier, TextEdit, WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type DocumentColorClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColorProviderOptions {}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StaticTextDocumentColorProviderOptions {
|
||||
/// A document selector to identify the scope of the registration. If set to null
|
||||
/// the document selector provided on the client side will be used.
|
||||
pub document_selector: Option<DocumentSelector>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ColorProviderCapability {
|
||||
Simple(bool),
|
||||
ColorProvider(ColorProviderOptions),
|
||||
Options(StaticTextDocumentColorProviderOptions),
|
||||
}
|
||||
|
||||
impl From<ColorProviderOptions> for ColorProviderCapability {
|
||||
fn from(from: ColorProviderOptions) -> Self {
|
||||
Self::ColorProvider(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StaticTextDocumentColorProviderOptions> for ColorProviderCapability {
|
||||
fn from(from: StaticTextDocumentColorProviderOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for ColorProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentColorParams {
|
||||
/// The text document
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColorInformation {
|
||||
/// The range in the document where this color appears.
|
||||
pub range: Range,
|
||||
/// The actual color value for this color range.
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Color {
|
||||
/// The red component of this color in the range [0-1].
|
||||
pub red: f32,
|
||||
/// The green component of this color in the range [0-1].
|
||||
pub green: f32,
|
||||
/// The blue component of this color in the range [0-1].
|
||||
pub blue: f32,
|
||||
/// The alpha component of this color in the range [0-1].
|
||||
pub alpha: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColorPresentationParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The color information to request presentations for.
|
||||
pub color: Color,
|
||||
|
||||
/// The range where the color would be inserted. Serves as a context.
|
||||
pub range: Range,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Default, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColorPresentation {
|
||||
/// The label of this color presentation. It will be shown on the color
|
||||
/// picker header. By default this is also the text that is inserted when selecting
|
||||
/// this color presentation.
|
||||
pub label: String,
|
||||
|
||||
/// An [edit](#TextEdit) which is applied to a document when selecting
|
||||
/// this presentation for the color. When `falsy` the [label](#ColorPresentation.label)
|
||||
/// is used.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_edit: Option<TextEdit>,
|
||||
|
||||
/// An optional array of additional [text edits](#TextEdit) that are applied when
|
||||
/// selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub additional_text_edits: Option<Vec<TextEdit>>,
|
||||
}
|
622
helix-lsp-types/src/completion.rs
Normal file
622
helix-lsp-types/src/completion.rs
Normal file
@ -0,0 +1,622 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
Command, Documentation, MarkupKind, PartialResultParams, TagSupport,
|
||||
TextDocumentPositionParams, TextDocumentRegistrationOptions, TextEdit, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use crate::Range;
|
||||
use serde_json::Value;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Defines how to interpret the insert text in a completion item
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct InsertTextFormat(i32);
|
||||
lsp_enum! {
|
||||
impl InsertTextFormat {
|
||||
pub const PLAIN_TEXT: InsertTextFormat = InsertTextFormat(1);
|
||||
pub const SNIPPET: InsertTextFormat = InsertTextFormat(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of a completion entry.
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct CompletionItemKind(i32);
|
||||
lsp_enum! {
|
||||
impl CompletionItemKind {
|
||||
pub const TEXT: CompletionItemKind = CompletionItemKind(1);
|
||||
pub const METHOD: CompletionItemKind = CompletionItemKind(2);
|
||||
pub const FUNCTION: CompletionItemKind = CompletionItemKind(3);
|
||||
pub const CONSTRUCTOR: CompletionItemKind = CompletionItemKind(4);
|
||||
pub const FIELD: CompletionItemKind = CompletionItemKind(5);
|
||||
pub const VARIABLE: CompletionItemKind = CompletionItemKind(6);
|
||||
pub const CLASS: CompletionItemKind = CompletionItemKind(7);
|
||||
pub const INTERFACE: CompletionItemKind = CompletionItemKind(8);
|
||||
pub const MODULE: CompletionItemKind = CompletionItemKind(9);
|
||||
pub const PROPERTY: CompletionItemKind = CompletionItemKind(10);
|
||||
pub const UNIT: CompletionItemKind = CompletionItemKind(11);
|
||||
pub const VALUE: CompletionItemKind = CompletionItemKind(12);
|
||||
pub const ENUM: CompletionItemKind = CompletionItemKind(13);
|
||||
pub const KEYWORD: CompletionItemKind = CompletionItemKind(14);
|
||||
pub const SNIPPET: CompletionItemKind = CompletionItemKind(15);
|
||||
pub const COLOR: CompletionItemKind = CompletionItemKind(16);
|
||||
pub const FILE: CompletionItemKind = CompletionItemKind(17);
|
||||
pub const REFERENCE: CompletionItemKind = CompletionItemKind(18);
|
||||
pub const FOLDER: CompletionItemKind = CompletionItemKind(19);
|
||||
pub const ENUM_MEMBER: CompletionItemKind = CompletionItemKind(20);
|
||||
pub const CONSTANT: CompletionItemKind = CompletionItemKind(21);
|
||||
pub const STRUCT: CompletionItemKind = CompletionItemKind(22);
|
||||
pub const EVENT: CompletionItemKind = CompletionItemKind(23);
|
||||
pub const OPERATOR: CompletionItemKind = CompletionItemKind(24);
|
||||
pub const TYPE_PARAMETER: CompletionItemKind = CompletionItemKind(25);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItemCapability {
|
||||
/// Client supports snippets as insert text.
|
||||
///
|
||||
/// A snippet can define tab stops and placeholders with `$1`, `$2`
|
||||
/// and `${3:foo}`. `$0` defines the final tab stop, it defaults to
|
||||
/// the end of the snippet. Placeholders with equal identifiers are linked,
|
||||
/// that is typing in one will update others too.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub snippet_support: Option<bool>,
|
||||
|
||||
/// Client supports commit characters on a completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub commit_characters_support: Option<bool>,
|
||||
|
||||
/// Client supports the follow content formats for the documentation
|
||||
/// property. The order describes the preferred format of the client.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation_format: Option<Vec<MarkupKind>>,
|
||||
|
||||
/// Client supports the deprecated property on a completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub deprecated_support: Option<bool>,
|
||||
|
||||
/// Client supports the preselect property on a completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub preselect_support: Option<bool>,
|
||||
|
||||
/// Client supports the tag property on a completion item. Clients supporting
|
||||
/// tags have to handle unknown tags gracefully. Clients especially need to
|
||||
/// preserve unknown tags when sending a completion item back to the server in
|
||||
/// a resolve call.
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "TagSupport::deserialize_compat"
|
||||
)]
|
||||
pub tag_support: Option<TagSupport<CompletionItemTag>>,
|
||||
|
||||
/// Client support insert replace edit to control different behavior if a
|
||||
/// completion item is inserted in the text or should replace text.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_replace_support: Option<bool>,
|
||||
|
||||
/// Indicates which properties a client can resolve lazily on a completion
|
||||
/// item. Before version 3.16.0 only the predefined properties `documentation`
|
||||
/// and `details` could be resolved lazily.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_support: Option<CompletionItemCapabilityResolveSupport>,
|
||||
|
||||
/// The client supports the `insertTextMode` property on
|
||||
/// a completion item to override the whitespace handling mode
|
||||
/// as defined by the client.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_mode_support: Option<InsertTextModeSupport>,
|
||||
|
||||
/// The client has support for completion item label
|
||||
/// details (see also `CompletionItemLabelDetails`).
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub label_details_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItemCapabilityResolveSupport {
|
||||
/// The properties that a client can resolve lazily.
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InsertTextModeSupport {
|
||||
pub value_set: Vec<InsertTextMode>,
|
||||
}
|
||||
|
||||
/// How whitespace and indentation is handled during completion
|
||||
/// item insertion.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct InsertTextMode(i32);
|
||||
lsp_enum! {
|
||||
impl InsertTextMode {
|
||||
/// The insertion or replace strings is taken as it is. If the
|
||||
/// value is multi line the lines below the cursor will be
|
||||
/// inserted using the indentation defined in the string value.
|
||||
/// The client will not apply any kind of adjustments to the
|
||||
/// string.
|
||||
pub const AS_IS: InsertTextMode = InsertTextMode(1);
|
||||
|
||||
/// The editor adjusts leading whitespace of new lines so that
|
||||
/// they match the indentation up to the cursor of the line for
|
||||
/// which the item is accepted.
|
||||
///
|
||||
/// Consider a line like this: `<2tabs><cursor><3tabs>foo`. Accepting a
|
||||
/// multi line completion item is indented using 2 tabs all
|
||||
/// following lines inserted will be indented using 2 tabs as well.
|
||||
pub const ADJUST_INDENTATION: InsertTextMode = InsertTextMode(2);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct CompletionItemTag(i32);
|
||||
lsp_enum! {
|
||||
impl CompletionItemTag {
|
||||
pub const DEPRECATED: CompletionItemTag = CompletionItemTag(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItemKindCapability {
|
||||
/// The completion item kind values the client supports. When this
|
||||
/// property exists the client also guarantees that it will
|
||||
/// handle values outside its set gracefully and falls back
|
||||
/// to a default value when unknown.
|
||||
///
|
||||
/// If this property is not present the client only supports
|
||||
/// the completion items kinds from `Text` to `Reference` as defined in
|
||||
/// the initial version of the protocol.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub value_set: Option<Vec<CompletionItemKind>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionListCapability {
|
||||
/// The client supports the following itemDefaults on
|
||||
/// a completion list.
|
||||
///
|
||||
/// The value lists the supported property names of the
|
||||
/// `CompletionList.itemDefaults` object. If omitted
|
||||
/// no properties are supported.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub item_defaults: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionClientCapabilities {
|
||||
/// Whether completion supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The client supports the following `CompletionItem` specific
|
||||
/// capabilities.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_item: Option<CompletionItemCapability>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_item_kind: Option<CompletionItemKindCapability>,
|
||||
|
||||
/// The client supports to send additional context information for a
|
||||
/// `textDocument/completion` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context_support: Option<bool>,
|
||||
|
||||
/// The client's default when the completion item doesn't provide a
|
||||
/// `insertTextMode` property.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_mode: Option<InsertTextMode>,
|
||||
|
||||
/// The client supports the following `CompletionList` specific
|
||||
/// capabilities.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_list: Option<CompletionListCapability>,
|
||||
}
|
||||
|
||||
/// A special text edit to provide an insert and a replace operation.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InsertReplaceEdit {
|
||||
/// The string to be inserted.
|
||||
pub new_text: String,
|
||||
|
||||
/// The range if the insert is requested
|
||||
pub insert: Range,
|
||||
|
||||
/// The range if the replace is requested.
|
||||
pub replace: Range,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CompletionTextEdit {
|
||||
Edit(TextEdit),
|
||||
InsertAndReplace(InsertReplaceEdit),
|
||||
}
|
||||
|
||||
impl From<TextEdit> for CompletionTextEdit {
|
||||
fn from(edit: TextEdit) -> Self {
|
||||
CompletionTextEdit::Edit(edit)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InsertReplaceEdit> for CompletionTextEdit {
|
||||
fn from(edit: InsertReplaceEdit) -> Self {
|
||||
CompletionTextEdit::InsertAndReplace(edit)
|
||||
}
|
||||
}
|
||||
|
||||
/// Completion options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionOptions {
|
||||
/// The server provides support to resolve additional information for a completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
|
||||
/// Most tools trigger completion request automatically without explicitly
|
||||
/// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they
|
||||
/// do so when the user starts to type an identifier. For example if the user
|
||||
/// types `c` in a JavaScript file code complete will automatically pop up
|
||||
/// present `console` besides others as a completion item. Characters that
|
||||
/// make up identifiers don't need to be listed here.
|
||||
///
|
||||
/// If code complete should automatically be trigger on characters not being
|
||||
/// valid inside an identifier (for example `.` in JavaScript) list them in
|
||||
/// `triggerCharacters`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_characters: Option<Vec<String>>,
|
||||
|
||||
/// The list of all possible characters that commit a completion. This field
|
||||
/// can be used if clients don't support individual commit characters per
|
||||
/// completion item. See client capability
|
||||
/// `completion.completionItem.commitCharactersSupport`.
|
||||
///
|
||||
/// If a server provides both `allCommitCharacters` and commit characters on
|
||||
/// an individual completion item the ones on the completion item win.
|
||||
///
|
||||
/// @since 3.2.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub all_commit_characters: Option<Vec<String>>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
|
||||
/// The server supports the following `CompletionItem` specific
|
||||
/// capabilities.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_item: Option<CompletionOptionsCompletionItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionOptionsCompletionItem {
|
||||
/// The server has support for completion item label
|
||||
/// details (see also `CompletionItemLabelDetails`) when receiving
|
||||
/// a completion item in a resolve call.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub label_details_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct CompletionRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub completion_options: CompletionOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CompletionResponse {
|
||||
Array(Vec<CompletionItem>),
|
||||
List(CompletionList),
|
||||
}
|
||||
|
||||
impl From<Vec<CompletionItem>> for CompletionResponse {
|
||||
fn from(items: Vec<CompletionItem>) -> Self {
|
||||
CompletionResponse::Array(items)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompletionList> for CompletionResponse {
|
||||
fn from(list: CompletionList) -> Self {
|
||||
CompletionResponse::List(list)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionParams {
|
||||
// This field was "mixed-in" from TextDocumentPositionParams
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
// CompletionParams properties:
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context: Option<CompletionContext>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionContext {
|
||||
/// How the completion was triggered.
|
||||
pub trigger_kind: CompletionTriggerKind,
|
||||
|
||||
/// The trigger character (a single character) that has trigger code complete.
|
||||
/// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_character: Option<String>,
|
||||
}
|
||||
|
||||
/// How a completion was triggered.
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct CompletionTriggerKind(i32);
|
||||
lsp_enum! {
|
||||
impl CompletionTriggerKind {
|
||||
pub const INVOKED: CompletionTriggerKind = CompletionTriggerKind(1);
|
||||
pub const TRIGGER_CHARACTER: CompletionTriggerKind = CompletionTriggerKind(2);
|
||||
pub const TRIGGER_FOR_INCOMPLETE_COMPLETIONS: CompletionTriggerKind = CompletionTriggerKind(3);
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a collection of [completion items](#CompletionItem) to be presented
|
||||
/// in the editor.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionList {
|
||||
/// This list it not complete. Further typing should result in recomputing
|
||||
/// this list.
|
||||
pub is_incomplete: bool,
|
||||
|
||||
/// The completion items.
|
||||
pub items: Vec<CompletionItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItem {
|
||||
/// The label of this completion item. By default
|
||||
/// also the text that is inserted when selecting
|
||||
/// this completion.
|
||||
pub label: String,
|
||||
|
||||
/// Additional details for the label
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub label_details: Option<CompletionItemLabelDetails>,
|
||||
|
||||
/// The kind of this completion item. Based of the kind
|
||||
/// an icon is chosen by the editor.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<CompletionItemKind>,
|
||||
|
||||
/// A human-readable string with additional information
|
||||
/// about this item, like type or symbol information.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
|
||||
/// A human-readable string that represents a doc-comment.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation: Option<Documentation>,
|
||||
|
||||
/// Indicates if this item is deprecated.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub deprecated: Option<bool>,
|
||||
|
||||
/// Select this item when showing.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub preselect: Option<bool>,
|
||||
|
||||
/// A string that should be used when comparing this item
|
||||
/// with other items. When `falsy` the label is used
|
||||
/// as the sort text for this item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sort_text: Option<String>,
|
||||
|
||||
/// A string that should be used when filtering a set of
|
||||
/// completion items. When `falsy` the label is used as the
|
||||
/// filter text for this item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub filter_text: Option<String>,
|
||||
|
||||
/// A string that should be inserted into a document when selecting
|
||||
/// this completion. When `falsy` the label is used as the insert text
|
||||
/// for this item.
|
||||
///
|
||||
/// The `insertText` is subject to interpretation by the client side.
|
||||
/// Some tools might not take the string literally. For example
|
||||
/// VS Code when code complete is requested in this example
|
||||
/// `con<cursor position>` and a completion item with an `insertText` of
|
||||
/// `console` is provided it will only insert `sole`. Therefore it is
|
||||
/// recommended to use `textEdit` instead since it avoids additional client
|
||||
/// side interpretation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text: Option<String>,
|
||||
|
||||
/// The format of the insert text. The format applies to both the `insertText` property
|
||||
/// and the `newText` property of a provided `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_format: Option<InsertTextFormat>,
|
||||
|
||||
/// How whitespace and indentation is handled during completion
|
||||
/// item insertion. If not provided the client's default value depends on
|
||||
/// the `textDocument.completion.insertTextMode` client capability.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
/// @since 3.17.0 - support for `textDocument.completion.insertTextMode`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_mode: Option<InsertTextMode>,
|
||||
|
||||
/// An edit which is applied to a document when selecting
|
||||
/// this completion. When an edit is provided the value of
|
||||
/// insertText is ignored.
|
||||
///
|
||||
/// Most editors support two different operation when accepting a completion item. One is to insert a
|
||||
|
||||
/// completion text and the other is to replace an existing text with a completion text. Since this can
|
||||
/// usually not predetermined by a server it can report both ranges. Clients need to signal support for
|
||||
/// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability
|
||||
/// property.
|
||||
///
|
||||
/// *Note 1:* The text edit's range as well as both ranges from a insert replace edit must be a
|
||||
/// [single line] and they must contain the position at which completion has been requested.
|
||||
/// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range must be a prefix of
|
||||
/// the edit's replace range, that means it must be contained and starting at the same position.
|
||||
///
|
||||
/// @since 3.16.0 additional type `InsertReplaceEdit`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_edit: Option<CompletionTextEdit>,
|
||||
|
||||
/// An optional array of additional text edits that are applied when
|
||||
/// selecting this completion. Edits must not overlap with the main edit
|
||||
/// nor with themselves.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub additional_text_edits: Option<Vec<TextEdit>>,
|
||||
|
||||
/// An optional command that is executed *after* inserting this completion. *Note* that
|
||||
/// additional modifications to the current document should be described with the
|
||||
/// additionalTextEdits-property.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
|
||||
/// An optional set of characters that when pressed while this completion is
|
||||
/// active will accept it first and then type that character. *Note* that all
|
||||
/// commit characters should have `length=1` and that superfluous characters
|
||||
/// will be ignored.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub commit_characters: Option<Vec<String>>,
|
||||
|
||||
/// An data entry field that is preserved on a completion item between
|
||||
/// a completion and a completion resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
|
||||
/// Tags for this completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<CompletionItemTag>>,
|
||||
}
|
||||
|
||||
impl CompletionItem {
|
||||
/// Create a CompletionItem with the minimum possible info (label and detail).
|
||||
pub fn new_simple(label: String, detail: String) -> CompletionItem {
|
||||
CompletionItem {
|
||||
label,
|
||||
detail: Some(detail),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional details for a completion item label.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItemLabelDetails {
|
||||
/// An optional string which is rendered less prominently directly after
|
||||
/// {@link CompletionItemLabel.label label}, without any spacing. Should be
|
||||
/// used for function signatures or type annotations.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
|
||||
/// An optional string which is rendered less prominently after
|
||||
/// {@link CompletionItemLabel.detail}. Should be used for fully qualified
|
||||
/// names or file path.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_deserialization;
|
||||
|
||||
#[test]
|
||||
fn test_tag_support_deserialization() {
|
||||
let empty = CompletionItemCapability {
|
||||
tag_support: None,
|
||||
..CompletionItemCapability::default()
|
||||
};
|
||||
|
||||
test_deserialization(r#"{}"#, &empty);
|
||||
test_deserialization(r#"{"tagSupport": false}"#, &empty);
|
||||
|
||||
let t = CompletionItemCapability {
|
||||
tag_support: Some(TagSupport { value_set: vec![] }),
|
||||
..CompletionItemCapability::default()
|
||||
};
|
||||
test_deserialization(r#"{"tagSupport": true}"#, &t);
|
||||
|
||||
let t = CompletionItemCapability {
|
||||
tag_support: Some(TagSupport {
|
||||
value_set: vec![CompletionItemTag::DEPRECATED],
|
||||
}),
|
||||
..CompletionItemCapability::default()
|
||||
};
|
||||
test_deserialization(r#"{"tagSupport": {"valueSet": [1]}}"#, &t);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_debug_enum() {
|
||||
assert_eq!(format!("{:?}", CompletionItemKind::TEXT), "Text");
|
||||
assert_eq!(
|
||||
format!("{:?}", CompletionItemKind::TYPE_PARAMETER),
|
||||
"TypeParameter"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from_enum() {
|
||||
use std::convert::TryInto;
|
||||
assert_eq!("Text".try_into(), Ok(CompletionItemKind::TEXT));
|
||||
assert_eq!(
|
||||
"TypeParameter".try_into(),
|
||||
Ok(CompletionItemKind::TYPE_PARAMETER)
|
||||
);
|
||||
}
|
||||
}
|
269
helix-lsp-types/src/document_diagnostic.rs
Normal file
269
helix-lsp-types/src/document_diagnostic.rs
Normal file
@ -0,0 +1,269 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
Diagnostic, PartialResultParams, StaticRegistrationOptions, TextDocumentIdentifier,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
/// Client capabilities specific to diagnostic pull requests.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration.
|
||||
///
|
||||
/// If this is set to `true` the client supports the new `(TextDocumentRegistrationOptions &
|
||||
/// StaticRegistrationOptions)` return value for the corresponding server capability as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Whether the clients supports related documents for document diagnostic pulls.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub related_document_support: Option<bool>,
|
||||
}
|
||||
|
||||
/// Diagnostic options.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticOptions {
|
||||
/// An optional identifier under which the diagnostics are
|
||||
/// managed by the client.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub identifier: Option<String>,
|
||||
|
||||
/// Whether the language has inter file dependencies, meaning that editing code in one file can
|
||||
/// result in a different diagnostic set in another file. Inter file dependencies are common
|
||||
/// for most programming languages and typically uncommon for linters.
|
||||
pub inter_file_dependencies: bool,
|
||||
|
||||
/// The server provides support for workspace diagnostics as well.
|
||||
pub workspace_diagnostics: bool,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
/// Diagnostic registration options.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub diagnostic_options: DiagnosticOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DiagnosticServerCapabilities {
|
||||
Options(DiagnosticOptions),
|
||||
RegistrationOptions(DiagnosticRegistrationOptions),
|
||||
}
|
||||
|
||||
/// Parameters of the document diagnostic request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentDiagnosticParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The additional identifier provided during registration.
|
||||
pub identifier: Option<String>,
|
||||
|
||||
/// The result ID of a previous response if provided.
|
||||
pub previous_result_id: Option<String>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A diagnostic report with a full set of problems.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FullDocumentDiagnosticReport {
|
||||
/// An optional result ID. If provided it will be sent on the next diagnostic request for the
|
||||
/// same document.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub result_id: Option<String>,
|
||||
|
||||
/// The actual items.
|
||||
pub items: Vec<Diagnostic>,
|
||||
}
|
||||
|
||||
/// A diagnostic report indicating that the last returned report is still accurate.
|
||||
///
|
||||
/// A server can only return `unchanged` if result ids are provided.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UnchangedDocumentDiagnosticReport {
|
||||
/// A result ID which will be sent on the next diagnostic request for the same document.
|
||||
pub result_id: String,
|
||||
}
|
||||
|
||||
/// The document diagnostic report kinds.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum DocumentDiagnosticReportKind {
|
||||
/// A diagnostic report with a full set of problems.
|
||||
Full(FullDocumentDiagnosticReport),
|
||||
/// A report indicating that the last returned report is still accurate.
|
||||
Unchanged(UnchangedDocumentDiagnosticReport),
|
||||
}
|
||||
|
||||
impl From<FullDocumentDiagnosticReport> for DocumentDiagnosticReportKind {
|
||||
fn from(from: FullDocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReportKind::Full(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UnchangedDocumentDiagnosticReport> for DocumentDiagnosticReportKind {
|
||||
fn from(from: UnchangedDocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReportKind::Unchanged(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A full diagnostic report with a set of related documents.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RelatedFullDocumentDiagnosticReport {
|
||||
/// Diagnostics of related documents.
|
||||
///
|
||||
/// This information is useful in programming languages where code in a file A can generate
|
||||
/// diagnostics in a file B which A depends on. An example of such a language is C/C++ where
|
||||
/// macro definitions in a file `a.cpp` result in errors in a header file `b.hpp`.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(with = "crate::url_map")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub related_documents: Option<HashMap<Url, DocumentDiagnosticReportKind>>,
|
||||
// relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; };
|
||||
#[serde(flatten)]
|
||||
pub full_document_diagnostic_report: FullDocumentDiagnosticReport,
|
||||
}
|
||||
|
||||
/// An unchanged diagnostic report with a set of related documents.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RelatedUnchangedDocumentDiagnosticReport {
|
||||
/// Diagnostics of related documents.
|
||||
///
|
||||
/// This information is useful in programming languages where code in a file A can generate
|
||||
/// diagnostics in a file B which A depends on. An example of such a language is C/C++ where
|
||||
/// macro definitions in a file `a.cpp` result in errors in a header file `b.hpp`.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(with = "crate::url_map")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub related_documents: Option<HashMap<Url, DocumentDiagnosticReportKind>>,
|
||||
// relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; };
|
||||
#[serde(flatten)]
|
||||
pub unchanged_document_diagnostic_report: UnchangedDocumentDiagnosticReport,
|
||||
}
|
||||
|
||||
/// The result of a document diagnostic pull request.
|
||||
///
|
||||
/// A report can either be a full report containing all diagnostics for the requested document or
|
||||
/// an unchanged report indicating that nothing has changed in terms of diagnostics in comparison
|
||||
/// to the last pull request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum DocumentDiagnosticReport {
|
||||
/// A diagnostic report with a full set of problems.
|
||||
Full(RelatedFullDocumentDiagnosticReport),
|
||||
/// A report indicating that the last returned report is still accurate.
|
||||
Unchanged(RelatedUnchangedDocumentDiagnosticReport),
|
||||
}
|
||||
|
||||
impl From<RelatedFullDocumentDiagnosticReport> for DocumentDiagnosticReport {
|
||||
fn from(from: RelatedFullDocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReport::Full(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RelatedUnchangedDocumentDiagnosticReport> for DocumentDiagnosticReport {
|
||||
fn from(from: RelatedUnchangedDocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReport::Unchanged(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A partial result for a document diagnostic report.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentDiagnosticReportPartialResult {
|
||||
#[serde(with = "crate::url_map")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub related_documents: Option<HashMap<Url, DocumentDiagnosticReportKind>>,
|
||||
// relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; };
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum DocumentDiagnosticReportResult {
|
||||
Report(DocumentDiagnosticReport),
|
||||
Partial(DocumentDiagnosticReportPartialResult),
|
||||
}
|
||||
|
||||
impl From<DocumentDiagnosticReport> for DocumentDiagnosticReportResult {
|
||||
fn from(from: DocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReportResult::Report(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DocumentDiagnosticReportPartialResult> for DocumentDiagnosticReportResult {
|
||||
fn from(from: DocumentDiagnosticReportPartialResult) -> Self {
|
||||
DocumentDiagnosticReportResult::Partial(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancellation data returned from a diagnostic request.
|
||||
///
|
||||
/// If no data is provided, it defaults to `{ retrigger_request: true }`.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticServerCancellationData {
|
||||
pub retrigger_request: bool,
|
||||
}
|
||||
|
||||
impl Default for DiagnosticServerCancellationData {
|
||||
fn default() -> Self {
|
||||
DiagnosticServerCancellationData {
|
||||
retrigger_request: true,
|
||||
}
|
||||
}
|
||||
}
|
51
helix-lsp-types/src/document_highlight.rs
Normal file
51
helix-lsp-types/src/document_highlight.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, PartialResultParams, Range, TextDocumentPositionParams,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type DocumentHighlightClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentHighlightParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A document highlight is a range inside a text document which deserves
|
||||
/// special attention. Usually a document highlight is visualized by changing
|
||||
/// the background color of its range.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct DocumentHighlight {
|
||||
/// The range this highlight applies to.
|
||||
pub range: Range,
|
||||
|
||||
/// The highlight kind, default is DocumentHighlightKind.Text.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<DocumentHighlightKind>,
|
||||
}
|
||||
|
||||
/// A document highlight kind.
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct DocumentHighlightKind(i32);
|
||||
lsp_enum! {
|
||||
impl DocumentHighlightKind {
|
||||
/// A textual occurrence.
|
||||
pub const TEXT: DocumentHighlightKind = DocumentHighlightKind(1);
|
||||
|
||||
/// Read-access of a symbol, like reading a variable.
|
||||
pub const READ: DocumentHighlightKind = DocumentHighlightKind(2);
|
||||
|
||||
/// Write-access of a symbol, like writing to a variable.
|
||||
pub const WRITE: DocumentHighlightKind = DocumentHighlightKind(3);
|
||||
}
|
||||
}
|
67
helix-lsp-types/src/document_link.rs
Normal file
67
helix-lsp-types/src/document_link.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use crate::{
|
||||
PartialResultParams, Range, TextDocumentIdentifier, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentLinkClientCapabilities {
|
||||
/// Whether document link supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Whether the client support the `tooltip` property on `DocumentLink`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tooltip_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentLinkOptions {
|
||||
/// Document links have a resolve provider as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentLinkParams {
|
||||
/// The document to provide document links for.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A document link is a range in a text document that links to an internal or external resource, like another
|
||||
/// text document or a web site.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct DocumentLink {
|
||||
/// The range this link applies to.
|
||||
pub range: Range,
|
||||
/// The uri this link points to.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub target: Option<Url>,
|
||||
|
||||
/// The tooltip text when you hover over this link.
|
||||
///
|
||||
/// If a tooltip is provided, is will be displayed in a string that includes instructions on how to
|
||||
/// trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS,
|
||||
/// user settings, and localization.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tooltip: Option<String>,
|
||||
|
||||
/// A data entry field that is preserved on a document link between a DocumentLinkRequest
|
||||
/// and a DocumentLinkResolveRequest.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
134
helix-lsp-types/src/document_symbols.rs
Normal file
134
helix-lsp-types/src/document_symbols.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use crate::{
|
||||
Location, PartialResultParams, Range, SymbolKind, SymbolKindCapability, TextDocumentIdentifier,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use crate::{SymbolTag, TagSupport};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentSymbolClientCapabilities {
|
||||
/// This capability supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Specific capabilities for the `SymbolKind`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub symbol_kind: Option<SymbolKindCapability>,
|
||||
|
||||
/// The client support hierarchical document symbols.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub hierarchical_document_symbol_support: Option<bool>,
|
||||
|
||||
/// The client supports tags on `SymbolInformation`. Tags are supported on
|
||||
/// `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true.
|
||||
/// Clients supporting tags have to handle unknown tags gracefully.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "TagSupport::deserialize_compat"
|
||||
)]
|
||||
pub tag_support: Option<TagSupport<SymbolTag>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DocumentSymbolResponse {
|
||||
Flat(Vec<SymbolInformation>),
|
||||
Nested(Vec<DocumentSymbol>),
|
||||
}
|
||||
|
||||
impl From<Vec<SymbolInformation>> for DocumentSymbolResponse {
|
||||
fn from(info: Vec<SymbolInformation>) -> Self {
|
||||
DocumentSymbolResponse::Flat(info)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<DocumentSymbol>> for DocumentSymbolResponse {
|
||||
fn from(symbols: Vec<DocumentSymbol>) -> Self {
|
||||
DocumentSymbolResponse::Nested(symbols)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentSymbolParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Represents programming constructs like variables, classes, interfaces etc.
|
||||
/// that appear in a document. Document symbols can be hierarchical and they have two ranges:
|
||||
/// one that encloses its definition and one that points to its most interesting range,
|
||||
/// e.g. the range of an identifier.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentSymbol {
|
||||
/// The name of this symbol.
|
||||
pub name: String,
|
||||
/// More detail for this symbol, e.g the signature of a function. If not provided the
|
||||
/// name is used.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
/// The kind of this symbol.
|
||||
pub kind: SymbolKind,
|
||||
/// Tags for this completion item.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<SymbolTag>>,
|
||||
/// Indicates if this symbol is deprecated.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[deprecated(note = "Use tags instead")]
|
||||
pub deprecated: Option<bool>,
|
||||
/// The range enclosing this symbol not including leading/trailing whitespace but everything else
|
||||
/// like comments. This information is typically used to determine if the the clients cursor is
|
||||
/// inside the symbol to reveal in the symbol in the UI.
|
||||
pub range: Range,
|
||||
/// The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
|
||||
/// Must be contained by the the `range`.
|
||||
pub selection_range: Range,
|
||||
/// Children of this symbol, e.g. properties of a class.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub children: Option<Vec<DocumentSymbol>>,
|
||||
}
|
||||
|
||||
/// Represents information about programming constructs like variables, classes,
|
||||
/// interfaces etc.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SymbolInformation {
|
||||
/// The name of this symbol.
|
||||
pub name: String,
|
||||
|
||||
/// The kind of this symbol.
|
||||
pub kind: SymbolKind,
|
||||
|
||||
/// Tags for this completion item.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<SymbolTag>>,
|
||||
|
||||
/// Indicates if this symbol is deprecated.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[deprecated(note = "Use tags instead")]
|
||||
pub deprecated: Option<bool>,
|
||||
|
||||
/// The location of this symbol.
|
||||
pub location: Location,
|
||||
|
||||
/// The name of the symbol containing this symbol.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub container_name: Option<String>,
|
||||
}
|
54
helix-lsp-types/src/error_codes.rs
Normal file
54
helix-lsp-types/src/error_codes.rs
Normal file
@ -0,0 +1,54 @@
|
||||
//! In this module we only define constants for lsp specific error codes.
|
||||
//! There are other error codes that are defined in the
|
||||
//! [JSON RPC specification](https://www.jsonrpc.org/specification#error_object).
|
||||
|
||||
/// Defined in the LSP specification but in the range reserved for JSON-RPC error codes,
|
||||
/// namely the -32099 to -32000 "Reserved for implementation-defined server-errors." range.
|
||||
/// The code has, nonetheless, been left in this range for backwards compatibility reasons.
|
||||
pub const SERVER_NOT_INITIALIZED: i64 = -32002;
|
||||
|
||||
/// Defined in the LSP specification but in the range reserved for JSON-RPC error codes,
|
||||
/// namely the -32099 to -32000 "Reserved for implementation-defined server-errors." range.
|
||||
/// The code has, nonetheless, left in this range for backwards compatibility reasons.
|
||||
pub const UNKNOWN_ERROR_CODE: i64 = -32001;
|
||||
|
||||
/// This is the start range of LSP reserved error codes.
|
||||
/// It doesn't denote a real error code.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
pub const LSP_RESERVED_ERROR_RANGE_START: i64 = -32899;
|
||||
|
||||
/// A request failed but it was syntactically correct, e.g the
|
||||
/// method name was known and the parameters were valid. The error
|
||||
/// message should contain human readable information about why
|
||||
/// the request failed.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
pub const REQUEST_FAILED: i64 = -32803;
|
||||
|
||||
/// The server cancelled the request. This error code should
|
||||
/// only be used for requests that explicitly support being
|
||||
/// server cancellable.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
pub const SERVER_CANCELLED: i64 = -32802;
|
||||
|
||||
/// The server detected that the content of a document got
|
||||
/// modified outside normal conditions. A server should
|
||||
/// NOT send this error code if it detects a content change
|
||||
/// in it unprocessed messages. The result even computed
|
||||
/// on an older state might still be useful for the client.
|
||||
///
|
||||
/// If a client decides that a result is not of any use anymore
|
||||
/// the client should cancel the request.
|
||||
pub const CONTENT_MODIFIED: i64 = -32801;
|
||||
|
||||
/// The client has canceled a request and a server as detected
|
||||
/// the cancel.
|
||||
pub const REQUEST_CANCELLED: i64 = -32800;
|
||||
|
||||
/// This is the end range of LSP reserved error codes.
|
||||
/// It doesn't denote a real error code.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
pub const LSP_RESERVED_ERROR_RANGE_END: i64 = -32800;
|
213
helix-lsp-types/src/file_operations.rs
Normal file
213
helix-lsp-types/src/file_operations.rs
Normal file
@ -0,0 +1,213 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFileOperationsClientCapabilities {
|
||||
/// Whether the client supports dynamic registration for file
|
||||
/// requests/notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The client has support for sending didCreateFiles notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_create: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving willCreateFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_create: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving didRenameFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_rename: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving willRenameFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_rename: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving didDeleteFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_delete: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving willDeleteFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_delete: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFileOperationsServerCapabilities {
|
||||
/// The server is interested in receiving didCreateFiles
|
||||
/// notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_create: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving willCreateFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_create: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving didRenameFiles
|
||||
/// notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_rename: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving willRenameFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_rename: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving didDeleteFiles file
|
||||
/// notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_delete: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving willDeleteFiles file
|
||||
/// requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_delete: Option<FileOperationRegistrationOptions>,
|
||||
}
|
||||
|
||||
/// The options to register for file operations.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileOperationRegistrationOptions {
|
||||
/// The actual filters.
|
||||
pub filters: Vec<FileOperationFilter>,
|
||||
}
|
||||
|
||||
/// A filter to describe in which file operation requests or notifications
|
||||
/// the server is interested in.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileOperationFilter {
|
||||
/// A Uri like `file` or `untitled`.
|
||||
pub scheme: Option<String>,
|
||||
|
||||
/// The actual file operation pattern.
|
||||
pub pattern: FileOperationPattern,
|
||||
}
|
||||
|
||||
/// A pattern kind describing if a glob pattern matches a file a folder or
|
||||
/// both.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum FileOperationPatternKind {
|
||||
/// The pattern matches a file only.
|
||||
File,
|
||||
|
||||
/// The pattern matches a folder only.
|
||||
Folder,
|
||||
}
|
||||
|
||||
/// Matching options for the file operation pattern.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
///
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileOperationPatternOptions {
|
||||
/// The pattern should be matched ignoring casing.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ignore_case: Option<bool>,
|
||||
}
|
||||
|
||||
/// A pattern to describe in which file operation requests or notifications
|
||||
/// the server is interested in.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileOperationPattern {
|
||||
/// The glob pattern to match. Glob patterns can have the following syntax:
|
||||
/// - `*` to match one or more characters in a path segment
|
||||
/// - `?` to match on one character in a path segment
|
||||
/// - `**` to match any number of path segments, including none
|
||||
/// - `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript
|
||||
/// and JavaScript files)
|
||||
/// - `[]` to declare a range of characters to match in a path segment
|
||||
/// (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
|
||||
/// - `[!...]` to negate a range of characters to match in a path segment
|
||||
/// (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but
|
||||
/// not `example.0`)
|
||||
pub glob: String,
|
||||
|
||||
/// Whether to match files or folders with this pattern.
|
||||
///
|
||||
/// Matches both if undefined.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub matches: Option<FileOperationPatternKind>,
|
||||
|
||||
/// Additional options used during matching.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub options: Option<FileOperationPatternOptions>,
|
||||
}
|
||||
|
||||
/// The parameters sent in notifications/requests for user-initiated creation
|
||||
/// of files.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateFilesParams {
|
||||
/// An array of all files/folders created in this operation.
|
||||
pub files: Vec<FileCreate>,
|
||||
}
|
||||
/// Represents information on a file/folder create.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileCreate {
|
||||
/// A file:// URI for the location of the file/folder being created.
|
||||
pub uri: String,
|
||||
}
|
||||
|
||||
/// The parameters sent in notifications/requests for user-initiated renames
|
||||
/// of files.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenameFilesParams {
|
||||
/// An array of all files/folders renamed in this operation. When a folder
|
||||
/// is renamed, only the folder will be included, and not its children.
|
||||
pub files: Vec<FileRename>,
|
||||
}
|
||||
|
||||
/// Represents information on a file/folder rename.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileRename {
|
||||
/// A file:// URI for the original location of the file/folder being renamed.
|
||||
pub old_uri: String,
|
||||
|
||||
/// A file:// URI for the new location of the file/folder being renamed.
|
||||
pub new_uri: String,
|
||||
}
|
||||
|
||||
/// The parameters sent in notifications/requests for user-initiated deletes
|
||||
/// of files.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeleteFilesParams {
|
||||
/// An array of all files/folders deleted in this operation.
|
||||
pub files: Vec<FileDelete>,
|
||||
}
|
||||
|
||||
/// Represents information on a file/folder delete.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileDelete {
|
||||
/// A file:// URI for the location of the file/folder being deleted.
|
||||
pub uri: String,
|
||||
}
|
145
helix-lsp-types/src/folding_range.rs
Normal file
145
helix-lsp-types/src/folding_range.rs
Normal file
@ -0,0 +1,145 @@
|
||||
use crate::{
|
||||
PartialResultParams, StaticTextDocumentColorProviderOptions, TextDocumentIdentifier,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRangeParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum FoldingRangeProviderCapability {
|
||||
Simple(bool),
|
||||
FoldingProvider(FoldingProviderOptions),
|
||||
Options(StaticTextDocumentColorProviderOptions),
|
||||
}
|
||||
|
||||
impl From<StaticTextDocumentColorProviderOptions> for FoldingRangeProviderCapability {
|
||||
fn from(from: StaticTextDocumentColorProviderOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FoldingProviderOptions> for FoldingRangeProviderCapability {
|
||||
fn from(from: FoldingProviderOptions) -> Self {
|
||||
Self::FoldingProvider(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for FoldingRangeProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct FoldingProviderOptions {}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRangeKindCapability {
|
||||
/// The folding range kind values the client supports. When this
|
||||
/// property exists the client also guarantees that it will
|
||||
/// handle values outside its set gracefully and falls back
|
||||
/// to a default value when unknown.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub value_set: Option<Vec<FoldingRangeKind>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRangeCapability {
|
||||
/// If set, the client signals that it supports setting collapsedText on
|
||||
/// folding ranges to display custom labels instead of the default text.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub collapsed_text: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRangeClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration for folding range providers. If this is set to `true`
|
||||
/// the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||
/// return value for the corresponding server capability as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The maximum number of folding ranges that the client prefers to receive per document. The value serves as a
|
||||
/// hint, servers are free to follow the limit.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range_limit: Option<u32>,
|
||||
|
||||
/// If set, the client signals that it only supports folding complete lines. If set, client will
|
||||
/// ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub line_folding_only: Option<bool>,
|
||||
|
||||
/// Specific options for the folding range kind.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub folding_range_kind: Option<FoldingRangeKindCapability>,
|
||||
|
||||
/// Specific options for the folding range.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub folding_range: Option<FoldingRangeCapability>,
|
||||
}
|
||||
|
||||
/// Enum of known range kinds
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum FoldingRangeKind {
|
||||
/// Folding range for a comment
|
||||
Comment,
|
||||
/// Folding range for a imports or includes
|
||||
Imports,
|
||||
/// Folding range for a region (e.g. `#region`)
|
||||
Region,
|
||||
}
|
||||
|
||||
/// Represents a folding range.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRange {
|
||||
/// The zero-based line number from where the folded range starts.
|
||||
pub start_line: u32,
|
||||
|
||||
/// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub start_character: Option<u32>,
|
||||
|
||||
/// The zero-based line number where the folded range ends.
|
||||
pub end_line: u32,
|
||||
|
||||
/// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub end_character: Option<u32>,
|
||||
|
||||
/// Describes the kind of the folding range such as `comment' or 'region'. The kind
|
||||
/// is used to categorize folding ranges and used by commands like 'Fold all comments'. See
|
||||
/// [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<FoldingRangeKind>,
|
||||
|
||||
/// The text that the client should show when the specified range is
|
||||
/// collapsed. If not defined or not supported by the client, a default
|
||||
/// will be chosen by the client.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub collapsed_text: Option<String>,
|
||||
}
|
153
helix-lsp-types/src/formatting.rs
Normal file
153
helix-lsp-types/src/formatting.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
DocumentSelector, DynamicRegistrationClientCapabilities, Range, TextDocumentIdentifier,
|
||||
TextDocumentPositionParams, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub type DocumentFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
pub type DocumentRangeFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
pub type DocumentOnTypeFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
/// Format document on type options
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentOnTypeFormattingOptions {
|
||||
/// A character on which formatting should be triggered, like `}`.
|
||||
pub first_trigger_character: String,
|
||||
|
||||
/// More trigger characters.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub more_trigger_character: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentFormattingParams {
|
||||
/// The document to format.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The format options.
|
||||
pub options: FormattingOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
/// Value-object describing what options formatting should use.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FormattingOptions {
|
||||
/// Size of a tab in spaces.
|
||||
pub tab_size: u32,
|
||||
|
||||
/// Prefer spaces over tabs.
|
||||
pub insert_spaces: bool,
|
||||
|
||||
/// Signature for further properties.
|
||||
#[serde(flatten)]
|
||||
pub properties: HashMap<String, FormattingProperty>,
|
||||
|
||||
/// Trim trailing whitespace on a line.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trim_trailing_whitespace: Option<bool>,
|
||||
|
||||
/// Insert a newline character at the end of the file if one does not exist.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_final_newline: Option<bool>,
|
||||
|
||||
/// Trim all newlines after the final newline at the end of the file.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trim_final_newlines: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum FormattingProperty {
|
||||
Bool(bool),
|
||||
Number(i32),
|
||||
String(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentRangeFormattingParams {
|
||||
/// The document to format.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The range to format
|
||||
pub range: Range,
|
||||
|
||||
/// The format options
|
||||
pub options: FormattingOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentOnTypeFormattingParams {
|
||||
/// Text Document and Position fields.
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
/// The character that has been typed.
|
||||
pub ch: String,
|
||||
|
||||
/// The format options.
|
||||
pub options: FormattingOptions,
|
||||
}
|
||||
|
||||
/// Extends TextDocumentRegistrationOptions
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentOnTypeFormattingRegistrationOptions {
|
||||
/// A document selector to identify the scope of the registration. If set to null
|
||||
/// the document selector provided on the client side will be used.
|
||||
pub document_selector: Option<DocumentSelector>,
|
||||
|
||||
/// A character on which formatting should be triggered, like `}`.
|
||||
pub first_trigger_character: String,
|
||||
|
||||
/// More trigger characters.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub more_trigger_character: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_serialization;
|
||||
|
||||
#[test]
|
||||
fn formatting_options() {
|
||||
test_serialization(
|
||||
&FormattingOptions {
|
||||
tab_size: 123,
|
||||
insert_spaces: true,
|
||||
properties: HashMap::new(),
|
||||
trim_trailing_whitespace: None,
|
||||
insert_final_newline: None,
|
||||
trim_final_newlines: None,
|
||||
},
|
||||
r#"{"tabSize":123,"insertSpaces":true}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&FormattingOptions {
|
||||
tab_size: 123,
|
||||
insert_spaces: true,
|
||||
properties: vec![("prop".to_string(), FormattingProperty::Number(1))]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
trim_trailing_whitespace: None,
|
||||
insert_final_newline: None,
|
||||
trim_final_newlines: None,
|
||||
},
|
||||
r#"{"tabSize":123,"insertSpaces":true,"prop":1}"#,
|
||||
);
|
||||
}
|
||||
}
|
86
helix-lsp-types/src/hover.rs
Normal file
86
helix-lsp-types/src/hover.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
MarkedString, MarkupContent, MarkupKind, Range, TextDocumentPositionParams,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HoverClientCapabilities {
|
||||
/// Whether completion supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Client supports the follow content formats for the content
|
||||
/// property. The order describes the preferred format of the client.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content_format: Option<Vec<MarkupKind>>,
|
||||
}
|
||||
|
||||
/// Hover options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HoverOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HoverRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub hover_options: HoverOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum HoverProviderCapability {
|
||||
Simple(bool),
|
||||
Options(HoverOptions),
|
||||
}
|
||||
|
||||
impl From<HoverOptions> for HoverProviderCapability {
|
||||
fn from(from: HoverOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for HoverProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HoverParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
/// The result of a hover request.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct Hover {
|
||||
/// The hover's content
|
||||
pub contents: HoverContents,
|
||||
/// An optional range is a range inside a text document
|
||||
/// that is used to visualize a hover, e.g. by changing the background color.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range: Option<Range>,
|
||||
}
|
||||
|
||||
/// Hover contents could be single entry or multiple entries.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum HoverContents {
|
||||
Scalar(MarkedString),
|
||||
Array(Vec<MarkedString>),
|
||||
Markup(MarkupContent),
|
||||
}
|
281
helix-lsp-types/src/inlay_hint.rs
Normal file
281
helix-lsp-types/src/inlay_hint.rs
Normal file
@ -0,0 +1,281 @@
|
||||
use crate::{
|
||||
Command, LSPAny, Location, MarkupContent, Position, Range, StaticRegistrationOptions,
|
||||
TextDocumentIdentifier, TextDocumentRegistrationOptions, TextEdit, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum InlayHintServerCapabilities {
|
||||
Options(InlayHintOptions),
|
||||
RegistrationOptions(InlayHintRegistrationOptions),
|
||||
}
|
||||
|
||||
/// Inlay hint client capabilities.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintClientCapabilities {
|
||||
/// Whether inlay hints support dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Indicates which properties a client can resolve lazily on a inlay
|
||||
/// hint.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_support: Option<InlayHintResolveClientCapabilities>,
|
||||
}
|
||||
|
||||
/// Inlay hint options used during static registration.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
|
||||
/// The server provides support to resolve additional
|
||||
/// information for an inlay hint item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
}
|
||||
|
||||
/// Inlay hint options used during static or dynamic registration.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub inlay_hint_options: InlayHintOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
/// A parameter literal used in inlay hint requests.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The visible document range for which inlay hints should be computed.
|
||||
pub range: Range,
|
||||
}
|
||||
|
||||
/// Inlay hint information.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHint {
|
||||
/// The position of this hint.
|
||||
pub position: Position,
|
||||
|
||||
/// The label of this hint. A human readable string or an array of
|
||||
/// InlayHintLabelPart label parts.
|
||||
///
|
||||
/// *Note* that neither the string nor the label part can be empty.
|
||||
pub label: InlayHintLabel,
|
||||
|
||||
/// The kind of this hint. Can be omitted in which case the client
|
||||
/// should fall back to a reasonable default.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<InlayHintKind>,
|
||||
|
||||
/// Optional text edits that are performed when accepting this inlay hint.
|
||||
///
|
||||
/// *Note* that edits are expected to change the document so that the inlay
|
||||
/// hint (or its nearest variant) is now part of the document and the inlay
|
||||
/// hint itself is now obsolete.
|
||||
///
|
||||
/// Depending on the client capability `inlayHint.resolveSupport` clients
|
||||
/// might resolve this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_edits: Option<Vec<TextEdit>>,
|
||||
|
||||
/// The tooltip text when you hover over this item.
|
||||
///
|
||||
/// Depending on the client capability `inlayHint.resolveSupport` clients
|
||||
/// might resolve this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tooltip: Option<InlayHintTooltip>,
|
||||
|
||||
/// Render padding before the hint.
|
||||
///
|
||||
/// Note: Padding should use the editor's background color, not the
|
||||
/// background color of the hint itself. That means padding can be used
|
||||
/// to visually align/separate an inlay hint.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub padding_left: Option<bool>,
|
||||
|
||||
/// Render padding after the hint.
|
||||
///
|
||||
/// Note: Padding should use the editor's background color, not the
|
||||
/// background color of the hint itself. That means padding can be used
|
||||
/// to visually align/separate an inlay hint.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub padding_right: Option<bool>,
|
||||
|
||||
/// A data entry field that is preserved on a inlay hint between
|
||||
/// a `textDocument/inlayHint` and a `inlayHint/resolve` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<LSPAny>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlayHintLabel {
|
||||
String(String),
|
||||
LabelParts(Vec<InlayHintLabelPart>),
|
||||
}
|
||||
|
||||
impl From<String> for InlayHintLabel {
|
||||
#[inline]
|
||||
fn from(from: String) -> Self {
|
||||
Self::String(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<InlayHintLabelPart>> for InlayHintLabel {
|
||||
#[inline]
|
||||
fn from(from: Vec<InlayHintLabelPart>) -> Self {
|
||||
Self::LabelParts(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlayHintTooltip {
|
||||
String(String),
|
||||
MarkupContent(MarkupContent),
|
||||
}
|
||||
|
||||
impl From<String> for InlayHintTooltip {
|
||||
#[inline]
|
||||
fn from(from: String) -> Self {
|
||||
Self::String(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MarkupContent> for InlayHintTooltip {
|
||||
#[inline]
|
||||
fn from(from: MarkupContent) -> Self {
|
||||
Self::MarkupContent(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// An inlay hint label part allows for interactive and composite labels
|
||||
/// of inlay hints.
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintLabelPart {
|
||||
/// The value of this label part.
|
||||
pub value: String,
|
||||
|
||||
/// The tooltip text when you hover over this label part. Depending on
|
||||
/// the client capability `inlayHint.resolveSupport` clients might resolve
|
||||
/// this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tooltip: Option<InlayHintLabelPartTooltip>,
|
||||
|
||||
/// An optional source code location that represents this
|
||||
/// label part.
|
||||
///
|
||||
/// The editor will use this location for the hover and for code navigation
|
||||
/// features: This part will become a clickable link that resolves to the
|
||||
/// definition of the symbol at the given location (not necessarily the
|
||||
/// location itself), it shows the hover that shows at the given location,
|
||||
/// and it shows a context menu with further code navigation commands.
|
||||
///
|
||||
/// Depending on the client capability `inlayHint.resolveSupport` clients
|
||||
/// might resolve this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub location: Option<Location>,
|
||||
|
||||
/// An optional command for this label part.
|
||||
///
|
||||
/// Depending on the client capability `inlayHint.resolveSupport` clients
|
||||
/// might resolve this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlayHintLabelPartTooltip {
|
||||
String(String),
|
||||
MarkupContent(MarkupContent),
|
||||
}
|
||||
|
||||
impl From<String> for InlayHintLabelPartTooltip {
|
||||
#[inline]
|
||||
fn from(from: String) -> Self {
|
||||
Self::String(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MarkupContent> for InlayHintLabelPartTooltip {
|
||||
#[inline]
|
||||
fn from(from: MarkupContent) -> Self {
|
||||
Self::MarkupContent(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// Inlay hint kinds.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct InlayHintKind(i32);
|
||||
lsp_enum! {
|
||||
impl InlayHintKind {
|
||||
/// An inlay hint that for a type annotation.
|
||||
pub const TYPE: InlayHintKind = InlayHintKind(1);
|
||||
|
||||
/// An inlay hint that is for a parameter.
|
||||
pub const PARAMETER: InlayHintKind = InlayHintKind(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inlay hint client capabilities.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintResolveClientCapabilities {
|
||||
/// The properties that a client can resolve lazily.
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
/// Client workspace capabilities specific to inlay hints.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from
|
||||
/// the server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// inlay hints currently shown. It should be used with absolute care and
|
||||
/// is useful for situation where a server for example detects a project wide
|
||||
/// change that requires such a calculation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
||||
|
||||
// TODO(sno2): add tests once stabilized
|
162
helix-lsp-types/src/inline_completion.rs
Normal file
162
helix-lsp-types/src/inline_completion.rs
Normal file
@ -0,0 +1,162 @@
|
||||
use crate::{
|
||||
Command, InsertTextFormat, Range, StaticRegistrationOptions, TextDocumentPositionParams,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Client capabilities specific to inline completions.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineCompletionClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration for inline completion providers.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
}
|
||||
|
||||
/// Inline completion options used during static registration.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineCompletionOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
/// Inline completion options used during static or dynamic registration.
|
||||
///
|
||||
// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineCompletionRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub inline_completion_options: InlineCompletionOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
/// A parameter literal used in inline completion requests.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineCompletionParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
/// Additional information about the context in which inline completions were requested.
|
||||
pub context: InlineCompletionContext,
|
||||
}
|
||||
|
||||
/// Describes how an [`InlineCompletionItemProvider`] was triggered.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
pub struct InlineCompletionTriggerKind(i32);
|
||||
lsp_enum! {
|
||||
impl InlineCompletionTriggerKind {
|
||||
/// Completion was triggered explicitly by a user gesture.
|
||||
/// Return multiple completion items to enable cycling through them.
|
||||
pub const Invoked: InlineCompletionTriggerKind = InlineCompletionTriggerKind(1);
|
||||
|
||||
/// Completion was triggered automatically while editing.
|
||||
/// It is sufficient to return a single completion item in this case.
|
||||
pub const Automatic: InlineCompletionTriggerKind = InlineCompletionTriggerKind(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the currently selected completion item.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct SelectedCompletionInfo {
|
||||
/// The range that will be replaced if this completion item is accepted.
|
||||
pub range: Range,
|
||||
/// The text the range will be replaced with if this completion is
|
||||
/// accepted.
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
/// Provides information about the context in which an inline completion was
|
||||
/// requested.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineCompletionContext {
|
||||
/// Describes how the inline completion was triggered.
|
||||
pub trigger_kind: InlineCompletionTriggerKind,
|
||||
/// Provides information about the currently selected item in the
|
||||
/// autocomplete widget if it is visible.
|
||||
///
|
||||
/// If set, provided inline completions must extend the text of the
|
||||
/// selected item and use the same range, otherwise they are not shown as
|
||||
/// preview.
|
||||
/// As an example, if the document text is `console.` and the selected item
|
||||
/// is `.log` replacing the `.` in the document, the inline completion must
|
||||
/// also replace `.` and start with `.log`, for example `.log()`.
|
||||
///
|
||||
/// Inline completion providers are requested again whenever the selected
|
||||
/// item changes.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub selected_completion_info: Option<SelectedCompletionInfo>,
|
||||
}
|
||||
|
||||
/// InlineCompletion response can be multiple completion items, or a list of completion items
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlineCompletionResponse {
|
||||
Array(Vec<InlineCompletionItem>),
|
||||
List(InlineCompletionList),
|
||||
}
|
||||
|
||||
/// Represents a collection of [`InlineCompletionItem`] to be presented in the editor.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct InlineCompletionList {
|
||||
/// The inline completion items
|
||||
pub items: Vec<InlineCompletionItem>,
|
||||
}
|
||||
|
||||
/// An inline completion item represents a text snippet that is proposed inline
|
||||
/// to complete text that is being typed.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineCompletionItem {
|
||||
/// The text to replace the range with. Must be set.
|
||||
/// Is used both for the preview and the accept operation.
|
||||
pub insert_text: String,
|
||||
/// A text that is used to decide if this inline completion should be
|
||||
/// shown. When `falsy` the [`InlineCompletionItem::insertText`] is
|
||||
/// used.
|
||||
///
|
||||
/// An inline completion is shown if the text to replace is a prefix of the
|
||||
/// filter text.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub filter_text: Option<String>,
|
||||
/// The range to replace.
|
||||
/// Must begin and end on the same line.
|
||||
///
|
||||
/// Prefer replacements over insertions to provide a better experience when
|
||||
/// the user deletes typed text.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range: Option<Range>,
|
||||
/// An optional command that is executed *after* inserting this
|
||||
/// completion.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
/// The format of the insert text. The format applies to the `insertText`.
|
||||
/// If omitted defaults to `InsertTextFormat.PlainText`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_format: Option<InsertTextFormat>,
|
||||
}
|
217
helix-lsp-types/src/inline_value.rs
Normal file
217
helix-lsp-types/src/inline_value.rs
Normal file
@ -0,0 +1,217 @@
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, Range, StaticRegistrationOptions,
|
||||
TextDocumentIdentifier, TextDocumentRegistrationOptions, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type InlineValueClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlineValueServerCapabilities {
|
||||
Options(InlineValueOptions),
|
||||
RegistrationOptions(InlineValueRegistrationOptions),
|
||||
}
|
||||
|
||||
/// Inline value options used during static registration.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineValueOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
/// Inline value options used during static or dynamic registration.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineValueRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub inline_value_options: InlineValueOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
/// A parameter literal used in inline value requests.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The document range for which inline values should be computed.
|
||||
pub range: Range,
|
||||
|
||||
/// Additional information about the context in which inline values were
|
||||
/// requested.
|
||||
pub context: InlineValueContext,
|
||||
}
|
||||
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueContext {
|
||||
/// The stack frame (as a DAP Id) where the execution has stopped.
|
||||
pub frame_id: i32,
|
||||
|
||||
/// The document range where execution has stopped.
|
||||
/// Typically the end position of the range denotes the line where the
|
||||
/// inline values are shown.
|
||||
pub stopped_location: Range,
|
||||
}
|
||||
|
||||
/// Provide inline value as text.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineValueText {
|
||||
/// The document range for which the inline value applies.
|
||||
pub range: Range,
|
||||
|
||||
/// The text of the inline value.
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
/// Provide inline value through a variable lookup.
|
||||
///
|
||||
/// If only a range is specified, the variable name will be extracted from
|
||||
/// the underlying document.
|
||||
///
|
||||
/// An optional variable name can be used to override the extracted name.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueVariableLookup {
|
||||
/// The document range for which the inline value applies.
|
||||
/// The range is used to extract the variable name from the underlying
|
||||
/// document.
|
||||
pub range: Range,
|
||||
|
||||
/// If specified the name of the variable to look up.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub variable_name: Option<String>,
|
||||
|
||||
/// How to perform the lookup.
|
||||
pub case_sensitive_lookup: bool,
|
||||
}
|
||||
|
||||
/// Provide an inline value through an expression evaluation.
|
||||
///
|
||||
/// If only a range is specified, the expression will be extracted from the
|
||||
/// underlying document.
|
||||
///
|
||||
/// An optional expression can be used to override the extracted expression.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueEvaluatableExpression {
|
||||
/// The document range for which the inline value applies.
|
||||
/// The range is used to extract the evaluatable expression from the
|
||||
/// underlying document.
|
||||
pub range: Range,
|
||||
|
||||
/// If specified the expression overrides the extracted expression.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub expression: Option<String>,
|
||||
}
|
||||
|
||||
/// Inline value information can be provided by different means:
|
||||
/// - directly as a text value (class InlineValueText).
|
||||
/// - as a name to use for a variable lookup (class InlineValueVariableLookup)
|
||||
/// - as an evaluatable expression (class InlineValueEvaluatableExpression)
|
||||
/// The InlineValue types combines all inline value types into one type.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlineValue {
|
||||
Text(InlineValueText),
|
||||
VariableLookup(InlineValueVariableLookup),
|
||||
EvaluatableExpression(InlineValueEvaluatableExpression),
|
||||
}
|
||||
|
||||
impl From<InlineValueText> for InlineValue {
|
||||
#[inline]
|
||||
fn from(from: InlineValueText) -> Self {
|
||||
Self::Text(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InlineValueVariableLookup> for InlineValue {
|
||||
#[inline]
|
||||
fn from(from: InlineValueVariableLookup) -> Self {
|
||||
Self::VariableLookup(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InlineValueEvaluatableExpression> for InlineValue {
|
||||
#[inline]
|
||||
fn from(from: InlineValueEvaluatableExpression) -> Self {
|
||||
Self::EvaluatableExpression(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// Client workspace capabilities specific to inline values.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from
|
||||
/// the server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// inline values currently shown. It should be used with absolute care and
|
||||
/// is useful for situation where a server for example detect a project wide
|
||||
/// change that requires such a calculation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_serialization;
|
||||
use crate::Position;
|
||||
|
||||
#[test]
|
||||
fn inline_values() {
|
||||
test_serialization(
|
||||
&InlineValueText {
|
||||
range: Range::new(Position::new(0, 0), Position::new(0, 4)),
|
||||
text: "one".to_owned(),
|
||||
},
|
||||
r#"{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":4}},"text":"one"}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&InlineValue::VariableLookup(InlineValueVariableLookup {
|
||||
range: Range::new(Position::new(1, 0), Position::new(1, 4)),
|
||||
variable_name: None,
|
||||
case_sensitive_lookup: false,
|
||||
}),
|
||||
r#"{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":4}},"caseSensitiveLookup":false}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&InlineValue::EvaluatableExpression(InlineValueEvaluatableExpression {
|
||||
range: Range::new(Position::new(2, 0), Position::new(2, 4)),
|
||||
expression: None,
|
||||
}),
|
||||
r#"{"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":4}}}"#,
|
||||
);
|
||||
}
|
||||
}
|
2882
helix-lsp-types/src/lib.rs
Normal file
2882
helix-lsp-types/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
61
helix-lsp-types/src/linked_editing.rs
Normal file
61
helix-lsp-types/src/linked_editing.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, Range, StaticRegistrationOptions,
|
||||
TextDocumentPositionParams, TextDocumentRegistrationOptions, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type LinkedEditingRangeClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinkedEditingRangeOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinkedEditingRangeRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub linked_editing_range_options: LinkedEditingRangeOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum LinkedEditingRangeServerCapabilities {
|
||||
Simple(bool),
|
||||
Options(LinkedEditingRangeOptions),
|
||||
RegistrationOptions(LinkedEditingRangeRegistrationOptions),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinkedEditingRangeParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinkedEditingRanges {
|
||||
/// A list of ranges that can be renamed together. The ranges must have
|
||||
/// identical length and contain identical text content. The ranges cannot overlap.
|
||||
pub ranges: Vec<Range>,
|
||||
|
||||
/// An optional word pattern (regular expression) that describes valid contents for
|
||||
/// the given ranges. If no pattern is provided, the client configuration's word
|
||||
/// pattern will be used.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub word_pattern: Option<String>,
|
||||
}
|
336
helix-lsp-types/src/lsif.rs
Normal file
336
helix-lsp-types/src/lsif.rs
Normal file
@ -0,0 +1,336 @@
|
||||
//! Types of Language Server Index Format (LSIF). LSIF is a standard format
|
||||
//! for language servers or other programming tools to dump their knowledge
|
||||
//! about a workspace.
|
||||
//!
|
||||
//! Based on <https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/>
|
||||
|
||||
use crate::{Range, Url};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type Id = crate::NumberOrString;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum LocationOrRangeId {
|
||||
Location(crate::Location),
|
||||
RangeId(Id),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Entry {
|
||||
pub id: Id,
|
||||
#[serde(flatten)]
|
||||
pub data: Element,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Element {
|
||||
Vertex(Vertex),
|
||||
Edge(Edge),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ToolInfo {
|
||||
pub name: String,
|
||||
#[serde(default = "Default::default")]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub args: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
|
||||
pub enum Encoding {
|
||||
/// Currently only 'utf-16' is supported due to the limitations in LSP.
|
||||
#[serde(rename = "utf-16")]
|
||||
Utf16,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RangeBasedDocumentSymbol {
|
||||
pub id: Id,
|
||||
#[serde(default = "Default::default")]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub children: Vec<RangeBasedDocumentSymbol>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum DocumentSymbolOrRangeBasedVec {
|
||||
DocumentSymbol(Vec<crate::DocumentSymbol>),
|
||||
RangeBased(Vec<RangeBasedDocumentSymbol>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DefinitionTag {
|
||||
/// The text covered by the range
|
||||
text: String,
|
||||
/// The symbol kind.
|
||||
kind: crate::SymbolKind,
|
||||
/// Indicates if this symbol is deprecated.
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "std::ops::Not::not")]
|
||||
deprecated: bool,
|
||||
/// The full range of the definition not including leading/trailing whitespace but everything else, e.g comments and code.
|
||||
/// The range must be included in fullRange.
|
||||
full_range: Range,
|
||||
/// Optional detail information for the definition.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
detail: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeclarationTag {
|
||||
/// The text covered by the range
|
||||
text: String,
|
||||
/// The symbol kind.
|
||||
kind: crate::SymbolKind,
|
||||
/// Indicates if this symbol is deprecated.
|
||||
#[serde(default)]
|
||||
deprecated: bool,
|
||||
/// The full range of the definition not including leading/trailing whitespace but everything else, e.g comments and code.
|
||||
/// The range must be included in fullRange.
|
||||
full_range: Range,
|
||||
/// Optional detail information for the definition.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
detail: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReferenceTag {
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UnknownTag {
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "type")]
|
||||
pub enum RangeTag {
|
||||
Definition(DefinitionTag),
|
||||
Declaration(DeclarationTag),
|
||||
Reference(ReferenceTag),
|
||||
Unknown(UnknownTag),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "label")]
|
||||
pub enum Vertex {
|
||||
MetaData(MetaData),
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#the-project-vertex>
|
||||
Project(Project),
|
||||
Document(Document),
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#ranges>
|
||||
Range {
|
||||
#[serde(flatten)]
|
||||
range: Range,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
tag: Option<RangeTag>,
|
||||
},
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#result-set>
|
||||
ResultSet(ResultSet),
|
||||
Moniker(crate::Moniker),
|
||||
PackageInformation(PackageInformation),
|
||||
|
||||
#[serde(rename = "$event")]
|
||||
Event(Event),
|
||||
|
||||
DefinitionResult,
|
||||
DeclarationResult,
|
||||
TypeDefinitionResult,
|
||||
ReferenceResult,
|
||||
ImplementationResult,
|
||||
FoldingRangeResult {
|
||||
result: Vec<crate::FoldingRange>,
|
||||
},
|
||||
HoverResult {
|
||||
result: crate::Hover,
|
||||
},
|
||||
DocumentSymbolResult {
|
||||
result: DocumentSymbolOrRangeBasedVec,
|
||||
},
|
||||
DocumentLinkResult {
|
||||
result: Vec<crate::DocumentLink>,
|
||||
},
|
||||
DiagnosticResult {
|
||||
result: Vec<crate::Diagnostic>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EventKind {
|
||||
Begin,
|
||||
End,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EventScope {
|
||||
Document,
|
||||
Project,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Event {
|
||||
pub kind: EventKind,
|
||||
pub scope: EventScope,
|
||||
pub data: Id,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "label")]
|
||||
pub enum Edge {
|
||||
Contains(EdgeDataMultiIn),
|
||||
Moniker(EdgeData),
|
||||
NextMoniker(EdgeData),
|
||||
Next(EdgeData),
|
||||
PackageInformation(EdgeData),
|
||||
Item(Item),
|
||||
|
||||
// Methods
|
||||
#[serde(rename = "textDocument/definition")]
|
||||
Definition(EdgeData),
|
||||
#[serde(rename = "textDocument/declaration")]
|
||||
Declaration(EdgeData),
|
||||
#[serde(rename = "textDocument/hover")]
|
||||
Hover(EdgeData),
|
||||
#[serde(rename = "textDocument/references")]
|
||||
References(EdgeData),
|
||||
#[serde(rename = "textDocument/implementation")]
|
||||
Implementation(EdgeData),
|
||||
#[serde(rename = "textDocument/typeDefinition")]
|
||||
TypeDefinition(EdgeData),
|
||||
#[serde(rename = "textDocument/foldingRange")]
|
||||
FoldingRange(EdgeData),
|
||||
#[serde(rename = "textDocument/documentLink")]
|
||||
DocumentLink(EdgeData),
|
||||
#[serde(rename = "textDocument/documentSymbol")]
|
||||
DocumentSymbol(EdgeData),
|
||||
#[serde(rename = "textDocument/diagnostic")]
|
||||
Diagnostic(EdgeData),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EdgeData {
|
||||
pub in_v: Id,
|
||||
pub out_v: Id,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EdgeDataMultiIn {
|
||||
pub in_vs: Vec<Id>,
|
||||
pub out_v: Id,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DefinitionResultType {
|
||||
Scalar(LocationOrRangeId),
|
||||
Array(LocationOrRangeId),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ItemKind {
|
||||
Declarations,
|
||||
Definitions,
|
||||
References,
|
||||
ReferenceResults,
|
||||
ImplementationResults,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Item {
|
||||
pub document: Id,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub property: Option<ItemKind>,
|
||||
#[serde(flatten)]
|
||||
pub edge_data: EdgeDataMultiIn,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Document {
|
||||
pub uri: Url,
|
||||
pub language_id: String,
|
||||
}
|
||||
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#result-set>
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ResultSet {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub key: Option<String>,
|
||||
}
|
||||
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#the-project-vertex>
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Project {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resource: Option<Url>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content: Option<String>,
|
||||
pub kind: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MetaData {
|
||||
/// The version of the LSIF format using semver notation. See <https://semver.org/>. Please note
|
||||
/// the version numbers starting with 0 don't adhere to semver and adopters have to assume
|
||||
/// that each new version is breaking.
|
||||
pub version: String,
|
||||
|
||||
/// The project root (in form of an URI) used to compute this dump.
|
||||
pub project_root: Url,
|
||||
|
||||
/// The string encoding used to compute line and character values in
|
||||
/// positions and ranges.
|
||||
pub position_encoding: Encoding,
|
||||
|
||||
/// Information about the tool that created the dump
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tool_info: Option<ToolInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Repository {
|
||||
pub r#type: String,
|
||||
pub url: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub commit_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PackageInformation {
|
||||
pub name: String,
|
||||
pub manager: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub uri: Option<Url>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub repository: Option<Repository>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub version: Option<String>,
|
||||
}
|
92
helix-lsp-types/src/moniker.rs
Normal file
92
helix-lsp-types/src/moniker.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, PartialResultParams, TextDocumentPositionParams,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type MonikerClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum MonikerServerCapabilities {
|
||||
Options(MonikerOptions),
|
||||
RegistrationOptions(MonikerRegistrationOptions),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct MonikerOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MonikerRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub moniker_options: MonikerOptions,
|
||||
}
|
||||
|
||||
/// Moniker uniqueness level to define scope of the moniker.
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum UniquenessLevel {
|
||||
/// The moniker is only unique inside a document
|
||||
Document,
|
||||
/// The moniker is unique inside a project for which a dump got created
|
||||
Project,
|
||||
/// The moniker is unique inside the group to which a project belongs
|
||||
Group,
|
||||
/// The moniker is unique inside the moniker scheme.
|
||||
Scheme,
|
||||
/// The moniker is globally unique
|
||||
Global,
|
||||
}
|
||||
|
||||
/// The moniker kind.
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum MonikerKind {
|
||||
/// The moniker represent a symbol that is imported into a project
|
||||
Import,
|
||||
/// The moniker represent a symbol that is exported into a project
|
||||
Export,
|
||||
/// The moniker represents a symbol that is local to a project (e.g. a local
|
||||
/// variable of a function, a class not visible outside the project, ...)
|
||||
Local,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MonikerParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Moniker definition to match LSIF 0.5 moniker definition.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Moniker {
|
||||
/// The scheme of the moniker. For example tsc or .Net
|
||||
pub scheme: String,
|
||||
|
||||
/// The identifier of the moniker. The value is opaque in LSIF however
|
||||
/// schema owners are allowed to define the structure if they want.
|
||||
pub identifier: String,
|
||||
|
||||
/// The scope in which the moniker is unique
|
||||
pub unique: UniquenessLevel,
|
||||
|
||||
/// The moniker kind if known.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<MonikerKind>,
|
||||
}
|
361
helix-lsp-types/src/notification.rs
Normal file
361
helix-lsp-types/src/notification.rs
Normal file
@ -0,0 +1,361 @@
|
||||
use super::*;
|
||||
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
pub trait Notification {
|
||||
type Params: DeserializeOwned + Serialize + Send + Sync + 'static;
|
||||
const METHOD: &'static str;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! lsp_notification {
|
||||
("$/cancelRequest") => {
|
||||
$crate::notification::Cancel
|
||||
};
|
||||
("$/setTrace") => {
|
||||
$crate::notification::SetTrace
|
||||
};
|
||||
("$/logTrace") => {
|
||||
$crate::notification::LogTrace
|
||||
};
|
||||
("initialized") => {
|
||||
$crate::notification::Initialized
|
||||
};
|
||||
("exit") => {
|
||||
$crate::notification::Exit
|
||||
};
|
||||
|
||||
("window/showMessage") => {
|
||||
$crate::notification::ShowMessage
|
||||
};
|
||||
("window/logMessage") => {
|
||||
$crate::notification::LogMessage
|
||||
};
|
||||
("window/workDoneProgress/cancel") => {
|
||||
$crate::notification::WorkDoneProgressCancel
|
||||
};
|
||||
|
||||
("telemetry/event") => {
|
||||
$crate::notification::TelemetryEvent
|
||||
};
|
||||
|
||||
("textDocument/didOpen") => {
|
||||
$crate::notification::DidOpenTextDocument
|
||||
};
|
||||
("textDocument/didChange") => {
|
||||
$crate::notification::DidChangeTextDocument
|
||||
};
|
||||
("textDocument/willSave") => {
|
||||
$crate::notification::WillSaveTextDocument
|
||||
};
|
||||
("textDocument/didSave") => {
|
||||
$crate::notification::DidSaveTextDocument
|
||||
};
|
||||
("textDocument/didClose") => {
|
||||
$crate::notification::DidCloseTextDocument
|
||||
};
|
||||
("textDocument/publishDiagnostics") => {
|
||||
$crate::notification::PublishDiagnostics
|
||||
};
|
||||
|
||||
("workspace/didChangeConfiguration") => {
|
||||
$crate::notification::DidChangeConfiguration
|
||||
};
|
||||
("workspace/didChangeWatchedFiles") => {
|
||||
$crate::notification::DidChangeWatchedFiles
|
||||
};
|
||||
("workspace/didChangeWorkspaceFolders") => {
|
||||
$crate::notification::DidChangeWorkspaceFolders
|
||||
};
|
||||
("$/progress") => {
|
||||
$crate::notification::Progress
|
||||
};
|
||||
("workspace/didCreateFiles") => {
|
||||
$crate::notification::DidCreateFiles
|
||||
};
|
||||
("workspace/didRenameFiles") => {
|
||||
$crate::notification::DidRenameFiles
|
||||
};
|
||||
("workspace/didDeleteFiles") => {
|
||||
$crate::notification::DidDeleteFiles
|
||||
};
|
||||
}
|
||||
|
||||
/// The base protocol now offers support for request cancellation. To cancel a request,
|
||||
/// a notification message with the following properties is sent:
|
||||
///
|
||||
/// A request that got canceled still needs to return from the server and send a response back.
|
||||
/// It can not be left open / hanging. This is in line with the JSON RPC protocol that requires
|
||||
/// that every request sends a response back. In addition it allows for returning partial results on cancel.
|
||||
#[derive(Debug)]
|
||||
pub enum Cancel {}
|
||||
|
||||
impl Notification for Cancel {
|
||||
type Params = CancelParams;
|
||||
const METHOD: &'static str = "$/cancelRequest";
|
||||
}
|
||||
|
||||
/// A notification that should be used by the client to modify the trace
|
||||
/// setting of the server.
|
||||
#[derive(Debug)]
|
||||
pub enum SetTrace {}
|
||||
|
||||
impl Notification for SetTrace {
|
||||
type Params = SetTraceParams;
|
||||
const METHOD: &'static str = "$/setTrace";
|
||||
}
|
||||
|
||||
/// A notification to log the trace of the server’s execution.
|
||||
/// The amount and content of these notifications depends on the current trace configuration.
|
||||
///
|
||||
/// `LogTrace` should be used for systematic trace reporting. For single debugging messages,
|
||||
/// the server should send `LogMessage` notifications.
|
||||
#[derive(Debug)]
|
||||
pub enum LogTrace {}
|
||||
|
||||
impl Notification for LogTrace {
|
||||
type Params = LogTraceParams;
|
||||
const METHOD: &'static str = "$/logTrace";
|
||||
}
|
||||
|
||||
/// The initialized notification is sent from the client to the server after the client received
|
||||
/// the result of the initialize request but before the client is sending any other request or
|
||||
/// notification to the server. The server can use the initialized notification for example to
|
||||
/// dynamically register capabilities.
|
||||
#[derive(Debug)]
|
||||
pub enum Initialized {}
|
||||
|
||||
impl Notification for Initialized {
|
||||
type Params = InitializedParams;
|
||||
const METHOD: &'static str = "initialized";
|
||||
}
|
||||
|
||||
/// A notification to ask the server to exit its process.
|
||||
/// The server should exit with success code 0 if the shutdown request has been received before;
|
||||
/// otherwise with error code 1.
|
||||
#[derive(Debug)]
|
||||
pub enum Exit {}
|
||||
|
||||
impl Notification for Exit {
|
||||
type Params = ();
|
||||
const METHOD: &'static str = "exit";
|
||||
}
|
||||
|
||||
/// The show message notification is sent from a server to a client to ask the client to display a particular message
|
||||
/// in the user interface.
|
||||
#[derive(Debug)]
|
||||
pub enum ShowMessage {}
|
||||
|
||||
impl Notification for ShowMessage {
|
||||
type Params = ShowMessageParams;
|
||||
const METHOD: &'static str = "window/showMessage";
|
||||
}
|
||||
|
||||
/// The log message notification is sent from the server to the client to ask the client to log a particular message.
|
||||
#[derive(Debug)]
|
||||
pub enum LogMessage {}
|
||||
|
||||
impl Notification for LogMessage {
|
||||
type Params = LogMessageParams;
|
||||
const METHOD: &'static str = "window/logMessage";
|
||||
}
|
||||
|
||||
/// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event.
|
||||
/// The protocol doesn't specify the payload since no interpretation of the data happens in the protocol. Most clients even don't handle
|
||||
/// the event directly but forward them to the extensions owning the corresponding server issuing the event.
|
||||
#[derive(Debug)]
|
||||
pub enum TelemetryEvent {}
|
||||
|
||||
impl Notification for TelemetryEvent {
|
||||
type Params = OneOf<LSPObject, LSPArray>;
|
||||
const METHOD: &'static str = "telemetry/event";
|
||||
}
|
||||
|
||||
/// A notification sent from the client to the server to signal the change of configuration settings.
|
||||
#[derive(Debug)]
|
||||
pub enum DidChangeConfiguration {}
|
||||
|
||||
impl Notification for DidChangeConfiguration {
|
||||
type Params = DidChangeConfigurationParams;
|
||||
const METHOD: &'static str = "workspace/didChangeConfiguration";
|
||||
}
|
||||
|
||||
/// The document open notification is sent from the client to the server to signal newly opened text documents.
|
||||
/// The document's truth is now managed by the client and the server must not try to read the document's truth
|
||||
/// using the document's uri.
|
||||
#[derive(Debug)]
|
||||
pub enum DidOpenTextDocument {}
|
||||
|
||||
impl Notification for DidOpenTextDocument {
|
||||
type Params = DidOpenTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/didOpen";
|
||||
}
|
||||
|
||||
/// The document change notification is sent from the client to the server to signal changes to a text document.
|
||||
/// In 2.0 the shape of the params has changed to include proper version numbers and language ids.
|
||||
#[derive(Debug)]
|
||||
pub enum DidChangeTextDocument {}
|
||||
|
||||
impl Notification for DidChangeTextDocument {
|
||||
type Params = DidChangeTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/didChange";
|
||||
}
|
||||
|
||||
/// The document will save notification is sent from the client to the server before the document
|
||||
/// is actually saved.
|
||||
#[derive(Debug)]
|
||||
pub enum WillSaveTextDocument {}
|
||||
|
||||
impl Notification for WillSaveTextDocument {
|
||||
type Params = WillSaveTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/willSave";
|
||||
}
|
||||
|
||||
/// The document close notification is sent from the client to the server when the document got closed in the client.
|
||||
/// The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri
|
||||
/// the truth now exists on disk).
|
||||
#[derive(Debug)]
|
||||
pub enum DidCloseTextDocument {}
|
||||
|
||||
impl Notification for DidCloseTextDocument {
|
||||
type Params = DidCloseTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/didClose";
|
||||
}
|
||||
|
||||
/// The document save notification is sent from the client to the server when the document was saved in the client.
|
||||
#[derive(Debug)]
|
||||
pub enum DidSaveTextDocument {}
|
||||
|
||||
impl Notification for DidSaveTextDocument {
|
||||
type Params = DidSaveTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/didSave";
|
||||
}
|
||||
|
||||
/// The watched files notification is sent from the client to the server when the client detects changes to files and folders
|
||||
/// watched by the language client (note although the name suggest that only file events are sent it is about file system events which include folders as well).
|
||||
/// It is recommended that servers register for these file system events using the registration mechanism.
|
||||
/// In former implementations clients pushed file events without the server actively asking for it.
|
||||
#[derive(Debug)]
|
||||
pub enum DidChangeWatchedFiles {}
|
||||
|
||||
impl Notification for DidChangeWatchedFiles {
|
||||
type Params = DidChangeWatchedFilesParams;
|
||||
const METHOD: &'static str = "workspace/didChangeWatchedFiles";
|
||||
}
|
||||
|
||||
/// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server to inform the server
|
||||
/// about workspace folder configuration changes
|
||||
#[derive(Debug)]
|
||||
pub enum DidChangeWorkspaceFolders {}
|
||||
|
||||
impl Notification for DidChangeWorkspaceFolders {
|
||||
type Params = DidChangeWorkspaceFoldersParams;
|
||||
const METHOD: &'static str = "workspace/didChangeWorkspaceFolders";
|
||||
}
|
||||
|
||||
/// Diagnostics notification are sent from the server to the client to signal results of validation runs.
|
||||
#[derive(Debug)]
|
||||
pub enum PublishDiagnostics {}
|
||||
|
||||
impl Notification for PublishDiagnostics {
|
||||
type Params = PublishDiagnosticsParams;
|
||||
const METHOD: &'static str = "textDocument/publishDiagnostics";
|
||||
}
|
||||
|
||||
/// The progress notification is sent from the server to the client to ask
|
||||
/// the client to indicate progress.
|
||||
#[derive(Debug)]
|
||||
pub enum Progress {}
|
||||
|
||||
impl Notification for Progress {
|
||||
type Params = ProgressParams;
|
||||
const METHOD: &'static str = "$/progress";
|
||||
}
|
||||
|
||||
/// The `window/workDoneProgress/cancel` notification is sent from the client
|
||||
/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`.
|
||||
#[derive(Debug)]
|
||||
pub enum WorkDoneProgressCancel {}
|
||||
|
||||
impl Notification for WorkDoneProgressCancel {
|
||||
type Params = WorkDoneProgressCancelParams;
|
||||
const METHOD: &'static str = "window/workDoneProgress/cancel";
|
||||
}
|
||||
|
||||
/// The did create files notification is sent from the client to the server when files were created from within the client.
|
||||
#[derive(Debug)]
|
||||
pub enum DidCreateFiles {}
|
||||
|
||||
impl Notification for DidCreateFiles {
|
||||
type Params = CreateFilesParams;
|
||||
const METHOD: &'static str = "workspace/didCreateFiles";
|
||||
}
|
||||
|
||||
/// The did rename files notification is sent from the client to the server when files were renamed from within the client.
|
||||
#[derive(Debug)]
|
||||
pub enum DidRenameFiles {}
|
||||
|
||||
impl Notification for DidRenameFiles {
|
||||
type Params = RenameFilesParams;
|
||||
const METHOD: &'static str = "workspace/didRenameFiles";
|
||||
}
|
||||
|
||||
/// The did delete files notification is sent from the client to the server when files were deleted from within the client.
|
||||
#[derive(Debug)]
|
||||
pub enum DidDeleteFiles {}
|
||||
|
||||
impl Notification for DidDeleteFiles {
|
||||
type Params = DeleteFilesParams;
|
||||
const METHOD: &'static str = "workspace/didDeleteFiles";
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
fn fake_call<N>()
|
||||
where
|
||||
N: Notification,
|
||||
N::Params: serde::Serialize,
|
||||
{
|
||||
}
|
||||
|
||||
macro_rules! check_macro {
|
||||
($name:tt) => {
|
||||
// check whether the macro name matches the method
|
||||
assert_eq!(<lsp_notification!($name) as Notification>::METHOD, $name);
|
||||
// test whether type checking passes for each component
|
||||
fake_call::<lsp_notification!($name)>();
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_macro_definitions() {
|
||||
check_macro!("$/cancelRequest");
|
||||
check_macro!("$/progress");
|
||||
check_macro!("$/logTrace");
|
||||
check_macro!("$/setTrace");
|
||||
check_macro!("initialized");
|
||||
check_macro!("exit");
|
||||
check_macro!("window/showMessage");
|
||||
check_macro!("window/logMessage");
|
||||
check_macro!("window/workDoneProgress/cancel");
|
||||
check_macro!("telemetry/event");
|
||||
check_macro!("textDocument/didOpen");
|
||||
check_macro!("textDocument/didChange");
|
||||
check_macro!("textDocument/willSave");
|
||||
check_macro!("textDocument/didSave");
|
||||
check_macro!("textDocument/didClose");
|
||||
check_macro!("textDocument/publishDiagnostics");
|
||||
check_macro!("workspace/didChangeConfiguration");
|
||||
check_macro!("workspace/didChangeWatchedFiles");
|
||||
check_macro!("workspace/didChangeWorkspaceFolders");
|
||||
check_macro!("workspace/didCreateFiles");
|
||||
check_macro!("workspace/didRenameFiles");
|
||||
check_macro!("workspace/didDeleteFiles");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "proposed")]
|
||||
fn check_proposed_macro_definitions() {}
|
||||
}
|
134
helix-lsp-types/src/progress.rs
Normal file
134
helix-lsp-types/src/progress.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::NumberOrString;
|
||||
|
||||
pub type ProgressToken = NumberOrString;
|
||||
|
||||
/// The progress notification is sent from the server to the client to ask
|
||||
/// the client to indicate progress.
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProgressParams {
|
||||
/// The progress token provided by the client.
|
||||
pub token: ProgressToken,
|
||||
|
||||
/// The progress data.
|
||||
pub value: ProgressParamsValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum ProgressParamsValue {
|
||||
WorkDone(WorkDoneProgress),
|
||||
}
|
||||
|
||||
/// The `window/workDoneProgress/create` request is sent
|
||||
/// from the server to the client to ask the client to create a work done progress.
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressCreateParams {
|
||||
/// The token to be used to report progress.
|
||||
pub token: ProgressToken,
|
||||
}
|
||||
|
||||
/// The `window/workDoneProgress/cancel` notification is sent from the client
|
||||
/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`.
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressCancelParams {
|
||||
/// The token to be used to report progress.
|
||||
pub token: ProgressToken,
|
||||
}
|
||||
|
||||
/// Options to signal work done progress support in server capabilities.
|
||||
#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressOptions {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub work_done_progress: Option<bool>,
|
||||
}
|
||||
|
||||
/// An optional token that a server can use to report work done progress
|
||||
#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressParams {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub work_done_token: Option<ProgressToken>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressBegin {
|
||||
/// Mandatory title of the progress operation. Used to briefly inform
|
||||
/// about the kind of operation being performed.
|
||||
/// Examples: "Indexing" or "Linking dependencies".
|
||||
pub title: String,
|
||||
|
||||
/// Controls if a cancel button should show to allow the user to cancel the
|
||||
/// long running operation. Clients that don't support cancellation are allowed
|
||||
/// to ignore the setting.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cancellable: Option<bool>,
|
||||
|
||||
/// Optional, more detailed associated progress message. Contains
|
||||
/// complementary information to the `title`.
|
||||
///
|
||||
/// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
|
||||
/// If unset, the previous progress message (if any) is still valid.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
|
||||
/// Optional progress percentage to display (value 100 is considered 100%).
|
||||
/// If not provided infinite progress is assumed and clients are allowed
|
||||
/// to ignore the `percentage` value in subsequent in report notifications.
|
||||
///
|
||||
/// The value should be steadily rising. Clients are free to ignore values
|
||||
/// that are not following this rule. The value range is [0, 100]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub percentage: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressReport {
|
||||
/// Controls if a cancel button should show to allow the user to cancel the
|
||||
/// long running operation. Clients that don't support cancellation are allowed
|
||||
/// to ignore the setting.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cancellable: Option<bool>,
|
||||
|
||||
/// Optional, more detailed associated progress message. Contains
|
||||
/// complementary information to the `title`.
|
||||
/// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
|
||||
/// If unset, the previous progress message (if any) is still valid.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
|
||||
/// Optional progress percentage to display (value 100 is considered 100%).
|
||||
/// If not provided infinite progress is assumed and clients are allowed
|
||||
/// to ignore the `percentage` value in subsequent in report notifications.
|
||||
///
|
||||
/// The value should be steadily rising. Clients are free to ignore values
|
||||
/// that are not following this rule. The value range is [0, 100]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub percentage: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressEnd {
|
||||
/// Optional, more detailed associated progress message. Contains
|
||||
/// complementary information to the `title`.
|
||||
/// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
|
||||
/// If unset, the previous progress message (if any) is still valid.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum WorkDoneProgress {
|
||||
Begin(WorkDoneProgressBegin),
|
||||
Report(WorkDoneProgressReport),
|
||||
End(WorkDoneProgressEnd),
|
||||
}
|
30
helix-lsp-types/src/references.rs
Normal file
30
helix-lsp-types/src/references.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, PartialResultParams, TextDocumentPositionParams,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type ReferenceClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReferenceContext {
|
||||
/// Include the declaration of the current symbol.
|
||||
pub include_declaration: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReferenceParams {
|
||||
// Text Document and Position fields
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
// ReferenceParams properties:
|
||||
pub context: ReferenceContext,
|
||||
}
|
88
helix-lsp-types/src/rename.rs
Normal file
88
helix-lsp-types/src/rename.rs
Normal file
@ -0,0 +1,88 @@
|
||||
use crate::{Range, TextDocumentPositionParams, WorkDoneProgressOptions, WorkDoneProgressParams};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenameParams {
|
||||
/// Text Document and Position fields
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
/// The new name of the symbol. If the given name is not valid the
|
||||
/// request must return a [ResponseError](#ResponseError) with an
|
||||
/// appropriate message set.
|
||||
pub new_name: String,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenameOptions {
|
||||
/// Renames should be checked and tested before being executed.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prepare_provider: Option<bool>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenameClientCapabilities {
|
||||
/// Whether rename supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Client supports testing for validity of rename operations before execution.
|
||||
///
|
||||
/// @since 3.12.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prepare_support: Option<bool>,
|
||||
|
||||
/// Client supports the default behavior result.
|
||||
///
|
||||
/// The value indicates the default behavior used by the
|
||||
/// client.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prepare_support_default_behavior: Option<PrepareSupportDefaultBehavior>,
|
||||
|
||||
/// Whether the client honors the change annotations in
|
||||
/// text edits and resource operations returned via the
|
||||
/// rename request's workspace edit by for example presenting
|
||||
/// the workspace edit in the user interface and asking
|
||||
/// for confirmation.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub honors_change_annotations: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct PrepareSupportDefaultBehavior(i32);
|
||||
lsp_enum! {
|
||||
impl PrepareSupportDefaultBehavior {
|
||||
/// The client's default behavior is to select the identifier
|
||||
/// according the to language's syntax rule
|
||||
pub const IDENTIFIER: PrepareSupportDefaultBehavior = PrepareSupportDefaultBehavior(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum PrepareRenameResponse {
|
||||
Range(Range),
|
||||
RangeWithPlaceholder {
|
||||
range: Range,
|
||||
placeholder: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
DefaultBehavior {
|
||||
default_behavior: bool,
|
||||
},
|
||||
}
|
1068
helix-lsp-types/src/request.rs
Normal file
1068
helix-lsp-types/src/request.rs
Normal file
File diff suppressed because it is too large
Load Diff
86
helix-lsp-types/src/selection_range.rs
Normal file
86
helix-lsp-types/src/selection_range.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
PartialResultParams, Position, Range, StaticTextDocumentRegistrationOptions,
|
||||
TextDocumentIdentifier, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SelectionRangeClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration for selection range
|
||||
/// providers. If this is set to `true` the client supports the new
|
||||
/// `SelectionRangeRegistrationOptions` return value for the corresponding
|
||||
/// server capability as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct SelectionRangeOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct SelectionRangeRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub selection_range_options: SelectionRangeOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub registration_options: StaticTextDocumentRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum SelectionRangeProviderCapability {
|
||||
Simple(bool),
|
||||
Options(SelectionRangeOptions),
|
||||
RegistrationOptions(SelectionRangeRegistrationOptions),
|
||||
}
|
||||
|
||||
impl From<SelectionRangeRegistrationOptions> for SelectionRangeProviderCapability {
|
||||
fn from(from: SelectionRangeRegistrationOptions) -> Self {
|
||||
Self::RegistrationOptions(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SelectionRangeOptions> for SelectionRangeProviderCapability {
|
||||
fn from(from: SelectionRangeOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for SelectionRangeProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A parameter literal used in selection range requests.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SelectionRangeParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The positions inside the text document.
|
||||
pub positions: Vec<Position>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Represents a selection range.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SelectionRange {
|
||||
/// Range of the selection.
|
||||
pub range: Range,
|
||||
|
||||
/// The parent selection range containing this range.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parent: Option<Box<SelectionRange>>,
|
||||
}
|
734
helix-lsp-types/src/semantic_tokens.rs
Normal file
734
helix-lsp-types/src/semantic_tokens.rs
Normal file
@ -0,0 +1,734 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
PartialResultParams, Range, StaticRegistrationOptions, TextDocumentIdentifier,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
/// A set of predefined token types. This set is not fixed
|
||||
/// and clients can specify additional token types via the
|
||||
/// corresponding client capabilities.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
pub struct SemanticTokenType(Cow<'static, str>);
|
||||
|
||||
impl SemanticTokenType {
|
||||
pub const NAMESPACE: SemanticTokenType = SemanticTokenType::new("namespace");
|
||||
pub const TYPE: SemanticTokenType = SemanticTokenType::new("type");
|
||||
pub const CLASS: SemanticTokenType = SemanticTokenType::new("class");
|
||||
pub const ENUM: SemanticTokenType = SemanticTokenType::new("enum");
|
||||
pub const INTERFACE: SemanticTokenType = SemanticTokenType::new("interface");
|
||||
pub const STRUCT: SemanticTokenType = SemanticTokenType::new("struct");
|
||||
pub const TYPE_PARAMETER: SemanticTokenType = SemanticTokenType::new("typeParameter");
|
||||
pub const PARAMETER: SemanticTokenType = SemanticTokenType::new("parameter");
|
||||
pub const VARIABLE: SemanticTokenType = SemanticTokenType::new("variable");
|
||||
pub const PROPERTY: SemanticTokenType = SemanticTokenType::new("property");
|
||||
pub const ENUM_MEMBER: SemanticTokenType = SemanticTokenType::new("enumMember");
|
||||
pub const EVENT: SemanticTokenType = SemanticTokenType::new("event");
|
||||
pub const FUNCTION: SemanticTokenType = SemanticTokenType::new("function");
|
||||
pub const METHOD: SemanticTokenType = SemanticTokenType::new("method");
|
||||
pub const MACRO: SemanticTokenType = SemanticTokenType::new("macro");
|
||||
pub const KEYWORD: SemanticTokenType = SemanticTokenType::new("keyword");
|
||||
pub const MODIFIER: SemanticTokenType = SemanticTokenType::new("modifier");
|
||||
pub const COMMENT: SemanticTokenType = SemanticTokenType::new("comment");
|
||||
pub const STRING: SemanticTokenType = SemanticTokenType::new("string");
|
||||
pub const NUMBER: SemanticTokenType = SemanticTokenType::new("number");
|
||||
pub const REGEXP: SemanticTokenType = SemanticTokenType::new("regexp");
|
||||
pub const OPERATOR: SemanticTokenType = SemanticTokenType::new("operator");
|
||||
|
||||
/// @since 3.17.0
|
||||
pub const DECORATOR: SemanticTokenType = SemanticTokenType::new("decorator");
|
||||
|
||||
pub const fn new(tag: &'static str) -> Self {
|
||||
SemanticTokenType(Cow::Borrowed(tag))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for SemanticTokenType {
|
||||
fn from(from: String) -> Self {
|
||||
SemanticTokenType(Cow::from(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for SemanticTokenType {
|
||||
fn from(from: &'static str) -> Self {
|
||||
SemanticTokenType::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of predefined token modifiers. This set is not fixed
|
||||
/// and clients can specify additional token types via the
|
||||
/// corresponding client capabilities.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
pub struct SemanticTokenModifier(Cow<'static, str>);
|
||||
|
||||
impl SemanticTokenModifier {
|
||||
pub const DECLARATION: SemanticTokenModifier = SemanticTokenModifier::new("declaration");
|
||||
pub const DEFINITION: SemanticTokenModifier = SemanticTokenModifier::new("definition");
|
||||
pub const READONLY: SemanticTokenModifier = SemanticTokenModifier::new("readonly");
|
||||
pub const STATIC: SemanticTokenModifier = SemanticTokenModifier::new("static");
|
||||
pub const DEPRECATED: SemanticTokenModifier = SemanticTokenModifier::new("deprecated");
|
||||
pub const ABSTRACT: SemanticTokenModifier = SemanticTokenModifier::new("abstract");
|
||||
pub const ASYNC: SemanticTokenModifier = SemanticTokenModifier::new("async");
|
||||
pub const MODIFICATION: SemanticTokenModifier = SemanticTokenModifier::new("modification");
|
||||
pub const DOCUMENTATION: SemanticTokenModifier = SemanticTokenModifier::new("documentation");
|
||||
pub const DEFAULT_LIBRARY: SemanticTokenModifier = SemanticTokenModifier::new("defaultLibrary");
|
||||
|
||||
pub const fn new(tag: &'static str) -> Self {
|
||||
SemanticTokenModifier(Cow::Borrowed(tag))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for SemanticTokenModifier {
|
||||
fn from(from: String) -> Self {
|
||||
SemanticTokenModifier(Cow::from(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for SemanticTokenModifier {
|
||||
fn from(from: &'static str) -> Self {
|
||||
SemanticTokenModifier::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
pub struct TokenFormat(Cow<'static, str>);
|
||||
|
||||
impl TokenFormat {
|
||||
pub const RELATIVE: TokenFormat = TokenFormat::new("relative");
|
||||
|
||||
pub const fn new(tag: &'static str) -> Self {
|
||||
TokenFormat(Cow::Borrowed(tag))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for TokenFormat {
|
||||
fn from(from: String) -> Self {
|
||||
TokenFormat(Cow::from(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for TokenFormat {
|
||||
fn from(from: &'static str) -> Self {
|
||||
TokenFormat::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensLegend {
|
||||
/// The token types a server uses.
|
||||
pub token_types: Vec<SemanticTokenType>,
|
||||
|
||||
/// The token modifiers a server uses.
|
||||
pub token_modifiers: Vec<SemanticTokenModifier>,
|
||||
}
|
||||
|
||||
/// The actual tokens.
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
|
||||
pub struct SemanticToken {
|
||||
pub delta_line: u32,
|
||||
pub delta_start: u32,
|
||||
pub length: u32,
|
||||
pub token_type: u32,
|
||||
pub token_modifiers_bitset: u32,
|
||||
}
|
||||
|
||||
impl SemanticToken {
|
||||
fn deserialize_tokens<'de, D>(deserializer: D) -> Result<Vec<SemanticToken>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let data = Vec::<u32>::deserialize(deserializer)?;
|
||||
let chunks = data.chunks_exact(5);
|
||||
|
||||
if !chunks.remainder().is_empty() {
|
||||
return Result::Err(serde::de::Error::custom("Length is not divisible by 5"));
|
||||
}
|
||||
|
||||
Result::Ok(
|
||||
chunks
|
||||
.map(|chunk| SemanticToken {
|
||||
delta_line: chunk[0],
|
||||
delta_start: chunk[1],
|
||||
length: chunk[2],
|
||||
token_type: chunk[3],
|
||||
token_modifiers_bitset: chunk[4],
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
fn serialize_tokens<S>(tokens: &[SemanticToken], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(tokens.len() * 5))?;
|
||||
for token in tokens.iter() {
|
||||
seq.serialize_element(&token.delta_line)?;
|
||||
seq.serialize_element(&token.delta_start)?;
|
||||
seq.serialize_element(&token.length)?;
|
||||
seq.serialize_element(&token.token_type)?;
|
||||
seq.serialize_element(&token.token_modifiers_bitset)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
|
||||
fn deserialize_tokens_opt<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Vec<SemanticToken>>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct Wrapper {
|
||||
#[serde(deserialize_with = "SemanticToken::deserialize_tokens")]
|
||||
tokens: Vec<SemanticToken>,
|
||||
}
|
||||
|
||||
Ok(Option::<Wrapper>::deserialize(deserializer)?.map(|wrapper| wrapper.tokens))
|
||||
}
|
||||
|
||||
fn serialize_tokens_opt<S>(
|
||||
data: &Option<Vec<SemanticToken>>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
#[derive(Serialize)]
|
||||
#[serde(transparent)]
|
||||
struct Wrapper {
|
||||
#[serde(serialize_with = "SemanticToken::serialize_tokens")]
|
||||
tokens: Vec<SemanticToken>,
|
||||
}
|
||||
|
||||
let opt = data.as_ref().map(|t| Wrapper { tokens: t.to_vec() });
|
||||
|
||||
opt.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokens {
|
||||
/// An optional result id. If provided and clients support delta updating
|
||||
/// the client will include the result id in the next semantic token request.
|
||||
/// A server can then instead of computing all semantic tokens again simply
|
||||
/// send a delta.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub result_id: Option<String>,
|
||||
|
||||
/// The actual tokens. For a detailed description about how the data is
|
||||
/// structured please see
|
||||
/// <https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71>
|
||||
#[serde(
|
||||
deserialize_with = "SemanticToken::deserialize_tokens",
|
||||
serialize_with = "SemanticToken::serialize_tokens"
|
||||
)]
|
||||
pub data: Vec<SemanticToken>,
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensPartialResult {
|
||||
#[serde(
|
||||
deserialize_with = "SemanticToken::deserialize_tokens",
|
||||
serialize_with = "SemanticToken::serialize_tokens"
|
||||
)]
|
||||
pub data: Vec<SemanticToken>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensResult {
|
||||
Tokens(SemanticTokens),
|
||||
Partial(SemanticTokensPartialResult),
|
||||
}
|
||||
|
||||
impl From<SemanticTokens> for SemanticTokensResult {
|
||||
fn from(from: SemanticTokens) -> Self {
|
||||
SemanticTokensResult::Tokens(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemanticTokensPartialResult> for SemanticTokensResult {
|
||||
fn from(from: SemanticTokensPartialResult) -> Self {
|
||||
SemanticTokensResult::Partial(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensEdit {
|
||||
pub start: u32,
|
||||
pub delete_count: u32,
|
||||
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "SemanticToken::deserialize_tokens_opt",
|
||||
serialize_with = "SemanticToken::serialize_tokens_opt"
|
||||
)]
|
||||
pub data: Option<Vec<SemanticToken>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensFullDeltaResult {
|
||||
Tokens(SemanticTokens),
|
||||
TokensDelta(SemanticTokensDelta),
|
||||
PartialTokensDelta { edits: Vec<SemanticTokensEdit> },
|
||||
}
|
||||
|
||||
impl From<SemanticTokens> for SemanticTokensFullDeltaResult {
|
||||
fn from(from: SemanticTokens) -> Self {
|
||||
SemanticTokensFullDeltaResult::Tokens(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemanticTokensDelta> for SemanticTokensFullDeltaResult {
|
||||
fn from(from: SemanticTokensDelta) -> Self {
|
||||
SemanticTokensFullDeltaResult::TokensDelta(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensDelta {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub result_id: Option<String>,
|
||||
/// For a detailed description how these edits are structured please see
|
||||
/// <https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L131>
|
||||
pub edits: Vec<SemanticTokensEdit>,
|
||||
}
|
||||
|
||||
/// Capabilities specific to the `textDocument/semanticTokens/*` requests.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration. If this is set to `true`
|
||||
/// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||
/// return value for the corresponding server capability as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Which requests the client supports and might send to the server
|
||||
/// depending on the server's capability. Please note that clients might not
|
||||
/// show semantic tokens or degrade some of the user experience if a range
|
||||
/// or full request is advertised by the client but not provided by the
|
||||
/// server. If for example the client capability `requests.full` and
|
||||
/// `request.range` are both set to true but the server only provides a
|
||||
/// range provider the client might not render a minimap correctly or might
|
||||
/// even decide to not show any semantic tokens at all.
|
||||
pub requests: SemanticTokensClientCapabilitiesRequests,
|
||||
|
||||
/// The token types that the client supports.
|
||||
pub token_types: Vec<SemanticTokenType>,
|
||||
|
||||
/// The token modifiers that the client supports.
|
||||
pub token_modifiers: Vec<SemanticTokenModifier>,
|
||||
|
||||
/// The token formats the clients supports.
|
||||
pub formats: Vec<TokenFormat>,
|
||||
|
||||
/// Whether the client supports tokens that can overlap each other.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub overlapping_token_support: Option<bool>,
|
||||
|
||||
/// Whether the client supports tokens that can span multiple lines.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub multiline_token_support: Option<bool>,
|
||||
|
||||
/// Whether the client allows the server to actively cancel a
|
||||
/// semantic token request, e.g. supports returning
|
||||
/// ErrorCodes.ServerCancelled. If a server does the client
|
||||
/// needs to retrigger the request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub server_cancel_support: Option<bool>,
|
||||
|
||||
/// Whether the client uses semantic tokens to augment existing
|
||||
/// syntax tokens. If set to `true` client side created syntax
|
||||
/// tokens and semantic tokens are both used for colorization. If
|
||||
/// set to `false` the client only uses the returned semantic tokens
|
||||
/// for colorization.
|
||||
///
|
||||
/// If the value is `undefined` then the client behavior is not
|
||||
/// specified.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub augments_syntax_tokens: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensClientCapabilitiesRequests {
|
||||
/// The client will send the `textDocument/semanticTokens/range` request if the server provides a corresponding handler.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range: Option<bool>,
|
||||
|
||||
/// The client will send the `textDocument/semanticTokens/full` request if the server provides a corresponding handler.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub full: Option<SemanticTokensFullOptions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensFullOptions {
|
||||
Bool(bool),
|
||||
Delta {
|
||||
/// The client will send the `textDocument/semanticTokens/full/delta` request if the server provides a corresponding handler.
|
||||
/// The server supports deltas for full documents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
delta: Option<bool>,
|
||||
},
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
|
||||
/// The legend used by the server
|
||||
pub legend: SemanticTokensLegend,
|
||||
|
||||
/// Server supports providing semantic tokens for a specific range
|
||||
/// of a document.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range: Option<bool>,
|
||||
|
||||
/// Server supports providing semantic tokens for a full document.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub full: Option<SemanticTokensFullOptions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub semantic_tokens_options: SemanticTokensOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensServerCapabilities {
|
||||
SemanticTokensOptions(SemanticTokensOptions),
|
||||
SemanticTokensRegistrationOptions(SemanticTokensRegistrationOptions),
|
||||
}
|
||||
|
||||
impl From<SemanticTokensOptions> for SemanticTokensServerCapabilities {
|
||||
fn from(from: SemanticTokensOptions) -> Self {
|
||||
SemanticTokensServerCapabilities::SemanticTokensOptions(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemanticTokensRegistrationOptions> for SemanticTokensServerCapabilities {
|
||||
fn from(from: SemanticTokensRegistrationOptions) -> Self {
|
||||
SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from
|
||||
/// the server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// semantic tokens currently shown. It should be used with absolute care
|
||||
/// and is useful for situation where a server for example detect a project
|
||||
/// wide change that requires such a calculation.
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensDeltaParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The result id of a previous response. The result Id can either point to a full response
|
||||
/// or a delta response depending on what was received last.
|
||||
pub previous_result_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensRangeParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The range the semantic tokens are requested for.
|
||||
pub range: Range,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensRangeResult {
|
||||
Tokens(SemanticTokens),
|
||||
Partial(SemanticTokensPartialResult),
|
||||
}
|
||||
|
||||
impl From<SemanticTokens> for SemanticTokensRangeResult {
|
||||
fn from(tokens: SemanticTokens) -> Self {
|
||||
SemanticTokensRangeResult::Tokens(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemanticTokensPartialResult> for SemanticTokensRangeResult {
|
||||
fn from(partial: SemanticTokensPartialResult) -> Self {
|
||||
SemanticTokensRangeResult::Partial(partial)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::{test_deserialization, test_serialization};
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_support_serialization() {
|
||||
test_serialization(
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![],
|
||||
},
|
||||
r#"{"data":[]}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
}],
|
||||
},
|
||||
r#"{"data":[2,5,3,0,3]}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![
|
||||
SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
},
|
||||
SemanticToken {
|
||||
delta_line: 0,
|
||||
delta_start: 5,
|
||||
length: 4,
|
||||
token_type: 1,
|
||||
token_modifiers_bitset: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_support_deserialization() {
|
||||
test_deserialization(
|
||||
r#"{"data":[]}"#,
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![],
|
||||
},
|
||||
);
|
||||
|
||||
test_deserialization(
|
||||
r#"{"data":[2,5,3,0,3]}"#,
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
}],
|
||||
},
|
||||
);
|
||||
|
||||
test_deserialization(
|
||||
r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#,
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![
|
||||
SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
},
|
||||
SemanticToken {
|
||||
delta_line: 0,
|
||||
delta_start: 5,
|
||||
length: 4,
|
||||
token_type: 1,
|
||||
token_modifiers_bitset: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_semantic_tokens_support_deserialization_err() {
|
||||
test_deserialization(
|
||||
r#"{"data":[1]}"#,
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_edit_support_deserialization() {
|
||||
test_deserialization(
|
||||
r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#,
|
||||
&SemanticTokensEdit {
|
||||
start: 0,
|
||||
delete_count: 1,
|
||||
data: Some(vec![
|
||||
SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
},
|
||||
SemanticToken {
|
||||
delta_line: 0,
|
||||
delta_start: 5,
|
||||
length: 4,
|
||||
token_type: 1,
|
||||
token_modifiers_bitset: 0,
|
||||
},
|
||||
]),
|
||||
},
|
||||
);
|
||||
|
||||
test_deserialization(
|
||||
r#"{"start":0,"deleteCount":1}"#,
|
||||
&SemanticTokensEdit {
|
||||
start: 0,
|
||||
delete_count: 1,
|
||||
data: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_edit_support_serialization() {
|
||||
test_serialization(
|
||||
&SemanticTokensEdit {
|
||||
start: 0,
|
||||
delete_count: 1,
|
||||
data: Some(vec![
|
||||
SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
},
|
||||
SemanticToken {
|
||||
delta_line: 0,
|
||||
delta_start: 5,
|
||||
length: 4,
|
||||
token_type: 1,
|
||||
token_modifiers_bitset: 0,
|
||||
},
|
||||
]),
|
||||
},
|
||||
r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&SemanticTokensEdit {
|
||||
start: 0,
|
||||
delete_count: 1,
|
||||
data: None,
|
||||
},
|
||||
r#"{"start":0,"deleteCount":1}"#,
|
||||
);
|
||||
}
|
||||
}
|
207
helix-lsp-types/src/signature_help.rs
Normal file
207
helix-lsp-types/src/signature_help.rs
Normal file
@ -0,0 +1,207 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
Documentation, MarkupKind, TextDocumentPositionParams, TextDocumentRegistrationOptions,
|
||||
WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureInformationSettings {
|
||||
/// Client supports the follow content formats for the documentation
|
||||
/// property. The order describes the preferred format of the client.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation_format: Option<Vec<MarkupKind>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parameter_information: Option<ParameterInformationSettings>,
|
||||
|
||||
/// The client support the `activeParameter` property on `SignatureInformation`
|
||||
/// literal.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_parameter_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParameterInformationSettings {
|
||||
/// The client supports processing label offsets instead of a
|
||||
/// simple label string.
|
||||
///
|
||||
/// @since 3.14.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub label_offset_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelpClientCapabilities {
|
||||
/// Whether completion supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The client supports the following `SignatureInformation`
|
||||
/// specific properties.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub signature_information: Option<SignatureInformationSettings>,
|
||||
|
||||
/// The client supports to send additional context information for a
|
||||
/// `textDocument/signatureHelp` request. A client that opts into
|
||||
/// contextSupport will also support the `retriggerCharacters` on
|
||||
/// `SignatureHelpOptions`.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context_support: Option<bool>,
|
||||
}
|
||||
|
||||
/// Signature help options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelpOptions {
|
||||
/// The characters that trigger signature help automatically.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_characters: Option<Vec<String>>,
|
||||
|
||||
/// List of characters that re-trigger signature help.
|
||||
/// These trigger characters are only active when signature help is already showing. All trigger characters
|
||||
/// are also counted as re-trigger characters.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub retrigger_characters: Option<Vec<String>>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
/// Signature help options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct SignatureHelpRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
}
|
||||
|
||||
/// Signature help options.
|
||||
#[derive(Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct SignatureHelpTriggerKind(i32);
|
||||
lsp_enum! {
|
||||
impl SignatureHelpTriggerKind {
|
||||
/// Signature help was invoked manually by the user or by a command.
|
||||
pub const INVOKED: SignatureHelpTriggerKind = SignatureHelpTriggerKind(1);
|
||||
/// Signature help was triggered by a trigger character.
|
||||
pub const TRIGGER_CHARACTER: SignatureHelpTriggerKind = SignatureHelpTriggerKind(2);
|
||||
/// Signature help was triggered by the cursor moving or by the document content changing.
|
||||
pub const CONTENT_CHANGE: SignatureHelpTriggerKind = SignatureHelpTriggerKind(3);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelpParams {
|
||||
/// The signature help context. This is only available if the client specifies
|
||||
/// to send this using the client capability `textDocument.signatureHelp.contextSupport === true`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context: Option<SignatureHelpContext>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelpContext {
|
||||
/// Action that caused signature help to be triggered.
|
||||
pub trigger_kind: SignatureHelpTriggerKind,
|
||||
|
||||
/// Character that caused signature help to be triggered.
|
||||
/// This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_character: Option<String>,
|
||||
|
||||
/// `true` if signature help was already showing when it was triggered.
|
||||
/// Retriggers occur when the signature help is already active and can be caused by actions such as
|
||||
/// typing a trigger character, a cursor move, or document content changes.
|
||||
pub is_retrigger: bool,
|
||||
|
||||
/// The currently active `SignatureHelp`.
|
||||
/// The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on
|
||||
/// the user navigating through available signatures.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_signature_help: Option<SignatureHelp>,
|
||||
}
|
||||
|
||||
/// Signature help represents the signature of something
|
||||
/// callable. There can be multiple signature but only one
|
||||
/// active and only one active parameter.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelp {
|
||||
/// One or more signatures.
|
||||
pub signatures: Vec<SignatureInformation>,
|
||||
|
||||
/// The active signature.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_signature: Option<u32>,
|
||||
|
||||
/// The active parameter of the active signature.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_parameter: Option<u32>,
|
||||
}
|
||||
|
||||
/// Represents the signature of something callable. A signature
|
||||
/// can have a label, like a function-name, a doc-comment, and
|
||||
/// a set of parameters.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureInformation {
|
||||
/// The label of this signature. Will be shown in
|
||||
/// the UI.
|
||||
pub label: String,
|
||||
|
||||
/// The human-readable doc-comment of this signature. Will be shown
|
||||
/// in the UI but can be omitted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation: Option<Documentation>,
|
||||
|
||||
/// The parameters of this signature.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parameters: Option<Vec<ParameterInformation>>,
|
||||
|
||||
/// The index of the active parameter.
|
||||
///
|
||||
/// If provided, this is used in place of `SignatureHelp.activeParameter`.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_parameter: Option<u32>,
|
||||
}
|
||||
|
||||
/// Represents a parameter of a callable-signature. A parameter can
|
||||
/// have a label and a doc-comment.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParameterInformation {
|
||||
/// The label of this parameter information.
|
||||
///
|
||||
/// Either a string or an inclusive start and exclusive end offsets within its containing
|
||||
/// signature label. (see SignatureInformation.label). *Note*: A label of type string must be
|
||||
/// a substring of its containing signature label.
|
||||
pub label: ParameterLabel,
|
||||
|
||||
/// The human-readable doc-comment of this parameter. Will be shown
|
||||
/// in the UI but can be omitted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation: Option<Documentation>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ParameterLabel {
|
||||
Simple(String),
|
||||
LabelOffsets([u32; 2]),
|
||||
}
|
77
helix-lsp-types/src/trace.rs
Normal file
77
helix-lsp-types/src/trace.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct SetTraceParams {
|
||||
/// The new value that should be assigned to the trace setting.
|
||||
pub value: TraceValue,
|
||||
}
|
||||
|
||||
/// A TraceValue represents the level of verbosity with which the server systematically
|
||||
/// reports its execution trace using `LogTrace` notifications.
|
||||
///
|
||||
/// The initial trace value is set by the client at initialization and can be modified
|
||||
/// later using the `SetTrace` notification.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum TraceValue {
|
||||
/// The server should not send any `$/logTrace` notification
|
||||
#[default]
|
||||
Off,
|
||||
/// The server should not add the 'verbose' field in the `LogTraceParams`
|
||||
Messages,
|
||||
Verbose,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LogTraceParams {
|
||||
/// The message to be logged.
|
||||
pub message: String,
|
||||
/// Additional information that can be computed if the `trace` configuration
|
||||
/// is set to `'verbose'`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub verbose: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_set_trace_params() {
|
||||
test_serialization(
|
||||
&SetTraceParams {
|
||||
value: TraceValue::Off,
|
||||
},
|
||||
r#"{"value":"off"}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log_trace_params() {
|
||||
test_serialization(
|
||||
&LogTraceParams {
|
||||
message: "message".into(),
|
||||
verbose: None,
|
||||
},
|
||||
r#"{"message":"message"}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&LogTraceParams {
|
||||
message: "message".into(),
|
||||
verbose: Some("verbose".into()),
|
||||
},
|
||||
r#"{"message":"message","verbose":"verbose"}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trace_value() {
|
||||
test_serialization(
|
||||
&vec![TraceValue::Off, TraceValue::Messages, TraceValue::Verbose],
|
||||
r#"["off","messages","verbose"]"#,
|
||||
);
|
||||
}
|
||||
}
|
90
helix-lsp-types/src/type_hierarchy.rs
Normal file
90
helix-lsp-types/src/type_hierarchy.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, LSPAny, PartialResultParams, Range,
|
||||
StaticRegistrationOptions, SymbolKind, SymbolTag, TextDocumentPositionParams,
|
||||
TextDocumentRegistrationOptions, Url, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type TypeHierarchyClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchyOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchyRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
#[serde(flatten)]
|
||||
pub type_hierarchy_options: TypeHierarchyOptions,
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchyPrepareParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchySupertypesParams {
|
||||
pub item: TypeHierarchyItem,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchySubtypesParams {
|
||||
pub item: TypeHierarchyItem,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TypeHierarchyItem {
|
||||
/// The name of this item.
|
||||
pub name: String,
|
||||
|
||||
/// The kind of this item.
|
||||
pub kind: SymbolKind,
|
||||
|
||||
/// Tags for this item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<SymbolTag>,
|
||||
|
||||
/// More detail for this item, e.g. the signature of a function.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
|
||||
/// The resource identifier of this item.
|
||||
pub uri: Url,
|
||||
|
||||
/// The range enclosing this symbol not including leading/trailing whitespace
|
||||
/// but everything else, e.g. comments and code.
|
||||
pub range: Range,
|
||||
|
||||
/// The range that should be selected and revealed when this symbol is being
|
||||
/// picked, e.g. the name of a function. Must be contained by the
|
||||
/// [`range`](#TypeHierarchyItem.range).
|
||||
pub selection_range: Range,
|
||||
|
||||
/// A data entry field that is preserved between a type hierarchy prepare and
|
||||
/// supertypes or subtypes requests. It could also be used to identify the
|
||||
/// type hierarchy in the server, helping improve the performance on
|
||||
/// resolving supertypes and subtypes.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<LSPAny>,
|
||||
}
|
173
helix-lsp-types/src/window.rs
Normal file
173
helix-lsp-types/src/window.rs
Normal file
@ -0,0 +1,173 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use url::Url;
|
||||
|
||||
use crate::Range;
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct MessageType(i32);
|
||||
lsp_enum! {
|
||||
impl MessageType {
|
||||
/// An error message.
|
||||
pub const ERROR: MessageType = MessageType(1);
|
||||
/// A warning message.
|
||||
pub const WARNING: MessageType = MessageType(2);
|
||||
/// An information message;
|
||||
pub const INFO: MessageType = MessageType(3);
|
||||
/// A log message.
|
||||
pub const LOG: MessageType = MessageType(4);
|
||||
}
|
||||
}
|
||||
|
||||
/// Window specific client capabilities.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WindowClientCapabilities {
|
||||
/// Whether client supports handling progress notifications. If set
|
||||
/// servers are allowed to report in `workDoneProgress` property in the
|
||||
/// request specific server capabilities.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub work_done_progress: Option<bool>,
|
||||
|
||||
/// Capabilities specific to the showMessage request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub show_message: Option<ShowMessageRequestClientCapabilities>,
|
||||
|
||||
/// Client capabilities for the show document request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub show_document: Option<ShowDocumentClientCapabilities>,
|
||||
}
|
||||
|
||||
/// Show message request client capabilities
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShowMessageRequestClientCapabilities {
|
||||
/// Capabilities specific to the `MessageActionItem` type.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message_action_item: Option<MessageActionItemCapabilities>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MessageActionItemCapabilities {
|
||||
/// Whether the client supports additional attributes which
|
||||
/// are preserved and send back to the server in the
|
||||
/// request's response.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub additional_properties_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MessageActionItem {
|
||||
/// A short title like 'Retry', 'Open Log' etc.
|
||||
pub title: String,
|
||||
|
||||
/// Additional attributes that the client preserves and
|
||||
/// sends back to the server. This depends on the client
|
||||
/// capability window.messageActionItem.additionalPropertiesSupport
|
||||
#[serde(flatten)]
|
||||
pub properties: HashMap<String, MessageActionItemProperty>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum MessageActionItemProperty {
|
||||
String(String),
|
||||
Boolean(bool),
|
||||
Integer(i32),
|
||||
Object(Value),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct LogMessageParams {
|
||||
/// The message type. See {@link MessageType}
|
||||
#[serde(rename = "type")]
|
||||
pub typ: MessageType,
|
||||
|
||||
/// The actual message
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct ShowMessageParams {
|
||||
/// The message type. See {@link MessageType}.
|
||||
#[serde(rename = "type")]
|
||||
pub typ: MessageType,
|
||||
|
||||
/// The actual message.
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct ShowMessageRequestParams {
|
||||
/// The message type. See {@link MessageType}
|
||||
#[serde(rename = "type")]
|
||||
pub typ: MessageType,
|
||||
|
||||
/// The actual message
|
||||
pub message: String,
|
||||
|
||||
/// The message action items to present.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub actions: Option<Vec<MessageActionItem>>,
|
||||
}
|
||||
|
||||
/// Client capabilities for the show document request.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShowDocumentClientCapabilities {
|
||||
/// The client has support for the show document request.
|
||||
pub support: bool,
|
||||
}
|
||||
|
||||
/// Params to show a document.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShowDocumentParams {
|
||||
/// The document uri to show.
|
||||
pub uri: Url,
|
||||
|
||||
/// Indicates to show the resource in an external program.
|
||||
/// To show for example `https://code.visualstudio.com/`
|
||||
/// in the default WEB browser set `external` to `true`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub external: Option<bool>,
|
||||
|
||||
/// An optional property to indicate whether the editor
|
||||
/// showing the document should take focus or not.
|
||||
/// Clients might ignore this property if an external
|
||||
/// program in started.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub take_focus: Option<bool>,
|
||||
|
||||
/// An optional selection range if the document is a text
|
||||
/// document. Clients might ignore the property if an
|
||||
/// external program is started or the file is not a text
|
||||
/// file.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub selection: Option<Range>,
|
||||
}
|
||||
|
||||
/// The result of an show document request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShowDocumentResult {
|
||||
/// A boolean indicating if the show was successful.
|
||||
pub success: bool,
|
||||
}
|
149
helix-lsp-types/src/workspace_diagnostic.rs
Normal file
149
helix-lsp-types/src/workspace_diagnostic.rs
Normal file
@ -0,0 +1,149 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
FullDocumentDiagnosticReport, PartialResultParams, UnchangedDocumentDiagnosticReport,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
/// Workspace client capabilities specific to diagnostic pull requests.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from
|
||||
/// the server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// pulled diagnostics currently shown. It should be used with absolute care
|
||||
/// and is useful for situation where a server for example detects a project
|
||||
/// wide change that requires such a calculation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
||||
|
||||
/// A previous result ID in a workspace pull request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct PreviousResultId {
|
||||
/// The URI for which the client knows a result ID.
|
||||
pub uri: Url,
|
||||
|
||||
/// The value of the previous result ID.
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
/// Parameters of the workspace diagnostic request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceDiagnosticParams {
|
||||
/// The additional identifier provided during registration.
|
||||
pub identifier: Option<String>,
|
||||
|
||||
/// The currently known diagnostic reports with their
|
||||
/// previous result ids.
|
||||
pub previous_result_ids: Vec<PreviousResultId>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A full document diagnostic report for a workspace diagnostic result.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFullDocumentDiagnosticReport {
|
||||
/// The URI for which diagnostic information is reported.
|
||||
pub uri: Url,
|
||||
|
||||
/// The version number for which the diagnostics are reported.
|
||||
///
|
||||
/// If the document is not marked as open, `None` can be provided.
|
||||
pub version: Option<i64>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub full_document_diagnostic_report: FullDocumentDiagnosticReport,
|
||||
}
|
||||
|
||||
/// An unchanged document diagnostic report for a workspace diagnostic result.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceUnchangedDocumentDiagnosticReport {
|
||||
/// The URI for which diagnostic information is reported.
|
||||
pub uri: Url,
|
||||
|
||||
/// The version number for which the diagnostics are reported.
|
||||
///
|
||||
/// If the document is not marked as open, `None` can be provided.
|
||||
pub version: Option<i64>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub unchanged_document_diagnostic_report: UnchangedDocumentDiagnosticReport,
|
||||
}
|
||||
|
||||
/// A workspace diagnostic document report.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum WorkspaceDocumentDiagnosticReport {
|
||||
Full(WorkspaceFullDocumentDiagnosticReport),
|
||||
Unchanged(WorkspaceUnchangedDocumentDiagnosticReport),
|
||||
}
|
||||
|
||||
impl From<WorkspaceFullDocumentDiagnosticReport> for WorkspaceDocumentDiagnosticReport {
|
||||
fn from(from: WorkspaceFullDocumentDiagnosticReport) -> Self {
|
||||
WorkspaceDocumentDiagnosticReport::Full(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WorkspaceUnchangedDocumentDiagnosticReport> for WorkspaceDocumentDiagnosticReport {
|
||||
fn from(from: WorkspaceUnchangedDocumentDiagnosticReport) -> Self {
|
||||
WorkspaceDocumentDiagnosticReport::Unchanged(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A workspace diagnostic report.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
pub struct WorkspaceDiagnosticReport {
|
||||
pub items: Vec<WorkspaceDocumentDiagnosticReport>,
|
||||
}
|
||||
|
||||
/// A partial result for a workspace diagnostic report.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
pub struct WorkspaceDiagnosticReportPartialResult {
|
||||
pub items: Vec<WorkspaceDocumentDiagnosticReport>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum WorkspaceDiagnosticReportResult {
|
||||
Report(WorkspaceDiagnosticReport),
|
||||
Partial(WorkspaceDiagnosticReportPartialResult),
|
||||
}
|
||||
|
||||
impl From<WorkspaceDiagnosticReport> for WorkspaceDiagnosticReportResult {
|
||||
fn from(from: WorkspaceDiagnosticReport) -> Self {
|
||||
WorkspaceDiagnosticReportResult::Report(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WorkspaceDiagnosticReportPartialResult> for WorkspaceDiagnosticReportResult {
|
||||
fn from(from: WorkspaceDiagnosticReportPartialResult) -> Self {
|
||||
WorkspaceDiagnosticReportResult::Partial(from)
|
||||
}
|
||||
}
|
49
helix-lsp-types/src/workspace_folders.rs
Normal file
49
helix-lsp-types/src/workspace_folders.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::OneOf;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFoldersServerCapabilities {
|
||||
/// The server has support for workspace folders
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub supported: Option<bool>,
|
||||
|
||||
/// Whether the server wants to receive workspace folder
|
||||
/// change notifications.
|
||||
///
|
||||
/// If a string is provided, the string is treated as an ID
|
||||
/// under which the notification is registered on the client
|
||||
/// side. The ID can be used to unregister for these events
|
||||
/// using the `client/unregisterCapability` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub change_notifications: Option<OneOf<bool, String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFolder {
|
||||
/// The associated URI for this workspace folder.
|
||||
pub uri: Url,
|
||||
/// The name of the workspace folder. Defaults to the uri's basename.
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DidChangeWorkspaceFoldersParams {
|
||||
/// The actual workspace folder change event.
|
||||
pub event: WorkspaceFoldersChangeEvent,
|
||||
}
|
||||
|
||||
/// The workspace folder change event.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFoldersChangeEvent {
|
||||
/// The array of added workspace folders
|
||||
pub added: Vec<WorkspaceFolder>,
|
||||
|
||||
/// The array of the removed workspace folders
|
||||
pub removed: Vec<WorkspaceFolder>,
|
||||
}
|
105
helix-lsp-types/src/workspace_symbols.rs
Normal file
105
helix-lsp-types/src/workspace_symbols.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use crate::{
|
||||
LSPAny, Location, OneOf, PartialResultParams, SymbolInformation, SymbolKind,
|
||||
SymbolKindCapability, SymbolTag, TagSupport, Url, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceSymbolClientCapabilities {
|
||||
/// This capability supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub symbol_kind: Option<SymbolKindCapability>,
|
||||
|
||||
/// The client supports tags on `SymbolInformation`.
|
||||
/// Clients supporting tags have to handle unknown tags gracefully.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "TagSupport::deserialize_compat"
|
||||
)]
|
||||
pub tag_support: Option<TagSupport<SymbolTag>>,
|
||||
|
||||
/// The client support partial workspace symbols. The client will send the
|
||||
/// request `workspaceSymbol/resolve` to the server to resolve additional
|
||||
/// properties.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_support: Option<WorkspaceSymbolResolveSupportCapability>,
|
||||
}
|
||||
|
||||
/// The parameters of a Workspace Symbol Request.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct WorkspaceSymbolParams {
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
/// A non-empty query string
|
||||
pub query: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct WorkspaceSymbolResolveSupportCapability {
|
||||
/// The properties that a client can resolve lazily. Usually
|
||||
/// `location.range`
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
/// A special workspace symbol that supports locations without a range
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceSymbol {
|
||||
/// The name of this symbol.
|
||||
pub name: String,
|
||||
|
||||
/// The kind of this symbol.
|
||||
pub kind: SymbolKind,
|
||||
|
||||
/// Tags for this completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<SymbolTag>>,
|
||||
|
||||
/// The name of the symbol containing this symbol. This information is for
|
||||
/// user interface purposes (e.g. to render a qualifier in the user interface
|
||||
/// if necessary). It can't be used to re-infer a hierarchy for the document
|
||||
/// symbols.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub container_name: Option<String>,
|
||||
|
||||
/// The location of this symbol. Whether a server is allowed to
|
||||
/// return a location without a range depends on the client
|
||||
/// capability `workspace.symbol.resolveSupport`.
|
||||
///
|
||||
/// See also `SymbolInformation.location`.
|
||||
pub location: OneOf<Location, WorkspaceLocation>,
|
||||
|
||||
/// A data entry field that is preserved on a workspace symbol between a
|
||||
/// workspace symbol request and a workspace symbol resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<LSPAny>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct WorkspaceLocation {
|
||||
pub uri: Url,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum WorkspaceSymbolResponse {
|
||||
Flat(Vec<SymbolInformation>),
|
||||
Nested(Vec<WorkspaceSymbol>),
|
||||
}
|
@ -17,16 +17,16 @@ helix-stdx = { path = "../helix-stdx" }
|
||||
helix-core = { path = "../helix-core" }
|
||||
helix-loader = { path = "../helix-loader" }
|
||||
helix-parsec = { path = "../helix-parsec" }
|
||||
helix-lsp-types = { path = "../helix-lsp-types" }
|
||||
|
||||
anyhow = "1.0"
|
||||
futures-executor = "0.3"
|
||||
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
|
||||
globset = "0.4.14"
|
||||
log = "0.4"
|
||||
lsp-types = { version = "0.95" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1.38", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
|
||||
tokio = { version = "1.39", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
|
||||
tokio-stream = "0.1.15"
|
||||
parking_lot = "0.12.3"
|
||||
arc-swap = "1"
|
||||
|
@ -5,15 +5,14 @@
|
||||
Call, Error, LanguageServerId, OffsetEncoding, Result,
|
||||
};
|
||||
|
||||
use helix_core::{find_workspace, syntax::LanguageServerFeature, ChangeSet, Rope};
|
||||
use helix_loader::VERSION_AND_GIT_HASH;
|
||||
use helix_stdx::path;
|
||||
use lsp::{
|
||||
notification::DidChangeWorkspaceFolders, CodeActionCapabilityResolveSupport,
|
||||
use crate::lsp::{
|
||||
self, notification::DidChangeWorkspaceFolders, CodeActionCapabilityResolveSupport,
|
||||
DidChangeWorkspaceFoldersParams, OneOf, PositionEncodingKind, SignatureHelp, Url,
|
||||
WorkspaceFolder, WorkspaceFoldersChangeEvent,
|
||||
};
|
||||
use lsp_types as lsp;
|
||||
use helix_core::{find_workspace, syntax::LanguageServerFeature, ChangeSet, Rope};
|
||||
use helix_loader::VERSION_AND_GIT_HASH;
|
||||
use helix_stdx::path;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
@ -999,7 +998,7 @@ pub fn text_document_did_save(
|
||||
..
|
||||
}) => match options.as_ref()? {
|
||||
lsp::TextDocumentSyncSaveOptions::Supported(true) => false,
|
||||
lsp::TextDocumentSyncSaveOptions::SaveOptions(lsp_types::SaveOptions {
|
||||
lsp::TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
|
||||
include_text,
|
||||
}) => include_text.unwrap_or(false),
|
||||
lsp::TextDocumentSyncSaveOptions::Supported(false) => return None,
|
||||
|
@ -8,9 +8,9 @@
|
||||
use arc_swap::ArcSwap;
|
||||
pub use client::Client;
|
||||
pub use futures_executor::block_on;
|
||||
pub use helix_lsp_types as lsp;
|
||||
pub use jsonrpc::Call;
|
||||
pub use lsp::{Position, Url};
|
||||
pub use lsp_types as lsp;
|
||||
|
||||
use futures_util::stream::select_all::SelectAll;
|
||||
use helix_core::syntax::{
|
||||
@ -284,10 +284,8 @@ fn find_completion_range(text: RopeSlice, replace_mode: bool, cursor: usize) ->
|
||||
if replace_mode {
|
||||
end += text
|
||||
.chars_at(cursor)
|
||||
.skip(1)
|
||||
.take_while(|ch| chars::char_is_word(*ch))
|
||||
.count()
|
||||
+ 1;
|
||||
.count();
|
||||
}
|
||||
(start, end)
|
||||
}
|
||||
@ -505,7 +503,7 @@ pub fn generate_transaction_from_edits(
|
||||
) -> Transaction {
|
||||
// Sort edits by start range, since some LSPs (Omnisharp) send them
|
||||
// in reverse order.
|
||||
edits.sort_unstable_by_key(|edit| edit.range.start);
|
||||
edits.sort_by_key(|edit| edit.range.start);
|
||||
|
||||
// Generate a diff if the edit is a full document replacement.
|
||||
#[allow(clippy::collapsible_if)]
|
||||
@ -677,7 +675,7 @@ pub fn get_by_id(&self, id: LanguageServerId) -> Option<&Arc<Client>> {
|
||||
|
||||
pub fn remove_by_id(&mut self, id: LanguageServerId) {
|
||||
let Some(client) = self.inner.remove(id) else {
|
||||
log::error!("client was already removed");
|
||||
log::debug!("client was already removed");
|
||||
return;
|
||||
};
|
||||
self.file_event_handler.remove_client(id);
|
||||
@ -737,6 +735,11 @@ pub fn restart(
|
||||
.iter()
|
||||
.filter_map(|LanguageServerFeatures { name, .. }| {
|
||||
if let Some(old_clients) = self.inner_by_name.remove(name) {
|
||||
if old_clients.is_empty() {
|
||||
log::info!("restarting client for '{name}' which was manually stopped");
|
||||
} else {
|
||||
log::info!("stopping existing clients for '{name}'");
|
||||
}
|
||||
for old_client in old_clients {
|
||||
self.file_event_handler.remove_client(old_client.id());
|
||||
self.inner.remove(old_client.id());
|
||||
@ -765,8 +768,13 @@ pub fn restart(
|
||||
}
|
||||
|
||||
pub fn stop(&mut self, name: &str) {
|
||||
if let Some(clients) = self.inner_by_name.remove(name) {
|
||||
for client in clients {
|
||||
if let Some(clients) = self.inner_by_name.get_mut(name) {
|
||||
// Drain the clients vec so that the entry in `inner_by_name` remains
|
||||
// empty. We use the empty vec as a "tombstone" to mean that a server
|
||||
// has been manually stopped with :lsp-stop and shouldn't be automatically
|
||||
// restarted by `get`. :lsp-restart can be used to restart the server
|
||||
// manually.
|
||||
for client in clients.drain(..) {
|
||||
self.file_event_handler.remove_client(client.id());
|
||||
self.inner.remove(client.id());
|
||||
tokio::spawn(async move {
|
||||
@ -786,6 +794,14 @@ pub fn get<'a>(
|
||||
language_config.language_servers.iter().filter_map(
|
||||
move |LanguageServerFeatures { name, .. }| {
|
||||
if let Some(clients) = self.inner_by_name.get(name) {
|
||||
// If the clients vec is empty, do not automatically start a client
|
||||
// for this server. The empty vec is a tombstone left to mean that a
|
||||
// server has been manually stopped and shouldn't be started automatically.
|
||||
// See `stop`.
|
||||
if clients.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some((_, client)) = clients.iter().enumerate().find(|(i, client)| {
|
||||
client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0)
|
||||
}) {
|
||||
@ -1097,7 +1113,7 @@ macro_rules! test_case {
|
||||
|
||||
#[test]
|
||||
fn emoji_format_gh_4791() {
|
||||
use lsp_types::{Position, Range, TextEdit};
|
||||
use lsp::{Position, Range, TextEdit};
|
||||
|
||||
let edits = vec![
|
||||
TextEdit {
|
||||
|
@ -1,4 +1,8 @@
|
||||
use crate::{jsonrpc, Error, LanguageServerId, Result};
|
||||
use crate::{
|
||||
jsonrpc,
|
||||
lsp::{self, notification::Notification as _},
|
||||
Error, LanguageServerId, Result,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use log::{error, info};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -289,11 +293,10 @@ async fn recv(
|
||||
}
|
||||
|
||||
// Hack: inject a terminated notification so we trigger code that needs to happen after exit
|
||||
use lsp_types::notification::Notification as _;
|
||||
let notification =
|
||||
ServerMessage::Call(jsonrpc::Call::Notification(jsonrpc::Notification {
|
||||
jsonrpc: None,
|
||||
method: lsp_types::notification::Exit::METHOD.to_string(),
|
||||
method: lsp::notification::Exit::METHOD.to_string(),
|
||||
params: jsonrpc::Params::None,
|
||||
}));
|
||||
match transport
|
||||
@ -338,8 +341,8 @@ async fn send(
|
||||
|
||||
// Determine if a message is allowed to be sent early
|
||||
fn is_initialize(payload: &Payload) -> bool {
|
||||
use lsp_types::{
|
||||
notification::{Initialized, Notification},
|
||||
use lsp::{
|
||||
notification::Initialized,
|
||||
request::{Initialize, Request},
|
||||
};
|
||||
match payload {
|
||||
@ -357,7 +360,7 @@ fn is_initialize(payload: &Payload) -> bool {
|
||||
}
|
||||
|
||||
fn is_shutdown(payload: &Payload) -> bool {
|
||||
use lsp_types::request::{Request, Shutdown};
|
||||
use lsp::request::{Request, Shutdown};
|
||||
matches!(payload, Payload::Request { value: jsonrpc::MethodCall { method, .. }, .. } if method == Shutdown::METHOD)
|
||||
}
|
||||
|
||||
@ -370,12 +373,11 @@ fn is_shutdown(payload: &Payload) -> bool {
|
||||
// server successfully initialized
|
||||
is_pending = false;
|
||||
|
||||
use lsp_types::notification::Notification;
|
||||
// Hack: inject an initialized notification so we trigger code that needs to happen after init
|
||||
let notification = ServerMessage::Call(jsonrpc::Call::Notification(jsonrpc::Notification {
|
||||
jsonrpc: None,
|
||||
|
||||
method: lsp_types::notification::Initialized::METHOD.to_string(),
|
||||
method: lsp::notification::Initialized::METHOD.to_string(),
|
||||
params: jsonrpc::Params::None,
|
||||
}));
|
||||
let language_server_name = &transport.name;
|
||||
|
@ -74,6 +74,11 @@ pub fn copy_metadata(from: &Path, to: &Path) -> io::Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hardlink_count(p: &Path) -> std::io::Result<u64> {
|
||||
let metadata = p.metadata()?;
|
||||
Ok(metadata.nlink())
|
||||
}
|
||||
}
|
||||
|
||||
// Licensed under MIT from faccess except for `chown`, `copy_metadata` and `is_acl_inherited`
|
||||
@ -94,8 +99,8 @@ mod imp {
|
||||
SID_IDENTIFIER_AUTHORITY, TOKEN_DUPLICATE, TOKEN_QUERY,
|
||||
};
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
FILE_ACCESS_RIGHTS, FILE_ALL_ACCESS, FILE_GENERIC_EXECUTE, FILE_GENERIC_READ,
|
||||
FILE_GENERIC_WRITE,
|
||||
GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION, FILE_ACCESS_RIGHTS,
|
||||
FILE_ALL_ACCESS, FILE_GENERIC_EXECUTE, FILE_GENERIC_READ, FILE_GENERIC_WRITE,
|
||||
};
|
||||
use windows_sys::Win32::System::Threading::{GetCurrentThread, OpenThreadToken};
|
||||
|
||||
@ -103,7 +108,7 @@ mod imp {
|
||||
|
||||
use std::ffi::c_void;
|
||||
|
||||
use std::os::windows::{ffi::OsStrExt, fs::OpenOptionsExt};
|
||||
use std::os::windows::{ffi::OsStrExt, fs::OpenOptionsExt, io::AsRawHandle};
|
||||
|
||||
struct SecurityDescriptor {
|
||||
sd: PSECURITY_DESCRIPTOR,
|
||||
@ -290,21 +295,21 @@ fn eaccess(p: &Path, mut mode: FILE_ACCESS_RIGHTS) -> io::Result<()> {
|
||||
let mut privileges_length = std::mem::size_of::<PRIVILEGE_SET>() as u32;
|
||||
let mut result = 0;
|
||||
|
||||
let mut mapping = GENERIC_MAPPING {
|
||||
let mapping = GENERIC_MAPPING {
|
||||
GenericRead: FILE_GENERIC_READ,
|
||||
GenericWrite: FILE_GENERIC_WRITE,
|
||||
GenericExecute: FILE_GENERIC_EXECUTE,
|
||||
GenericAll: FILE_ALL_ACCESS,
|
||||
};
|
||||
|
||||
unsafe { MapGenericMask(&mut mode, &mut mapping) };
|
||||
unsafe { MapGenericMask(&mut mode, &mapping) };
|
||||
|
||||
if unsafe {
|
||||
AccessCheck(
|
||||
*sd.descriptor(),
|
||||
*token.as_handle(),
|
||||
mode,
|
||||
&mut mapping,
|
||||
&mapping,
|
||||
&mut privileges,
|
||||
&mut privileges_length,
|
||||
&mut granted_access,
|
||||
@ -411,6 +416,18 @@ pub fn copy_metadata(from: &Path, to: &Path) -> io::Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hardlink_count(p: &Path) -> std::io::Result<u64> {
|
||||
let file = std::fs::File::open(p)?;
|
||||
let handle = file.as_raw_handle() as isize;
|
||||
let mut info: BY_HANDLE_FILE_INFORMATION = unsafe { std::mem::zeroed() };
|
||||
|
||||
if unsafe { GetFileInformationByHandle(handle, &mut info) } == 0 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(info.nNumberOfLinks as u64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Licensed under MIT from faccess except for `copy_metadata`
|
||||
@ -457,3 +474,7 @@ pub fn readonly(p: &Path) -> bool {
|
||||
pub fn copy_metadata(from: &Path, to: &Path) -> io::Result<()> {
|
||||
imp::copy_metadata(from, to)
|
||||
}
|
||||
|
||||
pub fn hardlink_count(p: &Path) -> io::Result<u64> {
|
||||
imp::hardlink_count(p)
|
||||
}
|
||||
|
@ -86,3 +86,4 @@ helix-loader = { path = "../helix-loader" }
|
||||
smallvec = "1.13"
|
||||
indoc = "2.0.5"
|
||||
tempfile = "3.10.1"
|
||||
same-file = "1.0.1"
|
||||
|
@ -66,18 +66,16 @@ fn find_rc_exe() -> io::Result<PathBuf> {
|
||||
.output();
|
||||
|
||||
match find_reg_key {
|
||||
Err(find_reg_key) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Failed to run registry query: {}", find_reg_key),
|
||||
))
|
||||
}
|
||||
Err(find_reg_key) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Failed to run registry query: {}", find_reg_key),
|
||||
)),
|
||||
Ok(find_reg_key) => {
|
||||
if find_reg_key.status.code().unwrap() != 0 {
|
||||
return Err(io::Error::new(
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Can not find Windows SDK",
|
||||
));
|
||||
))
|
||||
} else {
|
||||
let lines = String::from_utf8(find_reg_key.stdout)
|
||||
.expect("Should be able to parse the output");
|
||||
|
@ -35,7 +35,9 @@
|
||||
use std::io::stdout;
|
||||
use std::{collections::btree_map::Entry, io::stdin, path::Path, sync::Arc};
|
||||
|
||||
use anyhow::{Context, Error};
|
||||
#[cfg(not(windows))]
|
||||
use anyhow::Context;
|
||||
use anyhow::Error;
|
||||
|
||||
use crossterm::{event::Event as CrosstermEvent, tty::IsTty};
|
||||
#[cfg(not(windows))]
|
||||
@ -575,7 +577,7 @@ pub fn handle_document_write(&mut self, doc_save_event: DocumentSavedEventResult
|
||||
doc_save_event.revision
|
||||
);
|
||||
|
||||
doc.set_last_saved_revision(doc_save_event.revision);
|
||||
doc.set_last_saved_revision(doc_save_event.revision, doc_save_event.save_time);
|
||||
|
||||
let lines = doc_save_event.text.len_lines();
|
||||
let bytes = doc_save_event.text.len_bytes();
|
||||
|
@ -1939,6 +1939,8 @@ fn select_regex(cx: &mut Context) {
|
||||
selection::select_on_matches(text, doc.selection(view.id), ®ex)
|
||||
{
|
||||
doc.set_selection(view.id, selection);
|
||||
} else {
|
||||
cx.editor.set_error("nothing selected");
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -4624,6 +4626,8 @@ fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) {
|
||||
selection::keep_or_remove_matches(text, doc.selection(view.id), ®ex, remove)
|
||||
{
|
||||
doc.set_selection(view.id, selection);
|
||||
} else {
|
||||
cx.editor.set_error("no selections remaining");
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -5716,27 +5720,24 @@ async fn shell_impl_async(
|
||||
process.wait_with_output().await?
|
||||
};
|
||||
|
||||
if !output.status.success() {
|
||||
if !output.stderr.is_empty() {
|
||||
let err = String::from_utf8_lossy(&output.stderr).to_string();
|
||||
log::error!("Shell error: {}", err);
|
||||
bail!("Shell error: {}", err);
|
||||
}
|
||||
match output.status.code() {
|
||||
Some(exit_code) => bail!("Shell command failed: status {}", exit_code),
|
||||
None => bail!("Shell command failed"),
|
||||
let output = if !output.status.success() {
|
||||
if output.stderr.is_empty() {
|
||||
match output.status.code() {
|
||||
Some(exit_code) => bail!("Shell command failed: status {}", exit_code),
|
||||
None => bail!("Shell command failed"),
|
||||
}
|
||||
}
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
// Prioritize `stderr` output over `stdout`
|
||||
} else if !output.stderr.is_empty() {
|
||||
log::debug!(
|
||||
"Command printed to stderr: {}",
|
||||
String::from_utf8_lossy(&output.stderr).to_string()
|
||||
);
|
||||
}
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
log::debug!("Command printed to stderr: {stderr}");
|
||||
stderr
|
||||
} else {
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
};
|
||||
|
||||
let str = std::str::from_utf8(&output.stdout)
|
||||
.map_err(|_| anyhow!("Process did not output valid UTF-8"))?;
|
||||
let tendril = Tendril::from(str);
|
||||
Ok(tendril)
|
||||
Ok(Tendril::from(output))
|
||||
}
|
||||
|
||||
fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
|
||||
|
@ -34,7 +34,7 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{btree_map::Entry, BTreeMap, HashMap, HashSet},
|
||||
fmt::Write,
|
||||
fmt::{Display, Write},
|
||||
future::Future,
|
||||
path::Path,
|
||||
};
|
||||
@ -832,13 +832,13 @@ pub enum ApplyEditErrorKind {
|
||||
// InvalidEdit,
|
||||
}
|
||||
|
||||
impl ToString for ApplyEditErrorKind {
|
||||
fn to_string(&self) -> String {
|
||||
impl Display for ApplyEditErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ApplyEditErrorKind::DocumentChanged => "document has changed".to_string(),
|
||||
ApplyEditErrorKind::FileNotFound => "file not found".to_string(),
|
||||
ApplyEditErrorKind::UnknownURISchema => "URI schema not supported".to_string(),
|
||||
ApplyEditErrorKind::IoError(err) => err.to_string(),
|
||||
ApplyEditErrorKind::DocumentChanged => f.write_str("document has changed"),
|
||||
ApplyEditErrorKind::FileNotFound => f.write_str("file not found"),
|
||||
ApplyEditErrorKind::UnknownURISchema => f.write_str("URI schema not supported"),
|
||||
ApplyEditErrorKind::IoError(err) => f.write_str(&format!("{err}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1360,7 +1360,7 @@ fn compute_inlay_hints_for_view(
|
||||
|
||||
// Most language servers will already send them sorted but ensure this is the case to
|
||||
// avoid errors on our end.
|
||||
hints.sort_unstable_by_key(|inlay_hint| inlay_hint.position);
|
||||
hints.sort_by_key(|inlay_hint| inlay_hint.position);
|
||||
|
||||
let mut padding_before_inlay_hints = Vec::new();
|
||||
let mut type_inlay_hints = Vec::new();
|
||||
|
@ -2308,7 +2308,7 @@ fn run_shell_command(
|
||||
));
|
||||
compositor.replace_or_push("shell", popup);
|
||||
}
|
||||
editor.set_status("Command succeeded");
|
||||
editor.set_status("Command run");
|
||||
},
|
||||
));
|
||||
Ok(call)
|
||||
@ -2498,7 +2498,7 @@ fn read(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) ->
|
||||
ensure!(!args.is_empty(), "file name is expected");
|
||||
ensure!(args.len() == 1, "only the file name is expected");
|
||||
|
||||
let filename = args.get(0).unwrap();
|
||||
let filename = args.first().unwrap();
|
||||
let path = PathBuf::from(filename.to_string());
|
||||
ensure!(
|
||||
path.exists() && path.is_file(),
|
||||
|
@ -117,10 +117,9 @@ async fn main_impl() -> Result<i32> {
|
||||
setup_logging(args.verbosity).context("failed to initialize logging")?;
|
||||
|
||||
// Before setting the working directory, resolve all the paths in args.files
|
||||
for (path, _) in args.files.iter_mut() {
|
||||
*path = helix_stdx::path::canonicalize(&path);
|
||||
for (path, _) in &mut args.files {
|
||||
*path = helix_stdx::path::canonicalize(&*path);
|
||||
}
|
||||
|
||||
// NOTE: Set the working directory early so the correct configuration is loaded. Be aware that
|
||||
// Application::new() depends on this logic so it must be updated if this changes.
|
||||
if let Some(path) = &args.working_directory {
|
||||
|
@ -799,21 +799,25 @@ fn render_picker(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context)
|
||||
if self.columns.len() > 1 {
|
||||
let active_column = self.query.active_column(self.prompt.position());
|
||||
let header_style = cx.editor.theme.get("ui.picker.header");
|
||||
let header_column_style = cx.editor.theme.get("ui.picker.header.column");
|
||||
|
||||
table = table.header(Row::new(self.columns.iter().map(|column| {
|
||||
if column.hidden {
|
||||
Cell::default()
|
||||
} else {
|
||||
let style = if active_column.is_some_and(|name| Arc::ptr_eq(name, &column.name))
|
||||
{
|
||||
cx.editor.theme.get("ui.picker.header.active")
|
||||
table = table.header(
|
||||
Row::new(self.columns.iter().map(|column| {
|
||||
if column.hidden {
|
||||
Cell::default()
|
||||
} else {
|
||||
header_style
|
||||
};
|
||||
let style =
|
||||
if active_column.is_some_and(|name| Arc::ptr_eq(name, &column.name)) {
|
||||
cx.editor.theme.get("ui.picker.header.column.active")
|
||||
} else {
|
||||
header_column_style
|
||||
};
|
||||
|
||||
Cell::from(Span::styled(Cow::from(&*column.name), style))
|
||||
}
|
||||
})));
|
||||
Cell::from(Span::styled(Cow::from(&*column.name), style))
|
||||
}
|
||||
}))
|
||||
.style(header_style),
|
||||
);
|
||||
}
|
||||
|
||||
use tui::widgets::TableState;
|
||||
|
@ -649,6 +649,41 @@ async fn test_symlink_write_relative() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[cfg(not(target_os = "android"))]
|
||||
async fn test_hardlink_write() -> anyhow::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
|
||||
let mut file = tempfile::NamedTempFile::new_in(&dir)?;
|
||||
let hardlink_path = dir.path().join("linked");
|
||||
std::fs::hard_link(file.path(), &hardlink_path)?;
|
||||
|
||||
let mut app = helpers::AppBuilder::new()
|
||||
.with_file(&hardlink_path, None)
|
||||
.build()?;
|
||||
|
||||
test_key_sequence(
|
||||
&mut app,
|
||||
Some("ithe gostak distims the doshes<ret><esc>:w<ret>"),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
reload_file(&mut file).unwrap();
|
||||
let mut file_content = String::new();
|
||||
file.as_file_mut().read_to_string(&mut file_content)?;
|
||||
|
||||
assert_eq!(
|
||||
LineFeedHandling::Native.apply("the gostak distims the doshes"),
|
||||
file_content
|
||||
);
|
||||
assert!(helix_stdx::faccess::hardlink_count(&hardlink_path)? > 1);
|
||||
assert!(same_file::is_same_file(file.path(), &hardlink_path)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn edit_file_with_content(file_content: &[u8]) -> anyhow::Result<()> {
|
||||
let mut file = tempfile::NamedTempFile::new()?;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! - A single line string where all graphemes have the same style is represented by a [`Span`].
|
||||
//! - A single line string where each grapheme may have its own style is represented by [`Spans`].
|
||||
//! - A multiple line string where each grapheme may have its own style is represented by a
|
||||
//! [`Text`].
|
||||
//! [`Text`].
|
||||
//!
|
||||
//! These types form a hierarchy: [`Spans`] is a collection of [`Span`] and each line of [`Text`]
|
||||
//! is a [`Spans`].
|
||||
|
@ -19,8 +19,8 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p
|
||||
parking_lot = "0.12"
|
||||
arc-swap = { version = "1.7.1" }
|
||||
|
||||
gix = { version = "0.63.0", features = ["attributes", "status"], default-features = false, optional = true }
|
||||
imara-diff = "0.1.6"
|
||||
gix = { version = "0.64.0", features = ["attributes", "status"], default-features = false, optional = true }
|
||||
imara-diff = "0.1.7"
|
||||
anyhow = "1"
|
||||
|
||||
log = "0.4"
|
||||
|
@ -106,6 +106,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DocumentSavedEvent {
|
||||
pub revision: usize,
|
||||
pub save_time: SystemTime,
|
||||
pub doc_id: DocumentId,
|
||||
pub path: PathBuf,
|
||||
pub text: Rope,
|
||||
@ -936,6 +937,9 @@ impl Future<Output = Result<DocumentSavedEvent, anyhow::Error>> + 'static + Send
|
||||
"Path is read only"
|
||||
));
|
||||
}
|
||||
|
||||
// Assume it is a hardlink to prevent data loss if the metadata cant be read (e.g. on certain Windows configurations)
|
||||
let is_hardlink = helix_stdx::faccess::hardlink_count(&write_path).unwrap_or(2) > 1;
|
||||
let backup = if path.exists() {
|
||||
let path_ = write_path.clone();
|
||||
// hacks: we use tempfile to handle the complex task of creating
|
||||
@ -944,14 +948,22 @@ impl Future<Output = Result<DocumentSavedEvent, anyhow::Error>> + 'static + Send
|
||||
// since the path doesn't exist yet, we just want
|
||||
// the path
|
||||
tokio::task::spawn_blocking(move || -> Option<PathBuf> {
|
||||
tempfile::Builder::new()
|
||||
.prefix(path_.file_name()?)
|
||||
.suffix(".bck")
|
||||
.make_in(path_.parent()?, |backup| std::fs::rename(&path_, backup))
|
||||
.ok()?
|
||||
.into_temp_path()
|
||||
.keep()
|
||||
.ok()
|
||||
let mut builder = tempfile::Builder::new();
|
||||
builder.prefix(path_.file_name()?).suffix(".bck");
|
||||
|
||||
let backup_path = if is_hardlink {
|
||||
builder
|
||||
.make_in(path_.parent()?, |backup| std::fs::copy(&path_, backup))
|
||||
.ok()?
|
||||
.into_temp_path()
|
||||
} else {
|
||||
builder
|
||||
.make_in(path_.parent()?, |backup| std::fs::rename(&path_, backup))
|
||||
.ok()?
|
||||
.into_temp_path()
|
||||
};
|
||||
|
||||
backup_path.keep().ok()
|
||||
})
|
||||
.await
|
||||
.ok()
|
||||
@ -968,8 +980,29 @@ impl Future<Output = Result<DocumentSavedEvent, anyhow::Error>> + 'static + Send
|
||||
}
|
||||
.await;
|
||||
|
||||
let save_time = match fs::metadata(&write_path).await {
|
||||
Ok(metadata) => metadata.modified().map_or(SystemTime::now(), |mtime| mtime),
|
||||
Err(_) => SystemTime::now(),
|
||||
};
|
||||
|
||||
if let Some(backup) = backup {
|
||||
if write_result.is_err() {
|
||||
if is_hardlink {
|
||||
let mut delete = true;
|
||||
if write_result.is_err() {
|
||||
// Restore backup
|
||||
let _ = tokio::fs::copy(&backup, &write_path).await.map_err(|e| {
|
||||
delete = false;
|
||||
log::error!("Failed to restore backup on write failure: {e}")
|
||||
});
|
||||
}
|
||||
|
||||
if delete {
|
||||
// Delete backup
|
||||
let _ = tokio::fs::remove_file(backup)
|
||||
.await
|
||||
.map_err(|e| log::error!("Failed to remove backup file on write: {e}"));
|
||||
}
|
||||
} else if write_result.is_err() {
|
||||
// restore backup
|
||||
let _ = tokio::fs::rename(&backup, &write_path)
|
||||
.await
|
||||
@ -990,6 +1023,7 @@ impl Future<Output = Result<DocumentSavedEvent, anyhow::Error>> + 'static + Send
|
||||
|
||||
let event = DocumentSavedEvent {
|
||||
revision: current_rev,
|
||||
save_time,
|
||||
doc_id,
|
||||
path,
|
||||
text: text.clone(),
|
||||
@ -1048,6 +1082,25 @@ pub fn detect_indent_and_line_ending(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pickup_last_saved_time(&mut self) {
|
||||
self.last_saved_time = match self.path() {
|
||||
Some(path) => match path.metadata() {
|
||||
Ok(metadata) => match metadata.modified() {
|
||||
Ok(mtime) => mtime,
|
||||
Err(err) => {
|
||||
log::debug!("Could not fetch file system's mtime, falling back to current system time: {}", err);
|
||||
SystemTime::now()
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::debug!("Could not fetch file system's mtime, falling back to current system time: {}", err);
|
||||
SystemTime::now()
|
||||
}
|
||||
},
|
||||
None => SystemTime::now(),
|
||||
};
|
||||
}
|
||||
|
||||
// Detect if the file is readonly and change the readonly field if necessary (unix only)
|
||||
pub fn detect_readonly(&mut self) {
|
||||
// Allows setting the flag for files the user cannot modify, like root files
|
||||
@ -1085,9 +1138,7 @@ pub fn reload(
|
||||
self.apply(&transaction, view.id);
|
||||
self.append_changes_to_history(view);
|
||||
self.reset_modified();
|
||||
|
||||
self.last_saved_time = SystemTime::now();
|
||||
|
||||
self.pickup_last_saved_time();
|
||||
self.detect_indent_and_line_ending();
|
||||
|
||||
match provider_registry.get_diff_base(&path) {
|
||||
@ -1126,6 +1177,7 @@ pub fn set_path(&mut self, path: Option<&Path>) {
|
||||
self.path = path;
|
||||
|
||||
self.detect_readonly();
|
||||
self.pickup_last_saved_time();
|
||||
}
|
||||
|
||||
/// Set the programming language for the file and load associated data (e.g. highlighting)
|
||||
@ -1196,7 +1248,7 @@ pub fn reset_selection(&mut self, view_id: ViewId) {
|
||||
/// Initializes a new selection and view_data for the given view
|
||||
/// if it does not already have them.
|
||||
pub fn ensure_view_init(&mut self, view_id: ViewId) {
|
||||
if self.selections.get(&view_id).is_none() {
|
||||
if !self.selections.contains_key(&view_id) {
|
||||
self.reset_selection(view_id);
|
||||
}
|
||||
|
||||
@ -1225,34 +1277,12 @@ fn apply_impl(
|
||||
use helix_core::Assoc;
|
||||
|
||||
let old_doc = self.text().clone();
|
||||
let changes = transaction.changes();
|
||||
if !changes.apply(&mut self.text) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let success = transaction.changes().apply(&mut self.text);
|
||||
|
||||
if success {
|
||||
if emit_lsp_notification {
|
||||
helix_event::dispatch(DocumentDidChange {
|
||||
doc: self,
|
||||
view: view_id,
|
||||
old_text: &old_doc,
|
||||
});
|
||||
}
|
||||
|
||||
for selection in self.selections.values_mut() {
|
||||
*selection = selection
|
||||
.clone()
|
||||
// Map through changes
|
||||
.map(transaction.changes())
|
||||
// Ensure all selections across all views still adhere to invariants.
|
||||
.ensure_invariants(self.text.slice(..));
|
||||
}
|
||||
|
||||
for view_data in self.view_data.values_mut() {
|
||||
view_data.view_position.anchor = transaction
|
||||
.changes()
|
||||
.map_pos(view_data.view_position.anchor, Assoc::Before);
|
||||
}
|
||||
|
||||
// if specified, the current selection should instead be replaced by transaction.selection
|
||||
if changes.is_empty() {
|
||||
if let Some(selection) = transaction.selection() {
|
||||
self.selections.insert(
|
||||
view_id,
|
||||
@ -1263,129 +1293,160 @@ fn apply_impl(
|
||||
view: view_id,
|
||||
});
|
||||
}
|
||||
|
||||
self.modified_since_accessed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if !transaction.changes().is_empty() {
|
||||
self.version += 1;
|
||||
// start computing the diff in parallel
|
||||
if let Some(diff_handle) = &self.diff_handle {
|
||||
diff_handle.update_document(self.text.clone(), false);
|
||||
}
|
||||
self.modified_since_accessed = true;
|
||||
self.version += 1;
|
||||
|
||||
// generate revert to savepoint
|
||||
if !self.savepoints.is_empty() {
|
||||
let revert = transaction.invert(&old_doc);
|
||||
self.savepoints
|
||||
.retain_mut(|save_point| match save_point.upgrade() {
|
||||
Some(savepoint) => {
|
||||
let mut revert_to_savepoint = savepoint.revert.lock();
|
||||
*revert_to_savepoint =
|
||||
revert.clone().compose(mem::take(&mut revert_to_savepoint));
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
})
|
||||
}
|
||||
for selection in self.selections.values_mut() {
|
||||
*selection = selection
|
||||
.clone()
|
||||
// Map through changes
|
||||
.map(transaction.changes())
|
||||
// Ensure all selections across all views still adhere to invariants.
|
||||
.ensure_invariants(self.text.slice(..));
|
||||
}
|
||||
|
||||
// update tree-sitter syntax tree
|
||||
if let Some(syntax) = &mut self.syntax {
|
||||
// TODO: no unwrap
|
||||
let res = syntax.update(
|
||||
old_doc.slice(..),
|
||||
self.text.slice(..),
|
||||
transaction.changes(),
|
||||
);
|
||||
if res.is_err() {
|
||||
log::error!("TS parser failed, disabling TS for the current buffer: {res:?}");
|
||||
self.syntax = None;
|
||||
}
|
||||
}
|
||||
for view_data in self.view_data.values_mut() {
|
||||
view_data.view_position.anchor = transaction
|
||||
.changes()
|
||||
.map_pos(view_data.view_position.anchor, Assoc::Before);
|
||||
}
|
||||
|
||||
let changes = transaction.changes();
|
||||
|
||||
// map diagnostics over changes too
|
||||
changes.update_positions(self.diagnostics.iter_mut().map(|diagnostic| {
|
||||
let assoc = if diagnostic.starts_at_word {
|
||||
Assoc::BeforeWord
|
||||
} else {
|
||||
Assoc::After
|
||||
};
|
||||
(&mut diagnostic.range.start, assoc)
|
||||
}));
|
||||
changes.update_positions(self.diagnostics.iter_mut().filter_map(|diagnostic| {
|
||||
if diagnostic.zero_width {
|
||||
// for zero width diagnostics treat the diagnostic as a point
|
||||
// rather than a range
|
||||
return None;
|
||||
}
|
||||
let assoc = if diagnostic.ends_at_word {
|
||||
Assoc::AfterWord
|
||||
} else {
|
||||
Assoc::Before
|
||||
};
|
||||
Some((&mut diagnostic.range.end, assoc))
|
||||
}));
|
||||
self.diagnostics.retain_mut(|diagnostic| {
|
||||
if diagnostic.zero_width {
|
||||
diagnostic.range.end = diagnostic.range.start
|
||||
} else if diagnostic.range.start >= diagnostic.range.end {
|
||||
return false;
|
||||
}
|
||||
diagnostic.line = self.text.char_to_line(diagnostic.range.start);
|
||||
true
|
||||
});
|
||||
|
||||
self.diagnostics.sort_by_key(|diagnostic| {
|
||||
(diagnostic.range, diagnostic.severity, diagnostic.provider)
|
||||
});
|
||||
|
||||
// Update the inlay hint annotations' positions, helping ensure they are displayed in the proper place
|
||||
let apply_inlay_hint_changes = |annotations: &mut Vec<InlineAnnotation>| {
|
||||
changes.update_positions(
|
||||
annotations
|
||||
.iter_mut()
|
||||
.map(|annotation| (&mut annotation.char_idx, Assoc::After)),
|
||||
);
|
||||
};
|
||||
|
||||
self.inlay_hints_oudated = true;
|
||||
for text_annotation in self.inlay_hints.values_mut() {
|
||||
let DocumentInlayHints {
|
||||
id: _,
|
||||
type_inlay_hints,
|
||||
parameter_inlay_hints,
|
||||
other_inlay_hints,
|
||||
padding_before_inlay_hints,
|
||||
padding_after_inlay_hints,
|
||||
} = text_annotation;
|
||||
|
||||
apply_inlay_hint_changes(padding_before_inlay_hints);
|
||||
apply_inlay_hint_changes(type_inlay_hints);
|
||||
apply_inlay_hint_changes(parameter_inlay_hints);
|
||||
apply_inlay_hint_changes(other_inlay_hints);
|
||||
apply_inlay_hint_changes(padding_after_inlay_hints);
|
||||
}
|
||||
|
||||
if emit_lsp_notification {
|
||||
// TODO: move to hook
|
||||
// emit lsp notification
|
||||
for language_server in self.language_servers() {
|
||||
let notify = language_server.text_document_did_change(
|
||||
self.versioned_identifier(),
|
||||
&old_doc,
|
||||
self.text(),
|
||||
changes,
|
||||
);
|
||||
|
||||
if let Some(notify) = notify {
|
||||
tokio::spawn(notify);
|
||||
// generate revert to savepoint
|
||||
if !self.savepoints.is_empty() {
|
||||
let revert = transaction.invert(&old_doc);
|
||||
self.savepoints
|
||||
.retain_mut(|save_point| match save_point.upgrade() {
|
||||
Some(savepoint) => {
|
||||
let mut revert_to_savepoint = savepoint.revert.lock();
|
||||
*revert_to_savepoint =
|
||||
revert.clone().compose(mem::take(&mut revert_to_savepoint));
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
})
|
||||
}
|
||||
|
||||
// update tree-sitter syntax tree
|
||||
if let Some(syntax) = &mut self.syntax {
|
||||
// TODO: no unwrap
|
||||
let res = syntax.update(
|
||||
old_doc.slice(..),
|
||||
self.text.slice(..),
|
||||
transaction.changes(),
|
||||
);
|
||||
if res.is_err() {
|
||||
log::error!("TS parser failed, disabling TS for the current buffer: {res:?}");
|
||||
self.syntax = None;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: all of that should likely just be hooks
|
||||
// start computing the diff in parallel
|
||||
if let Some(diff_handle) = &self.diff_handle {
|
||||
diff_handle.update_document(self.text.clone(), false);
|
||||
}
|
||||
|
||||
// map diagnostics over changes too
|
||||
changes.update_positions(self.diagnostics.iter_mut().map(|diagnostic| {
|
||||
let assoc = if diagnostic.starts_at_word {
|
||||
Assoc::BeforeWord
|
||||
} else {
|
||||
Assoc::After
|
||||
};
|
||||
(&mut diagnostic.range.start, assoc)
|
||||
}));
|
||||
changes.update_positions(self.diagnostics.iter_mut().filter_map(|diagnostic| {
|
||||
if diagnostic.zero_width {
|
||||
// for zero width diagnostics treat the diagnostic as a point
|
||||
// rather than a range
|
||||
return None;
|
||||
}
|
||||
let assoc = if diagnostic.ends_at_word {
|
||||
Assoc::AfterWord
|
||||
} else {
|
||||
Assoc::Before
|
||||
};
|
||||
Some((&mut diagnostic.range.end, assoc))
|
||||
}));
|
||||
self.diagnostics.retain_mut(|diagnostic| {
|
||||
if diagnostic.zero_width {
|
||||
diagnostic.range.end = diagnostic.range.start
|
||||
} else if diagnostic.range.start >= diagnostic.range.end {
|
||||
return false;
|
||||
}
|
||||
diagnostic.line = self.text.char_to_line(diagnostic.range.start);
|
||||
true
|
||||
});
|
||||
|
||||
self.diagnostics
|
||||
.sort_by_key(|diagnostic| (diagnostic.range, diagnostic.severity, diagnostic.provider));
|
||||
|
||||
// Update the inlay hint annotations' positions, helping ensure they are displayed in the proper place
|
||||
let apply_inlay_hint_changes = |annotations: &mut Vec<InlineAnnotation>| {
|
||||
changes.update_positions(
|
||||
annotations
|
||||
.iter_mut()
|
||||
.map(|annotation| (&mut annotation.char_idx, Assoc::After)),
|
||||
);
|
||||
};
|
||||
|
||||
self.inlay_hints_oudated = true;
|
||||
for text_annotation in self.inlay_hints.values_mut() {
|
||||
let DocumentInlayHints {
|
||||
id: _,
|
||||
type_inlay_hints,
|
||||
parameter_inlay_hints,
|
||||
other_inlay_hints,
|
||||
padding_before_inlay_hints,
|
||||
padding_after_inlay_hints,
|
||||
} = text_annotation;
|
||||
|
||||
apply_inlay_hint_changes(padding_before_inlay_hints);
|
||||
apply_inlay_hint_changes(type_inlay_hints);
|
||||
apply_inlay_hint_changes(parameter_inlay_hints);
|
||||
apply_inlay_hint_changes(other_inlay_hints);
|
||||
apply_inlay_hint_changes(padding_after_inlay_hints);
|
||||
}
|
||||
|
||||
helix_event::dispatch(DocumentDidChange {
|
||||
doc: self,
|
||||
view: view_id,
|
||||
old_text: &old_doc,
|
||||
});
|
||||
|
||||
// if specified, the current selection should instead be replaced by transaction.selection
|
||||
if let Some(selection) = transaction.selection() {
|
||||
self.selections.insert(
|
||||
view_id,
|
||||
selection.clone().ensure_invariants(self.text.slice(..)),
|
||||
);
|
||||
helix_event::dispatch(SelectionDidChange {
|
||||
doc: self,
|
||||
view: view_id,
|
||||
});
|
||||
}
|
||||
|
||||
if emit_lsp_notification {
|
||||
// TODO: move to hook
|
||||
// emit lsp notification
|
||||
for language_server in self.language_servers() {
|
||||
let notify = language_server.text_document_did_change(
|
||||
self.versioned_identifier(),
|
||||
&old_doc,
|
||||
self.text(),
|
||||
changes,
|
||||
);
|
||||
|
||||
if let Some(notify) = notify {
|
||||
tokio::spawn(notify);
|
||||
}
|
||||
}
|
||||
}
|
||||
success
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn apply_inner(
|
||||
@ -1597,7 +1658,7 @@ pub fn reset_modified(&mut self) {
|
||||
}
|
||||
|
||||
/// Set the document's latest saved revision to the given one.
|
||||
pub fn set_last_saved_revision(&mut self, rev: usize) {
|
||||
pub fn set_last_saved_revision(&mut self, rev: usize, save_time: SystemTime) {
|
||||
log::debug!(
|
||||
"doc {} revision updated {} -> {}",
|
||||
self.id,
|
||||
@ -1605,7 +1666,7 @@ pub fn set_last_saved_revision(&mut self, rev: usize) {
|
||||
rev
|
||||
);
|
||||
self.last_saved_revision = rev;
|
||||
self.last_saved_time = SystemTime::now();
|
||||
self.last_saved_time = save_time;
|
||||
}
|
||||
|
||||
/// Get the document's latest saved revision.
|
||||
|
@ -1376,6 +1376,11 @@ pub fn move_path(&mut self, old_path: &Path, new_path: &Path) -> io::Result<()>
|
||||
}
|
||||
let is_dir = new_path.is_dir();
|
||||
for ls in self.language_servers.iter_clients() {
|
||||
// A new language server might have been started in `set_doc_path` and won't
|
||||
// be initialized yet. Skip the `did_rename` notification for this server.
|
||||
if !ls.is_initialized() {
|
||||
continue;
|
||||
}
|
||||
if let Some(notification) = ls.did_rename(old_path, &new_path, is_dir) {
|
||||
tokio::spawn(notification);
|
||||
};
|
||||
@ -2083,7 +2088,7 @@ pub async fn flush_writes(&mut self) -> anyhow::Result<()> {
|
||||
};
|
||||
|
||||
let doc = doc_mut!(self, &save_event.doc_id);
|
||||
doc.set_last_saved_revision(save_event.revision);
|
||||
doc.set_last_saved_revision(save_event.revision, save_event.save_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ pub async fn select_thread_id(editor: &mut Editor, thread_id: ThreadId, force: b
|
||||
debugger.thread_id = Some(thread_id);
|
||||
fetch_stack_trace(debugger, thread_id).await;
|
||||
|
||||
let frame = debugger.stack_frames[&thread_id].get(0).cloned();
|
||||
let frame = debugger.stack_frames[&thread_id].first().cloned();
|
||||
if let Some(frame) = &frame {
|
||||
jump_to_stack_frame(editor, frame);
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::editor::Action;
|
||||
use crate::Editor;
|
||||
use crate::{DocumentId, ViewId};
|
||||
@ -73,13 +75,13 @@ fn from(err: helix_core::uri::UrlConversionError) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for ApplyEditErrorKind {
|
||||
fn to_string(&self) -> String {
|
||||
impl Display for ApplyEditErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ApplyEditErrorKind::DocumentChanged => "document has changed".to_string(),
|
||||
ApplyEditErrorKind::FileNotFound => "file not found".to_string(),
|
||||
ApplyEditErrorKind::InvalidUrl(err) => err.to_string(),
|
||||
ApplyEditErrorKind::IoError(err) => err.to_string(),
|
||||
ApplyEditErrorKind::DocumentChanged => f.write_str("document has changed"),
|
||||
ApplyEditErrorKind::FileNotFound => f.write_str("file not found"),
|
||||
ApplyEditErrorKind::InvalidUrl(err) => f.write_str(&format!("{err}")),
|
||||
ApplyEditErrorKind::IoError(err) => f.write_str(&format!("{err}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,13 +241,23 @@ pub fn offset_coords_to_in_view_center<const CENTERING: bool>(
|
||||
let text_fmt = doc.text_format(viewport.width, None);
|
||||
let annotations = self.text_annotations(doc, None);
|
||||
|
||||
// - 1 so we have at least one gap in the middle.
|
||||
// a height of 6 with padding of 3 on each side will keep shifting the view back and forth
|
||||
// as we type
|
||||
let scrolloff = if CENTERING {
|
||||
0
|
||||
let (scrolloff_top, scrolloff_bottom) = if CENTERING {
|
||||
(0, 0)
|
||||
} else {
|
||||
scrolloff.min(viewport.height.saturating_sub(1) as usize / 2)
|
||||
(
|
||||
// - 1 from the top so we have at least one gap in the middle.
|
||||
scrolloff.min(viewport.height.saturating_sub(1) as usize / 2),
|
||||
scrolloff.min(viewport.height as usize / 2),
|
||||
)
|
||||
};
|
||||
let (scrolloff_left, scrolloff_right) = if CENTERING {
|
||||
(0, 0)
|
||||
} else {
|
||||
(
|
||||
// - 1 from the left so we have at least one gap in the middle.
|
||||
scrolloff.min(viewport.width.saturating_sub(1) as usize / 2),
|
||||
scrolloff.min(viewport.width as usize / 2),
|
||||
)
|
||||
};
|
||||
|
||||
let cursor = doc.selection(self.id).primary().cursor(doc_text);
|
||||
@ -262,14 +272,14 @@ pub fn offset_coords_to_in_view_center<const CENTERING: bool>(
|
||||
);
|
||||
|
||||
let (new_anchor, at_top) = match off {
|
||||
Ok((visual_pos, _)) if visual_pos.row < scrolloff + offset.vertical_offset => {
|
||||
Ok((visual_pos, _)) if visual_pos.row < scrolloff_top + offset.vertical_offset => {
|
||||
if CENTERING {
|
||||
// cursor out of view
|
||||
return None;
|
||||
}
|
||||
(true, true)
|
||||
}
|
||||
Ok((visual_pos, _)) if visual_pos.row + scrolloff >= vertical_viewport_end => {
|
||||
Ok((visual_pos, _)) if visual_pos.row + scrolloff_bottom >= vertical_viewport_end => {
|
||||
(true, false)
|
||||
}
|
||||
Ok((_, _)) => (false, false),
|
||||
@ -280,9 +290,9 @@ pub fn offset_coords_to_in_view_center<const CENTERING: bool>(
|
||||
|
||||
if new_anchor {
|
||||
let v_off = if at_top {
|
||||
scrolloff as isize
|
||||
scrolloff_top as isize
|
||||
} else {
|
||||
viewport.height as isize - scrolloff as isize - 1
|
||||
viewport.height as isize - scrolloff_bottom as isize - 1
|
||||
};
|
||||
(offset.anchor, offset.vertical_offset) =
|
||||
char_idx_at_visual_offset(doc_text, cursor, -v_off, 0, &text_fmt, &annotations);
|
||||
@ -306,12 +316,12 @@ pub fn offset_coords_to_in_view_center<const CENTERING: bool>(
|
||||
.col;
|
||||
|
||||
let last_col = offset.horizontal_offset + viewport.width.saturating_sub(1) as usize;
|
||||
if col > last_col.saturating_sub(scrolloff) {
|
||||
if col > last_col.saturating_sub(scrolloff_right) {
|
||||
// scroll right
|
||||
offset.horizontal_offset += col - (last_col.saturating_sub(scrolloff))
|
||||
} else if col < offset.horizontal_offset + scrolloff {
|
||||
offset.horizontal_offset += col - (last_col.saturating_sub(scrolloff_right))
|
||||
} else if col < offset.horizontal_offset + scrolloff_left {
|
||||
// scroll left
|
||||
offset.horizontal_offset = col.saturating_sub(scrolloff)
|
||||
offset.horizontal_offset = col.saturating_sub(scrolloff_left)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1533,7 +1533,7 @@ source = { git = "https://github.com/Flakebi/tree-sitter-tablegen", rev = "568dd
|
||||
name = "markdown"
|
||||
scope = "source.md"
|
||||
injection-regex = "md|markdown"
|
||||
file-types = ["md", "markdown", "mkd", "mkdn", "mdwn", "mdown", "markdn", "mdtxt", "mdtext", "workbook", { glob = "PULLREQ_EDITMSG" }]
|
||||
file-types = ["md", "markdown", "mdx", "mkd", "mkdn", "mdwn", "mdown", "markdn", "mdtxt", "mdtext", "workbook", { glob = "PULLREQ_EDITMSG" }]
|
||||
roots = [".marksman.toml"]
|
||||
language-servers = [ "marksman", "markdown-oxide" ]
|
||||
indent = { tab-width = 2, unit = " " }
|
||||
@ -1995,12 +1995,12 @@ shebangs = []
|
||||
roots = ["project.godot"]
|
||||
auto-format = true
|
||||
formatter = { command = "gdformat", args = ["-"] }
|
||||
comment-token = "#"
|
||||
comment-tokens = ["#", "##"]
|
||||
indent = { tab-width = 4, unit = "\t" }
|
||||
|
||||
[[grammar]]
|
||||
name = "gdscript"
|
||||
source = { git = "https://github.com/PrestonKnopp/tree-sitter-gdscript", rev = "a4b57cc3bcbfc24550e858159647e9238e7ad1ac" }
|
||||
source = { git = "https://github.com/PrestonKnopp/tree-sitter-gdscript", rev = "1f1e782fe2600f50ae57b53876505b8282388d77" }
|
||||
|
||||
[[language]]
|
||||
name = "godot-resource"
|
||||
@ -2015,7 +2015,7 @@ indent = { tab-width = 4, unit = "\t" }
|
||||
|
||||
[[grammar]]
|
||||
name = "godot-resource"
|
||||
source = { git = "https://github.com/PrestonKnopp/tree-sitter-godot-resource", rev = "b6ef0768711086a86b3297056f9ffb5cc1d77b4a" }
|
||||
source = { git = "https://github.com/PrestonKnopp/tree-sitter-godot-resource", rev = "2ffb90de47417018651fc3b970e5f6b67214dc9d" }
|
||||
|
||||
[[language]]
|
||||
name = "nu"
|
||||
@ -3073,7 +3073,7 @@ source = { git = "https://github.com/lefp/tree-sitter-opencl", rev = "8e1d24a570
|
||||
[[language]]
|
||||
name = "just"
|
||||
scope = "source.just"
|
||||
file-types = [{ glob = "justfile" }, { glob = "Justfile" }, { glob = ".justfile" }, { glob = ".Justfile" }]
|
||||
file-types = ["just", { glob = "justfile" }, { glob = "Justfile" }, { glob = ".justfile" }, { glob = ".Justfile" }]
|
||||
injection-regex = "just"
|
||||
comment-token = "#"
|
||||
indent = { tab-width = 4, unit = " " }
|
||||
@ -3082,7 +3082,7 @@ indent = { tab-width = 4, unit = " " }
|
||||
|
||||
[[grammar]]
|
||||
name = "just"
|
||||
source = { git = "https://github.com/IndianBoy42/tree-sitter-just", rev = "8af0aab79854aaf25b620a52c39485849922f766" }
|
||||
source = { git = "https://github.com/IndianBoy42/tree-sitter-just", rev = "379fbe36d1e441bc9414ea050ad0c85c9d6935ea" }
|
||||
|
||||
[[language]]
|
||||
name = "gn"
|
||||
@ -3203,6 +3203,19 @@ grammar = "jinja2"
|
||||
name = "jinja2"
|
||||
source = { git = "https://github.com/varpeti/tree-sitter-jinja2", rev = "a533cd3c33aea6acb0f9bf9a56f35dcfe6a8eb53" }
|
||||
|
||||
[[language]]
|
||||
name = "jjdescription"
|
||||
scope = "jj.description"
|
||||
file-types = [{ glob = "*.jjdescription" }]
|
||||
comment-token = "JJ:"
|
||||
indent = { tab-width = 2, unit = " " }
|
||||
rulers = [51, 73]
|
||||
text-width = 72
|
||||
|
||||
[[grammar]]
|
||||
name = "jjdescription"
|
||||
source = { git = "https://github.com/kareigu/tree-sitter-jjdescription", rev = "2ddec6cad07b366aee276a608e1daa2c29d3caf2" }
|
||||
|
||||
[[grammar]]
|
||||
name = "wren"
|
||||
source = { git = "https://git.sr.ht/~jummit/tree-sitter-wren", rev = "6748694be32f11e7ec6b5faeb1b48ca6156d4e06" }
|
||||
@ -3477,7 +3490,7 @@ name = "tcl"
|
||||
scope = "source.tcl"
|
||||
injection-regex = "tcl"
|
||||
file-types = [ "tcl" ]
|
||||
shebangs = [ "tclish", "jimsh", "wish" ]
|
||||
shebangs = [ "tclsh", "tclish", "jimsh", "wish" ]
|
||||
comment-token = '#'
|
||||
|
||||
[[grammar]]
|
||||
|
@ -14,6 +14,7 @@
|
||||
(attribute_call (identifier) @function)
|
||||
(base_call (identifier) @function)
|
||||
(call (identifier) @function)
|
||||
(lambda (name) @function)
|
||||
|
||||
; Function definitions
|
||||
|
||||
@ -88,6 +89,7 @@
|
||||
"<<"
|
||||
">>"
|
||||
":="
|
||||
":"
|
||||
] @operator
|
||||
|
||||
(annotation (identifier) @keyword.storage.modifier)
|
||||
@ -97,6 +99,7 @@
|
||||
"else"
|
||||
"elif"
|
||||
"match"
|
||||
"when"
|
||||
] @keyword.control.conditional
|
||||
|
||||
[
|
||||
|
@ -6,6 +6,7 @@
|
||||
(pattern_section)
|
||||
|
||||
(function_definition)
|
||||
(lambda)
|
||||
(constructor_definition)
|
||||
(class_definition)
|
||||
(enum_definition)
|
||||
|
@ -5,6 +5,8 @@
|
||||
(function_definition
|
||||
(body) @function.inside) @function.around
|
||||
|
||||
(lambda (body) @function.inside) @function.around
|
||||
|
||||
(parameters
|
||||
[
|
||||
(identifier)
|
||||
@ -15,5 +17,12 @@
|
||||
|
||||
(arguments (_expression) @parameter.inside @parameter.around)
|
||||
|
||||
[
|
||||
(const_statement)
|
||||
(variable_statement)
|
||||
(pair)
|
||||
(enumerator)
|
||||
] @entry.around
|
||||
|
||||
(comment) @comment.inside
|
||||
(comment)+ @comment.around
|
||||
|
@ -11,8 +11,41 @@
|
||||
(property
|
||||
(path) @_is_code
|
||||
(string) @injection.content))
|
||||
(#match? @_type "type")
|
||||
(#eq? @_type "type")
|
||||
(#match? @_is_shader "Shader")
|
||||
(#eq? @_is_code "code")
|
||||
(#set! injection.language "glsl")
|
||||
)
|
||||
|
||||
((section
|
||||
(identifier) @_is_resource
|
||||
(property
|
||||
(path) @_is_code
|
||||
(string) @injection.content))
|
||||
(#eq? @_is_resource "resource")
|
||||
(#eq? @_is_code "code")
|
||||
(#set! injection.language "glsl")
|
||||
)
|
||||
|
||||
((section
|
||||
(identifier) @_id
|
||||
(property
|
||||
(path) @_is_expression
|
||||
(string) @injection.content))
|
||||
(#eq? @_id "sub_resource")
|
||||
(#eq? @_is_expression "expression")
|
||||
(#set! injection.language "glsl")
|
||||
)
|
||||
|
||||
((section
|
||||
(attribute
|
||||
(identifier) @_type
|
||||
(string) @_is_shader)
|
||||
(property
|
||||
(path) @_is_code
|
||||
(string) @injection.content))
|
||||
(#eq? @_type "type")
|
||||
(#match? @_is_shader "GDScript")
|
||||
(#eq? @_is_code "script/source")
|
||||
(#set! injection.language "gdscript")
|
||||
)
|
||||
|
23
runtime/queries/godot-resource/textobjects.scm
Normal file
23
runtime/queries/godot-resource/textobjects.scm
Normal file
@ -0,0 +1,23 @@
|
||||
(section
|
||||
(identifier)
|
||||
(_)
|
||||
(property) @class.inside
|
||||
) @class.around
|
||||
|
||||
(attribute
|
||||
(identifier)
|
||||
(_) @parameter.inside) @parameter.around
|
||||
|
||||
(property
|
||||
(path)
|
||||
(_) @entry.inside) @entry.around
|
||||
|
||||
(pair
|
||||
(_) @entry.inside) @entry.around
|
||||
|
||||
(array
|
||||
(_) @entry.around)
|
||||
|
||||
(comment) @comment.inside
|
||||
|
||||
(comment)+ @comment.around
|
8
runtime/queries/jjdescription/highlights.scm
Normal file
8
runtime/queries/jjdescription/highlights.scm
Normal file
@ -0,0 +1,8 @@
|
||||
(text) @string
|
||||
(filepath) @string.special.path
|
||||
|
||||
(change type: "A" @diff.plus)
|
||||
(change type: "D" @diff.minus)
|
||||
(change type: "M" @diff.delta)
|
||||
|
||||
(comment) @comment
|
@ -1,4 +1,10 @@
|
||||
(body) @fold
|
||||
(recipe) @fold
|
||||
(interpolation) @fold
|
||||
(item (_) @fold)
|
||||
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/folds.scm>
|
||||
|
||||
; Define collapse points
|
||||
|
||||
([
|
||||
(recipe)
|
||||
(string)
|
||||
(external_command)
|
||||
] @fold
|
||||
(#trim! @fold))
|
||||
|
@ -1,33 +1,149 @@
|
||||
(assignment (NAME) @variable)
|
||||
(alias (NAME) @variable)
|
||||
(value (NAME) @variable)
|
||||
(parameter (NAME) @variable)
|
||||
(setting (NAME) @keyword)
|
||||
(setting "shell" @keyword)
|
||||
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/highlights.scm>
|
||||
|
||||
(call (NAME) @function)
|
||||
(dependency (NAME) @function)
|
||||
(depcall (NAME) @function)
|
||||
(recipeheader (NAME) @function)
|
||||
; This file specifies how matched syntax patterns should be highlighted
|
||||
|
||||
(depcall (expression) @variable.parameter)
|
||||
(parameter) @variable.parameter
|
||||
(variadic_parameters) @variable.parameter
|
||||
[
|
||||
"export"
|
||||
"import"
|
||||
] @keyword.control.import
|
||||
|
||||
["if" "else"] @keyword.control.conditional
|
||||
"mod" @keyword.directive
|
||||
|
||||
(string) @string
|
||||
[
|
||||
"alias"
|
||||
"set"
|
||||
"shell"
|
||||
] @keyword
|
||||
|
||||
(boolean ["true" "false"]) @constant.builtin.boolean
|
||||
[
|
||||
"if"
|
||||
"else"
|
||||
] @keyword.control.conditional
|
||||
|
||||
(comment) @comment
|
||||
; Variables
|
||||
|
||||
; (interpolation) @string
|
||||
(value
|
||||
(identifier) @variable)
|
||||
|
||||
(shebang interpreter:(TEXT) @keyword ) @comment
|
||||
(alias
|
||||
left: (identifier) @variable)
|
||||
|
||||
["export" "alias" "set"] @keyword
|
||||
(assignment
|
||||
left: (identifier) @variable)
|
||||
|
||||
["@" "==" "!=" "+" ":="] @operator
|
||||
; Functions
|
||||
|
||||
[ "(" ")" "[" "]" "{{" "}}" "{" "}"] @punctuation.bracket
|
||||
(recipe_header
|
||||
name: (identifier) @function)
|
||||
|
||||
(dependency
|
||||
name: (identifier) @function)
|
||||
|
||||
(dependency_expression
|
||||
name: (identifier) @function)
|
||||
|
||||
(function_call
|
||||
name: (identifier) @function)
|
||||
|
||||
; Parameters
|
||||
|
||||
(parameter
|
||||
name: (identifier) @variable.parameter)
|
||||
|
||||
; Namespaces
|
||||
|
||||
(module
|
||||
name: (identifier) @namespace)
|
||||
|
||||
; Operators
|
||||
|
||||
[
|
||||
":="
|
||||
"?"
|
||||
"=="
|
||||
"!="
|
||||
"=~"
|
||||
"@"
|
||||
"="
|
||||
"$"
|
||||
"*"
|
||||
"+"
|
||||
"&&"
|
||||
"@-"
|
||||
"-@"
|
||||
"-"
|
||||
"/"
|
||||
":"
|
||||
] @operator
|
||||
|
||||
; Punctuation
|
||||
|
||||
"," @punctuation.delimiter
|
||||
|
||||
[
|
||||
"{"
|
||||
"}"
|
||||
"["
|
||||
"]"
|
||||
"("
|
||||
")"
|
||||
"{{"
|
||||
"}}"
|
||||
] @punctuation.bracket
|
||||
|
||||
[ "`" "```" ] @punctuation.special
|
||||
|
||||
; Literals
|
||||
|
||||
(boolean) @constant.builtin.boolean
|
||||
|
||||
[
|
||||
(string)
|
||||
(external_command)
|
||||
] @string
|
||||
|
||||
(escape_sequence) @constant.character.escape
|
||||
|
||||
; Comments
|
||||
|
||||
(comment) @comment.line
|
||||
|
||||
(shebang) @keyword.directive
|
||||
|
||||
; highlight known settings (filtering does not always work)
|
||||
(setting
|
||||
left: (identifier) @keyword
|
||||
(#any-of? @keyword
|
||||
"allow-duplicate-recipes"
|
||||
"dotenv-filename"
|
||||
"dotenv-load"
|
||||
"dotenv-path"
|
||||
"export"
|
||||
"fallback"
|
||||
"ignore-comments"
|
||||
"positional-arguments"
|
||||
"shell"
|
||||
"tempdi"
|
||||
"windows-powershell"
|
||||
"windows-shell"))
|
||||
|
||||
; highlight known attributes (filtering does not always work)
|
||||
(attribute
|
||||
(identifier) @attribute
|
||||
(#any-of? @attribute
|
||||
"private"
|
||||
"allow-duplicate-recipes"
|
||||
"dotenv-filename"
|
||||
"dotenv-load"
|
||||
"dotenv-path"
|
||||
"export"
|
||||
"fallback"
|
||||
"ignore-comments"
|
||||
"positional-arguments"
|
||||
"shell"
|
||||
"tempdi"
|
||||
"windows-powershell"
|
||||
"windows-shell"))
|
||||
|
||||
; Numbers are part of the syntax tree, even if disallowed
|
||||
(numeric_error) @error
|
||||
|
@ -1,3 +1,11 @@
|
||||
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/indents.scm>
|
||||
;
|
||||
; This query specifies how to auto-indent logical blocks.
|
||||
;
|
||||
; Better documentation with diagrams is in https://docs.helix-editor.com/guides/indent.html
|
||||
|
||||
[
|
||||
(recipe_body)
|
||||
] @indent
|
||||
(recipe)
|
||||
(string)
|
||||
(external_command)
|
||||
] @indent @extend
|
||||
|
@ -1,16 +1,84 @@
|
||||
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/injections.scm>
|
||||
;
|
||||
; Specify nested languages that live within a `justfile`
|
||||
|
||||
; ================ Always applicable ================
|
||||
|
||||
((comment) @injection.content
|
||||
(#set! injection.language "comment"))
|
||||
(#set! injection.language "comment"))
|
||||
|
||||
(shebang_recipe
|
||||
(shebang
|
||||
interpreter:(TEXT) @injection.language)
|
||||
(shebang_body) @injection.content
|
||||
)
|
||||
; Highlight the RHS of `=~` as regex
|
||||
((regex_literal
|
||||
(_) @injection.content)
|
||||
(#set! injection.language "regex"))
|
||||
|
||||
(source_file
|
||||
(item (setting lang:(NAME) @injection.language))
|
||||
(item (recipe (body (recipe_body) @injection.content)))
|
||||
)
|
||||
; ================ Global defaults ================
|
||||
|
||||
; ((interpolation (expression) @injection.content)
|
||||
; (#set! injection.language "just"))
|
||||
; Default everything to be bash
|
||||
(recipe_body
|
||||
!shebang
|
||||
(#set! injection.language "bash")
|
||||
(#set! injection.include-children)) @injection.content
|
||||
|
||||
(external_command
|
||||
(command_body) @injection.content
|
||||
(#set! injection.language "bash"))
|
||||
|
||||
; ================ Global language specified ================
|
||||
; Global language is set with something like one of the following:
|
||||
;
|
||||
; set shell := ["bash", "-c", ...]
|
||||
; set shell := ["pwsh.exe"]
|
||||
;
|
||||
; We can extract the first item of the array, but we can't extract the language
|
||||
; name from the string with something like regex. So instead we special case
|
||||
; two things: powershell, which is likely to come with a `.exe` attachment that
|
||||
; we need to strip, and everything else which hopefully has no extension. We
|
||||
; separate this with a `#match?`.
|
||||
;
|
||||
; Unfortunately, there also isn't a way to allow arbitrary nesting or
|
||||
; alternatively set "global" capture variables. So we can set this for item-
|
||||
; level external commands, but not for e.g. external commands within an
|
||||
; expression without getting _really_ annoying. Should at least look fine since
|
||||
; they default to bash. Limitations...
|
||||
; See https://github.com/tree-sitter/tree-sitter/issues/880 for more on that.
|
||||
|
||||
(source_file
|
||||
(setting "shell" ":=" "[" (string) @_langstr
|
||||
(#match? @_langstr ".*(powershell|pwsh|cmd).*")
|
||||
(#set! injection.language "powershell"))
|
||||
[
|
||||
(recipe
|
||||
(recipe_body
|
||||
!shebang
|
||||
(#set! injection.include-children)) @injection.content)
|
||||
|
||||
(assignment
|
||||
(expression
|
||||
(value
|
||||
(external_command
|
||||
(command_body) @injection.content))))
|
||||
])
|
||||
|
||||
(source_file
|
||||
(setting "shell" ":=" "[" (string) @injection.language
|
||||
(#not-match? @injection.language ".*(powershell|pwsh|cmd).*"))
|
||||
[
|
||||
(recipe
|
||||
(recipe_body
|
||||
!shebang
|
||||
(#set! injection.include-children)) @injection.content)
|
||||
|
||||
(assignment
|
||||
(expression
|
||||
(value
|
||||
(external_command
|
||||
(command_body) @injection.content))))
|
||||
])
|
||||
|
||||
; ================ Recipe language specified - Helix only ================
|
||||
|
||||
; Set highlighting for recipes that specify a language using builtin shebang matching
|
||||
(recipe_body
|
||||
(shebang) @injection.shebang
|
||||
(#set! injection.include-children)) @injection.content
|
||||
|
@ -1,10 +1,42 @@
|
||||
(assignment (NAME) @local.definition)
|
||||
(alias left:(NAME) @local.definition)
|
||||
(alias right:(NAME) @local.reference)
|
||||
(value (NAME) @local.reference)
|
||||
(parameter (NAME) @local.definition)
|
||||
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/locals.scm>
|
||||
;
|
||||
; This file tells us about the scope of variables so e.g. local
|
||||
; variables override global functions with the same name
|
||||
|
||||
(call (NAME) @local.reference)
|
||||
(dependency (NAME) @local.reference)
|
||||
(depcall (NAME) @local.reference)
|
||||
(recipeheader (NAME) @local.definition)
|
||||
; Scope
|
||||
|
||||
(recipe) @local.scope
|
||||
|
||||
; Definitions
|
||||
|
||||
(alias
|
||||
left: (identifier) @local.definition)
|
||||
|
||||
(assignment
|
||||
left: (identifier) @local.definition)
|
||||
|
||||
(module
|
||||
name: (identifier) @local.definition)
|
||||
|
||||
(parameter
|
||||
name: (identifier) @local.definition)
|
||||
|
||||
(recipe_header
|
||||
name: (identifier) @local.definition)
|
||||
|
||||
; References
|
||||
|
||||
(alias
|
||||
right: (identifier) @local.reference)
|
||||
|
||||
(function_call
|
||||
name: (identifier) @local.reference)
|
||||
|
||||
(dependency
|
||||
name: (identifier) @local.reference)
|
||||
|
||||
(dependency_expression
|
||||
name: (identifier) @local.reference)
|
||||
|
||||
(value
|
||||
(identifier) @local.reference)
|
||||
|
@ -1,48 +1,18 @@
|
||||
(body) @function.inside
|
||||
(recipe) @function.around
|
||||
(expression
|
||||
if:(expression) @function.inside
|
||||
)
|
||||
(expression
|
||||
else:(expression) @function.inside
|
||||
)
|
||||
(interpolation (expression) @function.inside) @function.around
|
||||
(settinglist (stringlist) @function.inside) @function.around
|
||||
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/textobjects.scm>
|
||||
;
|
||||
; Specify how to navigate around logical blocks in code
|
||||
|
||||
(call (NAME) @class.inside) @class.around
|
||||
(dependency (NAME) @class.inside) @class.around
|
||||
(depcall (NAME) @class.inside)
|
||||
(recipe
|
||||
(recipe_body) @function.inside) @function.around
|
||||
|
||||
(dependency) @parameter.around
|
||||
(depcall) @parameter.inside
|
||||
(depcall (expression) @parameter.inside)
|
||||
(parameters
|
||||
((_) @parameter.inside . ","? @parameter.around)) @parameter.around
|
||||
|
||||
(stringlist
|
||||
(string) @parameter.inside
|
||||
. ","? @_end
|
||||
; Commented out since we don't support `#make-range!` at the moment
|
||||
; (#make-range! "parameter.around" @parameter.inside @_end)
|
||||
)
|
||||
(parameters
|
||||
[(parameter)
|
||||
(variadic_parameters)] @parameter.inside
|
||||
. " "? @_end
|
||||
; Commented out since we don't support `#make-range!` at the moment
|
||||
; (#make-range! "parameter.around" @parameter.inside @_end)
|
||||
)
|
||||
(dependency_expression
|
||||
(_) @parameter.inside) @parameter.around
|
||||
|
||||
(expression
|
||||
(condition) @function.inside
|
||||
) @function.around
|
||||
(expression
|
||||
if:(expression) @function.inside
|
||||
)
|
||||
(expression
|
||||
else:(expression) @function.inside
|
||||
)
|
||||
|
||||
(item [(alias) (assignment) (export) (setting)]) @class.around
|
||||
(recipeheader) @class.around
|
||||
(line) @class.around
|
||||
(function_call
|
||||
arguments: (sequence
|
||||
(expression) @parameter.inside) @parameter.around) @function.around
|
||||
|
||||
(comment) @comment.around
|
||||
|
165
runtime/themes/ao.toml
Normal file
165
runtime/themes/ao.toml
Normal file
@ -0,0 +1,165 @@
|
||||
# Theme: Ao
|
||||
# Author: YardQuit
|
||||
|
||||
# SYNTAX HIGHLIGHTING
|
||||
"attribute" = { fg = "yellow" }
|
||||
"type" = { fg = "white" }
|
||||
"type.builtin" = { fg = "white" }
|
||||
"type.parameter" = { fg = "white" }
|
||||
"type.enum" = { fg = "white" }
|
||||
"type.enum.variant" = { fg = "white" }
|
||||
"constructor" = { fg = "orange" }
|
||||
"constant" = { fg = "blue" }
|
||||
"constant.character.escape" = { fg = "yellow" }
|
||||
"string" = { fg = "blue" }
|
||||
"string.regexp" = { fg = "yellow" }
|
||||
"comment" = { fg = "gray" }
|
||||
"variable" = { fg = "orange" }
|
||||
"variable.parameter" = { fg = "yellow" }
|
||||
"variable.other" = { fg = "green" }
|
||||
"variable.other.member" = { fg = "green" }
|
||||
"label" = { fg = "blue" }
|
||||
"punctuation" = { fg = "white" }
|
||||
"punctuation.bracket" = { fg = "orange" }
|
||||
"punctuation.special" = { fg = "yellow" }
|
||||
"keyword" = { fg = "red" }
|
||||
"keyword.operator" = { fg = "blue" }
|
||||
"keyword.directive" = { fg = "white" }
|
||||
"keyword.function" = { fg = "red" }
|
||||
"keyword.storage" = { fg = "red" }
|
||||
"keyword.storage.modifier" = { fg = "green" }
|
||||
"operator" = { fg = "white" }
|
||||
"function" = { fg = "purple" }
|
||||
"function.method" = { fg = "green" }
|
||||
"function.macro" = { fg = "green" }
|
||||
"function.special" = { fg = "yellow" }
|
||||
"tag" = { fg = "green" }
|
||||
"namespace" = { fg = "white" }
|
||||
"diff" = { fg = "white" }
|
||||
"diff.minus" = { fg = "red" }
|
||||
"diff.delta" = { fg = "brown" }
|
||||
|
||||
# MARKUP, SYNAX HIGHLIGHTING AND INTERFACE HYBRID
|
||||
"markup.heading" = { fg = "blaze_orange" }
|
||||
"markup.heading.1" = { fg = "crystal_blue", modifiers = ["bold"] }
|
||||
"markup.heading.2" = { fg = "sky_blue", modifiers = ["bold"] }
|
||||
"markup.heading.3" = { fg = "dreamy_blue", modifiers = ["bold"] }
|
||||
"markup.heading.4" = { fg = "crystal_blue" }
|
||||
"markup.heading.5" = { fg = "sky_blue" }
|
||||
"markup.heading.6" = { fg = "dreamy_blue" }
|
||||
"markup.list" = { fg = "blaze_orange" }
|
||||
"markup.bold" = { fg = "crystal_blue", modifiers = ["bold"] }
|
||||
"markup.italic" = { fg = "crystal_blue", modifiers = ["italic"] }
|
||||
"markup.strikethrough" = { fg = "crystal_blue", modifiers = ["crossed_out"] }
|
||||
"markup.link" = { fg = "crystal_blue", underline = { color = "light_purple", style = "line" } }
|
||||
"markup.link.url" = { fg = "slate_purple", underline = { color = "slate_purple", style = "line" } }
|
||||
"markup.link.label" = { fg = "crystal_blue" }
|
||||
"markup.link.text" = { fg = "crystal_blue", modifiers = ["bold"] }
|
||||
"markup.quote" = { fg = "winter_sky", modifiers = ["italic"] }
|
||||
"markup.raw" = { fg = "winter_sky" }
|
||||
"markup.raw.block" = { fg = "white" }
|
||||
|
||||
# USER INTERFACE
|
||||
"ui.background" = { bg = "deep_abyss"} # workspace background
|
||||
"ui.background.separator" = { fg = "winter_sky" } # picker separator below input line (space + j)
|
||||
"ui.gutter" = { bg = "deep_abyss" } # gutter
|
||||
"ui.gutter.selected" = { bg = "pitch_black" } # gutter for the line the cursor is on
|
||||
"ui.linenr" = { fg = "slate_gray" } # line numbers
|
||||
"ui.linenr.selected" = { fg = "blaze_orange", modifiers = ["bold"] } # line number for the line the cursor is on
|
||||
"ui.statusline" = { fg = "winter_sky", bg = "twilight_blue" } # statusline, fucused
|
||||
"ui.statusline.inactive" = { fg = "slate_gray", bg = "pitch_black" } # statusline, unfocused
|
||||
"ui.statusline.normal" = { fg = "deep_abyss", bg = "leafy_green", modifiers = ["bold"] } # statusline normal mode (if editor.color-modes is enabled)
|
||||
"ui.statusline.insert" = { fg = "deep_abyss", bg = "blaze_orange", modifiers = ["bold"] } # statusline insert mode (if editor.color-modes is enabled)
|
||||
"ui.statusline.select" = { fg = "deep_abyss", bg = "sky_blue", modifiers = ["bold"] } # statusline select mode (if editor.color-modes is enabled)
|
||||
"ui.statusline.separator" = { fg = "winter_sky" } # separator character is statusline
|
||||
"ui.bufferline" = { fg = "slate_gray", modifiers = ["bold"] } # bufferline inactive tab
|
||||
"ui.bufferline.active" = { fg = "winter_sky", bg = "twilight_blue" } # bufferline active tab
|
||||
"ui.bufferline.background" = { bg = "pitch_black" } # bufferline background
|
||||
"ui.virtual.ruler" = { bg = "stormy_night" } # ruler columns
|
||||
"ui.virtual.whitespace" = { fg = "stormy_night" } # whitespace characters
|
||||
"ui.virtual.indent-guide" = { fg = "stormy_night" } # vertical indent width guides
|
||||
"ui.virtual.inlay-hint" = { fg = "slate_gray" } # inlay hints of all kinds
|
||||
"ui.virtual.inlay-hint.parameter" = { fg = "slate_gray" } # inlay hints of kind parameter (lsps are not required to set a kind)
|
||||
"ui.virtual.inlay-hint.type" = { fg = "slate_gray" } # inlay hints of kind type (lsps are not required to set a kind)
|
||||
"ui.virtual.wrap" = { fg = "slate_gray" } # soft-wrap indicator
|
||||
"ui.virtual.jump-label" = { modifiers = ["reversed"] } # virtual jump labels (g + w)
|
||||
"ui.selection" = { bg = "deep_purple" } # slave selections in the editing area
|
||||
"ui.selection.primary" = { bg = "light_purple" } # primary selection in the editing area
|
||||
"ui.cursor" = { modifiers = ["reversed"] } # only if "ui.cursor.primary.normal" isn't set
|
||||
"ui.cursor.normal" = { fg = "winter_sky", bg = "twilight_blue" } # slave cursor block in normal mode
|
||||
"ui.cursor.insert" = { bg = "rustic_red" } # slave cursor block in insert mode
|
||||
"ui.cursor.select" = { bg = "deep_purple" } # slave cursor block in select mode
|
||||
"ui.cursor.match" = { fg = "deep_abyss", bg = "blaze_orange", modifiers = ["bold"] } # matching bracket etc
|
||||
"ui.cursor.primary" = { modifiers = ["reversed"] } # cursor with primary selection (has no effect due to "ui.cursor.primary.normal" is set)
|
||||
"ui.cursor.primary.normal" = { fg = "deep_abyss", bg = "sky_blue" } # cursor block in normal mode
|
||||
"ui.cursor.primary.insert" = { fg = "deep_abyss", bg = "ruby_glow" } # cursor block in insert mode
|
||||
"ui.cursor.primary.select" = { fg = "winter_sky", bg = "deep_purple" } # cursor block in select mode (not the selected color)
|
||||
"ui.cursorline.primary" = { bg = "nightfall_blue" } # line of the primary cursor
|
||||
"ui.cursorline.secondary" = { bg = "midnight_thunder"} # lines of secondary cursors
|
||||
"ui.cursorcolumn.primary" = { bg = "nightfall_blue" } # column of the primary cursor
|
||||
"ui.cursorcolumn.secondary" = { bg = "midnight_thunder" } # columns of secondary cursors
|
||||
|
||||
# USER INTERFACE - MENUS AND POPUP
|
||||
"ui.popup" = { fg = "winter_sky", bg = "midnight_thunder" } # documentation popups (space + k)
|
||||
"ui.popup.info" = { fg = "winter_sky", bg = "nightfall_blue" } # prompt for multiple key options, menu border (space, g, z, m, etc)
|
||||
"ui.window" = { fg = "slate_gray" } # borderlines separating splits
|
||||
"ui.help" = { fg = "winter_sky", bg = "nightfall_blue" } # description box for commands
|
||||
"ui.text" = { fg = "white" } # default text style, command prompts, popup text, etc
|
||||
"ui.text.focus" = { fg = "dreamy_blue" } # the currently selected line in the picker (space j, space f, space s, etc)
|
||||
"ui.text.inactive" = { fg = "slate_gray" } # same as ui.text but when the text is inactive e.g. suggestions
|
||||
"ui.text.info" = { fg = "winter_sky", bg = "nightfall_blue" } # the key: command in ui.popup.info boxes (space, g, z, m, etc)
|
||||
"ui.menu" = { fg = "winter_sky", bg = "midnight_thunder" } # code and command completion menus ":"
|
||||
"ui.menu.selected" = { fg = "winter_sky", bg = "twilight_blue" } # selected autocomplete item
|
||||
"ui.menu.scroll" = { fg = "crystal_blue", bg = "moonlight_ocean" } # scrollbar
|
||||
"ui.highlight" = { underline = { color = "sky_blue", style = "line" } } # highlighted lines in the picker preview
|
||||
|
||||
# USER INTERFACE - DIAGNOSTICS
|
||||
"warning" = { fg = "lemon_zest" } # diagnostics warning (gutter)
|
||||
"error" = { fg = "ruby_glow" } # diagnostics error (gutter)
|
||||
"info" = { fg = "sky_blue" } # diagnostics info (gutter)
|
||||
"hint" = { fg = "walnut_brown" } # diagnostics hint (gutter)
|
||||
"diagnostic" = { modifiers = ["reversed"] } # diagnostics fallback style (editing area)
|
||||
"diagnostic.hint" = { fg = "deep_abyss", bg = "walnut_brown" } # diagnostics hint (editing area)
|
||||
"diagnostic.info" = { fg = "winter_sky", bg = "twilight_blue" } # diagnostics info (editing area)
|
||||
"diagnostic.warning" = { fg = "winter_sky", bg = "rustic_amber" } # diagnostics warning (editing area)
|
||||
"diagnostic.error" = { fg = "winter_sky", bg = "rustic_red" } # diagnostics error (editing area)
|
||||
|
||||
# COLOR NAMES
|
||||
[palette]
|
||||
# PALETTE USER INTERFACE
|
||||
deep_abyss = "#080d15"
|
||||
stormy_night = "#254862"
|
||||
nightfall_blue = "#1f2937"
|
||||
midnight_thunder = "#0d1526"
|
||||
twilight_blue = "#2c5484"
|
||||
pitch_black = "#000000"
|
||||
winter_sky = "#f3f4f6"
|
||||
slate_gray = "#838a97"
|
||||
blaze_orange = "#ff9000"
|
||||
lemon_zest = "#ffba00"
|
||||
leafy_green = "#81be83"
|
||||
dreamy_blue = "#6eb0ff"
|
||||
crystal_blue = "#99c7ff"
|
||||
sky_blue = "#45b1e8"
|
||||
moonlight_ocean = "#0c1420"
|
||||
rustic_red = "#540b0c"
|
||||
ruby_glow = "#fa7970"
|
||||
walnut_brown = "#987654"
|
||||
rustic_amber = "#9d5800"
|
||||
slate_purple = "#d2a8ff"
|
||||
light_purple = "#7533bd"
|
||||
deep_purple = "#4c1785"
|
||||
|
||||
# SYNTAX HIGHLIGHTING
|
||||
black = "#0d1117"
|
||||
red = "#fa7970"
|
||||
green = "#81be83"
|
||||
yellow = "#ffba00"
|
||||
orange = "#ff9000"
|
||||
blue = "#45b1e8"
|
||||
purple = "#d2a8ff"
|
||||
brown = "#987654"
|
||||
gray = "#838a97"
|
||||
white = "#dadada"
|
||||
|
||||
|
@ -988,6 +988,28 @@ lines.
|
||||
|
||||
|
||||
|
||||
=================================================================
|
||||
= 9.4 JUMP WITH TWO-CHARACTER LABELS =
|
||||
=================================================================
|
||||
|
||||
Type gw to enable the 2-character labels. The start of each word
|
||||
will be replaced by 2 highlighted characters. Type any sequence
|
||||
of 2 highlighted characters to jump to the corresponding label,
|
||||
or use ESC to drop the labels.
|
||||
|
||||
The 2-character labels allow you to quickly jump to any location
|
||||
in the viewable selection.
|
||||
|
||||
1. Move the cursor to the start of the line marked '-->' below.
|
||||
2. Press gw to enable the 2-character labels, and then the two
|
||||
characters that replace the two letters he at the start of
|
||||
here to jump to the corresponding word.
|
||||
|
||||
--> This is just a simple line of text.
|
||||
There may be many such lines
|
||||
But you really want to jump here!
|
||||
This is fast with the 2-character labels.
|
||||
|
||||
=================================================================
|
||||
= CHAPTER 9 RECAP =
|
||||
=================================================================
|
||||
@ -1001,8 +1023,8 @@ lines.
|
||||
* Press Ctrl-i and Ctrl-o to go forward and backward in the
|
||||
jumplist.
|
||||
|
||||
|
||||
|
||||
* Type gw to enable 2-character labels, and any 2 characters to
|
||||
jump to the corresponding label, or ESC to drop the labels.
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user