Compare commits

..

1 Commits
master ... cow

Author SHA1 Message Date
Austen Adler
cf6568834c Waste part of my life on stupid cows 2022-10-02 15:37:28 -04:00
23 changed files with 316 additions and 636 deletions

430
Cargo.lock generated
View File

@ -1,76 +1,44 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "alphanumeric-sort"
version = "1.5.3"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d67c60c5f10f11c6ee04de72b2dd98bb9d2548cbc314d22a609bfa8bd9e87e8f"
checksum = "20e59b2ccb4c1ffbbf45af6f493e16ac65a66981c85664f1587816c0b08cd698"
[[package]]
name = "anstream"
version = "0.6.17"
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "anstyle"
version = "1.0.9"
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
@ -80,79 +48,45 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.20"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
dependencies = [
"clap_builder",
"atty",
"bitflags",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153"
dependencies = [
"heck 0.5.0",
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.85",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "duct"
version = "0.13.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c"
dependencies = [
"libc",
"once_cell",
"os_pipe",
"shared_child",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "evalexpr"
version = "7.2.0"
version = "7.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d4fd7bd9e32c1205549decf6f36772d7b606a579b26afaffa335ae148151a5d"
checksum = "90c8b61e4acbb2e4fbcf9d4c7af4d431f38c2a60b975b1d03d0276fbb032ec5d"
[[package]]
name = "getrandom"
version = "0.2.15"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
dependencies = [
"cfg-if",
"libc",
@ -160,30 +94,34 @@ dependencies = [
]
[[package]]
name = "heck"
version = "0.4.1"
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.5.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"either",
"libc",
]
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
@ -199,10 +137,7 @@ version = "0.1.0"
dependencies = [
"alphanumeric-sort",
"clap",
"duct",
"either",
"evalexpr",
"itertools",
"kakplugin",
"linked-hash-map",
"linked_hash_set",
@ -213,16 +148,22 @@ dependencies = [
]
[[package]]
name = "libc"
version = "0.2.161"
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "linked_hash_set"
@ -235,49 +176,63 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.4"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "once_cell"
version = "1.20.2"
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "os_pipe"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"libc",
"windows-sys",
"memchr",
]
[[package]]
name = "ppv-lite86"
version = "0.2.20"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"zerocopy",
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.89"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-ident",
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.37"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
@ -305,30 +260,18 @@ dependencies = [
[[package]]
name = "rand_core"
version = "0.6.4"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.11.1"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
@ -337,25 +280,15 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.5"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustversion"
version = "1.0.18"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
[[package]]
name = "shared_child"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c"
dependencies = [
"libc",
"windows-sys",
]
checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf"
[[package]]
name = "shell-words"
@ -365,9 +298,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]]
name = "strsim"
version = "0.11.1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strum"
@ -380,147 +313,88 @@ dependencies = [
[[package]]
name = "strum_macros"
version = "0.24.3"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
checksum = "4faebde00e8ff94316c01800f9054fd2ba77d30d9e922541913051d1d978918b"
dependencies = [
"heck 0.4.1",
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 1.0.109",
"syn",
]
[[package]]
name = "syn"
version = "1.0.109"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
"unicode-xid",
]
[[package]]
name = "syn"
version = "2.0.85"
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
"winapi-util",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
[[package]]
name = "utf8parse"
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "windows-sys"
version = "0.59.0"
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"windows-targets",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"winapi",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.85",
]
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -32,7 +32,7 @@ image = "scratch"
[dependencies]
regex = "1"
clap = { version = "4", features = ["derive", "env"] }
clap = {version = "3", features = ["derive", "env"]}
alphanumeric-sort = "1"
# shellwords = {version = "1", path = "../../../git/rust-shellwords/"}
# shellwords = "1"
@ -43,9 +43,6 @@ linked-hash-map = "0.5.4"
linked_hash_set = "0.1.4"
strum_macros = "0.24"
strum = { version = "0.24", features = ["derive"] }
itertools = "0.10.5"
either = "1.8.1"
duct = "0.13.7"
[profile.release]
lto = true
@ -53,4 +50,3 @@ opt-level = "z"
strip = true
codegen-units = 1
panic = "abort"
debug = true

View File

@ -6,7 +6,7 @@
Sort by regular expression or lexicographically, find uniqes, shuffle, or evaluate rust selections without spawning a new command for each selection.
image::https://asciinema.org/a/dIQh9NtLRkzVEENxmij5qBaai.svg[link="https://asciinema.org/a/dIQh9NtLRkzVEENxmij5qBaai"]
[![asciicast](https://asciinema.org/a/dIQh9NtLRkzVEENxmij5qBaai.svg)](https://asciinema.org/a/dIQh9NtLRkzVEENxmij5qBaai)
== Example
@ -876,19 +876,12 @@ After `uniq`:
====
=== incr/decr
Select only unique selections
Increment or decrement selections
* `[AMOUNT]` - Optional increment/decrement count
* `[AMOUNT]` - Optional increment/decrement count (default: `1`)
== TODO
.Example
[%collapsible]
====
Before:
++++
++++
After `incr 3`:
++++
++++
====
* I don't know what will happen with multiline strings and regex
* Figure out how to change the `no_skip_whitespace` option name in the source
* Get sort by selections working

View File

@ -1,4 +1,3 @@
use crate::Register;
use std::{fmt, fmt::Display, num::ParseIntError};
#[derive(Debug)]
@ -23,8 +22,6 @@ pub enum KakError {
CustomStatic(&'static str),
/// The selections/selections_desc list passed was empty
SetEmptySelections,
/// The register register has no content
EmptyRegister(Register),
}
impl std::error::Error for KakError {}
@ -44,9 +41,6 @@ impl KakError {
Self::SetEmptySelections => {
String::from("Attempted to set selections/selections_desc to empty list")
}
Self::EmptyRegister(r) => {
format!("Empty register: {r}")
}
}
}
}
@ -68,7 +62,6 @@ impl Display for KakError {
f,
"Attempted to set selections/selections_desc to empty list"
),
Self::EmptyRegister(r) => write!(f, "Register {r} has no content"),
}
}
}

View File

@ -22,23 +22,6 @@ pub fn get_selections(keys: Option<&'_ str>) -> Result<Vec<Selection>, KakError>
response("%val{selections}", keys)
}
pub fn get_register_selections<R>(r: R) -> Result<Vec<Selection>, KakError>
where
R: AsRef<Register>,
{
cmd(&format!(
r#"
evaluate-commands -draft %{{
execute-keys '\"{}z';
echo -quoting shell -to-file {} -- %val{{selections}};
}}"#,
r.as_ref().kak_escaped(),
get_var("kak_response_fifo")?
))?;
let selections = shell_words::split(&fs::read_to_string(&get_var("kak_response_fifo")?)?)?;
Ok(selections)
}
/// # Errors
///
/// Will return `Err` if command fifo could not be opened, read from, or written to
@ -57,7 +40,10 @@ where
/// # Errors
///
/// Will return `Err` if command fifo could not be opened, read from, or written to
pub fn get_selections_desc_unordered(keys: Option<&str>) -> Result<Vec<SelectionDesc>, KakError> {
pub fn get_selections_desc_unordered<S>(keys: Option<S>) -> Result<Vec<SelectionDesc>, KakError>
where
S: AsRef<str>,
{
response("%val{selections_desc}", keys.as_ref())?
.iter()
.map(|sd| SelectionDesc::from_str(sd))
@ -158,6 +144,10 @@ where
write!(f, "set-register '\"'")?;
for i in selections_iter {
num_written = num_written.saturating_add(1);
// eprintln!(
// "Got response: {:?}",
// i.map_err(Into::into)?.clone().as_ref()
// );
write!(f, " '{}'", escape(i.map_err(Into::into)?.as_ref()))?;
}
@ -295,13 +285,13 @@ where
cmd(match keys.as_ref() {
None => format!(
"echo -quoting shell -to-file '{response_fifo}' -- {}",
"echo -quoting shell -to-file {response_fifo} -- {}",
msg.as_ref()
),
Some(keys) => format!(
r#"evaluate-commands -draft %{{
execute-keys '{}';
echo -quoting shell -to-file '{response_fifo}' -- {};
echo -quoting shell -to-file {response_fifo} -- {};
}}"#,
escape(keys.as_ref()),
msg.as_ref()
@ -364,12 +354,5 @@ where
}
pub fn reg(register: Register, keys: Option<&'_ str>) -> Result<Vec<String>, KakError> {
let ret = response(format!("%reg{{{}}}", register.kak_expanded()), keys)?;
// Kak returns a single empty line
if &ret[..] == [""] {
return Err(KakError::EmptyRegister(register));
}
Ok(ret)
response(format!("%reg{{{}}}", register.kak_expanded()), keys)
}

View File

@ -71,7 +71,7 @@ pub struct SelectionWithSubselections {
// }
// }
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
pub struct SelectionDesc {
pub left: AnchorPosition,
pub right: AnchorPosition,
@ -86,46 +86,6 @@ impl SelectionDesc {
s.right.row - s.left.row + 1
}
/// Gets the smallest selection that encompases both selections
///
/// ```rust
/// let sel1 = SelectionDesc {
/// left: AnchorPosition { row: 10, col: 16 },
/// right: AnchorPosition { row: 1, col: 14 },
/// };
/// let sel2 = SelectionDesc {
/// left: AnchorPosition { row: 64, col: 10 },
/// right: AnchorPosition { row: 1, col: 100 },
/// };
/// let expected_bounding = SelectionDesc {
/// left: AnchorPosition { row: 1, col: 14 },
/// right: AnchorPosition { row: 64, col: 27 },
/// };
/// assert_eq!(sel1.rev().bounding_selection(&sel1), sel1.sort());
/// assert_eq!(sel2.bounding_selection(&sel1), expected_bounding.sort());
/// assert_eq!(sel2.rev().bounding_selection(&sel1.rev()), expected_bounding.sort());
/// assert_eq!(sel2.rev().bounding_selection(&sel1), expected_bounding.sort());
/// ```
pub fn bounding_selection<SD>(&self, other: SD) -> Self
where
SD: AsRef<Self>,
{
// So left is the minimum and right is the maximum
let (a, b) = (self.sort(), other.as_ref().sort());
Self {
left: min(a.left, b.left),
right: max(a.right, b.right),
}
}
pub fn rev(&self) -> Self {
Self {
left: self.right,
right: self.left,
}
}
#[must_use]
pub fn sort(&self) -> Self {
if self.left < self.right {

View File

@ -2,7 +2,7 @@ use kakplugin::{
get_selections_desc, set_selections_desc, AnchorPosition, KakError, SelectionDesc,
};
use std::cmp::{max, min};
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
/// Bounding box mode, which selects the largest box to contain everything
#[clap(short, long, help = "Select the bonding box of all selections")]
@ -70,10 +70,10 @@ fn boxed_selections(options: &Options) -> Result<Vec<SelectionDesc>, KakError> {
let whole_line_selection_command = if options.no_newline {
// Select everything and only keep non-newlines
"xs^[^\\n]+<ret>"
"<a-x>s^[^\\n]+<ret>"
} else {
// Select everything and split
"x<a-s>"
"<a-x><a-s>"
};
// Whole-row selections split on newline
@ -128,11 +128,11 @@ fn boxed_selections(options: &Options) -> Result<Vec<SelectionDesc>, KakError> {
/// Returns a vec of `selections_desc` of the intersection of the bounding box and the component rows
///
/// This function takes a selection desc, and its whole-row split selections (`x<a-s>`).
/// This function takes a selection desc, and its whole-row split selections (`<a-x><a-s>`).
/// For each whole-row (col 1 to max col) selection, it finds the intersection between the min col and max col in `selection_desc`
///
/// * `selection_desc` - The base (possibly multiline) `selection_desc`
/// * `selections_desc_rows` - Vec of above `selection_desc` split by line (`x<a-s>`)
/// * `selections_desc_rows` - Vec of above `selection_desc` split by line (`<a-x><a-s>`)
fn to_boxed_selections<SD1, SD2>(
selection_desc: SD1,
selections_desc_rows: &[SD2],

View File

@ -2,7 +2,7 @@ use evalexpr::{eval, Value};
use kakplugin::{get_selections, set_selections, KakError};
use std::borrow::Cow;
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(index = 1, help = "Amount to increment/decrement", default_value = "1")]
amount: isize,

View File

@ -1,7 +1,7 @@
use kakplugin::{
get_selections_desc, set_selections_desc, types::MaybeSplit, KakError, SelectionDesc,
};
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(short, long, help = "Do not include newlines")]
no_newline: bool,
@ -16,7 +16,7 @@ pub fn invert(options: &Options) -> Result<String, KakError> {
// Split by multiline so subtraction is defined (see below)
// Group by row, so for a given document row, subtraction can iterate over the Vec
get_selections_desc(Some("<a-s>"))?
.chunk_by(|a, b| a.left.row == b.left.row)
.group_by(|a, b| a.left.row == b.left.row)
.map(|sds| (sds[0].left.row, sds.to_vec()))
.collect()
};
@ -29,9 +29,9 @@ pub fn invert(options: &Options) -> Result<String, KakError> {
// Select everything and split
(false, false) => "%<a-s>",
// Select entire line, then remove newline
(true, true) => "x<a-s>s^[^\\n]+<ret>",
(true, true) => "<a-x><a-s>s^[^\\n]+<ret>",
// Select entire line, including newline
(true, false) => "x<a-s>",
(true, false) => "<a-x><a-s>",
};
let document_descs: Vec<SelectionDesc> = {

View File

@ -1,14 +0,0 @@
use kakplugin::{get_selections_desc_unordered, set_selections_desc, KakError};
#[derive(clap::Args, Debug)]
pub struct Options;
pub fn join(_options: &Options) -> Result<String, KakError> {
set_selections_desc(
get_selections_desc_unordered(None)?
.into_iter()
.reduce(|acc, sd| acc.bounding_selection(sd)),
)?;
Ok(format!("Joined all selections"))
}

View File

@ -1,31 +0,0 @@
use itertools::Itertools;
use kakplugin::{get_selections_desc_unordered, set_selections_desc, KakError};
#[derive(Debug, clap::Args)]
pub struct Options {
#[clap(index = 1, value_parser = clap::value_parser!(u16).range(2..))]
keep_every: u16,
}
pub fn keep_every(options: &Options) -> Result<String, KakError> {
let old_selections_desc = get_selections_desc_unordered(None)?;
let mut new_count = 0;
set_selections_desc(
old_selections_desc
.iter()
.chunks(options.keep_every.into())
.into_iter()
.flat_map(|mut it| {
// Only keep the first selection from each chunk
new_count += 1;
it.next()
}),
)?;
Ok(format!(
"{} kept from {}",
new_count,
old_selections_desc.len()
))
}

View File

@ -5,6 +5,7 @@
// Cannot be fixed
#![allow(clippy::multiple_crate_versions)]
#![allow(clippy::struct_excessive_bools)]
#![feature(slice_group_by)]
#![feature(slice_take)]
#![feature(array_chunks)]
@ -12,11 +13,8 @@ mod box_;
mod errors;
mod incr;
mod invert;
mod join;
mod keep_every;
mod math_eval;
mod pad;
mod rev;
mod set;
mod shuf;
mod sort;
@ -71,12 +69,6 @@ enum Commands {
Decr(incr::Options),
#[clap(about = "Decrement selections")]
Incr(incr::Options),
#[clap(about = "Reverse selections")]
Rev(rev::Options),
#[clap(about = "Join selections")]
Join(join::Options),
#[clap(about = "Keep a subset of selections", visible_aliases = &["keep"])]
KeepEvery(keep_every::Options),
}
fn main() {
@ -127,8 +119,5 @@ fn run() -> Result<String, KakError> {
Commands::Xlookup(o) => xlookup::xlookup(o),
Commands::Incr(o) => incr::incr(o, true),
Commands::Decr(o) => incr::incr(o, false),
Commands::Rev(o) => rev::rev(o),
Commands::Join(o) => join::join(o),
Commands::KeepEvery(o) => keep_every::keep_every(o),
}
}

View File

@ -2,35 +2,22 @@ use evalexpr::{eval, Value};
use kakplugin::{get_selections, set_selections, KakError};
use std::borrow::Cow;
#[derive(clap::Args, Debug)]
pub struct Options {
/// Additional arguments to pass to the math evaluator
///
/// For example, you can run `kakutils-rs bc + 5` to add 5 to all selections
extra_math_args: Option<Vec<String>>,
}
pub fn math_eval(options: &Options) -> Result<String, KakError> {
#[derive(clap::StructOpt, Debug)]
pub struct Options;
pub fn math_eval(_options: &Options) -> Result<String, KakError> {
let mut err_count: usize = 0;
let selections = get_selections(None)?;
let extra = options.extra_math_args.as_ref().map(|v| v.join(" "));
set_selections(selections.iter().map(|s| {
match eval(&if let Some(e) = &extra {
Cow::Owned(format!("{s} {e}"))
} else {
Cow::Borrowed(s)
}) {
Ok(Value::Float(f)) => Cow::Owned(f.to_string()),
Ok(Value::Int(f)) => Cow::Owned(f.to_string()),
Ok(_) => Cow::Borrowed(""),
Err(e) => {
eprintln!("Error: {:?}", e);
err_count = err_count.saturating_add(1);
// Set the selection to empty
Cow::Borrowed("")
}
set_selections(selections.iter().map(|s| match eval(s) {
Ok(Value::Float(f)) => Cow::Owned(f.to_string()),
Ok(Value::Int(f)) => Cow::Owned(f.to_string()),
Ok(_) => Cow::Borrowed(""),
Err(e) => {
eprintln!("Error: {:?}", e);
err_count = err_count.saturating_add(1);
// Set the selection to empty
Cow::Borrowed("")
}
}))?;

View File

@ -2,7 +2,7 @@ use crate::utils::split_newlines;
use kakplugin::{get_selections, set_selections, KakError};
use std::borrow::Cow;
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(index = 1, help = "Pad with this char", default_value = "0")]
fill: char,

View File

@ -1,11 +0,0 @@
use kakplugin::{get_selections, set_selections, KakError};
#[derive(clap::Args, Debug)]
pub struct Options;
pub fn rev(_options: &Options) -> Result<String, KakError> {
let selections = get_selections(None)?;
set_selections(selections.iter().rev())?;
Ok(format!("Reversed {} selections", selections.len()))
}

View File

@ -1,19 +1,22 @@
// use crate::utils;
use kakplugin::{
get_register_selections, get_selections, get_selections_with_desc, set_selections_desc,
types::Register, KakError,
get_selections, get_selections_with_desc, set_selections_desc, types::Register, KakError,
Selection,
};
use linked_hash_map::LinkedHashMap;
use linked_hash_set::LinkedHashSet;
use regex::Regex;
use std::{borrow::Cow, io::Write, str::FromStr};
use std::{
borrow::{Borrow, Cow},
io::Write,
str::FromStr,
};
const KAK_BUFFER_NAME: &str = "*kakplugin-set*";
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(
num_args = 1..=3,
min_values = 1,
max_values = 3,
allow_hyphen_values = true,
help = "Register operation and operand. Empty register is current selection. Example: 'a-b' or '+b'"
)]
@ -66,102 +69,101 @@ impl FromStr for Operation {
}
}
pub fn set<'sel>(options: &'_ Options) -> Result<String, KakError> {
pub fn set(options: &Options) -> Result<String, KakError> {
// Get the actual operation we are performing
let (left_register, operation, right_register) = parse_arguments(&options.args[..])?;
// Get the selections for the left register and the right register, depending on the arguments
// Underscore is a special case. We will treat it as the current selection
let (left_selections, right_selections) = match (&left_register, &right_register) {
(Register::Underscore, r) => {
let l_selections = get_selections(None)?;
let r_selections = get_register_selections(r)?;
let (left_selections, right_selections): (Vec<Cow<str>>, Vec<Cow<str>>) = {
let (l, r): (Vec<Selection>, Vec<Selection>) = match (&left_register, &right_register) {
(Register::Underscore, r) => {
let l_selections = get_selections(None)?;
let r_selections = get_selections(Some(&format!("\"{r}z")))?;
(l_selections, r_selections)
}
(l, Register::Underscore) => {
let r_selections = get_selections(None)?;
let l_selections = get_register_selections(l)?;
(l_selections, r_selections)
}
(l, Register::Underscore) => {
let r_selections = get_selections(None)?;
let l_selections = get_selections(Some(&format!("\"{l}z")))?;
(l_selections, r_selections)
}
(l, r) => {
let l_selections = get_register_selections(l)?;
let r_selections = get_register_selections(r)?;
(l_selections, r_selections)
}
(l, r) => {
let l_selections = get_selections(Some(&format!("\"{l}z")))?;
let r_selections = get_selections(Some(&format!("\"{r}z")))?;
(l_selections, r_selections)
}
(l_selections, r_selections)
}
};
(
l.into_iter().map(|s| Cow::Owned(s)).collect(),
r.into_iter().map(|s| Cow::Owned(s)).collect(),
)
};
// Get the frequency of each selection. The count does not matter as much as presence
// Count is used only for compare
let (left_ordered_counts, right_ordered_counts) = (
to_ordered_counts(
options,
left_selections.iter().map(|s| s.as_ref()).collect(),
),
to_ordered_counts(
options,
right_selections.iter().map(|s| s.as_ref()).collect(),
),
to_ordered_counts(options, &left_selections[..]),
to_ordered_counts(options, &right_selections[..]),
);
// Get an ordered set of every key for each register
let (left_keys, right_keys) = (
left_ordered_counts
.keys()
.map(|k| -> &str { k.as_ref() })
.collect::<LinkedHashSet<&str>>(),
.map(|c| Cow::Borrowed(c.borrow()))
.collect(),
right_ordered_counts
.keys()
.map(|k| -> &str { k.as_ref() })
.collect::<LinkedHashSet<&str>>(),
.map(|c| Cow::Borrowed(c.borrow()))
.collect(),
);
// Run the actual set operation
let result = key_set_operation(&operation, &left_keys, &right_keys);
let num_modified = result.len();
let result = key_set_operation(&operation, left_keys, right_keys);
match &operation {
Operation::Compare => compare(
left_register,
right_register,
result,
&result,
&left_ordered_counts,
&right_ordered_counts,
)?,
Operation::Union => print_result(result)?,
Operation::Union => print_result(&result)?,
// Intersect/subtract will have at most the number of elements in the current selection
// If the user operated on the current selection, and we can modify the selection descs inplace, do it
Operation::Intersect | Operation::Subtract => {
if left_register == Register::Underscore {
// If the user asked for an intersection or subtraction from the current selection, we can update selection_descs only
// For example (current selection) - (contents of register a) allows us to simply deselect some selections
reduce_selections(options, result)?;
reduce_selections(options, &result)?;
} else {
// The user asked for registers that *aren't* the current selection
// This means either registers don't represent the current selection, or the current selection is on the other side
print_result(result)?;
print_result(&result)?;
}
}
}
Ok(match &operation {
Operation::Compare => format!("Compared {} selections", num_modified),
Operation::Compare => format!("Compared {} selections", result.len()),
op => format!(
"{}{}{} returned {} selections",
left_register.to_char(),
op.to_char(),
right_register.to_char(),
num_modified
result.len()
),
})
}
/// Reduces selections to those that are in the `key_set_operation_result`
fn reduce_selections<'sel, 'a>(
fn reduce_selections<'sel>(
options: &Options,
key_set_operation_result: LinkedHashSet<&'sel str>,
key_set_operation_result: &LinkedHashSet<Cow<'sel, str>>,
) -> Result<(), KakError> {
// The registers should have been read in a draft context
// So the current selection will be unmodified
@ -172,13 +174,13 @@ fn reduce_selections<'sel, 'a>(
// Since key_set_operation_result contains elements that should be in the resulting set,
// we can just use contains here
let key = crate::utils::get_key(
&swd.content,
!options.skip_whitespace,
Cow::Owned(swd.content),
options.skip_whitespace,
options.regex.as_ref(),
options.ignore_case,
);
if key_set_operation_result.contains(key.as_ref()) {
if key_set_operation_result.contains(&key) {
Some(swd.desc)
} else {
None
@ -188,8 +190,7 @@ fn reduce_selections<'sel, 'a>(
Ok(())
}
/// Writes the result of a set operation to a new kak buffer
fn print_result(key_set_operation_result: LinkedHashSet<&str>) -> Result<(), KakError> {
fn print_result(key_set_operation_result: &LinkedHashSet<Cow<str>>) -> Result<(), KakError> {
// Manually set selections so we don't have to allocate a string
let mut f = kakplugin::open_command_fifo()?;
@ -208,10 +209,9 @@ fn print_result(key_set_operation_result: LinkedHashSet<&str>) -> Result<(), Kak
write!(
f,
r#";
edit -scratch '{}';
edit -scratch '*kakplugin-set*';
execute-keys '%<a-R>_';
}}"#,
KAK_BUFFER_NAME
}}"#
)?;
f.flush()?;
@ -219,19 +219,12 @@ fn print_result(key_set_operation_result: LinkedHashSet<&str>) -> Result<(), Kak
Ok(())
}
/// Writes a comparison table to a new kak buffer
///
/// * `left_register` - Register of the left side
/// * `right_register` - Register of the right side
/// * `key_set_operation_result` - Set of selections after chosen operation
/// * `left_ordered_counts` - Map of ordered counts on `get_key` to frequency on the left side
/// * `right_ordered_counts` - Map of ordered counts on `get_key` to frequency on the right side
fn compare<'sel, 'a, 'b>(
fn compare<'sel>(
left_register: Register,
right_register: Register,
key_set_operation_result: LinkedHashSet<&'b str>,
left_ordered_counts: &'b LinkedHashMap<Cow<'sel, str>, usize>,
right_ordered_counts: &'b LinkedHashMap<Cow<'sel, str>, usize>,
key_set_operation_result: &LinkedHashSet<Cow<'sel, str>>,
left_ordered_counts: &LinkedHashMap<Cow<'sel, str>, usize>,
right_ordered_counts: &LinkedHashMap<Cow<'sel, str>, usize>,
) -> Result<(), KakError> {
// Manually set selections so we don't have to allocate a string
let mut f = kakplugin::open_command_fifo()?;
@ -251,8 +244,8 @@ fn compare<'sel, 'a, 'b>(
)?;
for k in key_set_operation_result {
let left_count = left_ordered_counts.get(k as &str).unwrap_or(&0);
let right_count = right_ordered_counts.get(k as &str).unwrap_or(&0);
let left_count = left_ordered_counts.get(k).unwrap_or(&0);
let right_count = right_ordered_counts.get(k).unwrap_or(&0);
write!(
f,
@ -272,10 +265,9 @@ fn compare<'sel, 'a, 'b>(
write!(
f,
r#";
edit -scratch '{}';
edit -scratch '*kakplugin-set*';
execute-keys '%<a-R><a-;>3<a-W>L)<a-space>_vb';
}}"#,
KAK_BUFFER_NAME
}}"#
)?;
f.flush()?;
@ -283,21 +275,16 @@ fn compare<'sel, 'a, 'b>(
Ok(())
}
/// Counts frequency of unique selection contents, while preserving document order using a `LinkedHashMap`
///
/// # Returns
///
/// `LinkedHashMap` ordered by document order with `get_key(selection, ...)` as key and frequency of selection
fn to_ordered_counts<'sel>(
options: &Options,
selections: Vec<&'sel str>,
sels: &'sel [Cow<'sel, str>],
) -> LinkedHashMap<Cow<'sel, str>, usize> {
let mut ret = LinkedHashMap::new();
for i in selections {
for i in sels {
let key = crate::utils::get_key(
&i,
!options.skip_whitespace,
Cow::Borrowed(&*i),
options.skip_whitespace,
options.regex.as_ref(),
options.ignore_case,
);
@ -313,23 +300,28 @@ fn to_ordered_counts<'sel>(
ret
}
/// Performs an `Operation` on some set of keys
/// Performs an `Operation` on some set of keys. This returns a a hashset of the operations
/// * `operation` - The operation to perform
/// * `left_keys` - The set on the left side of the operator
/// * `right_keys` - The set on the right side of the operator
fn key_set_operation<'sel>(
operation: &Operation,
left_keys: &LinkedHashSet<&'sel str>,
right_keys: &LinkedHashSet<&'sel str>,
) -> LinkedHashSet<&'sel str> {
fn key_set_operation<'a, 'sel>(
operation: &'a Operation,
left_keys: LinkedHashSet<Cow<'sel, str>>,
right_keys: LinkedHashSet<Cow<'sel, str>>,
) -> LinkedHashSet<Cow<'sel, str>> {
match operation {
Operation::Intersect => left_keys
.intersection(right_keys)
// .into_iter()
.copied()
.intersection(&right_keys)
.map(|s| Cow::Borrowed(s.borrow()))
.collect(),
Operation::Subtract => left_keys.difference(right_keys).copied().collect(),
Operation::Compare | Operation::Union => left_keys.union(right_keys).copied().collect(), // TODO: Symmetric difference?
Operation::Subtract => left_keys
.difference(&right_keys)
.map(|s| Cow::Borrowed(s.borrow()))
.collect(),
Operation::Compare | Operation::Union => left_keys
.union(&right_keys)
.map(|s| Cow::Borrowed(s.borrow()))
.collect(), // TODO: Symmetric difference?
}
}
@ -371,18 +363,9 @@ fn parse_arguments(args: &[String]) -> Result<(Register, Operation, Register), K
Register::from_str(r)?,
))
}
[middle] => {
// They gave us one argument like "-"
// Default to (current selection)(operation)(^ register (set with Z)) => _-^
Ok((
Register::Underscore,
Operation::from_str(middle)?,
Register::Caret,
))
}
_ => Err(KakError::Custom(format!(
"Invalid arguments to set command: {args:?}"
))),
_ => Err(KakError::Custom(
"Invalid arguments to set command".to_string(),
)),
}?;
if left_register == right_register {

View File

@ -1,6 +1,6 @@
use kakplugin::{get_selections, set_selections, KakError};
use rand::{seq::SliceRandom, thread_rng};
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options;
pub fn shuf(_options: &Options) -> Result<String, KakError> {
let mut selections = get_selections(None)?;

View File

@ -1,10 +1,9 @@
use alphanumeric_sort::compare_str;
use clap::ArgAction;
use kakplugin::{self, get_selections_with_desc, open_command_fifo, KakError, SelectionWithDesc};
use regex::Regex;
use std::{borrow::Cow, cmp::Ordering, io::Write};
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(index = 1, help = "Optional regex comparison key")]
regex: Option<Regex>,
@ -15,8 +14,7 @@ pub struct Options {
)]
subselections_register: Option<char>,
// TODO: Can we invert a boolean? This name is terrible
// #[clap(short = 'S', long, value_parser = invert_bool, default_value_t, help = "Do not treat trimmed value of selections when sorting")]
#[clap(short = 'S', long, action = ArgAction::SetFalse, default_value_t, help = "Do not treat trimmed value of selections when sorting")]
#[clap(short = 'S', long, parse(try_from_str = invert_bool), default_value_t, help = "Do not treat trimmed value of selections when sorting")]
no_skip_whitespace: bool,
#[clap(short = 'L', long, help = "Do not sort numbers lexicographically")]
no_lexicographic_sort: bool,
@ -26,14 +24,14 @@ pub struct Options {
ignore_case: bool,
}
// fn invert_bool(s: &str) -> Result<bool, &'static str> {
// // Invert the boolean
// match s {
// "false" => Ok(true),
// "true" => Ok(false),
// _ => Err("Unparsable boolean value"),
// }
// }
fn invert_bool(s: &str) -> Result<bool, &'static str> {
// Invert the boolean
match s {
"false" => Ok(true),
"true" => Ok(false),
_ => Err("Unparsable boolean value"),
}
}
struct SortableSelection<'a> {
/// The content of the selection

View File

@ -1,7 +1,7 @@
use kakplugin::{get_selections, open_command_fifo, KakError};
use std::io::Write;
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(short, long, help = "Trim from left")]
left: bool,

View File

@ -6,7 +6,7 @@ use kakplugin::{
use regex::Regex;
use std::collections::BTreeSet;
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(index = 1, help = "Optional regex to compare unique elements")]
regex: Option<Regex>,

View File

@ -1,38 +1,26 @@
// use kakplugin::Selection;
use kakplugin::Selection;
use regex::Regex;
use std::{
borrow::Cow,
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
/// Gets a key out of a selection
///
/// # Examples
///
/// ```
/// assert_eq!(get_key(" asdf\n", false, None, false), "asdf\n");
/// assert_eq!(get_key(" asdf\n", true, None, false), " asdf\n");
/// assert_eq!(get_key(" as1f\n", false, Some("\w+"), false), "as");
/// assert_eq!(get_key(" aS1F\n", false, Some("\w+"), true), "as1f");
/// ```
pub fn get_key<'sel>(
selection: &'sel str,
preserve_whitespace: bool,
pub fn get_key(
// TODO: Use Cow
selection: &Selection,
skip_whitespace: bool,
regex: Option<&Regex>,
ignore_case: bool,
) -> Cow<'sel, str> {
) -> String {
// Strip whitespace if requested
let mut key = if preserve_whitespace {
// TODO: Does this need to be swapped?
selection
let mut key = if skip_whitespace {
selection.as_str()
} else {
selection.trim()
};
// If they requested a regex match, set the key to the string slice of that match
if let Some(regex_match) = (|| {
// let captures = regex.as_ref()?.captures(&key)?;
let captures = regex.as_ref()?.captures(key)?;
captures
.get(1)
@ -40,35 +28,29 @@ pub fn get_key<'sel>(
.map(|m| m.as_str())
})() {
key = regex_match;
// Cow::Borrowed(regex_match)
}
// Ignore case if requested
// Lowercase at the end to not mangle regex
if ignore_case {
// Lowercase at the end to not mangle regex
// TODO: Do not allocate if it is already lowercased
// Need to_lowercase(&self) -> Cow<str>
if !key.as_bytes().iter().any(u8::is_ascii_uppercase) {
Cow::Borrowed(key)
} else {
Cow::Owned(key.to_ascii_lowercase())
}
key.to_lowercase()
} else {
Cow::Borrowed(key)
// TODO: Do not perform an allocation here
key.to_string()
}
}
/// Get a key out of a selection based on options
pub fn get_hash(
// TODO: Accept any Into<AsRef<Selection>>
selection: &str,
preserve_whitespace: bool,
selection: &Selection,
skip_whitespace: bool,
regex: Option<&Regex>,
ignore_case: bool,
) -> u64 {
let mut hasher = DefaultHasher::new();
get_key(&selection, preserve_whitespace, regex, ignore_case).hash(&mut hasher);
get_key(selection, skip_whitespace, regex, ignore_case).hash(&mut hasher);
hasher.finish()
}

View File

@ -3,7 +3,7 @@ use std::{
io::{BufRead, BufReader, Write},
process::{Command, Stdio},
};
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap()]
command: String,

View File

@ -8,15 +8,13 @@ use std::{
},
};
#[derive(clap::Args, Debug)]
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(help = "Register with the lookup table", default_value = "^")]
#[clap(help = "Register with the lookup table", default_value = "\"")]
register: Register,
}
pub fn xlookup(options: &Options) -> Result<String, KakError> {
eprintln!("Getting registers for {options:?}");
let lookup_table = build_lookuptable(kakplugin::get_register_selections(options.register)?)?;
// let lookup_table = build_lookuptable(kakplugin::reg(options.register, None)?)?;
let lookup_table = build_lookuptable(kakplugin::reg(options.register, None)?)?;
let selections = get_selections(None)?;
@ -24,7 +22,7 @@ pub fn xlookup(options: &Options) -> Result<String, KakError> {
set_selections(selections.iter().map(|key| {
lookup_table
.get(&get_hash(&key, false, None, false))
.get(&get_hash(key, false, None, false))
.map_or_else(
|| {
eprintln!("Key '{key}' not found",);
@ -50,7 +48,7 @@ pub fn xlookup(options: &Options) -> Result<String, KakError> {
fn build_lookuptable(mut selections: Vec<Selection>) -> Result<BTreeMap<u64, Selection>, KakError> {
let mut iter = selections.array_chunks_mut();
let ret = iter.try_fold(BTreeMap::new(), |mut acc, [key, value]| {
match acc.entry(get_hash(&key, false, None, false)) {
match acc.entry(get_hash(key, false, None, false)) {
Occupied(_) => Err(KakError::Custom(format!("Duplicate key '{key}'"))),
Vacant(v) => {
v.insert(value.clone());
@ -78,7 +76,7 @@ mod tests {
}
macro_rules! hsh {
($expr:expr) => {
get_hash($expr, false, None, false)
get_hash(&$expr.to_string(), false, None, false)
};
}
#[test]