feat: new follow command to follow files pointed to by symlinks (#2543)

This commit is contained in:
三咲雅 · Misaki Masa 2025-03-28 20:14:53 +08:00 committed by GitHub
parent a25bbe2e9d
commit 0ada74efbe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 60 additions and 11 deletions

View file

@ -2,6 +2,7 @@ use std::{env, ffi::OsStr, fmt::Write};
use regex::Regex;
use yazi_adapter::Mux;
use yazi_shared::timestamp_us;
use super::Actions;
@ -100,6 +101,9 @@ impl Actions {
writeln!(s, " xclip : {}", Self::process_output("xclip", "-version"))?;
writeln!(s, " xsel : {}", Self::process_output("xsel", "--version"))?;
writeln!(s, "\nRoutine")?;
writeln!(s, " `file -bL --mime-type`: {}", Self::file1_output())?;
writeln!(
s,
"\n\nSee https://yazi-rs.github.io/docs/plugins/overview#debugging on how to enable logging or debug runtime errors."
@ -132,4 +136,19 @@ impl Actions {
Err(e) => format!("{e}"),
}
}
fn file1_output() -> String {
use std::io::Write;
let p = env::temp_dir().join(format!("yazi-debug-{}", timestamp_us()));
std::fs::File::create_new(&p).map(|mut f| f.write_all(b"Hello, World!")).ok();
let cmd = env::var_os("YAZI_FILE_ONE").unwrap_or("file".into());
match std::process::Command::new(cmd).args(["-bL", "--mime-type"]).arg(&p).output() {
Ok(out) => {
String::from_utf8_lossy(&out.stdout).trim().lines().next().unwrap_or_default().to_owned()
}
Err(e) => format!("{e}"),
}
}
}

View file

@ -128,6 +128,7 @@ keymap = [
{ on = [ "g", "c" ], run = "cd ~/.config", desc = "Go ~/.config" },
{ on = [ "g", "d" ], run = "cd ~/Downloads", desc = "Go ~/Downloads" },
{ on = [ "g", "<Space>" ], run = "cd --interactive", desc = "Jump interactively" },
{ on = [ "g", "f" ], run = "follow", desc = "Follow hovered symlink" },
# Tabs
{ on = "t", run = "tab_create --current", desc = "Create a new tab with CWD" },
@ -228,8 +229,8 @@ keymap = [
keymap = [
{ on = "<C-c>", run = "close", desc = "Cancel input" },
{ on = "<Enter>", run = "close --submit", desc = "Submit input" },
{ on = "<Esc>", run = "escape", desc = "Go back the normal mode, or cancel input" },
{ on = "<C-[>", run = "escape", desc = "Go back the normal mode, or cancel input" },
{ on = "<Esc>", run = "escape", desc = "Back to normal mode, or cancel input" },
{ on = "<C-[>", run = "escape", desc = "Back to normal mode, or cancel input" },
# Mode
{ on = "i", run = "insert", desc = "Enter insert mode" },
@ -285,14 +286,14 @@ keymap = [
{ on = "<A-d>", run = "kill forward", desc = "Kill forwards to the end of the current word" },
# Cut/Yank/Paste
{ on = "d", run = "delete --cut", desc = "Cut the selected characters" },
{ on = "D", run = [ "delete --cut", "move eol" ], desc = "Cut until the EOL" },
{ on = "c", run = "delete --cut --insert", desc = "Cut the selected characters, and enter insert mode" },
{ on = "C", run = [ "delete --cut --insert", "move eol" ], desc = "Cut until the EOL, and enter insert mode" },
{ on = "x", run = [ "delete --cut", "move 1 --in-operating" ], desc = "Cut the current character" },
{ on = "y", run = "yank", desc = "Copy the selected characters" },
{ on = "p", run = "paste", desc = "Paste the copied characters after the cursor" },
{ on = "P", run = "paste --before", desc = "Paste the copied characters before the cursor" },
{ on = "d", run = "delete --cut", desc = "Cut selected characters" },
{ on = "D", run = [ "delete --cut", "move eol" ], desc = "Cut until EOL" },
{ on = "c", run = "delete --cut --insert", desc = "Cut selected characters, and enter insert mode" },
{ on = "C", run = [ "delete --cut --insert", "move eol" ], desc = "Cut until EOL, and enter insert mode" },
{ on = "x", run = [ "delete --cut", "move 1 --in-operating" ], desc = "Cut current character" },
{ on = "y", run = "yank", desc = "Copy selected characters" },
{ on = "p", run = "paste", desc = "Paste copied characters after the cursor" },
{ on = "P", run = "paste --before", desc = "Paste copied characters before the cursor" },
# Undo/Redo
{ on = "u", run = "undo", desc = "Undo the last operation" },
@ -361,5 +362,5 @@ keymap = [
{ on = "<Down>", run = "arrow next", desc = "Next line" },
# Filtering
{ on = "f", run = "filter", desc = "Apply a filter for the help items" },
{ on = "f", run = "filter", desc = "Filter help items" },
]

View file

@ -0,0 +1,24 @@
use yazi_fs::clean_url;
use yazi_shared::event::CmdCow;
use crate::tab::Tab;
struct Opt;
impl From<CmdCow> for Opt {
fn from(_: CmdCow) -> Self { Self }
}
impl Tab {
#[yazi_codegen::command]
pub fn follow(&mut self, _: Opt) {
let Some(file) = self.hovered() else { return };
let Some(link_to) = &file.link_to else { return };
if link_to.is_absolute() {
self.reveal(link_to.to_owned());
} else if let Some(p) = file.url.parent_url() {
self.reveal(clean_url(&p.join(link_to)));
}
}
}

View file

@ -23,4 +23,5 @@ yazi_macro::mod_flat!(
update_peeked
update_spotted
visual_mode
follow,
);

View file

@ -97,6 +97,7 @@ impl<'a> Executor<'a> {
on!(ACTIVE, forward);
on!(ACTIVE, cd);
on!(ACTIVE, reveal);
on!(ACTIVE, follow);
// Toggle
on!(ACTIVE, toggle);

View file

@ -5,6 +5,9 @@ use yazi_shared::url::{Loc, Url};
use crate::CWD;
#[inline]
pub fn clean_url(url: &Url) -> Url { Url::from(clean_path(url)) }
#[inline]
pub fn clean_path(path: impl AsRef<Path>) -> PathBuf { _clean_path(path.as_ref()) }