Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions yazi-actor/src/mgr/peek.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::mgr::PeekOpt;
use yazi_proxy::HIDER;
use yazi_shared::data::Data;
use yazi_shared::{data::Data, url::AsUrl};

use crate::{Actor, Ctx};

Expand All @@ -25,7 +25,8 @@ impl Actor for Peek {
let folder = cx.tab().hovered_folder().map(|f| (f.offset, f.cha));

if !cx.tab().preview.same_url(&hovered.url) {
cx.tab_mut().preview.skip = folder.map(|f| f.0).unwrap_or_default();
// set matched line on the top of preview window
cx.tab_mut().preview.skip = folder.map(|f| f.0).unwrap_or_else(|| hovered.url.as_url().line().map_or(0, |l| l.saturating_sub(1)));
}
if !cx.tab().preview.same_file(&hovered, &mime) {
cx.tab_mut().preview.reset();
Expand Down
35 changes: 34 additions & 1 deletion yazi-actor/src/mgr/reveal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_fs::{File, FilesOp};
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::RevealOpt;
use yazi_shared::{data::Data, url::UrlLike};
use yazi_shared::{data::Data, url::{AsUrl, UrlLike}};

use crate::{Actor, Ctx};

Expand All @@ -14,6 +14,15 @@ impl Actor for Reveal {
const NAME: &str = "reveal";

fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
match cx.cwd().is_search() {
true => Self::reveal_search(cx, opt),
false => Self::reveal_regular(cx, opt),
}
}
}

impl Reveal {
fn reveal_regular(cx: &mut Ctx, opt: RevealOpt) -> Result<Data> {
let Some((parent, child)) = opt.target.pair() else { succ!() };

// Cd to the parent directory
Expand All @@ -37,4 +46,28 @@ impl Actor for Reveal {
act!(mgr:watch, cx)?;
succ!();
}

fn reveal_search(cx: &mut Ctx, opt: RevealOpt) -> Result<Data> {
let cwd = cx.cwd().clone();
let tab = cx.tab_mut();
let pos = tab.current.files.iter().position(|f| f.url == opt.target);

if let Some(pos) = pos {
let delta = pos as isize - tab.current.cursor as isize;
tab.current.arrow(delta);
} else if !opt.no_dummy {
let op = FilesOp::Creating(cwd, vec![File::from_dummy(&opt.target, None)]);
tab.current.update_pub(tab.id, op);

if let Some(pos) = tab.current.files.iter().position(|f| f.url == opt.target) {
let delta = pos as isize - tab.current.cursor as isize;
tab.current.arrow(delta);
}
}

act!(mgr:hover, cx, None)?;
act!(mgr:peek, cx)?;
act!(mgr:watch, cx)?;
succ!();
}
}
5 changes: 5 additions & 0 deletions yazi-binding/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,5 +238,10 @@ macro_rules! impl_file_methods {
// TODO: use a cache
Ok(yazi_config::THEME.icon.matches(me).map(Icon::from))
});

$methods.add_method("line", |_, me, ()| {
use yazi_shared::url::AsUrl;
Ok(me.url.as_url().line().map(|v| v as i64))
});
};
}
34 changes: 33 additions & 1 deletion yazi-fs/src/splatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::os::unix::ffi::{OsStrExt, OsStringExt};
#[cfg(windows)]
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::{cell::Cell, ffi::{OsStr, OsString}, iter::{self, Peekable}, mem};
use std::{cell::Cell, ffi::{OsStr, OsString}, fs::OpenOptions, io::Write, iter::{self, Peekable}, mem};

use yazi_shared::url::{AsUrl, Url, UrlCow};

Expand Down Expand Up @@ -81,6 +81,8 @@ where
Some('d') | Some('D') => self.visit_dirname(it, buf),
Some('t') | Some('T') => self.visit_tab(it, buf),
Some('y') | Some('Y') => self.visit_yanked(it, buf),
Some('l') | Some('L') => self.visit_line_number(it, buf),
Some('c') | Some('C') => self.visit_column_number(it, buf),
Some('%') => self.visit_escape(it, buf),
Some('*') => self.visit_selected(it, buf), // TODO: remove this
Some(c) if c.is_ascii_digit() => self.visit_digit(it, buf),
Expand Down Expand Up @@ -192,6 +194,36 @@ where
}
}

fn visit_line_number(&mut self, it: &mut Iter, buf: &mut Buf) {
it.next();
let idx = self.consume_digit(it);

let line_str = self
.src
.selected(self.tab, idx)
.next()
.and_then(|url| url.line())
.map(|line| line.to_string())
.unwrap_or_else(|| "".to_string());

cue(buf, OsStr::new(&line_str));
}

fn visit_column_number(&mut self, it: &mut Iter, buf: &mut Buf) {
it.next();
let idx = self.consume_digit(it);

let col_str = self
.src
.selected(self.tab, idx)
.next()
.and_then(|url| url.column())
.map(|col| col.to_string())
.unwrap_or_else(|| "".to_string());

cue(buf, OsStr::new(&col_str));
}

fn visit_escape(&mut self, it: &mut Iter, buf: &mut Buf) { buf.push(it.next().unwrap()); }

fn visit_unknown(&mut self, it: &mut Iter, buf: &mut Buf) {
Expand Down
7 changes: 7 additions & 0 deletions yazi-plugin/preset/components/entity.lua
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ end

function Entity:highlights()
local name, p = self._file.name, ui.printable

local ok, line = pcall(function() return self._file:line() end)
if ok and line then
local path_str = tostring(self._file.path)
name = name .. ":" .. line .. " (" .. path_str .. ")"
end

local highlights = self._file:highlights()
if not highlights or #highlights == 0 then
return p(name)
Expand Down
30 changes: 23 additions & 7 deletions yazi-plugin/src/external/rg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::process::Stdio;

use anyhow::Result;
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::{self, UnboundedReceiver}};
use yazi_fs::{File, FsUrl};
use yazi_shared::url::{AsUrl, UrlBuf, UrlLike};
use yazi_fs::{File};
use yazi_shared::url::{UrlBuf, UrlLike};
use yazi_vfs::VfsFile;

pub struct RgOpt {
Expand All @@ -13,13 +13,24 @@ pub struct RgOpt {
pub args: Vec<String>,
}

fn parse_rg_line_column(line: &str) -> Option<(&str, usize, usize)> {
let mut parts = line.split(':');

let (f, l, c) = (parts.next()?, parts.next()?, parts.next()?);
if f.is_empty() { return None; }

Some((f, l.parse().ok()?, c.parse().ok()?))
}

pub fn rg(opt: RgOpt) -> Result<UnboundedReceiver<File>> {
let subject = opt.subject.clone();
let cwd = opt.cwd.clone();

let mut child = Command::new("rg")
.args(["--color=never", "--files-with-matches", "--smart-case"])
.args(["--color=never", "--line-number", "--no-heading", "--smart-case", "--column"])
.arg(if opt.hidden { "--hidden" } else { "--no-hidden" })
.args(opt.args)
.arg(opt.subject)
.arg(&*opt.cwd.as_url().unified_path())
.kill_on_drop(true)
.stdout(Stdio::piped())
.stderr(Stdio::null())
Expand All @@ -30,9 +41,14 @@ pub fn rg(opt: RgOpt) -> Result<UnboundedReceiver<File>> {

tokio::spawn(async move {
while let Ok(Some(line)) = it.next_line().await {
let Ok(url) = opt.cwd.try_join(line) else {
continue;
};
let Some((fp, l, c)) = parse_rg_line_column(&line) else { continue };

let url = cwd.try_join(fp)
.ok()
.and_then(|u| u.to_search(&format!("{}#{}:{}", subject, l, c)).ok());

let Some(url) = url else { continue };

if let Ok(file) = File::new(url).await {
tx.send(file).ok();
}
Expand Down
5 changes: 1 addition & 4 deletions yazi-plugin/src/utils/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ impl Utils {
let path = lock.url.as_url().unified_path();
let inner = match Highlighter::new(path).highlight(lock.skip, area.size()).await {
Ok(text) => text,
Err(e @ PeekError::Exceed(max)) => return (e.to_string(), max).into_lua_multi(&lua),
Err(e @ PeekError::Unexpected(_)) => {
return e.to_string().into_lua_multi(&lua);
}
Err(e) => return e.to_string().into_lua_multi(&lua),
};

lock.data = vec![Renderable::Text(Text {
Expand Down
2 changes: 1 addition & 1 deletion yazi-shared/src/scheme/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl<'a> From<crate::url::Encode<'a>> for Encode<'a> {
impl<'a> Encode<'a> {
#[inline]
pub fn domain<'s>(s: &'s str) -> PercentEncode<'s> {
const SET: &AsciiSet = &CONTROLS.add(b'/').add(b':');
const SET: &AsciiSet = &CONTROLS.add(b'/').add(b':').add(b'#');
percent_encode(s.as_bytes(), SET)
}

Expand Down
30 changes: 30 additions & 0 deletions yazi-shared/src/url/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,36 @@ impl<'a> Url<'a> {
})
}

#[inline]
pub fn line(self) -> Option<usize> {
let Self::Search { domain, .. } = self else { return None };
let Some(hash_pos) = domain.find('#') else {
return None
};

let frag = &domain[hash_pos + 1..];
if let Some(colon_pos) = frag.find(':') {
frag[..colon_pos].parse::<usize>().ok()
} else {
frag.parse::<usize>().ok()
}
}

#[inline]
pub fn column(self) -> Option<usize> {
let Self::Search { domain, .. } = self else { return None };
let Some(hash_pos) = domain.find('#') else {
return None
};

let frag = &domain[hash_pos + 1..];
if let Some(colon_pos) = frag.find(':') {
frag[colon_pos + 1..].parse::<usize>().ok()
} else {
None
}
}

#[inline]
pub fn has_base(self) -> bool {
match self {
Expand Down
Loading