From 95d2358100ca57092e2aeb49c88c6b342d102f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Thu, 15 Feb 2024 20:20:28 +0800 Subject: [PATCH] feat: expose selected/yanked files as API (#674) --- Cargo.lock | 137 +++++++++++----------- yazi-config/preset/keymap.toml | 4 +- yazi-config/preset/yazi.toml | 4 +- yazi-core/src/folder/files.rs | 2 +- yazi-core/src/manager/commands/link.rs | 5 +- yazi-core/src/manager/commands/open.rs | 58 ++++++--- yazi-core/src/manager/commands/paste.rs | 11 +- yazi-core/src/manager/commands/peek.rs | 6 +- yazi-core/src/manager/commands/remove.rs | 2 +- yazi-core/src/manager/commands/rename.rs | 4 +- yazi-core/src/manager/commands/unyank.rs | 2 +- yazi-core/src/manager/commands/yank.rs | 6 +- yazi-core/src/manager/manager.rs | 11 +- yazi-core/src/manager/mod.rs | 2 + yazi-core/src/manager/yanked.rs | 15 +++ yazi-core/src/tab/commands/copy.rs | 12 +- yazi-core/src/tab/commands/escape.rs | 14 ++- yazi-core/src/tab/commands/shell.rs | 2 +- yazi-core/src/tab/tab.rs | 46 ++------ yazi-fm/src/help/layout.rs | 2 +- yazi-fm/src/lives/file.rs | 7 +- yazi-fm/src/lives/lives.rs | 3 + yazi-fm/src/lives/mod.rs | 4 + yazi-fm/src/lives/preview.rs | 5 +- yazi-fm/src/lives/selected.rs | 52 ++++++++ yazi-fm/src/lives/tab.rs | 7 +- yazi-fm/src/lives/yanked.rs | 13 ++ yazi-fm/src/notify/notify.rs | 6 +- yazi-fm/src/root.rs | 2 +- yazi-plugin/preset/components/current.lua | 17 ++- yazi-plugin/preset/components/folder.lua | 8 +- yazi-plugin/preset/components/parent.lua | 21 +++- yazi-plugin/preset/components/status.lua | 8 +- yazi-plugin/preset/inspect/inspect.lua | 6 - yazi-plugin/preset/plugins/folder.lua | 24 +++- yazi-plugin/preset/ya.lua | 2 +- 36 files changed, 328 insertions(+), 202 deletions(-) create mode 100644 yazi-core/src/manager/yanked.rs create mode 100644 yazi-fm/src/lives/selected.rs create mode 100644 yazi-fm/src/lives/yanked.rs diff --git a/Cargo.lock b/Cargo.lock index b3139f0e..5da44b6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" dependencies = [ "cfg-if", "once_cell", @@ -230,9 +230,9 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytemuck" -version = "1.14.1" +version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2490600f404f2b94c167e31d3ed1d5f3c225a0f3b80230053b3e0b7b962bd9" +checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" [[package]] name = "byteorder" @@ -278,9 +278,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "android-tzdata", "iana-time-zone", @@ -290,9 +290,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" dependencies = [ "clap_builder", "clap_derive", @@ -300,9 +300,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" dependencies = [ "anstream", "anstyle", @@ -312,18 +312,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.10" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb745187d7f4d76267b37485a65e0149edd0e91a4cfcdd3f27524ad86cee9f3" +checksum = "299353be8209bd133b049bf1c63582d184a8b39fd9c04f15fe65f50f88bdfe6c" dependencies = [ "clap", ] [[package]] name = "clap_complete_fig" -version = "4.4.2" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e571d70e22ec91d34e1c5317c8308035a2280d925167646bf094fc5de1737c" +checksum = "54b3e65f91fabdd23cac3d57d39d5d938b4daabd070c335c006dccb866a61110" dependencies = [ "clap", "clap_complete", @@ -331,9 +331,9 @@ dependencies = [ [[package]] name = "clap_complete_nushell" -version = "4.4.2" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "948bf70d7e1f179635d3ef819ce8baa2d3074d0d57816ac37387cd6f9eed0c31" +checksum = "92cd8ac7c321605310e4b3bdc047daf27c6ca1b50f6ae59b22aa0661ab45e295" dependencies = [ "clap", "clap_complete", @@ -341,9 +341,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", @@ -353,9 +353,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clipboard-win" @@ -422,9 +422,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -547,9 +547,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "encode_unicode" @@ -853,9 +853,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "home" @@ -941,9 +941,9 @@ checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" [[package]] name = "indexmap" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", "hashbrown", @@ -1001,9 +1001,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] @@ -1276,9 +1276,9 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -1523,9 +1523,9 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "154b85ef15a5d1719bcaa193c3c81fe645cd120c156874cd660fe49fd21d1373" +checksum = "bcb12f8fbf6c62614b0d56eb352af54f6a22410c3b079eb53ee93c7b97dd31d8" dependencies = [ "bitflags 2.4.2", "cassowary", @@ -1590,7 +1590,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.2", + "regex-syntax", ] [[package]] @@ -1601,15 +1601,9 @@ checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - [[package]] name = "regex-syntax" version = "0.8.2" @@ -1851,9 +1845,9 @@ checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "strum" @@ -1901,9 +1895,9 @@ dependencies = [ [[package]] name = "syntect" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02b4b303bf8d08bfeb0445cba5068a3d306b6baece1d5582171a9bf49188f91" +checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" dependencies = [ "bincode", "bitflags 1.3.2", @@ -1912,8 +1906,9 @@ dependencies = [ "once_cell", "onig", "plist", - "regex-syntax 0.7.5", + "regex-syntax", "serde", + "serde_derive", "serde_json", "thiserror", "walkdir", @@ -1921,18 +1916,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -2084,9 +2079,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" dependencies = [ "indexmap", "serde", @@ -2106,9 +2101,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "99e68c159e8f5ba8a28c4eb7b0c0c190d77bb479047ca713270048145a9ad28a" dependencies = [ "indexmap", "serde", @@ -2188,9 +2183,9 @@ dependencies = [ [[package]] name = "trash" -version = "3.2.1" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55bb920006929bc37df8c151c3c063b6fc10f485dfe4937393f905861a632e53" +checksum = "c658458d46d9d5a153a3b5cdd88d8579ad50d4fb85d53961e4526c8fc7c55a57" dependencies = [ "chrono", "libc", @@ -2231,9 +2226,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -2352,9 +2347,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2362,9 +2357,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", @@ -2377,9 +2372,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2387,9 +2382,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", @@ -2400,9 +2395,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "weezl" @@ -2663,9 +2658,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.37" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cad8365489051ae9f054164e459304af2e7e9bb407c958076c8bf4aef52da5" +checksum = "6b1dbce9e90e5404c5a52ed82b1d13fc8cfbdad85033b6f57546ffd1265f8451" dependencies = [ "memchr", ] diff --git a/yazi-config/preset/keymap.toml b/yazi-config/preset/keymap.toml index 96ed0044..0d8c2fc7 100644 --- a/yazi-config/preset/keymap.toml +++ b/yazi-config/preset/keymap.toml @@ -31,8 +31,8 @@ keymap = [ { on = [ "" ], exec = "arrow -100%", desc = "Move cursor up one page" }, { on = [ "" ], exec = "arrow 100%", desc = "Move cursor down one page" }, - { on = [ "h" ], exec = [ "leave", "escape --visual --select" ], desc = "Go back to the parent directory" }, - { on = [ "l" ], exec = [ "enter", "escape --visual --select" ], desc = "Enter the child directory" }, + { on = [ "h" ], exec = [ "escape --visual", "leave" ], desc = "Go back to the parent directory" }, + { on = [ "l" ], exec = [ "escape --visual", "enter" ], desc = "Enter the child directory" }, { on = [ "H" ], exec = "back", desc = "Go back to the previous directory" }, { on = [ "L" ], exec = "forward", desc = "Go forward to the next directory" }, diff --git a/yazi-config/preset/yazi.toml b/yazi-config/preset/yazi.toml index d4eaf662..e9d46403 100644 --- a/yazi-config/preset/yazi.toml +++ b/yazi-config/preset/yazi.toml @@ -26,8 +26,8 @@ ueberzug_offset = [ 0, 0, 0, 0 ] [opener] edit = [ - { exec = '[ -n "$EDITOR" ] && $EDITOR "$@"', desc = "$EDITOR", block = true, for = "unix" }, - { exec = 'code "%*"', orphan = true, for = "windows" }, + { exec = '${EDITOR:=vi} "$@"', desc = "$EDITOR", block = true, for = "unix" }, + { exec = 'code "%*"', orphan = true, for = "windows" }, ] open = [ { exec = 'xdg-open "$@"', desc = "Open", for = "linux" }, diff --git a/yazi-core/src/folder/files.rs b/yazi-core/src/folder/files.rs index 59837ca3..b4a61acc 100644 --- a/yazi-core/src/folder/files.rs +++ b/yazi-core/src/folder/files.rs @@ -317,7 +317,7 @@ impl Files { impl Files { // --- Items #[inline] - pub fn position(&self, url: &Url) -> Option { self.iter().position(|f| &f.url == url) } + pub fn position(&self, url: &Url) -> Option { self.iter().position(|f| f.url == *url) } // --- Ticket #[inline] diff --git a/yazi-core/src/manager/commands/link.rs b/yazi-core/src/manager/commands/link.rs index e6c72ce9..2329782f 100644 --- a/yazi-core/src/manager/commands/link.rs +++ b/yazi-core/src/manager/commands/link.rs @@ -15,12 +15,11 @@ impl From for Opt { impl Manager { pub fn link(&mut self, opt: impl Into, tasks: &Tasks) { - let (cut, ref src) = self.yanked; - if cut { + if self.yanked.cut { return; } let opt = opt.into() as Opt; - tasks.file_link(src, self.cwd(), opt.relative, opt.force); + tasks.file_link(&self.yanked, self.cwd(), opt.relative, opt.force); } } diff --git a/yazi-core/src/manager/commands/open.rs b/yazi-core/src/manager/commands/open.rs index 2bbd211e..4bec6d07 100644 --- a/yazi-core/src/manager/commands/open.rs +++ b/yazi-core/src/manager/commands/open.rs @@ -5,10 +5,10 @@ use yazi_config::{popup::SelectCfg, ARGS, OPEN}; use yazi_plugin::isolate; use yazi_shared::{emit, event::{Cmd, EventQuit}, fs::{File, Url}, Layer, MIME_DIR}; -use crate::{manager::Manager, select::Select, tasks::Tasks}; +use crate::{folder::Folder, manager::Manager, select::Select, tasks::Tasks}; pub struct Opt { - targets: Vec<(Url, Option)>, + targets: Vec<(Url, String)>, interactive: bool, } @@ -23,7 +23,7 @@ impl From for Opt { impl Manager { pub fn open(&mut self, opt: impl Into, tasks: &Tasks) { - let selected = self.selected(); + let selected = self.selected_or_hovered(); if selected.is_empty() { return; } else if Self::quit_with_selected(&selected) { @@ -31,13 +31,13 @@ impl Manager { } let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]); - for f in selected { - if f.is_dir() { - done.push((f.url(), Some(MIME_DIR.to_owned()))); - } else if self.mimetype.get(&f.url).is_some() { - done.push((f.url(), None)); + for u in selected { + if self.mimetype.get(u).is_some() { + done.push((u.clone(), String::new())); + } else if self.guess_folder(u) { + done.push((u.clone(), MIME_DIR.to_owned())); } else { - todo.push(f.clone()); + todo.push(u.clone()); } } @@ -48,8 +48,15 @@ impl Manager { } tokio::spawn(async move { - done.extend(todo.iter().map(|f| (f.url(), None))); - if let Err(e) = isolate::preload("mime", todo, true).await { + let mut files = Vec::with_capacity(todo.len()); + for u in todo { + if let Ok(f) = File::from(u).await { + files.push(f); + } + } + + done.extend(files.iter().map(|f| (f.url(), String::new()))); + if let Err(e) = isolate::preload("mime", files, true).await { error!("preload in watcher failed: {e}"); } @@ -58,7 +65,7 @@ impl Manager { } #[inline] - pub fn _open_do(interactive: bool, targets: Vec<(Url, Option)>) { + pub fn _open_do(interactive: bool, targets: Vec<(Url, String)>) { emit!(Call( Cmd::new("open_do").with_bool("interactive", interactive).with_data(targets), Layer::Manager @@ -74,7 +81,9 @@ impl Manager { let targets: Vec<_> = opt .targets .into_iter() - .filter_map(|(u, m)| m.or_else(|| self.mimetype.get(&u).cloned()).map(|m| (u, m))) + .filter_map(|(u, m)| { + Some(m).filter(|m| !m.is_empty()).or_else(|| self.mimetype.get(&u).cloned()).map(|m| (u, m)) + }) .collect(); if targets.is_empty() { @@ -98,13 +107,30 @@ impl Manager { }); } - fn quit_with_selected(selected: &[&File]) -> bool { + fn guess_folder(&self, url: &Url) -> bool { + let Some(p) = url.parent_url() else { + return true; + }; + + let find = |folder: Option<&Folder>| { + folder.is_some_and(|folder| { + folder.cwd == p && folder.files.iter().any(|f| f.is_dir() && f.url == *url) + }) + }; + + find(Some(self.current())) + || find(self.parent()) + || find(self.hovered_folder()) + || find(self.active().history.get(&p)) + } + + fn quit_with_selected(selected: &[&Url]) -> bool { if ARGS.chooser_file.is_none() { return false; } - let paths = selected.iter().fold(OsString::new(), |mut s, &f| { - s.push(f.url.as_os_str()); + let paths = selected.iter().fold(OsString::new(), |mut s, &u| { + s.push(u.as_os_str()); s.push("\n"); s }); diff --git a/yazi-core/src/manager/commands/paste.rs b/yazi-core/src/manager/commands/paste.rs index 256ffe58..8b2c9530 100644 --- a/yazi-core/src/manager/commands/paste.rs +++ b/yazi-core/src/manager/commands/paste.rs @@ -15,14 +15,13 @@ impl From for Opt { impl Manager { pub fn paste(&mut self, opt: impl Into, tasks: &Tasks) { - let dest = self.cwd(); - let (cut, ref src) = self.yanked; - let opt = opt.into() as Opt; - if cut { - tasks.file_cut(src, dest, opt.force); + + let dest = self.cwd(); + if self.yanked.cut { + tasks.file_cut(&self.yanked, dest, opt.force); } else { - tasks.file_copy(src, dest, opt.force, opt.follow); + tasks.file_copy(&self.yanked, dest, opt.force, opt.follow); } } } diff --git a/yazi-core/src/manager/commands/peek.rs b/yazi-core/src/manager/commands/peek.rs index 8bfdae47..df6d8304 100644 --- a/yazi-core/src/manager/commands/peek.rs +++ b/yazi-core/src/manager/commands/peek.rs @@ -35,11 +35,7 @@ impl Manager { return render!(self.active_mut().preview.reset()); }; - let folder = Some(()) - .filter(|_| hovered.is_dir()) - .and_then(|_| self.active().history.get(&hovered.url)) - .map(|f| (f.offset, f.mtime)); - + let folder = self.active().hovered_folder().map(|f| (f.offset, f.mtime)); if !self.active().preview.same_url(&hovered.url) { self.active_mut().preview.skip = folder.map(|f| f.0).unwrap_or_default(); render!(self.active_mut().preview.reset()); diff --git a/yazi-core/src/manager/commands/remove.rs b/yazi-core/src/manager/commands/remove.rs index bc411c54..15e9f70e 100644 --- a/yazi-core/src/manager/commands/remove.rs +++ b/yazi-core/src/manager/commands/remove.rs @@ -19,7 +19,7 @@ impl From for Opt { impl Manager { pub fn remove(&mut self, opt: impl Into, tasks: &Tasks) { let opt = opt.into() as Opt; - let targets = self.selected().into_iter().map(|f| f.url()).collect(); + let targets = self.selected_or_hovered().into_iter().cloned().collect(); tasks.file_remove(targets, opt.force, opt.permanently); } } diff --git a/yazi-core/src/manager/commands/rename.rs b/yazi-core/src/manager/commands/rename.rs index a1510484..80271fd2 100644 --- a/yazi-core/src/manager/commands/rename.rs +++ b/yazi-core/src/manager/commands/rename.rs @@ -53,7 +53,7 @@ impl Manager { } pub fn rename(&self, opt: impl Into) { - if self.active().in_selecting() { + if !self.active().selected.is_empty() { return self.bulk_rename(); } @@ -96,7 +96,7 @@ impl Manager { } fn bulk_rename(&self) { - let old: Vec<_> = self.selected().into_iter().map(|f| &f.url).collect(); + let old: Vec<_> = self.selected_or_hovered(); let root = max_common_root(&old); let old: Vec<_> = old.into_iter().map(|p| p.strip_prefix(&root).unwrap().to_owned()).collect(); diff --git a/yazi-core/src/manager/commands/unyank.rs b/yazi-core/src/manager/commands/unyank.rs index 918223f0..6071bdf9 100644 --- a/yazi-core/src/manager/commands/unyank.rs +++ b/yazi-core/src/manager/commands/unyank.rs @@ -4,7 +4,7 @@ use crate::manager::Manager; impl Manager { pub fn unyank(&mut self, _: Cmd) { - render!(!self.yanked.1.is_empty()); + render!(!self.yanked.is_empty()); self.yanked = Default::default(); } diff --git a/yazi-core/src/manager/commands/yank.rs b/yazi-core/src/manager/commands/yank.rs index 7f1209a5..5886d515 100644 --- a/yazi-core/src/manager/commands/yank.rs +++ b/yazi-core/src/manager/commands/yank.rs @@ -1,6 +1,6 @@ use yazi_shared::{event::Cmd, render}; -use crate::manager::Manager; +use crate::manager::{Manager, Yanked}; pub struct Opt { cut: bool, @@ -14,8 +14,8 @@ impl Manager { pub fn yank(&mut self, opt: impl Into) { let opt = opt.into() as Opt; - self.yanked.0 = opt.cut; - self.yanked.1 = self.selected().into_iter().map(|f| f.url()).collect(); + self.yanked = + Yanked { cut: opt.cut, urls: self.selected_or_hovered().into_iter().cloned().collect() }; render!(); } } diff --git a/yazi-core/src/manager/manager.rs b/yazi-core/src/manager/manager.rs index 813593fd..4250eab4 100644 --- a/yazi-core/src/manager/manager.rs +++ b/yazi-core/src/manager/manager.rs @@ -1,13 +1,13 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use yazi_shared::fs::{File, Url}; -use super::{Tabs, Watcher}; +use super::{Tabs, Watcher, Yanked}; use crate::{folder::Folder, tab::Tab}; pub struct Manager { pub tabs: Tabs, - pub yanked: (bool, HashSet), + pub yanked: Yanked, pub(super) watcher: Watcher, pub mimetype: HashMap, @@ -48,5 +48,8 @@ impl Manager { pub fn hovered(&self) -> Option<&File> { self.tabs.active().current.hovered() } #[inline] - pub fn selected(&self) -> Vec<&File> { self.tabs.active().selected() } + pub fn hovered_folder(&self) -> Option<&Folder> { self.tabs.active().hovered_folder() } + + #[inline] + pub fn selected_or_hovered(&self) -> Vec<&Url> { self.tabs.active().selected_or_hovered() } } diff --git a/yazi-core/src/manager/mod.rs b/yazi-core/src/manager/mod.rs index 8016b0e4..46c3d35d 100644 --- a/yazi-core/src/manager/mod.rs +++ b/yazi-core/src/manager/mod.rs @@ -3,8 +3,10 @@ mod linked; mod manager; mod tabs; mod watcher; +mod yanked; pub use linked::*; pub use manager::*; pub use tabs::*; pub use watcher::*; +pub use yanked::*; diff --git a/yazi-core/src/manager/yanked.rs b/yazi-core/src/manager/yanked.rs new file mode 100644 index 00000000..438fed3d --- /dev/null +++ b/yazi-core/src/manager/yanked.rs @@ -0,0 +1,15 @@ +use std::{collections::HashSet, ops::Deref}; + +use yazi_shared::fs::Url; + +#[derive(Default)] +pub struct Yanked { + pub cut: bool, + pub(super) urls: HashSet, +} + +impl Deref for Yanked { + type Target = HashSet; + + fn deref(&self) -> &Self::Target { &self.urls } +} diff --git a/yazi-core/src/tab/commands/copy.rs b/yazi-core/src/tab/commands/copy.rs index a629d9e7..78477bb6 100644 --- a/yazi-core/src/tab/commands/copy.rs +++ b/yazi-core/src/tab/commands/copy.rs @@ -17,13 +17,13 @@ impl Tab { let opt = opt.into() as Opt; let mut s = OsString::new(); - let mut it = self.selected().into_iter().peekable(); - while let Some(f) = it.next() { + let mut it = self.selected_or_hovered().into_iter().peekable(); + while let Some(u) = it.next() { s.push(match opt.type_.as_str() { - "path" => f.url.as_os_str(), - "dirname" => f.url.parent().map_or(OsStr::new(""), |p| p.as_os_str()), - "filename" => f.name().unwrap_or(OsStr::new("")), - "name_without_ext" => f.stem().unwrap_or(OsStr::new("")), + "path" => u.as_os_str(), + "dirname" => u.parent().map_or(OsStr::new(""), |p| p.as_os_str()), + "filename" => u.file_name().unwrap_or(OsStr::new("")), + "name_without_ext" => u.file_stem().unwrap_or(OsStr::new("")), _ => return, }); if it.peek().is_some() { diff --git a/yazi-core/src/tab/commands/escape.rs b/yazi-core/src/tab/commands/escape.rs index df31e2ef..fd37d2cc 100644 --- a/yazi-core/src/tab/commands/escape.rs +++ b/yazi-core/src/tab/commands/escape.rs @@ -1,7 +1,7 @@ use bitflags::bitflags; use yazi_shared::{event::Cmd, render}; -use crate::tab::{Mode, Tab}; +use crate::{manager::Manager, tab::{Mode, Tab}}; bitflags! { pub struct Opt: u8 { @@ -53,9 +53,15 @@ impl Tab { #[inline] fn escape_select(&mut self) -> bool { - let old = self.selected.len(); - self.select_all(Some(false)); - old != self.selected.len() + if self.selected.is_empty() { + return false; + } + + self.selected.clear(); + if self.current.hovered().is_some_and(|h| h.is_dir()) { + Manager::_peek(true); + } + true } #[inline] diff --git a/yazi-core/src/tab/commands/shell.rs b/yazi-core/src/tab/commands/shell.rs index d5d6b6ee..11c07983 100644 --- a/yazi-core/src/tab/commands/shell.rs +++ b/yazi-core/src/tab/commands/shell.rs @@ -22,7 +22,7 @@ impl From for Opt { impl Tab { pub fn shell(&self, opt: impl Into) { let mut opt = opt.into() as Opt; - let selected: Vec<_> = self.selected().into_iter().map(|f| f.url()).collect(); + let selected: Vec<_> = self.selected_or_hovered().into_iter().cloned().collect(); tokio::spawn(async move { if !opt.confirm || opt.exec.is_empty() { diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index ac6a4f29..f8f1678f 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -1,8 +1,8 @@ -use std::{borrow::Cow, collections::{BTreeMap, BTreeSet}}; +use std::collections::{BTreeMap, BTreeSet}; use anyhow::Result; use tokio::task::JoinHandle; -use yazi_shared::{fs::{File, Url}, render}; +use yazi_shared::{fs::Url, render}; use super::{Backstack, Config, Finder, Mode, Preview}; use crate::folder::{Folder, FolderStage}; @@ -50,41 +50,12 @@ impl From<&Url> for Tab { impl Tab { // --- Current - #[inline] - pub fn in_selecting(&self) -> bool { - !self.selected.is_empty() || self.mode.visual().is_some_and(|(_, indices)| !indices.is_empty()) - } - - pub fn selected(&self) -> Vec<&File> { - let pending = self.mode.visual().map(|(_, p)| Cow::Borrowed(p)).unwrap_or_default(); - let is_unset = self.mode.is_unset(); - if self.selected.is_empty() && (is_unset || pending.is_empty()) { - return self.current.hovered().map(|h| vec![h]).unwrap_or_default(); - } - - let selected: BTreeSet<_> = self.selected.iter().collect(); - let pending: BTreeSet<_> = - pending.iter().filter_map(|&i| self.current.files.get(i)).map(|f| &f.url).collect(); - - let urls: BTreeSet<_> = if is_unset { - selected.difference(&pending).copied().collect() + pub fn selected_or_hovered(&self) -> Vec<&Url> { + if self.selected.is_empty() { + self.current.hovered().map(|h| vec![&h.url]).unwrap_or_default() } else { - selected.union(&pending).copied().collect() - }; - - let mut items = Vec::with_capacity(urls.len()); - for item in self.current.files.iter() { - if urls.contains(&item.url) { - items.push(item); - if items.len() == urls.len() { - break; - } - } + self.selected.iter().collect() } - Some(items) - .filter(|v| !v.is_empty()) - .or_else(|| self.current.hovered().map(|h| vec![h])) - .unwrap_or_default() } // --- History @@ -93,6 +64,11 @@ impl Tab { self.history.remove(url).unwrap_or_else(|| Folder::from(url)) } + #[inline] + pub fn hovered_folder(&self) -> Option<&Folder> { + self.current.hovered().filter(|&h| h.is_dir()).and_then(|h| self.history.get(&h.url)) + } + pub fn apply_files_attrs(&mut self) { let apply = |f: &mut Folder| { if f.stage == FolderStage::Loading { diff --git a/yazi-fm/src/help/layout.rs b/yazi-fm/src/help/layout.rs index 7326444d..1d78c169 100644 --- a/yazi-fm/src/help/layout.rs +++ b/yazi-fm/src/help/layout.rs @@ -17,7 +17,7 @@ impl<'a> Widget for Layout<'a> { let help = &self.cx.help; widgets::Clear.render(area, buf); - let chunks = layout::Layout::vertical([Constraint::Min(0), Constraint::Length(1)]).split(area); + let chunks = layout::Layout::vertical([Constraint::Fill(1), Constraint::Length(1)]).split(area); Line::styled( help.keyword().unwrap_or_else(|| format!("{}.help", help.layer.to_string())), THEME.help.footer, diff --git a/yazi-fm/src/lives/file.rs b/yazi-fm/src/lives/file.rs index 3827966a..e7eb1dc2 100644 --- a/yazi-fm/src/lives/file.rs +++ b/yazi-fm/src/lives/file.rs @@ -76,9 +76,9 @@ impl File { }); reg.add_method("is_yanked", |lua, me, ()| { let cx = lua.named_registry_value::("cx")?; - Ok(if !cx.manager.yanked.1.contains(&me.url) { + Ok(if !cx.manager.yanked.contains(&me.url) { 0u8 - } else if cx.manager.yanked.0 { + } else if cx.manager.yanked.cut { 2u8 } else { 1u8 @@ -88,8 +88,11 @@ impl File { let cx = lua.named_registry_value::("cx")?; let selected = me.tab().selected.contains(&me.url); + #[allow(clippy::if_same_then_else)] Ok(if !cx.manager.active().mode.is_visual() { selected + } else if me.folder().cwd != me.tab().current.cwd { + selected } else { cx.manager.active().mode.pending(me.idx, selected) }) diff --git a/yazi-fm/src/lives/lives.rs b/yazi-fm/src/lives/lives.rs index d078deb4..3b45c761 100644 --- a/yazi-fm/src/lives/lives.rs +++ b/yazi-fm/src/lives/lives.rs @@ -20,9 +20,11 @@ impl Lives { super::Folder::register(&LUA)?; super::Mode::register(&LUA)?; super::Preview::register(&LUA)?; + super::Selected::register(&LUA)?; super::Tab::register(&LUA)?; super::Tabs::register(&LUA)?; super::Tasks::register(&LUA)?; + super::Yanked::register(&LUA)?; Ok(()) } @@ -42,6 +44,7 @@ impl Lives { ("active", super::Tab::make(cx.manager.active())?), ("tabs", super::Tabs::make(&cx.manager.tabs)?), ("tasks", super::Tasks::make(&cx.tasks)?), + ("yanked", scope.create_any_userdata_ref(&cx.manager.yanked)?), ])?, )?; diff --git a/yazi-fm/src/lives/mod.rs b/yazi-fm/src/lives/mod.rs index b16a4ece..52e6ff63 100644 --- a/yazi-fm/src/lives/mod.rs +++ b/yazi-fm/src/lives/mod.rs @@ -7,9 +7,11 @@ mod folder; mod lives; mod mode; mod preview; +mod selected; mod tab; mod tabs; mod tasks; +mod yanked; use config::*; use file::*; @@ -18,8 +20,10 @@ use folder::*; pub(super) use lives::*; use mode::*; use preview::*; +use selected::*; use tab::*; use tabs::*; use tasks::*; +use yanked::*; type CtxRef<'lua> = mlua::UserDataRef<'lua, crate::Ctx>; diff --git a/yazi-fm/src/lives/preview.rs b/yazi-fm/src/lives/preview.rs index 2e8d07cd..83018ed7 100644 --- a/yazi-fm/src/lives/preview.rs +++ b/yazi-fm/src/lives/preview.rs @@ -26,10 +26,7 @@ impl Preview { reg.add_field_method_get("skip", |_, me| Ok(me.skip)); reg.add_field_method_get("folder", |_, me| { me.tab() - .current - .hovered() - .filter(|&f| f.is_dir()) - .and_then(|f| me.tab().history.get(&f.url)) + .hovered_folder() .map(|f| { let limit = LAYOUT.load().preview.height as usize; Folder::make(Some(me.skip..f.files.len().min(me.skip + limit)), f, me.tab()) diff --git a/yazi-fm/src/lives/selected.rs b/yazi-fm/src/lives/selected.rs new file mode 100644 index 00000000..b20233fb --- /dev/null +++ b/yazi-fm/src/lives/selected.rs @@ -0,0 +1,52 @@ +use std::{collections::{btree_set, BTreeSet}, ops::Deref}; + +use mlua::{AnyUserData, Lua, MetaMethod, UserDataMethods, UserDataRefMut}; +use yazi_plugin::{bindings::Cast, url::Url}; + +use super::SCOPE; + +#[derive(Clone, Copy)] +pub(super) struct Selected { + inner: *const BTreeSet, +} + +impl Deref for Selected { + type Target = BTreeSet; + + fn deref(&self) -> &Self::Target { self.inner() } +} + +impl Selected { + #[inline] + pub(crate) fn make(inner: &BTreeSet) -> mlua::Result> { + SCOPE.create_any_userdata(Self { inner }) + } + + pub(super) fn register(lua: &Lua) -> mlua::Result<()> { + lua.register_userdata_type::(|reg| { + reg.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.len())); + + reg.add_meta_method(MetaMethod::Pairs, |lua, me, ()| { + let iter = lua.create_function(|lua, mut iter: UserDataRefMut| { + Ok(if let Some(url) = iter.0.next() { Some(Url::cast(lua, url.clone())?) } else { None }) + })?; + + Ok((iter, SelectedIter::make(me.inner()))) + }); + })?; + + Ok(()) + } + + #[inline] + fn inner(&self) -> &'static BTreeSet { unsafe { &*self.inner } } +} + +struct SelectedIter(btree_set::Iter<'static, yazi_shared::fs::Url>); + +impl SelectedIter { + #[inline] + fn make(selected: &'static BTreeSet) -> mlua::Result> { + SCOPE.create_any_userdata(Self(selected.iter())) + } +} diff --git a/yazi-fm/src/lives/tab.rs b/yazi-fm/src/lives/tab.rs index f393340f..6451082d 100644 --- a/yazi-fm/src/lives/tab.rs +++ b/yazi-fm/src/lives/tab.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use mlua::{AnyUserData, Lua, UserDataFields, UserDataMethods}; -use super::{Config, Folder, Mode, Preview, SCOPE}; +use super::{Config, Folder, Mode, Preview, Selected, SCOPE}; pub(super) struct Tab { inner: *const yazi_core::tab::Tab, @@ -36,10 +36,13 @@ impl Tab { reg.add_field_method_get("mode", |_, me| Mode::make(&me.mode)); reg.add_field_method_get("conf", |_, me| Config::make(&me.conf)); + reg.add_field_method_get("current", |_, me| Folder::make(None, &me.current, me)); reg.add_field_method_get("parent", |_, me| { me.parent.as_ref().map(|f| Folder::make(None, f, me)).transpose() }); - reg.add_field_method_get("current", |_, me| Folder::make(None, &me.current, me)); + + reg.add_field_method_get("selected", |_, me| Selected::make(&me.selected)); + reg.add_field_method_get("preview", |_, me| Preview::make(me)); })?; diff --git a/yazi-fm/src/lives/yanked.rs b/yazi-fm/src/lives/yanked.rs new file mode 100644 index 00000000..3051ecae --- /dev/null +++ b/yazi-fm/src/lives/yanked.rs @@ -0,0 +1,13 @@ +use mlua::{Lua, MetaMethod, UserDataFields, UserDataMethods}; + +pub(super) struct Yanked; + +impl Yanked { + pub(super) fn register(lua: &Lua) -> mlua::Result<()> { + lua.register_userdata_type::(|reg| { + reg.add_field_method_get("is_cut", |_, me| Ok(me.cut)); + + reg.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.len())); + }) + } +} diff --git a/yazi-fm/src/notify/notify.rs b/yazi-fm/src/notify/notify.rs index 3a097f49..97e040f5 100644 --- a/yazi-fm/src/notify/notify.rs +++ b/yazi-fm/src/notify/notify.rs @@ -13,7 +13,11 @@ impl<'a> Notify<'a> { pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } } fn chunks(area: Rect, messages: &[Message]) -> Rc<[Rect]> { - let chunks = Layout::horizontal([Constraint::Percentage(100), Constraint::Min(40)]).split(area); + let chunks = + Layout::horizontal([Constraint::Fill(1), Constraint::Length(40), Constraint::Max(1)]) + .split(area); + + let chunks = Layout::vertical([Constraint::Max(1), Constraint::Min(1)]).split(chunks[1]); Layout::vertical(messages.iter().map(|m| Constraint::Length(m.height() as u16))) .spacing(1) diff --git a/yazi-fm/src/root.rs b/yazi-fm/src/root.rs index 057e0b3b..4b75c623 100644 --- a/yazi-fm/src/root.rs +++ b/yazi-fm/src/root.rs @@ -18,7 +18,7 @@ impl<'a> Root<'a> { impl<'a> Widget for Root<'a> { fn render(self, area: Rect, buf: &mut Buffer) { let chunks = - Layout::vertical([Constraint::Length(1), Constraint::Min(0), Constraint::Length(1)]) + Layout::vertical([Constraint::Length(1), Constraint::Fill(1), Constraint::Length(1)]) .split(area); components::Header.render(chunks[0], buf); diff --git a/yazi-plugin/preset/components/current.lua b/yazi-plugin/preset/components/current.lua index 24fa14d4..bac9858d 100644 --- a/yazi-plugin/preset/components/current.lua +++ b/yazi-plugin/preset/components/current.lua @@ -5,9 +5,13 @@ Current = { function Current:render(area) self.area = area - local markers = {} - local items = {} - for i, f in ipairs(Folder:by_kind(Folder.CURRENT).window) do + local files = Folder:by_kind(Folder.CURRENT).window + if #files == 0 then + return {} + end + + local items, markers = {}, {} + for i, f in ipairs(files) do local name = Folder:highlighted_name(f) -- Highlight hovered file @@ -27,5 +31,10 @@ function Current:render(area) markers[#markers + 1] = { i, 3 } end end - return ya.flat { ui.List(area, items), Folder:linemode(area), Folder:markers(area, markers) } + + return ya.flat { + ui.List(area, items), + Folder:linemode(area, files), + Folder:markers(area, markers), + } end diff --git a/yazi-plugin/preset/components/folder.lua b/yazi-plugin/preset/components/folder.lua index 129f4674..cea95c5a 100644 --- a/yazi-plugin/preset/components/folder.lua +++ b/yazi-plugin/preset/components/folder.lua @@ -20,7 +20,7 @@ function Folder:icon(file) end function Folder:highlight_ranges(s, ranges) - if ranges == nil or #ranges == 0 then + if not ranges or #ranges == 0 then return { ui.Span(s) } end @@ -55,7 +55,7 @@ function Folder:highlighted_name(file) spans[#spans + 1] = ui.Span(" -> " .. tostring(file.link_to)):italic() end - if highlights == nil or not file:is_hovered() then + if not highlights or not file:is_hovered() then return spans end @@ -67,14 +67,14 @@ function Folder:highlighted_name(file) return spans end -function Folder:linemode(area) +function Folder:linemode(area, files) local mode = cx.active.conf.linemode if mode == "none" then return {} end local lines = {} - for _, f in ipairs(self:by_kind(self.CURRENT).window) do + for _, f in ipairs(files) do local spans = { ui.Span(" ") } if mode == "size" then local size = f:size() diff --git a/yazi-plugin/preset/components/parent.lua b/yazi-plugin/preset/components/parent.lua index 6c29bd81..c40d418b 100644 --- a/yazi-plugin/preset/components/parent.lua +++ b/yazi-plugin/preset/components/parent.lua @@ -6,21 +6,32 @@ function Parent:render(area) self.area = area local folder = Folder:by_kind(Folder.PARENT) - if folder == nil then + if not folder then return {} end - local items = {} - for _, f in ipairs(folder.window) do + local items, markers = {}, {} + for i, f in ipairs(folder.window) do + -- Highlight hovered file local item = ui.ListItem(ui.Line { Folder:icon(f), ui.Span(f.name) }) if f:is_hovered() then item = item:style(THEME.manager.hovered) else item = item:style(f:style()) end - items[#items + 1] = item + + -- Mark yanked/selected files + local yanked = f:is_yanked() + if yanked ~= 0 then + markers[#markers + 1] = { i, yanked } + elseif f:is_selected() then + markers[#markers + 1] = { i, 3 } + end end - return { ui.List(area, items) } + return ya.flat { + ui.List(area, items), + Folder:markers(area, markers), + } end diff --git a/yazi-plugin/preset/components/status.lua b/yazi-plugin/preset/components/status.lua index 3fc9d5ca..1e9291e1 100644 --- a/yazi-plugin/preset/components/status.lua +++ b/yazi-plugin/preset/components/status.lua @@ -27,7 +27,7 @@ end function Status:size() local h = cx.active.current.hovered - if h == nil then + if not h then return ui.Line {} end @@ -40,7 +40,7 @@ end function Status:name() local h = cx.active.current.hovered - if h == nil then + if not h then return ui.Span("") end @@ -49,12 +49,12 @@ end function Status:permissions() local h = cx.active.current.hovered - if h == nil then + if not h then return ui.Line {} end local perm = h.cha:permissions() - if perm == nil then + if not perm then return ui.Line {} end diff --git a/yazi-plugin/preset/inspect/inspect.lua b/yazi-plugin/preset/inspect/inspect.lua index be86016e..c23bee92 100644 --- a/yazi-plugin/preset/inspect/inspect.lua +++ b/yazi-plugin/preset/inspect/inspect.lua @@ -304,9 +304,3 @@ setmetatable(inspect, { ya = ya or {} ya.inspect = inspect -ya.print = function(...) - local args = { ... } - for i = 1, #args do - print(inspect(args[i])) - end -end diff --git a/yazi-plugin/preset/plugins/folder.lua b/yazi-plugin/preset/plugins/folder.lua index 6ebf14aa..80d82ae5 100644 --- a/yazi-plugin/preset/plugins/folder.lua +++ b/yazi-plugin/preset/plugins/folder.lua @@ -2,7 +2,7 @@ local M = {} function M:peek() local folder = Folder:by_kind(Folder.PREVIEW) - if folder == nil or folder.cwd ~= self.file.url then + if not folder or folder.cwd ~= self.file.url then return {} end @@ -11,8 +11,9 @@ function M:peek() ya.manager_emit("peek", { tostring(bound), only_if = tostring(self.file.url), upper_bound = "" }) end - local items = {} - for _, f in ipairs(folder.window) do + local items, markers = {}, {} + for i, f in ipairs(folder.window) do + -- Highlight hovered file local item = ui.ListItem(ui.Line { Folder:icon(f), ui.Span(f.name) }) if f:is_hovered() then item = item:style(THEME.manager.preview_hovered) @@ -20,8 +21,23 @@ function M:peek() item = item:style(f:style()) end items[#items + 1] = item + + -- Mark yanked/selected files + local yanked = f:is_yanked() + if yanked ~= 0 then + markers[#markers + 1] = { i, yanked } + elseif f:is_selected() then + markers[#markers + 1] = { i, 3 } + end end - ya.preview_widgets(self, { ui.List(self.area, items) }) + + ya.preview_widgets( + self, + ya.flat { + ui.List(self.area, items), + Folder:markers(self.area, markers), + } + ) end function M:seek(units) diff --git a/yazi-plugin/preset/ya.lua b/yazi-plugin/preset/ya.lua index 121a25f8..7cf6fa69 100644 --- a/yazi-plugin/preset/ya.lua +++ b/yazi-plugin/preset/ya.lua @@ -52,7 +52,7 @@ end function ya.readable_path(path) local home = os.getenv("HOME") or os.getenv("USERPROFILE") - if home == nil then + if not home then return path elseif string.sub(path, 1, #home) == home then return "~" .. string.sub(path, #home + 1)