This commit is contained in:
sxyazi 2023-11-09 08:18:39 +08:00
parent bbe157bd9f
commit 67fcb484fb
No known key found for this signature in database
11 changed files with 58 additions and 76 deletions

View file

@ -20,7 +20,7 @@ pub async fn zoxide(opt: ZoxideOpt) -> Result<Url> {
let selected = String::from_utf8_lossy(&output.stdout).trim().to_string(); let selected = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !selected.is_empty() { if !selected.is_empty() {
return Ok(Url::from(selected).push_slash()); return Ok(Url::from(selected));
} }
bail!("No match") bail!("No match")
} }

View file

@ -39,7 +39,7 @@ impl File {
cm |= ChaMeta::BAD_LINK; cm |= ChaMeta::BAD_LINK;
} }
if url.was_hidden() { if url.is_hidden() {
cm |= ChaMeta::HIDDEN; cm |= ChaMeta::HIDDEN;
} }
@ -48,7 +48,7 @@ impl File {
#[inline] #[inline]
pub fn from_dummy(url: Url) -> Self { pub fn from_dummy(url: Url) -> Self {
let cm = if url.was_hidden() { ChaMeta::HIDDEN } else { ChaMeta::empty() }; let cm = if url.is_hidden() { ChaMeta::HIDDEN } else { ChaMeta::empty() };
Self { url, cha: Cha::default().with_meta(cm), link_to: None } Self { url, cha: Cha::default().with_meta(cm), link_to: None }
} }

View file

@ -3,14 +3,14 @@ use crate::tab::Tab;
impl Tab { impl Tab {
pub fn back(&mut self) -> bool { pub fn back(&mut self) -> bool {
if let Some(url) = self.backstack.shift_backward().cloned() { if let Some(url) = self.backstack.shift_backward().cloned() {
self.cd(url.push_slash()); self.cd(url);
} }
false false
} }
pub fn forward(&mut self) -> bool { pub fn forward(&mut self) -> bool {
if let Some(url) = self.backstack.shift_forward().cloned() { if let Some(url) = self.backstack.shift_forward().cloned() {
self.cd(url.push_slash()); self.cd(url);
} }
false false
} }

View file

@ -1,26 +1,15 @@
use std::{mem, time::Duration}; use std::{mem, time::Duration};
use tokio::pin; use tokio::{fs, pin};
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::keymap::{Exec, KeymapLayer}; use yazi_config::keymap::{Exec, KeymapLayer};
use yazi_shared::{expand_path, Debounce, InputError, Url}; use yazi_shared::{expand_path, Debounce, InputError, Url};
use crate::{emit, files::{File, FilesOp}, input::InputOpt, tab::Tab}; use crate::{emit, input::InputOpt, tab::Tab};
impl Tab { impl Tab {
pub fn cd(&mut self, mut target: Url) -> bool { pub fn cd(&mut self, target: Url) -> bool {
let mut hovered = None;
if let (false, Some(parent)) = (target.pop_slash(), target.parent_url()) {
emit!(Files(FilesOp::Creating(parent.clone(), File::from_dummy(target.clone()).into_map())));
hovered = Some(target);
target = parent;
}
// Already in target
if self.current.cwd == target { if self.current.cwd == target {
if let Some(h) = hovered {
emit!(Hover(h));
}
return false; return false;
} }
@ -41,11 +30,6 @@ impl Tab {
self.parent = Some(self.history_new(&parent)); self.parent = Some(self.history_new(&parent));
} }
// Hover the file
if let Some(h) = hovered {
emit!(Hover(h));
}
// Backstack // Backstack
if target.is_regular() { if target.is_regular() {
self.backstack.push(target.clone()); self.backstack.push(target.clone());
@ -67,8 +51,16 @@ impl Tab {
while let Some(result) = rx.next().await { while let Some(result) = rx.next().await {
match result { match result {
Ok(s) => { Ok(s) => {
let p = expand_path(s);
let Ok(meta) = fs::metadata(&p).await else {
return;
};
emit!(Call( emit!(Call(
Exec::call("cd", vec![expand_path(s).to_string_lossy().to_string()]).vec(), Exec::call(if meta.is_dir() { "cd" } else { "reveal" }, vec![
p.to_string_lossy().to_string()
])
.vec(),
KeymapLayer::Manager KeymapLayer::Manager
)); ));
} }

View file

@ -1,5 +1,5 @@
use yazi_config::keymap::{Exec, KeymapLayer}; use yazi_config::keymap::{Exec, KeymapLayer};
use yazi_shared::Defer; use yazi_shared::{ends_with_slash, Defer};
use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, tab::Tab, Event, BLOCKER}; use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, tab::Tab, Event, BLOCKER};
@ -18,7 +18,8 @@ impl Tab {
external::zoxide(ZoxideOpt { cwd }).await external::zoxide(ZoxideOpt { cwd }).await
}?; }?;
emit!(Call(Exec::call("cd", vec![url.to_string()]).vec(), KeymapLayer::Manager)); let op = if global && !ends_with_slash(&url) { "reveal" } else { "cd" };
emit!(Call(Exec::call(op, vec![url.to_string()]).vec(), KeymapLayer::Manager));
Ok::<(), anyhow::Error>(()) Ok::<(), anyhow::Error>(())
}); });
false false

View file

@ -9,6 +9,7 @@ mod hidden;
mod jump; mod jump;
mod leave; mod leave;
mod linemode; mod linemode;
mod reveal;
mod search; mod search;
mod select; mod select;
mod shell; mod shell;

View file

@ -0,0 +1,28 @@
use yazi_config::keymap::Exec;
use yazi_shared::Url;
use crate::{emit, files::{File, FilesOp}, tab::Tab};
pub struct Opt<'a> {
target: &'a str,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self { Self { target: e.args.first().map(|s| s.as_str()).unwrap_or("") } }
}
impl Tab {
pub fn reveal<'a>(&mut self, opt: impl Into<Opt<'a>>) -> bool {
let opt = opt.into() as Opt;
let target = Url::from(opt.target);
let Some(parent) = target.parent_url() else {
return false;
};
let b = self.cd(parent.clone());
emit!(Files(FilesOp::Creating(parent.clone(), File::from_dummy(target.clone()).into_map())));
emit!(Hover(target));
b
}
}

View file

@ -35,10 +35,7 @@ impl Tab {
let mut first = true; let mut first = true;
while let Some(chunk) = rx.next().await { while let Some(chunk) = rx.next().await {
if first { if first {
emit!(Call( emit!(Call(Exec::call("cd", vec![cwd.clone().to_string()]).vec(), KeymapLayer::Manager));
Exec::call("cd", vec![cwd.clone().push_slash().to_string()]).vec(),
KeymapLayer::Manager
));
first = false; first = false;
} }
emit!(Files(FilesOp::Part(cwd.clone(), ticket, chunk))); emit!(Files(FilesOp::Part(cwd.clone(), ticket, chunk)));

View file

@ -99,6 +99,7 @@ impl<'a> Executor<'a> {
self.cx.manager.active_mut().cd(expand_url(url)) self.cx.manager.active_mut().cd(expand_url(url))
} }
} }
"reveal" => self.cx.manager.active_mut().reveal(exec),
// Selection // Selection
"select" => { "select" => {

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, env, ffi::OsString, path::{Component, Path, PathBuf, MAIN_SEPARATOR, MAIN_SEPARATOR_STR}}; use std::{borrow::Cow, env, ffi::OsString, path::{Component, Path, PathBuf, MAIN_SEPARATOR}};
use tokio::fs; use tokio::fs;
@ -20,24 +20,13 @@ fn _expand_path(p: &Path) -> PathBuf {
}); });
let p = Path::new(s.as_ref()); let p = Path::new(s.as_ref());
if let (slash, Ok(rest)) = (ends_with_slash(p), p.strip_prefix("~")) { if let Ok(rest) = p.strip_prefix("~") {
#[cfg(unix)] #[cfg(unix)]
let Some(home) = env::var_os("HOME") else { let home = env::var_os("HOME");
return rest.to_path_buf();
};
#[cfg(windows)] #[cfg(windows)]
let Some(home) = env::var_os("USERPROFILE") else { let home = env::var_os("USERPROFILE");
return rest.to_path_buf();
};
let mut home = PathBuf::from(home); return if let Some(p) = home { PathBuf::from(p).join(rest) } else { rest.to_path_buf() };
pop_end_slash(&mut home);
let mut p = if rest == Path::new("") { home } else { home.join(rest) };
if slash {
p.as_mut_os_string().push(MAIN_SEPARATOR_STR);
}
return p;
} }
if p.is_absolute() { if p.is_absolute() {
@ -76,18 +65,6 @@ pub fn ends_with_slash(p: &Path) -> bool {
} }
} }
#[inline]
#[allow(clippy::unnecessary_to_owned)]
pub fn pop_end_slash(p: &mut PathBuf) -> bool {
if !ends_with_slash(p) {
return false;
}
if let Some(n) = p.file_name() {
p.set_file_name(n.to_owned());
}
true
}
pub async fn unique_path(mut p: Url) -> Url { pub async fn unique_path(mut p: Url) -> Url {
let Some(stem) = p.file_stem().map(|s| s.to_owned()) else { let Some(stem) = p.file_stem().map(|s| s.to_owned()) else {
return p; return p;

View file

@ -1,9 +1,7 @@
use std::{ffi::{OsStr, OsString}, fmt::{Debug, Formatter}, ops::{Deref, DerefMut}, path::{Path, PathBuf, MAIN_SEPARATOR_STR}}; use std::{ffi::{OsStr, OsString}, fmt::{Debug, Formatter}, ops::{Deref, DerefMut}, path::{Path, PathBuf}};
use percent_encoding::{percent_decode_str, percent_encode, AsciiSet, CONTROLS}; use percent_encoding::{percent_decode_str, percent_encode, AsciiSet, CONTROLS};
use crate::{ends_with_slash, pop_end_slash};
const ENCODE_SET: &AsciiSet = &CONTROLS.add(b'#'); const ENCODE_SET: &AsciiSet = &CONTROLS.add(b'#');
#[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
@ -155,22 +153,9 @@ impl Url {
pub fn into_os_string(self) -> OsString { self.path.into_os_string() } pub fn into_os_string(self) -> OsString { self.path.into_os_string() }
#[inline] #[inline]
pub fn was_hidden(&self) -> bool { pub fn is_hidden(&self) -> bool {
self.file_name().map_or(false, |s| s.to_string_lossy().starts_with('.')) self.file_name().map_or(false, |s| s.to_string_lossy().starts_with('.'))
} }
#[inline]
pub fn pop_slash(&mut self) -> bool { pop_end_slash(self) }
#[inline]
pub fn push_slash(mut self) -> Self {
if !ends_with_slash(&self) {
self
} else {
self.path.as_mut_os_string().push(MAIN_SEPARATOR_STR);
self
}
}
} }
impl Url { impl Url {