refactor: tab locking

This commit is contained in:
sxyazi 2024-08-10 20:25:35 +08:00
parent 36381e676f
commit b066652b65
No known key found for this signature in database
21 changed files with 81 additions and 48 deletions

View file

@ -7,13 +7,19 @@ use crate::manager::Manager;
pub struct Opt {
url: Option<Url>,
tab: Option<usize>,
}
impl From<Cmd> for Opt {
fn from(mut c: Cmd) -> Self { Self { url: c.take_first().and_then(Data::into_url) } }
fn from(mut c: Cmd) -> Self {
Self {
url: c.take_first().and_then(Data::into_url),
tab: c.get("tab").and_then(Data::as_usize),
}
}
}
impl From<Option<Url>> for Opt {
fn from(url: Option<Url>) -> Self { Self { url } }
fn from(url: Option<Url>) -> Self { Self { url, tab: None } }
}
impl Manager {
@ -21,11 +27,11 @@ impl Manager {
let opt = opt.into() as Opt;
// Hover on the file
render!(self.current_mut().repos(opt.url.as_ref()));
render!(self.current_or_mut(opt.tab).repos(opt.url.as_ref()));
if opt.url.zip(self.current().hovered()).is_some_and(|(u, f)| u == f.url) {
// `hover(Some)` occurs after user actions, such as create, rename, reveal, etc.
// At this point, it's intuitive to track the location of this file regardless.
self.current_mut().tracing = true;
self.current_or_mut(opt.tab).tracing = true;
}
// Repeek

View file

@ -7,17 +7,6 @@ use yazi_shared::event::Cmd;
use crate::{manager::Manager, tasks::Tasks};
impl Manager {
fn title(&self) -> String {
let home = dirs::home_dir().unwrap_or_default();
let cwd = if let Some(p) = self.cwd().strip_prefix(home) {
format!("~{}{}", MAIN_SEPARATOR, p.display())
} else {
format!("{}", self.cwd().display())
};
MANAGER.title_format.replace("{cwd}", &cwd)
}
pub fn refresh(&mut self, _: Cmd, tasks: &Tasks) {
env::set_current_dir(self.cwd()).ok();
env::set_var("PWD", self.cwd());
@ -39,4 +28,15 @@ impl Manager {
tasks.prework_sorted(&self.current().files);
}
fn title(&self) -> String {
let home = dirs::home_dir().unwrap_or_default();
let cwd = if let Some(p) = self.cwd().strip_prefix(home) {
format!("~{}{}", MAIN_SEPARATOR, p.display())
} else {
format!("{}", self.cwd().display())
};
MANAGER.title_format.replace("{cwd}", &cwd)
}
}

View file

@ -86,7 +86,7 @@ impl Manager {
return;
}
ManagerProxy::hover(None); // Re-hover in next loop
ManagerProxy::hover(None, tab.idx); // Re-hover in next loop
ManagerProxy::update_paged(); // Update for paged files in next loop
if calc {
tasks.prework_sorted(&tab.current.files);

View file

@ -39,19 +39,33 @@ impl Manager {
pub fn active_mut(&mut self) -> &mut Tab { self.tabs.active_mut() }
#[inline]
pub fn current(&self) -> &Folder { &self.tabs.active().current }
pub fn active_or(&self, idx: Option<usize>) -> &Tab { self.tabs.active_or(idx) }
#[inline]
pub fn current_mut(&mut self) -> &mut Folder { &mut self.tabs.active_mut().current }
pub fn active_or_mut(&mut self, idx: Option<usize>) -> &mut Tab { self.tabs.active_or_mut(idx) }
#[inline]
pub fn parent(&self) -> Option<&Folder> { self.tabs.active().parent.as_ref() }
pub fn current(&self) -> &Folder { &self.active().current }
#[inline]
pub fn hovered(&self) -> Option<&File> { self.tabs.active().current.hovered() }
pub fn current_mut(&mut self) -> &mut Folder { &mut self.active_mut().current }
#[inline]
pub fn hovered_folder(&self) -> Option<&Folder> { self.tabs.active().hovered_folder() }
pub fn current_or(&self, idx: Option<usize>) -> &Folder { &self.active_or(idx).current }
#[inline]
pub fn current_or_mut(&mut self, idx: Option<usize>) -> &mut Folder {
&mut self.active_or_mut(idx).current
}
#[inline]
pub fn parent(&self) -> Option<&Folder> { self.active().parent.as_ref() }
#[inline]
pub fn hovered(&self) -> Option<&File> { self.active().current.hovered() }
#[inline]
pub fn hovered_folder(&self) -> Option<&Folder> { self.active().hovered_folder() }
#[inline]
pub fn selected_or_hovered(&self, reorder: bool) -> Box<dyn Iterator<Item = &Url> + '_> {

View file

@ -59,6 +59,20 @@ impl Tabs {
#[inline]
pub(super) fn active_mut(&mut self) -> &mut Tab { &mut self.items[self.cursor] }
#[inline]
pub fn active_or(&self, idx: Option<usize>) -> &Tab {
idx.and_then(|i| self.items.get(i)).unwrap_or(&self.items[self.cursor])
}
#[inline]
pub(super) fn active_or_mut(&mut self, idx: Option<usize>) -> &mut Tab {
if let Some(i) = idx.filter(|&i| i < self.items.len()) {
&mut self.items[i]
} else {
&mut self.items[self.cursor]
}
}
}
impl Deref for Tabs {

View file

@ -12,6 +12,6 @@ impl Notify {
msg.timeout += instant - self.messages.first().map_or(instant, |m| m.instant);
self.messages.push(msg);
emit!(Call(Cmd::args("update_notify", vec![0.to_string()]), Layer::App));
emit!(Call(Cmd::args("update_notify", &[0]), Layer::App));
}
}

View file

@ -62,7 +62,7 @@ impl Notify {
self.tick_handle = Some(tokio::spawn(async move {
tokio::time::sleep(interval).await;
emit!(Call(Cmd::args("update_notify", vec![interval.as_secs_f64().to_string()]), Layer::App));
emit!(Call(Cmd::args("update_notify", &[interval.as_secs_f64()]), Layer::App));
}));
}
}

View file

@ -41,7 +41,7 @@ impl Tab {
}
}
ManagerProxy::hover(None);
ManagerProxy::hover(None, self.idx);
render!();
}
}

View file

@ -40,7 +40,7 @@ impl Tab {
let (Ok(s) | Err(InputError::Typed(s))) = result else { continue };
emit!(Call(
Cmd::args("filter_do", vec![s])
Cmd::args("filter_do", &[s])
.with_bool("smart", opt.case == FilterCase::Smart)
.with_bool("insensitive", opt.case == FilterCase::Insensitive)
.with_bool("done", done),
@ -72,7 +72,7 @@ impl Tab {
self.current.repos(hovered.as_ref());
if self.current.hovered().map(|f| &f.url) != hovered.as_ref() {
ManagerProxy::hover(None);
ManagerProxy::hover(None, self.idx);
}
render!();

View file

@ -40,7 +40,7 @@ impl Tab {
while let Some(Ok(s)) | Some(Err(InputError::Typed(s))) = rx.next().await {
emit!(Call(
Cmd::args("find_do", vec![s])
Cmd::args("find_do", &[s])
.with_bool("previous", opt.prev)
.with_bool("smart", opt.case == FilterCase::Smart)
.with_bool("insensitive", opt.case == FilterCase::Insensitive),

View file

@ -15,7 +15,7 @@ impl Tab {
self.apply_files_attrs();
if hovered.as_ref() != self.current.hovered().map(|f| &f.url) {
ManagerProxy::hover(hovered);
ManagerProxy::hover(hovered, self.idx);
} else if self.current.hovered().is_some_and(|f| f.is_dir()) {
ManagerProxy::peek(true);
}

View file

@ -31,6 +31,6 @@ impl Tab {
self.cd(parent.clone());
FilesOp::Creating(parent, vec![File::from_dummy(opt.target.clone(), None)]).emit();
ManagerProxy::hover(Some(opt.target));
ManagerProxy::hover(Some(opt.target), self.idx);
}
}

View file

@ -33,7 +33,7 @@ impl TryFrom<Cmd> for Opt {
impl From<Opt> for Cmd {
fn from(value: Opt) -> Self {
let mut cmd =
Cmd::args("", vec![value.id]).with_bool("sync", value.sync).with_any("args", value.args);
Cmd::args("", &[value.id]).with_bool("sync", value.sync).with_any("args", value.args);
if let Some(cb) = value.cb {
cmd = cmd.with_any("callback", cb);

View file

@ -38,7 +38,7 @@ impl Utils {
let cand = cand?;
cands.push(Control {
on: Self::parse_keys(cand.raw_get("on")?)?,
run: vec![Cmd::args("callback", vec![i.to_string()]).with_any("tx", tx.clone())],
run: vec![Cmd::args("callback", &[i]).with_any("tx", tx.clone())],
desc: cand.raw_get("desc").ok(),
});
}

View file

@ -71,9 +71,7 @@ impl Utils {
};
emit!(Call(
Cmd::args("plugin", vec![name.to_owned()])
.with_bool("sync", true)
.with_any("callback", callback),
Cmd::args("plugin", &[name]).with_bool("sync", true).with_any("callback", callback),
Layer::App
));

View file

@ -10,9 +10,6 @@ impl CompletionProxy {
#[inline]
pub fn trigger(word: &str, ticket: usize) {
emit!(Call(
Cmd::args("trigger", vec![word.to_owned()]).with("ticket", ticket),
Layer::Completion
));
emit!(Call(Cmd::args("trigger", &[word]).with("ticket", ticket), Layer::Completion));
}
}

View file

@ -14,6 +14,6 @@ impl InputProxy {
#[inline]
pub fn complete(word: &str, ticket: usize) {
emit!(Call(Cmd::args("complete", vec![word.to_owned()]).with("ticket", ticket), Layer::Input));
emit!(Call(Cmd::args("complete", &[word]).with("ticket", ticket), Layer::Input));
}
}

View file

@ -11,9 +11,9 @@ impl ManagerProxy {
}
#[inline]
pub fn hover(url: Option<Url>) {
pub fn hover(url: Option<Url>, tab: usize) {
emit!(Call(
Cmd::args("hover", url.map_or_else(Vec::new, |u| vec![u.to_string()])),
Cmd::args("hover", &url.map_or_else(Vec::new, |u| vec![u])).with("tab", tab),
Layer::Manager
));
}
@ -49,7 +49,7 @@ impl ManagerProxy {
#[inline]
pub fn update_paged_by(page: usize, only_if: &Url) {
emit!(Call(
Cmd::args("update_paged", vec![page.to_string()]).with_any("only-if", only_if.clone()),
Cmd::args("update_paged", &[page]).with_any("only-if", only_if.clone()),
Layer::Manager
));
}

View file

@ -7,18 +7,18 @@ pub struct TabProxy;
impl TabProxy {
#[inline]
pub fn cd(target: &Url) {
emit!(Call(Cmd::args("cd", vec![target.to_string()]), Layer::Manager));
emit!(Call(Cmd::args("cd", &[target]), Layer::Manager));
}
#[inline]
pub fn reveal(target: &Url) {
emit!(Call(Cmd::args("reveal", vec![target.to_string()]), Layer::Manager));
emit!(Call(Cmd::args("reveal", &[target]), Layer::Manager));
}
#[inline]
pub fn search_do(opt: SearchOpt) {
emit!(Call(
Cmd::args("search_do", vec![opt.subject]).with("via", opt.via).with("args", opt.args_raw),
Cmd::args("search_do", &[opt.subject]).with("via", opt.via).with("args", opt.args_raw),
Layer::Manager
));
}

View file

@ -21,7 +21,7 @@ impl Process {
let (id, cmd) = (task.id, task.cmd.clone());
let result = super::shell(task.into());
if let Err(e) = result {
AppProxy::notify_warn(&cmd.to_string_lossy(), &format!("Failed to spawn process: {e}"));
AppProxy::notify_warn(&cmd.to_string_lossy(), format!("Failed to spawn process: {e}"));
return self.succ(id);
}

View file

@ -16,10 +16,14 @@ impl Cmd {
pub fn new(name: &str) -> Self { Self { name: name.to_owned(), ..Default::default() } }
#[inline]
pub fn args(name: &str, args: Vec<String>) -> Self {
pub fn args(name: &str, args: &[impl ToString]) -> Self {
Self {
name: name.to_owned(),
args: args.into_iter().enumerate().map(|(i, s)| (i.to_string(), Data::String(s))).collect(),
args: args
.iter()
.enumerate()
.map(|(i, s)| (i.to_string(), Data::String(s.to_string())))
.collect(),
}
}