mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
bbe157bd9f
commit
67fcb484fb
11 changed files with 58 additions and 76 deletions
2
yazi-core/src/external/zoxide.rs
vendored
2
yazi-core/src/external/zoxide.rs
vendored
|
|
@ -20,7 +20,7 @@ pub async fn zoxide(opt: ZoxideOpt) -> Result<Url> {
|
|||
let selected = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
|
||||
if !selected.is_empty() {
|
||||
return Ok(Url::from(selected).push_slash());
|
||||
return Ok(Url::from(selected));
|
||||
}
|
||||
bail!("No match")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ impl File {
|
|||
cm |= ChaMeta::BAD_LINK;
|
||||
}
|
||||
|
||||
if url.was_hidden() {
|
||||
if url.is_hidden() {
|
||||
cm |= ChaMeta::HIDDEN;
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ impl File {
|
|||
|
||||
#[inline]
|
||||
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 }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ use crate::tab::Tab;
|
|||
impl Tab {
|
||||
pub fn back(&mut self) -> bool {
|
||||
if let Some(url) = self.backstack.shift_backward().cloned() {
|
||||
self.cd(url.push_slash());
|
||||
self.cd(url);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn forward(&mut self) -> bool {
|
||||
if let Some(url) = self.backstack.shift_forward().cloned() {
|
||||
self.cd(url.push_slash());
|
||||
self.cd(url);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,15 @@
|
|||
use std::{mem, time::Duration};
|
||||
|
||||
use tokio::pin;
|
||||
use tokio::{fs, pin};
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use yazi_config::keymap::{Exec, KeymapLayer};
|
||||
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 {
|
||||
pub fn cd(&mut self, mut 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
|
||||
pub fn cd(&mut self, target: Url) -> bool {
|
||||
if self.current.cwd == target {
|
||||
if let Some(h) = hovered {
|
||||
emit!(Hover(h));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -41,11 +30,6 @@ impl Tab {
|
|||
self.parent = Some(self.history_new(&parent));
|
||||
}
|
||||
|
||||
// Hover the file
|
||||
if let Some(h) = hovered {
|
||||
emit!(Hover(h));
|
||||
}
|
||||
|
||||
// Backstack
|
||||
if target.is_regular() {
|
||||
self.backstack.push(target.clone());
|
||||
|
|
@ -67,8 +51,16 @@ impl Tab {
|
|||
while let Some(result) = rx.next().await {
|
||||
match result {
|
||||
Ok(s) => {
|
||||
let p = expand_path(s);
|
||||
let Ok(meta) = fs::metadata(&p).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
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
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
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};
|
||||
|
||||
|
|
@ -18,7 +18,8 @@ impl Tab {
|
|||
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>(())
|
||||
});
|
||||
false
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ mod hidden;
|
|||
mod jump;
|
||||
mod leave;
|
||||
mod linemode;
|
||||
mod reveal;
|
||||
mod search;
|
||||
mod select;
|
||||
mod shell;
|
||||
|
|
|
|||
28
yazi-core/src/tab/commands/reveal.rs
Normal file
28
yazi-core/src/tab/commands/reveal.rs
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -35,10 +35,7 @@ impl Tab {
|
|||
let mut first = true;
|
||||
while let Some(chunk) = rx.next().await {
|
||||
if first {
|
||||
emit!(Call(
|
||||
Exec::call("cd", vec![cwd.clone().push_slash().to_string()]).vec(),
|
||||
KeymapLayer::Manager
|
||||
));
|
||||
emit!(Call(Exec::call("cd", vec![cwd.clone().to_string()]).vec(), KeymapLayer::Manager));
|
||||
first = false;
|
||||
}
|
||||
emit!(Files(FilesOp::Part(cwd.clone(), ticket, chunk)));
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ impl<'a> Executor<'a> {
|
|||
self.cx.manager.active_mut().cd(expand_url(url))
|
||||
}
|
||||
}
|
||||
"reveal" => self.cx.manager.active_mut().reveal(exec),
|
||||
|
||||
// Selection
|
||||
"select" => {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
@ -20,24 +20,13 @@ fn _expand_path(p: &Path) -> PathBuf {
|
|||
});
|
||||
|
||||
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)]
|
||||
let Some(home) = env::var_os("HOME") else {
|
||||
return rest.to_path_buf();
|
||||
};
|
||||
let home = env::var_os("HOME");
|
||||
#[cfg(windows)]
|
||||
let Some(home) = env::var_os("USERPROFILE") else {
|
||||
return rest.to_path_buf();
|
||||
};
|
||||
let home = env::var_os("USERPROFILE");
|
||||
|
||||
let mut home = PathBuf::from(home);
|
||||
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;
|
||||
return if let Some(p) = home { PathBuf::from(p).join(rest) } else { rest.to_path_buf() };
|
||||
}
|
||||
|
||||
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 {
|
||||
let Some(stem) = p.file_stem().map(|s| s.to_owned()) else {
|
||||
return p;
|
||||
|
|
|
|||
|
|
@ -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 crate::{ends_with_slash, pop_end_slash};
|
||||
|
||||
const ENCODE_SET: &AsciiSet = &CONTROLS.add(b'#');
|
||||
|
||||
#[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() }
|
||||
|
||||
#[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('.'))
|
||||
}
|
||||
|
||||
#[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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue