5083 lines
160 KiB
Diff
5083 lines
160 KiB
Diff
diff -ur a/Cargo.lock b/Cargo.lock
|
|
--- a/Cargo.lock 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/Cargo.lock 2021-08-07 11:25:14.695474018 +0300
|
|
@@ -54,12 +54,24 @@
|
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
|
|
|
[[package]]
|
|
+name = "base-x"
|
|
+version = "0.2.8"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
|
|
+
|
|
+[[package]]
|
|
name = "base64"
|
|
version = "0.13.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|
|
|
[[package]]
|
|
+name = "beef"
|
|
+version = "0.5.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "6736e2428df2ca2848d846c43e88745121a6654696e349ce0054a420815a7409"
|
|
+
|
|
+[[package]]
|
|
name = "bitflags"
|
|
version = "1.2.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -86,6 +98,12 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "bumpalo"
|
|
+version = "3.6.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
|
|
+
|
|
+[[package]]
|
|
name = "cassowary"
|
|
version = "0.3.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -118,7 +136,7 @@
|
|
"libc",
|
|
"num-integer",
|
|
"num-traits",
|
|
- "time",
|
|
+ "time 0.1.43",
|
|
"winapi",
|
|
]
|
|
|
|
@@ -131,19 +149,110 @@
|
|
"ansi_term",
|
|
"atty",
|
|
"bitflags",
|
|
- "strsim",
|
|
+ "strsim 0.8.0",
|
|
"textwrap",
|
|
"unicode-width",
|
|
"vec_map",
|
|
]
|
|
|
|
[[package]]
|
|
+name = "colors-transform"
|
|
+version = "0.2.11"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "9226dbc05df4fb986f48d730b001532580883c4c06c5d1c213f4b34c1c157178"
|
|
+
|
|
+[[package]]
|
|
+name = "const_fn"
|
|
+version = "0.4.8"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7"
|
|
+
|
|
+[[package]]
|
|
name = "constant_time_eq"
|
|
version = "0.1.5"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
|
|
|
[[package]]
|
|
+name = "crossbeam"
|
|
+version = "0.8.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "fd01a6eb3daaafa260f6fc94c3a6c36390abc2080e38e3e34ced87393fb77d80"
|
|
+dependencies = [
|
|
+ "cfg-if 1.0.0",
|
|
+ "crossbeam-channel 0.5.1",
|
|
+ "crossbeam-deque",
|
|
+ "crossbeam-epoch",
|
|
+ "crossbeam-queue",
|
|
+ "crossbeam-utils 0.8.4",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "crossbeam-channel"
|
|
+version = "0.4.4"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
|
|
+dependencies = [
|
|
+ "crossbeam-utils 0.7.2",
|
|
+ "maybe-uninit",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "crossbeam-channel"
|
|
+version = "0.5.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
|
+dependencies = [
|
|
+ "cfg-if 1.0.0",
|
|
+ "crossbeam-utils 0.8.4",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "crossbeam-deque"
|
|
+version = "0.8.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
|
+dependencies = [
|
|
+ "cfg-if 1.0.0",
|
|
+ "crossbeam-epoch",
|
|
+ "crossbeam-utils 0.8.4",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "crossbeam-epoch"
|
|
+version = "0.9.4"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94"
|
|
+dependencies = [
|
|
+ "cfg-if 1.0.0",
|
|
+ "crossbeam-utils 0.8.4",
|
|
+ "lazy_static",
|
|
+ "memoffset",
|
|
+ "scopeguard",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "crossbeam-queue"
|
|
+version = "0.3.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756"
|
|
+dependencies = [
|
|
+ "cfg-if 1.0.0",
|
|
+ "crossbeam-utils 0.8.4",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "crossbeam-utils"
|
|
+version = "0.7.2"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
|
+dependencies = [
|
|
+ "autocfg",
|
|
+ "cfg-if 0.1.10",
|
|
+ "lazy_static",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "crossbeam-utils"
|
|
version = "0.8.4"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -155,6 +264,76 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "darling"
|
|
+version = "0.10.2"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
|
|
+dependencies = [
|
|
+ "darling_core",
|
|
+ "darling_macro",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "darling_core"
|
|
+version = "0.10.2"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
|
|
+dependencies = [
|
|
+ "fnv",
|
|
+ "ident_case",
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "strsim 0.9.3",
|
|
+ "syn",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "darling_macro"
|
|
+version = "0.10.2"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
|
+dependencies = [
|
|
+ "darling_core",
|
|
+ "quote",
|
|
+ "syn",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "defer-drop"
|
|
+version = "1.0.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "18ae055245e14ed411f56dddf2a78caae87c25d9d6a18fb61f398a596cad77b4"
|
|
+dependencies = [
|
|
+ "crossbeam-channel 0.4.4",
|
|
+ "once_cell",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "derive_builder"
|
|
+version = "0.9.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0"
|
|
+dependencies = [
|
|
+ "darling",
|
|
+ "derive_builder_core",
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "syn",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "derive_builder_core"
|
|
+version = "0.9.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef"
|
|
+dependencies = [
|
|
+ "darling",
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "syn",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "dirs"
|
|
version = "1.0.5"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -166,6 +345,16 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "dirs"
|
|
+version = "2.0.2"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
|
+dependencies = [
|
|
+ "cfg-if 0.1.10",
|
|
+ "dirs-sys",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "dirs-next"
|
|
version = "2.0.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -176,6 +365,17 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "dirs-sys"
|
|
+version = "0.3.6"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
|
|
+dependencies = [
|
|
+ "libc",
|
|
+ "redox_users 0.4.0",
|
|
+ "winapi",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "dirs-sys-next"
|
|
version = "0.1.2"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -187,18 +387,58 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "discard"
|
|
+version = "1.0.4"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
|
+
|
|
+[[package]]
|
|
name = "either"
|
|
version = "1.6.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
|
|
|
[[package]]
|
|
+name = "env_logger"
|
|
+version = "0.8.3"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
|
|
+dependencies = [
|
|
+ "atty",
|
|
+ "humantime",
|
|
+ "log",
|
|
+ "regex",
|
|
+ "termcolor",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "filetime"
|
|
+version = "0.2.14"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8"
|
|
+dependencies = [
|
|
+ "cfg-if 1.0.0",
|
|
+ "libc",
|
|
+ "redox_syscall 0.2.8",
|
|
+ "winapi",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "fnv"
|
|
version = "1.0.7"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
|
|
[[package]]
|
|
+name = "fuzzy-matcher"
|
|
+version = "0.3.7"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
|
|
+dependencies = [
|
|
+ "thread_local",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "getrandom"
|
|
version = "0.1.16"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -252,29 +492,51 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "humantime"
|
|
+version = "2.1.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|
+
|
|
+[[package]]
|
|
+name = "ident_case"
|
|
+version = "1.0.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|
+
|
|
+[[package]]
|
|
+name = "itoa"
|
|
+version = "0.4.7"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
|
+
|
|
+[[package]]
|
|
name = "joshuto"
|
|
-version = "0.8.6"
|
|
+version = "0.9.0"
|
|
dependencies = [
|
|
"alphanumeric-sort",
|
|
"chrono",
|
|
+ "colors-transform",
|
|
"dirs-next",
|
|
+ "filetime",
|
|
"globset",
|
|
"lazy_static",
|
|
"libc",
|
|
"open",
|
|
"phf",
|
|
- "rand 0.8.3",
|
|
+ "rand",
|
|
"rustyline",
|
|
"serde",
|
|
"serde_derive",
|
|
"shell-words",
|
|
"shellexpand",
|
|
"signal-hook",
|
|
+ "skim",
|
|
"structopt",
|
|
"termion",
|
|
"toml",
|
|
"trash",
|
|
"tui",
|
|
+ "unicode-segmentation",
|
|
"unicode-width",
|
|
"users",
|
|
"whoami",
|
|
@@ -303,12 +565,27 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "maybe-uninit"
|
|
+version = "2.0.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
|
+
|
|
+[[package]]
|
|
name = "memchr"
|
|
version = "2.4.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
|
|
|
[[package]]
|
|
+name = "memoffset"
|
|
+version = "0.6.3"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
|
|
+dependencies = [
|
|
+ "autocfg",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "nix"
|
|
version = "0.13.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -322,6 +599,31 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "nix"
|
|
+version = "0.14.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
|
|
+dependencies = [
|
|
+ "bitflags",
|
|
+ "cc",
|
|
+ "cfg-if 0.1.10",
|
|
+ "libc",
|
|
+ "void",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "nix"
|
|
+version = "0.19.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2"
|
|
+dependencies = [
|
|
+ "bitflags",
|
|
+ "cc",
|
|
+ "cfg-if 1.0.0",
|
|
+ "libc",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "num-integer"
|
|
version = "0.1.44"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -341,12 +643,28 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "num_cpus"
|
|
+version = "1.13.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
|
+dependencies = [
|
|
+ "hermit-abi",
|
|
+ "libc",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "numtoa"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
|
|
|
[[package]]
|
|
+name = "once_cell"
|
|
+version = "1.7.2"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
|
+
|
|
+[[package]]
|
|
name = "open"
|
|
version = "1.7.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -374,7 +692,7 @@
|
|
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
|
|
dependencies = [
|
|
"phf_shared",
|
|
- "rand 0.7.3",
|
|
+ "rand",
|
|
]
|
|
|
|
[[package]]
|
|
@@ -462,42 +780,20 @@
|
|
dependencies = [
|
|
"getrandom 0.1.16",
|
|
"libc",
|
|
- "rand_chacha 0.2.2",
|
|
- "rand_core 0.5.1",
|
|
- "rand_hc 0.2.0",
|
|
+ "rand_chacha",
|
|
+ "rand_core",
|
|
+ "rand_hc",
|
|
"rand_pcg",
|
|
]
|
|
|
|
[[package]]
|
|
-name = "rand"
|
|
-version = "0.8.3"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
|
-dependencies = [
|
|
- "libc",
|
|
- "rand_chacha 0.3.0",
|
|
- "rand_core 0.6.2",
|
|
- "rand_hc 0.3.0",
|
|
-]
|
|
-
|
|
-[[package]]
|
|
name = "rand_chacha"
|
|
version = "0.2.2"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
|
dependencies = [
|
|
"ppv-lite86",
|
|
- "rand_core 0.5.1",
|
|
-]
|
|
-
|
|
-[[package]]
|
|
-name = "rand_chacha"
|
|
-version = "0.3.0"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
|
-dependencies = [
|
|
- "ppv-lite86",
|
|
- "rand_core 0.6.2",
|
|
+ "rand_core",
|
|
]
|
|
|
|
[[package]]
|
|
@@ -510,39 +806,46 @@
|
|
]
|
|
|
|
[[package]]
|
|
-name = "rand_core"
|
|
-version = "0.6.2"
|
|
+name = "rand_hc"
|
|
+version = "0.2.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
|
|
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
|
dependencies = [
|
|
- "getrandom 0.2.2",
|
|
+ "rand_core",
|
|
]
|
|
|
|
[[package]]
|
|
-name = "rand_hc"
|
|
-version = "0.2.0"
|
|
+name = "rand_pcg"
|
|
+version = "0.2.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
|
+checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
|
dependencies = [
|
|
- "rand_core 0.5.1",
|
|
+ "rand_core",
|
|
]
|
|
|
|
[[package]]
|
|
-name = "rand_hc"
|
|
-version = "0.3.0"
|
|
+name = "rayon"
|
|
+version = "1.5.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
|
+checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
|
|
dependencies = [
|
|
- "rand_core 0.6.2",
|
|
+ "autocfg",
|
|
+ "crossbeam-deque",
|
|
+ "either",
|
|
+ "rayon-core",
|
|
]
|
|
|
|
[[package]]
|
|
-name = "rand_pcg"
|
|
-version = "0.2.1"
|
|
+name = "rayon-core"
|
|
+version = "1.9.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
|
+checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
|
|
dependencies = [
|
|
- "rand_core 0.5.1",
|
|
+ "crossbeam-channel 0.5.1",
|
|
+ "crossbeam-deque",
|
|
+ "crossbeam-utils 0.8.4",
|
|
+ "lazy_static",
|
|
+ "num_cpus",
|
|
]
|
|
|
|
[[package]]
|
|
@@ -616,7 +919,16 @@
|
|
"base64",
|
|
"blake2b_simd",
|
|
"constant_time_eq",
|
|
- "crossbeam-utils",
|
|
+ "crossbeam-utils 0.8.4",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "rustc_version"
|
|
+version = "0.2.3"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
|
+dependencies = [
|
|
+ "semver",
|
|
]
|
|
|
|
[[package]]
|
|
@@ -625,18 +937,45 @@
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "0f47ea1ceb347d2deae482d655dc8eef4bd82363d3329baffa3818bd76fea48b"
|
|
dependencies = [
|
|
- "dirs",
|
|
+ "dirs 1.0.5",
|
|
"libc",
|
|
"log",
|
|
"memchr",
|
|
- "nix",
|
|
+ "nix 0.13.1",
|
|
"unicode-segmentation",
|
|
"unicode-width",
|
|
- "utf8parse",
|
|
+ "utf8parse 0.1.1",
|
|
"winapi",
|
|
]
|
|
|
|
[[package]]
|
|
+name = "ryu"
|
|
+version = "1.0.5"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
|
+
|
|
+[[package]]
|
|
+name = "scopeguard"
|
|
+version = "1.1.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|
+
|
|
+[[package]]
|
|
+name = "semver"
|
|
+version = "0.9.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
|
+dependencies = [
|
|
+ "semver-parser",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "semver-parser"
|
|
+version = "0.7.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|
+
|
|
+[[package]]
|
|
name = "serde"
|
|
version = "1.0.125"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -654,6 +993,23 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "serde_json"
|
|
+version = "1.0.64"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
|
+dependencies = [
|
|
+ "itoa",
|
|
+ "ryu",
|
|
+ "serde",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "sha1"
|
|
+version = "0.6.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
|
+
|
|
+[[package]]
|
|
name = "shell-words"
|
|
version = "1.0.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -669,6 +1025,12 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "shlex"
|
|
+version = "0.1.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
|
+
|
|
+[[package]]
|
|
name = "signal-hook"
|
|
version = "0.3.8"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -694,12 +1056,105 @@
|
|
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
|
|
|
|
[[package]]
|
|
+name = "skim"
|
|
+version = "0.9.4"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "4b9d19f904221fab15163486d2ce116cb86e60296470bb4e956d6687f04ebbb4"
|
|
+dependencies = [
|
|
+ "atty",
|
|
+ "beef",
|
|
+ "bitflags",
|
|
+ "chrono",
|
|
+ "clap",
|
|
+ "crossbeam",
|
|
+ "defer-drop",
|
|
+ "derive_builder",
|
|
+ "env_logger",
|
|
+ "fuzzy-matcher",
|
|
+ "lazy_static",
|
|
+ "log",
|
|
+ "nix 0.19.1",
|
|
+ "rayon",
|
|
+ "regex",
|
|
+ "shlex",
|
|
+ "time 0.2.26",
|
|
+ "timer",
|
|
+ "tuikit",
|
|
+ "unicode-width",
|
|
+ "vte",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "standback"
|
|
+version = "0.2.17"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
|
|
+dependencies = [
|
|
+ "version_check",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "stdweb"
|
|
+version = "0.4.20"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
|
|
+dependencies = [
|
|
+ "discard",
|
|
+ "rustc_version",
|
|
+ "stdweb-derive",
|
|
+ "stdweb-internal-macros",
|
|
+ "stdweb-internal-runtime",
|
|
+ "wasm-bindgen",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "stdweb-derive"
|
|
+version = "0.5.3"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
|
+dependencies = [
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "serde",
|
|
+ "serde_derive",
|
|
+ "syn",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "stdweb-internal-macros"
|
|
+version = "0.2.9"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
|
+dependencies = [
|
|
+ "base-x",
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "serde",
|
|
+ "serde_derive",
|
|
+ "serde_json",
|
|
+ "sha1",
|
|
+ "syn",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "stdweb-internal-runtime"
|
|
+version = "0.1.5"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
|
+
|
|
+[[package]]
|
|
name = "strsim"
|
|
version = "0.8.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
|
|
|
[[package]]
|
|
+name = "strsim"
|
|
+version = "0.9.3"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
|
+
|
|
+[[package]]
|
|
name = "structopt"
|
|
version = "0.3.21"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -735,6 +1190,25 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "term"
|
|
+version = "0.6.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5"
|
|
+dependencies = [
|
|
+ "dirs 2.0.2",
|
|
+ "winapi",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "termcolor"
|
|
+version = "1.1.2"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
|
+dependencies = [
|
|
+ "winapi-util",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "termion"
|
|
version = "1.5.6"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -756,6 +1230,15 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "thread_local"
|
|
+version = "1.1.3"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
|
|
+dependencies = [
|
|
+ "once_cell",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "time"
|
|
version = "0.1.43"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -766,6 +1249,53 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "time"
|
|
+version = "0.2.26"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "08a8cbfbf47955132d0202d1662f49b2423ae35862aee471f3ba4b133358f372"
|
|
+dependencies = [
|
|
+ "const_fn",
|
|
+ "libc",
|
|
+ "standback",
|
|
+ "stdweb",
|
|
+ "time-macros",
|
|
+ "version_check",
|
|
+ "winapi",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "time-macros"
|
|
+version = "0.1.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1"
|
|
+dependencies = [
|
|
+ "proc-macro-hack",
|
|
+ "time-macros-impl",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "time-macros-impl"
|
|
+version = "0.1.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa"
|
|
+dependencies = [
|
|
+ "proc-macro-hack",
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "standback",
|
|
+ "syn",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "timer"
|
|
+version = "0.2.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b"
|
|
+dependencies = [
|
|
+ "chrono",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "toml"
|
|
version = "0.5.8"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -797,6 +1327,20 @@
|
|
]
|
|
|
|
[[package]]
|
|
+name = "tuikit"
|
|
+version = "0.4.5"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "8c628cfc5752254a33ebccf73eb79ef6508fab77de5d5ef76246b5e45010a51f"
|
|
+dependencies = [
|
|
+ "bitflags",
|
|
+ "lazy_static",
|
|
+ "log",
|
|
+ "nix 0.14.1",
|
|
+ "term",
|
|
+ "unicode-width",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "unicode-segmentation"
|
|
version = "1.7.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -831,6 +1375,12 @@
|
|
checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
|
|
|
|
[[package]]
|
|
+name = "utf8parse"
|
|
+version = "0.2.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
|
|
+
|
|
+[[package]]
|
|
name = "vec_map"
|
|
version = "0.8.2"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -849,6 +1399,27 @@
|
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
|
|
|
[[package]]
|
|
+name = "vte"
|
|
+version = "0.9.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "6e7745610024d50ab1ebfa41f8f8ee361c567f7ab51032f93cc1cc4cbf0c547a"
|
|
+dependencies = [
|
|
+ "arrayvec",
|
|
+ "utf8parse 0.2.0",
|
|
+ "vte_generate_state_changes",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "vte_generate_state_changes"
|
|
+version = "0.1.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
|
|
+dependencies = [
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "wasi"
|
|
version = "0.9.0+wasi-snapshot-preview1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -861,6 +1432,60 @@
|
|
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
|
|
|
[[package]]
|
|
+name = "wasm-bindgen"
|
|
+version = "0.2.74"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
|
|
+dependencies = [
|
|
+ "cfg-if 1.0.0",
|
|
+ "wasm-bindgen-macro",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "wasm-bindgen-backend"
|
|
+version = "0.2.74"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
|
|
+dependencies = [
|
|
+ "bumpalo",
|
|
+ "lazy_static",
|
|
+ "log",
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "syn",
|
|
+ "wasm-bindgen-shared",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "wasm-bindgen-macro"
|
|
+version = "0.2.74"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
|
|
+dependencies = [
|
|
+ "quote",
|
|
+ "wasm-bindgen-macro-support",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "wasm-bindgen-macro-support"
|
|
+version = "0.2.74"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
|
+dependencies = [
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "syn",
|
|
+ "wasm-bindgen-backend",
|
|
+ "wasm-bindgen-shared",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "wasm-bindgen-shared"
|
|
+version = "0.2.74"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
|
|
+
|
|
+[[package]]
|
|
name = "which"
|
|
version = "4.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
@@ -893,6 +1518,15 @@
|
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
|
|
[[package]]
|
|
+name = "winapi-util"
|
|
+version = "0.1.5"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
|
+dependencies = [
|
|
+ "winapi",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
name = "winapi-x86_64-pc-windows-gnu"
|
|
version = "0.4.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
diff -ur a/Cargo.toml b/Cargo.toml
|
|
--- a/Cargo.toml 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/Cargo.toml 2021-08-07 11:25:14.695474018 +0300
|
|
@@ -10,7 +10,9 @@
|
|
[dependencies]
|
|
alphanumeric-sort = "^1"
|
|
chrono = "^0"
|
|
+colors-transform = "^0"
|
|
dirs-next = "^2"
|
|
+filetime = "^0"
|
|
globset = "^0"
|
|
lazy_static = "^1"
|
|
libc = "^0"
|
|
@@ -22,6 +24,7 @@
|
|
shell-words = "^1"
|
|
shellexpand = "^2"
|
|
signal-hook = "^0"
|
|
+skim = "^0"
|
|
structopt = "^0"
|
|
termion = "^1"
|
|
toml = "^0"
|
|
@@ -32,7 +35,7 @@
|
|
xdg = "^2"
|
|
phf = { version = "^0", features = ["macros"], optional = true }
|
|
trash = { version = "^1", optional = true }
|
|
-
|
|
+unicode-segmentation = "^1"
|
|
[features]
|
|
devicons = [ "phf" ]
|
|
file_mimetype = []
|
|
diff -ur a/config/joshuto.toml b/config/joshuto.toml
|
|
--- a/config/joshuto.toml 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/config/joshuto.toml 2021-08-07 11:25:14.695474018 +0300
|
|
@@ -4,9 +4,6 @@
|
|
xdg_open = false
|
|
use_trash = true
|
|
|
|
-# currently does not work
|
|
-max_preview_size = 2097152 # 2MB
|
|
-
|
|
[display]
|
|
# ratios for parent view, current view and preview
|
|
collapse_preview = true
|
|
@@ -23,3 +20,12 @@
|
|
case_sensitive = false
|
|
directories_first = true
|
|
reverse = false
|
|
+
|
|
+[preview]
|
|
+max_preview_size = 2097152 # 2MB
|
|
+preview_images = false
|
|
+preview_script = "~/.config/joshuto/preview.sh"
|
|
+
|
|
+[tab]
|
|
+# inherit, home, root
|
|
+home_page = "home"
|
|
diff -ur a/config/keymap.toml b/config/keymap.toml
|
|
--- a/config/keymap.toml 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/config/keymap.toml 2021-08-07 11:25:14.695474018 +0300
|
|
@@ -36,13 +36,13 @@
|
|
|
|
[[mapcommand]]
|
|
command = "cursor_move_up"
|
|
-keys = [ "up" ]
|
|
+keys = [ "arrow_up" ]
|
|
[[mapcommand]]
|
|
command = "cursor_move_up"
|
|
keys = [ "k" ]
|
|
[[mapcommand]]
|
|
command = "cursor_move_down"
|
|
-keys = [ "down" ]
|
|
+keys = [ "arrow_down" ]
|
|
[[mapcommand]]
|
|
command = "cursor_move_down"
|
|
keys = [ "j" ]
|
|
@@ -73,16 +73,16 @@
|
|
keys = [ "]" ]
|
|
|
|
[[mapcommand]]
|
|
-command = "open_file"
|
|
-keys = [ "right" ]
|
|
+command = "open"
|
|
+keys = [ "arrow_right" ]
|
|
[[mapcommand]]
|
|
-command = "open_file"
|
|
+command = "open"
|
|
keys = [ "l" ]
|
|
[[mapcommand]]
|
|
-command = "open_file"
|
|
+command = "open"
|
|
keys = [ "\n" ]
|
|
[[mapcommand]]
|
|
-command = "open_file_with"
|
|
+command = "open_with"
|
|
keys = [ "r" ]
|
|
|
|
[[mapcommand]]
|
|
@@ -90,7 +90,7 @@
|
|
keys = [ "c", "d" ]
|
|
[[mapcommand]]
|
|
command = "cd .."
|
|
-keys = [ "left" ]
|
|
+keys = [ "arrow_left" ]
|
|
[[mapcommand]]
|
|
command = "cd .."
|
|
keys = [ "h" ]
|
|
@@ -102,6 +102,15 @@
|
|
command = "copy_files"
|
|
keys = [ "y", "y" ]
|
|
[[mapcommand]]
|
|
+command = "copy_filename"
|
|
+keys = [ "y", "n" ]
|
|
+[[mapcommand]]
|
|
+command = "copy_filepath"
|
|
+keys = [ "y", "p" ]
|
|
+[[mapcommand]]
|
|
+command = "copy_dirname"
|
|
+keys = [ "y", "d" ]
|
|
+[[mapcommand]]
|
|
command = "paste_files"
|
|
keys = [ "p", "p" ]
|
|
[[mapcommand]]
|
|
@@ -152,11 +161,17 @@
|
|
command = ":"
|
|
keys = [ ";" ]
|
|
[[mapcommand]]
|
|
+command = ":"
|
|
+keys = [ ":" ]
|
|
+[[mapcommand]]
|
|
command = ":mkdir "
|
|
keys = [ "m", "k" ]
|
|
[[mapcommand]]
|
|
command = ":rename "
|
|
keys = [ "c", "w" ]
|
|
+[[mapcommand]]
|
|
+command = ":touch"
|
|
+keys = [ "f", "t" ]
|
|
|
|
[[mapcommand]]
|
|
command = "sort lexical"
|
|
@@ -168,6 +183,9 @@
|
|
command = "sort natural"
|
|
keys = [ "s", "n" ]
|
|
[[mapcommand]]
|
|
+command = "sort ext"
|
|
+keys = [ "s", "e" ]
|
|
+[[mapcommand]]
|
|
command = "sort reverse"
|
|
keys = [ "s", "r" ]
|
|
|
|
diff -ur a/config/mimetype.toml b/config/mimetype.toml
|
|
--- a/config/mimetype.toml 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/config/mimetype.toml 2021-08-07 11:25:14.695474018 +0300
|
|
@@ -1,314 +1,156 @@
|
|
-[extension]
|
|
-
|
|
-## image formats
|
|
-bmp = [
|
|
- { command = "qimgv", fork = true, silent = true },
|
|
- { command = "krita", fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true } ]
|
|
-gif = [
|
|
- { command = "qimgv", fork = true, silent = true },
|
|
- { command = "krita", fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true } ]
|
|
-heic = [
|
|
- { command = "qimgv", fork = true, silent = true },
|
|
- { command = "krita", fork = true, silent = true },
|
|
+[class]
|
|
+audio_default = [
|
|
+ { command = "mpv", args = [ "--" ] },
|
|
{ command = "mediainfo", confirm_exit = true } ]
|
|
-jpeg = [
|
|
- { command = "qimgv", fork = true, silent = true },
|
|
- { command = "krita", fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-jpe = [
|
|
- { command = "qimgv", fork = true, silent = true },
|
|
- { command = "krita", fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-jpg = [
|
|
- { command = "qimgv", fork = true, silent = true },
|
|
- { command = "krita", fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-pgm = [
|
|
- { command = "qimgv", fork = true, silent = true },
|
|
- { command = "krita", fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-png = [
|
|
+
|
|
+image_default = [
|
|
{ command = "qimgv", fork = true, silent = true },
|
|
{ command = "krita", fork = true, silent = true },
|
|
{ command = "mediainfo", confirm_exit = true },
|
|
-ppm = [
|
|
- { command = "qimgv", fork = true, silent = true },
|
|
- { command = "krita", fork = true, silent = true },
|
|
+ { command = "swappy", args = [ "-f" ], fork = true } ]
|
|
+
|
|
+video_default = [
|
|
+ { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
{ command = "mediainfo", confirm_exit = true },
|
|
-svg = [
|
|
+ { command = "mpv", args = [ "--mute", "on", "--" ], fork = true, silent = true } ]
|
|
+
|
|
+text_default = [
|
|
+ { command = "micro" },
|
|
+ { command = "gedit", fork = true, silent = true },
|
|
+ { command = "bat", confirm_exit = true } ]
|
|
+
|
|
+[extension]
|
|
+
|
|
+## image formats
|
|
+bmp.inherit = "image_default"
|
|
+gif.inherit = "image_default"
|
|
+heic.inherit = "image_default"
|
|
+jpeg.inherit = "image_default"
|
|
+jpe.inherit = "image_default"
|
|
+jpg.inherit = "image_default"
|
|
+pgm.inherit = "image_default"
|
|
+png.inherit = "image_default"
|
|
+ppm.inherit = "image_default"
|
|
+
|
|
+svg.app_list = [
|
|
{ command = "inkview", fork = true, silent = true },
|
|
{ command = "inkscape", fork = true, silent = true } ]
|
|
-tiff = [
|
|
+tiff.app_list = [
|
|
{ command = "qimgv", fork = true, silent = true },
|
|
{ command = "krita", fork = true, silent = true } ]
|
|
|
|
## audio formats
|
|
-flac = [
|
|
- { command = "mpv", args = [ "--" ] },
|
|
- { command = "mediainfo", confirm_exit = true } ]
|
|
-m4a = [
|
|
- { command = "mpv", args = [ "--" ] },
|
|
- { command = "mediainfo", confirm_exit = true } ]
|
|
-mp3 = [
|
|
- { command = "mpv", args = [ "--" ] },
|
|
- { command = "mediainfo", confirm_exit = true } ]
|
|
-ogg = [
|
|
- { command = "mpv", args = [ "--" ] },
|
|
- { command = "mediainfo", confirm_exit = true } ]
|
|
-wav = [
|
|
- { command = "mpv", args = [ "--" ] },
|
|
- { command = "mediainfo", confirm_exit = true } ]
|
|
-ts = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mpv" },
|
|
- { command = "mediainfo", confirm_exit = true } ]
|
|
+flac.inherit = "audio_default"
|
|
+m4a.inherit = "audio_default"
|
|
+mp3.inherit = "audio_default"
|
|
+ogg.inherit = "audio_default"
|
|
+wav.inherit = "audio_default"
|
|
+ts.inherit = "audio_default"
|
|
|
|
## video formats
|
|
-avi = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-av1 = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-flv = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-mkv = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-m4v = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-mov = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-mp4 = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-webm = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
-wmv = [
|
|
- { command = "mpv", args = [ "--" ] , fork = true, silent = true },
|
|
- { command = "mediainfo", confirm_exit = true },
|
|
+avi.inherit = "video_default"
|
|
+av1.inherit = "video_default"
|
|
+flv.inherit = "video_default"
|
|
+mkv.inherit = "video_default"
|
|
+m4v.inherit = "video_default"
|
|
+mov.inherit = "video_default"
|
|
+mp4.inherit = "video_default"
|
|
+webm.inherit = "video_default"
|
|
+webp.inherit = "video_default"
|
|
+wmv.inherit = "video_default"
|
|
|
|
## text formats
|
|
-build = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-c = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-cmake = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-conf = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-cpp = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-css = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-csv = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-cu = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-eex = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-env = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-ex = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-exs = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-go = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-h = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-hpp = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-hs = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-html = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-ini = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-java = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-js = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-json = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-kt = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-lua = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-log = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-md = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-micro = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-ninja = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-py = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-rkt = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-rs = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-scss = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-sh = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-srt = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-svelte = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-toml = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-tsx = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-txt = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-vim = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-xml = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-yaml = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
-yml = [
|
|
- { command = "micro" },
|
|
- { command = "gedit", fork = true, silent = true },
|
|
- { command = "bat", confirm_exit = true } ]
|
|
+build.inherit = "text_default"
|
|
+c.inherit = "text_default"
|
|
+cmake.inherit = "text_default"
|
|
+conf.inherit = "text_default"
|
|
+cpp.inherit = "text_default"
|
|
+css.inherit = "text_default"
|
|
+csv.inherit = "text_default"
|
|
+cu.inherit = "text_default"
|
|
+eex.inherit = "text_default"
|
|
+env.inherit = "text_default"
|
|
+ex.inherit = "text_default"
|
|
+exs.inherit = "text_default"
|
|
+go.inherit = "text_default"
|
|
+h.inherit = "text_default"
|
|
+hpp.inherit = "text_default"
|
|
+hs.inherit = "text_default"
|
|
+html.inherit = "text_default"
|
|
+ini.inherit = "text_default"
|
|
+java.inherit = "text_default"
|
|
+js.inherit = "text_default"
|
|
+json.inherit = "text_default"
|
|
+kt.inherit = "text_default"
|
|
+lua.inherit = "text_default"
|
|
+log.inherit = "text_default"
|
|
+md.inherit = "text_default"
|
|
+micro.inherit = "text_default"
|
|
+ninja.inherit = "text_default"
|
|
+py.inherit = "text_default"
|
|
+rkt.inherit = "text_default"
|
|
+rs.inherit = "text_default"
|
|
+scss.inherit = "text_default"
|
|
+sh.inherit = "text_default"
|
|
+srt.inherit = "text_default"
|
|
+svelte.inherit = "text_default"
|
|
+toml.inherit = "text_default"
|
|
+tsx.inherit = "text_default"
|
|
+txt.inherit = "text_default"
|
|
+vim.inherit = "text_default"
|
|
+xml.inherit = "text_default"
|
|
+yaml.inherit = "text_default"
|
|
+yml.inherit = "text_default"
|
|
|
|
# archive formats
|
|
-7z = [
|
|
+7z.app_list = [
|
|
{ command = "7z", args = [ "x" ], confirm_exit = true },
|
|
{ command = "file-roller", fork = true, silent = true } ]
|
|
-bz2 = [
|
|
+bz2.app_list = [
|
|
{ command = "tar", args = [ "-xvjf" ], confirm_exit = true },
|
|
{ command = "file-roller", fork = true, silent = true } ]
|
|
-gz = [
|
|
+gz.app_list = [
|
|
{ command = "tar", args = [ "-xvzf" ], confirm_exit = true },
|
|
{ command = "file-roller", fork = true, silent = true } ]
|
|
-tar = [
|
|
+tar.app_list = [
|
|
{ command = "tar", args = [ "-xvf" ], confirm_exit = true },
|
|
{ command = "file-roller", fork = true, silent = true } ]
|
|
-tgz = [
|
|
+tgz.app_list = [
|
|
{ command = "tar", args = [ "-xvzf" ], confirm_exit = true },
|
|
{ command = "file-roller", fork = true, silent = true } ]
|
|
-rar = [
|
|
+rar.app_list = [
|
|
{ command = "unrar", args = [ "e" ], confirm_exit = true },
|
|
{ command = "file-roller", fork = true, silent = true } ]
|
|
-xz = [
|
|
+xz.app_list = [
|
|
{ command = "tar", args = [ "-xvJf" ], confirm_exit = true },
|
|
{ command = "file-roller", fork = true, silent = true } ]
|
|
-zip = [
|
|
+zip.app_list = [
|
|
{ command = "unzip", confirm_exit = true },
|
|
{ command = "file-roller", fork = true, silent = true } ]
|
|
|
|
# misc formats
|
|
-aup = [
|
|
+aup.app_list = [
|
|
{ command = "audacity", fork = true, silent = true } ]
|
|
|
|
-m3u = [
|
|
+m3u.app_list = [
|
|
{ command = "micro" },
|
|
{ command = "mpv" },
|
|
{ command = "gedit", fork = true, silent = true },
|
|
{ command = "bat", confirm_exit = true } ]
|
|
-docx = [
|
|
+docx.app_list = [
|
|
{ command = "libreoffice", fork = true, silent = true } ]
|
|
-odt = [
|
|
+odt.app_list = [
|
|
{ command = "libreoffice", fork = true, silent = true } ]
|
|
-odf = [
|
|
+odf.app_list = [
|
|
{ command = "libreoffice", fork = true, silent = true } ]
|
|
-pdf = [
|
|
+pdf.app_list = [
|
|
{ command = "evince", fork = true, silent = true } ]
|
|
|
|
-tex = [
|
|
+tex.app_list = [
|
|
{ command = "micro" },
|
|
{ command = "gedit", fork = true, silent = true },
|
|
{ command = "bat", confirm_exit = true },
|
|
{ command = "pdflatex" } ]
|
|
|
|
-torrent = [
|
|
+torrent.app_list = [
|
|
{ command = "transmission-gtk" } ]
|
|
diff -ur a/config/theme.toml b/config/theme.toml
|
|
--- a/config/theme.toml 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/config/theme.toml 2021-08-07 11:25:14.695474018 +0300
|
|
@@ -34,6 +34,8 @@
|
|
fg = "yellow"
|
|
[ext.png]
|
|
fg = "yellow"
|
|
+[ext.webp]
|
|
+fg = "yellow"
|
|
[ext.ppm]
|
|
fg = "yellow"
|
|
[ext.svg]
|
|
Только в b: .git
|
|
Только в b/.github/workflows: rust-linux-dev.yml
|
|
Только в b/.github/workflows: rust-linux-main.yml
|
|
Только в a/.github/workflows: rust-linux.yml
|
|
Только в b/.github/workflows: rust-macos-dev.yml
|
|
Только в b/.github/workflows: rust-macos-main.yml
|
|
Только в a/.github/workflows: rust-macos.yml
|
|
diff -ur a/README.md b/README.md
|
|
--- a/README.md 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/README.md 2021-08-07 11:25:14.695474018 +0300
|
|
@@ -1,6 +1,6 @@
|
|
-[![Linux Build](https://github.com/kamiyaa/joshuto/actions/workflows/rust-linux.yml/badge.svg)](https://github.com/kamiyaa/joshuto/actions/workflows/rust-linux.yml)
|
|
+[![Linux build](https://github.com/kamiyaa/joshuto/actions/workflows/rust-linux-main.yml/badge.svg)](https://github.com/kamiyaa/joshuto/actions/workflows/rust-linux-main.yml)
|
|
|
|
-[![MacOS Build](https://github.com/kamiyaa/joshuto/actions/workflows/rust-macos.yml/badge.svg)](https://github.com/kamiyaa/joshuto/actions/workflows/rust-macos.yml)
|
|
+[![MacOS build](https://github.com/kamiyaa/joshuto/actions/workflows/rust-macos-main.yml/badge.svg)](https://github.com/kamiyaa/joshuto/actions/workflows/rust-macos-main.yml)
|
|
|
|
# joshuto
|
|
|
|
@@ -45,6 +45,18 @@
|
|
sudo dnf install joshuto
|
|
```
|
|
|
|
+##### Arch ([AUR](https://aur.archlinux.org))
|
|
+
|
|
+* [release](https://aur.archlinux.org/packages/joshuto)
|
|
+```
|
|
+[yay/paru] -S joshuto
|
|
+```
|
|
+
|
|
+* [build from source](https://aur.archlinux.org/packages/joshuto-git)
|
|
+```
|
|
+[yay/paru] -S joshuto-git
|
|
+```
|
|
+
|
|
## Usage
|
|
|
|
```
|
|
@@ -53,30 +65,24 @@
|
|
|
|
## Configuration
|
|
|
|
-Place config files inside `$XDG_CONFIG_HOME/joshuto` (usually `$HOME/.config/joshuto/` for GNU/Linux).
|
|
-
|
|
-Joshuto can currently be configured using the following files:
|
|
+Check out [wiki/Configuration](https://github.com/kamiyaa/joshuto/wiki/Configuration) for details
|
|
+and [config/](config/) for examples
|
|
|
|
#### [joshuto.toml](config/joshuto.toml)
|
|
-
|
|
- general configurations
|
|
|
|
#### [keymap.toml](/config/keymap.toml)
|
|
-
|
|
- for keybindings, please take a look at [src/util/key_mapping.rs](/src/util/key_mapping.rs#L18) for non-printable keys
|
|
- for commands, please take a look at [src/commands/commands.rs](/src/commands/commands.rs#L139)
|
|
|
|
#### [mimetype.toml](/config/mimetype.toml)
|
|
-
|
|
- for opening files with applications
|
|
|
|
#### [theme.toml](/config/theme.toml)
|
|
-
|
|
- color customizations
|
|
|
|
## Contributing
|
|
-
|
|
-Please create a pull request :)
|
|
+See [wiki/Contributing](https://github.com/kamiyaa/joshuto/wiki/Contributing)
|
|
|
|
## Features/Bugs
|
|
|
|
@@ -87,8 +93,10 @@
|
|
- [x] Migrate to [tui-rs](https://github.com/fdehau/tui-rs)
|
|
- [x] Tab support
|
|
- [x] Ctrl/Shift/Alt support
|
|
-- [x] Asynch File IO (cut/copy/paste/delete/rename) (in progress)
|
|
+- [x] Asynch File IO (cut/copy/paste)
|
|
- [ ] Built-in command line (in progress)
|
|
+ - Currently implementation is kind of janky
|
|
- [ ] File previews (in progress)
|
|
+ - Waiting for tui-rs to support parsing ANSI color codes
|
|
- [ ] Tab autocomplete (in progress)
|
|
- [x] Bulk rename
|
|
diff -ur a/src/commands/bulk_rename.rs b/src/commands/bulk_rename.rs
|
|
--- a/src/commands/bulk_rename.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/bulk_rename.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -81,6 +81,9 @@
|
|
));
|
|
}
|
|
|
|
+ println!("{}", termion::clear::All);
|
|
+ termion::cursor::Goto(0, 0);
|
|
+
|
|
for (p, q) in paths.iter().zip(paths_renamed.iter()) {
|
|
println!("{:?} -> {:?}", p, q);
|
|
}
|
|
diff -ur a/src/commands/change_directory.rs b/src/commands/change_directory.rs
|
|
--- a/src/commands/change_directory.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/change_directory.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -3,7 +3,6 @@
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
use crate::history::DirectoryHistory;
|
|
-use crate::util::load_child::LoadChild;
|
|
|
|
pub fn cd(path: &path::Path, context: &mut AppContext) -> std::io::Result<()> {
|
|
std::env::set_current_dir(path)?;
|
|
@@ -25,6 +24,5 @@
|
|
|
|
pub fn change_directory(context: &mut AppContext, path: &path::Path) -> JoshutoResult<()> {
|
|
_change_directory(path, context)?;
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
diff -ur a/src/commands/command_line.rs b/src/commands/command_line.rs
|
|
--- a/src/commands/command_line.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/command_line.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -1,3 +1,5 @@
|
|
+use std::str::FromStr;
|
|
+
|
|
use crate::commands::KeyCommand;
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
@@ -21,7 +23,7 @@
|
|
|
|
if let Some(s) = user_input {
|
|
let trimmed = s.trim_start();
|
|
- let command = KeyCommand::parse_command(trimmed)?;
|
|
+ let command = KeyCommand::from_str(trimmed)?;
|
|
command.execute(context, backend)
|
|
} else {
|
|
Ok(())
|
|
diff -ur a/src/commands/cursor_move.rs b/src/commands/cursor_move.rs
|
|
--- a/src/commands/cursor_move.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/cursor_move.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -1,7 +1,7 @@
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
-use crate::history::DirectoryHistory;
|
|
use crate::ui::TuiBackend;
|
|
+
|
|
use std::path::PathBuf;
|
|
|
|
pub fn cursor_move(new_index: usize, context: &mut AppContext) -> JoshutoResult<()> {
|
|
@@ -20,18 +20,6 @@
|
|
path = Some(entry.file_path().to_path_buf())
|
|
}
|
|
}
|
|
-
|
|
- // get preview
|
|
- if let Some(path) = path {
|
|
- if path.is_dir() {
|
|
- let options = context.config_ref().display_options_ref().clone();
|
|
- context
|
|
- .tab_context_mut()
|
|
- .curr_tab_mut()
|
|
- .history_mut()
|
|
- .create_or_soft_update(path.as_path(), &options)?;
|
|
- }
|
|
- }
|
|
Ok(())
|
|
}
|
|
|
|
@@ -96,18 +84,33 @@
|
|
Ok(())
|
|
}
|
|
|
|
-pub fn page_up(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
|
|
- let half_page = {
|
|
- match backend.terminal.as_ref().unwrap().size() {
|
|
- Ok(rect) => rect.height as usize - 2,
|
|
- _ => 10,
|
|
+fn get_page_size(context: &AppContext, backend: &TuiBackend) -> Option<usize> {
|
|
+ let config = context.config_ref();
|
|
+ let rect = backend.terminal.as_ref().map(|t| t.size())?.ok()?;
|
|
+
|
|
+ let rect_height = rect.height as usize;
|
|
+ if config.display_options_ref().show_borders() {
|
|
+ if rect_height >= 4 {
|
|
+ Some(rect_height - 4)
|
|
+ } else {
|
|
+ None
|
|
+ }
|
|
+ } else {
|
|
+ if rect_height >= 2 {
|
|
+ Some(rect_height - 2)
|
|
+ } else {
|
|
+ None
|
|
}
|
|
- };
|
|
+ }
|
|
+}
|
|
+
|
|
+pub fn page_up(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
|
|
+ let page_size = get_page_size(context, backend).unwrap_or(10);
|
|
|
|
let movement = match context.tab_context_ref().curr_tab_ref().curr_list_ref() {
|
|
Some(curr_list) => curr_list
|
|
.index
|
|
- .map(|idx| if idx > half_page { idx - half_page } else { 0 }),
|
|
+ .map(|idx| if idx > page_size { idx - page_size } else { 0 }),
|
|
None => None,
|
|
};
|
|
|
|
@@ -118,21 +121,16 @@
|
|
}
|
|
|
|
pub fn page_down(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
|
|
- let half_page = {
|
|
- match backend.terminal.as_ref().unwrap().size() {
|
|
- Ok(rect) => rect.height as usize - 2,
|
|
- _ => 10,
|
|
- }
|
|
- };
|
|
+ let page_size = get_page_size(context, backend).unwrap_or(10);
|
|
|
|
let movement = match context.tab_context_ref().curr_tab_ref().curr_list_ref() {
|
|
Some(curr_list) => {
|
|
let dir_len = curr_list.len();
|
|
curr_list.index.map(|idx| {
|
|
- if idx + half_page > dir_len - 1 {
|
|
+ if idx + page_size > dir_len - 1 {
|
|
dir_len - 1
|
|
} else {
|
|
- idx + half_page
|
|
+ idx + page_size
|
|
}
|
|
})
|
|
}
|
|
diff -ur a/src/commands/delete_files.rs b/src/commands/delete_files.rs
|
|
--- a/src/commands/delete_files.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/delete_files.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -7,7 +7,6 @@
|
|
use crate::history::DirectoryHistory;
|
|
use crate::ui::widgets::TuiPrompt;
|
|
use crate::ui::TuiBackend;
|
|
-use crate::util::load_child::LoadChild;
|
|
|
|
use super::reload;
|
|
|
|
@@ -116,6 +115,5 @@
|
|
for tab in context.tab_context_mut().iter_mut() {
|
|
tab.history_mut().reload(&curr_path, &options)?;
|
|
}
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
diff -ur a/src/commands/file_ops.rs b/src/commands/file_ops.rs
|
|
--- a/src/commands/file_ops.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/file_ops.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -49,45 +49,76 @@
|
|
}
|
|
|
|
pub fn copy_filename(context: &mut AppContext) -> JoshutoResult<()> {
|
|
- let entry_file_name = match context
|
|
+ let entry_file_name = context
|
|
.tab_context_ref()
|
|
.curr_tab_ref()
|
|
.curr_list_ref()
|
|
.and_then(|c| c.curr_entry_ref())
|
|
- {
|
|
- Some(entry) => Some(entry.file_name().to_string()),
|
|
- None => None,
|
|
- };
|
|
+ .map(|entry| entry.file_name().to_string());
|
|
+
|
|
if let Some(file_name) = entry_file_name {
|
|
- let clipboards = [
|
|
- (
|
|
- "wl-copy",
|
|
- format!("printf '%s' {} | {} 2> /dev/null", file_name, "wl-copy"),
|
|
- ),
|
|
- (
|
|
- "xsel",
|
|
- format!("printf '%s' {} | {} -ib 2> /dev/null", file_name, "xsel"),
|
|
- ),
|
|
- (
|
|
- "xclip",
|
|
- format!(
|
|
- "printf '%s' {} | {} -selection clipboard 2> /dev/null",
|
|
- file_name, "xclip"
|
|
- ),
|
|
+ copy_string_to_buffer(file_name)?;
|
|
+ }
|
|
+ Ok(())
|
|
+}
|
|
+
|
|
+pub fn copy_filepath(context: &mut AppContext) -> JoshutoResult<()> {
|
|
+ let entry_file_path = context
|
|
+ .tab_context_ref()
|
|
+ .curr_tab_ref()
|
|
+ .curr_list_ref()
|
|
+ .and_then(|c| c.curr_entry_ref())
|
|
+ .and_then(|entry| entry.file_path().to_str())
|
|
+ .map(|s| s.to_string());
|
|
+
|
|
+ if let Some(file_path) = entry_file_path {
|
|
+ copy_string_to_buffer(file_path)?;
|
|
+ }
|
|
+ Ok(())
|
|
+}
|
|
+
|
|
+pub fn copy_dirname(context: &mut AppContext) -> JoshutoResult<()> {
|
|
+ let opt_entry = context
|
|
+ .tab_context_ref()
|
|
+ .curr_tab_ref()
|
|
+ .curr_list_ref()
|
|
+ .map(|dirlist| dirlist.file_path());
|
|
+
|
|
+ if let Some(pathbuf) = opt_entry {
|
|
+ if let Some(dir) = pathbuf.to_str().map(String::from) {
|
|
+ copy_string_to_buffer(dir)?
|
|
+ }
|
|
+ };
|
|
+ Ok(())
|
|
+}
|
|
+
|
|
+fn copy_string_to_buffer(string: String) -> JoshutoResult<()> {
|
|
+ let clipboards = [
|
|
+ (
|
|
+ "wl-copy",
|
|
+ format!("printf '%s' {} | {} 2> /dev/null", string, "wl-copy"),
|
|
+ ),
|
|
+ (
|
|
+ "xsel",
|
|
+ format!("printf '%s' {} | {} -ib 2> /dev/null", string, "xsel"),
|
|
+ ),
|
|
+ (
|
|
+ "xclip",
|
|
+ format!(
|
|
+ "printf '%s' {} | {} -selection clipboard 2> /dev/null",
|
|
+ string, "xclip"
|
|
),
|
|
- ];
|
|
+ ),
|
|
+ ];
|
|
|
|
- for (_, command) in clipboards.iter() {
|
|
- match Command::new("sh").args(&["-c", command.as_str()]).status() {
|
|
- Ok(s) if s.success() => return Ok(()),
|
|
- _ => {}
|
|
- }
|
|
+ for (_, command) in clipboards.iter() {
|
|
+ match Command::new("sh").args(&["-c", command.as_str()]).status() {
|
|
+ Ok(s) if s.success() => return Ok(()),
|
|
+ _ => {}
|
|
}
|
|
- let err = Err(JoshutoError::new(
|
|
- JoshutoErrorKind::ClipboardError,
|
|
- "Failed to copy to clipboard".to_string(),
|
|
- ));
|
|
- return err;
|
|
}
|
|
- Ok(())
|
|
+ Err(JoshutoError::new(
|
|
+ JoshutoErrorKind::ClipboardError,
|
|
+ "Failed to copy to clipboard".to_string(),
|
|
+ ))
|
|
}
|
|
diff -ur a/src/commands/key_command.rs b/src/commands/key_command.rs
|
|
--- a/src/commands/key_command.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/key_command.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -4,7 +4,6 @@
|
|
use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
|
|
use crate::io::IoWorkerOptions;
|
|
use crate::ui::TuiBackend;
|
|
-use crate::util::load_child::LoadChild;
|
|
use crate::util::select::SelectOption;
|
|
use crate::util::sort::SortType;
|
|
|
|
@@ -24,6 +23,8 @@
|
|
CopyFiles,
|
|
PasteFiles(IoWorkerOptions),
|
|
CopyFileName,
|
|
+ CopyFilePath,
|
|
+ CopyDirName,
|
|
|
|
CursorMoveUp(usize),
|
|
CursorMoveDown(usize),
|
|
@@ -40,7 +41,7 @@
|
|
DeleteFiles,
|
|
NewDirectory(path::PathBuf),
|
|
OpenFile,
|
|
- OpenFileWith,
|
|
+ OpenFileWith(Option<usize>),
|
|
ParentDirectory,
|
|
|
|
Quit,
|
|
@@ -49,15 +50,17 @@
|
|
RenameFile(path::PathBuf),
|
|
RenameFileAppend,
|
|
RenameFilePrepend,
|
|
+ TouchFile(String),
|
|
|
|
SearchGlob(String),
|
|
SearchString(String),
|
|
+ SearchSkim,
|
|
SearchNext,
|
|
SearchPrev,
|
|
|
|
SelectFiles(String, SelectOption),
|
|
SetMode,
|
|
- ShellCommand(Vec<String>),
|
|
+ SubProcess(Vec<String>, bool),
|
|
ShowWorkers,
|
|
|
|
ToggleHiddenFiles,
|
|
@@ -77,12 +80,14 @@
|
|
Self::ChangeDirectory(_) => "cd",
|
|
Self::NewTab => "new_tab",
|
|
Self::CloseTab => "close_tab",
|
|
- Self::CommandLine(_, _) => "console",
|
|
+ Self::CommandLine(_, _) => ":",
|
|
|
|
Self::CutFiles => "cut_files",
|
|
Self::CopyFiles => "copy_files",
|
|
Self::PasteFiles(_) => "paste_files",
|
|
Self::CopyFileName => "copy_filename",
|
|
+ Self::CopyFilePath => "copy_filepath",
|
|
+ Self::CopyDirName => "copy_dirname",
|
|
|
|
Self::CursorMoveUp(_) => "cursor_move_up",
|
|
Self::CursorMoveDown(_) => "cursor_move_down",
|
|
@@ -95,26 +100,29 @@
|
|
Self::ParentCursorMoveDown(_) => "parent_cursor_move_down",
|
|
|
|
Self::DeleteFiles => "delete_files",
|
|
- Self::NewDirectory(_) => "new_directory",
|
|
+ Self::NewDirectory(_) => "mkdir",
|
|
Self::OpenFile => "open",
|
|
- Self::OpenFileWith => "open_with",
|
|
+ Self::OpenFileWith(_) => "open_with",
|
|
Self::ParentDirectory => "cd ..",
|
|
|
|
Self::Quit => "quit",
|
|
Self::ForceQuit => "force_quit",
|
|
Self::ReloadDirList => "reload_dirlist",
|
|
- Self::RenameFile(_) => "rename_file",
|
|
+ Self::RenameFile(_) => "rename",
|
|
+ Self::TouchFile(_) => "touch",
|
|
Self::RenameFileAppend => "rename_append",
|
|
Self::RenameFilePrepend => "rename_prepend",
|
|
|
|
Self::SearchString(_) => "search",
|
|
Self::SearchGlob(_) => "search_glob",
|
|
+ Self::SearchSkim => "search_skim",
|
|
Self::SearchNext => "search_next",
|
|
Self::SearchPrev => "search_prev",
|
|
|
|
Self::SelectFiles(_, _) => "select",
|
|
Self::SetMode => "set_mode",
|
|
- Self::ShellCommand(_) => "shell",
|
|
+ Self::SubProcess(_, false) => "shell",
|
|
+ Self::SubProcess(_, true) => "spawn",
|
|
Self::ShowWorkers => "show_workers",
|
|
|
|
Self::ToggleHiddenFiles => "toggle_hidden",
|
|
@@ -125,8 +133,12 @@
|
|
Self::TabSwitch(_) => "tab_switch",
|
|
}
|
|
}
|
|
+}
|
|
+
|
|
+impl std::str::FromStr for KeyCommand {
|
|
+ type Err = JoshutoError;
|
|
|
|
- pub fn parse_command(s: &str) -> JoshutoResult<Self> {
|
|
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
if let Some(stripped) = s.strip_prefix(':') {
|
|
return Ok(Self::CommandLine(stripped.to_owned(), "".to_owned()));
|
|
}
|
|
@@ -155,6 +167,8 @@
|
|
"close_tab" => Ok(Self::CloseTab),
|
|
"copy_files" => Ok(Self::CopyFiles),
|
|
"copy_filename" => Ok(Self::CopyFileName),
|
|
+ "copy_filepath" => Ok(Self::CopyFilePath),
|
|
+ "copy_dirname" => Ok(Self::CopyDirName),
|
|
"cursor_move_home" => Ok(Self::CursorMoveHome),
|
|
"cursor_move_end" => Ok(Self::CursorMoveEnd),
|
|
"cursor_move_page_up" => Ok(Self::CursorMovePageUp),
|
|
@@ -206,16 +220,24 @@
|
|
if arg.is_empty() {
|
|
Err(JoshutoError::new(
|
|
JoshutoErrorKind::InvalidParameters,
|
|
- format!("{}: missing additional parameter", command),
|
|
+ format!("{}: no directory name given", command),
|
|
))
|
|
} else {
|
|
Ok(Self::NewDirectory(path::PathBuf::from(arg)))
|
|
}
|
|
}
|
|
"new_tab" => Ok(Self::NewTab),
|
|
-
|
|
- "open_file" => Ok(Self::OpenFile),
|
|
- "open_file_with" => Ok(Self::OpenFileWith),
|
|
+ "open" => Ok(Self::OpenFile),
|
|
+ "open_with" => match arg {
|
|
+ "" => Ok(Self::OpenFileWith(None)),
|
|
+ arg => match arg.trim().parse::<usize>() {
|
|
+ Ok(s) => Ok(Self::OpenFileWith(Some(s))),
|
|
+ Err(e) => Err(JoshutoError::new(
|
|
+ JoshutoErrorKind::ParseError,
|
|
+ e.to_string(),
|
|
+ )),
|
|
+ },
|
|
+ },
|
|
"paste_files" => {
|
|
let mut options = IoWorkerOptions::default();
|
|
for arg in arg.split_whitespace() {
|
|
@@ -246,6 +268,7 @@
|
|
Ok(Self::RenameFile(path))
|
|
}
|
|
},
|
|
+ "touch" => Ok(Self::TouchFile(arg.to_string())),
|
|
"rename_append" => Ok(Self::RenameFileAppend),
|
|
"rename_prepend" => Ok(Self::RenameFilePrepend),
|
|
"search" => match arg {
|
|
@@ -262,6 +285,7 @@
|
|
)),
|
|
arg => Ok(Self::SearchGlob(arg.to_string())),
|
|
},
|
|
+ "search_skim" => Ok(Self::SearchSkim),
|
|
"search_next" => Ok(Self::SearchNext),
|
|
"search_prev" => Ok(Self::SearchPrev),
|
|
"select" => {
|
|
@@ -289,11 +313,11 @@
|
|
}
|
|
}
|
|
"set_mode" => Ok(Self::SetMode),
|
|
- "shell" => match shell_words::split(arg) {
|
|
- Ok(s) if !s.is_empty() => Ok(Self::ShellCommand(s)),
|
|
+ "shell" | "spawn" => match shell_words::split(arg) {
|
|
+ Ok(s) if !s.is_empty() => Ok(Self::SubProcess(s, command == "spawn")),
|
|
Ok(_) => Err(JoshutoError::new(
|
|
JoshutoErrorKind::InvalidParameters,
|
|
- format!("sort: args {}", arg),
|
|
+ format!("{}: No commands given", command),
|
|
)),
|
|
Err(e) => Err(JoshutoError::new(
|
|
JoshutoErrorKind::InvalidParameters,
|
|
@@ -307,7 +331,7 @@
|
|
Some(s) => Ok(Self::Sort(s)),
|
|
None => Err(JoshutoError::new(
|
|
JoshutoErrorKind::InvalidParameters,
|
|
- format!("sort: Unknown option {}", arg),
|
|
+ format!("{}: Unknown option '{}'", command, arg),
|
|
)),
|
|
},
|
|
},
|
|
@@ -321,7 +345,7 @@
|
|
"toggle_hidden" => Ok(Self::ToggleHiddenFiles),
|
|
inp => Err(JoshutoError::new(
|
|
JoshutoErrorKind::UnrecognizedCommand,
|
|
- format!("Unknown command: {}", inp),
|
|
+ format!("Unrecognized command '{}'", inp),
|
|
)),
|
|
}
|
|
}
|
|
@@ -333,7 +357,6 @@
|
|
Self::BulkRename => bulk_rename::bulk_rename(context, backend),
|
|
Self::ChangeDirectory(p) => {
|
|
change_directory::change_directory(context, p.as_path())?;
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
Self::NewTab => tab_ops::new_tab(context),
|
|
@@ -345,6 +368,8 @@
|
|
Self::CopyFiles => file_ops::copy(context),
|
|
Self::PasteFiles(options) => file_ops::paste(context, options.clone()),
|
|
Self::CopyFileName => file_ops::copy_filename(context),
|
|
+ Self::CopyFilePath => file_ops::copy_filepath(context),
|
|
+ Self::CopyDirName => file_ops::copy_dirname(context),
|
|
|
|
Self::CursorMoveUp(u) => cursor_move::up(context, *u),
|
|
Self::CursorMoveDown(u) => cursor_move::down(context, *u),
|
|
@@ -362,7 +387,8 @@
|
|
}
|
|
Self::NewDirectory(p) => new_directory::new_directory(context, p.as_path()),
|
|
Self::OpenFile => open_file::open(context, backend),
|
|
- Self::OpenFileWith => open_file::open_with(context, backend),
|
|
+ Self::OpenFileWith(None) => open_file::open_with_interactive(context, backend),
|
|
+ Self::OpenFileWith(Some(i)) => open_file::open_with_index(context, backend, *i),
|
|
Self::ParentDirectory => parent_directory::parent_directory(context),
|
|
|
|
Self::Quit => quit::quit(context),
|
|
@@ -371,8 +397,10 @@
|
|
Self::RenameFile(p) => rename_file::rename_file(context, p.as_path()),
|
|
Self::RenameFileAppend => rename_file::rename_file_append(context, backend),
|
|
Self::RenameFilePrepend => rename_file::rename_file_prepend(context, backend),
|
|
+ Self::TouchFile(arg) => touch_file::touch_file(context, arg.as_str()),
|
|
Self::SearchGlob(pattern) => search_glob::search_glob(context, pattern.as_str()),
|
|
Self::SearchString(pattern) => search_string::search_string(context, pattern.as_str()),
|
|
+ Self::SearchSkim => search_skim::search_skim(context, backend),
|
|
Self::SearchNext => search::search_next(context),
|
|
Self::SearchPrev => search::search_prev(context),
|
|
|
|
@@ -380,7 +408,9 @@
|
|
selection::select_files(context, pattern.as_str(), &options)
|
|
}
|
|
Self::SetMode => set_mode::set_mode(context, backend),
|
|
- Self::ShellCommand(v) => shell::shell(context, backend, v.as_slice()),
|
|
+ Self::SubProcess(v, spawn) => {
|
|
+ sub_process::sub_process(context, backend, v.as_slice(), *spawn)
|
|
+ }
|
|
Self::ShowWorkers => show_workers::show_workers(context, backend),
|
|
|
|
Self::ToggleHiddenFiles => show_hidden::toggle_hidden(context),
|
|
@@ -415,7 +445,7 @@
|
|
Self::SelectFiles(pattern, options) => {
|
|
write!(f, "{} {} {}", self.command(), pattern, options)
|
|
}
|
|
- Self::ShellCommand(c) => write!(f, "{} {:?}", self.command(), c),
|
|
+ Self::SubProcess(c, _) => write!(f, "{} {:?}", self.command(), c),
|
|
Self::Sort(t) => write!(f, "{} {}", self.command(), t),
|
|
Self::TabSwitch(i) => write!(f, "{} {}", self.command(), i),
|
|
_ => write!(f, "{}", self.command()),
|
|
diff -ur a/src/commands/mod.rs b/src/commands/mod.rs
|
|
--- a/src/commands/mod.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/mod.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -13,14 +13,16 @@
|
|
pub mod rename_file;
|
|
pub mod search;
|
|
pub mod search_glob;
|
|
+pub mod search_skim;
|
|
pub mod search_string;
|
|
pub mod selection;
|
|
pub mod set_mode;
|
|
-pub mod shell;
|
|
pub mod show_hidden;
|
|
pub mod show_workers;
|
|
pub mod sort;
|
|
+pub mod sub_process;
|
|
pub mod tab_ops;
|
|
+pub mod touch_file;
|
|
|
|
pub mod command_keybind;
|
|
pub mod key_command;
|
|
diff -ur a/src/commands/new_directory.rs b/src/commands/new_directory.rs
|
|
--- a/src/commands/new_directory.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/new_directory.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -3,7 +3,6 @@
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
use crate::history::DirectoryHistory;
|
|
-use crate::util::load_child::LoadChild;
|
|
|
|
pub fn new_directory(context: &mut AppContext, p: &path::Path) -> JoshutoResult<()> {
|
|
std::fs::create_dir_all(p)?;
|
|
@@ -12,6 +11,5 @@
|
|
for tab in context.tab_context_mut().iter_mut() {
|
|
tab.history_mut().reload(&curr_path, &options)?;
|
|
}
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
diff -ur a/src/commands/open_file.rs b/src/commands/open_file.rs
|
|
--- a/src/commands/open_file.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/open_file.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -6,7 +6,6 @@
|
|
use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
|
|
use crate::ui::views::TuiTextField;
|
|
use crate::ui::TuiBackend;
|
|
-use crate::util::load_child::LoadChild;
|
|
|
|
use super::change_directory;
|
|
|
|
@@ -16,7 +15,7 @@
|
|
let mut options: Vec<&AppMimetypeEntry> = Vec::new();
|
|
if let Some(file_ext) = path.extension() {
|
|
if let Some(file_ext) = file_ext.to_str() {
|
|
- let ext_entries = MIMETYPE_T.get_entries_for_ext(file_ext);
|
|
+ let ext_entries = MIMETYPE_T.app_list_for_ext(file_ext);
|
|
options.extend(ext_entries);
|
|
}
|
|
}
|
|
@@ -24,6 +23,8 @@
|
|
}
|
|
|
|
pub fn open(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
|
|
+ let config = context.config_ref();
|
|
+
|
|
if let Some(entry) = context
|
|
.tab_context_ref()
|
|
.curr_tab_ref()
|
|
@@ -33,7 +34,6 @@
|
|
if entry.file_path().is_dir() {
|
|
let path = entry.file_path().to_path_buf();
|
|
change_directory::cd(path.as_path(), context)?;
|
|
- LoadChild::load_child(context)?;
|
|
} else {
|
|
let paths = context
|
|
.tab_context_ref()
|
|
@@ -48,6 +48,7 @@
|
|
));
|
|
}
|
|
let files: Vec<&std::ffi::OsStr> = paths.iter().filter_map(|e| e.file_name()).collect();
|
|
+
|
|
let options = get_options(paths[0].as_path());
|
|
|
|
if !options.is_empty() {
|
|
@@ -59,6 +60,10 @@
|
|
backend.terminal_restore()?;
|
|
res?;
|
|
}
|
|
+ } else if config.xdg_open {
|
|
+ backend.terminal_drop();
|
|
+ open::that(paths[0].as_path())?;
|
|
+ backend.terminal_restore()?;
|
|
} else {
|
|
open_with_helper(context, backend, options, files)?;
|
|
}
|
|
@@ -133,7 +138,10 @@
|
|
}
|
|
}
|
|
|
|
-pub fn open_with(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
|
|
+pub fn open_with_interactive(
|
|
+ context: &mut AppContext,
|
|
+ backend: &mut TuiBackend,
|
|
+) -> JoshutoResult<()> {
|
|
let paths = context
|
|
.tab_context_ref()
|
|
.curr_tab_ref()
|
|
@@ -152,3 +160,43 @@
|
|
open_with_helper(context, backend, options, files)?;
|
|
Ok(())
|
|
}
|
|
+
|
|
+pub fn open_with_index(
|
|
+ context: &mut AppContext,
|
|
+ backend: &mut TuiBackend,
|
|
+ index: usize,
|
|
+) -> JoshutoResult<()> {
|
|
+ let paths = context
|
|
+ .tab_context_ref()
|
|
+ .curr_tab_ref()
|
|
+ .curr_list_ref()
|
|
+ .map_or(vec![], |s| s.get_selected_paths());
|
|
+
|
|
+ if paths.is_empty() {
|
|
+ return Err(JoshutoError::new(
|
|
+ JoshutoErrorKind::Io(io::ErrorKind::NotFound),
|
|
+ String::from("No files selected"),
|
|
+ ));
|
|
+ }
|
|
+ let files: Vec<&std::ffi::OsStr> = paths.iter().filter_map(|e| e.file_name()).collect();
|
|
+ let options = get_options(paths[0].as_path());
|
|
+
|
|
+ if index >= options.len() {
|
|
+ return Err(JoshutoError::new(
|
|
+ JoshutoErrorKind::Io(std::io::ErrorKind::InvalidData),
|
|
+ "option does not exist".to_string(),
|
|
+ ));
|
|
+ }
|
|
+
|
|
+ let mimetype_entry = &options[index];
|
|
+ if mimetype_entry.get_fork() {
|
|
+ mimetype_entry.execute_with(files.as_slice())?;
|
|
+ Ok(())
|
|
+ } else {
|
|
+ backend.terminal_drop();
|
|
+ let res = mimetype_entry.execute_with(files.as_slice());
|
|
+ backend.terminal_restore()?;
|
|
+ res?;
|
|
+ Ok(())
|
|
+ }
|
|
+}
|
|
diff -ur a/src/commands/parent_directory.rs b/src/commands/parent_directory.rs
|
|
--- a/src/commands/parent_directory.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/parent_directory.rs 2021-08-07 11:25:14.702140722 +0300
|
|
@@ -1,6 +1,5 @@
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
-use crate::util::load_child::LoadChild;
|
|
|
|
use super::reload;
|
|
|
|
@@ -24,6 +23,5 @@
|
|
pub fn parent_directory(context: &mut AppContext) -> JoshutoResult<()> {
|
|
parent_directory_helper(context)?;
|
|
reload::soft_reload(context.tab_context_ref().index, context)?;
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
diff -ur a/src/commands/reload.rs b/src/commands/reload.rs
|
|
--- a/src/commands/reload.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/reload.rs 2021-08-07 11:25:14.705474074 +0300
|
|
@@ -1,6 +1,5 @@
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
-use crate::util::load_child::LoadChild;
|
|
|
|
pub fn soft_reload(index: usize, context: &mut AppContext) -> std::io::Result<()> {
|
|
let options = context.config_ref().display_options_ref().clone();
|
|
@@ -42,6 +41,5 @@
|
|
|
|
pub fn reload_dirlist(context: &mut AppContext) -> JoshutoResult<()> {
|
|
reload(context, context.tab_context_ref().index)?;
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
diff -ur a/src/commands/rename_file.rs b/src/commands/rename_file.rs
|
|
--- a/src/commands/rename_file.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/rename_file.rs 2021-08-07 11:25:14.705474074 +0300
|
|
@@ -3,7 +3,6 @@
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
use crate::ui::TuiBackend;
|
|
-use crate::util::load_child::LoadChild;
|
|
|
|
use super::command_line;
|
|
|
|
@@ -31,12 +30,11 @@
|
|
.curr_tab_ref()
|
|
.curr_list_ref()
|
|
.and_then(|s| s.curr_entry_ref())
|
|
- .and_then(|s| Some(s.file_path().to_path_buf()));
|
|
+ .map(|s| s.file_path().to_path_buf());
|
|
|
|
if let Some(path) = path {
|
|
_rename_file(context, path.as_path(), dest)?;
|
|
}
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
|
|
Только в b/src/commands: search_skim.rs
|
|
diff -ur a/src/commands/set_mode.rs b/src/commands/set_mode.rs
|
|
--- a/src/commands/set_mode.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/set_mode.rs 2021-08-07 11:25:14.705474074 +0300
|
|
@@ -1,3 +1,5 @@
|
|
+use std::fs;
|
|
+
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
use crate::ui::views::TuiTextField;
|
|
@@ -9,6 +11,7 @@
|
|
#[derive(Clone, Debug)]
|
|
pub struct SetMode;
|
|
|
|
+#[cfg(unix)]
|
|
const LIBC_PERMISSION_VALS: [(libc::mode_t, char); 9] = [
|
|
(libc::S_IRUSR, 'r'),
|
|
(libc::S_IWUSR, 'w'),
|
|
@@ -23,7 +26,7 @@
|
|
|
|
pub fn str_to_mode(s: &str) -> u32 {
|
|
let mut mode: u32 = 0;
|
|
- for (i, ch) in s.chars().enumerate() {
|
|
+ for (i, ch) in s.chars().enumerate().take(LIBC_PERMISSION_VALS.len()) {
|
|
if ch == LIBC_PERMISSION_VALS[i].1 {
|
|
let val: u32 = LIBC_PERMISSION_VALS[i].0 as u32;
|
|
mode |= val;
|
|
@@ -33,6 +36,7 @@
|
|
}
|
|
|
|
pub fn set_mode(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
|
|
+ #[cfg(unix)]
|
|
use std::os::unix::fs::PermissionsExt;
|
|
|
|
const PREFIX: &str = "set_mode ";
|
|
@@ -44,9 +48,10 @@
|
|
|
|
let user_input = match entry {
|
|
Some(entry) => {
|
|
- context.flush_event();
|
|
let mode = entry.metadata.permissions_ref().mode();
|
|
let mode_string = unix::mode_to_string(mode);
|
|
+
|
|
+ context.flush_event();
|
|
TuiTextField::default()
|
|
.prompt(":")
|
|
.prefix(PREFIX)
|
|
@@ -58,19 +63,28 @@
|
|
|
|
if let Some(s) = user_input {
|
|
if let Some(stripped) = s.strip_prefix(PREFIX) {
|
|
- let s = stripped;
|
|
- let mode = str_to_mode(s);
|
|
-
|
|
- let entry = context
|
|
- .tab_context_mut()
|
|
- .curr_tab_mut()
|
|
- .curr_list_mut()
|
|
- .and_then(|x| x.curr_entry_mut())
|
|
- .unwrap();
|
|
-
|
|
- unix::set_mode(entry.file_path(), mode);
|
|
- entry.metadata.permissions_mut().set_mode(mode);
|
|
- cursor_move::down(context, 1)?;
|
|
+ let mode = str_to_mode(stripped);
|
|
+ if let Some(curr_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() {
|
|
+ if curr_list.any_selected() {
|
|
+ for entry in curr_list.iter_selected_mut() {
|
|
+ let mut permissions = entry.metadata.permissions_ref().clone();
|
|
+ let file_mode = (permissions.mode() >> 12) << 12 | mode;
|
|
+ permissions.set_mode(file_mode);
|
|
+
|
|
+ fs::set_permissions(entry.file_path(), permissions)?;
|
|
+ entry.metadata.permissions_mut().set_mode(file_mode);
|
|
+ }
|
|
+ } else if let Some(entry) = curr_list.curr_entry_mut() {
|
|
+ let mut permissions = entry.metadata.permissions_ref().clone();
|
|
+ let file_mode = (permissions.mode() >> 12) << 12 | mode;
|
|
+ permissions.set_mode(file_mode);
|
|
+
|
|
+ fs::set_permissions(entry.file_path(), permissions)?;
|
|
+ entry.metadata.permissions_mut().set_mode(file_mode);
|
|
+
|
|
+ cursor_move::down(context, 1)?;
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
Ok(())
|
|
Только в a/src/commands: shell.rs
|
|
diff -ur a/src/commands/sort.rs b/src/commands/sort.rs
|
|
--- a/src/commands/sort.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/sort.rs 2021-08-07 11:25:14.705474074 +0300
|
|
@@ -1,22 +1,19 @@
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
use crate::history::DirectoryHistory;
|
|
-
|
|
-use crate::util::load_child::LoadChild;
|
|
use crate::util::sort::SortType;
|
|
|
|
use super::reload;
|
|
|
|
pub fn set_sort(context: &mut AppContext, method: SortType) -> JoshutoResult<()> {
|
|
- context.config_mut().sort_options_mut().sort_method = method;
|
|
-
|
|
+ context
|
|
+ .config_mut()
|
|
+ .sort_options_mut()
|
|
+ .set_sort_method(method);
|
|
for tab in context.tab_context_mut().iter_mut() {
|
|
tab.history_mut().depreciate_all_entries();
|
|
}
|
|
-
|
|
- reload::soft_reload(context.tab_context_ref().index, context)?;
|
|
- LoadChild::load_child(context)?;
|
|
- Ok(())
|
|
+ refresh(context)
|
|
}
|
|
|
|
pub fn toggle_reverse(context: &mut AppContext) -> JoshutoResult<()> {
|
|
@@ -26,7 +23,10 @@
|
|
for tab in context.tab_context_mut().iter_mut() {
|
|
tab.history_mut().depreciate_all_entries();
|
|
}
|
|
+ refresh(context)
|
|
+}
|
|
+
|
|
+fn refresh(context: &mut AppContext) -> JoshutoResult<()> {
|
|
reload::soft_reload(context.tab_context_ref().index, context)?;
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
Только в b/src/commands: sub_process.rs
|
|
diff -ur a/src/commands/tab_ops.rs b/src/commands/tab_ops.rs
|
|
--- a/src/commands/tab_ops.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/commands/tab_ops.rs 2021-08-07 11:25:14.705474074 +0300
|
|
@@ -3,8 +3,7 @@
|
|
use crate::context::AppContext;
|
|
use crate::error::JoshutoResult;
|
|
use crate::history::DirectoryHistory;
|
|
-use crate::tab::JoshutoTab;
|
|
-use crate::util::load_child::LoadChild;
|
|
+use crate::tab::{JoshutoTab, TabHomePage};
|
|
|
|
use crate::HOME_DIR;
|
|
|
|
@@ -51,19 +50,25 @@
|
|
_tab_switch(new_index, context)
|
|
}
|
|
|
|
+pub fn new_tab_home_path(context: &AppContext) -> path::PathBuf {
|
|
+ match context.config_ref().tab_options_ref().home_page() {
|
|
+ TabHomePage::Home => match HOME_DIR.as_ref() {
|
|
+ Some(s) => s.clone(),
|
|
+ None => path::PathBuf::from("/"),
|
|
+ },
|
|
+ TabHomePage::Inherit => context.tab_context_ref().curr_tab_ref().cwd().to_path_buf(),
|
|
+ TabHomePage::Root => path::PathBuf::from("/"),
|
|
+ }
|
|
+}
|
|
+
|
|
pub fn new_tab(context: &mut AppContext) -> JoshutoResult<()> {
|
|
- /* start the new tab in $HOME or root */
|
|
- let curr_path = match HOME_DIR.as_ref() {
|
|
- Some(s) => s.clone(),
|
|
- None => path::PathBuf::from("/"),
|
|
- };
|
|
+ let new_tab_path = new_tab_home_path(context);
|
|
|
|
- let tab = JoshutoTab::new(curr_path, context.config_ref().display_options_ref())?;
|
|
+ let tab = JoshutoTab::new(new_tab_path, context.config_ref().display_options_ref())?;
|
|
context.tab_context_mut().push_tab(tab);
|
|
let new_index = context.tab_context_ref().len() - 1;
|
|
context.tab_context_mut().index = new_index;
|
|
_tab_switch(new_index, context)?;
|
|
- LoadChild::load_child(context)?;
|
|
Ok(())
|
|
}
|
|
|
|
Только в b/src/commands: touch_file.rs
|
|
diff -ur a/src/config/default/config.rs b/src/config/default/config.rs
|
|
--- a/src/config/default/config.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/default/config.rs 2021-08-07 11:25:14.705474074 +0300
|
|
@@ -1,6 +1,9 @@
|
|
use serde_derive::Deserialize;
|
|
|
|
+use super::preview::{PreviewOption, PreviewRawOption};
|
|
+use super::tab::{TabOption, TabRawOption};
|
|
use super::DisplayRawOption;
|
|
+
|
|
use crate::config::{parse_to_config_file, ConfigStructure, Flattenable};
|
|
use crate::util::display::DisplayOption;
|
|
use crate::util::sort;
|
|
@@ -11,9 +14,6 @@
|
|
const fn default_scroll_offset() -> usize {
|
|
6
|
|
}
|
|
-const fn default_max_preview_size() -> u64 {
|
|
- 2 * 1024 * 1024 // 2 MB
|
|
-}
|
|
|
|
#[derive(Clone, Debug, Deserialize)]
|
|
pub struct RawAppConfig {
|
|
@@ -23,31 +23,35 @@
|
|
use_trash: bool,
|
|
#[serde(default)]
|
|
xdg_open: bool,
|
|
- #[serde(default = "default_max_preview_size")]
|
|
- max_preview_size: u64,
|
|
#[serde(default, rename = "display")]
|
|
display_options: DisplayRawOption,
|
|
+ #[serde(default, rename = "preview")]
|
|
+ preview_options: PreviewRawOption,
|
|
+ #[serde(default, rename = "tab")]
|
|
+ tab_options: TabRawOption,
|
|
}
|
|
|
|
impl Flattenable<AppConfig> for RawAppConfig {
|
|
fn flatten(self) -> AppConfig {
|
|
AppConfig {
|
|
- max_preview_size: self.max_preview_size,
|
|
scroll_offset: self.scroll_offset,
|
|
use_trash: self.use_trash,
|
|
xdg_open: self.xdg_open,
|
|
_display_options: self.display_options.flatten(),
|
|
+ _preview_options: self.preview_options.flatten(),
|
|
+ _tab_options: self.tab_options.flatten(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct AppConfig {
|
|
- pub max_preview_size: u64,
|
|
pub scroll_offset: usize,
|
|
pub use_trash: bool,
|
|
pub xdg_open: bool,
|
|
_display_options: DisplayOption,
|
|
+ _preview_options: PreviewOption,
|
|
+ _tab_options: TabOption,
|
|
}
|
|
|
|
impl AppConfig {
|
|
@@ -58,12 +62,26 @@
|
|
&mut self._display_options
|
|
}
|
|
|
|
+ pub fn preview_options_ref(&self) -> &PreviewOption {
|
|
+ &self._preview_options
|
|
+ }
|
|
+ pub fn preview_options_mut(&mut self) -> &mut PreviewOption {
|
|
+ &mut self._preview_options
|
|
+ }
|
|
+
|
|
pub fn sort_options_ref(&self) -> &sort::SortOption {
|
|
self.display_options_ref().sort_options_ref()
|
|
}
|
|
pub fn sort_options_mut(&mut self) -> &mut sort::SortOption {
|
|
self.display_options_mut().sort_options_mut()
|
|
}
|
|
+
|
|
+ pub fn tab_options_ref(&self) -> &TabOption {
|
|
+ &self._tab_options
|
|
+ }
|
|
+ pub fn tab_options_mut(&mut self) -> &mut TabOption {
|
|
+ &mut self._tab_options
|
|
+ }
|
|
}
|
|
|
|
impl ConfigStructure for AppConfig {
|
|
@@ -75,11 +93,12 @@
|
|
impl std::default::Default for AppConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
- max_preview_size: default_max_preview_size(),
|
|
scroll_offset: default_scroll_offset(),
|
|
use_trash: true,
|
|
xdg_open: false,
|
|
_display_options: DisplayOption::default(),
|
|
+ _preview_options: PreviewOption::default(),
|
|
+ _tab_options: TabOption::default(),
|
|
}
|
|
}
|
|
}
|
|
diff -ur a/src/config/default/mod.rs b/src/config/default/mod.rs
|
|
--- a/src/config/default/mod.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/default/mod.rs 2021-08-07 11:25:14.705474074 +0300
|
|
@@ -1,7 +1,11 @@
|
|
pub mod config;
|
|
pub mod display;
|
|
+pub mod preview;
|
|
pub mod sort;
|
|
+pub mod tab;
|
|
|
|
pub use self::config::AppConfig;
|
|
pub use self::display::DisplayRawOption;
|
|
+pub use self::preview::{PreviewOption, PreviewRawOption};
|
|
pub use self::sort::SortRawOption;
|
|
+pub use self::tab::{TabOption, TabRawOption};
|
|
Только в b/src/config/default: preview.rs
|
|
diff -ur a/src/config/default/sort.rs b/src/config/default/sort.rs
|
|
--- a/src/config/default/sort.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/default/sort.rs 2021-08-07 11:25:14.705474074 +0300
|
|
@@ -24,11 +24,15 @@
|
|
Some(s) => sort::SortType::parse(s).unwrap_or(sort::SortType::Natural),
|
|
None => sort::SortType::Natural,
|
|
};
|
|
+
|
|
+ let mut sort_methods = sort::SortTypes::default();
|
|
+ sort_methods.reorganize(sort_method);
|
|
+
|
|
sort::SortOption {
|
|
directories_first: self.directories_first,
|
|
case_sensitive: self.case_sensitive,
|
|
reverse: self.reverse,
|
|
- sort_method,
|
|
+ sort_methods,
|
|
}
|
|
}
|
|
}
|
|
Только в b/src/config/default: tab.rs
|
|
diff -ur a/src/config/keymap/keymapping.rs b/src/config/keymap/keymapping.rs
|
|
--- a/src/config/keymap/keymapping.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/keymap/keymapping.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -1,6 +1,7 @@
|
|
use serde_derive::Deserialize;
|
|
|
|
use std::collections::{hash_map::Entry, HashMap};
|
|
+use std::str::FromStr;
|
|
|
|
#[cfg(feature = "mouse")]
|
|
use termion::event::MouseEvent;
|
|
@@ -27,7 +28,7 @@
|
|
fn flatten(self) -> AppKeyMapping {
|
|
let mut keymaps = AppKeyMapping::new();
|
|
for m in self.mapcommand {
|
|
- match KeyCommand::parse_command(m.command.as_str()) {
|
|
+ match KeyCommand::from_str(m.command.as_str()) {
|
|
Ok(command) => {
|
|
let events: Vec<Event> = m
|
|
.keys
|
|
@@ -167,7 +168,7 @@
|
|
let keys = [Event::Key(Key::BackTab)];
|
|
insert_keycommand(&mut m, cmd, &keys)?;
|
|
|
|
- let cmd = KeyCommand::OpenFileWith;
|
|
+ let cmd = KeyCommand::OpenFileWith(None);
|
|
let keys = [Event::Key(Key::Char('r'))];
|
|
insert_keycommand(&mut m, cmd, &keys)?;
|
|
|
|
@@ -223,6 +224,10 @@
|
|
let keys = [Event::Key(Key::Char(';'))];
|
|
insert_keycommand(&mut m, cmd, &keys)?;
|
|
|
|
+ let cmd = KeyCommand::CommandLine("".to_string(), "".to_string());
|
|
+ let keys = [Event::Key(Key::Char(':'))];
|
|
+ insert_keycommand(&mut m, cmd, &keys)?;
|
|
+
|
|
let cmd = KeyCommand::CommandLine("mkdir ".to_string(), "".to_string());
|
|
let keys = [Event::Key(Key::Char('m')), Event::Key(Key::Char('k'))];
|
|
insert_keycommand(&mut m, cmd, &keys)?;
|
|
diff -ur a/src/config/keymap/keyparse.rs b/src/config/keymap/keyparse.rs
|
|
--- a/src/config/keymap/keyparse.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/keymap/keyparse.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -18,10 +18,10 @@
|
|
let key = match s {
|
|
"backspace" => Some(Key::Backspace),
|
|
"backtab" => Some(Key::BackTab),
|
|
- "left" => Some(Key::Left),
|
|
- "right" => Some(Key::Right),
|
|
- "up" => Some(Key::Up),
|
|
- "down" => Some(Key::Down),
|
|
+ "arrow_left" => Some(Key::Left),
|
|
+ "arrow_right" => Some(Key::Right),
|
|
+ "arrow_up" => Some(Key::Up),
|
|
+ "arrow_down" => Some(Key::Down),
|
|
"home" => Some(Key::Home),
|
|
"end" => Some(Key::End),
|
|
"page_up" => Some(Key::PageUp),
|
|
diff -ur a/src/config/mimetype/entry.rs b/src/config/mimetype/entry.rs
|
|
--- a/src/config/mimetype/entry.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/mimetype/entry.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -3,7 +3,32 @@
|
|
use std::io::Read;
|
|
use std::process;
|
|
|
|
-#[derive(Debug, Deserialize)]
|
|
+#[derive(Clone, Debug, Deserialize)]
|
|
+pub struct AppList {
|
|
+ #[serde(default, rename = "inherit")]
|
|
+ _inherit: String,
|
|
+ #[serde(default, rename = "app_list")]
|
|
+ _app_list: Vec<AppMimetypeEntry>,
|
|
+}
|
|
+
|
|
+impl AppList {
|
|
+ pub fn new(_inherit: String, _app_list: Vec<AppMimetypeEntry>) -> Self {
|
|
+ Self {
|
|
+ _inherit,
|
|
+ _app_list,
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pub fn parent(&self) -> &str {
|
|
+ self._inherit.as_str()
|
|
+ }
|
|
+
|
|
+ pub fn app_list(&self) -> &[AppMimetypeEntry] {
|
|
+ &self._app_list.as_slice()
|
|
+ }
|
|
+}
|
|
+
|
|
+#[derive(Clone, Debug, Deserialize)]
|
|
pub struct AppMimetypeEntry {
|
|
#[serde(rename = "command")]
|
|
_command: String,
|
|
diff -ur a/src/config/mimetype/mod.rs b/src/config/mimetype/mod.rs
|
|
--- a/src/config/mimetype/mod.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/mimetype/mod.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -1,5 +1,5 @@
|
|
mod entry;
|
|
mod registry;
|
|
|
|
-pub use self::entry::AppMimetypeEntry;
|
|
+pub use self::entry::{AppList, AppMimetypeEntry};
|
|
pub use self::registry::AppMimetypeRegistry;
|
|
diff -ur a/src/config/mimetype/registry.rs b/src/config/mimetype/registry.rs
|
|
--- a/src/config/mimetype/registry.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/mimetype/registry.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -1,39 +1,69 @@
|
|
use serde_derive::Deserialize;
|
|
use std::collections::HashMap;
|
|
|
|
-use super::AppMimetypeEntry;
|
|
-use crate::config::{parse_config_file, ConfigStructure};
|
|
+use super::{AppList, AppMimetypeEntry};
|
|
+use crate::config::{parse_to_config_file, ConfigStructure, Flattenable};
|
|
|
|
-pub type MimetypeRegistry = HashMap<String, Vec<AppMimetypeEntry>>;
|
|
+pub type MimetypeRegistry = HashMap<String, AppList>;
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
+pub struct RawAppMimetypeRegistry {
|
|
+ #[serde(default, rename = "class")]
|
|
+ pub _class: HashMap<String, Vec<AppMimetypeEntry>>,
|
|
+ #[serde(default, rename = "extension")]
|
|
+ pub _extension: MimetypeRegistry,
|
|
+}
|
|
+
|
|
+impl Flattenable<AppMimetypeRegistry> for RawAppMimetypeRegistry {
|
|
+ fn flatten(self) -> AppMimetypeRegistry {
|
|
+ let mut registry = MimetypeRegistry::new();
|
|
+
|
|
+ for (ext, app_list) in self._extension {
|
|
+ let class = app_list.parent();
|
|
+ let mut combined_app_list: Vec<AppMimetypeEntry> = self
|
|
+ ._class
|
|
+ .get(class)
|
|
+ .map(|v| (*v).clone())
|
|
+ .unwrap_or_default();
|
|
+ combined_app_list.extend_from_slice(app_list.app_list());
|
|
+ let combined_app_list = AppList::new(class.to_string(), combined_app_list);
|
|
+ registry.insert(ext, combined_app_list);
|
|
+ }
|
|
+
|
|
+ AppMimetypeRegistry {
|
|
+ _extension: registry,
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+#[derive(Debug)]
|
|
pub struct AppMimetypeRegistry {
|
|
- #[serde(default, skip)]
|
|
- empty_vec: Vec<AppMimetypeEntry>,
|
|
- #[serde(default)]
|
|
- pub extension: MimetypeRegistry,
|
|
+ // pub _class: HashMap<String, Vec<AppMimetypeEntry>>,
|
|
+ pub _extension: MimetypeRegistry,
|
|
}
|
|
|
|
+pub const EMPTY_ARR: [AppMimetypeEntry; 0] = [];
|
|
+
|
|
impl AppMimetypeRegistry {
|
|
- pub fn get_entries_for_ext(&self, extension: &str) -> &[AppMimetypeEntry] {
|
|
- match self.extension.get(extension) {
|
|
- Some(s) => s,
|
|
- None => &self.empty_vec,
|
|
+ pub fn app_list_for_ext(&self, extension: &str) -> &[AppMimetypeEntry] {
|
|
+ match self._extension.get(extension) {
|
|
+ Some(s) => s.app_list(),
|
|
+ None => &EMPTY_ARR,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ConfigStructure for AppMimetypeRegistry {
|
|
fn get_config(file_name: &str) -> Self {
|
|
- parse_config_file::<AppMimetypeRegistry>(file_name).unwrap_or_else(Self::default)
|
|
+ parse_to_config_file::<RawAppMimetypeRegistry, AppMimetypeRegistry>(file_name)
|
|
+ .unwrap_or_else(Self::default)
|
|
}
|
|
}
|
|
|
|
impl std::default::Default for AppMimetypeRegistry {
|
|
fn default() -> Self {
|
|
Self {
|
|
- empty_vec: Vec::new(),
|
|
- extension: MimetypeRegistry::new(),
|
|
+ _extension: MimetypeRegistry::new(),
|
|
}
|
|
}
|
|
}
|
|
diff -ur a/src/config/mod.rs b/src/config/mod.rs
|
|
--- a/src/config/mod.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/mod.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -61,26 +61,3 @@
|
|
};
|
|
Some(config.flatten())
|
|
}
|
|
-
|
|
-// parses a config file into its appropriate format
|
|
-fn parse_config_file<T>(filename: &str) -> Option<T>
|
|
-where
|
|
- T: DeserializeOwned,
|
|
-{
|
|
- let file_path = search_directories(filename, &CONFIG_HIERARCHY)?;
|
|
- let file_contents = match fs::read_to_string(&file_path) {
|
|
- Ok(content) => content,
|
|
- Err(e) => {
|
|
- eprintln!("Error reading {} file: {}", filename, e);
|
|
- return None;
|
|
- }
|
|
- };
|
|
-
|
|
- match toml::from_str::<T>(&file_contents) {
|
|
- Ok(config) => Some(config),
|
|
- Err(e) => {
|
|
- eprintln!("Error parsing {} file: {}", filename, e);
|
|
- None
|
|
- }
|
|
- }
|
|
-}
|
|
diff -ur a/src/config/theme/style.rs b/src/config/theme/style.rs
|
|
--- a/src/config/theme/style.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/config/theme/style.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -1,9 +1,11 @@
|
|
+use colors_transform::{Color, Rgb};
|
|
+
|
|
use serde_derive::Deserialize;
|
|
|
|
-use tui::style::{Color, Modifier};
|
|
+use tui::style;
|
|
|
|
-const fn default_color() -> Color {
|
|
- Color::Reset
|
|
+const fn default_color() -> style::Color {
|
|
+ style::Color::Reset
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize)]
|
|
@@ -25,39 +27,49 @@
|
|
let bg = Self::str_to_color(self.bg.as_str());
|
|
let fg = Self::str_to_color(self.fg.as_str());
|
|
|
|
- let mut modifier = Modifier::empty();
|
|
+ let mut modifier = style::Modifier::empty();
|
|
if self.bold {
|
|
- modifier.insert(Modifier::BOLD);
|
|
+ modifier.insert(style::Modifier::BOLD);
|
|
}
|
|
if self.underline {
|
|
- modifier.insert(Modifier::UNDERLINED);
|
|
+ modifier.insert(style::Modifier::UNDERLINED);
|
|
}
|
|
if self.invert {
|
|
- modifier.insert(Modifier::REVERSED);
|
|
+ modifier.insert(style::Modifier::REVERSED);
|
|
}
|
|
|
|
AppStyle::default().set_fg(fg).set_bg(bg).insert(modifier)
|
|
}
|
|
|
|
- pub fn str_to_color(s: &str) -> Color {
|
|
+ pub fn str_to_color(s: &str) -> style::Color {
|
|
match s {
|
|
- "black" => Color::Black,
|
|
- "red" => Color::Red,
|
|
- "blue" => Color::Blue,
|
|
- "green" => Color::Green,
|
|
- "yellow" => Color::Yellow,
|
|
- "magenta" => Color::Magenta,
|
|
- "cyan" => Color::Cyan,
|
|
- "white" => Color::White,
|
|
- "gray" => Color::Gray,
|
|
- "dark_gray" => Color::DarkGray,
|
|
- "light_red" => Color::LightRed,
|
|
- "light_green" => Color::LightGreen,
|
|
- "light_yellow" => Color::LightYellow,
|
|
- "light_blue" => Color::LightBlue,
|
|
- "light_magenta" => Color::LightMagenta,
|
|
- "light_cyan" => Color::LightCyan,
|
|
- _ => Color::Reset,
|
|
+ "black" => style::Color::Black,
|
|
+ "red" => style::Color::Red,
|
|
+ "green" => style::Color::Green,
|
|
+ "yellow" => style::Color::Yellow,
|
|
+ "blue" => style::Color::Blue,
|
|
+ "magenta" => style::Color::Magenta,
|
|
+ "cyan" => style::Color::Cyan,
|
|
+ "gray" => style::Color::Gray,
|
|
+ "dark_gray" => style::Color::DarkGray,
|
|
+ "light_red" => style::Color::LightRed,
|
|
+ "light_green" => style::Color::LightGreen,
|
|
+ "light_yellow" => style::Color::LightYellow,
|
|
+ "light_blue" => style::Color::LightBlue,
|
|
+ "light_magenta" => style::Color::LightMagenta,
|
|
+ "light_cyan" => style::Color::LightCyan,
|
|
+ "white" => style::Color::White,
|
|
+ "reset" => style::Color::Reset,
|
|
+ s if s.is_empty() => style::Color::Reset,
|
|
+ s => match s.parse::<Rgb>() {
|
|
+ Ok(rgb) => {
|
|
+ let r = rgb.get_red() as u8;
|
|
+ let g = rgb.get_green() as u8;
|
|
+ let b = rgb.get_blue() as u8;
|
|
+ style::Color::Rgb(r, g, b)
|
|
+ }
|
|
+ Err(_) => style::Color::Reset,
|
|
+ },
|
|
}
|
|
}
|
|
}
|
|
@@ -76,22 +88,22 @@
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct AppStyle {
|
|
- pub fg: Color,
|
|
- pub bg: Color,
|
|
- pub modifier: Modifier,
|
|
+ pub fg: style::Color,
|
|
+ pub bg: style::Color,
|
|
+ pub modifier: style::Modifier,
|
|
}
|
|
|
|
impl AppStyle {
|
|
- pub fn set_bg(mut self, bg: Color) -> Self {
|
|
+ pub fn set_bg(mut self, bg: style::Color) -> Self {
|
|
self.bg = bg;
|
|
self
|
|
}
|
|
- pub fn set_fg(mut self, fg: Color) -> Self {
|
|
+ pub fn set_fg(mut self, fg: style::Color) -> Self {
|
|
self.fg = fg;
|
|
self
|
|
}
|
|
|
|
- pub fn insert(mut self, modifier: Modifier) -> Self {
|
|
+ pub fn insert(mut self, modifier: style::Modifier) -> Self {
|
|
self.modifier.insert(modifier);
|
|
self
|
|
}
|
|
@@ -102,7 +114,7 @@
|
|
Self {
|
|
fg: default_color(),
|
|
bg: default_color(),
|
|
- modifier: Modifier::empty(),
|
|
+ modifier: style::Modifier::empty(),
|
|
}
|
|
}
|
|
}
|
|
diff -ur a/src/context/app_context.rs b/src/context/app_context.rs
|
|
--- a/src/context/app_context.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/context/app_context.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -3,7 +3,7 @@
|
|
|
|
use crate::config;
|
|
use crate::context::{LocalStateContext, TabContext, WorkerContext};
|
|
-use crate::util::event::{AppEvent, Events};
|
|
+use crate::event::{AppEvent, Events};
|
|
use crate::util::search::SearchPattern;
|
|
|
|
pub struct AppContext {
|
|
@@ -11,7 +11,7 @@
|
|
// app config
|
|
config: config::AppConfig,
|
|
// event loop querying
|
|
- events: Events,
|
|
+ pub events: Events,
|
|
// context related to tabs
|
|
tab_context: TabContext,
|
|
// context related to local file state
|
|
diff -ur a/src/context/worker_context.rs b/src/context/worker_context.rs
|
|
--- a/src/context/worker_context.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/context/worker_context.rs 2021-08-07 11:25:14.708807426 +0300
|
|
@@ -3,8 +3,8 @@
|
|
use std::sync::mpsc;
|
|
use std::thread;
|
|
|
|
+use crate::event::AppEvent;
|
|
use crate::io::{IoWorkerObserver, IoWorkerProgress, IoWorkerThread};
|
|
-use crate::util::event::AppEvent;
|
|
|
|
pub struct WorkerContext {
|
|
// queue of IO workers
|
|
Только в b/src: event.rs
|
|
diff -ur a/src/fs/dirlist.rs b/src/fs/dirlist.rs
|
|
--- a/src/fs/dirlist.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/fs/dirlist.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -108,13 +108,21 @@
|
|
Ok(())
|
|
}
|
|
|
|
- pub fn selected_entries(&self) -> impl Iterator<Item = &JoshutoDirEntry> {
|
|
+ pub fn any_selected(&self) -> bool {
|
|
+ self.contents.iter().any(|e| e.is_selected())
|
|
+ }
|
|
+
|
|
+ pub fn iter_selected(&self) -> impl Iterator<Item = &JoshutoDirEntry> {
|
|
self.contents.iter().filter(|entry| entry.is_selected())
|
|
}
|
|
|
|
+ pub fn iter_selected_mut(&mut self) -> impl Iterator<Item = &mut JoshutoDirEntry> {
|
|
+ self.contents.iter_mut().filter(|entry| entry.is_selected())
|
|
+ }
|
|
+
|
|
pub fn get_selected_paths(&self) -> Vec<path::PathBuf> {
|
|
let vec: Vec<path::PathBuf> = self
|
|
- .selected_entries()
|
|
+ .iter_selected()
|
|
.map(|e| e.file_path().to_path_buf())
|
|
.collect();
|
|
if !vec.is_empty() {
|
|
@@ -135,6 +143,17 @@
|
|
self.get_curr_mut_(self.index?)
|
|
}
|
|
|
|
+ /// For a given number of entries, visible in a UI, this method returns the index of the entry
|
|
+ /// with which the UI should start to list the entries.
|
|
+ ///
|
|
+ /// This method assures that the cursor is always in the viewport of the UI.
|
|
+ pub fn first_index_for_viewport(&self, viewport_height: usize) -> usize {
|
|
+ match self.index {
|
|
+ Some(index) => index / viewport_height as usize * viewport_height as usize,
|
|
+ None => 0,
|
|
+ }
|
|
+ }
|
|
+
|
|
fn get_curr_mut_(&mut self, index: usize) -> Option<&mut JoshutoDirEntry> {
|
|
if index < self.contents.len() {
|
|
Some(&mut self.contents[index])
|
|
diff -ur a/src/fs/entry.rs b/src/fs/entry.rs
|
|
--- a/src/fs/entry.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/fs/entry.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -18,6 +18,7 @@
|
|
impl JoshutoDirEntry {
|
|
pub fn from(direntry: &fs::DirEntry, show_icons: bool) -> std::io::Result<Self> {
|
|
let path = direntry.path();
|
|
+
|
|
let metadata = JoshutoMetadata::from(&path)?;
|
|
let name = direntry
|
|
.file_name()
|
|
@@ -86,6 +87,14 @@
|
|
pub fn set_selected(&mut self, selected: bool) {
|
|
self.selected = selected;
|
|
}
|
|
+
|
|
+ pub fn get_ext(&self) -> &str {
|
|
+ let fname = self.file_name();
|
|
+ match fname.rfind('.') {
|
|
+ Some(pos) => &fname[pos..],
|
|
+ None => "",
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
impl std::fmt::Display for JoshutoDirEntry {
|
|
diff -ur a/src/fs/metadata.rs b/src/fs/metadata.rs
|
|
--- a/src/fs/metadata.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/fs/metadata.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -3,16 +3,23 @@
|
|
#[derive(Clone, Debug)]
|
|
pub enum FileType {
|
|
Directory,
|
|
- Symlink(String),
|
|
File,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
+pub enum LinkType {
|
|
+ Normal,
|
|
+ Symlink(String),
|
|
+}
|
|
+
|
|
+#[derive(Clone, Debug)]
|
|
pub struct JoshutoMetadata {
|
|
_len: u64,
|
|
+ _directory_size: Option<usize>,
|
|
_modified: time::SystemTime,
|
|
_permissions: fs::Permissions,
|
|
_file_type: FileType,
|
|
+ _link_type: LinkType,
|
|
#[cfg(unix)]
|
|
pub uid: u32,
|
|
#[cfg(unix)]
|
|
@@ -26,40 +33,46 @@
|
|
#[cfg(unix)]
|
|
use std::os::unix::fs::MetadataExt;
|
|
|
|
- let metadata = fs::symlink_metadata(path)?;
|
|
+ let symlink_metadata = fs::symlink_metadata(path)?;
|
|
+ let metadata = fs::metadata(path)?;
|
|
|
|
let _len = metadata.len();
|
|
let _modified = metadata.modified()?;
|
|
let _permissions = metadata.permissions();
|
|
- let file_type = metadata.file_type();
|
|
-
|
|
- let file_type = if file_type.is_dir() {
|
|
- FileType::Directory
|
|
- } else if file_type.is_symlink() {
|
|
- let mut link = "".to_string();
|
|
-
|
|
- if let Ok(path) = fs::read_link(path) {
|
|
- if let Some(s) = path.to_str() {
|
|
- link = s.to_string();
|
|
+ let (_file_type, _directory_size) = if metadata.file_type().is_dir() {
|
|
+ let _directory_size = fs::read_dir(path).map(|s| s.count()).ok();
|
|
+ (FileType::Directory, _directory_size)
|
|
+ } else {
|
|
+ (FileType::File, None)
|
|
+ };
|
|
+ let _link_type = match symlink_metadata.file_type().is_symlink() {
|
|
+ true => {
|
|
+ let mut link = "".to_string();
|
|
+
|
|
+ if let Ok(path) = fs::read_link(path) {
|
|
+ if let Some(s) = path.to_str() {
|
|
+ link = s.to_string();
|
|
+ }
|
|
}
|
|
+ LinkType::Symlink(link)
|
|
}
|
|
- FileType::Symlink(link)
|
|
- } else {
|
|
- FileType::File
|
|
+ false => LinkType::Normal,
|
|
};
|
|
|
|
#[cfg(unix)]
|
|
- let uid = metadata.uid();
|
|
+ let uid = symlink_metadata.uid();
|
|
#[cfg(unix)]
|
|
- let gid = metadata.gid();
|
|
+ let gid = symlink_metadata.gid();
|
|
#[cfg(unix)]
|
|
- let mode = metadata.mode();
|
|
+ let mode = symlink_metadata.mode();
|
|
|
|
Ok(Self {
|
|
_len,
|
|
+ _directory_size,
|
|
_modified,
|
|
_permissions,
|
|
- _file_type: file_type,
|
|
+ _file_type,
|
|
+ _link_type,
|
|
#[cfg(unix)]
|
|
uid,
|
|
#[cfg(unix)]
|
|
@@ -73,6 +86,10 @@
|
|
self._len
|
|
}
|
|
|
|
+ pub fn directory_size(&self) -> Option<usize> {
|
|
+ self._directory_size
|
|
+ }
|
|
+
|
|
pub fn modified(&self) -> time::SystemTime {
|
|
self._modified
|
|
}
|
|
@@ -88,4 +105,8 @@
|
|
pub fn file_type(&self) -> &FileType {
|
|
&self._file_type
|
|
}
|
|
+
|
|
+ pub fn link_type(&self) -> &LinkType {
|
|
+ &self._link_type
|
|
+ }
|
|
}
|
|
diff -ur a/src/fs/mod.rs b/src/fs/mod.rs
|
|
--- a/src/fs/mod.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/fs/mod.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -4,4 +4,4 @@
|
|
|
|
pub use self::dirlist::JoshutoDirList;
|
|
pub use self::entry::JoshutoDirEntry;
|
|
-pub use self::metadata::{FileType, JoshutoMetadata};
|
|
+pub use self::metadata::{FileType, JoshutoMetadata, LinkType};
|
|
diff -ur a/src/io/io_observer.rs b/src/io/io_observer.rs
|
|
--- a/src/io/io_observer.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/io/io_observer.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -34,18 +34,20 @@
|
|
match self.progress.as_ref() {
|
|
None => {}
|
|
Some(progress) => {
|
|
- let size_str = format::file_size_to_string(progress.bytes_processed());
|
|
let op_str = match progress.kind() {
|
|
FileOp::Cut => "Moving",
|
|
FileOp::Copy => "Copying",
|
|
};
|
|
+ let processed_size = format::file_size_to_string(progress.bytes_processed());
|
|
+ let total_size = format::file_size_to_string(progress.total_bytes());
|
|
|
|
let msg = format!(
|
|
- "{} ({}/{}) {} completed",
|
|
+ "{} ({}/{}) ({}/{}) completed",
|
|
op_str,
|
|
- progress.completed() + 1,
|
|
- progress.len(),
|
|
- size_str
|
|
+ progress.files_processed() + 1,
|
|
+ progress.total_files(),
|
|
+ processed_size,
|
|
+ total_size,
|
|
);
|
|
self.msg = msg;
|
|
}
|
|
diff -ur a/src/io/io_worker.rs b/src/io/io_worker.rs
|
|
--- a/src/io/io_worker.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/io/io_worker.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -12,21 +12,12 @@
|
|
Copy,
|
|
}
|
|
|
|
-#[derive(Clone, Debug)]
|
|
+#[derive(Clone, Copy, Debug, Default)]
|
|
pub struct IoWorkerOptions {
|
|
pub overwrite: bool,
|
|
pub skip_exist: bool,
|
|
}
|
|
|
|
-impl std::default::Default for IoWorkerOptions {
|
|
- fn default() -> Self {
|
|
- Self {
|
|
- overwrite: false,
|
|
- skip_exist: false,
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
impl std::fmt::Display for IoWorkerOptions {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(
|
|
@@ -40,18 +31,26 @@
|
|
#[derive(Clone, Debug)]
|
|
pub struct IoWorkerProgress {
|
|
_kind: FileOp,
|
|
- _completed: usize,
|
|
- _len: usize,
|
|
+ _files_processed: usize,
|
|
+ _total_files: usize,
|
|
_bytes_processed: u64,
|
|
+ _total_bytes: u64,
|
|
}
|
|
|
|
impl IoWorkerProgress {
|
|
- pub fn new(_kind: FileOp, _completed: usize, _len: usize, _bytes_processed: u64) -> Self {
|
|
+ pub fn new(
|
|
+ _kind: FileOp,
|
|
+ _files_processed: usize,
|
|
+ _total_files: usize,
|
|
+ _bytes_processed: u64,
|
|
+ _total_bytes: u64,
|
|
+ ) -> Self {
|
|
Self {
|
|
_kind,
|
|
- _completed,
|
|
- _len,
|
|
+ _files_processed,
|
|
+ _total_files,
|
|
_bytes_processed,
|
|
+ _total_bytes,
|
|
}
|
|
}
|
|
|
|
@@ -59,16 +58,16 @@
|
|
self._kind
|
|
}
|
|
|
|
- pub fn completed(&self) -> usize {
|
|
- self._completed
|
|
+ pub fn files_processed(&self) -> usize {
|
|
+ self._files_processed
|
|
}
|
|
|
|
- pub fn increment_completed(&mut self) {
|
|
- self._completed += 1;
|
|
+ pub fn set_files_processed(&mut self, files_processed: usize) {
|
|
+ self._files_processed = files_processed;
|
|
}
|
|
|
|
- pub fn len(&self) -> usize {
|
|
- self._len
|
|
+ pub fn total_files(&self) -> usize {
|
|
+ self._total_files
|
|
}
|
|
|
|
pub fn bytes_processed(&self) -> u64 {
|
|
@@ -78,6 +77,10 @@
|
|
pub fn set_bytes_processed(&mut self, _bytes_processed: u64) {
|
|
self._bytes_processed = _bytes_processed;
|
|
}
|
|
+
|
|
+ pub fn total_bytes(&self) -> u64 {
|
|
+ self._total_bytes
|
|
+ }
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
@@ -107,89 +110,92 @@
|
|
self._kind
|
|
}
|
|
|
|
- pub fn start(&self, tx: mpsc::Sender<IoWorkerProgress>) -> std::io::Result<IoWorkerProgress> {
|
|
+ pub fn start(&self, tx: mpsc::Sender<IoWorkerProgress>) -> io::Result<IoWorkerProgress> {
|
|
match self.kind() {
|
|
FileOp::Cut => self.paste_cut(tx),
|
|
FileOp::Copy => self.paste_copy(tx),
|
|
}
|
|
}
|
|
|
|
- fn query_number_of_items(&self) -> io::Result<usize> {
|
|
+ fn query_number_of_items(&self) -> io::Result<(usize, u64)> {
|
|
+ let mut total_bytes = 0;
|
|
+ let mut total_files = 0;
|
|
+
|
|
let mut dirs: VecDeque<path::PathBuf> = VecDeque::new();
|
|
for path in self.paths.iter() {
|
|
let metadata = path.symlink_metadata()?;
|
|
if metadata.is_dir() {
|
|
dirs.push_back(path.clone());
|
|
+ } else {
|
|
+ let metadata = path.symlink_metadata()?;
|
|
+ total_bytes += metadata.len();
|
|
+ total_files += 1;
|
|
}
|
|
}
|
|
|
|
- let mut total = self.paths.len() - dirs.len();
|
|
-
|
|
while let Some(dir) = dirs.pop_front() {
|
|
for entry in fs::read_dir(dir)? {
|
|
let path = entry?.path();
|
|
if path.is_dir() {
|
|
dirs.push_back(path);
|
|
} else {
|
|
- total += 1;
|
|
+ let metadata = path.symlink_metadata()?;
|
|
+ total_bytes += metadata.len();
|
|
+ total_files += 1;
|
|
}
|
|
}
|
|
}
|
|
- Ok(total)
|
|
+ Ok((total_files, total_bytes))
|
|
}
|
|
|
|
- fn paste_copy(&self, tx: mpsc::Sender<IoWorkerProgress>) -> std::io::Result<IoWorkerProgress> {
|
|
- let num_items = self.query_number_of_items()?;
|
|
- let mut progress = IoWorkerProgress::new(self.kind(), 0, num_items, 0);
|
|
+ fn paste_copy(&self, tx: mpsc::Sender<IoWorkerProgress>) -> io::Result<IoWorkerProgress> {
|
|
+ let (total_files, total_bytes) = self.query_number_of_items()?;
|
|
+ let mut progress = IoWorkerProgress::new(self.kind(), 0, total_files, 0, total_bytes);
|
|
for path in self.paths.iter() {
|
|
let _ = tx.send(progress.clone());
|
|
recursive_copy(
|
|
+ self.options,
|
|
path.as_path(),
|
|
self.dest.as_path(),
|
|
tx.clone(),
|
|
&mut progress,
|
|
)?;
|
|
}
|
|
- Ok(IoWorkerProgress::new(
|
|
- self.kind(),
|
|
- self.paths.len(),
|
|
- self.paths.len(),
|
|
- progress.bytes_processed(),
|
|
- ))
|
|
+ Ok(progress)
|
|
}
|
|
|
|
- fn paste_cut(&self, tx: mpsc::Sender<IoWorkerProgress>) -> std::io::Result<IoWorkerProgress> {
|
|
- let num_items = self.query_number_of_items()?;
|
|
- let mut progress = IoWorkerProgress::new(self.kind(), 0, num_items, 0);
|
|
+ fn paste_cut(&self, tx: mpsc::Sender<IoWorkerProgress>) -> io::Result<IoWorkerProgress> {
|
|
+ let (total_files, total_bytes) = self.query_number_of_items()?;
|
|
+ let mut progress = IoWorkerProgress::new(self.kind(), 0, total_files, 0, total_bytes);
|
|
+
|
|
for path in self.paths.iter() {
|
|
let _ = tx.send(progress.clone());
|
|
recursive_cut(
|
|
+ self.options,
|
|
path.as_path(),
|
|
self.dest.as_path(),
|
|
tx.clone(),
|
|
&mut progress,
|
|
)?;
|
|
}
|
|
- Ok(IoWorkerProgress::new(
|
|
- self.kind(),
|
|
- self.paths.len(),
|
|
- self.paths.len(),
|
|
- progress.bytes_processed(),
|
|
- ))
|
|
+ Ok(progress)
|
|
}
|
|
}
|
|
|
|
pub fn recursive_copy(
|
|
+ options: IoWorkerOptions,
|
|
src: &path::Path,
|
|
dest: &path::Path,
|
|
tx: mpsc::Sender<IoWorkerProgress>,
|
|
progress: &mut IoWorkerProgress,
|
|
-) -> std::io::Result<()> {
|
|
+) -> io::Result<()> {
|
|
let mut dest_buf = dest.to_path_buf();
|
|
if let Some(s) = src.file_name() {
|
|
dest_buf.push(s);
|
|
}
|
|
- rename_filename_conflict(&mut dest_buf);
|
|
+ if !options.overwrite {
|
|
+ rename_filename_conflict(&mut dest_buf);
|
|
+ }
|
|
let file_type = fs::symlink_metadata(src)?.file_type();
|
|
if file_type.is_dir() {
|
|
fs::create_dir(dest_buf.as_path())?;
|
|
@@ -197,6 +203,7 @@
|
|
let entry = entry?;
|
|
let entry_path = entry.path();
|
|
recursive_copy(
|
|
+ options,
|
|
entry_path.as_path(),
|
|
dest_buf.as_path(),
|
|
tx.clone(),
|
|
@@ -208,12 +215,12 @@
|
|
} else if file_type.is_file() {
|
|
let bytes_processed = progress.bytes_processed() + fs::copy(src, dest_buf)?;
|
|
progress.set_bytes_processed(bytes_processed);
|
|
- progress.increment_completed();
|
|
+ progress.set_files_processed(progress.files_processed() + 1);
|
|
Ok(())
|
|
} else if file_type.is_symlink() {
|
|
let link_path = fs::read_link(src)?;
|
|
std::os::unix::fs::symlink(link_path, dest_buf)?;
|
|
- progress.increment_completed();
|
|
+ progress.set_files_processed(progress.files_processed() + 1);
|
|
Ok(())
|
|
} else {
|
|
Ok(())
|
|
@@ -221,29 +228,36 @@
|
|
}
|
|
|
|
pub fn recursive_cut(
|
|
+ options: IoWorkerOptions,
|
|
src: &path::Path,
|
|
dest: &path::Path,
|
|
tx: mpsc::Sender<IoWorkerProgress>,
|
|
progress: &mut IoWorkerProgress,
|
|
-) -> std::io::Result<()> {
|
|
+) -> io::Result<()> {
|
|
let mut dest_buf = dest.to_path_buf();
|
|
if let Some(s) = src.file_name() {
|
|
dest_buf.push(s);
|
|
}
|
|
- rename_filename_conflict(&mut dest_buf);
|
|
+ if !options.overwrite {
|
|
+ rename_filename_conflict(&mut dest_buf);
|
|
+ }
|
|
let metadata = fs::symlink_metadata(src)?;
|
|
let file_type = metadata.file_type();
|
|
- if file_type.is_dir() {
|
|
- match fs::rename(src, dest_buf.as_path()) {
|
|
- Ok(_) => {
|
|
- let processed = progress.bytes_processed() + metadata.len();
|
|
- progress.set_bytes_processed(processed);
|
|
- }
|
|
- Err(_) => {
|
|
+
|
|
+ match fs::rename(src, dest_buf.as_path()) {
|
|
+ Ok(_) => {
|
|
+ let bytes_processed = progress.bytes_processed() + metadata.len();
|
|
+ progress.set_bytes_processed(bytes_processed);
|
|
+ progress.set_files_processed(progress.files_processed() + 1);
|
|
+ Ok(())
|
|
+ }
|
|
+ Err(e) if e.kind() == io::ErrorKind::Other => {
|
|
+ if file_type.is_dir() {
|
|
fs::create_dir(dest_buf.as_path())?;
|
|
for entry in fs::read_dir(src)? {
|
|
let entry_path = entry?.path();
|
|
recursive_cut(
|
|
+ options,
|
|
entry_path.as_path(),
|
|
dest_buf.as_path(),
|
|
tx.clone(),
|
|
@@ -251,23 +265,21 @@
|
|
)?;
|
|
}
|
|
fs::remove_dir(src)?;
|
|
+ } else if file_type.is_symlink() {
|
|
+ let link_path = fs::read_link(src)?;
|
|
+ std::os::unix::fs::symlink(link_path, dest_buf)?;
|
|
+ fs::remove_file(src)?;
|
|
+ let processed = progress.bytes_processed() + metadata.len();
|
|
+ progress.set_bytes_processed(processed);
|
|
+ progress.set_files_processed(progress.files_processed() + 1);
|
|
+ } else {
|
|
+ let processed = progress.bytes_processed() + fs::copy(src, dest_buf.as_path())?;
|
|
+ fs::remove_file(src)?;
|
|
+ progress.set_bytes_processed(processed);
|
|
+ progress.set_files_processed(progress.files_processed() + 1);
|
|
}
|
|
+ Ok(())
|
|
}
|
|
- } else if file_type.is_file() {
|
|
- if fs::rename(src, dest_buf.as_path()).is_err() {
|
|
- fs::copy(src, dest_buf.as_path())?;
|
|
- fs::remove_file(src)?;
|
|
- let processed = progress.bytes_processed() + metadata.len();
|
|
- progress.set_bytes_processed(processed);
|
|
- }
|
|
- progress.increment_completed();
|
|
- } else if file_type.is_symlink() {
|
|
- let link_path = fs::read_link(src)?;
|
|
- std::os::unix::fs::symlink(link_path, dest_buf)?;
|
|
- fs::remove_file(src)?;
|
|
- let processed = progress.bytes_processed() + metadata.len();
|
|
- progress.set_bytes_processed(processed);
|
|
- progress.increment_completed();
|
|
+ e => e,
|
|
}
|
|
- Ok(())
|
|
}
|
|
diff -ur a/src/main.rs b/src/main.rs
|
|
--- a/src/main.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/main.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -2,9 +2,11 @@
|
|
mod config;
|
|
mod context;
|
|
mod error;
|
|
+mod event;
|
|
mod fs;
|
|
mod history;
|
|
mod io;
|
|
+mod preview;
|
|
mod run;
|
|
mod tab;
|
|
mod ui;
|
|
@@ -34,16 +36,32 @@
|
|
lazy_static! {
|
|
// dynamically builds the config hierarchy
|
|
static ref CONFIG_HIERARCHY: Vec<PathBuf> = {
|
|
- let mut temp = vec![];
|
|
- match xdg::BaseDirectories::with_prefix(PROGRAM_NAME) {
|
|
- Ok(dirs) => temp.push(dirs.get_config_home()),
|
|
- Err(e) => eprintln!("{}", e),
|
|
- };
|
|
+ let mut config_dirs = vec![];
|
|
+
|
|
+ if let Ok(p) = std::env::var("JOSHUTO_CONFIG_HOME") {
|
|
+ let p = PathBuf::from(p);
|
|
+ if p.is_dir() {
|
|
+ config_dirs.push(p);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if let Ok(dirs) = xdg::BaseDirectories::with_prefix(PROGRAM_NAME) {
|
|
+ config_dirs.push(dirs.get_config_home());
|
|
+ }
|
|
+
|
|
+ if let Ok(p) = std::env::var("HOME") {
|
|
+ let mut p = PathBuf::from(p);
|
|
+ p.push(".config/joshuto");
|
|
+ if p.is_dir() {
|
|
+ config_dirs.push(p);
|
|
+ }
|
|
+ }
|
|
+
|
|
// adds the default config files to the config hierarchy if running through cargo
|
|
if cfg!(debug_assertions) {
|
|
- temp.push(PathBuf::from("./config"));
|
|
+ config_dirs.push(PathBuf::from("./config"));
|
|
}
|
|
- temp
|
|
+ config_dirs
|
|
};
|
|
static ref THEME_T: AppTheme = AppTheme::get_config(THEME_FILE);
|
|
static ref MIMETYPE_T: AppMimetypeRegistry = AppMimetypeRegistry::get_config(MIMETYPE_FILE);
|
|
@@ -71,21 +89,17 @@
|
|
return Ok(());
|
|
}
|
|
if let Some(p) = args.path.as_ref() {
|
|
- match std::env::set_current_dir(p.as_path()) {
|
|
- Ok(_) => {}
|
|
- Err(e) => {
|
|
- eprintln!("{}", e);
|
|
- process::exit(1);
|
|
- }
|
|
+ if let Err(e) = std::env::set_current_dir(p.as_path()) {
|
|
+ eprintln!("{}", e);
|
|
+ process::exit(1);
|
|
}
|
|
}
|
|
|
|
let config = AppConfig::get_config(CONFIG_FILE);
|
|
let keymap = AppKeyMapping::get_config(KEYMAP_FILE);
|
|
|
|
- let mut context = AppContext::new(config);
|
|
-
|
|
{
|
|
+ let mut context = AppContext::new(config);
|
|
let mut backend: ui::TuiBackend = ui::TuiBackend::new()?;
|
|
run(&mut backend, &mut context, keymap)?;
|
|
}
|
|
@@ -108,11 +122,8 @@
|
|
fn main() {
|
|
let args = Args::from_args();
|
|
|
|
- match run_joshuto(args) {
|
|
- Ok(_) => {}
|
|
- Err(e) => {
|
|
- eprintln!("{}", e.to_string());
|
|
- process::exit(1);
|
|
- }
|
|
+ if let Err(e) = run_joshuto(args) {
|
|
+ eprintln!("{}", e.to_string());
|
|
+ process::exit(1);
|
|
}
|
|
}
|
|
Только в b/src: preview
|
|
diff -ur a/src/run.rs b/src/run.rs
|
|
--- a/src/run.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/run.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -3,12 +3,12 @@
|
|
use crate::commands::{AppExecute, CommandKeybind, KeyCommand};
|
|
use crate::config::AppKeyMapping;
|
|
use crate::context::AppContext;
|
|
+use crate::event::AppEvent;
|
|
+use crate::preview::preview_default;
|
|
use crate::tab::JoshutoTab;
|
|
use crate::ui;
|
|
use crate::ui::views::{TuiCommandMenu, TuiView};
|
|
-use crate::util::event::AppEvent;
|
|
use crate::util::input;
|
|
-use crate::util::load_child::LoadChild;
|
|
use crate::util::to_string::ToString;
|
|
|
|
pub fn run(
|
|
@@ -23,7 +23,7 @@
|
|
context.tab_context_mut().push_tab(tab);
|
|
|
|
// trigger a preview of child
|
|
- LoadChild::load_child(context)?;
|
|
+ preview_default::load_preview(context, backend);
|
|
}
|
|
|
|
while !context.exit {
|
|
@@ -40,6 +40,7 @@
|
|
match event {
|
|
AppEvent::Termion(Event::Mouse(event)) => {
|
|
input::process_mouse(event, context, backend);
|
|
+ preview_default::load_preview(context, backend);
|
|
}
|
|
AppEvent::Termion(key) => {
|
|
if !context.message_queue_ref().is_empty() {
|
|
@@ -82,6 +83,7 @@
|
|
},
|
|
}
|
|
context.flush_event();
|
|
+ preview_default::load_preview(context, backend);
|
|
}
|
|
event => input::process_noninteractive(event, context),
|
|
}
|
|
diff -ur a/src/tab.rs b/src/tab.rs
|
|
--- a/src/tab.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/tab.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -4,6 +4,13 @@
|
|
use crate::history::{DirectoryHistory, JoshutoHistory};
|
|
use crate::util::display::DisplayOption;
|
|
|
|
+#[derive(Clone, Copy, Debug)]
|
|
+pub enum TabHomePage {
|
|
+ Inherit,
|
|
+ Home,
|
|
+ Root,
|
|
+}
|
|
+
|
|
pub struct JoshutoTab {
|
|
history: JoshutoHistory,
|
|
_cwd: path::PathBuf,
|
|
diff -ur a/src/ui/views/tui_command_menu.rs b/src/ui/views/tui_command_menu.rs
|
|
--- a/src/ui/views/tui_command_menu.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/views/tui_command_menu.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -7,10 +7,10 @@
|
|
use crate::commands::{CommandKeybind, KeyCommand};
|
|
use crate::config::AppKeyMapping;
|
|
use crate::context::AppContext;
|
|
+use crate::event::AppEvent;
|
|
use crate::ui::views::TuiView;
|
|
use crate::ui::widgets::TuiMenu;
|
|
use crate::ui::TuiBackend;
|
|
-use crate::util::event::AppEvent;
|
|
use crate::util::input;
|
|
use crate::util::to_string::ToString;
|
|
|
|
@@ -36,11 +36,11 @@
|
|
|
|
loop {
|
|
let _ = terminal.draw(|frame| {
|
|
- let f_size: Rect = frame.size();
|
|
+ let area = frame.size();
|
|
|
|
{
|
|
let view = TuiView::new(&context);
|
|
- frame.render_widget(view, f_size);
|
|
+ frame.render_widget(view, area);
|
|
}
|
|
|
|
{
|
|
@@ -54,21 +54,27 @@
|
|
let display_str: Vec<&str> = display_vec.iter().map(|v| v.as_str()).collect();
|
|
let display_str_len = display_str.len();
|
|
|
|
- let y = if (f_size.height as usize)
|
|
+ let y = if (area.height as usize)
|
|
< display_str_len + BORDER_HEIGHT + BOTTOM_MARGIN
|
|
{
|
|
0
|
|
} else {
|
|
- f_size.height
|
|
+ area.height
|
|
- (BORDER_HEIGHT + BOTTOM_MARGIN) as u16
|
|
- display_str_len as u16
|
|
};
|
|
|
|
+ let menu_height = if display_str_len + BORDER_HEIGHT > area.height as usize {
|
|
+ area.height
|
|
+ } else {
|
|
+ (display_str_len + BORDER_HEIGHT) as u16
|
|
+ };
|
|
+
|
|
let menu_rect = Rect {
|
|
x: 0,
|
|
y,
|
|
- width: f_size.width,
|
|
- height: (display_str_len + BORDER_HEIGHT) as u16,
|
|
+ width: area.width,
|
|
+ height: menu_height,
|
|
};
|
|
|
|
frame.render_widget(Clear, menu_rect);
|
|
diff -ur a/src/ui/views/tui_folder_view.rs b/src/ui/views/tui_folder_view.rs
|
|
--- a/src/ui/views/tui_folder_view.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/views/tui_folder_view.rs 2021-08-07 11:25:14.712140779 +0300
|
|
@@ -1,6 +1,7 @@
|
|
use tui::buffer::Buffer;
|
|
use tui::layout::{Constraint, Direction, Layout, Rect};
|
|
use tui::style::{Color, Style};
|
|
+use tui::symbols::line::{HORIZONTAL_DOWN, HORIZONTAL_UP};
|
|
use tui::text::Span;
|
|
use tui::widgets::{Block, Borders, Paragraph, Widget, Wrap};
|
|
|
|
@@ -48,6 +49,7 @@
|
|
height: area.height - 2,
|
|
..area
|
|
};
|
|
+
|
|
let block = Block::default().borders(Borders::ALL);
|
|
let inner = block.inner(area);
|
|
block.render(area, buf);
|
|
@@ -57,6 +59,25 @@
|
|
.constraints(constraints.as_ref())
|
|
.split(inner);
|
|
|
|
+ // Render inner borders properly.
|
|
+ {
|
|
+ let top = area.top();
|
|
+ let bottom = area.bottom() - 1;
|
|
+ let left = layout_rect[1].left() - 1;
|
|
+ let right = layout_rect[2].left();
|
|
+ let intersections = Intersections {
|
|
+ top,
|
|
+ bottom,
|
|
+ left,
|
|
+ right,
|
|
+ };
|
|
+
|
|
+ intersections.render_left(buf);
|
|
+ if child_list.as_ref().is_some() {
|
|
+ intersections.render_right(buf);
|
|
+ }
|
|
+ }
|
|
+
|
|
let block = Block::default().borders(Borders::RIGHT);
|
|
let inner1 = block.inner(layout_rect[0]);
|
|
block.render(layout_rect[0], buf);
|
|
@@ -160,3 +181,24 @@
|
|
}
|
|
}
|
|
}
|
|
+
|
|
+struct Intersections {
|
|
+ top: u16,
|
|
+ bottom: u16,
|
|
+ left: u16,
|
|
+ right: u16,
|
|
+}
|
|
+
|
|
+impl Intersections {
|
|
+ fn render_left(&self, buf: &mut Buffer) {
|
|
+ buf.get_mut(self.left, self.top).set_symbol(HORIZONTAL_DOWN);
|
|
+ buf.get_mut(self.left, self.bottom)
|
|
+ .set_symbol(HORIZONTAL_UP);
|
|
+ }
|
|
+ fn render_right(&self, buf: &mut Buffer) {
|
|
+ buf.get_mut(self.right, self.top)
|
|
+ .set_symbol(HORIZONTAL_DOWN);
|
|
+ buf.get_mut(self.right, self.bottom)
|
|
+ .set_symbol(HORIZONTAL_UP);
|
|
+ }
|
|
+}
|
|
diff -ur a/src/ui/views/tui_textfield.rs b/src/ui/views/tui_textfield.rs
|
|
--- a/src/ui/views/tui_textfield.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/views/tui_textfield.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -7,10 +7,10 @@
|
|
use unicode_width::UnicodeWidthStr;
|
|
|
|
use crate::context::AppContext;
|
|
+use crate::event::AppEvent;
|
|
use crate::ui::views::TuiView;
|
|
use crate::ui::widgets::{TuiMenu, TuiMultilineText};
|
|
use crate::ui::TuiBackend;
|
|
-use crate::util::event::AppEvent;
|
|
use crate::util::input;
|
|
|
|
struct CompletionTracker {
|
|
diff -ur a/src/ui/views/tui_worker_view.rs b/src/ui/views/tui_worker_view.rs
|
|
--- a/src/ui/views/tui_worker_view.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/views/tui_worker_view.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -3,9 +3,9 @@
|
|
use tui::layout::Rect;
|
|
|
|
use crate::context::AppContext;
|
|
+use crate::event::AppEvent;
|
|
use crate::ui::widgets::{TuiTopBar, TuiWorker};
|
|
use crate::ui::TuiBackend;
|
|
-use crate::util::event::AppEvent;
|
|
use crate::util::input;
|
|
|
|
pub struct TuiWorkerView {}
|
|
@@ -43,11 +43,8 @@
|
|
if let Ok(event) = context.poll_event() {
|
|
match event {
|
|
AppEvent::Termion(event) => {
|
|
- match event {
|
|
- Event::Key(Key::Esc) => {
|
|
- break;
|
|
- }
|
|
- _ => {}
|
|
+ if let Event::Key(Key::Esc) = event {
|
|
+ break;
|
|
}
|
|
context.flush_event();
|
|
}
|
|
diff -ur a/src/ui/widgets/mod.rs b/src/ui/widgets/mod.rs
|
|
--- a/src/ui/widgets/mod.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/widgets/mod.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -9,7 +9,7 @@
|
|
mod tui_worker;
|
|
|
|
pub use self::tui_dirlist::TuiDirList;
|
|
-pub use self::tui_dirlist_detailed::TuiDirListDetailed;
|
|
+pub use self::tui_dirlist_detailed::{trim_file_label, TuiDirListDetailed};
|
|
pub use self::tui_footer::TuiFooter;
|
|
pub use self::tui_menu::TuiMenu;
|
|
pub use self::tui_prompt::TuiPrompt;
|
|
diff -ur a/src/ui/widgets/tui_dirlist_detailed.rs b/src/ui/widgets/tui_dirlist_detailed.rs
|
|
--- a/src/ui/widgets/tui_dirlist_detailed.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/widgets/tui_dirlist_detailed.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -2,13 +2,14 @@
|
|
use tui::layout::Rect;
|
|
use tui::style::{Color, Modifier, Style};
|
|
use tui::widgets::Widget;
|
|
-use unicode_width::UnicodeWidthStr;
|
|
|
|
-use crate::fs::{FileType, JoshutoDirEntry, JoshutoDirList};
|
|
+use crate::fs::{FileType, JoshutoDirEntry, JoshutoDirList, LinkType};
|
|
use crate::util::format;
|
|
+use crate::util::string::UnicodeTruncate;
|
|
use crate::util::style;
|
|
+use unicode_width::UnicodeWidthStr;
|
|
|
|
-const FILE_SIZE_WIDTH: usize = 8;
|
|
+const MIN_LEFT_LABEL_WIDTH: i32 = 15;
|
|
|
|
const ELLIPSIS: &str = "…";
|
|
|
|
@@ -40,7 +41,7 @@
|
|
};
|
|
|
|
let drawing_width = area.width as usize;
|
|
- let skip_dist = curr_index / area.height as usize * area.height as usize;
|
|
+ let skip_dist = self.dirlist.first_index_for_viewport(area.height as usize);
|
|
|
|
// draw every entry
|
|
self.dirlist
|
|
@@ -79,77 +80,223 @@
|
|
(x, y): (u16, u16),
|
|
drawing_width: usize,
|
|
) {
|
|
- let name = entry.label();
|
|
- let name_width = name.width();
|
|
+ let size_string = match entry.metadata.file_type() {
|
|
+ FileType::Directory => entry
|
|
+ .metadata
|
|
+ .directory_size()
|
|
+ .map(|n| n.to_string())
|
|
+ .unwrap_or("".to_string()),
|
|
+ FileType::File => format::file_size_to_string(entry.metadata.len()),
|
|
+ };
|
|
+ let symlink_string = match entry.metadata.link_type() {
|
|
+ LinkType::Normal => "",
|
|
+ LinkType::Symlink(_) => "-> ",
|
|
+ };
|
|
+ let left_label_original = entry.label();
|
|
+ let right_label_original = format!(" {}{} ", symlink_string, size_string);
|
|
+
|
|
+ let (left_label, right_label) = factor_labels_for_entry(
|
|
+ left_label_original,
|
|
+ right_label_original.as_str(),
|
|
+ drawing_width,
|
|
+ );
|
|
+
|
|
+ let right_width = right_label.width();
|
|
+ buf.set_stringn(x, y, left_label, drawing_width, style);
|
|
+ buf.set_stringn(
|
|
+ x + drawing_width as u16 - right_width as u16,
|
|
+ y,
|
|
+ right_label,
|
|
+ drawing_width,
|
|
+ style,
|
|
+ );
|
|
+}
|
|
|
|
- match entry.metadata.file_type() {
|
|
- FileType::Directory => {
|
|
- // print filename
|
|
- buf.set_stringn(x, y, name, drawing_width, style);
|
|
- if name_width > drawing_width {
|
|
- buf.set_string(x + drawing_width as u16 - 1, y, ELLIPSIS, style);
|
|
- }
|
|
- }
|
|
- FileType::Symlink(_) => {
|
|
- // print filename
|
|
- buf.set_stringn(x, y, name, drawing_width, style);
|
|
- buf.set_string(x + drawing_width as u16 - 4, y, "->", style);
|
|
- if name_width >= drawing_width - 4 {
|
|
- buf.set_string(x + drawing_width as u16 - 1, y, ELLIPSIS, style);
|
|
- }
|
|
+fn factor_labels_for_entry<'a>(
|
|
+ left_label_original: &'a str,
|
|
+ right_label_original: &'a str,
|
|
+ drawing_width: usize,
|
|
+) -> (String, &'a str) {
|
|
+ let left_label_original_width = left_label_original.width();
|
|
+ let right_label_original_width = right_label_original.width();
|
|
+
|
|
+ let left_width_remainder = drawing_width as i32 - right_label_original_width as i32;
|
|
+ let width_remainder = left_width_remainder as i32 - left_label_original_width as i32;
|
|
+
|
|
+ if drawing_width == 0 {
|
|
+ ("".to_string(), "")
|
|
+ } else if width_remainder >= 0 {
|
|
+ (left_label_original.to_string(), right_label_original)
|
|
+ } else {
|
|
+ if left_width_remainder < MIN_LEFT_LABEL_WIDTH {
|
|
+ (
|
|
+ if left_label_original.width() as i32 <= left_width_remainder {
|
|
+ trim_file_label(left_label_original, drawing_width)
|
|
+ } else {
|
|
+ left_label_original.to_string()
|
|
+ },
|
|
+ "",
|
|
+ )
|
|
+ } else {
|
|
+ (
|
|
+ trim_file_label(left_label_original, left_width_remainder as usize),
|
|
+ right_label_original,
|
|
+ )
|
|
}
|
|
- FileType::File => {
|
|
- if drawing_width < FILE_SIZE_WIDTH {
|
|
- return;
|
|
- }
|
|
- let file_drawing_width = drawing_width - FILE_SIZE_WIDTH;
|
|
+ }
|
|
+}
|
|
|
|
- let (stem, extension) = match name.rfind('.') {
|
|
- None => (name, ""),
|
|
- Some(i) => name.split_at(i),
|
|
- };
|
|
- if stem.is_empty() {
|
|
- let ext_width = extension.width();
|
|
- buf.set_stringn(x, y, extension, file_drawing_width, style);
|
|
- if ext_width > drawing_width {
|
|
- buf.set_string(x + drawing_width as u16 - 1, y, ELLIPSIS, style);
|
|
- }
|
|
- } else if extension.is_empty() {
|
|
- let stem_width = stem.width();
|
|
- buf.set_stringn(x, y, stem, file_drawing_width, style);
|
|
- if stem_width > file_drawing_width {
|
|
- buf.set_string(x + drawing_width as u16 - 1, y, ELLIPSIS, style);
|
|
- }
|
|
- } else {
|
|
- let stem_width = stem.width();
|
|
- let ext_width = extension.width();
|
|
- buf.set_stringn(x, y, stem, file_drawing_width, style);
|
|
- if stem_width + ext_width > file_drawing_width {
|
|
- let ext_start_idx = if file_drawing_width < ext_width {
|
|
- 0
|
|
- } else {
|
|
- (file_drawing_width - ext_width) as u16
|
|
- };
|
|
- buf.set_string(x + ext_start_idx, y, extension, style);
|
|
- let ext_start_idx = if ext_start_idx > 0 {
|
|
- ext_start_idx - 1
|
|
- } else {
|
|
- 0
|
|
- };
|
|
- buf.set_string(x + ext_start_idx, y, ELLIPSIS, style);
|
|
- } else {
|
|
- buf.set_string(x + stem_width as u16, y, extension, style);
|
|
- }
|
|
- }
|
|
- // print file size
|
|
- let file_size_string = format::file_size_to_string(entry.metadata.len());
|
|
- buf.set_string(x + file_drawing_width as u16, y, " ", style);
|
|
- buf.set_string(
|
|
- x + file_drawing_width as u16 + 1,
|
|
- y,
|
|
- file_size_string,
|
|
- style,
|
|
- );
|
|
+pub fn trim_file_label(name: &str, drawing_width: usize) -> String {
|
|
+ // pre-condition: string name is longer than width
|
|
+ let (stem, extension) = match name.rfind('.') {
|
|
+ None => (name, ""),
|
|
+ Some(i) => name.split_at(i),
|
|
+ };
|
|
+ if drawing_width < 1 {
|
|
+ String::from("")
|
|
+ } else if stem.is_empty() || extension.is_empty() {
|
|
+ let full = format!("{}{}", stem, extension);
|
|
+ let mut truncated = full.trunc(drawing_width - 1);
|
|
+ truncated.push_str(ELLIPSIS);
|
|
+ truncated
|
|
+ } else {
|
|
+ let ext_width = extension.width();
|
|
+ if ext_width > drawing_width {
|
|
+ // file ext does not fit
|
|
+ ELLIPSIS.to_string()
|
|
+ } else if ext_width == drawing_width {
|
|
+ extension.replacen('.', ELLIPSIS, 1).to_string()
|
|
+ } else {
|
|
+ let stem_width = drawing_width - ext_width;
|
|
+ let truncated_stem = stem.trunc(stem_width - 1);
|
|
+ format!("{}{}{}", truncated_stem, ELLIPSIS, extension)
|
|
}
|
|
}
|
|
}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod test_factor_labels {
|
|
+ use super::{factor_labels_for_entry, MIN_LEFT_LABEL_WIDTH};
|
|
+
|
|
+ #[test]
|
|
+ fn both_labels_empty_if_drawing_width_zero() {
|
|
+ let left = "foo.ext";
|
|
+ let right = "right";
|
|
+ assert_eq!(
|
|
+ ("".to_string(), ""),
|
|
+ factor_labels_for_entry(left, right, 0)
|
|
+ );
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn nothing_changes_if_all_labels_fit_easily() {
|
|
+ let left = "foo.ext";
|
|
+ let right = "right";
|
|
+ assert_eq!(
|
|
+ (left.to_string(), right),
|
|
+ factor_labels_for_entry(left, right, 20)
|
|
+ );
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn nothing_changes_if_all_labels_just_fit() {
|
|
+ let left = "foo.ext";
|
|
+ let right = "right";
|
|
+ assert_eq!(
|
|
+ (left.to_string(), right),
|
|
+ factor_labels_for_entry(left, right, 12)
|
|
+ );
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn right_label_omitted_if_left_label_would_need_to_be_shortened_below_min_left_label_width() {
|
|
+ let left = "foobarbazfo.ext";
|
|
+ let right = "right";
|
|
+ assert!(left.chars().count() as i32 == MIN_LEFT_LABEL_WIDTH);
|
|
+ assert_eq!(
|
|
+ ("foobarbazfo.ext".to_string(), ""),
|
|
+ factor_labels_for_entry(left, right, MIN_LEFT_LABEL_WIDTH as usize)
|
|
+ );
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn right_label_is_kept_if_left_label_is_not_shortened_below_min_left_label_width() {
|
|
+ let left = "foobarbazfoobarbaz.ext";
|
|
+ let right = "right";
|
|
+ assert!(left.chars().count() as i32 > MIN_LEFT_LABEL_WIDTH + right.chars().count() as i32);
|
|
+ assert_eq!(
|
|
+ ("foobarbazf….ext".to_string(), right),
|
|
+ factor_labels_for_entry(
|
|
+ left,
|
|
+ right,
|
|
+ MIN_LEFT_LABEL_WIDTH as usize + right.chars().count()
|
|
+ )
|
|
+ );
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ // regression
|
|
+ fn file_name_which_is_smaller_or_equal_drawing_width_does_not_cause_right_label_to_be_omitted()
|
|
+ {
|
|
+ let left = "foooooobaaaaaaarbaaaaaaaaaz";
|
|
+ let right = "right";
|
|
+ assert!(left.chars().count() as i32 > MIN_LEFT_LABEL_WIDTH);
|
|
+ assert_eq!(
|
|
+ ("foooooobaaaaaaarbaaaa…".to_string(), right),
|
|
+ factor_labels_for_entry(left, right, left.chars().count())
|
|
+ );
|
|
+ }
|
|
+}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod test_trim_file_label {
|
|
+ use super::trim_file_label;
|
|
+
|
|
+ #[test]
|
|
+ fn dotfiles_get_an_ellipsis_at_the_end_if_they_dont_fit() {
|
|
+ let label = ".joshuto";
|
|
+ assert_eq!(".jos…".to_string(), trim_file_label(label, 5));
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn dotless_files_get_an_ellipsis_at_the_end_if_they_dont_fit() {
|
|
+ let label = "Desktop";
|
|
+ assert_eq!("Desk…".to_string(), trim_file_label(label, 5));
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn if_the_extension_doesnt_fit_just_an_ellipses_is_shown() {
|
|
+ let label = "foo.ext";
|
|
+ assert_eq!("…".to_string(), trim_file_label(label, 2));
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn if_just_the_extension_fits_its_shown_with_an_ellipsis_instead_of_a_dot() {
|
|
+ let left = "foo.ext";
|
|
+ assert_eq!("…ext".to_string(), trim_file_label(left, 4));
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn if_the_extension_fits_the_stem_is_truncated_with_an_appended_ellipsis_1() {
|
|
+ let left = "foo.ext";
|
|
+ assert_eq!("….ext".to_string(), trim_file_label(left, 5));
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn if_the_extension_fits_the_stem_is_truncated_with_an_appended_ellipsis_2() {
|
|
+ let left = "foo.ext";
|
|
+ assert_eq!("f….ext".to_string(), trim_file_label(left, 6));
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn if_the_name_is_truncated_after_a_full_width_character_the_ellipsis_is_shown_correctly() {
|
|
+ let left = "🌕🌕🌕";
|
|
+ assert_eq!("🌕…".to_string(), trim_file_label(left, 4));
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn if_the_name_is_truncated_within_a_full_width_character_the_ellipsis_is_shown_correctly() {
|
|
+ let left = "🌕🌕🌕";
|
|
+ assert_eq!("🌕🌕…".to_string(), trim_file_label(left, 5));
|
|
+ }
|
|
+}
|
|
diff -ur a/src/ui/widgets/tui_dirlist.rs b/src/ui/widgets/tui_dirlist.rs
|
|
--- a/src/ui/widgets/tui_dirlist.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/widgets/tui_dirlist.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -4,11 +4,10 @@
|
|
use tui::widgets::Widget;
|
|
use unicode_width::UnicodeWidthStr;
|
|
|
|
-use crate::fs::{FileType, JoshutoDirEntry, JoshutoDirList};
|
|
+use crate::fs::{JoshutoDirEntry, JoshutoDirList};
|
|
+use crate::ui::widgets::trim_file_label;
|
|
use crate::util::style;
|
|
|
|
-const ELLIPSIS: &str = "…";
|
|
-
|
|
pub struct TuiDirList<'a> {
|
|
dirlist: &'a JoshutoDirList,
|
|
}
|
|
@@ -37,7 +36,7 @@
|
|
}
|
|
|
|
let curr_index = self.dirlist.index.unwrap();
|
|
- let skip_dist = curr_index / area.height as usize * area.height as usize;
|
|
+ let skip_dist = self.dirlist.first_index_for_viewport(area.height as usize);
|
|
|
|
let drawing_width = area.width as usize;
|
|
|
|
@@ -79,54 +78,10 @@
|
|
) {
|
|
let name = entry.label();
|
|
let name_width = name.width();
|
|
-
|
|
- match entry.metadata.file_type() {
|
|
- FileType::Directory => {
|
|
- // print filename
|
|
- buf.set_stringn(x, y, name, drawing_width, style);
|
|
- if name_width > drawing_width {
|
|
- buf.set_string(x + drawing_width as u16 - 1, y, ELLIPSIS, style);
|
|
- }
|
|
- }
|
|
- _ => {
|
|
- let file_drawing_width = drawing_width;
|
|
- let (stem, extension) = match name.rfind('.') {
|
|
- None => (name, ""),
|
|
- Some(i) => name.split_at(i),
|
|
- };
|
|
- if stem.is_empty() {
|
|
- let ext_width = extension.width();
|
|
- buf.set_stringn(x, y, extension, file_drawing_width, style);
|
|
- if ext_width > drawing_width {
|
|
- buf.set_string(x + drawing_width as u16 - 1, y, ELLIPSIS, style);
|
|
- }
|
|
- } else if extension.is_empty() {
|
|
- let stem_width = stem.width();
|
|
- buf.set_stringn(x, y, stem, file_drawing_width, style);
|
|
- if stem_width > file_drawing_width {
|
|
- buf.set_string(x + file_drawing_width as u16 - 1, y, ELLIPSIS, style);
|
|
- }
|
|
- } else {
|
|
- let stem_width = stem.width();
|
|
- let ext_width = extension.width();
|
|
- buf.set_stringn(x, y, stem, file_drawing_width, style);
|
|
- if stem_width + ext_width > file_drawing_width {
|
|
- let ext_start_idx = if file_drawing_width < ext_width {
|
|
- 0
|
|
- } else {
|
|
- (file_drawing_width - ext_width) as u16
|
|
- };
|
|
- buf.set_string(x + ext_start_idx, y, extension, style);
|
|
- let ext_start_idx = if ext_start_idx > 0 {
|
|
- ext_start_idx - 1
|
|
- } else {
|
|
- 0
|
|
- };
|
|
- buf.set_string(x + ext_start_idx, y, ELLIPSIS, style);
|
|
- } else {
|
|
- buf.set_string(x + stem_width as u16, y, extension, style);
|
|
- }
|
|
- }
|
|
- }
|
|
- }
|
|
+ let label = if name_width > drawing_width {
|
|
+ trim_file_label(name, drawing_width)
|
|
+ } else {
|
|
+ name.to_string()
|
|
+ };
|
|
+ buf.set_string(x, y, label, style);
|
|
}
|
|
diff -ur a/src/ui/widgets/tui_footer.rs b/src/ui/widgets/tui_footer.rs
|
|
--- a/src/ui/widgets/tui_footer.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/widgets/tui_footer.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -4,7 +4,7 @@
|
|
use tui::text::{Span, Spans};
|
|
use tui::widgets::{Paragraph, Widget};
|
|
|
|
-use crate::fs::{FileType, JoshutoDirList};
|
|
+use crate::fs::{JoshutoDirList, LinkType};
|
|
use crate::util::format;
|
|
use crate::util::unix;
|
|
|
|
@@ -41,7 +41,7 @@
|
|
Span::raw(size_str),
|
|
];
|
|
|
|
- if let FileType::Symlink(s) = entry.metadata.file_type() {
|
|
+ if let LinkType::Symlink(s) = entry.metadata.link_type() {
|
|
text.push(Span::styled(" -> ", mode_style));
|
|
text.push(Span::styled(s, mode_style));
|
|
}
|
|
diff -ur a/src/ui/widgets/tui_menu.rs b/src/ui/widgets/tui_menu.rs
|
|
--- a/src/ui/widgets/tui_menu.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/widgets/tui_menu.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -19,18 +19,18 @@
|
|
|
|
impl<'a> Widget for TuiMenu<'a> {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
- let text_iter = self.options.iter().chain(&[" "]);
|
|
let style = Style::default().fg(Color::Reset).bg(Color::Reset);
|
|
- let area_x = area.x + 1;
|
|
- let area_y = area.y + 1;
|
|
|
|
Block::default()
|
|
.style(style)
|
|
.borders(Borders::TOP)
|
|
.render(area, buf);
|
|
|
|
- for (i, text) in text_iter.enumerate() {
|
|
- buf.set_string(area_x, area_y + i as u16, text, style);
|
|
+ let text_iter = self.options.iter().chain(&[" "]);
|
|
+ let area_x = area.x + 1;
|
|
+
|
|
+ for (y, text) in (area.y + 1..area.y + area.height).zip(text_iter) {
|
|
+ buf.set_string(area_x, y, text, style);
|
|
}
|
|
}
|
|
}
|
|
diff -ur a/src/ui/widgets/tui_prompt.rs b/src/ui/widgets/tui_prompt.rs
|
|
--- a/src/ui/widgets/tui_prompt.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/widgets/tui_prompt.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -5,9 +5,9 @@
|
|
use tui::widgets::{Clear, Paragraph, Wrap};
|
|
|
|
use crate::context::AppContext;
|
|
+use crate::event::AppEvent;
|
|
use crate::ui::views::TuiView;
|
|
use crate::ui::TuiBackend;
|
|
-use crate::util::event::AppEvent;
|
|
use crate::util::input;
|
|
|
|
pub struct TuiPrompt<'a> {
|
|
diff -ur a/src/ui/widgets/tui_topbar.rs b/src/ui/widgets/tui_topbar.rs
|
|
--- a/src/ui/widgets/tui_topbar.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/widgets/tui_topbar.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -22,10 +22,6 @@
|
|
|
|
impl<'a> Widget for TuiTopBar<'a> {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
- let username_style = Style::default()
|
|
- .fg(Color::LightGreen)
|
|
- .add_modifier(Modifier::BOLD);
|
|
-
|
|
let path_style = Style::default()
|
|
.fg(Color::LightBlue)
|
|
.add_modifier(Modifier::BOLD);
|
|
@@ -34,12 +30,9 @@
|
|
let mut curr_path_str = self.path.to_string_lossy().into_owned();
|
|
|
|
if curr_path_str.len() > area.width as usize {
|
|
- match self.path.file_name() {
|
|
- Some(s) => {
|
|
- curr_path_str = s.to_string_lossy().into_owned();
|
|
- ellipses = Some(Span::styled("…", path_style));
|
|
- }
|
|
- None => {}
|
|
+ if let Some(s) = self.path.file_name() {
|
|
+ curr_path_str = s.to_string_lossy().into_owned();
|
|
+ ellipses = Some(Span::styled("…", path_style));
|
|
}
|
|
}
|
|
if self
|
|
@@ -54,6 +47,14 @@
|
|
}
|
|
}
|
|
|
|
+ let username_style = if USERNAME.as_str() == "root" {
|
|
+ Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)
|
|
+ } else {
|
|
+ Style::default()
|
|
+ .fg(Color::LightGreen)
|
|
+ .add_modifier(Modifier::BOLD)
|
|
+ };
|
|
+
|
|
let text = match ellipses {
|
|
Some(s) => Spans::from(vec![
|
|
Span::styled(USERNAME.as_str(), username_style),
|
|
diff -ur a/src/ui/widgets/tui_worker.rs b/src/ui/widgets/tui_worker.rs
|
|
--- a/src/ui/widgets/tui_worker.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/ui/widgets/tui_worker.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -5,6 +5,7 @@
|
|
|
|
use crate::context::AppContext;
|
|
use crate::io::FileOp;
|
|
+use crate::util::format;
|
|
|
|
pub struct TuiWorker<'a> {
|
|
pub context: &'a AppContext,
|
|
@@ -25,19 +26,28 @@
|
|
FileOp::Copy => "Copying",
|
|
FileOp::Cut => "Moving",
|
|
};
|
|
+
|
|
+ let processed_size = format::file_size_to_string(progress.bytes_processed());
|
|
+ let total_size = format::file_size_to_string(progress.total_bytes());
|
|
+
|
|
let msg = format!(
|
|
- "{} ({}/{}) {:?}",
|
|
+ "{} ({}/{}) ({}/{}) {:?}",
|
|
op_str,
|
|
- progress.completed() + 1,
|
|
- progress.len(),
|
|
+ progress.files_processed() + 1,
|
|
+ progress.total_files(),
|
|
+ processed_size,
|
|
+ total_size,
|
|
io_obs.dest_path()
|
|
);
|
|
+
|
|
let style = Style::default();
|
|
buf.set_stringn(0, 2, msg, area.width as usize, style);
|
|
|
|
// draw a progress bar
|
|
- let progress_bar_width = (progress.completed() as f32 / progress.len() as f32
|
|
+ let progress_bar_width = (progress.files_processed() as f32
|
|
+ / progress.total_files() as f32
|
|
* area.width as f32) as usize;
|
|
+
|
|
let progress_bar_space = " ".repeat(progress_bar_width);
|
|
let style = Style::default().bg(Color::Blue);
|
|
buf.set_stringn(0, 3, progress_bar_space, area.width as usize, style);
|
|
diff -ur a/src/util/display.rs b/src/util/display.rs
|
|
--- a/src/util/display.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/util/display.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -106,14 +106,11 @@
|
|
|
|
fn filter_hidden(result: &Result<fs::DirEntry, std::io::Error>) -> bool {
|
|
match result {
|
|
- Err(_) => false,
|
|
+ Err(_) => true,
|
|
Ok(entry) => {
|
|
let file_name = entry.file_name();
|
|
- if let Some(file_name) = file_name.to_str() {
|
|
- !file_name.starts_with('.')
|
|
- } else {
|
|
- false
|
|
- }
|
|
+ let lossy_string = file_name.as_os_str().to_string_lossy();
|
|
+ !lossy_string.starts_with('.')
|
|
}
|
|
}
|
|
}
|
|
Только в a/src/util: event.rs
|
|
diff -ur a/src/util/input.rs b/src/util/input.rs
|
|
--- a/src/util/input.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/util/input.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -4,10 +4,10 @@
|
|
|
|
use crate::commands::{cursor_move, parent_cursor_move, AppExecute, KeyCommand};
|
|
use crate::context::AppContext;
|
|
+use crate::event::AppEvent;
|
|
use crate::history::DirectoryHistory;
|
|
use crate::io::{FileOp, IoWorkerProgress};
|
|
use crate::ui;
|
|
-use crate::util::event::AppEvent;
|
|
use crate::util::format;
|
|
|
|
pub fn process_mouse(event: MouseEvent, context: &mut AppContext, backend: &mut ui::TuiBackend) {
|
|
@@ -16,7 +16,13 @@
|
|
let constraints: &[Constraint; 3] = &context.config_ref().display_options_ref().default_layout;
|
|
let layout_rect = Layout::default()
|
|
.direction(Direction::Horizontal)
|
|
- .vertical_margin(1)
|
|
+ .vertical_margin(
|
|
+ if context.config_ref().display_options_ref().show_borders() {
|
|
+ 2
|
|
+ } else {
|
|
+ 1
|
|
+ },
|
|
+ )
|
|
.constraints(constraints.as_ref())
|
|
.split(f_size);
|
|
|
|
@@ -54,28 +60,28 @@
|
|
MouseEvent::Press(MouseButton::Left, x, y)
|
|
if y > layout_rect[1].y && y <= layout_rect[1].y + layout_rect[1].height =>
|
|
{
|
|
- if x < layout_rect[1].x {
|
|
- if let Some(dirlist) = context.tab_context_ref().curr_tab_ref().curr_list_ref() {
|
|
- if let Some(curr_index) = dirlist.index {
|
|
- let skip_dist = curr_index / layout_rect[1].height as usize
|
|
- * layout_rect[1].height as usize;
|
|
-
|
|
- let new_index = skip_dist + (y - layout_rect[1].y - 1) as usize;
|
|
- if let Err(e) = parent_cursor_move::parent_cursor_move(new_index, context) {
|
|
- context.push_msg(e.to_string());
|
|
- }
|
|
- }
|
|
- }
|
|
- } else if x < layout_rect[2].x {
|
|
- if let Some(dirlist) = context.tab_context_ref().curr_tab_ref().curr_list_ref() {
|
|
- if let Some(curr_index) = dirlist.index {
|
|
- let skip_dist = curr_index / layout_rect[1].height as usize
|
|
- * layout_rect[1].height as usize;
|
|
-
|
|
- let new_index = skip_dist + (y - layout_rect[1].y - 1) as usize;
|
|
- if let Err(e) = cursor_move::cursor_move(new_index, context) {
|
|
- context.push_msg(e.to_string());
|
|
- }
|
|
+ if x < layout_rect[2].x {
|
|
+ let (dirlist, is_parent) = if x < layout_rect[1].x {
|
|
+ (
|
|
+ context.tab_context_ref().curr_tab_ref().parent_list_ref(),
|
|
+ true,
|
|
+ )
|
|
+ } else {
|
|
+ (
|
|
+ context.tab_context_ref().curr_tab_ref().curr_list_ref(),
|
|
+ false,
|
|
+ )
|
|
+ };
|
|
+ if let Some(dirlist) = dirlist {
|
|
+ let skip_dist =
|
|
+ dirlist.first_index_for_viewport(layout_rect[1].height as usize);
|
|
+ let new_index = skip_dist + (y - layout_rect[1].y - 1) as usize;
|
|
+ if let Err(e) = if is_parent {
|
|
+ parent_cursor_move::parent_cursor_move(new_index, context)
|
|
+ } else {
|
|
+ cursor_move::cursor_move(new_index, context)
|
|
+ } {
|
|
+ context.push_msg(e.to_string());
|
|
}
|
|
}
|
|
} else {
|
|
@@ -118,12 +124,14 @@
|
|
FileOp::Copy => "copied",
|
|
FileOp::Cut => "moved",
|
|
};
|
|
- let size_str = format::file_size_to_string(progress.bytes_processed());
|
|
+ let processed_size = format::file_size_to_string(progress.bytes_processed());
|
|
+ let total_size = format::file_size_to_string(progress.total_bytes());
|
|
let msg = format!(
|
|
- "successfully {} {} items ({})",
|
|
+ "successfully {} {} items ({}/{})",
|
|
op,
|
|
- progress.len(),
|
|
- size_str
|
|
+ progress.total_files(),
|
|
+ processed_size,
|
|
+ total_size,
|
|
);
|
|
context.push_msg(msg);
|
|
}
|
|
Только в a/src/util: load_child.rs
|
|
diff -ur a/src/util/mod.rs b/src/util/mod.rs
|
|
--- a/src/util/mod.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/util/mod.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -2,14 +2,13 @@
|
|
pub mod devicons;
|
|
|
|
pub mod display;
|
|
-pub mod event;
|
|
pub mod format;
|
|
pub mod input;
|
|
-pub mod load_child;
|
|
pub mod name_resolution;
|
|
pub mod search;
|
|
pub mod select;
|
|
pub mod sort;
|
|
+pub mod string;
|
|
pub mod style;
|
|
pub mod to_string;
|
|
pub mod unix;
|
|
diff -ur a/src/util/sort.rs b/src/util/sort.rs
|
|
--- a/src/util/sort.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/util/sort.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -1,4 +1,5 @@
|
|
use std::cmp;
|
|
+use std::collections::VecDeque;
|
|
use std::fs;
|
|
use std::time;
|
|
|
|
@@ -6,12 +7,13 @@
|
|
|
|
use crate::fs::JoshutoDirEntry;
|
|
|
|
-#[derive(Clone, Copy, Debug, Deserialize)]
|
|
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
|
|
pub enum SortType {
|
|
Lexical,
|
|
Mtime,
|
|
Natural,
|
|
Size,
|
|
+ Ext,
|
|
}
|
|
|
|
impl SortType {
|
|
@@ -21,6 +23,7 @@
|
|
"mtime" => Some(SortType::Mtime),
|
|
"natural" => Some(SortType::Natural),
|
|
"size" => Some(SortType::Size),
|
|
+ "ext" => Some(SortType::Ext),
|
|
_ => None,
|
|
}
|
|
}
|
|
@@ -30,6 +33,21 @@
|
|
SortType::Mtime => "mtime",
|
|
SortType::Natural => "natural",
|
|
SortType::Size => "size",
|
|
+ SortType::Ext => "ext",
|
|
+ }
|
|
+ }
|
|
+ pub fn cmp(
|
|
+ &self,
|
|
+ f1: &JoshutoDirEntry,
|
|
+ f2: &JoshutoDirEntry,
|
|
+ sort_option: &SortOption,
|
|
+ ) -> cmp::Ordering {
|
|
+ match &self {
|
|
+ SortType::Natural => natural_sort(f1, f2, sort_option),
|
|
+ SortType::Lexical => lexical_sort(f1, f2, sort_option),
|
|
+ SortType::Size => size_sort(f1, f2),
|
|
+ SortType::Mtime => mtime_sort(f1, f2),
|
|
+ SortType::Ext => ext_sort(f1, f2),
|
|
}
|
|
}
|
|
}
|
|
@@ -41,14 +59,61 @@
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
+pub struct SortTypes {
|
|
+ pub list: VecDeque<SortType>,
|
|
+}
|
|
+
|
|
+impl SortTypes {
|
|
+ pub fn reorganize(&mut self, st: SortType) {
|
|
+ self.list.push_front(st);
|
|
+ self.list.pop_back();
|
|
+ }
|
|
+
|
|
+ pub fn cmp(
|
|
+ &self,
|
|
+ f1: &JoshutoDirEntry,
|
|
+ f2: &JoshutoDirEntry,
|
|
+ sort_option: &SortOption,
|
|
+ ) -> cmp::Ordering {
|
|
+ for st in &self.list {
|
|
+ let res = st.cmp(f1, f2, sort_option);
|
|
+ if res != cmp::Ordering::Equal {
|
|
+ return res;
|
|
+ }
|
|
+ }
|
|
+ cmp::Ordering::Equal
|
|
+ }
|
|
+}
|
|
+
|
|
+impl std::default::Default for SortTypes {
|
|
+ fn default() -> Self {
|
|
+ let list: VecDeque<SortType> = vec![
|
|
+ SortType::Natural,
|
|
+ SortType::Lexical,
|
|
+ SortType::Size,
|
|
+ SortType::Ext,
|
|
+ SortType::Mtime,
|
|
+ ]
|
|
+ .into_iter()
|
|
+ .collect();
|
|
+
|
|
+ Self { list }
|
|
+ }
|
|
+}
|
|
+
|
|
+#[derive(Clone, Debug)]
|
|
pub struct SortOption {
|
|
pub directories_first: bool,
|
|
pub case_sensitive: bool,
|
|
pub reverse: bool,
|
|
- pub sort_method: SortType,
|
|
+ pub sort_methods: SortTypes,
|
|
}
|
|
|
|
impl SortOption {
|
|
+ pub fn set_sort_method(&mut self, method: SortType) {
|
|
+ self.sort_methods.reorganize(method);
|
|
+ }
|
|
+
|
|
pub fn compare(&self, f1: &JoshutoDirEntry, f2: &JoshutoDirEntry) -> cmp::Ordering {
|
|
if self.directories_first {
|
|
let f1_isdir = f1.file_path().is_dir();
|
|
@@ -61,40 +126,15 @@
|
|
}
|
|
}
|
|
|
|
- let mut res = match self.sort_method {
|
|
- SortType::Lexical => {
|
|
- let f1_name = f1.file_name();
|
|
- let f2_name = f2.file_name();
|
|
- if self.case_sensitive {
|
|
- f1_name.cmp(&f2_name)
|
|
- } else {
|
|
- let f1_name = f1_name.to_lowercase();
|
|
- let f2_name = f2_name.to_lowercase();
|
|
- f1_name.cmp(&f2_name)
|
|
- }
|
|
- }
|
|
- SortType::Natural => {
|
|
- let f1_name = f1.file_name();
|
|
- let f2_name = f2.file_name();
|
|
- if self.case_sensitive {
|
|
- alphanumeric_sort::compare_str(&f1_name, &f2_name)
|
|
- } else {
|
|
- let f1_name = f1_name.to_lowercase();
|
|
- let f2_name = f2_name.to_lowercase();
|
|
- alphanumeric_sort::compare_str(&f1_name, &f2_name)
|
|
- }
|
|
- }
|
|
- SortType::Mtime => mtime_sort(f1, f2),
|
|
- SortType::Size => size_sort(f1, f2),
|
|
- };
|
|
-
|
|
+ // let mut res = self.sort_method.cmp(f1, f2, &self);
|
|
+ let mut res = self.sort_methods.cmp(f1, f2, &self);
|
|
if self.reverse {
|
|
res = match res {
|
|
cmp::Ordering::Less => cmp::Ordering::Greater,
|
|
cmp::Ordering::Greater => cmp::Ordering::Less,
|
|
s => s,
|
|
};
|
|
- }
|
|
+ };
|
|
res
|
|
}
|
|
}
|
|
@@ -105,7 +145,7 @@
|
|
directories_first: true,
|
|
case_sensitive: false,
|
|
reverse: false,
|
|
- sort_method: SortType::Natural,
|
|
+ sort_methods: SortTypes::default(),
|
|
}
|
|
}
|
|
}
|
|
@@ -120,16 +160,49 @@
|
|
|
|
let f1_mtime: time::SystemTime = f1_meta.modified()?;
|
|
let f2_mtime: time::SystemTime = f2_meta.modified()?;
|
|
-
|
|
- Ok(if f1_mtime >= f2_mtime {
|
|
- cmp::Ordering::Less
|
|
- } else {
|
|
- cmp::Ordering::Greater
|
|
- })
|
|
+ Ok(f1_mtime.cmp(&f2_mtime))
|
|
}
|
|
- compare(&file1, &file2).unwrap_or(cmp::Ordering::Less)
|
|
+ compare(&file1, &file2).unwrap_or(cmp::Ordering::Equal)
|
|
}
|
|
|
|
fn size_sort(file1: &JoshutoDirEntry, file2: &JoshutoDirEntry) -> cmp::Ordering {
|
|
file1.metadata.len().cmp(&file2.metadata.len())
|
|
}
|
|
+
|
|
+fn ext_sort(file1: &JoshutoDirEntry, file2: &JoshutoDirEntry) -> cmp::Ordering {
|
|
+ let f1_ext = file1.get_ext();
|
|
+ let f2_ext = file2.get_ext();
|
|
+ alphanumeric_sort::compare_str(&f1_ext, &f2_ext)
|
|
+}
|
|
+
|
|
+fn lexical_sort(
|
|
+ f1: &JoshutoDirEntry,
|
|
+ f2: &JoshutoDirEntry,
|
|
+ sort_option: &SortOption,
|
|
+) -> cmp::Ordering {
|
|
+ let f1_name = f1.file_name();
|
|
+ let f2_name = f2.file_name();
|
|
+ if sort_option.case_sensitive {
|
|
+ f1_name.cmp(&f2_name)
|
|
+ } else {
|
|
+ let f1_name = f1_name.to_lowercase();
|
|
+ let f2_name = f2_name.to_lowercase();
|
|
+ f1_name.cmp(&f2_name)
|
|
+ }
|
|
+}
|
|
+
|
|
+fn natural_sort(
|
|
+ f1: &JoshutoDirEntry,
|
|
+ f2: &JoshutoDirEntry,
|
|
+ sort_option: &SortOption,
|
|
+) -> cmp::Ordering {
|
|
+ let f1_name = f1.file_name();
|
|
+ let f2_name = f2.file_name();
|
|
+ if sort_option.case_sensitive {
|
|
+ alphanumeric_sort::compare_str(&f1_name, &f2_name)
|
|
+ } else {
|
|
+ let f1_name = f1_name.to_lowercase();
|
|
+ let f2_name = f2_name.to_lowercase();
|
|
+ alphanumeric_sort::compare_str(&f1_name, &f2_name)
|
|
+ }
|
|
+}
|
|
Только в b/src/util: string.rs
|
|
diff -ur a/src/util/style.rs b/src/util/style.rs
|
|
--- a/src/util/style.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/util/style.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -1,6 +1,6 @@
|
|
use tui::style::Style;
|
|
|
|
-use crate::fs::{FileType, JoshutoDirEntry};
|
|
+use crate::fs::{FileType, JoshutoDirEntry, LinkType};
|
|
use crate::util::unix;
|
|
|
|
use crate::THEME_T;
|
|
@@ -8,25 +8,39 @@
|
|
pub fn entry_style(entry: &JoshutoDirEntry) -> Style {
|
|
let metadata = &entry.metadata;
|
|
let filetype = &metadata.file_type();
|
|
+ let linktype = &metadata.link_type();
|
|
|
|
- match filetype {
|
|
- _ if entry.is_selected() => Style::default()
|
|
+ if entry.is_selected() {
|
|
+ Style::default()
|
|
.fg(THEME_T.selection.fg)
|
|
.bg(THEME_T.selection.bg)
|
|
- .add_modifier(THEME_T.selection.modifier),
|
|
- FileType::Directory => Style::default()
|
|
- .fg(THEME_T.directory.fg)
|
|
- .bg(THEME_T.directory.bg)
|
|
- .add_modifier(THEME_T.directory.modifier),
|
|
- FileType::Symlink(_) => Style::default()
|
|
- .fg(THEME_T.link.fg)
|
|
- .bg(THEME_T.link.bg)
|
|
- .add_modifier(THEME_T.link.modifier),
|
|
- _ if unix::is_executable(metadata.mode) => Style::default()
|
|
+ .add_modifier(THEME_T.selection.modifier)
|
|
+ } else {
|
|
+ match linktype {
|
|
+ LinkType::Symlink(_) => Style::default()
|
|
+ .fg(THEME_T.link.fg)
|
|
+ .bg(THEME_T.link.bg)
|
|
+ .add_modifier(THEME_T.link.modifier),
|
|
+ LinkType::Normal => match filetype {
|
|
+ FileType::Directory => Style::default()
|
|
+ .fg(THEME_T.directory.fg)
|
|
+ .bg(THEME_T.directory.bg)
|
|
+ .add_modifier(THEME_T.directory.modifier),
|
|
+ FileType::File => file_style(entry),
|
|
+ },
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+fn file_style(entry: &JoshutoDirEntry) -> Style {
|
|
+ let metadata = &entry.metadata;
|
|
+ if unix::is_executable(metadata.mode) {
|
|
+ Style::default()
|
|
.fg(THEME_T.executable.fg)
|
|
.bg(THEME_T.executable.bg)
|
|
- .add_modifier(THEME_T.executable.modifier),
|
|
- _ => match entry.file_path().extension() {
|
|
+ .add_modifier(THEME_T.executable.modifier)
|
|
+ } else {
|
|
+ match entry.file_path().extension() {
|
|
None => Style::default(),
|
|
Some(os_str) => match os_str.to_str() {
|
|
None => Style::default(),
|
|
@@ -35,6 +49,6 @@
|
|
Some(t) => Style::default().fg(t.fg).bg(t.bg).add_modifier(t.modifier),
|
|
},
|
|
},
|
|
- },
|
|
+ }
|
|
}
|
|
}
|
|
diff -ur a/src/util/to_string.rs b/src/util/to_string.rs
|
|
--- a/src/util/to_string.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/util/to_string.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -30,9 +30,8 @@
|
|
|
|
impl ToString for MouseEvent {
|
|
fn to_string(&self) -> String {
|
|
- match *self {
|
|
- k => format!("{:?}", k),
|
|
- }
|
|
+ let k = *self;
|
|
+ format!("{:?}", k)
|
|
}
|
|
}
|
|
|
|
diff -ur a/src/util/unix.rs b/src/util/unix.rs
|
|
--- a/src/util/unix.rs 2021-05-08 03:04:44.000000000 +0300
|
|
+++ b/src/util/unix.rs 2021-08-07 11:25:14.715474131 +0300
|
|
@@ -1,5 +1,3 @@
|
|
-use std::path::Path;
|
|
-
|
|
pub fn is_executable(mode: u32) -> bool {
|
|
const LIBC_PERMISSION_VALS: [libc::mode_t; 3] = [libc::S_IXUSR, libc::S_IXGRP, libc::S_IXOTH];
|
|
|
|
@@ -51,13 +49,3 @@
|
|
}
|
|
mode_str
|
|
}
|
|
-
|
|
-pub fn set_mode(path: &Path, mode: u32) {
|
|
- let os_path = path.as_os_str();
|
|
- if let Some(s) = os_path.to_str() {
|
|
- let svec: Vec<libc::c_char> = s.bytes().map(|ch| ch as libc::c_char).collect();
|
|
- unsafe {
|
|
- libc::chmod(svec.as_ptr(), mode as libc::mode_t);
|
|
- }
|
|
- }
|
|
-}
|