diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4cddcb3..54e93c4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -89,5 +89,5 @@ jobs: env: VSCE_PAT: ${{ secrets.VSCE_ACCESS_TOKEN }} run: | - make package + make CARGO_FLAGS=--release package just release ${{ steps.new_version.outputs.value }} diff --git a/.gitignore b/.gitignore index 9a22832..8f43650 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ **/target **/node_modules -**/out +out yarn-error.log .vscode-test *.vsix diff --git a/client/src/index.ts b/client/src/index.ts index 38b6d67..9453560 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -157,6 +157,7 @@ class Extension implements Disposable { .getConfiguration() .get('vscode-kanata.includesAndWorkspaces', ''), localKeysVariant: localKeysVariant as string, + format: getFormatterSettings(), }, }; @@ -258,4 +259,26 @@ function getLocalKeysVariant(): LocalKeysVariant { } return localKeysVariant as LocalKeysVariant; -} \ No newline at end of file +} + + +interface FormatterSettings { + enable: boolean; +} + +// Gets localkeys variant from config and when set to auto, detects it based on current OS. +function getFormatterSettings(): FormatterSettings { + const formatSettings = workspace + .getConfiguration() + .get('vscode-kanata.format'); + + if (formatSettings === undefined) { + throw new Error('should be defined') + } + + console.log("formatSettings:", formatSettings) + + return formatSettings; +} + + diff --git a/justfile b/justfile index 6831966..cd9bfcd 100644 --- a/justfile +++ b/justfile @@ -4,7 +4,12 @@ _default: install: git submodule update make package - code --install-extension kanata.vsix + code --install-extension kanata.vsix --force + +install_release: + git submodule update + make CARGO_FLAGS=--release package + code --install-extension kanata.vsix --force # Creates a commit, that updates kanata to latest git and adds notice about it to CHANGELOG.md bump_kanata: diff --git a/kls/.gitignore b/kls/.gitignore index e69de29..1de5659 100644 --- a/kls/.gitignore +++ b/kls/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/kls/.vscode/extensions.json b/kls/.vscode/extensions.json new file mode 100644 index 0000000..61ed5d4 --- /dev/null +++ b/kls/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "rust-lang.rust-analyzer" + ] +} \ No newline at end of file diff --git a/kls/.vscode/settings.json b/kls/.vscode/settings.json new file mode 100644 index 0000000..494f440 --- /dev/null +++ b/kls/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + // "rust-analyzer.cargo.target": "wasm32-unknown-unknown", + "rust-analyzer.cargo.features": "all", + "rust-analyzer.showUnlinkedFileNotification": false, +} \ No newline at end of file diff --git a/kls/Cargo.lock b/kls/Cargo.lock index e7b2157..b5036ae 100644 --- a/kls/Cargo.lock +++ b/kls/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "arraydeque" @@ -31,9 +31,9 @@ checksum = "f0ffd3d69bd89910509a5d31d1f1353f38ccffdd116dd0099bbd6627f7bd8ad8" [[package]] name = "atomic-polyfill" -version = "0.1.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" dependencies = [ "critical-section", ] @@ -46,9 +46,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -76,27 +76,27 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] @@ -119,9 +119,9 @@ dependencies = [ [[package]] name = "critical-section" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" [[package]] name = "endian-type" @@ -131,45 +131,28 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "errno" -version = "0.3.2" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", "libc", "windows-sys", ] -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "hash32" @@ -182,9 +165,9 @@ dependencies = [ [[package]] name = "heapless" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ "atomic-polyfill", "hash32", @@ -195,15 +178,15 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -211,9 +194,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ "hermit-abi", "rustix", @@ -228,15 +211,15 @@ checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -289,27 +272,26 @@ dependencies = [ "serde-wasm-bindgen", "serde_json", "wasm-bindgen", - "wasm-bindgen-test", "web-sys", ] [[package]] name = "libc" -version = "0.2.147" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -317,15 +299,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lsp-types" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b63735a13a1f9cd4f4835223d828ed9c2e35c8c5e61837774399f558b6a1237" +checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984" dependencies = [ "bitflags 1.3.2", "serde", @@ -336,9 +318,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miette" @@ -392,18 +374,18 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "owo-colors" @@ -423,37 +405,37 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -470,9 +452,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] @@ -500,11 +482,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.6" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", @@ -513,15 +495,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "scopeguard" @@ -531,26 +507,25 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.181" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3e73c93c3240c0bda063c239298e633114c69a888c3e37ca8bb33f343e9890" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" dependencies = [ "serde_derive", ] [[package]] name = "serde-wasm-bindgen" -version = "0.3.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618365e8e586c22123d692b72a7d791d5ee697817b65a218cdf12a98870af0f7" +checksum = "b9b713f70513ae1f8d92665bbbbda5c295c2cf1da5542881ae5eefe20c9af132" dependencies = [ - "fnv", "js-sys", "serde", "wasm-bindgen", @@ -558,9 +533,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.181" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be02f6cb0cd3a5ec20bbcfbcbd749f57daddb1a0882dc2e46a6c236c90b977ed" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", @@ -569,9 +544,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -580,9 +555,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.16" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", @@ -591,15 +566,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smawk" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "spin" @@ -618,9 +593,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "supports-color" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4950e7174bffabe99455511c39707310e7e9b440364a2fcb1cc21521be57b354" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" dependencies = [ "is-terminal", "is_ci", @@ -646,9 +621,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -678,18 +653,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", @@ -713,15 +688,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-linebreak" @@ -740,15 +715,15 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -758,9 +733,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -768,9 +743,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", @@ -781,23 +756,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -805,9 +768,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", @@ -818,39 +781,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "wasm-bindgen-test" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.37" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" -dependencies = [ - "proc-macro2", - "quote", -] +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -880,66 +819,123 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows-targets", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/kls/Cargo.toml b/kls/Cargo.toml index 2ac0944..342dd0c 100644 --- a/kls/Cargo.toml +++ b/kls/Cargo.toml @@ -16,18 +16,18 @@ crate-type = ["cdylib"] bench = false [dependencies] -kanata-parser = { path = "../kanata/parser", features = ["cmd"]} +kanata-parser = { path = "../kanata-local/parser", features = ["cmd"]} -console_error_panic_hook = "0.1.6" +console_error_panic_hook = "0.1.7" js-sys = "0.3.53" -lsp-types = "0.94.0" -serde = { version = "1.0", features = ["derive"] } -serde-wasm-bindgen = "0.3.1" -wasm-bindgen = "0.2.76" +lsp-types = "0.95.0" +serde = { version = "^1.0.194", features = ["derive"] } +serde-wasm-bindgen = "0.6.3" +wasm-bindgen = "0.2.88" web-sys = { version = "0.3.64", features = ["console"] } -rustc-hash = "1.1.0" -anyhow = "1.0.72" -serde_json = "1.0.104" +rustc-hash = "^1.1.0" +anyhow = "^1.0.72" +serde_json = "^1.0.104" [dev-dependencies] -wasm-bindgen-test = "0.3.26" +# wasm-bindgen-test = "0.3.39" diff --git a/kls/justfile b/kls/justfile new file mode 100644 index 0000000..e4985af --- /dev/null +++ b/kls/justfile @@ -0,0 +1,5 @@ +# default: +# @just --list + +test: + cargo test diff --git a/kls/src/formatter/ext_tree.rs b/kls/src/formatter/ext_tree.rs new file mode 100644 index 0000000..d10654f --- /dev/null +++ b/kls/src/formatter/ext_tree.rs @@ -0,0 +1,415 @@ +use kanata_parser::cfg::{ + sexpr::{self, Position, SExpr, SExprMetaData, Span, Spanned}, + ParseError, +}; +use std::{borrow::BorrowMut, fmt::Display}; + +/// Extended Parse Tree. +/// Let's represent the whole config as a [`ParseTreeNode`]. +/// Root node should be [`ParseTreeNode::List`] containing other top level items. +/// While [`sexpr::parse_`] can only return [`ParseTreeNode::List`]s as top-level items, +/// this doesn't change anything in regard to how we use this struct later. +#[derive(PartialEq, Eq, Debug)] +pub struct ExtParseTree(pub ParseTreeNode); + +#[derive(PartialEq, Eq, Debug)] +pub enum ParseTreeNode { + List(Vec), + + Atom(String), + LineComment(String), + BlockComment(String), + Whitespace(String), +} + +/// Parses config from text and combines both [`SExpr`] and [`SExprMetaData`] into [`ExtParseTree`]. +pub fn parse_into_ext_tree(src: &str) -> std::result::Result { + parse_into_ext_tree_and_root_span(src).map(|(x1, _)| x1) +} + +/// Compared to [`kanata_parser::cfg::sexpr::Span`], this struct uses `&'a str` +/// for `file_content` and String for `file_name` instead of using +/// [`alloc::rc::Rc`] for both. +#[derive(Clone)] +pub struct CustomSpan<'a> { + pub start: Position, + pub end: Position, + pub file_name: String, + pub file_content: &'a str, +} + +impl<'a> From> for Span { + fn from(val: CustomSpan<'a>) -> Self { + Span { + start: val.start, + end: val.end, + file_name: val.file_name.into(), + file_content: val.file_content.into(), + } + } +} + +pub fn parse_into_ext_tree_and_root_span( + src: &str, +) -> std::result::Result<(ExtParseTree, CustomSpan<'_>), ParseError> { + let filename = ""; + let (exprs, exprs_ext) = sexpr::parse_(src, filename, false)?; + let exprs: Vec = exprs.into_iter().map(SExpr::List).collect(); + let position_end = exprs.last().map(|x| x.span().end).unwrap_or_default(); + let root_span = CustomSpan { + start: Position::default(), + end: position_end, + file_name: filename.to_string(), + file_content: src, + }; + let exprs = { + let mut r = SExpr::List(Spanned::new( + Vec::with_capacity(exprs.len()), + root_span.clone().into(), + )); + for x in exprs { + if let SExpr::List(Spanned { t, .. }) = &mut r { + t.push(x) + } + } + r + }; + let exprs: SExprCustom = SExprCustom(exprs); + // crate::log!("sexprs: {:?}", sexprs); + + let mut metadata_iter = exprs_ext.into_iter().peekable(); + let mut tree: ExtParseTree = ExtParseTree(ParseTreeNode::List(vec![])); + let mut tree_depth: u8 = 0; // currentdepth of the list we're currently appending to in `tree`. + let mut expr_path: Vec = vec![0]; // path to the current item in `exprs` tree. + loop { + match exprs.get_node(&expr_path) { + Some(expr) => { + while let Some(metadata) = + metadata_iter.next_if(|m| m.span().start() < expr.span().start()) + { + tree.append( + tree_depth, + match metadata { + SExprMetaData::LineComment(m) => ParseTreeNode::LineComment(m.t), + SExprMetaData::BlockComment(m) => ParseTreeNode::BlockComment(m.t), + SExprMetaData::Whitespace(m) => ParseTreeNode::Whitespace(m.t), + }, + ) + } + + match expr { + SExpr::Atom(x) => { + tree.append(tree_depth, ParseTreeNode::Atom(x.t.clone())); + match expr_path.last_mut() { + Some(i) => *i += 1, + None => unreachable!(), + }; + } + SExpr::List(_) => { + tree.append(tree_depth, ParseTreeNode::List(vec![])); + tree_depth += 1; + expr_path.push(0); + } + } + } + None => { + // Reached the end of the list. + expr_path.pop(); + + // Get the absolute position of the closing paren, and push all leftover metadata + // that's located before it. + let expr = exprs + .get_node(&expr_path) + .expect("should exist, we just iterated over it"); + while let Some(metadata) = + metadata_iter.next_if(|m| m.span().start() < expr.span().end()) + { + tree.append( + tree_depth, + match metadata { + SExprMetaData::LineComment(m) => ParseTreeNode::LineComment(m.t), + SExprMetaData::BlockComment(m) => ParseTreeNode::BlockComment(m.t), + SExprMetaData::Whitespace(m) => ParseTreeNode::Whitespace(m.t), + }, + ) + } + + match expr_path.last_mut() { + Some(i) => *i += 1, + None => break, + }; + tree_depth -= 1; + } + }; + } + + // Add remaining metadata. + for metadata in metadata_iter { + tree.append( + tree_depth, + match metadata { + SExprMetaData::LineComment(m) => ParseTreeNode::LineComment(m.t), + SExprMetaData::BlockComment(m) => ParseTreeNode::BlockComment(m.t), + SExprMetaData::Whitespace(m) => ParseTreeNode::Whitespace(m.t), + }, + ) + } + + Ok((tree, root_span)) +} + +impl ParseTreeNode { + /// If any step on path is not List, panic. + /// If any step is out-of-bounds, return None. + pub fn get_node(&self, at_path: &[usize]) -> Option<&ParseTreeNode> { + let mut head: &ParseTreeNode = self; + for i in at_path { + if let ParseTreeNode::List(l) = head { + head = match &l.get(*i) { + Some(x) => x, + None => return None, + }; + } else { + panic!("invalid tree path") + } + } + Some(head) + } +} + +impl ExtParseTree { + /// Appends `node` to the last node at given `depth`, which is expected + /// to be a list (otherwise panics). + fn append(&mut self, depth: u8, node: ParseTreeNode) { + let mut head: &mut ParseTreeNode = self.0.borrow_mut(); + for _ in 0..depth { + if let ParseTreeNode::List(li) = head { + head = li.last_mut().expect("path is valid"); + } else { + panic!("unexpected non-list item") + } + } + if let ParseTreeNode::List(ref mut l) = head { + l.push(node); + } else { + panic!("unexpected non-list item"); + } + } + + /// If any step on path is not List, panic. + /// If any step is out-of-bounds, return None. + pub fn get_node(&self, at_path: &[usize]) -> Option<&ParseTreeNode> { + return self.0.get_node(at_path); + } +} + +struct SExprCustom(SExpr); + +impl<'a> SExprCustom { + /// If any step on path is not List, panic. + /// If any step is out-of-bounds, return None. + fn get_node(&'a self, at_path: &[usize]) -> Option<&'a SExpr> { + let mut head: &SExpr = &self.0; // is it ok to do this? + for i in at_path { + if let SExpr::List(Spanned { t, .. }) = head { + head = match &t.get(*i) { + Some(x) => x, + None => return None, + }; + } else { + panic!("invalid tree path") + } + } + Some(head) + } +} + +impl Display for ExtParseTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let ParseTreeNode::List(l) = &self.0 { + for expr in l { + write!(f, "{}", expr)?; + } + } else { + // root node must be a list. + return Err(std::fmt::Error); + } + Ok(()) + } +} + +impl Display for ParseTreeNode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ParseTreeNode::List(l) => { + write!(f, "(")?; + for expr in l { + write!(f, "{}", expr)?; + } + write!(f, ")")?; + } + ParseTreeNode::Atom(x) + | ParseTreeNode::LineComment(x) + | ParseTreeNode::BlockComment(x) + | ParseTreeNode::Whitespace(x) => { + write!(f, "{}", x)?; + } + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::log; + + macro_rules! Tree { + ($($element:expr),*) => {{ + ExtParseTree(ParseTreeNode::List(vec![$($element),*])) + }}; + } + + macro_rules! Atom { + ($text:expr) => { + ParseTreeNode::Atom($text.to_string()) + }; + } + + macro_rules! LineComment { + ($text:expr) => { + ParseTreeNode::LineComment($text.to_string()) + }; + } + + macro_rules! BlockComment { + ($text:expr) => { + ParseTreeNode::BlockComment($text.to_string()) + }; + } + + macro_rules! Whitespace { + ($text:expr) => { + ParseTreeNode::Whitespace($text.to_string()) + }; + } + + macro_rules! List { + ($($element:expr),*) => {{ + ParseTreeNode::List(vec![$($element),*]) + }}; + } + + #[test] + fn test_macros() { + use ParseTreeNode::*; + assert_eq!(Tree!(), ExtParseTree(List(vec![]))); + assert_eq!(Tree!(List!()), ExtParseTree(List(vec![List(vec![])]))); + assert_eq!( + Tree!( + Atom!("test"), + Whitespace!(" "), + LineComment!("# test"), + BlockComment!("#| test |#") + ), + ExtParseTree(List(vec![ + Atom("test".to_string()), + Whitespace(" ".to_string()), + LineComment("# test".to_string()), + BlockComment("#| test |#".to_string()) + ])) + ); + } + + #[test] + fn test_parse_into_ext_tree() { + let s = ""; + assert_eq!(parse_into_ext_tree(s).expect("parses"), Tree!()); + + #[rustfmt::skip] + let cases = vec![ + ( + "", + Tree!() + ), + ( + "()", + Tree!(List!()) + ), + ( + "(atom)", + Tree!(List!(Atom!("atom"))) + ), + ( + "( test)(1 \n\t 2)", + Tree!( + List!( + Whitespace!(" "), + Atom!("test") + ), + List!( + Atom!("1"), + Whitespace!(" \n\t "), + Atom!("2") + ) + ) + ), + ( + " \n\t \n", + Tree!(Whitespace!(" \n\t \n")) + ), + ( + "(1 2 #|block|# 3)", + Tree!( + List!( + Atom!("1"), + Whitespace!(" "), + Atom!("2"), + Whitespace!(" "), + BlockComment!("#|block|#"), + Whitespace!(" "), + Atom!("3") + ) + ) + ), + ( + "(1\n)", + Tree!( + List!( + Atom!("1"), + Whitespace!("\n") + ) + ) + ), + ( + "\n(1\n) \n ;; comment \n\t (2) ", + Tree!( + Whitespace!("\n"), + List!( + Atom!("1"), + Whitespace!("\n") + ), + Whitespace!(" \n "), + LineComment!(";; comment \n"), + Whitespace!("\t "), + List!( + Atom!("2") + ), + Whitespace!(" ") + ) + ), + ]; + for (case, expected_result) in cases { + log!("==========================="); + let actual_result = parse_into_ext_tree(case).expect("parses"); + log!("actual: {:#?}", actual_result); + log!("expected: {:#?}", expected_result); + assert_eq!(actual_result, expected_result, "parse_into_ext_tree(case)"); + assert_eq!( + actual_result.to_string(), + case, + ".to_string()" + ); + } + } +} diff --git a/kls/src/formatter/mod.rs b/kls/src/formatter/mod.rs new file mode 100644 index 0000000..bcb0d60 --- /dev/null +++ b/kls/src/formatter/mod.rs @@ -0,0 +1,42 @@ +use crate::log; +use kanata_parser::cfg::{ + sexpr::{self, Position, SExpr, SExprMetaData, Span, Spanned}, + ParseError, +}; +use std::{borrow::BorrowMut, collections::HashMap}; +use wasm_bindgen::prelude::*; + +pub mod ext_tree; +use ext_tree::*; + +mod remove_excessive_newlines; + +pub struct Formatter { + // Additional options + pub extension_options: crate::ExtensionFormatterOptions, + + pub remove_extra_empty_lines: bool, +} + +impl Formatter { + /// Transforms [`ExtParseTree`] to another [`ExtParseTree`] in-place, + /// applying selected formatting funtions depending on [`FormatterOptions`]. + pub fn format(&self, tree: &mut ExtParseTree) { + if !self.extension_options.enable { + return; + } + if self.remove_extra_empty_lines { + tree.0.remove_excessive_adjacent_newlines(2); + } + } + + // VSCode normally sends formatting options along with + // every textDocument/formatting request. + pub fn format_with_options( + &self, + tree: &mut ExtParseTree, + _options: &lsp_types::FormattingOptions, // todo: we should probably handle these options + ) { + self.format(tree) + } +} diff --git a/kls/src/formatter/remove_excessive_newlines.rs b/kls/src/formatter/remove_excessive_newlines.rs new file mode 100644 index 0000000..ee5256f --- /dev/null +++ b/kls/src/formatter/remove_excessive_newlines.rs @@ -0,0 +1,99 @@ +use std::borrow::BorrowMut; + +use super::ext_tree::*; + +impl ParseTreeNode { + /// Removes excessive adjacent newlines after `max` number of newlines. + /// Depends on whitespace removal at ends of lines to work correctly. + /// Otherwise it might look like it didn't remove some excessive newlines. + pub fn remove_excessive_adjacent_newlines(&mut self, max: usize) { + match self.borrow_mut() { + ParseTreeNode::List(list) => { + for node in list { + node.remove_excessive_adjacent_newlines(max); + } + } + ParseTreeNode::Whitespace(x) => loop { + let mut consecutive_newlines: usize = 0; + let mut replace_at_index: Option = None; + for (i, char) in x.chars().enumerate() { + if char == '\n' { + consecutive_newlines += 1; + + if consecutive_newlines > max { + replace_at_index = Some(i); + } + } else { + if consecutive_newlines > max { + break; + } + consecutive_newlines = 0; + } + } + if let Some(i) = replace_at_index { + let newlines_to_remove = consecutive_newlines - max; + x.drain((i + 1 - newlines_to_remove)..(i + 1)); + continue; + } + break; + }, + _ => {} + } + } +} + +#[cfg(test)] +mod tests { + use crate::log; + + use super::*; + + #[test] + fn test_remove_above_2_adjacent_newlines() { + #[rustfmt::skip] + let cases = vec![ + ( + 1, + "(1 \n\n\n 2)", + "(1 \n 2)" + ), + ( + 0, + "(1 \n\n\n 2)", + "(1 2)" + ), + ( + 1, + "\n\n\n\n", + "\n" + ), + ( + 0, + "\n\n\n\n", + "" + ), + ( + 3, + "\n\n\n\n\n", + "\n\n\n" + ), + ( + 3, + "\n\n\n\n\n \n\n\n\n \n\n", + "\n\n\n \n\n\n \n\n" + ), + ( + 2, + "(\n(\n\n\n (1\n \n\n\n\n ))\n)\n \n(\n\n\n 2\n)\n", + "(\n(\n\n (1\n \n\n ))\n)\n \n(\n\n 2\n)\n", + ), + ]; + for (max, case, expected_result) in cases { + log!("=============="); + log!("max: {:?}", max); + let mut tree = parse_into_ext_tree(case).expect("parses"); + tree.0.remove_excessive_adjacent_newlines(max); + assert_eq!(tree.to_string(), expected_result); + } + } +} diff --git a/kls/src/helpers.rs b/kls/src/helpers.rs index 0ba809b..d363a4b 100644 --- a/kls/src/helpers.rs +++ b/kls/src/helpers.rs @@ -1,7 +1,5 @@ use std::{collections::BTreeMap, path::Path, rc::Rc}; -use wasm_bindgen::JsValue; - use kanata_parser::cfg::{sexpr::Span, FileContentProvider, ParseError}; use lsp_types::{PublishDiagnosticsParams, TextDocumentItem, Url}; @@ -10,13 +8,22 @@ pub type HashSet = rustc_hash::FxHashSet; pub type Documents = BTreeMap; pub type Diagnostics = BTreeMap; +#[cfg(target_os = "unknown")] #[macro_export] macro_rules! log { ($string:expr) => { - web_sys::console::log_1(&JsValue::from($string)) + web_sys::console::log_1(&wasm_bindgen::JsValue::from($string)) + }; + ($($tokens:tt)*) => { + web_sys::console::log_1(&wasm_bindgen::JsValue::from(format!($($tokens)*))) }; +} + +#[cfg(not(target_os = "unknown"))] +#[macro_export] +macro_rules! log { ($($tokens:tt)*) => { - web_sys::console::log_1(&JsValue::from(format!($($tokens)*))) + println!($($tokens)*) }; } @@ -32,8 +39,8 @@ pub fn utf16_length(str: impl AsRef) -> usize { utf16_encoded.len() } -pub fn slice_rc_str(rc_str: &Rc, start: usize, end: usize) -> String { - rc_str[start..end].to_string() +pub fn slice_rc_str(rc_str: &Rc, start: usize, end: usize) -> &str { + &rc_str[start..end] } #[derive(Debug, Clone)] @@ -48,7 +55,7 @@ impl CustomParseError { pub fn from_parse_error(e: ParseError, main_cfg_file: &str) -> Self { Self { msg: e.msg, - span: e.span.unwrap_or_else(|| kanata_parser::cfg::sexpr::Span { + span: e.span.unwrap_or_else(|| Span { file_name: main_cfg_file.into(), ..Default::default() }), @@ -56,30 +63,28 @@ impl CustomParseError { } } -impl From<&CustomParseError> for lsp_types::Range { - fn from(val: &CustomParseError) -> Self { - lsp_types::Range { - start: lsp_types::Position::new( - val.span.start.line.try_into().unwrap(), - utf16_length(slice_rc_str( - &val.span.file_content, - val.span.start.line_beginning, - val.span.start.absolute, - )) - .try_into() - .unwrap(), - ), - end: lsp_types::Position::new( - val.span.end.line.try_into().unwrap(), - utf16_length(slice_rc_str( - &val.span.file_content, - val.span.end.line_beginning, - val.span.end.absolute, - )) - .try_into() - .unwrap(), - ), - } +pub fn lsp_range_from_span(span: &Span) -> lsp_types::Range { + lsp_types::Range { + start: lsp_types::Position::new( + span.start.line.try_into().unwrap(), + utf16_length(slice_rc_str( + &span.file_content, + span.start.line_beginning, + span.start.absolute, + )) + .try_into() + .unwrap(), + ), + end: lsp_types::Position::new( + span.end.line.try_into().unwrap(), + utf16_length(slice_rc_str( + &span.file_content, + span.end.line_beginning, + span.end.absolute, + )) + .try_into() + .unwrap(), + ), } } diff --git a/kls/src/lib.rs b/kls/src/lib.rs index ffae9bf..e4f01de 100644 --- a/kls/src/lib.rs +++ b/kls/src/lib.rs @@ -1,29 +1,33 @@ -use std::{ - collections::BTreeMap, - fmt::Display, - path::{self, Path, PathBuf}, - str::{FromStr, Split}, -}; - +use crate::helpers::{lsp_range_from_span, HashSet}; use anyhow::{anyhow, bail}; +use formatter::Formatter; +use kanata_parser::cfg::{FileContentProvider, ParseError}; use lsp_types::{ notification::{ DidChangeTextDocument, DidChangeWatchedFiles, DidCloseTextDocument, DidDeleteFiles, DidOpenTextDocument, DidSaveTextDocument, Initialized, Notification, }, + request::{Formatting, Request}, DeleteFilesParams, Diagnostic, DiagnosticSeverity, DidChangeTextDocumentParams, DidChangeWatchedFilesParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, FileChangeType, FileDelete, FileEvent, InitializeParams, PublishDiagnosticsParams, - TextDocumentItem, Url, VersionedTextDocumentIdentifier, + TextDocumentItem, TextEdit, Url, VersionedTextDocumentIdentifier, }; +use serde::Deserialize; use serde_wasm_bindgen::{from_value, to_value}; +use std::{ + collections::BTreeMap, + fmt::Display, + path::{self, Path, PathBuf}, + str::{FromStr, Split}, +}; use wasm_bindgen::prelude::*; -use kanata_parser::cfg::{FileContentProvider, ParseError}; - mod helpers; use helpers::{empty_diagnostics_for_doc, parse_wrapper, CustomParseError, Diagnostics, Documents}; +mod formatter; + struct Kanata { def_local_keys_variant_to_apply: String, } @@ -39,14 +43,17 @@ const KANATA_PARSER_HELP: &str = r"For more info, see the configuration guide or impl Kanata { fn new(def_local_keys_variant_to_apply: DefLocalKeysVariant) -> Self { - *kanata_parser::keys::OSCODE_MAPPING_VARIANT.lock() = match def_local_keys_variant_to_apply + #[cfg(target_os = "unknown")] // todo: make this compilable for non-wasm too { - DefLocalKeysVariant::Win | DefLocalKeysVariant::Wintercept => { - kanata_parser::keys::Platform::Win - } - DefLocalKeysVariant::Linux => kanata_parser::keys::Platform::Linux, - DefLocalKeysVariant::MacOS => kanata_parser::keys::Platform::Macos, - }; + *kanata_parser::keys::OSCODE_MAPPING_VARIANT.lock() = + match def_local_keys_variant_to_apply { + DefLocalKeysVariant::Win | DefLocalKeysVariant::Wintercept => { + kanata_parser::keys::Platform::Win + } + DefLocalKeysVariant::Linux => kanata_parser::keys::Platform::Linux, + DefLocalKeysVariant::MacOS => kanata_parser::keys::Platform::Macos, + }; + } Self { def_local_keys_variant_to_apply: def_local_keys_variant_to_apply.to_string(), } @@ -138,10 +145,6 @@ impl Kanata { } } -use serde::Deserialize; - -use crate::helpers::HashSet; - #[derive(Debug, Deserialize, Clone)] struct Config { #[serde(rename = "includesAndWorkspaces")] @@ -150,6 +153,7 @@ struct Config { main_config_file: String, #[serde(rename = "localKeysVariant")] def_local_keys_variant: DefLocalKeysVariant, + format: ExtensionFormatterOptions, } #[derive(Debug, Deserialize, Clone, Copy)] @@ -200,6 +204,11 @@ impl From for WorkspaceOptions { } } +#[derive(Debug, Deserialize, Clone, Copy)] +pub struct ExtensionFormatterOptions { + enable: bool, +} + #[wasm_bindgen] pub struct KanataLanguageServer { documents: Documents, @@ -207,6 +216,7 @@ pub struct KanataLanguageServer { workspace_options: WorkspaceOptions, root: Option, send_diagnostics_callback: js_sys::Function, + formatter: formatter::Formatter, } /// Public API exposed via WASM. @@ -247,6 +257,10 @@ impl KanataLanguageServer { Self { documents: BTreeMap::new(), kanata: Kanata::new(config.def_local_keys_variant), + formatter: Formatter { + extension_options: config.format, + remove_extra_empty_lines: true, + }, workspace_options: config.into(), root: root_uri, send_diagnostics_callback: send_diagnostics_callback.clone(), @@ -266,7 +280,7 @@ impl KanataLanguageServer { #[allow(unused_variables)] #[wasm_bindgen(js_class = KanataLanguageServer, js_name = onNotification)] pub fn on_notification(&mut self, method: &str, params: JsValue) { - log!(method); + log!("notification: {}", method); match method { // Nothing to do when we receive the `Initialized` notification. @@ -366,9 +380,47 @@ impl KanataLanguageServer { self.send_diagnostics(&diagnostics); } - _ => log!("unexpected notification"), + _ => log!("unsupported notification"), } } + + #[allow(unused_variables)] + #[wasm_bindgen(js_class = KanataLanguageServer, js_name = onDocumentFormatting)] + pub fn on_document_formatting(&mut self, params: JsValue) -> JsValue { + type Params = ::Params; + type Result = ::Result; + + let Params { + text_document, + options, // vscode formatting options + .. + } = from_value(params).expect("deserializes"); + + let text = &self + .documents + .get(&text_document.uri) + .expect("document should be cached") + .text; + + let (mut tree, root_span) = + match formatter::ext_tree::parse_into_ext_tree_and_root_span(text) { + Ok(x) => x, + Err(e) => { + log!("failed to parse into tree"); + return to_value::(&None).expect("serializes"); + } + }; + + let range = lsp_range_from_span(&root_span.into()); + + self.formatter.format_with_options(&mut tree, &options); + + to_value::(&Some(vec![TextEdit { + range, + new_text: tree.to_string(), + }])) + .expect("no err") + } } /// Individual LSP notification handlers. @@ -491,8 +543,10 @@ impl KanataLanguageServer { let mut diagnostics = vec![]; + let range = lsp_range_from_span(&err.span); + diagnostics.push(Diagnostic { - range: err.into(), + range, severity: Some(severity), source: if is_extension_the_error_source { Some("vscode-kanata".to_string()) @@ -505,7 +559,7 @@ impl KanataLanguageServer { if !is_extension_the_error_source { diagnostics.push(Diagnostic { - range: err.into(), + range, severity: Some(DiagnosticSeverity::INFORMATION), message: KANATA_PARSER_HELP.to_string(), ..Default::default() diff --git a/package.json b/package.json index e04da0d..03dda3b 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ ], "categories": [ "Programming Languages", - "Other" + "Other", + "Formatters" ], "repository": { "type": "git", @@ -99,6 +100,11 @@ ], "default": "auto", "markdownDescription": "Select which localkeys variant to use." + }, + "vscode-kanata.format.enable": { + "type": "boolean", + "default": true, + "description": "Enable formatting feature" } } } diff --git a/server/src/index.ts b/server/src/index.ts index 7d04b6a..bc39748 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -18,6 +18,7 @@ connection.onInitialize((params: InitializeParams) => { const kls = new KanataLanguageServer(params, sendDiagnosticsCallback); connection.onNotification((...args) => kls.onNotification(...args)); + connection.onDocumentFormatting((...args) => kls.onDocumentFormatting(...args)); return { capabilities: { @@ -29,6 +30,7 @@ connection.onInitialize((params: InitializeParams) => { // UTF-8 is not supported in vscode-languageserver/node. See: // https://github.com/microsoft/vscode-languageserver-node/issues/1224 positionEncoding: PositionEncodingKind.UTF16, + documentFormattingProvider: true, workspace: { workspaceFolders: { supported: false }, fileOperations: {