gentoo-overlay/app-misc/joshuto/files/72aaf0c5d10db0004d48e27c58d...

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);
- }
- }
-}