First commit
This commit is contained in:
commit
f193be1731
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
target/
|
||||
.direnv
|
902
Cargo.lock
generated
Normal file
902
Cargo.lock
generated
Normal file
|
@ -0,0 +1,902 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags 1.3.2",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kak-tree"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"itertools",
|
||||
"serde",
|
||||
"slog",
|
||||
"slog-scope",
|
||||
"sloggers",
|
||||
"toml",
|
||||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "libflate"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"crc32fast",
|
||||
"rle-decode-fast",
|
||||
"take_mut",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
dependencies = [
|
||||
"log 0.4.20",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rle-decode-fast"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.192"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.192"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slog"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06"
|
||||
|
||||
[[package]]
|
||||
name = "slog-async"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72c8038f898a2c79507940990f05386455b3a317d8f18d4caea7cbc3d5096b84"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"slog",
|
||||
"take_mut",
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slog-kvfilter"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae939ed7d169eed9699f4f5cd440f046f5dc5dfc27c19e3cd311619594c175e0"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"slog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slog-scope"
|
||||
version = "4.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f95a4b4c3274cd2869549da82b57ccc930859bdbf5bcea0424bc5f140b3c786"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"lazy_static",
|
||||
"slog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slog-stdlog"
|
||||
version = "3.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1c469573d1e3f36f9eee66cd132206caf47b50c94b1f6c6e7b4d8235e9ecf01"
|
||||
dependencies = [
|
||||
"crossbeam",
|
||||
"log 0.3.9",
|
||||
"slog",
|
||||
"slog-scope",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slog-term"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87d29185c55b7b258b4f120eab00f48557d4d9bc814f41713f449d35b0f8977c"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"slog",
|
||||
"term",
|
||||
"thread_local",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sloggers"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31bef221d42166d6708aa1e9b0182324b37a0a7517ff590ec201dbfe1cfa46ef"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"libflate",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"slog",
|
||||
"slog-async",
|
||||
"slog-kvfilter",
|
||||
"slog-scope",
|
||||
"slog-stdlog",
|
||||
"slog-term",
|
||||
"trackable 0.2.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "take_mut"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
|
||||
dependencies = [
|
||||
"dirs-next",
|
||||
"rustversion",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"libc",
|
||||
"num_threads",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trackable"
|
||||
version = "0.2.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b98abb9e7300b9ac902cc04920945a874c1973e08c310627cc4458c04b70dd32"
|
||||
dependencies = [
|
||||
"trackable 1.3.0",
|
||||
"trackable_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trackable"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15bd114abb99ef8cee977e517c8f37aee63f184f2d08e3e6ceca092373369ae"
|
||||
dependencies = [
|
||||
"trackable_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trackable_derive"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebeb235c5847e2f82cfe0f07eb971d1e5f6804b18dac2ae16349cc604380f82f"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "376e181cb69da67bad2d69806cf2500656fd68123c526a61e5cbbfc65110c5b0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log 0.4.20",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.51.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
68
Cargo.toml
Normal file
68
Cargo.toml
Normal file
|
@ -0,0 +1,68 @@
|
|||
[package]
|
||||
name = "kak-tree"
|
||||
version = "0.1.0"
|
||||
authors = ["Ruslan Prokopchuk <fer.obbee@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
itertools = "0.8.2"
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
slog = { version = "2.5.2", features = ["release_max_level_debug"] }
|
||||
slog-scope = "4.3.0"
|
||||
sloggers = "0.3.5"
|
||||
toml = "0.5.6"
|
||||
tree-sitter = "0.6.0"
|
||||
|
||||
# [profile.release]
|
||||
# lto = true
|
||||
|
||||
[features]
|
||||
default = ["rust"]
|
||||
all = [
|
||||
"bash",
|
||||
"c_sharp",
|
||||
"c",
|
||||
"clojure",
|
||||
"cpp",
|
||||
"css",
|
||||
"elm",
|
||||
"go",
|
||||
"haskell",
|
||||
"html",
|
||||
"java",
|
||||
"javascript",
|
||||
"json",
|
||||
"julia",
|
||||
"ocaml",
|
||||
"php",
|
||||
"python",
|
||||
"racket",
|
||||
"ruby",
|
||||
"rust",
|
||||
"scala",
|
||||
"typescript"
|
||||
]
|
||||
bash = []
|
||||
c_sharp = []
|
||||
c = []
|
||||
clojure = []
|
||||
cpp = []
|
||||
css = []
|
||||
elm = []
|
||||
go = []
|
||||
haskell = []
|
||||
html = []
|
||||
java = []
|
||||
javascript = []
|
||||
json = []
|
||||
julia = []
|
||||
ocaml = []
|
||||
php = []
|
||||
python = []
|
||||
racket = []
|
||||
ruby = []
|
||||
rust = []
|
||||
scala = []
|
||||
typescript = []
|
||||
|
121
README.original.asciidoc
Normal file
121
README.original.asciidoc
Normal file
|
@ -0,0 +1,121 @@
|
|||
= Structural selections for Kakoune
|
||||
|
||||
kak-tree is a plugin for Kakoune which enables selection of syntax tree nodes. Parsing is performed with https://github.com/tree-sitter/tree-sitter[tree-sitter].
|
||||
|
||||
Status: proof of concept, interface and overall development direction could change drastically based on feedback.
|
||||
|
||||
== Installation
|
||||
|
||||
Replace `"rust javascript"` with a list of languages you need. Or use `all` to build all supported
|
||||
languages. Note that `all` build takes a long time, and resulting binary is quite fat which could
|
||||
have a negative impact on responsiveness.
|
||||
|
||||
----
|
||||
git clone --recurse-submodules
|
||||
cargo install --path . --force --features "rust javascript"
|
||||
cp rc/tree.kak ~/.config/kak/autoload/
|
||||
----
|
||||
|
||||
Look at `Cargo.toml` for a full list of supported languages.
|
||||
|
||||
It is possible to check programmaticaly if kak-tree was built with support for a given filetype:
|
||||
|
||||
----
|
||||
kak-tree --do-you-understand rust
|
||||
----
|
||||
|
||||
If language is supported then exit code is 0 otherwise it's non-zero (1 at the moment, but it is not
|
||||
guaranteed in future).
|
||||
|
||||
== Usage
|
||||
|
||||
Tree-sitter parsers produce very detailed syntax tree, many elements of which are not interesting
|
||||
for day-to-day selection purposes. kak-tree introduces the concept of a _visible_ node. Node is
|
||||
_visible_ when:
|
||||
|
||||
. Node is named in the tree-sitter grammar for the given language (as opposed to anonymous nodes,
|
||||
http://tree-sitter.github.io/tree-sitter/using-parsers#named-vs-anonymous-nodes[more]).
|
||||
. Either there is no white/blacklist for the given filetype or node kind is whitelisted or not
|
||||
blacklisted. See <<Configuration>> for details about white/blacklisting.
|
||||
|
||||
Most of the kak-tree commands operate on _visible_ nodes and skip not _visible_ ones.
|
||||
|
||||
[cols=2*]
|
||||
|===
|
||||
|
||||
| tree-select-parent-node [<KIND>]
|
||||
| Select the closest visible ancestor or ancestor of KIND when provided.
|
||||
|
||||
| tree-select-next-node [<KIND>]
|
||||
| Select the closest visible next sibling or next sibling of KIND when provided.
|
||||
|
||||
| tree-select-previous-node [<KIND>]
|
||||
| Select the closest visible previous sibling or previous sibling of KIND when provided.
|
||||
|
||||
| tree-select-children [<KIND>]
|
||||
| Select all immediate visible children or all descendants matching KIND when provided.
|
||||
|
||||
| tree-select-first-child [<KIND>]
|
||||
| Select the first immediate visible children or the first descendant matching KIND when provided.
|
||||
|
||||
| tree-node-sexp
|
||||
| Show info box with a syntax tree of the main selection parent.
|
||||
|===
|
||||
|
||||
== Configuration
|
||||
|
||||
kak-tree supports configuration via a configuration file. As for now there is no default path to
|
||||
load the configuration file, and it must be given using CLI option `--config` or `-c` for short:
|
||||
|
||||
----
|
||||
set global tree_cmd 'kak-tree -c /path/to/kak-tree.toml'
|
||||
----
|
||||
|
||||
=== Filetype configuration
|
||||
|
||||
Configuration for specific filetypes should be provided like this:
|
||||
|
||||
----
|
||||
[filetype.rust]
|
||||
blacklist = ["identifier", "scoped_identifier", "string_literal"]
|
||||
whitelist = ["function_item"]
|
||||
group.identifier = ["identifier", "scoped_identifier"]
|
||||
group.fn = ["function_item"]
|
||||
|
||||
[filetype.javascript]
|
||||
group.fn = ["function", "arrow_function"]
|
||||
----
|
||||
|
||||
Configuration under the `[filetype.default]` key will be used for all filetypes without
|
||||
configuration. Specific filetype configuration _doesn't_ extend default configuration but rather
|
||||
overwrites it.
|
||||
|
||||
==== White/blacklisting
|
||||
|
||||
If `whitelist` array is provided then kak-tree selection will skip nodes which kinds are not whitelisted.
|
||||
If `blacklist` array is provided then kak-tree selection will skip nodes which kinds are blacklisted.
|
||||
|
||||
NOTE: `whitelist` takes precedence over `blacklist`. In the Rust example above kak-tree would expand
|
||||
selection up to the function definition, ignoring other node kinds.
|
||||
|
||||
NOTE: `tree-node-sexp` command is useful for exploring node kinds which appear in the specific code.
|
||||
|
||||
Whitelisting or blacklisting node kinds could be tedious as tree-sitter parsers define many of them,
|
||||
but it also could be rewarding as you will be able to quickly modify selection in scopes which
|
||||
matter for you with fewer keystrokes.
|
||||
|
||||
==== Kind groups
|
||||
|
||||
Groups of node kinds serve a two-fold purpose:
|
||||
|
||||
. Groups allow matching functionally similar node kinds (i.e. `identifier` and `scoped_identifier`
|
||||
in Rust) by a single query.
|
||||
|
||||
. Groups allow matching functionally similar nodes across filetypes (i.e. `function_item` in Rust
|
||||
and `function` in JavaScript) as tree-sitter parsers don't use uniform node kind names.
|
||||
|
||||
NOTE: `whitelist` and `blacklist` options doesn't expand groups yet.
|
||||
|
||||
== License
|
||||
|
||||
For kak-tree see UNLICENSE file. For tree-sitter and its parsers look at their repositories.
|
24
UNLICENSE
Normal file
24
UNLICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
51
build.rs
Normal file
51
build.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
fn main() {
|
||||
println!("cargo:rustc-link-search=native=lib");
|
||||
for lang in &[
|
||||
#[cfg(feature = "bash")]
|
||||
"bash",
|
||||
#[cfg(feature = "c_sharp")]
|
||||
"c-sharp",
|
||||
#[cfg(feature = "c")]
|
||||
"c",
|
||||
#[cfg(feature = "clojure")]
|
||||
"clojure",
|
||||
#[cfg(feature = "cpp")]
|
||||
"cpp",
|
||||
#[cfg(feature = "css")]
|
||||
"css",
|
||||
#[cfg(feature = "elm")]
|
||||
"elm",
|
||||
#[cfg(feature = "go")]
|
||||
"go",
|
||||
#[cfg(feature = "haskell")]
|
||||
"haskell",
|
||||
#[cfg(feature = "html")]
|
||||
"html",
|
||||
#[cfg(feature = "java")]
|
||||
"java",
|
||||
#[cfg(feature = "javascript")]
|
||||
"javascript",
|
||||
#[cfg(feature = "json")]
|
||||
"json",
|
||||
#[cfg(feature = "julia")]
|
||||
"julia",
|
||||
#[cfg(feature = "ocaml")]
|
||||
"ocaml",
|
||||
#[cfg(feature = "php")]
|
||||
"php",
|
||||
#[cfg(feature = "python")]
|
||||
"python",
|
||||
#[cfg(feature = "racket")]
|
||||
"racket",
|
||||
#[cfg(feature = "ruby")]
|
||||
"ruby",
|
||||
#[cfg(feature = "rust")]
|
||||
"rust",
|
||||
#[cfg(feature = "scala")]
|
||||
"scala",
|
||||
#[cfg(feature = "typescript")]
|
||||
"typescript",
|
||||
] {
|
||||
println!("cargo:rustc-link-lib=static=tree-sitter-{lang}");
|
||||
}
|
||||
}
|
195
flake.lock
Normal file
195
flake.lock
Normal file
|
@ -0,0 +1,195 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"inputs": {
|
||||
"systems": "systems_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1699155732,
|
||||
"narHash": "sha256-Wg4RmOGUEO4YCF0fEc/qiQ/3+BGC/f0qywIE8xEkIpY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "15492ddc2974ba426ea7e17116ea7aa44fc96dcd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681358109,
|
||||
"narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1697009197,
|
||||
"narHash": "sha256-viVRhBTFT8fPJTb1N3brQIpFZnttmwo3JVKNuWRVc3s=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "01441e14af5e29c9d27ace398e6dd0b293e25a54",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"tree-sitters": "tree-sitters"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1699669856,
|
||||
"narHash": "sha256-OIb0WAoEMUA1EH70AwpWabdEpvYt/kJChBnb7XiXAJs=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "efd15e11c8954051a47679e7718b4c2a9b68ce27",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_3": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"tree-sitters": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_3",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1699742193,
|
||||
"narHash": "sha256-1pc59vyEpFwtHYKsEGAwxL7/4wiTmLmzKO6j61wqOeo=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "bb561d2e33d4d9f9d8171df2484ba6ae8e810b74",
|
||||
"revCount": 3,
|
||||
"type": "git",
|
||||
"url": "https://githug.xyz/xenia/tree-sitters"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://githug.xyz/xenia/tree-sitters"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
64
flake.nix
Normal file
64
flake.nix
Normal file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
description = "kak-tree, packaged for nix";
|
||||
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
tree-sitters.url = "git+https://githug.xyz/xenia/tree-sitters";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, rust-overlay, tree-sitters }:
|
||||
flake-utils.lib.eachDefaultSystem (sys:
|
||||
let pkgs = import nixpkgs {
|
||||
system = sys;
|
||||
overlays = [ (import rust-overlay) ];
|
||||
};
|
||||
rust = pkgs.rust-bin.stable.latest.default.override {
|
||||
extensions = [ "rust-src" "rust-analyzer" ];
|
||||
};
|
||||
platform = pkgs.makeRustPlatform {
|
||||
rustc = rust;
|
||||
cargo = rust;
|
||||
};
|
||||
sitters = tree-sitters.packages.${sys};
|
||||
sitterlist = [
|
||||
sitters.agda sitters.bash sitters.c sitters.nix sitters.python sitters.rust
|
||||
];
|
||||
|
||||
kak-tree-bin = platform.buildRustPackage {
|
||||
name = "kak-tree-bin";
|
||||
src = ./.;
|
||||
cargoLock = { lockFile = ./Cargo.lock; };
|
||||
buildFeatures = ["bash" "c" "python" "rust"]; # TODO: Add agda, nix
|
||||
inherit sitterlist;
|
||||
preBuild = ''
|
||||
mkdir lib
|
||||
for sitter in $sitterlist ; do
|
||||
echo "Copying $sitter"
|
||||
cp $sitter/lib/* lib
|
||||
done
|
||||
'';
|
||||
doCheck = false;
|
||||
};
|
||||
|
||||
in rec {
|
||||
packages.bin = kak-tree-bin;
|
||||
packages.kak-tree = pkgs.stdenv.mkDerivation {
|
||||
name = "kak-tree";
|
||||
src = ./rc ;
|
||||
rtpPath = "share/kak/autoload/plugins";
|
||||
|
||||
patchPhase = ''
|
||||
sed -i -e 's|tree_cmd "kak-tree"|tree_cmd "${kak-tree-bin}/bin/kak-tree"|' tree.kak
|
||||
'';
|
||||
buildPhase = ''
|
||||
mkdir -p "$out/$rtpPath/kak-tree"
|
||||
cp * "$out/$rtpPath/kak-tree"
|
||||
'';
|
||||
};
|
||||
devShells.default = pkgs.mkShell {
|
||||
packages = [ rust ];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
79
rc/tree.kak
Normal file
79
rc/tree.kak
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Path to the kak-tree executable.
|
||||
# To load config: set-option global tree_cmd "kak-tree --config /path/to/kak-tree.toml"
|
||||
# To enable debug logging: set-option global tree_cmd "kak-tree -vvv"
|
||||
declare-option str tree_cmd "kak-tree"
|
||||
|
||||
# Path to the log file.
|
||||
declare-option str tree_log "/tmp/kak-tree.log"
|
||||
|
||||
# Option to store draft of the current buffer before passing to shell.
|
||||
declare-option -hidden str tree_draft
|
||||
|
||||
define-command -hidden tree-command -params 1..2 -docstring %{
|
||||
tree-command <OP_TYPE> [<OP_PARAMS>]
|
||||
Send request to kak-tree and evaluate response.
|
||||
} %{
|
||||
evaluate-commands -draft -no-hooks %{exec '%'; set buffer tree_draft %val{selection}}
|
||||
evaluate-commands %sh{
|
||||
|
||||
tree_draft=$(printf '%s.' "${kak_opt_tree_draft}" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed "s/$(printf '\t')/\\\\t/g")
|
||||
|
||||
tree_draft=${tree_draft%.}
|
||||
|
||||
printf '
|
||||
filetype = "%s"
|
||||
selections_desc = "%s"
|
||||
content = """
|
||||
%s"""
|
||||
[op]
|
||||
type = "%s"
|
||||
%s
|
||||
' "${kak_opt_filetype}" "${kak_selections_desc}" "${tree_draft}" $1 "$2" | ${kak_opt_tree_cmd} 2>${kak_opt_tree_log}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
define-command -hidden tree-command-with-optional-kind -params 1..2 -docstring %{
|
||||
tree-command-with-optional-kind <OP_TYPE> [<KIND>]
|
||||
Send request which optionally takes node kind.
|
||||
} %{
|
||||
tree-command %arg{1} %sh{
|
||||
if [ -n "$2" ]; then
|
||||
printf 'kind = "%s"' "$2"
|
||||
fi
|
||||
}
|
||||
}
|
||||
|
||||
define-command tree-select-parent-node -params ..1 -docstring %{
|
||||
tree-select-parent-node [<KIND>]
|
||||
Select the closest visible ancestor or ancestor of KIND when provided.
|
||||
} %{ tree-command-with-optional-kind SelectParentNode %arg{1} }
|
||||
|
||||
define-command tree-select-next-node -params ..1 -docstring %{
|
||||
tree-select-next-node [<KIND>]
|
||||
Select the closest visible next sibling or next sibling of KIND when provided.
|
||||
} %{ tree-command-with-optional-kind SelectNextNode %arg{1} }
|
||||
|
||||
define-command tree-select-previous-node -params ..1 -docstring %{
|
||||
tree-select-previous-node [<KIND>]
|
||||
Select the closest visible previous sibling or previous sibling of KIND when provided.
|
||||
} %{ tree-command-with-optional-kind SelectPreviousNode %arg{1} }
|
||||
|
||||
define-command tree-select-children -params ..1 -docstring %{
|
||||
tree-select-children [<KIND>]
|
||||
Select all immediate visible children or all descendants matching KIND when provided.
|
||||
} %{ tree-command-with-optional-kind SelectChildren %arg{1} }
|
||||
|
||||
define-command tree-node-sexp -docstring %{
|
||||
tree-node-sexp
|
||||
Show info box with a syntax tree of the main selection parent.
|
||||
} %{ tree-command NodeSExp }
|
||||
|
||||
define-command tree-select-first-child -params ..1 -docstring %{
|
||||
tree-select-first-child [<KIND>]
|
||||
Select the first immediate visible children or the first descendant matching KIND when provided.
|
||||
} %{
|
||||
tree-command-with-optional-kind SelectChildren %arg{1}
|
||||
execute-keys <space>
|
||||
}
|
||||
|
70
src/config.rs
Normal file
70
src/config.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use toml;
|
||||
use tree_sitter::Node;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
filetype: HashMap<String, FiletypeConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct FiletypeConfig {
|
||||
blacklist: Option<Vec<String>>,
|
||||
whitelist: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
group: HashMap<String, Vec<String>>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
let mut config = Config {
|
||||
filetype: HashMap::default(),
|
||||
};
|
||||
config
|
||||
.filetype
|
||||
.insert("default".to_owned(), FiletypeConfig::default());
|
||||
config
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Option<Self> {
|
||||
let config = std::fs::read_to_string(path).ok()?;
|
||||
let mut config: Config = toml::from_str(&config).ok()?;
|
||||
if config.filetype.get("default").is_none() {
|
||||
config
|
||||
.filetype
|
||||
.insert("default".to_owned(), FiletypeConfig::default());
|
||||
}
|
||||
Some(config)
|
||||
}
|
||||
|
||||
pub fn get_filetype_config<'a>(&'a self, filetype: &str) -> &'a FiletypeConfig {
|
||||
self.filetype
|
||||
.get(filetype)
|
||||
.or_else(|| self.filetype.get("default"))
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl FiletypeConfig {
|
||||
pub fn is_node_visible(&self, node: Node) -> bool {
|
||||
let kind = node.kind();
|
||||
match &self.whitelist {
|
||||
Some(whitelist) => whitelist.iter().any(|x| x == kind),
|
||||
None => match &self.blacklist {
|
||||
Some(blacklist) => !blacklist.iter().any(|x| x == kind),
|
||||
None => true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_alias<'a>(&'a self, kind: &str) -> Vec<String> {
|
||||
self.group
|
||||
.get(kind)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| vec![kind.to_string()])
|
||||
}
|
||||
}
|
99
src/ffi.rs
Normal file
99
src/ffi.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
use tree_sitter::Language;
|
||||
|
||||
extern "C" {
|
||||
#[cfg(feature = "bash")]
|
||||
fn tree_sitter_bash() -> Language;
|
||||
#[cfg(feature = "c")]
|
||||
fn tree_sitter_c() -> Language;
|
||||
#[cfg(feature = "c_sharp")]
|
||||
fn tree_sitter_c_sharp() -> Language;
|
||||
#[cfg(feature = "clojure")]
|
||||
fn tree_sitter_clojure() -> Language;
|
||||
#[cfg(feature = "cpp")]
|
||||
fn tree_sitter_cpp() -> Language;
|
||||
#[cfg(feature = "css")]
|
||||
fn tree_sitter_css() -> Language;
|
||||
#[cfg(feature = "elm")]
|
||||
fn tree_sitter_elm() -> Language;
|
||||
#[cfg(feature = "go")]
|
||||
fn tree_sitter_go() -> Language;
|
||||
#[cfg(feature = "haskell")]
|
||||
fn tree_sitter_haskell() -> Language;
|
||||
#[cfg(feature = "html")]
|
||||
fn tree_sitter_html() -> Language;
|
||||
#[cfg(feature = "java")]
|
||||
fn tree_sitter_java() -> Language;
|
||||
#[cfg(feature = "javascript")]
|
||||
fn tree_sitter_javascript() -> Language;
|
||||
#[cfg(feature = "json")]
|
||||
fn tree_sitter_json() -> Language;
|
||||
#[cfg(feature = "julia")]
|
||||
fn tree_sitter_julia() -> Language;
|
||||
#[cfg(feature = "ocaml")]
|
||||
fn tree_sitter_ocaml() -> Language;
|
||||
#[cfg(feature = "php")]
|
||||
fn tree_sitter_php() -> Language;
|
||||
#[cfg(feature = "python")]
|
||||
fn tree_sitter_python() -> Language;
|
||||
#[cfg(feature = "racket")]
|
||||
fn tree_sitter_racket() -> Language;
|
||||
#[cfg(feature = "ruby")]
|
||||
fn tree_sitter_ruby() -> Language;
|
||||
#[cfg(feature = "rust")]
|
||||
fn tree_sitter_rust() -> Language;
|
||||
#[cfg(feature = "scala")]
|
||||
fn tree_sitter_scala() -> Language;
|
||||
#[cfg(feature = "typescript")]
|
||||
fn tree_sitter_typescript() -> Language;
|
||||
}
|
||||
|
||||
pub fn filetype_to_language(filetype: &str) -> Option<Language> {
|
||||
let sitter = match filetype {
|
||||
#[cfg(feature = "bash")]
|
||||
"sh" => tree_sitter_bash,
|
||||
#[cfg(feature = "c")]
|
||||
"c" => tree_sitter_c,
|
||||
#[cfg(feature = "c_sharp")]
|
||||
"c_sharp" => tree_sitter_c_sharp,
|
||||
#[cfg(feature = "clojure")]
|
||||
"clojure" => tree_sitter_clojure,
|
||||
#[cfg(feature = "cpp")]
|
||||
"cpp" => tree_sitter_cpp,
|
||||
#[cfg(feature = "css")]
|
||||
"css" => tree_sitter_css,
|
||||
#[cfg(feature = "elm")]
|
||||
"elm" => tree_sitter_elm,
|
||||
#[cfg(feature = "go")]
|
||||
"go" => tree_sitter_go,
|
||||
#[cfg(feature = "haskell")]
|
||||
"haskell" => tree_sitter_haskell,
|
||||
#[cfg(feature = "html")]
|
||||
"html" => tree_sitter_html,
|
||||
#[cfg(feature = "java")]
|
||||
"java" => tree_sitter_java,
|
||||
#[cfg(feature = "javascript")]
|
||||
"javascript" => tree_sitter_javascript,
|
||||
#[cfg(feature = "json")]
|
||||
"json" => tree_sitter_json,
|
||||
#[cfg(feature = "julia")]
|
||||
"julia" => tree_sitter_julia,
|
||||
#[cfg(feature = "ocaml")]
|
||||
"ocaml" => tree_sitter_ocaml,
|
||||
#[cfg(feature = "php")]
|
||||
"php" => tree_sitter_php,
|
||||
#[cfg(feature = "python")]
|
||||
"python" => tree_sitter_python,
|
||||
#[cfg(feature = "racket")]
|
||||
"racket" => tree_sitter_racket,
|
||||
#[cfg(feature = "ruby")]
|
||||
"ruby" => tree_sitter_ruby,
|
||||
#[cfg(feature = "rust")]
|
||||
"rust" => tree_sitter_rust,
|
||||
#[cfg(feature = "scala")]
|
||||
"scala" => tree_sitter_scala,
|
||||
#[cfg(feature = "typescript")]
|
||||
"typescript" => tree_sitter_typescript,
|
||||
_ => return None,
|
||||
};
|
||||
Some(unsafe { sitter() })
|
||||
}
|
89
src/kakoune.rs
Normal file
89
src/kakoune.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
use itertools::Itertools;
|
||||
use tree_sitter::{Point, Range};
|
||||
|
||||
pub fn select_ranges(buffer: &[String], ranges: &[Range]) -> String {
|
||||
if ranges.is_empty() {
|
||||
"fail no selections remaining".into()
|
||||
} else {
|
||||
format!("select {}", ranges_to_selections_desc(&buffer, &ranges))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ranges_to_selections_desc(buffer: &[String], ranges: &[Range]) -> String {
|
||||
ranges
|
||||
.iter()
|
||||
.map(|range| {
|
||||
let mut end_row = range.end_point.row;
|
||||
let mut end_column = range.end_point.column;
|
||||
if end_column > 0 {
|
||||
end_column -= 1;
|
||||
} else {
|
||||
end_row -= 1;
|
||||
end_column = 1_000_000;
|
||||
}
|
||||
format!(
|
||||
"{},{}",
|
||||
point_to_kak_coords(buffer, range.start_point),
|
||||
point_to_kak_coords(buffer, Point::new(end_row, end_column))
|
||||
)
|
||||
})
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
pub fn selections_desc_to_ranges(buffer: &[String], selections_desc: &str) -> Vec<Range> {
|
||||
selections_desc
|
||||
.split_whitespace()
|
||||
.map(|selection_desc| selection_desc_to_range(buffer, selection_desc))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn selection_desc_to_range(buffer: &[String], selection_desc: &str) -> Range {
|
||||
let mut range = selection_desc.split(',');
|
||||
let start = range.next().unwrap();
|
||||
let end = range.next().unwrap();
|
||||
let (start_byte, start_point) = kak_coords_to_byte_and_point(buffer, start);
|
||||
let (end_byte, end_point) = kak_coords_to_byte_and_point(buffer, end);
|
||||
let reverse = start_byte > end_byte;
|
||||
if reverse {
|
||||
Range {
|
||||
start_byte: end_byte,
|
||||
end_byte: start_byte,
|
||||
start_point: end_point,
|
||||
end_point: start_point,
|
||||
}
|
||||
} else {
|
||||
Range {
|
||||
start_byte,
|
||||
end_byte,
|
||||
start_point,
|
||||
end_point,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn point_to_kak_coords(buffer: &[String], p: Point) -> String {
|
||||
let offset = buffer[p.row]
|
||||
.char_indices()
|
||||
.enumerate()
|
||||
.find_map(|(column, (offset, _))| {
|
||||
if column == p.column {
|
||||
Some(offset)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| buffer[p.row].len());
|
||||
format!("{}.{}", p.row + 1, offset + 1)
|
||||
}
|
||||
|
||||
fn kak_coords_to_byte_and_point(buffer: &[String], coords: &str) -> (usize, Point) {
|
||||
let mut coords = coords.split('.');
|
||||
let row = coords.next().unwrap().parse::<usize>().unwrap() - 1;
|
||||
let offset = coords.next().unwrap().parse::<usize>().unwrap() - 1;
|
||||
let byte = buffer[..row].iter().fold(0, |offset, c| offset + c.len()) + offset;
|
||||
let column = buffer[row]
|
||||
.char_indices()
|
||||
.position(|(i, _)| i == offset)
|
||||
.unwrap();
|
||||
(byte, Point::new(row, column))
|
||||
}
|
19
src/log.rs
Normal file
19
src/log.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use sloggers::terminal::{Destination, TerminalLoggerBuilder};
|
||||
use sloggers::types::Severity;
|
||||
use sloggers::Build;
|
||||
|
||||
pub fn init_global_logger(verbosity: u8) {
|
||||
let level = match verbosity {
|
||||
0 => Severity::Error,
|
||||
1 => Severity::Warning,
|
||||
2 => Severity::Info,
|
||||
3 => Severity::Debug,
|
||||
_ => Severity::Trace,
|
||||
};
|
||||
|
||||
let mut builder = TerminalLoggerBuilder::new();
|
||||
builder.level(level);
|
||||
builder.destination(Destination::Stderr);
|
||||
let logger = builder.build().unwrap();
|
||||
let _guard = slog_scope::set_global_logger(logger);
|
||||
}
|
229
src/main.rs
Normal file
229
src/main.rs
Normal file
|
@ -0,0 +1,229 @@
|
|||
use crate::config::{Config, FiletypeConfig};
|
||||
use clap::{crate_version, App, Arg};
|
||||
use serde::Deserialize;
|
||||
use std::io::Read;
|
||||
use toml;
|
||||
use tree_sitter::{Node, Parser, Range};
|
||||
|
||||
mod config;
|
||||
mod ffi;
|
||||
mod kakoune;
|
||||
mod log;
|
||||
mod tree;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Request {
|
||||
op: Op,
|
||||
filetype: String,
|
||||
selections_desc: String,
|
||||
content: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
enum Op {
|
||||
NodeSExp,
|
||||
SelectChildren { kind: Option<String> },
|
||||
SelectNextNode { kind: Option<String> },
|
||||
SelectParentNode { kind: Option<String> },
|
||||
SelectPreviousNode { kind: Option<String> },
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let matches = cli();
|
||||
|
||||
let verbosity = matches.occurrences_of("v") as u8;
|
||||
log::init_global_logger(verbosity);
|
||||
|
||||
if let Some(filetype) = matches.value_of("do-you-understand") {
|
||||
let language = ffi::filetype_to_language(filetype);
|
||||
std::process::exit(if language.is_some() { 0 } else { 1 });
|
||||
}
|
||||
|
||||
let config = if let Some(config_path) = matches.value_of("config") {
|
||||
Config::load(config_path).unwrap()
|
||||
} else {
|
||||
Config::default()
|
||||
};
|
||||
|
||||
let mut request = String::new();
|
||||
std::io::stdin().read_to_string(&mut request).unwrap();
|
||||
let request: Request = toml::from_str(&request).unwrap();
|
||||
let response = handle_request(&config, &request);
|
||||
println!("{}", response);
|
||||
}
|
||||
|
||||
fn cli() -> clap::ArgMatches<'static> {
|
||||
App::new("kak-tree")
|
||||
.version(crate_version!())
|
||||
.author("Ruslan Prokopchuk <fer.obbee@gmail.com>")
|
||||
.about("Structural selections for Kakoune")
|
||||
.arg(
|
||||
Arg::with_name("config")
|
||||
.short("c")
|
||||
.long("config")
|
||||
.value_name("FILE")
|
||||
.help("Read config from FILE")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("do-you-understand")
|
||||
.long("do-you-understand")
|
||||
.value_name("FILETYPE")
|
||||
.help("Exit with 0 if FILETYPE is supported, non-zero otherwise")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("v")
|
||||
.short("v")
|
||||
.multiple(true)
|
||||
.help("Sets the level of verbosity"),
|
||||
)
|
||||
.get_matches()
|
||||
}
|
||||
|
||||
fn handle_request(config: &Config, request: &Request) -> String {
|
||||
let mut parser = Parser::new();
|
||||
let language = ffi::filetype_to_language(&request.filetype).unwrap();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(&request.content, None).unwrap();
|
||||
let buffer = request
|
||||
.content
|
||||
.split('\n')
|
||||
.map(|s| format!("{}\n", s))
|
||||
.collect::<Vec<_>>();
|
||||
let ranges = kakoune::selections_desc_to_ranges(&buffer, &request.selections_desc);
|
||||
let mut new_ranges = Vec::new();
|
||||
let filetype_config = config.get_filetype_config(&request.filetype);
|
||||
match &request.op {
|
||||
Op::SelectParentNode { kind } => {
|
||||
let kinds = kind
|
||||
.as_ref()
|
||||
.and_then(|kind| Some(filetype_config.resolve_alias(kind)));
|
||||
for range in &ranges {
|
||||
let node = tree::shrink_to_range(tree.root_node(), range);
|
||||
let node = find_parent_of_interest(filetype_config, node, &kinds);
|
||||
new_ranges.push(node.range());
|
||||
}
|
||||
kakoune::select_ranges(&buffer, &new_ranges)
|
||||
}
|
||||
Op::SelectNextNode { kind } => {
|
||||
let kinds = kind
|
||||
.as_ref()
|
||||
.and_then(|kind| Some(filetype_config.resolve_alias(kind)));
|
||||
'outer_next: for range in &ranges {
|
||||
let node = tree::shrink_to_range(tree.root_node(), range);
|
||||
let mut cursor = traverse_up_to_node_which_matters(filetype_config, node);
|
||||
while let Some(node) = cursor.next_named_sibling() {
|
||||
if filetype_config.is_node_visible(node) && node_of_kinds(node, &kinds) {
|
||||
new_ranges.push(node.range());
|
||||
continue 'outer_next;
|
||||
}
|
||||
cursor = node;
|
||||
}
|
||||
let node = find_parent_of_interest(filetype_config, node, &kinds);
|
||||
new_ranges.push(node.range());
|
||||
}
|
||||
kakoune::select_ranges(&buffer, &new_ranges)
|
||||
}
|
||||
Op::SelectPreviousNode { kind } => {
|
||||
let kinds = kind
|
||||
.as_ref()
|
||||
.and_then(|kind| Some(filetype_config.resolve_alias(kind)));
|
||||
'outer_prev: for range in &ranges {
|
||||
let node = tree::shrink_to_range(tree.root_node(), range);
|
||||
let mut cursor = traverse_up_to_node_which_matters(filetype_config, node);
|
||||
while let Some(node) = cursor.prev_named_sibling() {
|
||||
if filetype_config.is_node_visible(node) && node_of_kinds(node, &kinds) {
|
||||
new_ranges.push(node.range());
|
||||
continue 'outer_prev;
|
||||
}
|
||||
cursor = node;
|
||||
}
|
||||
let node = find_parent_of_interest(filetype_config, node, &kinds);
|
||||
new_ranges.push(node.range());
|
||||
}
|
||||
kakoune::select_ranges(&buffer, &new_ranges)
|
||||
}
|
||||
Op::SelectChildren { kind } => {
|
||||
match kind {
|
||||
Some(kind) => {
|
||||
let kinds = filetype_config.resolve_alias(kind);
|
||||
for range in &ranges {
|
||||
for node in tree::nodes_in_range(tree.root_node(), range) {
|
||||
select_nodes(&node, &kinds, &mut new_ranges);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
for range in &ranges {
|
||||
let node = tree::shrink_to_range(tree.root_node(), range);
|
||||
for child in tree::named_children(&node) {
|
||||
if filetype_config.is_node_visible(child) {
|
||||
new_ranges.push(child.range());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kakoune::select_ranges(&buffer, &new_ranges)
|
||||
}
|
||||
Op::NodeSExp => {
|
||||
let node = tree::shrink_to_range(tree.root_node(), &ranges[0]);
|
||||
format!("info '{}'", node.to_sexp())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn select_nodes(node: &Node, kinds: &[String], new_ranges: &mut Vec<Range>) {
|
||||
if kinds.iter().any(|kind| kind == node.kind()) {
|
||||
new_ranges.push(node.range());
|
||||
} else {
|
||||
for child in tree::named_children(&node) {
|
||||
if kinds.iter().any(|kind| kind == child.kind()) {
|
||||
new_ranges.push(child.range());
|
||||
} else {
|
||||
select_nodes(&child, kinds, new_ranges);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse_up_to_node_which_matters<'a>(
|
||||
filetype_config: &FiletypeConfig,
|
||||
current_node: Node<'a>,
|
||||
) -> Node<'a> {
|
||||
let mut opt_node = Some(current_node);
|
||||
while let Some(node) = opt_node.filter(|&n| !(n.is_named() && filetype_config.is_node_visible(n))) {
|
||||
opt_node = node.parent();
|
||||
}
|
||||
opt_node.unwrap_or(current_node)
|
||||
}
|
||||
|
||||
fn find_parent_of_interest<'a>(
|
||||
filetype_config: &FiletypeConfig,
|
||||
current_node: Node<'a>,
|
||||
kinds: &Option<Vec<String>>,
|
||||
) -> Node<'a> {
|
||||
let parent = current_node.parent();
|
||||
match &kinds {
|
||||
Some(kinds) => {
|
||||
let mut cursor = parent;
|
||||
while let Some(node) = cursor {
|
||||
if kinds.iter().any(|kind| kind == node.kind()) {
|
||||
return node;
|
||||
}
|
||||
cursor = node.parent();
|
||||
}
|
||||
current_node
|
||||
}
|
||||
None => traverse_up_to_node_which_matters(filetype_config, parent.unwrap_or(current_node)),
|
||||
}
|
||||
}
|
||||
|
||||
fn node_of_kinds(node: Node, kinds: &Option<Vec<String>>) -> bool {
|
||||
kinds
|
||||
.as_ref()
|
||||
.and_then(|kinds| Some(kinds.iter().any(|x| x == node.kind())))
|
||||
.unwrap_or(true)
|
||||
}
|
79
src/tree.rs
Normal file
79
src/tree.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
use tree_sitter::{Node, Range};
|
||||
|
||||
pub fn named_children<'a>(node: &'a Node) -> impl Iterator<Item = Node<'a>> {
|
||||
(0..node.child_count()).map(move |i| node.child(i).unwrap())
|
||||
}
|
||||
|
||||
pub fn shrink_to_range<'a>(root_node: Node<'a>, range: &Range) -> Node<'a> {
|
||||
let mut node = root_node;
|
||||
'outer: loop {
|
||||
let parent = node;
|
||||
let mut cursor = parent.walk();
|
||||
for child in parent.children(&mut cursor) {
|
||||
if child.range().start_byte <= range.start_byte
|
||||
&& range.end_byte <= child.range().end_byte
|
||||
{
|
||||
node = child;
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
return highest_node_of_same_range(node);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nodes_in_range<'a>(root_node: Node<'a>, range: &Range) -> Vec<Node<'a>> {
|
||||
let mut nodes = Vec::new();
|
||||
let node = shrink_to_range(root_node, range);
|
||||
if node.range().start_byte >= range.start_byte && range.end_byte >= node.range().end_byte {
|
||||
nodes.push(node);
|
||||
return nodes;
|
||||
}
|
||||
let mut cursor = node.walk();
|
||||
for child in node.children(&mut cursor) {
|
||||
if child.range().start_byte <= range.start_byte && range.end_byte >= child.range().end_byte
|
||||
{
|
||||
nodes.extend(nodes_in_range(
|
||||
child,
|
||||
&Range {
|
||||
start_byte: range.start_byte,
|
||||
start_point: range.start_point,
|
||||
end_byte: child.range().end_byte,
|
||||
end_point: child.range().end_point,
|
||||
},
|
||||
));
|
||||
} else if child.range().start_byte >= range.start_byte
|
||||
&& range.end_byte <= child.range().end_byte
|
||||
{
|
||||
nodes.extend(nodes_in_range(
|
||||
child,
|
||||
&Range {
|
||||
start_byte: child.range().start_byte,
|
||||
start_point: child.range().start_point,
|
||||
end_byte: range.end_byte,
|
||||
end_point: range.end_point,
|
||||
},
|
||||
));
|
||||
} else if child.range().start_byte >= range.start_byte
|
||||
&& range.end_byte >= child.range().end_byte
|
||||
{
|
||||
nodes.push(child);
|
||||
}
|
||||
}
|
||||
nodes
|
||||
}
|
||||
|
||||
fn highest_node_of_same_range<'a>(current_node: Node<'a>) -> Node<'a> {
|
||||
let start_byte = current_node.start_byte();
|
||||
let end_byte = current_node.end_byte();
|
||||
let mut node = current_node;
|
||||
while let Some(parent) = node.parent().and_then(|parent| {
|
||||
if parent.start_byte() < start_byte || end_byte < parent.end_byte() {
|
||||
None
|
||||
} else {
|
||||
Some(parent)
|
||||
}
|
||||
}) {
|
||||
node = parent
|
||||
}
|
||||
node
|
||||
}
|
Loading…
Reference in New Issue
Block a user