diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b75ba..863aa97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ ## Unreleased +## v2.12.0 (2024-01-28) + +### Added + +- `:config` to point to the config file if exists. +- felix listens to the change of the config file, and re-read the config automatically (after some key inputs). + +### Changed + +- Refactor around `_run` and `State::new()`. + - Add `config_path` field to `State`. + +### Fixed + +- symlink path and operations with it on Windows. + ## v2.11.1 (2023-12-10) ### Fixed @@ -34,7 +50,7 @@ - Add `FxError::InvalidPath` to handle invalid unicode in file path. ## v2.9.0 (2023-10-22) - + ### Added - Change color of untracked/changed files or directories containing such files. Default color is Red(1). You can change it in the config file. - Add `git2`. diff --git a/Cargo.lock b/Cargo.lock index 9ed4309..743e08a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,9 +54,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "block-buffer" @@ -127,14 +127,14 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets", + "windows-targets 0.52.0", ] [[package]] @@ -164,15 +164,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -188,9 +188,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4939f9ed1444bd8c896d37f3090012fa6e7834fe84ef8c9daa166109515732f9" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -203,36 +203,28 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crossterm" @@ -271,9 +263,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] @@ -313,7 +305,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -328,9 +320,19 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "felix" -version = "2.11.1" +version = "2.12.0" dependencies = [ "bwrap", "chrono", @@ -357,14 +359,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys", + "redox_syscall", + "windows-sys 0.52.0", ] [[package]] @@ -379,9 +381,9 @@ dependencies = [ [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -398,9 +400,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -413,7 +415,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "libgit2-sys", "log", @@ -422,9 +424,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "hmac" @@ -437,9 +439,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -460,9 +462,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -489,9 +491,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" @@ -504,18 +506,18 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.149" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libgit2-sys" @@ -529,11 +531,22 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] + [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" dependencies = [ "cc", "libc", @@ -541,6 +554,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "lock_api" version = "0.4.11" @@ -569,9 +588,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memoffset" @@ -582,15 +601,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -602,14 +612,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -627,7 +637,7 @@ dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "memoffset 0.7.1", + "memoffset", "pin-utils", ] @@ -651,9 +661,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "option-ext" @@ -679,9 +689,9 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -709,9 +719,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-utils" @@ -721,9 +731,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "powerfmt" @@ -733,18 +743,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -757,9 +767,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "rayon" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -767,32 +777,14 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -804,20 +796,33 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] +[[package]] +name = "rustix" +version = "0.38.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -836,18 +841,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.190" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.190" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", @@ -856,9 +861,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.27" +version = "0.9.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" +checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" dependencies = [ "indexmap", "itoa", @@ -932,9 +937,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "subtle" @@ -944,9 +949,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.38" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -975,18 +980,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", @@ -995,9 +1000,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -1017,9 +1022,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -1047,9 +1052,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -1074,15 +1079,15 @@ checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unsafe-libyaml" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -1119,9 +1124,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1129,9 +1134,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", @@ -1144,9 +1149,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1154,9 +1159,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", @@ -1167,9 +1172,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "winapi" @@ -1204,11 +1209,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", ] [[package]] @@ -1217,7 +1222,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -1226,13 +1240,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -1241,49 +1270,93 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "xattr" -version = "1.0.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", + "linux-raw-sys", + "rustix", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ab06d2f..0cc00fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "felix" -version = "2.11.1" +version = "2.12.0" authors = ["Kyohei Uto "] edition = "2021" description = "tui file manager with vim-like key mapping" diff --git a/README.md b/README.md index 17fe256..dc36516 100644 --- a/README.md +++ b/README.md @@ -25,35 +25,21 @@ For more detailed document, visit https://kyoheiu.dev/felix. ## New release -## v2.11.1 (2023-12-10) - -### Fixed - -- Allow SHIFT key to enter characters after `i`, `I`, `c`, `/`, `:` and `z`. - -## v2.11.0 (2023-12-09) +## v2.12.0 (2024-01-28) ### Added -- `` for Backspace functionality after `i`, `I`, `c`, `/`, `:` and `z`. +- `:config` to point to the config file if exists. +- felix listens to the change of the config file, and re-read the config automatically (after some key inputs). -## v2.10.2 (2023-11-26) +### Changed -### Fixed -- Added a filter to every user input to reject `Keyup` events. This is required on the windows platform. - - -## v2.10.1 (2023-11-02) +- Refactor around `_run` and `State::new()`. + - Add `config_path` field to `State`. ### Fixed -- Convert tab to 4 spaces when using bat to preview text files. -## v2.10.0 (2023-11-01) - -### Added -- `bat` integration: If `bat` installed, felix automatically adds syntax highlighting to the text preview. - - Add `has_bat` field to `State`. - - Add `FxError::InvalidPath` to handle invalid unicode in file path. +- symlink path and operations with it on Windows. For more details, see `CHANGELOG.md`. @@ -203,6 +189,7 @@ N :Go backward to the item that matches the keyword. :cd :Go to the home directory. :cd {path} :Go to the path. :e :Reload the current directory. +:config :Go to the dirctory that contains the config file if exists. :trash :Go to the trash directory. :empty :Empty the trash directory. :h :Show help. diff --git a/src/config.rs b/src/config.rs index de8e6d7..ca20ffd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,51 +9,11 @@ pub const FELIX: &str = "felix"; const CONFIG_FILE: &str = "config.yaml"; const CONFIG_FILE_ANOTHER_EXT: &str = "config.yml"; -#[allow(dead_code)] -const CONFIG_EXAMPLE: &str = r###" -# Default exec command when open files. -# If not set, will default to $EDITOR. -# default: nvim - -# Whether to match the behavior of vim exit keybindings -# i.e. `ZQ` exits without cd to LWD (Last Working Directory) while `ZZ` cd to LWD -# match_vim_exit_behavior: false - -# key (the command you want to use when opening files): [values] (extensions) -# In the key, You can use arguments. -# exec: -# zathura: -# [pdf] -# 'feh -.': -# [jpg, jpeg, png, gif, svg, hdr] - -# The foreground color of directory, file and symlink. -# Pick one of the following: -# Black // 0 -# Red // 1 -# Green // 2 -# Yellow // 3 -# Blue // 4 -# Magenta // 5 -# Cyan // 6 -# White // 7 -# LightBlack // 8 -# LightRed // 9 -# LightGreen // 10 -# LightYellow // 11 -# LightBlue // 12 -# LightMagenta // 13 -# LightCyan // 14 -# LightWhite // 15 -# Rgb(u8, u8, u8) -# AnsiValue(u8) -# Default to LightCyan(dir), LightWhite(file), LightYellow(symlink) and Red(changed/untracked files in git repositories). -# color: -# dir_fg: LightCyan -# file_fg: LightWhite -# symlink_fg: LightYellow -# dirty_fg: Red -"###; +#[derive(Debug, Clone)] +pub struct ConfigWithPath { + pub config_path: Option, + pub config: Config, +} #[derive(Deserialize, Debug, Clone)] pub struct Config { @@ -115,13 +75,16 @@ impl Default for Config { } } -fn read_config(p: &Path) -> Result { +pub fn read_config(p: &Path) -> Result { let s = read_to_string(p)?; let deserialized: Config = serde_yaml::from_str(&s)?; - Ok(deserialized) + Ok(ConfigWithPath { + config_path: Some(p.to_path_buf()), + config: deserialized, + }) } -pub fn read_config_or_default() -> Result { +pub fn read_config_or_default() -> Result { //First, declare default config file path. let (config_file_path1, config_file_path2) = { let mut config_path = { @@ -172,6 +135,9 @@ pub fn read_config_or_default() -> Result { if let Some(config_file) = config_file { read_config(&config_file) } else { - Ok(Config::default()) + Ok(ConfigWithPath { + config_path: None, + config: Config::default(), + }) } } diff --git a/src/help.rs b/src/help.rs index fa49c0d..1a38b6c 100644 --- a/src/help.rs +++ b/src/help.rs @@ -68,6 +68,7 @@ N :Go backward to the item that matches the keyword. :cd :Go to the home directory. :cd {path} :Go to the path. :e :Reload the current directory. +:config :Go to the directory that contains the config file if exists. :trash :Go to the trash directory. :empty :Empty the trash directory. :h :Show help. diff --git a/src/layout.rs b/src/layout.rs index 40502e7..0cad56c 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -2,10 +2,11 @@ use super::config::*; use super::errors::FxError; use super::functions::*; use super::nums::*; -use super::session::SortKey; +use super::session::{read_session, SortKey}; use super::state::{ItemInfo, BEGINNING_ROW}; use super::term::*; +use log::error; use serde::{Deserialize, Serialize}; pub const MAX_SIZE_TO_PREVIEW: u64 = 1_000_000_000; @@ -16,7 +17,7 @@ pub const PROPER_WIDTH: u16 = 28; pub const TIME_WIDTH: u16 = 16; const EXTRA_SPACES: u16 = 3; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Layout { pub nums: Num, pub y: u16, @@ -46,20 +47,67 @@ pub enum PreviewType { Binary, } -#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone)] +#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Default)] pub enum Side { + #[default] Preview, Reg, None, } -#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone, Copy, Default)] pub enum Split { + #[default] Vertical, Horizontal, } impl Layout { + pub fn new(session_path: &std::path::Path, config: Config) -> Result { + let (original_column, original_row) = terminal_size()?; + // Return error if terminal size may cause panic + if original_column < 4 { + error!("Too small terminal size (less than 4 columns)."); + return Err(FxError::TooSmallWindowSize); + }; + if original_row < 4 { + error!("Too small terminal size. (less than 4 rows)"); + return Err(FxError::TooSmallWindowSize); + }; + + // Prepare state fields. + let (time_start, name_max) = make_layout(original_column); + let session = read_session(session_path); + let split = session.split.unwrap_or_default(); + let has_bat = check_bat(); + let has_chafa = check_chafa(); + let is_kitty = check_kitty_support(); + + let colors = config.color.unwrap_or_default(); + + Ok(Layout { + nums: Num::new(), + y: BEGINNING_ROW, + terminal_row: original_row, + terminal_column: original_column, + name_max_len: name_max, + time_start_pos: time_start, + sort_by: session.sort_by, + show_hidden: session.show_hidden, + side: match session.preview.unwrap_or(false) { + true => Side::Preview, + false => Side::None, + }, + split, + preview_start: (0, 0), + preview_space: (0, 0), + has_bat, + has_chafa, + is_kitty, + colors, + }) + } + pub fn is_preview(&self) -> bool { self.side == Side::Preview } @@ -364,3 +412,28 @@ pub fn make_layout(column: u16) -> (u16, usize) { (time_start, name_max) } } + +/// Check if bat is installed. +fn check_bat() -> bool { + std::process::Command::new("bat") + .arg("--help") + .output() + .is_ok() +} + +/// Check if chafa is installed. +fn check_chafa() -> bool { + std::process::Command::new("chafa") + .arg("--help") + .output() + .is_ok() +} + +/// Check if the terminal is Kitty or not +fn check_kitty_support() -> bool { + if let Ok(term) = std::env::var("TERM") { + term.contains("kitty") + } else { + false + } +} diff --git a/src/nums.rs b/src/nums.rs index 4b7720f..3aa05af 100644 --- a/src/nums.rs +++ b/src/nums.rs @@ -1,4 +1,4 @@ -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Num { pub index: usize, pub skip: u16, diff --git a/src/op.rs b/src/op.rs index d2a54ed..0590a28 100644 --- a/src/op.rs +++ b/src/op.rs @@ -3,7 +3,7 @@ use super::state::ItemBuffer; use log::info; use std::path::PathBuf; -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct Operation { pub pos: usize, pub op_list: Vec, diff --git a/src/run.rs b/src/run.rs index f551bb2..7ff0881 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,5 +1,4 @@ -#![allow(unreachable_code)] -use super::config::FELIX; +use super::config::{read_config, FELIX}; use super::errors::FxError; use super::functions::*; use super::layout::{PreviewType, Split}; @@ -18,6 +17,8 @@ use std::env; use std::io::{stdout, Write}; use std::panic; use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::thread; use std::time::Instant; const TRASH: &str = "Trash"; @@ -27,6 +28,11 @@ const SCROLL_POINT: u16 = 3; const CLRSCR: &str = "\x1B[2J"; const INITIAL_POS_COMMAND_LINE: u16 = 3; const INITIAL_POS_Z: u16 = 2; +const PROMPT_INSERT_FILE: &str = "New file: "; +const PROMPT_INSERT_DIR: &str = "New directory: "; +const PROMPT_RENAME: &str = "New name: "; +const PROMPT_SEARCH: &str = "/"; +const PROMPT_COMMAND_LINE: &str = ":"; /// Launch the app. If initialization goes wrong, return error. pub fn run(arg: PathBuf, log: bool) -> Result<(), FxError> { @@ -108,7 +114,7 @@ pub fn run(arg: PathBuf, log: bool) -> Result<(), FxError> { path }; - //Initialize app state. Inside State::new(), config file is read or created. + //Initialize app state. Inside `State::new()`, config file is read. let mut state = State::new(&session_path)?; state.trash_dir = trash_dir_path; state.lwd_file = lwd_file_path; @@ -169,7 +175,55 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } screen.flush()?; + // Spawn another thread to watch the config file. + let mut modified_time = match &state.config_path { + Some(config_path) => config_path.metadata().unwrap().modified().ok(), + None => None, + }; + let wait_update = Arc::new(Mutex::new(false)); + let wait_update_clone = wait_update.clone(); + let config_path_clone = state.config_path.clone(); + // if config file does not exist, no watching. + if modified_time.is_some() { + // Every 2 secondes, check if the config file is updated. + thread::spawn(move || loop { + thread::sleep(std::time::Duration::from_secs(2)); + if *wait_update_clone.lock().unwrap() { + continue; + } + let metadata = config_path_clone.as_ref().unwrap().metadata(); + if let Ok(metadata) = metadata { + let new_modified = metadata.modified().ok(); + if modified_time != new_modified { + if let Ok(mut updated) = wait_update_clone.lock() { + *updated = true; + modified_time = new_modified; + } else { + break; + } + } + } + }); + } + 'main: loop { + // Check if config file is updated + if state.config_path.is_some() { + if let Ok(mut wait_update) = wait_update.lock() { + if *wait_update { + if let Ok(c) = read_config(state.config_path.as_ref().unwrap()) { + state.set_config(c.config); + state.redraw(state.layout.y); + print_info("New config set.", state.layout.y); + } else { + // If reading the config file fails, leave the config as is. + print_warning("Something wrong with the config file.", state.layout.y); + } + *wait_update = false; + } + } + } + if state.is_out_of_bounds() { state.layout.nums.reset(); state.redraw(BEGINNING_ROW); @@ -405,9 +459,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } _ => { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); } } } @@ -648,9 +700,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { { match (code, modifiers) { (KeyCode::Esc, KeyModifiers::NONE) => { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); break 'zoxide; } @@ -675,9 +725,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { (KeyCode::Backspace, KeyModifiers::NONE) | (KeyCode::Char('h'), KeyModifiers::CONTROL) => { if current_pos == INITIAL_POS_Z + 1 { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); break 'zoxide; }; command.remove( @@ -794,15 +842,18 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { let is_dir = code == KeyCode::Char('I'); delete_pointer(); go_to_info_line_and_reset(); - // No need to place sign of the insert mode - print!(" "); + if is_dir { + print!("{}", PROMPT_INSERT_DIR); + } else { + print!("{}", PROMPT_INSERT_FILE); + } show_cursor(); screen.flush()?; let mut new_name: Vec = Vec::new(); // express position in terminal - let mut current_pos = INITIAL_POS_COMMAND_LINE; + let (mut current_pos, _) = cursor_pos()?; // express position in Vec let mut current_char_pos = 0; 'insert: loop { @@ -846,13 +897,24 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } } go_to_info_line_and_reset(); - print!( - " {}", - &new_name - .iter() - .collect::(), - ); - move_to(current_pos, 2); + if is_dir { + print!( + "{}{}", + PROMPT_INSERT_DIR, + &new_name + .iter() + .collect::(), + ); + } else { + print!( + "{}{}", + PROMPT_INSERT_FILE, + &new_name + .iter() + .collect::(), + ); + } + move_to(current_pos + 1, 2); screen.flush()?; continue; } else { @@ -865,40 +927,24 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } (KeyCode::Esc, KeyModifiers::NONE) => { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); break 'insert; } (KeyCode::Left, KeyModifiers::NONE) => { - if current_char_pos == 0 { - continue; - }; - if let Some(to_be_skipped) = - unicode_width::UnicodeWidthChar::width( - new_name[current_char_pos - 1], - ) - { - current_char_pos -= 1; - current_pos -= to_be_skipped as u16; - move_left(to_be_skipped as u16); - } + move_left_command_line( + &mut new_name, + &mut current_char_pos, + &mut current_pos, + ) } (KeyCode::Right, KeyModifiers::NONE) => { - if current_char_pos == new_name.len() { - continue; - }; - if let Some(to_be_skipped) = - unicode_width::UnicodeWidthChar::width( - new_name[current_char_pos], - ) - { - current_char_pos += 1; - current_pos += to_be_skipped as u16; - move_right(to_be_skipped as u16); - } + move_right_command_line( + &mut new_name, + &mut current_char_pos, + &mut current_pos, + ) } (KeyCode::Backspace, KeyModifiers::NONE) @@ -914,11 +960,51 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { current_pos -= to_be_removed as u16; go_to_info_line_and_reset(); - print!( - " {}", - &new_name.iter().collect::(), - ); - move_to(current_pos, 2); + if is_dir { + print!( + "{}{}", + PROMPT_INSERT_DIR, + &new_name.iter().collect::(), + ); + } else { + print!( + "{}{}", + PROMPT_INSERT_FILE, + &new_name.iter().collect::(), + ); + } + move_to(current_pos + 1, 2); + } + } + + (KeyCode::Char(c), _) => { + if let Some(to_be_added) = + unicode_width::UnicodeWidthChar::width(c) + { + if current_pos + to_be_added as u16 + > state.layout.terminal_column + { + continue; + } + new_name.insert(current_char_pos, c); + current_char_pos += 1; + current_pos += to_be_added as u16; + + go_to_info_line_and_reset(); + if is_dir { + print!( + "{}{}", + PROMPT_INSERT_DIR, + &new_name.iter().collect::(), + ); + } else { + print!( + "{}{}", + PROMPT_INSERT_FILE, + &new_name.iter().collect::(), + ); + } + move_to(current_pos + 1, 2); } } @@ -946,28 +1032,6 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { break 'insert; } - (KeyCode::Char(c), _) => { - if let Some(to_be_added) = - unicode_width::UnicodeWidthChar::width(c) - { - if current_pos + to_be_added as u16 - > state.layout.terminal_column - { - continue; - } - new_name.insert(current_char_pos, c); - current_char_pos += 1; - current_pos += to_be_added as u16; - - go_to_info_line_and_reset(); - print!( - " {}", - &new_name.iter().collect::(), - ); - move_to(current_pos, 2); - } - } - _ => continue, } screen.flush()?; @@ -1107,9 +1171,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } } _ => { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); } } } @@ -1152,20 +1214,17 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { None, false, ); - go_to_info_line_and_reset(); - hide_cursor(); + state.escape(); print_info("1 item yanked.", state.layout.y); } } _ => { - go_to_info_line_and_reset(); - hide_cursor(); + state.escape(); } } } } - state.move_cursor(state.layout.y); } //put @@ -1195,7 +1254,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { let mut rename = item.file_name.chars().collect::>(); to_info_line(); clear_current_line(); - print!("New name: {}", &rename.iter().collect::(),); + print!("{}{}", PROMPT_RENAME, &rename.iter().collect::(),); screen.flush()?; let (mut current_pos, _) = cursor_pos()?; @@ -1209,67 +1268,74 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { }) = event::read()? { match (code, modifiers) { - //rename item - (KeyCode::Enter, KeyModifiers::NONE) => { - let rename = rename.iter().collect::(); - let mut to = state.current_dir.clone(); - to.push(rename); - if let Err(e) = - std::fs::rename(&item.file_path, &to) + // to put the item name(s) from register + (KeyCode::Char('r'), KeyModifiers::CONTROL) => { + if let Event::Key(KeyEvent { + code, + kind: KeyEventKind::Press, + .. + }) = event::read()? { - hide_cursor(); - print_warning(e, state.layout.y); - break; + if let Some(reg) = + state.registers.check_reg(&code) + { + if !reg.is_empty() { + let to_be_inserted = reg + .iter() + .map(|x| x.file_name.clone()) + .collect::>() + .join(" "); + for c in to_be_inserted.chars() { + if let Some(to_be_added) = + unicode_width::UnicodeWidthChar::width(c) + { + if current_pos + to_be_added as u16 + > state.layout.terminal_column + { + continue; + } + rename.insert(current_char_pos, c); + current_char_pos += 1; + current_pos += to_be_added as u16; + } + } + go_to_info_line_and_reset(); + print!( + "{}{}", + PROMPT_RENAME, + &rename.iter().collect::() + ); + move_to(current_pos + 1, 2); + screen.flush()?; + continue; + } else { + continue; + } + } else { + continue; + } } - - state.operations.branch(); - state.operations.push(OpKind::Rename( - RenamedFile { - original_name: item.file_path.clone(), - new_name: to, - }, - )); - - hide_cursor(); - state.reload(state.layout.y)?; - break; } (KeyCode::Esc, KeyModifiers::NONE) => { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); break; } (KeyCode::Left, KeyModifiers::NONE) => { - if current_char_pos == 0 { - continue; - }; - if let Some(to_be_skipped) = - unicode_width::UnicodeWidthChar::width( - rename[current_char_pos - 1], - ) - { - current_char_pos -= 1; - current_pos -= to_be_skipped as u16; - move_left(to_be_skipped as u16); - } + move_left_command_line( + &mut rename, + &mut current_char_pos, + &mut current_pos, + ) } (KeyCode::Right, KeyModifiers::NONE) => { - if current_char_pos == rename.len() { - continue; - }; - if let Some(to_be_skipped) = - unicode_width::UnicodeWidthChar::width( - rename[current_char_pos], - ) - { - current_char_pos += 1; - current_pos += to_be_skipped as u16; - move_right(to_be_skipped as u16); - } + move_right_command_line( + &mut rename, + &mut current_char_pos, + &mut current_pos, + ) } (KeyCode::Backspace, KeyModifiers::NONE) @@ -1286,7 +1352,8 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { go_to_info_line_and_reset(); print!( - "New name: {}", + "{}{}", + PROMPT_RENAME, &rename.iter().collect::(), ); move_to(current_pos + 1, 2); @@ -1303,13 +1370,39 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { go_to_info_line_and_reset(); print!( - "New name: {}", + "{}{}", + PROMPT_RENAME, &rename.iter().collect::(), ); move_to(current_pos + 1, 2); } } + (KeyCode::Enter, KeyModifiers::NONE) => { + let rename = rename.iter().collect::(); + let mut to = state.current_dir.clone(); + to.push(rename); + if let Err(e) = + std::fs::rename(&item.file_path, &to) + { + hide_cursor(); + print_warning(e, state.layout.y); + break; + } + + state.operations.branch(); + state.operations.push(OpKind::Rename( + RenamedFile { + original_name: item.file_path.clone(), + new_name: to, + }, + )); + + hide_cursor(); + state.reload(state.layout.y)?; + break; + } + _ => continue, } screen.flush()?; @@ -1330,7 +1423,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { delete_pointer(); show_cursor(); go_to_info_line_and_reset(); - print!("/"); + print!("{}", PROMPT_SEARCH); screen.flush()?; let original_nums = state.layout.nums; @@ -1350,13 +1443,6 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { }) = event::read()? { match (code, modifiers) { - (KeyCode::Enter, KeyModifiers::NONE) => { - go_to_info_line_and_reset(); - state.keyword = Some(keyword.iter().collect()); - state.move_cursor(state.layout.y); - break; - } - (KeyCode::Esc, KeyModifiers::NONE) => { hide_cursor(); state.redraw(state.layout.y); @@ -1364,33 +1450,19 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } (KeyCode::Left, KeyModifiers::NONE) => { - if current_char_pos == 0 { - continue; - }; - if let Some(to_be_skipped) = - unicode_width::UnicodeWidthChar::width( - keyword[current_char_pos - 1], - ) - { - current_char_pos -= 1; - current_pos -= to_be_skipped as u16; - move_left(to_be_skipped as u16); - } + move_left_command_line( + &mut keyword, + &mut current_char_pos, + &mut current_pos, + ); } (KeyCode::Right, KeyModifiers::NONE) => { - if current_char_pos == keyword.len() { - continue; - }; - if let Some(to_be_skipped) = - unicode_width::UnicodeWidthChar::width( - keyword[current_char_pos], - ) - { - current_char_pos += 1; - current_pos += to_be_skipped as u16; - move_right(to_be_skipped as u16); - } + move_right_command_line( + &mut keyword, + &mut current_char_pos, + &mut current_pos, + ); } (KeyCode::Backspace, KeyModifiers::NONE) @@ -1427,7 +1499,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } } go_to_info_line_and_reset(); - print!("/{}", key.clone()); + print!("{}{}", PROMPT_SEARCH, key); move_to(current_pos, 2); } } @@ -1468,11 +1540,18 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } go_to_info_line_and_reset(); - print!("/{}", key.clone()); + print!("{}{}", PROMPT_SEARCH, key); move_to(current_pos, 2); } } + (KeyCode::Enter, KeyModifiers::NONE) => { + go_to_info_line_and_reset(); + state.keyword = Some(keyword.iter().collect()); + state.move_cursor(state.layout.y); + break; + } + _ => continue, } screen.flush()?; @@ -1561,9 +1640,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { { match code { KeyCode::Esc => { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); break 'reg; } @@ -1588,9 +1665,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { KeyCode::Backspace => { if current_pos == INITIAL_POS_COMMAND_LINE { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); break 'reg; } else { command.remove( @@ -1635,13 +1710,11 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { "p" => { //In read-only directory, put disabled if state.is_ro { - go_to_info_line_and_reset(); + state.escape(); print_warning( "Cannot put item in this directory.", state.layout.y, ); - hide_cursor(); - state.move_cursor(state.layout.y); break 'reg; } if state.v_start.is_some() { @@ -1720,13 +1793,11 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { state.move_cursor(state.layout.y); break 'reg; } - go_to_info_line_and_reset(); - hide_cursor(); + state.escape(); print_info( "1 item yanked.", state.layout.y, ); - state.move_cursor(state.layout.y); break 'reg; } //yank (visual mode) @@ -1784,13 +1855,11 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { //In read-only directory, delete //disabled if state.is_ro { - go_to_info_line_and_reset(); + state.escape(); print_warning( "Cannot delete item in this directory.", state.layout.y, ); - hide_cursor(); - state.move_cursor(state.layout.y); break 'reg; } if state.v_start.is_some() { @@ -1835,13 +1904,11 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { //In read-only directory, delete //disabled if state.is_ro { - go_to_info_line_and_reset(); + state.escape(); print_warning( "Cannot delete item in this directory.", state.layout.y, ); - hide_cursor(); - state.move_cursor(state.layout.y); break 'reg; } if state.v_start.is_none() { @@ -1924,7 +1991,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } delete_pointer(); go_to_info_line_and_reset(); - print!(":"); + print!("{}", PROMPT_COMMAND_LINE); show_cursor(); screen.flush()?; @@ -1975,7 +2042,8 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } go_to_info_line_and_reset(); print!( - ":{}", + "{}{}", + PROMPT_COMMAND_LINE, &command.iter().collect::(), ); move_to(current_pos, 2); @@ -1991,40 +2059,24 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } (KeyCode::Esc, KeyModifiers::NONE) => { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); break 'command; } (KeyCode::Left, KeyModifiers::NONE) => { - if current_char_pos == 0 { - continue; - }; - if let Some(to_be_skipped) = - unicode_width::UnicodeWidthChar::width( - command[current_char_pos - 1], - ) - { - current_char_pos -= 1; - current_pos -= to_be_skipped as u16; - move_left(to_be_skipped as u16); - } + move_left_command_line( + &mut command, + &mut current_char_pos, + &mut current_pos, + ); } (KeyCode::Right, KeyModifiers::NONE) => { - if current_char_pos == command.len() { - continue; - }; - if let Some(to_be_skipped) = - unicode_width::UnicodeWidthChar::width( - command[current_char_pos], - ) - { - current_char_pos += 1; - current_pos += to_be_skipped as u16; - move_right(to_be_skipped as u16); - } + move_right_command_line( + &mut command, + &mut current_char_pos, + &mut current_pos, + ); } (KeyCode::Backspace, KeyModifiers::NONE) @@ -2041,7 +2093,31 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { go_to_info_line_and_reset(); print!( - ":{}", + "{}{}", + PROMPT_COMMAND_LINE, + &command.iter().collect::(), + ); + move_to(current_pos, 2); + } + } + + (KeyCode::Char(c), _) => { + if let Some(to_be_added) = + unicode_width::UnicodeWidthChar::width(c) + { + if current_pos + to_be_added as u16 + > state.layout.terminal_column + { + continue; + } + command.insert(current_char_pos, c); + current_char_pos += 1; + current_pos += to_be_added as u16; + + go_to_info_line_and_reset(); + print!( + "{}{}", + PROMPT_COMMAND_LINE, &command.iter().collect::(), ); move_to(current_pos, 2); @@ -2055,80 +2131,111 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { let commands: Vec<&str> = commands.split_whitespace().collect(); if commands.is_empty() { - go_to_info_line_and_reset(); - state.move_cursor(state.layout.y); + state.escape(); break; } let command = commands[0]; if commands.len() == 1 { - if command == "q" { - //quit - break 'main; - } else if command == "cd" || command == "z" { - //go to the home directory - let home_dir = dirs::home_dir() - .ok_or_else(|| { - FxError::Dirs( - "Cannot read home dir." - .to_string(), - ) - })?; - if let Err(e) = - state.chdir(&home_dir, Move::Jump) - { - print_warning(e, state.layout.y); + match command { + "q" => { + //quit + break 'main; } - break 'command; - } else if command == "e" { - //reload current dir - state.keyword = None; - state.layout.nums.reset(); - state.reload(BEGINNING_ROW)?; - break 'command; - } else if command == "h" { - //show help - state.show_help(&screen)?; - state.redraw(state.layout.y); - break 'command; - } else if command == "reg" { - //:reg - Show registers - if state.layout.is_preview() { - state.layout.show_reg(); + "cd" | "z" => { + //go to the home directory + let home_dir = dirs::home_dir() + .ok_or_else(|| { + FxError::Dirs( + "Cannot read home dir." + .to_string(), + ) + })?; + if let Err(e) = + state.chdir(&home_dir, Move::Jump) + { + print_warning(e, state.layout.y); + } + break 'command; + } + "e" => { + //reload current dir + state.keyword = None; + state.layout.nums.reset(); + state.reload(BEGINNING_ROW)?; + break 'command; + } + "h" => { + //show help + state.show_help(&screen)?; state.redraw(state.layout.y); - } else if state.layout.is_reg() { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); - } else { - state.layout.show_reg(); - let (new_column, new_row) = state - .layout - .update_column_and_row()?; - state.refresh( - new_column, - new_row, - state.layout.y, - )?; - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + break 'command; } - break 'command; - } else if command == "trash" { - //move to trash dir - state.layout.nums.reset(); - if let Err(e) = state.chdir( - &(state.trash_dir.clone()), - Move::Jump, - ) { - print_warning(e, state.layout.y); + "reg" => { + //:reg - Show registers + if state.layout.is_preview() { + state.layout.show_reg(); + state.redraw(state.layout.y); + } else if state.layout.is_reg() { + state.escape(); + } else { + state.layout.show_reg(); + let (new_column, new_row) = state + .layout + .update_column_and_row()?; + state.refresh( + new_column, + new_row, + state.layout.y, + )?; + state.escape(); + } + break 'command; } - break 'command; - } else if command == "empty" { - //empty the trash dir - state.empty_trash(&screen)?; - break 'command; + "trash" => { + //move to trash dir + state.layout.nums.reset(); + if let Err(e) = state.chdir( + &(state.trash_dir.clone()), + Move::Jump, + ) { + print_warning(e, state.layout.y); + } + break 'command; + } + "empty" => { + //empty the trash dir + state.empty_trash(&screen)?; + break 'command; + } + "config" => { + //move to the directory that contains + //config path + state.layout.nums.reset(); + if let Some(ref config_path) = + state.config_path + { + if let Err(e) = state.chdir( + config_path + .clone() + .parent() + .unwrap(), + Move::Jump, + ) { + print_warning( + e, + state.layout.y, + ); + } + } else { + print_warning( + "Cannot find the config path.", + state.layout.y, + ) + } + break 'command; + } + _ => {} } } else if commands.len() == 2 && command == "cd" { if let Ok(target) = @@ -2206,28 +2313,6 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { break 'command; } - (KeyCode::Char(c), _) => { - if let Some(to_be_added) = - unicode_width::UnicodeWidthChar::width(c) - { - if current_pos + to_be_added as u16 - > state.layout.terminal_column - { - continue; - } - command.insert(current_char_pos, c); - current_char_pos += 1; - current_pos += to_be_added as u16; - - go_to_info_line_and_reset(); - print!( - ":{}", - &command.iter().collect::(), - ); - move_to(current_pos, 2); - } - } - _ => continue, } screen.flush()?; @@ -2318,9 +2403,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } _ => { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + state.escape(); } } } diff --git a/src/session.rs b/src/session.rs index 2b3ad01..f3ac3a6 100644 --- a/src/session.rs +++ b/src/session.rs @@ -18,8 +18,9 @@ pub struct Session { pub split: Option, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, Default)] pub enum SortKey { + #[default] Name, Time, } diff --git a/src/state.rs b/src/state.rs index 7cfecf6..6b0ec76 100644 --- a/src/state.rs +++ b/src/state.rs @@ -15,7 +15,7 @@ use chrono::prelude::*; use crossterm::event::KeyEventKind; use crossterm::event::{Event, KeyCode, KeyEvent}; use crossterm::style::Stylize; -use log::{error, info}; +use log::info; use std::collections::VecDeque; use std::collections::{BTreeMap, BTreeSet}; use std::env; @@ -40,13 +40,13 @@ use std::os::unix::fs::PermissionsExt; pub const BEGINNING_ROW: u16 = 3; pub const EMPTY_WARNING: &str = "Are you sure to empty the trash directory? (if yes: y)"; -const BASE32: &[u8; 32] = b"0123456789ABCDEFGHJKMNPQRSTVWXYZ"; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct State { pub list: Vec, pub current_dir: PathBuf, pub trash_dir: PathBuf, + pub config_path: Option, pub lwd_file: Option, pub match_vim_exit_behavior: bool, pub has_zoxide: bool, @@ -63,7 +63,7 @@ pub struct State { pub is_ro: bool, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Registers { pub unnamed: Vec, pub zero: Vec, @@ -235,102 +235,38 @@ impl State { pub fn new(session_path: &std::path::Path) -> Result { //Read config file. //Use default configuration if the file does not exist or cannot be read. - let config = read_config_or_default(); - let config = match config { - Ok(c) => c, + let config_with_path = read_config_or_default(); + let (config_path, config) = match config_with_path { + Ok(c) => (c.config_path, c.config), Err(e) => { eprintln!("Cannot read the config file properly.\nError: {}\nfelix launches with default configuration.", e); - Config::default() + (None, Config::default()) } }; + let mut state = State::default(); + state.set_config(config.clone()); - let session = read_session(session_path); - let (original_column, original_row) = terminal_size()?; - - // Return error if terminal size may cause panic - if original_column < 4 { - error!("Too small terminal size (less than 4 columns)."); - return Err(FxError::TooSmallWindowSize); - }; - if original_row < 4 { - error!("Too small terminal size. (less than 4 rows)"); - return Err(FxError::TooSmallWindowSize); - }; - - let (time_start, name_max) = make_layout(original_column); - - let color = config.color.unwrap_or_default(); - - let split = session.split.unwrap_or(Split::Vertical); - - let has_bat = check_bat(); - let has_chafa = check_chafa(); let has_zoxide = check_zoxide(); - let is_kitty = check_kitty_support(); Ok(State { - list: Vec::new(), - registers: Registers { - unnamed: vec![], - zero: vec![], - numbered: VecDeque::new(), - named: BTreeMap::new(), - }, - operations: Operation { - pos: 0, - op_list: Vec::new(), - }, - current_dir: PathBuf::new(), - trash_dir: PathBuf::new(), - lwd_file: None, - match_vim_exit_behavior: config.match_vim_exit_behavior.unwrap_or_default(), + config_path, has_zoxide, - default: config - .default - .unwrap_or_else(|| env::var("EDITOR").unwrap_or_default()), - commands: to_extension_map(&config.exec), - layout: Layout { - nums: Num::new(), - y: BEGINNING_ROW, - terminal_row: original_row, - terminal_column: original_column, - name_max_len: name_max, - time_start_pos: time_start, - colors: ConfigColor { - dir_fg: color.dir_fg, - file_fg: color.file_fg, - symlink_fg: color.symlink_fg, - dirty_fg: color.dirty_fg, - }, - sort_by: session.sort_by, - show_hidden: session.show_hidden, - side: if session.preview.unwrap_or(false) { - Side::Preview - } else { - Side::None - }, - split, - preview_start: match split { - Split::Vertical => (0, 0), - Split::Horizontal => (0, 0), - }, - preview_space: match split { - Split::Vertical => (0, 0), - Split::Horizontal => (0, 0), - }, - has_bat, - has_chafa, - is_kitty, - }, - jumplist: JumpList::default(), - c_memo: Vec::new(), - p_memo: Vec::new(), - keyword: None, - v_start: None, - is_ro: false, + layout: Layout::new(session_path, config)?, + ..state }) } + /// Set configuration from config file. + pub fn set_config(&mut self, config: Config) { + self.default = config + .default + .unwrap_or_else(|| env::var("EDITOR").unwrap_or_default()); + self.match_vim_exit_behavior = config.match_vim_exit_behavior.unwrap_or_default(); + self.commands = to_extension_map(&config.exec); + let colors = config.color.unwrap_or_default(); + self.layout.colors = colors; + } + /// Select item that the cursor points to. pub fn get_item(&self) -> Result<&ItemInfo, FxError> { self.list @@ -1140,6 +1076,13 @@ impl State { } } + /// Escape to normal mode. + pub fn escape(&mut self) { + go_to_info_line_and_reset(); + hide_cursor(); + self.move_cursor(self.layout.y); + } + /// Print an item in the directory. fn print_item(&self, item: &ItemInfo) { let name = if item.file_name.bytes().len() <= self.layout.name_max_len { @@ -1360,33 +1303,6 @@ impl State { } } - /// Creates temp file for directory. Works like touch, but with randomized suffix - #[allow(dead_code)] - pub fn create_temp(&mut self, is_dir: bool) -> Result { - let mut new_name = self.current_dir.join(".tmp"); - if new_name.exists() { - let mut nanos = std::time::SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .subsec_nanos(); - let encoded: &mut [u8] = &mut [0, 0, 0, 0, 0]; - for i in 0..5 { - let v = (nanos & 0x1f) as usize; - encoded[4 - i] = BASE32[v]; - nanos >>= 5; - } - new_name = self - .current_dir - .join(format!(".tmp_{}", String::from_utf8(encoded.to_vec())?)) - } - if is_dir { - std::fs::create_dir(new_name.clone())?; - } else { - std::fs::File::create(new_name.clone())?; - } - Ok(new_name) - } - /// Show help pub fn show_help(&self, mut screen: &Stdout) -> Result<(), FxError> { clear_all(); @@ -1872,7 +1788,12 @@ fn read_item(entry: fs::DirEntry) -> ItemInfo { if filetype == FileType::Symlink { if let Ok(sym_meta) = fs::metadata(&path) { if sym_meta.is_dir() { - fs::canonicalize(path.clone()).ok() + if cfg!(not(windows)) { + // Avoid error on Windows + path.canonicalize().ok() + } else { + Some(path.clone()) + } } else { None } @@ -1954,22 +1875,6 @@ fn read_item(entry: fs::DirEntry) -> ItemInfo { // Ok(result) // } -/// Check if bat is installed. -fn check_bat() -> bool { - std::process::Command::new("bat") - .arg("--help") - .output() - .is_ok() -} - -/// Check if chafa is installed. -fn check_chafa() -> bool { - std::process::Command::new("chafa") - .arg("--help") - .output() - .is_ok() -} - /// Check if zoxide is installed. fn check_zoxide() -> bool { std::process::Command::new("zoxide") @@ -1978,15 +1883,6 @@ fn check_zoxide() -> bool { .is_ok() } -/// Check if the terminal is Kitty or not -fn check_kitty_support() -> bool { - if let Ok(term) = std::env::var("TERM") { - term.contains("kitty") - } else { - false - } -} - /// Set content type from ItemInfo. fn set_preview_content_type(item: &mut ItemInfo) { if item.file_size > MAX_SIZE_TO_PREVIEW { diff --git a/src/term.rs b/src/term.rs index b2b7f87..c6435fa 100644 --- a/src/term.rs +++ b/src/term.rs @@ -65,10 +65,42 @@ pub fn move_left(x: u16) { print!("{}", MoveLeft(x)); } +pub fn move_left_command_line( + input: &mut [char], + current_char_pos: &mut usize, + current_pos: &mut u16, +) { + if current_char_pos == &0 { + return; + }; + if let Some(to_be_skipped) = + unicode_width::UnicodeWidthChar::width(input[*current_char_pos - 1]) + { + *current_char_pos -= 1; + *current_pos -= to_be_skipped as u16; + move_left(to_be_skipped as u16); + } +} + pub fn move_right(x: u16) { print!("{}", MoveRight(x)); } +pub fn move_right_command_line( + input: &mut [char], + current_char_pos: &mut usize, + current_pos: &mut u16, +) { + if *current_char_pos == input.len() { + return; + }; + if let Some(to_be_skipped) = unicode_width::UnicodeWidthChar::width(input[*current_char_pos]) { + *current_char_pos += 1; + *current_pos += to_be_skipped as u16; + move_right(to_be_skipped as u16); + } +} + pub fn hide_cursor() { print!("{}", Hide); }