mirror of
https://github.com/TECHNOFAB11/tmux-copyrat.git
synced 2025-12-12 16:10:07 +01:00
feat: copyrat
This commit is contained in:
parent
0d45a2872a
commit
37f22b67af
11 changed files with 840 additions and 728 deletions
|
|
@ -1,2 +1,13 @@
|
||||||
tab_spaces = 2
|
format_code_in_doc_comments = true
|
||||||
max_width = 120
|
match_block_trailing_comma = true
|
||||||
|
condense_wildcard_suffixes = true
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
overflow_delimited_expr = true
|
||||||
|
# width_heuristics = "Max"
|
||||||
|
normalize_comments = true
|
||||||
|
reorder_impl_items = true
|
||||||
|
use_try_shorthand = true
|
||||||
|
newline_style = "Unix"
|
||||||
|
format_strings = true
|
||||||
|
wrap_comments = true
|
||||||
|
# comment_width = 100
|
||||||
|
|
|
||||||
175
Cargo.lock
generated
175
Cargo.lock
generated
|
|
@ -8,14 +8,6 @@ dependencies = [
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ansi_term"
|
|
||||||
version = "0.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
|
@ -26,6 +18,11 @@ dependencies = [
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
|
@ -33,18 +30,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.33.0"
|
version = "3.0.0-beta.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap_derive 3.0.0-beta.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"os_str_bytes 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"term_size 1.0.0-beta1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "3.0.0-beta.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro-error 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "copyrat"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap 3.0.0-beta.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|
@ -61,6 +84,23 @@ dependencies = [
|
||||||
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
@ -81,12 +121,17 @@ name = "numtoa"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.2"
|
version = "0.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro-error-attr 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
@ -95,7 +140,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error-attr"
|
name = "proc-macro-error-attr"
|
||||||
version = "1.0.2"
|
version = "0.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
@ -152,31 +197,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "structopt"
|
|
||||||
version = "0.3.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"structopt-derive 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "structopt-derive"
|
|
||||||
version = "0.4.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.23"
|
version = "1.0.23"
|
||||||
|
|
@ -197,6 +220,33 @@ dependencies = [
|
||||||
"syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "term_size"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "term_size"
|
||||||
|
version = "1.0.0-beta1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termion"
|
name = "termion"
|
||||||
version = "1.5.5"
|
version = "1.5.5"
|
||||||
|
|
@ -213,6 +263,7 @@ name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"term_size 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -224,16 +275,6 @@ dependencies = [
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thumbs"
|
|
||||||
version = "0.4.1"
|
|
||||||
dependencies = [
|
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
|
@ -259,6 +300,11 @@ name = "version_check"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
|
@ -268,11 +314,24 @@ dependencies = [
|
||||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-build"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
@ -280,29 +339,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
|
||||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
"checksum clap 3.0.0-beta.1 (registry+https://github.com/rust-lang/crates.io-index)" = "860643c53f980f0d38a5e25dfab6c3c93b2cb3aa1fe192643d17a293c6c41936"
|
||||||
|
"checksum clap_derive 3.0.0-beta.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb51c9e75b94452505acd21d929323f5a5c6c4735a852adbd39ef5fb1b014f30"
|
||||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
"checksum hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
|
"checksum hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
|
||||||
|
"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
|
||||||
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
"checksum libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
|
"checksum libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
|
||||||
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||||
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||||
"checksum proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
|
"checksum os_str_bytes 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06de47b848347d8c4c94219ad8ecd35eb90231704b067e67e6ae2e36ee023510"
|
||||||
"checksum proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
|
"checksum proc-macro-error 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7"
|
||||||
|
"checksum proc-macro-error-attr 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de"
|
||||||
"checksum proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "de40dd4ff82d9c9bab6dae29dbab1167e515f8df9ed17d2987cb6012db206933"
|
"checksum proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "de40dd4ff82d9c9bab6dae29dbab1167e515f8df9ed17d2987cb6012db206933"
|
||||||
"checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
|
"checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
|
||||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||||
"checksum regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
|
"checksum regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
|
||||||
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
"checksum strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
"checksum structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef"
|
|
||||||
"checksum structopt-derive 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a"
|
|
||||||
"checksum syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269"
|
"checksum syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269"
|
||||||
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
||||||
|
"checksum term_size 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||||
|
"checksum term_size 1.0.0-beta1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8a17d8699e154863becdf18e4fd28bd0be27ca72856f54daf75c00f2566898f"
|
||||||
|
"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
|
||||||
"checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905"
|
"checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905"
|
||||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||||
|
|
@ -311,6 +375,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||||
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||||
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||||
|
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
|
||||||
17
Cargo.toml
17
Cargo.toml
|
|
@ -1,23 +1,22 @@
|
||||||
[package]
|
[package]
|
||||||
name = "thumbs"
|
name = "copyrat"
|
||||||
version = "0.4.1"
|
version = "0.1.0"
|
||||||
authors = ["Ferran Basora <fcsonline@gmail.com>"]
|
authors = ["Ferran Basora <fcsonline@gmail.com>", "u0xy <u0xy@u0xy.cc>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "A lightning fast version copy/pasting like vimium/vimperator"
|
description = "This is tmux-copycat on Rust steroids."
|
||||||
repository = "https://github.com/fcsonline/tmux-thumbs"
|
repository = "https://github.com/fcsonline/tmux-thumbs"
|
||||||
keywords = ["rust", "tmux", "tmux-plugin", "vimium", "vimperator"]
|
keywords = ["rust", "tmux", "tmux-plugin", "tmux-copycat"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
termion = "1.5"
|
termion = "1.5"
|
||||||
regex = "1.3.1"
|
regex = "1.3.1"
|
||||||
clap = "2.33.0"
|
clap = { version = "3.0.0-beta.1", features = ["suggestions", "color", "wrap_help", "term_size"]}
|
||||||
structopt = { version = "0.3", default-features = false }
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "thumbs"
|
name = "copyrat"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "tmux-thumbs"
|
name = "tmux-copyrat"
|
||||||
path = "src/swapper.rs"
|
path = "src/swapper.rs"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::HashMap;
|
use crate::error;
|
||||||
|
|
||||||
const ALPHABETS: [(&'static str, &'static str); 22] = [
|
const ALPHABETS: [(&'static str, &'static str); 22] = [
|
||||||
("numeric", "1234567890"),
|
("numeric", "1234567890"),
|
||||||
|
|
@ -25,17 +25,17 @@ const ALPHABETS: [(&'static str, &'static str); 22] = [
|
||||||
("colemak-right-hand", "neioluymjhk"),
|
("colemak-right-hand", "neioluymjhk"),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub struct Alphabet<'a> {
|
// pub struct Alphabet<'a> {
|
||||||
letters: &'a str,
|
// letters: &'a str,
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl<'a> Alphabet<'a> {
|
/// Type-safe string alphabet (newtype).
|
||||||
fn new(letters: &'a str) -> Alphabet {
|
#[derive(Debug)]
|
||||||
Alphabet { letters }
|
pub struct Alphabet(pub String);
|
||||||
}
|
|
||||||
|
|
||||||
|
impl Alphabet {
|
||||||
pub fn hints(&self, matches: usize) -> Vec<String> {
|
pub fn hints(&self, matches: usize) -> Vec<String> {
|
||||||
let letters: Vec<String> = self.letters.chars().map(|s| s.to_string()).collect();
|
let letters: Vec<String> = self.0.chars().map(|s| s.to_string()).collect();
|
||||||
|
|
||||||
let mut expansion = letters.clone();
|
let mut expansion = letters.clone();
|
||||||
let mut expanded: Vec<String> = Vec::new();
|
let mut expanded: Vec<String> = Vec::new();
|
||||||
|
|
@ -64,14 +64,22 @@ impl<'a> Alphabet<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_alphabet(alphabet_name: &str) -> Alphabet {
|
// pub fn get_alphabet(alphabet_name: &str) -> Alphabet {
|
||||||
let alphabets: HashMap<&str, &str> = ALPHABETS.iter().cloned().collect();
|
// let alphabets: HashMap<&str, &str> = ALPHABETS.iter().cloned().collect();
|
||||||
|
|
||||||
alphabets
|
// alphabets
|
||||||
.get(alphabet_name)
|
// .get(alphabet_name)
|
||||||
.expect(format!("Unknown alphabet: {}", alphabet_name).as_str()); // FIXME
|
// .expect(format!("Unknown alphabet: {}", alphabet_name).as_str());
|
||||||
|
|
||||||
Alphabet::new(alphabets[alphabet_name])
|
// Alphabet::new(alphabets[alphabet_name])
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn parse_alphabet(src: &str) -> Result<Alphabet, error::ParseError> {
|
||||||
|
let alphabet = ALPHABETS.iter().find(|&(name, _letters)| name == &src);
|
||||||
|
match alphabet {
|
||||||
|
Some((_name, letters)) => Ok(Alphabet(letters.to_string())),
|
||||||
|
None => Err(error::ParseError::UnknownAlphabet),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -80,28 +88,28 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_matches() {
|
fn simple_matches() {
|
||||||
let alphabet = Alphabet::new("abcd");
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
let hints = alphabet.hints(3);
|
let hints = alphabet.hints(3);
|
||||||
assert_eq!(hints, ["a", "b", "c"]);
|
assert_eq!(hints, ["a", "b", "c"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn composed_matches() {
|
fn composed_matches() {
|
||||||
let alphabet = Alphabet::new("abcd");
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
let hints = alphabet.hints(6);
|
let hints = alphabet.hints(6);
|
||||||
assert_eq!(hints, ["a", "b", "c", "da", "db", "dc"]);
|
assert_eq!(hints, ["a", "b", "c", "da", "db", "dc"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn composed_matches_multiple() {
|
fn composed_matches_multiple() {
|
||||||
let alphabet = Alphabet::new("abcd");
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
let hints = alphabet.hints(8);
|
let hints = alphabet.hints(8);
|
||||||
assert_eq!(hints, ["a", "b", "ca", "cb", "da", "db", "dc", "dd"]);
|
assert_eq!(hints, ["a", "b", "ca", "cb", "da", "db", "dc", "dd"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn composed_matches_max() {
|
fn composed_matches_max() {
|
||||||
let alphabet = Alphabet::new("ab");
|
let alphabet = Alphabet("ab".to_string());
|
||||||
let hints = alphabet.hints(8);
|
let hints = alphabet.hints(8);
|
||||||
assert_eq!(hints, ["aa", "ab", "ba", "bb"]);
|
assert_eq!(hints, ["aa", "ab", "ba", "bb"]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,39 @@
|
||||||
|
use crate::error;
|
||||||
use termion::color;
|
use termion::color;
|
||||||
|
|
||||||
pub fn get_color(color_name: &str) -> Box<&dyn color::Color> {
|
pub fn parse_color(src: &str) -> Result<Box<dyn color::Color>, error::ParseError> {
|
||||||
match color_name {
|
match src {
|
||||||
"black" => Box::new(&color::Black),
|
"black" => Ok(Box::new(color::Black)),
|
||||||
"red" => Box::new(&color::Red),
|
"red" => Ok(Box::new(color::Red)),
|
||||||
"green" => Box::new(&color::Green),
|
"green" => Ok(Box::new(color::Green)),
|
||||||
"yellow" => Box::new(&color::Yellow),
|
"yellow" => Ok(Box::new(color::Yellow)),
|
||||||
"blue" => Box::new(&color::Blue),
|
"blue" => Ok(Box::new(color::Blue)),
|
||||||
"magenta" => Box::new(&color::Magenta),
|
"magenta" => Ok(Box::new(color::Magenta)),
|
||||||
"cyan" => Box::new(&color::Cyan),
|
"cyan" => Ok(Box::new(color::Cyan)),
|
||||||
"white" => Box::new(&color::White),
|
"white" => Ok(Box::new(color::White)),
|
||||||
"default" => Box::new(&color::Reset),
|
// "default" => Ok(Box::new(color::Reset)),
|
||||||
_ => panic!("Unknown color: {}", color_name),
|
_ => Err(error::ParseError::UnknownColor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_color() {
|
fn match_color() {
|
||||||
let text1 = println!("{}{}", color::Fg(*get_color("green")), "foo");
|
let text1 = format!(
|
||||||
let text2 = println!("{}{}", color::Fg(color::Green), "foo");
|
"{}{}",
|
||||||
|
color::Fg(parse_color("green").unwrap().as_ref()),
|
||||||
|
"foo"
|
||||||
|
);
|
||||||
|
let text2 = format!("{}{}", color::Fg(color::Green), "foo");
|
||||||
|
|
||||||
assert_eq!(text1, text2);
|
assert_eq!(text1, text2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
fn no_match_color() {
|
||||||
fn no_match_color() {
|
assert!(parse_color("wat").is_err(), "this color should not exist");
|
||||||
println!("{}{}", color::Fg(*get_color("wat")), "foo");
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/error.rs
Normal file
18
src/error.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParseError {
|
||||||
|
ExpectedSurroundingPair,
|
||||||
|
UnknownAlphabet,
|
||||||
|
UnknownColor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ParseError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ParseError::ExpectedSurroundingPair => write!(f, "Expected 2 chars"),
|
||||||
|
ParseError::UnknownAlphabet => write!(f, "Expected a known alphabet"),
|
||||||
|
ParseError::UnknownColor => write!(f, "Expected ANSI color name (magenta, cyan, black, ...)"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
354
src/main.rs
354
src/main.rs
|
|
@ -1,239 +1,159 @@
|
||||||
extern crate clap;
|
use clap::Clap;
|
||||||
extern crate termion;
|
|
||||||
|
|
||||||
mod alphabets;
|
|
||||||
mod colors;
|
|
||||||
mod state;
|
|
||||||
mod view;
|
|
||||||
|
|
||||||
use self::clap::{App, Arg};
|
|
||||||
use clap::crate_version;
|
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use structopt::StructOpt;
|
use std::path;
|
||||||
|
|
||||||
// TODO: position as an enum ::Leading ::Trailing
|
mod alphabets;
|
||||||
|
mod colors;
|
||||||
|
mod error;
|
||||||
|
mod state;
|
||||||
|
mod view;
|
||||||
|
|
||||||
/// A lightning fast version copy/pasting like vimium/vimperator.
|
/// Main configuration, parsed from command line.
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(Clap, Debug)]
|
||||||
#[structopt(name = "thumbs")]
|
#[clap(author, about, version)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
/// Sets the alphabet.
|
/// Alphabet to draw hints from.
|
||||||
#[structopt(short, long, default_value = "qwerty")]
|
///
|
||||||
alphabet: String,
|
/// Possible values are "{A}", "{A}-homerow", "{A}-left-hand",
|
||||||
|
/// "{A}-right-hand", where "{A}" is one of "qwerty", "azerty", "qwertz",
|
||||||
|
/// "dvorak", "colemak". Examples: "qwerty", "dvorak-homerow".
|
||||||
|
#[clap(short = "k", long, default_value = "qwerty",
|
||||||
|
parse(try_from_str = alphabets::parse_alphabet))]
|
||||||
|
alphabet: alphabets::Alphabet,
|
||||||
|
|
||||||
/// Sets the foreground color for matches.
|
/// Enable multi-selection.
|
||||||
#[structopt(long, default_value = "green")]
|
#[clap(short, long)]
|
||||||
fg_color: String,
|
multi_selection: bool,
|
||||||
|
|
||||||
/// Sets the background color for matches.
|
#[clap(flatten)]
|
||||||
#[structopt(long, default_value = "black")]
|
colors: view::ViewColors,
|
||||||
bg_color: String,
|
|
||||||
|
/// Reverse the order for assigned hints.
|
||||||
|
#[clap(short, long)]
|
||||||
|
reverse: bool,
|
||||||
|
|
||||||
|
/// Keep the same hint for identical matches.
|
||||||
|
#[clap(short, long)]
|
||||||
|
unique: bool,
|
||||||
|
|
||||||
|
/// Align hint with its match.
|
||||||
|
#[clap(short = "a", long, arg_enum, default_value = "Leading")]
|
||||||
|
hint_alignment: view::HintAlignment,
|
||||||
|
|
||||||
|
/// Additional regex patterns.
|
||||||
|
#[clap(short = "c", long)]
|
||||||
|
custom_regex: Vec<String>,
|
||||||
|
|
||||||
|
/// Optional hint styling.
|
||||||
|
///
|
||||||
|
/// Underline or surround the hint for increased visibility.
|
||||||
|
/// If not provided, only the hint colors will be used.
|
||||||
|
#[clap(short = "s", long, arg_enum)]
|
||||||
|
hint_style: Option<HintStyleCli>,
|
||||||
|
|
||||||
|
/// Chars surrounding each hint, used with `Surrounded` style.
|
||||||
|
#[clap(long, default_value = "{}",
|
||||||
|
parse(try_from_str = parse_chars))]
|
||||||
|
hint_surroundings: (char, char),
|
||||||
|
|
||||||
|
/// Target path where to store the selected matches.
|
||||||
|
#[clap(short = "o", long = "output", parse(from_os_str))]
|
||||||
|
target_path: Option<path::PathBuf>,
|
||||||
|
|
||||||
|
/// Only output if key was uppercased.
|
||||||
|
#[clap(long)]
|
||||||
|
uppercased: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app_args<'a>() -> clap::ArgMatches<'a> {
|
/// Type introduced due to parsing limitation,
|
||||||
App::new("thumbs")
|
/// as we cannot directly parse into view::HintStyle.
|
||||||
.version(crate_version!())
|
#[derive(Debug, Clap)]
|
||||||
.about("A lightning fast version copy/pasting like vimium/vimperator")
|
enum HintStyleCli {
|
||||||
.arg(
|
Underlined,
|
||||||
Arg::with_name("alphabet")
|
Surrounded,
|
||||||
.help("Sets the alphabet")
|
}
|
||||||
.long("alphabet")
|
|
||||||
.short("a")
|
fn parse_chars(src: &str) -> Result<(char, char), error::ParseError> {
|
||||||
.default_value("qwerty"),
|
if src.len() != 2 {
|
||||||
)
|
return Err(error::ParseError::ExpectedSurroundingPair);
|
||||||
.arg(
|
}
|
||||||
Arg::with_name("format")
|
|
||||||
.help("Specifies the out format for the picked hint. (%U: Upcase, %H: Hint)")
|
let chars: Vec<char> = src.chars().collect();
|
||||||
.long("format")
|
Ok((chars[0], chars[1]))
|
||||||
.short("f")
|
|
||||||
.default_value("%H"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("foreground_color")
|
|
||||||
.help("Sets the foregroud color for matches")
|
|
||||||
.long("fg-color")
|
|
||||||
.default_value("green"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("background_color")
|
|
||||||
.help("Sets the background color for matches")
|
|
||||||
.long("bg-color")
|
|
||||||
.default_value("black"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("hint_foreground_color")
|
|
||||||
.help("Sets the foregroud color for hints")
|
|
||||||
.long("hint-fg-color")
|
|
||||||
.default_value("yellow"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("hint_background_color")
|
|
||||||
.help("Sets the background color for hints")
|
|
||||||
.long("hint-bg-color")
|
|
||||||
.default_value("black"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("select_foreground_color")
|
|
||||||
.help("Sets the foreground color for selection")
|
|
||||||
.long("select-fg-color")
|
|
||||||
.default_value("blue"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("select_background_color")
|
|
||||||
.help("Sets the background color for selection")
|
|
||||||
.long("select-bg-color")
|
|
||||||
.default_value("black"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("multi")
|
|
||||||
.help("Enable multi-selection")
|
|
||||||
.long("multi")
|
|
||||||
.short("m"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("reverse")
|
|
||||||
.help("Reverse the order for assigned hints")
|
|
||||||
.long("reverse")
|
|
||||||
.short("r"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("unique")
|
|
||||||
.help("Don't show duplicated hints for the same match")
|
|
||||||
.long("unique")
|
|
||||||
.short("u"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("position")
|
|
||||||
.help("Hint position")
|
|
||||||
.long("position")
|
|
||||||
.default_value("left")
|
|
||||||
.short("p"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("regexp")
|
|
||||||
.help("Use this regexp as extra pattern to match")
|
|
||||||
.long("regexp")
|
|
||||||
.short("x")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("contrast")
|
|
||||||
.help("Put square brackets around hint for visibility")
|
|
||||||
.long("contrast")
|
|
||||||
.short("c"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("target")
|
|
||||||
.help("Stores the hint in the specified path")
|
|
||||||
.long("target")
|
|
||||||
.short("t")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.get_matches()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = app_args();
|
let opt = Opt::parse();
|
||||||
let format = args.value_of("format").unwrap();
|
|
||||||
let alphabet = args.value_of("alphabet").unwrap();
|
|
||||||
let position = args.value_of("position").unwrap();
|
|
||||||
let target = args.value_of("target");
|
|
||||||
let multi = args.is_present("multi");
|
|
||||||
let reverse = args.is_present("reverse");
|
|
||||||
let unique = args.is_present("unique");
|
|
||||||
let contrast = args.is_present("contrast");
|
|
||||||
let regexp = if let Some(items) = args.values_of("regexp") {
|
|
||||||
items.collect::<Vec<_>>()
|
|
||||||
} else {
|
|
||||||
[].to_vec()
|
|
||||||
};
|
|
||||||
|
|
||||||
let foreground_color = colors::get_color(args.value_of("foreground_color").unwrap());
|
// Copy the pane contents (piped in via stdin) into a buffer, and split lines.
|
||||||
let background_color = colors::get_color(args.value_of("background_color").unwrap());
|
let stdin = io::stdin();
|
||||||
let hint_foreground_color = colors::get_color(args.value_of("hint_foreground_color").unwrap());
|
let mut handle = stdin.lock();
|
||||||
let hint_background_color = colors::get_color(args.value_of("hint_background_color").unwrap());
|
|
||||||
let select_foreground_color = colors::get_color(args.value_of("select_foreground_color").unwrap());
|
|
||||||
let select_background_color = colors::get_color(args.value_of("select_background_color").unwrap());
|
|
||||||
|
|
||||||
// Copy the pane contents (piped in via stdin) into a buffer, and split lines.
|
let mut buffer = String::new();
|
||||||
let mut buffer = String::new();
|
handle.read_to_string(&mut buffer).unwrap();
|
||||||
let stdin = io::stdin();
|
let lines: Vec<&str> = buffer.split('\n').collect();
|
||||||
let mut handle = stdin.lock();
|
|
||||||
|
|
||||||
handle.read_to_string(&mut buffer).unwrap();
|
let mut state = state::State::new(&lines, &opt.alphabet, &opt.custom_regex);
|
||||||
|
|
||||||
let lines: Vec<&str> = buffer.split('\n').collect();
|
let hint_style = match opt.hint_style {
|
||||||
|
None => None,
|
||||||
|
Some(style) => match style {
|
||||||
|
HintStyleCli::Underlined => Some(view::HintStyle::Underlined),
|
||||||
|
HintStyleCli::Surrounded => {
|
||||||
|
let (open, close) = opt.hint_surroundings;
|
||||||
|
Some(view::HintStyle::Surrounded(open, close))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let uppercase_flag = opt.uppercased;
|
||||||
|
|
||||||
let mut state = state::State::new(&lines, alphabet, ®exp);
|
let selections = {
|
||||||
|
let mut viewbox = view::View::new(
|
||||||
|
&mut state,
|
||||||
|
opt.multi_selection,
|
||||||
|
opt.reverse,
|
||||||
|
opt.unique,
|
||||||
|
opt.hint_alignment,
|
||||||
|
&opt.colors,
|
||||||
|
hint_style,
|
||||||
|
);
|
||||||
|
|
||||||
let hint_alignment = if position == "left" {
|
viewbox.present()
|
||||||
view::HintAlignment::Leading
|
};
|
||||||
} else {
|
|
||||||
view::HintAlignment::Trailing
|
|
||||||
};
|
|
||||||
|
|
||||||
let rendering_colors = view::ViewColors {
|
// Early exit, signaling tmux we had no selections.
|
||||||
focus_fg: select_foreground_color,
|
if selections.is_empty() {
|
||||||
focus_bg: select_background_color,
|
::std::process::exit(1);
|
||||||
match_fg: foreground_color,
|
}
|
||||||
match_bg: background_color,
|
|
||||||
hint_fg: hint_foreground_color,
|
let output = selections
|
||||||
hint_bg: hint_background_color,
|
.iter()
|
||||||
};
|
.map(|(text, uppercased)| {
|
||||||
|
let upcase_value = if *uppercased { "true" } else { "false" };
|
||||||
let hint_style = if contrast {
|
|
||||||
Some(view::HintStyle::Surrounded('[', ']'))
|
let output = if uppercase_flag { upcase_value } else { text };
|
||||||
} else {
|
// let mut output = &opt.format;
|
||||||
None
|
|
||||||
};
|
// output = str::replace(&output, "%U", upcase_value);
|
||||||
|
// output = str::replace(&output, "%H", text.as_str());
|
||||||
let selections = {
|
output
|
||||||
let mut viewbox = view::View::new(
|
})
|
||||||
&mut state,
|
.collect::<Vec<&str>>()
|
||||||
multi,
|
.join("\n");
|
||||||
reverse,
|
|
||||||
unique,
|
match opt.target_path {
|
||||||
hint_alignment,
|
None => println!("{}", output),
|
||||||
&rendering_colors,
|
Some(target) => {
|
||||||
hint_style,
|
let mut file = OpenOptions::new()
|
||||||
);
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
viewbox.present()
|
.write(true)
|
||||||
};
|
.open(target)
|
||||||
|
.expect("Unable to open the target file");
|
||||||
// Early exit, signaling tmux we had no selections.
|
|
||||||
if selections.is_empty() {
|
file.write(output.as_bytes()).unwrap();
|
||||||
::std::process::exit(1);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let output = selections
|
|
||||||
.iter()
|
|
||||||
.map(|(text, upcase)| {
|
|
||||||
let upcase_value = if *upcase { "true" } else { "false" };
|
|
||||||
|
|
||||||
let mut output = format.to_string();
|
|
||||||
|
|
||||||
output = str::replace(&output, "%U", upcase_value);
|
|
||||||
output = str::replace(&output, "%H", text.as_str());
|
|
||||||
output
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
match target {
|
|
||||||
None => println!("{}", output),
|
|
||||||
Some(target) => {
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.create(true)
|
|
||||||
.truncate(true)
|
|
||||||
.write(true)
|
|
||||||
.open(target)
|
|
||||||
.expect("Unable to open the target file");
|
|
||||||
|
|
||||||
file.write(output.as_bytes()).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
75
src/state.rs
75
src/state.rs
|
|
@ -1,3 +1,4 @@
|
||||||
|
use super::alphabets::Alphabet;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
@ -52,12 +53,12 @@ impl<'a> PartialEq for Match<'a> {
|
||||||
|
|
||||||
pub struct State<'a> {
|
pub struct State<'a> {
|
||||||
pub lines: &'a Vec<&'a str>,
|
pub lines: &'a Vec<&'a str>,
|
||||||
alphabet: &'a str,
|
alphabet: &'a Alphabet,
|
||||||
regexp: &'a Vec<&'a str>,
|
regexp: &'a Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
pub fn new(lines: &'a Vec<&'a str>, alphabet: &'a str, regexp: &'a Vec<&'a str>) -> State<'a> {
|
pub fn new(lines: &'a Vec<&'a str>, alphabet: &'a Alphabet, regexp: &'a Vec<String>) -> State<'a> {
|
||||||
State {
|
State {
|
||||||
lines,
|
lines,
|
||||||
alphabet,
|
alphabet,
|
||||||
|
|
@ -133,8 +134,8 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let alphabet = super::alphabets::get_alphabet(self.alphabet);
|
// let alphabet = super::alphabets::get_alphabet(self.alphabet);
|
||||||
let mut hints = alphabet.hints(matches.len());
|
let mut hints = self.alphabet.hints(matches.len());
|
||||||
|
|
||||||
// This looks wrong but we do a pop after
|
// This looks wrong but we do a pop after
|
||||||
if !reverse {
|
if !reverse {
|
||||||
|
|
@ -174,6 +175,7 @@ impl<'a> State<'a> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::alphabets::Alphabet;
|
||||||
|
|
||||||
fn split(output: &str) -> Vec<&str> {
|
fn split(output: &str) -> Vec<&str> {
|
||||||
output.split("\n").collect::<Vec<&str>>()
|
output.split("\n").collect::<Vec<&str>>()
|
||||||
|
|
@ -183,7 +185,8 @@ mod tests {
|
||||||
fn match_reverse() {
|
fn match_reverse() {
|
||||||
let lines = split("lorem 127.0.0.1 lorem 255.255.255.255 lorem 127.0.0.1 lorem");
|
let lines = split("lorem 127.0.0.1 lorem 255.255.255.255 lorem 127.0.0.1 lorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 3);
|
assert_eq!(results.len(), 3);
|
||||||
assert_eq!(results.first().unwrap().hint.clone().unwrap(), "a");
|
assert_eq!(results.first().unwrap().hint.clone().unwrap(), "a");
|
||||||
|
|
@ -194,7 +197,8 @@ mod tests {
|
||||||
fn match_unique() {
|
fn match_unique() {
|
||||||
let lines = split("lorem 127.0.0.1 lorem 255.255.255.255 lorem 127.0.0.1 lorem");
|
let lines = split("lorem 127.0.0.1 lorem 255.255.255.255 lorem 127.0.0.1 lorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, true);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, true);
|
||||||
|
|
||||||
assert_eq!(results.len(), 3);
|
assert_eq!(results.len(), 3);
|
||||||
assert_eq!(results.first().unwrap().hint.clone().unwrap(), "a");
|
assert_eq!(results.first().unwrap().hint.clone().unwrap(), "a");
|
||||||
|
|
@ -205,7 +209,8 @@ mod tests {
|
||||||
fn match_docker() {
|
fn match_docker() {
|
||||||
let lines = split("latest sha256:30557a29d5abc51e5f1d5b472e79b7e296f595abcf19fe6b9199dbbc809c6ff4 20 hours ago");
|
let lines = split("latest sha256:30557a29d5abc51e5f1d5b472e79b7e296f595abcf19fe6b9199dbbc809c6ff4 20 hours ago");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 1);
|
assert_eq!(results.len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -218,7 +223,8 @@ mod tests {
|
||||||
fn match_bash() {
|
fn match_bash() {
|
||||||
let lines = split("path: [32m/var/log/nginx.log[m\npath: [32mtest/log/nginx-2.log:32[mfolder/.nginx@4df2.log");
|
let lines = split("path: [32m/var/log/nginx.log[m\npath: [32mtest/log/nginx-2.log:32[mfolder/.nginx@4df2.log");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 3);
|
assert_eq!(results.len(), 3);
|
||||||
assert_eq!(results.get(0).unwrap().text, "/var/log/nginx.log");
|
assert_eq!(results.get(0).unwrap().text, "/var/log/nginx.log");
|
||||||
|
|
@ -230,7 +236,8 @@ mod tests {
|
||||||
fn match_paths() {
|
fn match_paths() {
|
||||||
let lines = split("Lorem /tmp/foo/bar_lol, lorem\n Lorem /var/log/boot-strap.log lorem ../log/kern.log lorem");
|
let lines = split("Lorem /tmp/foo/bar_lol, lorem\n Lorem /var/log/boot-strap.log lorem ../log/kern.log lorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 3);
|
assert_eq!(results.len(), 3);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "/tmp/foo/bar_lol");
|
assert_eq!(results.get(0).unwrap().text.clone(), "/tmp/foo/bar_lol");
|
||||||
|
|
@ -242,7 +249,8 @@ mod tests {
|
||||||
fn match_home() {
|
fn match_home() {
|
||||||
let lines = split("Lorem ~/.gnu/.config.txt, lorem");
|
let lines = split("Lorem ~/.gnu/.config.txt, lorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 1);
|
assert_eq!(results.len(), 1);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "~/.gnu/.config.txt");
|
assert_eq!(results.get(0).unwrap().text.clone(), "~/.gnu/.config.txt");
|
||||||
|
|
@ -252,7 +260,8 @@ mod tests {
|
||||||
fn match_uids() {
|
fn match_uids() {
|
||||||
let lines = split("Lorem ipsum 123e4567-e89b-12d3-a456-426655440000 lorem\n Lorem lorem lorem");
|
let lines = split("Lorem ipsum 123e4567-e89b-12d3-a456-426655440000 lorem\n Lorem lorem lorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 1);
|
assert_eq!(results.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
@ -261,7 +270,8 @@ mod tests {
|
||||||
fn match_shas() {
|
fn match_shas() {
|
||||||
let lines = split("Lorem fd70b5695 5246ddf f924213 lorem\n Lorem 973113963b491874ab2e372ee60d4b4cb75f717c lorem");
|
let lines = split("Lorem fd70b5695 5246ddf f924213 lorem\n Lorem 973113963b491874ab2e372ee60d4b4cb75f717c lorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 4);
|
assert_eq!(results.len(), 4);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "fd70b5695");
|
assert_eq!(results.get(0).unwrap().text.clone(), "fd70b5695");
|
||||||
|
|
@ -277,7 +287,8 @@ mod tests {
|
||||||
fn match_ips() {
|
fn match_ips() {
|
||||||
let lines = split("Lorem ipsum 127.0.0.1 lorem\n Lorem 255.255.10.255 lorem 127.0.0.1 lorem");
|
let lines = split("Lorem ipsum 127.0.0.1 lorem\n Lorem 255.255.10.255 lorem 127.0.0.1 lorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 3);
|
assert_eq!(results.len(), 3);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "127.0.0.1");
|
assert_eq!(results.get(0).unwrap().text.clone(), "127.0.0.1");
|
||||||
|
|
@ -289,7 +300,8 @@ mod tests {
|
||||||
fn match_ipv6s() {
|
fn match_ipv6s() {
|
||||||
let lines = split("Lorem ipsum fe80::2:202:fe4 lorem\n Lorem 2001:67c:670:202:7ba8:5e41:1591:d723 lorem fe80::2:1 lorem ipsum fe80:22:312:fe::1%eth0");
|
let lines = split("Lorem ipsum fe80::2:202:fe4 lorem\n Lorem 2001:67c:670:202:7ba8:5e41:1591:d723 lorem fe80::2:1 lorem ipsum fe80:22:312:fe::1%eth0");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 4);
|
assert_eq!(results.len(), 4);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "fe80::2:202:fe4");
|
assert_eq!(results.get(0).unwrap().text.clone(), "fe80::2:202:fe4");
|
||||||
|
|
@ -305,7 +317,8 @@ mod tests {
|
||||||
fn match_markdown_urls() {
|
fn match_markdown_urls() {
|
||||||
let lines = split("Lorem ipsum [link](https://github.io?foo=bar)  lorem");
|
let lines = split("Lorem ipsum [link](https://github.io?foo=bar)  lorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 2);
|
assert_eq!(results.len(), 2);
|
||||||
assert_eq!(results.get(0).unwrap().pattern.clone(), "markdown_url");
|
assert_eq!(results.get(0).unwrap().pattern.clone(), "markdown_url");
|
||||||
|
|
@ -318,7 +331,8 @@ mod tests {
|
||||||
fn match_urls() {
|
fn match_urls() {
|
||||||
let lines = split("Lorem ipsum https://www.rust-lang.org/tools lorem\n Lorem ipsumhttps://crates.io lorem https://github.io?foo=bar lorem ssh://github.io");
|
let lines = split("Lorem ipsum https://www.rust-lang.org/tools lorem\n Lorem ipsumhttps://crates.io lorem https://github.io?foo=bar lorem ssh://github.io");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 4);
|
assert_eq!(results.len(), 4);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "https://www.rust-lang.org/tools");
|
assert_eq!(results.get(0).unwrap().text.clone(), "https://www.rust-lang.org/tools");
|
||||||
|
|
@ -335,7 +349,8 @@ mod tests {
|
||||||
fn match_addresses() {
|
fn match_addresses() {
|
||||||
let lines = split("Lorem 0xfd70b5695 0x5246ddf lorem\n Lorem 0x973113tlorem");
|
let lines = split("Lorem 0xfd70b5695 0x5246ddf lorem\n Lorem 0x973113tlorem");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 3);
|
assert_eq!(results.len(), 3);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "0xfd70b5695");
|
assert_eq!(results.get(0).unwrap().text.clone(), "0xfd70b5695");
|
||||||
|
|
@ -347,7 +362,8 @@ mod tests {
|
||||||
fn match_hex_colors() {
|
fn match_hex_colors() {
|
||||||
let lines = split("Lorem #fd7b56 lorem #FF00FF\n Lorem #00fF05 lorem #abcd00 lorem #afRR00");
|
let lines = split("Lorem #fd7b56 lorem #FF00FF\n Lorem #00fF05 lorem #abcd00 lorem #afRR00");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 4);
|
assert_eq!(results.len(), 4);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "#fd7b56");
|
assert_eq!(results.get(0).unwrap().text.clone(), "#fd7b56");
|
||||||
|
|
@ -360,7 +376,8 @@ mod tests {
|
||||||
fn match_ipfs() {
|
fn match_ipfs() {
|
||||||
let lines = split("Lorem QmRdbNSxDJBXmssAc9fvTtux4duptMvfSGiGuq6yHAQVKQ lorem Qmfoobar");
|
let lines = split("Lorem QmRdbNSxDJBXmssAc9fvTtux4duptMvfSGiGuq6yHAQVKQ lorem Qmfoobar");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 1);
|
assert_eq!(results.len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -374,7 +391,8 @@ mod tests {
|
||||||
let lines =
|
let lines =
|
||||||
split("Lorem 5695 52463 lorem\n Lorem 973113 lorem 99999 lorem 8888 lorem\n 23456 lorem 5432 lorem 23444");
|
split("Lorem 5695 52463 lorem\n Lorem 973113 lorem 99999 lorem 8888 lorem\n 23456 lorem 5432 lorem 23444");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 8);
|
assert_eq!(results.len(), 8);
|
||||||
}
|
}
|
||||||
|
|
@ -383,7 +401,8 @@ mod tests {
|
||||||
fn match_diff_a() {
|
fn match_diff_a() {
|
||||||
let lines = split("Lorem lorem\n--- a/src/main.rs");
|
let lines = split("Lorem lorem\n--- a/src/main.rs");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 1);
|
assert_eq!(results.len(), 1);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "src/main.rs");
|
assert_eq!(results.get(0).unwrap().text.clone(), "src/main.rs");
|
||||||
|
|
@ -393,7 +412,8 @@ mod tests {
|
||||||
fn match_diff_b() {
|
fn match_diff_b() {
|
||||||
let lines = split("Lorem lorem\n+++ b/src/main.rs");
|
let lines = split("Lorem lorem\n+++ b/src/main.rs");
|
||||||
let custom = [].to_vec();
|
let custom = [].to_vec();
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 1);
|
assert_eq!(results.len(), 1);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "src/main.rs");
|
assert_eq!(results.get(0).unwrap().text.clone(), "src/main.rs");
|
||||||
|
|
@ -402,8 +422,13 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn priority() {
|
fn priority() {
|
||||||
let lines = split("Lorem [link](http://foo.bar) ipsum CUSTOM-52463 lorem ISSUE-123 lorem\nLorem /var/fd70b569/9999.log 52463 lorem\n Lorem 973113 lorem 123e4567-e89b-12d3-a456-426655440000 lorem 8888 lorem\n https://crates.io/23456/fd70b569 lorem");
|
let lines = split("Lorem [link](http://foo.bar) ipsum CUSTOM-52463 lorem ISSUE-123 lorem\nLorem /var/fd70b569/9999.log 52463 lorem\n Lorem 973113 lorem 123e4567-e89b-12d3-a456-426655440000 lorem 8888 lorem\n https://crates.io/23456/fd70b569 lorem");
|
||||||
let custom = ["CUSTOM-[0-9]{4,}", "ISSUE-[0-9]{3}"].to_vec();
|
|
||||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
let custom: Vec<String> = ["CUSTOM-[0-9]{4,}", "ISSUE-[0-9]{3}"]
|
||||||
|
.iter()
|
||||||
|
.map(|&s| s.to_string())
|
||||||
|
.collect();
|
||||||
|
let alphabet = Alphabet("abcd".to_string());
|
||||||
|
let results = State::new(&lines, &alphabet, &custom).matches(false, false);
|
||||||
|
|
||||||
assert_eq!(results.len(), 9);
|
assert_eq!(results.len(), 9);
|
||||||
assert_eq!(results.get(0).unwrap().text.clone(), "http://foo.bar");
|
assert_eq!(results.get(0).unwrap().text.clone(), "http://foo.bar");
|
||||||
|
|
|
||||||
631
src/swapper.rs
631
src/swapper.rs
|
|
@ -1,384 +1,417 @@
|
||||||
extern crate clap;
|
use clap::Clap;
|
||||||
|
|
||||||
use self::clap::{App, Arg};
|
|
||||||
use clap::crate_version;
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
trait Executor {
|
trait Executor {
|
||||||
fn execute(&mut self, args: Vec<String>) -> String;
|
fn execute(&mut self, args: Vec<String>) -> String;
|
||||||
fn last_executed(&self) -> Option<Vec<String>>;
|
fn last_executed(&self) -> Option<Vec<String>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RealShell {
|
struct RealShell {
|
||||||
executed: Option<Vec<String>>,
|
executed: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RealShell {
|
impl RealShell {
|
||||||
fn new() -> RealShell {
|
fn new() -> RealShell {
|
||||||
RealShell { executed: None }
|
RealShell { executed: None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Executor for RealShell {
|
impl Executor for RealShell {
|
||||||
fn execute(&mut self, args: Vec<String>) -> String {
|
fn execute(&mut self, args: Vec<String>) -> String {
|
||||||
let execution = Command::new(args[0].as_str())
|
let execution = Command::new(args[0].as_str())
|
||||||
.args(&args[1..])
|
.args(&args[1..])
|
||||||
.output()
|
.output()
|
||||||
.expect("Couldn't run it");
|
.expect("Execution failed");
|
||||||
|
|
||||||
self.executed = Some(args);
|
self.executed = Some(args);
|
||||||
|
|
||||||
let output: String = String::from_utf8_lossy(&execution.stdout).into();
|
let output: String = String::from_utf8_lossy(&execution.stdout).into();
|
||||||
|
|
||||||
output.trim_end().to_string()
|
output.trim_end().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_executed(&self) -> Option<Vec<String>> {
|
fn last_executed(&self) -> Option<Vec<String>> {
|
||||||
self.executed.clone()
|
self.executed.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TMP_FILE: &str = "/tmp/thumbs-last";
|
const TMP_FILE: &str = "/tmp/thumbs-last";
|
||||||
|
|
||||||
pub struct Swapper<'a> {
|
pub struct Swapper<'a> {
|
||||||
executor: Box<&'a mut dyn Executor>,
|
executor: Box<&'a mut dyn Executor>,
|
||||||
dir: String,
|
directory: &'a path::Path,
|
||||||
command: String,
|
command: &'a str,
|
||||||
upcase_command: String,
|
alt_command: &'a str,
|
||||||
active_pane_id: Option<String>,
|
active_pane_id: Option<String>,
|
||||||
active_pane_height: Option<i32>,
|
active_pane_height: Option<i32>,
|
||||||
active_pane_scroll_position: Option<i32>,
|
active_pane_scroll_position: Option<i32>,
|
||||||
active_pane_in_copy_mode: Option<String>,
|
active_pane_in_copy_mode: Option<String>,
|
||||||
thumbs_pane_id: Option<String>,
|
thumbs_pane_id: Option<String>,
|
||||||
content: Option<String>,
|
content: Option<String>,
|
||||||
signal: String,
|
signal: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Swapper<'a> {
|
impl<'a> Swapper<'a> {
|
||||||
fn new(executor: Box<&'a mut dyn Executor>, dir: String, command: String, upcase_command: String) -> Swapper {
|
fn new(
|
||||||
let since_the_epoch = SystemTime::now()
|
executor: Box<&'a mut dyn Executor>,
|
||||||
.duration_since(UNIX_EPOCH)
|
directory: &'a path::Path,
|
||||||
.expect("Time went backwards");
|
command: &'a str,
|
||||||
let signal = format!("thumbs-finished-{}", since_the_epoch.as_secs());
|
alt_command: &'a str,
|
||||||
|
) -> Swapper<'a> {
|
||||||
|
let since_the_epoch = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("Time went backwards");
|
||||||
|
let signal = format!("thumbs-finished-{}", since_the_epoch.as_secs());
|
||||||
|
|
||||||
Swapper {
|
Swapper {
|
||||||
executor,
|
executor,
|
||||||
dir,
|
directory,
|
||||||
command,
|
command,
|
||||||
upcase_command,
|
alt_command,
|
||||||
active_pane_id: None,
|
active_pane_id: None,
|
||||||
active_pane_height: None,
|
active_pane_height: None,
|
||||||
active_pane_scroll_position: None,
|
active_pane_scroll_position: None,
|
||||||
active_pane_in_copy_mode: None,
|
active_pane_in_copy_mode: None,
|
||||||
thumbs_pane_id: None,
|
thumbs_pane_id: None,
|
||||||
content: None,
|
content: None,
|
||||||
signal,
|
signal,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn capture_active_pane(&mut self) {
|
pub fn capture_active_pane(&mut self) {
|
||||||
let active_command = vec![
|
let active_command = vec![
|
||||||
"tmux",
|
"tmux",
|
||||||
"list-panes",
|
"list-panes",
|
||||||
"-F",
|
"-F",
|
||||||
"#{pane_id}:#{?pane_in_mode,1,0}:#{pane_height}:#{scroll_position}:#{?pane_active,active,nope}",
|
"#{pane_id}:#{?pane_in_mode,1,0}:#{pane_height}:#{scroll_position}:#{?pane_active,active,nope}",
|
||||||
];
|
];
|
||||||
|
|
||||||
let output = self
|
let output = self
|
||||||
.executor
|
.executor
|
||||||
.execute(active_command.iter().map(|arg| arg.to_string()).collect());
|
.execute(active_command.iter().map(|arg| arg.to_string()).collect());
|
||||||
|
|
||||||
let lines: Vec<&str> = output.split('\n').collect();
|
let lines: Vec<&str> = output.split('\n').collect();
|
||||||
let chunks: Vec<Vec<&str>> = lines.into_iter().map(|line| line.split(':').collect()).collect();
|
let chunks: Vec<Vec<&str>> = lines
|
||||||
|
.into_iter()
|
||||||
|
.map(|line| line.split(':').collect())
|
||||||
|
.collect();
|
||||||
|
|
||||||
let active_pane = chunks
|
let active_pane = chunks
|
||||||
.iter()
|
.iter()
|
||||||
.find(|&chunks| *chunks.get(4).unwrap() == "active")
|
.find(|&chunks| *chunks.get(4).unwrap() == "active")
|
||||||
.expect("Unable to find active pane");
|
.expect("Unable to find active pane");
|
||||||
|
|
||||||
let pane_id = active_pane.get(0).unwrap();
|
let pane_id = active_pane.get(0).unwrap();
|
||||||
let pane_in_copy_mode = active_pane.get(1).unwrap().to_string();
|
let pane_in_copy_mode = active_pane.get(1).unwrap().to_string();
|
||||||
|
|
||||||
self.active_pane_id = Some(pane_id.to_string());
|
self.active_pane_id = Some(pane_id.to_string());
|
||||||
self.active_pane_in_copy_mode = Some(pane_in_copy_mode);
|
self.active_pane_in_copy_mode = Some(pane_in_copy_mode);
|
||||||
|
|
||||||
if self.active_pane_in_copy_mode.clone().unwrap() == "1" {
|
if self.active_pane_in_copy_mode.clone().unwrap() == "1" {
|
||||||
let pane_height = active_pane
|
let pane_height = active_pane
|
||||||
.get(2)
|
.get(2)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("Unable to retrieve pane height");
|
.expect("Unable to retrieve pane height");
|
||||||
let pane_scroll_position = active_pane
|
let pane_scroll_position = active_pane
|
||||||
.get(3)
|
.get(3)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("Unable to retrieve pane scroll");
|
.expect("Unable to retrieve pane scroll");
|
||||||
|
|
||||||
self.active_pane_height = Some(pane_height);
|
self.active_pane_height = Some(pane_height);
|
||||||
self.active_pane_scroll_position = Some(pane_scroll_position);
|
self.active_pane_scroll_position = Some(pane_scroll_position);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_thumbs(&mut self) {
|
|
||||||
let options_command = vec!["tmux", "show", "-g"];
|
|
||||||
let params: Vec<String> = options_command.iter().map(|arg| arg.to_string()).collect();
|
|
||||||
let options = self.executor.execute(params);
|
|
||||||
let lines: Vec<&str> = options.split('\n').collect();
|
|
||||||
|
|
||||||
let pattern = Regex::new(r#"@thumbs-([\w\-0-9]+) "?(\w+)"?"#).unwrap();
|
|
||||||
|
|
||||||
let args = lines
|
|
||||||
.iter()
|
|
||||||
.flat_map(|line| {
|
|
||||||
if let Some(captures) = pattern.captures(line) {
|
|
||||||
let name = captures.get(1).unwrap().as_str();
|
|
||||||
let value = captures.get(2).unwrap().as_str();
|
|
||||||
|
|
||||||
let boolean_params = vec!["reverse", "unique", "contrast"];
|
|
||||||
|
|
||||||
if boolean_params.iter().any(|&x| x == name) {
|
|
||||||
return vec![format!("--{}", name)];
|
|
||||||
}
|
|
||||||
|
|
||||||
let string_params = vec![
|
|
||||||
"position",
|
|
||||||
"fg-color",
|
|
||||||
"bg-color",
|
|
||||||
"hint-bg-color",
|
|
||||||
"hint-fg-color",
|
|
||||||
"select-fg-color",
|
|
||||||
"select-bg-color",
|
|
||||||
];
|
|
||||||
|
|
||||||
if string_params.iter().any(|&x| x == name) {
|
|
||||||
return vec![format!("--{}", name), format!("'{}'", value)];
|
|
||||||
}
|
|
||||||
|
|
||||||
if name.starts_with("regexp") {
|
|
||||||
return vec!["--regexp".to_string(), format!("'{}'", value)];
|
|
||||||
}
|
|
||||||
|
|
||||||
vec![]
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.collect::<Vec<String>>();
|
|
||||||
|
|
||||||
let active_pane_id = self.active_pane_id.as_mut().unwrap().clone();
|
pub fn execute_thumbs(&mut self) {
|
||||||
|
let options_command = vec!["tmux", "show", "-g"];
|
||||||
|
let params: Vec<String> = options_command.iter().map(|arg| arg.to_string()).collect();
|
||||||
|
let options = self.executor.execute(params);
|
||||||
|
let lines: Vec<&str> = options.split('\n').collect();
|
||||||
|
|
||||||
let scroll_params = if self.active_pane_in_copy_mode.is_some() {
|
let pattern = Regex::new(r#"@thumbs-([\w\-0-9]+) "?(\w+)"?"#).unwrap();
|
||||||
if let (Some(pane_height), Some(scroll_position)) =
|
|
||||||
(self.active_pane_scroll_position, self.active_pane_scroll_position)
|
|
||||||
{
|
|
||||||
format!(" -S {} -E {}", -scroll_position, pane_height - scroll_position - 1)
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE: For debugging add echo $PWD && sleep 5 after tee
|
let args = lines
|
||||||
let pane_command = format!(
|
.iter()
|
||||||
|
.flat_map(|line| {
|
||||||
|
if let Some(captures) = pattern.captures(line) {
|
||||||
|
let name = captures.get(1).unwrap().as_str();
|
||||||
|
let value = captures.get(2).unwrap().as_str();
|
||||||
|
|
||||||
|
let boolean_params = vec!["reverse", "unique", "contrast"];
|
||||||
|
|
||||||
|
if boolean_params.iter().any(|&x| x == name) {
|
||||||
|
return vec![format!("--{}", name)];
|
||||||
|
}
|
||||||
|
|
||||||
|
let string_params = vec![
|
||||||
|
"position",
|
||||||
|
"fg-color",
|
||||||
|
"bg-color",
|
||||||
|
"hint-bg-color",
|
||||||
|
"hint-fg-color",
|
||||||
|
"select-fg-color",
|
||||||
|
"select-bg-color",
|
||||||
|
];
|
||||||
|
|
||||||
|
if string_params.iter().any(|&x| x == name) {
|
||||||
|
return vec![format!("--{}", name), format!("'{}'", value)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if name.starts_with("regexp") {
|
||||||
|
return vec!["--regexp".to_string(), format!("'{}'", value)];
|
||||||
|
}
|
||||||
|
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let active_pane_id = self.active_pane_id.as_mut().unwrap().clone();
|
||||||
|
|
||||||
|
let scroll_params = if self.active_pane_in_copy_mode.is_some() {
|
||||||
|
if let (Some(pane_height), Some(scroll_position)) = (
|
||||||
|
self.active_pane_scroll_position,
|
||||||
|
self.active_pane_scroll_position,
|
||||||
|
) {
|
||||||
|
format!(
|
||||||
|
" -S {} -E {}",
|
||||||
|
-scroll_position,
|
||||||
|
pane_height - scroll_position - 1
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: For debugging add echo $PWD && sleep 5 after tee
|
||||||
|
let pane_command = format!(
|
||||||
"tmux capture-pane -t {} -p{} | {}/target/release/thumbs -f '%U:%H' -t {} {}; tmux swap-pane -t {}; tmux wait-for -S {}",
|
"tmux capture-pane -t {} -p{} | {}/target/release/thumbs -f '%U:%H' -t {} {}; tmux swap-pane -t {}; tmux wait-for -S {}",
|
||||||
active_pane_id,
|
active_pane_id,
|
||||||
scroll_params,
|
scroll_params,
|
||||||
self.dir,
|
self.directory.to_str().unwrap(),
|
||||||
TMP_FILE,
|
TMP_FILE,
|
||||||
args.join(" "),
|
args.join(" "),
|
||||||
active_pane_id,
|
active_pane_id,
|
||||||
self.signal
|
self.signal
|
||||||
);
|
);
|
||||||
|
|
||||||
let thumbs_command = vec![
|
let thumbs_command = vec![
|
||||||
"tmux",
|
"tmux",
|
||||||
"new-window",
|
"new-window",
|
||||||
"-P",
|
"-P",
|
||||||
"-d",
|
"-d",
|
||||||
"-n",
|
"-n",
|
||||||
"[thumbs]",
|
"[thumbs]",
|
||||||
pane_command.as_str(),
|
pane_command.as_str(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let params: Vec<String> = thumbs_command.iter().map(|arg| arg.to_string()).collect();
|
let params: Vec<String> = thumbs_command.iter().map(|arg| arg.to_string()).collect();
|
||||||
|
|
||||||
self.thumbs_pane_id = Some(self.executor.execute(params));
|
self.thumbs_pane_id = Some(self.executor.execute(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swap_panes(&mut self) {
|
pub fn swap_panes(&mut self) {
|
||||||
let active_pane_id = self.active_pane_id.as_mut().unwrap().clone();
|
let active_pane_id = self.active_pane_id.as_mut().unwrap().clone();
|
||||||
let thumbs_pane_id = self.thumbs_pane_id.as_mut().unwrap().clone();
|
let thumbs_pane_id = self.thumbs_pane_id.as_mut().unwrap().clone();
|
||||||
|
|
||||||
let swap_command = vec![
|
let swap_command = vec![
|
||||||
"tmux",
|
"tmux",
|
||||||
"swap-pane",
|
"swap-pane",
|
||||||
"-d",
|
"-d",
|
||||||
"-s",
|
"-s",
|
||||||
active_pane_id.as_str(),
|
active_pane_id.as_str(),
|
||||||
"-t",
|
"-t",
|
||||||
thumbs_pane_id.as_str(),
|
thumbs_pane_id.as_str(),
|
||||||
];
|
];
|
||||||
let params = swap_command.iter().map(|arg| arg.to_string()).collect();
|
let params = swap_command.iter().map(|arg| arg.to_string()).collect();
|
||||||
|
|
||||||
self.executor.execute(params);
|
self.executor.execute(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_thumbs(&mut self) {
|
pub fn wait_thumbs(&mut self) {
|
||||||
let wait_command = vec!["tmux", "wait-for", self.signal.as_str()];
|
let wait_command = vec!["tmux", "wait-for", self.signal.as_str()];
|
||||||
let params = wait_command.iter().map(|arg| arg.to_string()).collect();
|
let params = wait_command.iter().map(|arg| arg.to_string()).collect();
|
||||||
|
|
||||||
self.executor.execute(params);
|
self.executor.execute(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retrieve_content(&mut self) {
|
pub fn retrieve_content(&mut self) {
|
||||||
let retrieve_command = vec!["cat", TMP_FILE];
|
let retrieve_command = vec!["cat", TMP_FILE];
|
||||||
let params = retrieve_command.iter().map(|arg| arg.to_string()).collect();
|
let params = retrieve_command.iter().map(|arg| arg.to_string()).collect();
|
||||||
|
|
||||||
self.content = Some(self.executor.execute(params));
|
self.content = Some(self.executor.execute(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy_content(&mut self) {
|
pub fn destroy_content(&mut self) {
|
||||||
let retrieve_command = vec!["rm", TMP_FILE];
|
let retrieve_command = vec!["rm", TMP_FILE];
|
||||||
let params = retrieve_command.iter().map(|arg| arg.to_string()).collect();
|
|
||||||
|
|
||||||
self.executor.execute(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_command(&mut self) {
|
|
||||||
let content = self.content.clone().unwrap();
|
|
||||||
let mut splitter = content.splitn(2, ':');
|
|
||||||
|
|
||||||
if let Some(upcase) = splitter.next() {
|
|
||||||
if let Some(text) = splitter.next() {
|
|
||||||
let execute_command = if upcase.trim_end() == "true" {
|
|
||||||
self.upcase_command.clone()
|
|
||||||
} else {
|
|
||||||
self.command.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let final_command = str::replace(execute_command.as_str(), "{}", text.trim_end());
|
|
||||||
let retrieve_command = vec!["bash", "-c", final_command.as_str()];
|
|
||||||
let params = retrieve_command.iter().map(|arg| arg.to_string()).collect();
|
let params = retrieve_command.iter().map(|arg| arg.to_string()).collect();
|
||||||
|
|
||||||
self.executor.execute(params);
|
self.executor.execute(params);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
pub fn execute_command(&mut self) {
|
||||||
|
let content = self.content.clone().unwrap();
|
||||||
|
let mut splitter = content.splitn(2, ':');
|
||||||
|
|
||||||
|
if let Some(upcase) = splitter.next() {
|
||||||
|
if let Some(text) = splitter.next() {
|
||||||
|
let execute_command = if upcase.trim_end() == "true" {
|
||||||
|
self.alt_command.clone()
|
||||||
|
} else {
|
||||||
|
self.command.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let final_command = str::replace(execute_command, "{}", text.trim_end());
|
||||||
|
let retrieve_command = vec!["bash", "-c", final_command.as_str()];
|
||||||
|
let params = retrieve_command.iter().map(|arg| arg.to_string()).collect();
|
||||||
|
|
||||||
|
self.executor.execute(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
struct TestShell {
|
struct TestShell {
|
||||||
outputs: Vec<String>,
|
outputs: Vec<String>,
|
||||||
executed: Option<Vec<String>>,
|
executed: Option<Vec<String>>,
|
||||||
}
|
|
||||||
|
|
||||||
impl TestShell {
|
|
||||||
fn new(outputs: Vec<String>) -> TestShell {
|
|
||||||
TestShell {
|
|
||||||
executed: None,
|
|
||||||
outputs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Executor for TestShell {
|
|
||||||
fn execute(&mut self, args: Vec<String>) -> String {
|
|
||||||
self.executed = Some(args);
|
|
||||||
self.outputs.pop().unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_executed(&self) -> Option<Vec<String>> {
|
impl TestShell {
|
||||||
self.executed.clone()
|
fn new(outputs: Vec<String>) -> TestShell {
|
||||||
|
TestShell {
|
||||||
|
executed: None,
|
||||||
|
outputs,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
impl Executor for TestShell {
|
||||||
fn retrieve_active_pane() {
|
fn execute(&mut self, args: Vec<String>) -> String {
|
||||||
let last_command_outputs = vec!["%97:100:24:1:active\n%106:100:24:1:nope\n%107:100:24:1:nope\n".to_string()];
|
self.executed = Some(args);
|
||||||
let mut executor = TestShell::new(last_command_outputs);
|
self.outputs.pop().unwrap()
|
||||||
let mut swapper = Swapper::new(Box::new(&mut executor), "".to_string(), "".to_string(), "".to_string());
|
}
|
||||||
|
|
||||||
swapper.capture_active_pane();
|
fn last_executed(&self) -> Option<Vec<String>> {
|
||||||
|
self.executed.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(swapper.active_pane_id.unwrap(), "%97");
|
#[test]
|
||||||
}
|
fn retrieve_active_pane() {
|
||||||
|
let last_command_outputs =
|
||||||
|
vec!["%97:100:24:1:active\n%106:100:24:1:nope\n%107:100:24:1:nope\n".to_string()];
|
||||||
|
let mut executor = TestShell::new(last_command_outputs);
|
||||||
|
let mut swapper = Swapper::new(Box::new(&mut executor), &path::Path::new(""), "", "");
|
||||||
|
|
||||||
#[test]
|
swapper.capture_active_pane();
|
||||||
fn swap_panes() {
|
|
||||||
let last_command_outputs = vec![
|
assert_eq!(swapper.active_pane_id.unwrap(), "%97");
|
||||||
"".to_string(),
|
}
|
||||||
"%100".to_string(),
|
|
||||||
"".to_string(),
|
#[test]
|
||||||
"%106:100:24:1:nope\n%98:100:24:1:active\n%107:100:24:1:nope\n".to_string(),
|
fn swap_panes() {
|
||||||
];
|
let last_command_outputs = vec![
|
||||||
let mut executor = TestShell::new(last_command_outputs);
|
"".to_string(),
|
||||||
let mut swapper = Swapper::new(Box::new(&mut executor), "".to_string(), "".to_string(), "".to_string());
|
"%100".to_string(),
|
||||||
|
"".to_string(),
|
||||||
|
"%106:100:24:1:nope\n%98:100:24:1:active\n%107:100:24:1:nope\n".to_string(),
|
||||||
|
];
|
||||||
|
let mut executor = TestShell::new(last_command_outputs);
|
||||||
|
let mut swapper = Swapper::new(Box::new(&mut executor), &path::Path::new(""), "", "");
|
||||||
|
|
||||||
|
swapper.capture_active_pane();
|
||||||
|
swapper.execute_thumbs();
|
||||||
|
swapper.swap_panes();
|
||||||
|
|
||||||
|
let expectation = vec!["tmux", "swap-pane", "-d", "-s", "%98", "-t", "%100"];
|
||||||
|
|
||||||
|
assert_eq!(executor.last_executed().unwrap(), expectation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Main configuration, parsed from command line.
|
||||||
|
#[derive(Clap, Debug)]
|
||||||
|
#[clap(author, about, version)]
|
||||||
|
struct Opt {
|
||||||
|
/// Directory where to execute copyrat.
|
||||||
|
#[clap(long, required = true)]
|
||||||
|
directory: path::PathBuf,
|
||||||
|
|
||||||
|
/// Command to execute on selection.
|
||||||
|
#[clap(short, long, default_value = "'tmux set-buffer {}'")]
|
||||||
|
command: String,
|
||||||
|
|
||||||
|
/// Command to execute on uppercased selection.
|
||||||
|
#[clap(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
default_value = "'tmux set-bufffer {} && tmux-paste-buffer'"
|
||||||
|
)]
|
||||||
|
alt_command: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn app_args<'a>() -> clap::ArgMatches<'a> {
|
||||||
|
// App::new("tmux-thumbs")
|
||||||
|
// .version(crate_version!())
|
||||||
|
// .about("A lightning fast version of tmux-fingers, copy/pasting tmux like vimium/vimperator")
|
||||||
|
// .arg(
|
||||||
|
// Arg::with_name("dir")
|
||||||
|
// .help("Directory where to execute thumbs")
|
||||||
|
// .long("dir")
|
||||||
|
// .default_value(""),
|
||||||
|
// )
|
||||||
|
// .arg(
|
||||||
|
// Arg::with_name("command")
|
||||||
|
// .help("Pick command")
|
||||||
|
// .long("command")
|
||||||
|
// .default_value("tmux set-buffer {}"),
|
||||||
|
// )
|
||||||
|
// .arg(
|
||||||
|
// Arg::with_name("upcase_command")
|
||||||
|
// .help("Upcase command")
|
||||||
|
// .long("upcase-command")
|
||||||
|
// .default_value("tmux set-buffer {} && tmux paste-buffer"),
|
||||||
|
// )
|
||||||
|
// .get_matches()
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn main() -> std::io::Result<()> {
|
||||||
|
let opt = Opt::parse();
|
||||||
|
// let dir = args.value_of("dir").unwrap();
|
||||||
|
// let command = args.value_of("command").unwrap();
|
||||||
|
// let upcase_command = args.value_of("upcase_command").unwrap();
|
||||||
|
|
||||||
|
// if dir.is_empty() {
|
||||||
|
// panic!("Invalid tmux-thumbs execution. Are you trying to execute tmux-thumbs directly?")
|
||||||
|
// }
|
||||||
|
|
||||||
|
let mut executor = RealShell::new();
|
||||||
|
let mut swapper = Swapper::new(
|
||||||
|
Box::new(&mut executor),
|
||||||
|
opt.directory.as_path(),
|
||||||
|
&opt.command,
|
||||||
|
&opt.alt_command,
|
||||||
|
);
|
||||||
|
|
||||||
swapper.capture_active_pane();
|
swapper.capture_active_pane();
|
||||||
swapper.execute_thumbs();
|
swapper.execute_thumbs();
|
||||||
swapper.swap_panes();
|
swapper.swap_panes();
|
||||||
|
swapper.wait_thumbs();
|
||||||
let expectation = vec!["tmux", "swap-pane", "-d", "-s", "%98", "-t", "%100"];
|
swapper.retrieve_content();
|
||||||
|
swapper.destroy_content();
|
||||||
assert_eq!(executor.last_executed().unwrap(), expectation);
|
swapper.execute_command();
|
||||||
}
|
Ok(())
|
||||||
}
|
|
||||||
|
|
||||||
fn app_args<'a>() -> clap::ArgMatches<'a> {
|
|
||||||
App::new("tmux-thumbs")
|
|
||||||
.version(crate_version!())
|
|
||||||
.about("A lightning fast version of tmux-fingers, copy/pasting tmux like vimium/vimperator")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("dir")
|
|
||||||
.help("Directory where to execute thumbs")
|
|
||||||
.long("dir")
|
|
||||||
.default_value(""),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("command")
|
|
||||||
.help("Pick command")
|
|
||||||
.long("command")
|
|
||||||
.default_value("tmux set-buffer {}"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("upcase_command")
|
|
||||||
.help("Upcase command")
|
|
||||||
.long("upcase-command")
|
|
||||||
.default_value("tmux set-buffer {} && tmux paste-buffer"),
|
|
||||||
)
|
|
||||||
.get_matches()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
|
||||||
let args = app_args();
|
|
||||||
let dir = args.value_of("dir").unwrap();
|
|
||||||
let command = args.value_of("command").unwrap();
|
|
||||||
let upcase_command = args.value_of("upcase_command").unwrap();
|
|
||||||
|
|
||||||
if dir.is_empty() {
|
|
||||||
panic!("Invalid tmux-thumbs execution. Are you trying to execute tmux-thumbs directly?")
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut executor = RealShell::new();
|
|
||||||
let mut swapper = Swapper::new(
|
|
||||||
Box::new(&mut executor),
|
|
||||||
dir.to_string(),
|
|
||||||
command.to_string(),
|
|
||||||
upcase_command.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
swapper.capture_active_pane();
|
|
||||||
swapper.execute_thumbs();
|
|
||||||
swapper.swap_panes();
|
|
||||||
swapper.wait_thumbs();
|
|
||||||
swapper.retrieve_content();
|
|
||||||
swapper.destroy_content();
|
|
||||||
swapper.execute_command();
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
181
src/view.rs
181
src/view.rs
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{colors, state};
|
use super::{colors, state};
|
||||||
|
use clap::Clap;
|
||||||
use std::char;
|
use std::char;
|
||||||
use std::io::{stdout, Read, Write};
|
use std::io::{stdout, Read, Write};
|
||||||
use termion::async_stdin;
|
use termion::async_stdin;
|
||||||
|
|
@ -14,7 +15,7 @@ pub struct View<'a> {
|
||||||
focus_index: usize,
|
focus_index: usize,
|
||||||
multi: bool,
|
multi: bool,
|
||||||
hint_alignment: HintAlignment,
|
hint_alignment: HintAlignment,
|
||||||
rendering_colors: &'a ViewColors<'a>,
|
rendering_colors: &'a ViewColors,
|
||||||
hint_style: Option<HintStyle>,
|
hint_style: Option<HintStyle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,17 +24,42 @@ pub struct View<'a> {
|
||||||
/// - `focus_*` colors are used to render the currently focused matched text.
|
/// - `focus_*` colors are used to render the currently focused matched text.
|
||||||
/// - `normal_*` colors are used to render other matched text.
|
/// - `normal_*` colors are used to render other matched text.
|
||||||
/// - `hint_*` colors are used to render the hints.
|
/// - `hint_*` colors are used to render the hints.
|
||||||
pub struct ViewColors<'a> {
|
#[derive(Clap, Debug)]
|
||||||
pub focus_fg: Box<&'a dyn color::Color>,
|
pub struct ViewColors {
|
||||||
pub focus_bg: Box<&'a dyn color::Color>,
|
/// Foreground color for matches.
|
||||||
pub match_fg: Box<&'a dyn color::Color>,
|
#[clap(long, default_value = "green",
|
||||||
pub match_bg: Box<&'a dyn color::Color>,
|
parse(try_from_str = colors::parse_color))]
|
||||||
pub hint_fg: Box<&'a dyn color::Color>,
|
match_fg: Box<dyn color::Color>,
|
||||||
pub hint_bg: Box<&'a dyn color::Color>,
|
|
||||||
|
/// Background color for matches.
|
||||||
|
#[clap(long, default_value = "black",
|
||||||
|
parse(try_from_str = colors::parse_color))]
|
||||||
|
match_bg: Box<dyn color::Color>,
|
||||||
|
|
||||||
|
/// Foreground color for the focused match.
|
||||||
|
#[clap(long, default_value = "blue",
|
||||||
|
parse(try_from_str = colors::parse_color))]
|
||||||
|
focused_fg: Box<dyn color::Color>,
|
||||||
|
|
||||||
|
/// Background color for the focused match.
|
||||||
|
#[clap(long, default_value = "black",
|
||||||
|
parse(try_from_str = colors::parse_color))]
|
||||||
|
focused_bg: Box<dyn color::Color>,
|
||||||
|
|
||||||
|
/// Foreground color for hints.
|
||||||
|
#[clap(long, default_value = "white",
|
||||||
|
parse(try_from_str = colors::parse_color))]
|
||||||
|
hint_fg: Box<dyn color::Color>,
|
||||||
|
|
||||||
|
/// Background color for hints.
|
||||||
|
#[clap(long, default_value = "black",
|
||||||
|
parse(try_from_str = colors::parse_color))]
|
||||||
|
hint_bg: Box<dyn color::Color>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes if, during rendering, a hint should aligned to the leading edge of
|
/// Describes if, during rendering, a hint should aligned to the leading edge of
|
||||||
/// the matched text, or to its trailing edge.
|
/// the matched text, or to its trailing edge.
|
||||||
|
#[derive(Debug, Clap)]
|
||||||
pub enum HintAlignment {
|
pub enum HintAlignment {
|
||||||
Leading,
|
Leading,
|
||||||
Trailing,
|
Trailing,
|
||||||
|
|
@ -135,7 +161,7 @@ impl<'a> View<'a> {
|
||||||
) {
|
) {
|
||||||
// To help identify it, the match thas has focus is rendered with a dedicated color.
|
// To help identify it, the match thas has focus is rendered with a dedicated color.
|
||||||
let (text_fg_color, text_bg_color) = if focused {
|
let (text_fg_color, text_bg_color) = if focused {
|
||||||
(&colors.focus_fg, &colors.focus_bg)
|
(&colors.focused_fg, &colors.focused_bg)
|
||||||
} else {
|
} else {
|
||||||
(&colors.match_fg, &colors.match_bg)
|
(&colors.match_fg, &colors.match_bg)
|
||||||
};
|
};
|
||||||
|
|
@ -145,8 +171,8 @@ impl<'a> View<'a> {
|
||||||
stdout,
|
stdout,
|
||||||
"{goto}{bg_color}{fg_color}{text}{fg_reset}{bg_reset}",
|
"{goto}{bg_color}{fg_color}{text}{fg_reset}{bg_reset}",
|
||||||
goto = cursor::Goto(offset.0 as u16 + 1, offset.1 as u16 + 1),
|
goto = cursor::Goto(offset.0 as u16 + 1, offset.1 as u16 + 1),
|
||||||
fg_color = color::Fg(**text_fg_color),
|
fg_color = color::Fg(text_fg_color.as_ref()),
|
||||||
bg_color = color::Bg(**text_bg_color),
|
bg_color = color::Bg(text_bg_color.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset),
|
bg_reset = color::Bg(color::Reset),
|
||||||
text = &text,
|
text = &text,
|
||||||
|
|
@ -171,8 +197,8 @@ impl<'a> View<'a> {
|
||||||
colors: &ViewColors,
|
colors: &ViewColors,
|
||||||
hint_style: &Option<HintStyle>,
|
hint_style: &Option<HintStyle>,
|
||||||
) {
|
) {
|
||||||
let fg_color = color::Fg(*colors.hint_fg);
|
let fg_color = color::Fg(colors.hint_fg.as_ref());
|
||||||
let bg_color = color::Bg(*colors.hint_bg);
|
let bg_color = color::Bg(colors.hint_bg.as_ref());
|
||||||
let fg_reset = color::Fg(color::Reset);
|
let fg_reset = color::Fg(color::Reset);
|
||||||
let bg_reset = color::Bg(color::Reset);
|
let bg_reset = color::Bg(color::Reset);
|
||||||
|
|
||||||
|
|
@ -426,6 +452,7 @@ impl<'a> View<'a> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::alphabets;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_render_all_lines() {
|
fn test_render_all_lines() {
|
||||||
|
|
@ -461,12 +488,12 @@ path: /usr/local/bin/cargo";
|
||||||
let focused = true;
|
let focused = true;
|
||||||
let offset: (usize, usize) = (3, 1);
|
let offset: (usize, usize) = (3, 1);
|
||||||
let colors = ViewColors {
|
let colors = ViewColors {
|
||||||
focus_fg: Box::new(&(color::Red)),
|
focused_fg: Box::new(color::Red),
|
||||||
focus_bg: Box::new(&(color::Blue)),
|
focused_bg: Box::new(color::Blue),
|
||||||
match_fg: Box::new(&color::Green),
|
match_fg: Box::new(color::Green),
|
||||||
match_bg: Box::new(&color::Magenta),
|
match_bg: Box::new(color::Magenta),
|
||||||
hint_fg: Box::new(&color::Yellow),
|
hint_fg: Box::new(color::Yellow),
|
||||||
hint_bg: Box::new(&color::Cyan),
|
hint_bg: Box::new(color::Cyan),
|
||||||
};
|
};
|
||||||
|
|
||||||
View::render_matched_text(&mut writer, text, focused, offset, &colors);
|
View::render_matched_text(&mut writer, text, focused, offset, &colors);
|
||||||
|
|
@ -476,8 +503,8 @@ path: /usr/local/bin/cargo";
|
||||||
format!(
|
format!(
|
||||||
"{goto}{bg}{fg}{text}{fg_reset}{bg_reset}",
|
"{goto}{bg}{fg}{text}{fg_reset}{bg_reset}",
|
||||||
goto = cursor::Goto(4, 2),
|
goto = cursor::Goto(4, 2),
|
||||||
fg = color::Fg(*colors.focus_fg),
|
fg = color::Fg(colors.focused_fg.as_ref()),
|
||||||
bg = color::Bg(*colors.focus_bg),
|
bg = color::Bg(colors.focused_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset),
|
bg_reset = color::Bg(color::Reset),
|
||||||
text = &text,
|
text = &text,
|
||||||
|
|
@ -493,12 +520,12 @@ path: /usr/local/bin/cargo";
|
||||||
let focused = false;
|
let focused = false;
|
||||||
let offset: (usize, usize) = (3, 1);
|
let offset: (usize, usize) = (3, 1);
|
||||||
let colors = ViewColors {
|
let colors = ViewColors {
|
||||||
focus_fg: Box::new(&(color::Red)),
|
focused_fg: Box::new(color::Red),
|
||||||
focus_bg: Box::new(&(color::Blue)),
|
focused_bg: Box::new(color::Blue),
|
||||||
match_fg: Box::new(&color::Green),
|
match_fg: Box::new(color::Green),
|
||||||
match_bg: Box::new(&color::Magenta),
|
match_bg: Box::new(color::Magenta),
|
||||||
hint_fg: Box::new(&color::Yellow),
|
hint_fg: Box::new(color::Yellow),
|
||||||
hint_bg: Box::new(&color::Cyan),
|
hint_bg: Box::new(color::Cyan),
|
||||||
};
|
};
|
||||||
|
|
||||||
View::render_matched_text(&mut writer, text, focused, offset, &colors);
|
View::render_matched_text(&mut writer, text, focused, offset, &colors);
|
||||||
|
|
@ -508,8 +535,8 @@ path: /usr/local/bin/cargo";
|
||||||
format!(
|
format!(
|
||||||
"{goto}{bg}{fg}{text}{fg_reset}{bg_reset}",
|
"{goto}{bg}{fg}{text}{fg_reset}{bg_reset}",
|
||||||
goto = cursor::Goto(4, 2),
|
goto = cursor::Goto(4, 2),
|
||||||
fg = color::Fg(*colors.match_fg),
|
fg = color::Fg(colors.match_fg.as_ref()),
|
||||||
bg = color::Bg(*colors.match_bg),
|
bg = color::Bg(colors.match_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset),
|
bg_reset = color::Bg(color::Reset),
|
||||||
text = &text,
|
text = &text,
|
||||||
|
|
@ -524,12 +551,12 @@ path: /usr/local/bin/cargo";
|
||||||
let hint_text = "eo";
|
let hint_text = "eo";
|
||||||
let offset: (usize, usize) = (3, 1);
|
let offset: (usize, usize) = (3, 1);
|
||||||
let colors = ViewColors {
|
let colors = ViewColors {
|
||||||
focus_fg: Box::new(&(color::Red)),
|
focused_fg: Box::new(color::Red),
|
||||||
focus_bg: Box::new(&(color::Blue)),
|
focused_bg: Box::new(color::Blue),
|
||||||
match_fg: Box::new(&color::Green),
|
match_fg: Box::new(color::Green),
|
||||||
match_bg: Box::new(&color::Magenta),
|
match_bg: Box::new(color::Magenta),
|
||||||
hint_fg: Box::new(&color::Yellow),
|
hint_fg: Box::new(color::Yellow),
|
||||||
hint_bg: Box::new(&color::Cyan),
|
hint_bg: Box::new(color::Cyan),
|
||||||
};
|
};
|
||||||
|
|
||||||
let extra_offset = 0;
|
let extra_offset = 0;
|
||||||
|
|
@ -548,8 +575,8 @@ path: /usr/local/bin/cargo";
|
||||||
format!(
|
format!(
|
||||||
"{goto}{bg}{fg}{text}{fg_reset}{bg_reset}",
|
"{goto}{bg}{fg}{text}{fg_reset}{bg_reset}",
|
||||||
goto = cursor::Goto(4, 2),
|
goto = cursor::Goto(4, 2),
|
||||||
fg = color::Fg(*colors.hint_fg),
|
fg = color::Fg(colors.hint_fg.as_ref()),
|
||||||
bg = color::Bg(*colors.hint_bg),
|
bg = color::Bg(colors.hint_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset),
|
bg_reset = color::Bg(color::Reset),
|
||||||
text = "eo",
|
text = "eo",
|
||||||
|
|
@ -564,12 +591,12 @@ path: /usr/local/bin/cargo";
|
||||||
let hint_text = "eo";
|
let hint_text = "eo";
|
||||||
let offset: (usize, usize) = (3, 1);
|
let offset: (usize, usize) = (3, 1);
|
||||||
let colors = ViewColors {
|
let colors = ViewColors {
|
||||||
focus_fg: Box::new(&(color::Red)),
|
focused_fg: Box::new(color::Red),
|
||||||
focus_bg: Box::new(&(color::Blue)),
|
focused_bg: Box::new(color::Blue),
|
||||||
match_fg: Box::new(&color::Green),
|
match_fg: Box::new(color::Green),
|
||||||
match_bg: Box::new(&color::Magenta),
|
match_bg: Box::new(color::Magenta),
|
||||||
hint_fg: Box::new(&color::Yellow),
|
hint_fg: Box::new(color::Yellow),
|
||||||
hint_bg: Box::new(&color::Cyan),
|
hint_bg: Box::new(color::Cyan),
|
||||||
};
|
};
|
||||||
|
|
||||||
let extra_offset = 0;
|
let extra_offset = 0;
|
||||||
|
|
@ -588,8 +615,8 @@ path: /usr/local/bin/cargo";
|
||||||
format!(
|
format!(
|
||||||
"{goto}{bg}{fg}{sty}{text}{sty_reset}{fg_reset}{bg_reset}",
|
"{goto}{bg}{fg}{sty}{text}{sty_reset}{fg_reset}{bg_reset}",
|
||||||
goto = cursor::Goto(4, 2),
|
goto = cursor::Goto(4, 2),
|
||||||
fg = color::Fg(*colors.hint_fg),
|
fg = color::Fg(colors.hint_fg.as_ref()),
|
||||||
bg = color::Bg(*colors.hint_bg),
|
bg = color::Bg(colors.hint_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset),
|
bg_reset = color::Bg(color::Reset),
|
||||||
sty = style::Underline,
|
sty = style::Underline,
|
||||||
|
|
@ -606,12 +633,12 @@ path: /usr/local/bin/cargo";
|
||||||
let hint_text = "eo";
|
let hint_text = "eo";
|
||||||
let offset: (usize, usize) = (3, 1);
|
let offset: (usize, usize) = (3, 1);
|
||||||
let colors = ViewColors {
|
let colors = ViewColors {
|
||||||
focus_fg: Box::new(&(color::Red)),
|
focused_fg: Box::new(color::Red),
|
||||||
focus_bg: Box::new(&(color::Blue)),
|
focused_bg: Box::new(color::Blue),
|
||||||
match_fg: Box::new(&color::Green),
|
match_fg: Box::new(color::Green),
|
||||||
match_bg: Box::new(&color::Magenta),
|
match_bg: Box::new(color::Magenta),
|
||||||
hint_fg: Box::new(&color::Yellow),
|
hint_fg: Box::new(color::Yellow),
|
||||||
hint_bg: Box::new(&color::Cyan),
|
hint_bg: Box::new(color::Cyan),
|
||||||
};
|
};
|
||||||
|
|
||||||
let extra_offset = 0;
|
let extra_offset = 0;
|
||||||
|
|
@ -630,8 +657,8 @@ path: /usr/local/bin/cargo";
|
||||||
format!(
|
format!(
|
||||||
"{goto}{bg}{fg}{bra}{text}{bra_close}{fg_reset}{bg_reset}",
|
"{goto}{bg}{fg}{bra}{text}{bra_close}{fg_reset}{bg_reset}",
|
||||||
goto = cursor::Goto(4, 2),
|
goto = cursor::Goto(4, 2),
|
||||||
fg = color::Fg(*colors.hint_fg),
|
fg = color::Fg(colors.hint_fg.as_ref()),
|
||||||
bg = color::Bg(*colors.hint_bg),
|
bg = color::Bg(colors.hint_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset),
|
bg_reset = color::Bg(color::Reset),
|
||||||
bra = '{',
|
bra = '{',
|
||||||
|
|
@ -652,15 +679,15 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
|
||||||
let lines = content.split('\n').collect();
|
let lines = content.split('\n').collect();
|
||||||
|
|
||||||
let custom_regexes = [].to_vec();
|
let custom_regexes = [].to_vec();
|
||||||
let alphabet = "abcd";
|
let alphabet = alphabets::Alphabet("abcd".to_string());
|
||||||
let mut state = state::State::new(&lines, alphabet, &custom_regexes);
|
let mut state = state::State::new(&lines, &alphabet, &custom_regexes);
|
||||||
let rendering_colors = ViewColors {
|
let rendering_colors = ViewColors {
|
||||||
focus_fg: Box::new(&(color::Red)),
|
focused_fg: Box::new(color::Red),
|
||||||
focus_bg: Box::new(&(color::Blue)),
|
focused_bg: Box::new(color::Blue),
|
||||||
match_fg: Box::new(&color::Green),
|
match_fg: Box::new(color::Green),
|
||||||
match_bg: Box::new(&color::Magenta),
|
match_bg: Box::new(color::Magenta),
|
||||||
hint_fg: Box::new(&color::Yellow),
|
hint_fg: Box::new(color::Yellow),
|
||||||
hint_bg: Box::new(&color::Cyan),
|
hint_bg: Box::new(color::Cyan),
|
||||||
};
|
};
|
||||||
let hint_alignment = HintAlignment::Leading;
|
let hint_alignment = HintAlignment::Leading;
|
||||||
|
|
||||||
|
|
@ -709,19 +736,19 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
|
||||||
let lines = content.split('\n').collect();
|
let lines = content.split('\n').collect();
|
||||||
|
|
||||||
let custom_regexes = [].to_vec();
|
let custom_regexes = [].to_vec();
|
||||||
let alphabet = "abcd";
|
let alphabet = alphabets::Alphabet("abcd".to_string());
|
||||||
let mut state = state::State::new(&lines, alphabet, &custom_regexes);
|
let mut state = state::State::new(&lines, &alphabet, &custom_regexes);
|
||||||
let multi = false;
|
let multi = false;
|
||||||
let reversed = true;
|
let reversed = true;
|
||||||
let unique = false;
|
let unique = false;
|
||||||
|
|
||||||
let rendering_colors = ViewColors {
|
let rendering_colors = ViewColors {
|
||||||
focus_fg: Box::new(&(color::Red)),
|
focused_fg: Box::new(color::Red),
|
||||||
focus_bg: Box::new(&(color::Blue)),
|
focused_bg: Box::new(color::Blue),
|
||||||
match_fg: Box::new(&color::Green),
|
match_fg: Box::new(color::Green),
|
||||||
match_bg: Box::new(&color::Magenta),
|
match_bg: Box::new(color::Magenta),
|
||||||
hint_fg: Box::new(&color::Yellow),
|
hint_fg: Box::new(color::Yellow),
|
||||||
hint_bg: Box::new(&color::Cyan),
|
hint_bg: Box::new(color::Cyan),
|
||||||
};
|
};
|
||||||
let hint_alignment = HintAlignment::Leading;
|
let hint_alignment = HintAlignment::Leading;
|
||||||
let hint_style = None;
|
let hint_style = None;
|
||||||
|
|
@ -758,8 +785,8 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
|
||||||
format!(
|
format!(
|
||||||
"{goto7_1}{match_bg}{match_fg}127.0.0.1{fg_reset}{bg_reset}",
|
"{goto7_1}{match_bg}{match_fg}127.0.0.1{fg_reset}{bg_reset}",
|
||||||
goto7_1 = goto7_1,
|
goto7_1 = goto7_1,
|
||||||
match_fg = color::Fg(*rendering_colors.match_fg),
|
match_fg = color::Fg(rendering_colors.match_fg.as_ref()),
|
||||||
match_bg = color::Bg(*rendering_colors.match_bg),
|
match_bg = color::Bg(rendering_colors.match_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset)
|
bg_reset = color::Bg(color::Reset)
|
||||||
)
|
)
|
||||||
|
|
@ -771,8 +798,8 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
|
||||||
format!(
|
format!(
|
||||||
"{goto7_1}{hint_bg}{hint_fg}b{fg_reset}{bg_reset}",
|
"{goto7_1}{hint_bg}{hint_fg}b{fg_reset}{bg_reset}",
|
||||||
goto7_1 = goto7_1,
|
goto7_1 = goto7_1,
|
||||||
hint_fg = color::Fg(*rendering_colors.hint_fg),
|
hint_fg = color::Fg(rendering_colors.hint_fg.as_ref()),
|
||||||
hint_bg = color::Bg(*rendering_colors.hint_bg),
|
hint_bg = color::Bg(rendering_colors.hint_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset)
|
bg_reset = color::Bg(color::Reset)
|
||||||
)
|
)
|
||||||
|
|
@ -783,8 +810,8 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
|
||||||
format!(
|
format!(
|
||||||
"{goto11_3}{focus_bg}{focus_fg}https://en.wikipedia.org/wiki/Barcelona{fg_reset}{bg_reset}",
|
"{goto11_3}{focus_bg}{focus_fg}https://en.wikipedia.org/wiki/Barcelona{fg_reset}{bg_reset}",
|
||||||
goto11_3 = goto11_3,
|
goto11_3 = goto11_3,
|
||||||
focus_fg = color::Fg(*rendering_colors.focus_fg),
|
focus_fg = color::Fg(rendering_colors.focused_fg.as_ref()),
|
||||||
focus_bg = color::Bg(*rendering_colors.focus_bg),
|
focus_bg = color::Bg(rendering_colors.focused_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset)
|
bg_reset = color::Bg(color::Reset)
|
||||||
)
|
)
|
||||||
|
|
@ -796,8 +823,8 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
|
||||||
format!(
|
format!(
|
||||||
"{goto11_3}{hint_bg}{hint_fg}a{fg_reset}{bg_reset}",
|
"{goto11_3}{hint_bg}{hint_fg}a{fg_reset}{bg_reset}",
|
||||||
goto11_3 = goto11_3,
|
goto11_3 = goto11_3,
|
||||||
hint_fg = color::Fg(*rendering_colors.hint_fg),
|
hint_fg = color::Fg(rendering_colors.hint_fg.as_ref()),
|
||||||
hint_bg = color::Bg(*rendering_colors.hint_bg),
|
hint_bg = color::Bg(rendering_colors.hint_bg.as_ref()),
|
||||||
fg_reset = color::Fg(color::Reset),
|
fg_reset = color::Fg(color::Reset),
|
||||||
bg_reset = color::Bg(color::Reset)
|
bg_reset = color::Bg(color::Reset)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
PARAMS=()
|
PARAMS=()
|
||||||
|
|
||||||
function add-option-param {
|
function add-option-param {
|
||||||
VALUE=$(tmux show -vg @thumbs-$1 2> /dev/null)
|
VALUE=$(tmux show-options -vg @thumbs-$1 2> /dev/null)
|
||||||
|
|
||||||
if [[ ${VALUE} ]]; then
|
if [[ ${VALUE} ]]; then
|
||||||
PARAMS+=("--$1=${VALUE}")
|
PARAMS+=("--$1=${VALUE}")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue