mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: wip store search_idx in preview to be usable in code.lua
This commit is contained in:
parent
ba43e04fb8
commit
947e734860
6 changed files with 156 additions and 63 deletions
|
|
@ -15,7 +15,9 @@ pub(super) struct Preview {
|
|||
impl Deref for Preview {
|
||||
type Target = yazi_core::tab::Preview;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.tab.preview }
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.tab.preview
|
||||
}
|
||||
}
|
||||
|
||||
impl Preview {
|
||||
|
|
@ -27,6 +29,7 @@ impl Preview {
|
|||
impl UserData for Preview {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("skip", |_, me| Ok(me.skip));
|
||||
fields.add_field_method_get("search_idx", |_, me| Ok(me.search_idx));
|
||||
cached_field!(fields, folder, |_, me| {
|
||||
me.tab
|
||||
.hovered_folder()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::mgr::PeekForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_shared::{data::Data, url::UrlLike};
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
|
|
@ -37,8 +37,8 @@ impl Actor for Peek {
|
|||
succ!();
|
||||
}
|
||||
|
||||
let preview = &mut cx.tab_mut().preview;
|
||||
if let Some(skip) = form.skip {
|
||||
let preview = &mut cx.tab_mut().preview;
|
||||
if form.upper_bound {
|
||||
preview.skip = preview.skip.min(skip);
|
||||
} else {
|
||||
|
|
@ -46,6 +46,15 @@ impl Actor for Peek {
|
|||
}
|
||||
}
|
||||
|
||||
tracing::debug!("peeeek boy before set stuff");
|
||||
match form.search_idx {
|
||||
Some(index) => {
|
||||
tracing::debug!("search index setting {}", index);
|
||||
preview.search_idx = Some(index);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
if hovered.is_dir() {
|
||||
cx.tab_mut().preview.go_folder(hovered, folder.map(|(_, cha)| cha), mime, form.force);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -6,20 +6,27 @@ use yazi_adapter::ADAPTOR;
|
|||
use yazi_config::{LAYOUT, YAZI};
|
||||
use yazi_fs::{File, Files, FilesOp, cha::Cha};
|
||||
use yazi_macro::render;
|
||||
use yazi_runner::{RUNNER, previewer::{PeekError, PeekJob}};
|
||||
use yazi_shared::{pool::Symbol, url::{UrlBuf, UrlLike}};
|
||||
use yazi_runner::{
|
||||
RUNNER,
|
||||
previewer::{PeekError, PeekJob},
|
||||
};
|
||||
use yazi_shared::{
|
||||
pool::Symbol,
|
||||
url::{UrlBuf, UrlLike},
|
||||
};
|
||||
use yazi_vfs::{VfsFiles, VfsFilesOp};
|
||||
|
||||
use crate::{AppProxy, Highlighter, MgrProxy, tab::PreviewLock};
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Preview {
|
||||
pub lock: Option<PreviewLock>,
|
||||
pub skip: usize,
|
||||
pub search_idx: Option<usize>,
|
||||
|
||||
handle: Option<JoinHandle<()>>,
|
||||
handle: Option<JoinHandle<()>>,
|
||||
pub folder_lock: Option<UrlBuf>,
|
||||
folder_loader: Option<JoinHandle<()>>,
|
||||
folder_loader: Option<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Preview {
|
||||
|
|
@ -35,8 +42,12 @@ impl Preview {
|
|||
};
|
||||
|
||||
self.abort();
|
||||
|
||||
// let search_first_occurrence = self.get_first_search_occurrence(&file.url);
|
||||
let job = PeekJob { previewer, file, mime, skip: self.skip };
|
||||
|
||||
tracing::debug!("preview {:?}", self);
|
||||
|
||||
self.handle = Some(tokio::spawn(async move {
|
||||
let mut rx = RUNNER.peek(&job).await;
|
||||
match rx.recv().await.unwrap_or(Err(PeekError::Cancelled)) {
|
||||
|
|
@ -85,7 +96,9 @@ impl Preview {
|
|||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.search_idx = None;
|
||||
self.abort();
|
||||
|
||||
ADAPTOR.get().image_hide().ok();
|
||||
render!(self.lock.take().is_some())
|
||||
}
|
||||
|
|
@ -95,7 +108,9 @@ impl Preview {
|
|||
ADAPTOR.get().image_hide().ok();
|
||||
}
|
||||
|
||||
pub fn same_url(&self, url: &UrlBuf) -> bool { matches!(&self.lock, Some(l) if l.url == *url) }
|
||||
pub fn same_url(&self, url: &UrlBuf) -> bool {
|
||||
matches!(&self.lock, Some(l) if l.url == *url)
|
||||
}
|
||||
|
||||
pub fn same_file(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_url(&file.url)
|
||||
|
|
@ -106,5 +121,7 @@ impl Preview {
|
|||
self.same_file(file, mime) && matches!(&self.lock, Some(l) if l.skip == self.skip)
|
||||
}
|
||||
|
||||
pub fn same_folder(&self, url: &UrlBuf) -> bool { self.folder_lock.as_ref() == Some(url) }
|
||||
pub fn same_folder(&self, url: &UrlBuf) -> bool {
|
||||
self.folder_lock.as_ref() == Some(url)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,31 +3,39 @@ use yazi_shared::{event::ActionCow, url::UrlBuf};
|
|||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PeekForm {
|
||||
pub skip: Option<usize>,
|
||||
pub force: bool,
|
||||
pub only_if: Option<UrlBuf>,
|
||||
pub skip: Option<usize>,
|
||||
pub force: bool,
|
||||
pub only_if: Option<UrlBuf>,
|
||||
pub upper_bound: bool,
|
||||
pub search_idx: Option<usize>,
|
||||
}
|
||||
|
||||
impl From<ActionCow> for PeekForm {
|
||||
fn from(mut a: ActionCow) -> Self {
|
||||
Self {
|
||||
skip: a.first().ok(),
|
||||
force: a.bool("force"),
|
||||
only_if: a.take("only-if").ok(),
|
||||
skip: a.first().ok(),
|
||||
force: a.bool("force"),
|
||||
only_if: a.take("only-if").ok(),
|
||||
upper_bound: a.bool("upper-bound"),
|
||||
search_idx: a.take("search_idx").ok(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for PeekForm {
|
||||
fn from(force: bool) -> Self { Self { force, ..Default::default() } }
|
||||
fn from(force: bool) -> Self {
|
||||
Self { force, ..Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for PeekForm {
|
||||
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> { Err("unsupported".into_lua_err()) }
|
||||
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
Err("unsupported".into_lua_err())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for PeekForm {
|
||||
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
|
||||
fn into_lua(self, _: &Lua) -> mlua::Result<Value> {
|
||||
Err("unsupported".into_lua_err())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ local function get_search_occurrences(url)
|
|||
local lines = {}
|
||||
for occurrence in occurrences:gmatch("[^,]+") do
|
||||
local line, col = occurrence:match("(%d+)-(%d+)")
|
||||
ya.dbg("line col:", line, col)
|
||||
table.insert(lines, { tonumber(line), tonumber(col) })
|
||||
end
|
||||
|
||||
|
|
@ -19,35 +18,38 @@ local function get_search_occurrences(url)
|
|||
return lines
|
||||
end
|
||||
|
||||
local function get_next_occurrence(occurrences, current_line, direction)
|
||||
local step = direction == "up" and -1 or 1
|
||||
local start = direction == "up" and #occurrences or 1
|
||||
local stop = direction == "up" and 1 or #occurrences
|
||||
|
||||
for i = start, stop, step do
|
||||
local line = occurrences[i]
|
||||
if go_up and line >= current_line then
|
||||
return line
|
||||
end
|
||||
if direction == "down" and line <= current_line then
|
||||
return line
|
||||
end
|
||||
|
||||
-- TODO: Handle return to first element or last one
|
||||
end
|
||||
end
|
||||
-- local function get_next_occurrence(occurrences, current_line, direction)
|
||||
-- local step = direction == "up" and -1 or 1
|
||||
-- local start = direction == "up" and #occurrences or 1
|
||||
-- local stop = direction == "up" and 1 or #occurrences
|
||||
--
|
||||
-- for i = start, stop, step do
|
||||
-- local line = occurrences[i]
|
||||
-- if go_up and line >= current_line then
|
||||
-- return line
|
||||
-- end
|
||||
-- if direction == "down" and line <= current_line then
|
||||
-- return line
|
||||
-- end
|
||||
--
|
||||
-- -- TODO: Handle return to first element or last one
|
||||
-- end
|
||||
-- end
|
||||
|
||||
function M:peek(job)
|
||||
local search_occurrences = get_search_occurrences(job.file.url)
|
||||
local search_idx = cx.active.preview.search_idx
|
||||
ya.dbg(" search index", search_idx)
|
||||
local occurrence
|
||||
if search_occurrences and search_idx then
|
||||
occurrence = search_occurrences[search_idx]
|
||||
end
|
||||
|
||||
ya.dgb("Peek Occurrence:", occurrence)
|
||||
|
||||
-- Todo: Pass the occurrence for highlighting
|
||||
local err, bound = ya.preview_code(job)
|
||||
ya.dbg("PEEKING broooo", job.file.url, bound)
|
||||
if bound then
|
||||
local search_occurrences = get_search_occurrences(job.file.url)
|
||||
if search_occurrences then
|
||||
local line = search_occurrences[1][1]
|
||||
ya.dbg("liiiiine: ", line)
|
||||
ya.emit("peek", { math.max(0, search_occurrences[1][1] - 1), only_if = job.file.url })
|
||||
return
|
||||
end
|
||||
ya.emit("peek", { bound, only_if = job.file.url, upper_bound = true })
|
||||
elseif err and not err:find("cancelled", 1, true) then
|
||||
require("empty").msg(job, err)
|
||||
|
|
@ -55,8 +57,11 @@ function M:peek(job)
|
|||
end
|
||||
|
||||
function M:seek(job)
|
||||
ya.dbg("UNITS IN SEEK ", job.units)
|
||||
local direction = job.units > 0 and "down" or "up" end
|
||||
local direction = job.units > 0 and "down" or "up"
|
||||
|
||||
local search_idx = cx.active.preview.search_idx
|
||||
ya.dbg(" search index", search_idx)
|
||||
|
||||
local h = cx.active.current.hovered
|
||||
if not h or h.url ~= job.file.url then
|
||||
return
|
||||
|
|
@ -64,20 +69,21 @@ function M:seek(job)
|
|||
|
||||
local search_occurrences = get_search_occurrences(job.file.url)
|
||||
if search_occurrences then
|
||||
local current_line = cx.active.preview.skip + 1
|
||||
|
||||
local next_occurrence = get_next_occurrence(search_occurrences, current_line, direction)
|
||||
|
||||
for _, occurrence in ipairs(search_occurrences) do
|
||||
local search_line = occurrence[1]
|
||||
-- local col = occurrence[2]
|
||||
|
||||
if search_line >= current_line then
|
||||
ya.emit("peek", { math.max(0, search_line - 1), only_if = job.file.url })
|
||||
return
|
||||
end
|
||||
end
|
||||
search_idx = (search_idx or 0) + 1
|
||||
-- local current_line = cx.active.preview.skip + 1
|
||||
-- ya.dbg("Current line:", current_line)
|
||||
-- local next_occurrence = get_next_occurrence(search_occurrences, current_line, direction)
|
||||
-- for _, occurrence in ipairs(search_occurrences) do
|
||||
-- local search_line = occurrence[1]
|
||||
-- -- local col = occurrence[2]
|
||||
--
|
||||
-- if search_line >= current_line then
|
||||
-- ya.emit("peek", { math.max(0, search_line - 1), only_if = job.file.url })
|
||||
-- return
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
|
||||
-- ya.emit("peek", { math.max(0, line - 1), only_if = job.file.url })
|
||||
|
||||
local step = math.floor(job.units * job.area.h / 10)
|
||||
|
|
@ -86,6 +92,7 @@ function M:seek(job)
|
|||
ya.emit("peek", {
|
||||
math.max(0, cx.active.preview.skip + step),
|
||||
only_if = job.file.url,
|
||||
search_idx,
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
use mlua::{ExternalError, Function, IntoLuaMulti, Lua, Table, Value};
|
||||
use yazi_binding::{Error, elements::{Area, Renderable, Text}};
|
||||
// use ratatui::style::Color;
|
||||
use yazi_binding::{
|
||||
Error,
|
||||
elements::{Area, HighlightPosition, Renderable, Text},
|
||||
};
|
||||
use yazi_core::{Highlighter, MgrProxy, tab::PreviewLock};
|
||||
use yazi_fs::FsUrl;
|
||||
use yazi_runner::previewer::PeekError;
|
||||
|
|
@ -14,10 +18,17 @@ impl Utils {
|
|||
pub(super) fn preview_code(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, t: Table| async move {
|
||||
let area: Area = t.raw_get("area")?;
|
||||
let mut lock = PreviewLock::try_from(t)?;
|
||||
// let position: Option<HighlightPosition> = t.raw_get("position").ok();
|
||||
|
||||
let mut lock = PreviewLock::try_from(t)?;
|
||||
let path = lock.url.as_url().unified_path();
|
||||
let inner = match Highlighter::oneshot(path, lock.skip, area.size()).await {
|
||||
|
||||
// let skip = position.map(|p| p.line).unwrap_or(lock.skip);
|
||||
let size = area.size();
|
||||
|
||||
// tracing::debug!("skip size: {size}");
|
||||
|
||||
let inner = match Highlighter::oneshot(path, lock.skip, size).await {
|
||||
Ok(text) => text,
|
||||
Err(e @ PeekError::Exceeded(max)) => return (e, max).into_lua_multi(&lua),
|
||||
Err(e) => {
|
||||
|
|
@ -25,6 +36,8 @@ impl Utils {
|
|||
}
|
||||
};
|
||||
|
||||
// tracing::debug!("Inner: {inner}");
|
||||
|
||||
lock.data = vec![Renderable::Text(Text { area, inner, ..Default::default() })];
|
||||
|
||||
MgrProxy::update_peeked(lock);
|
||||
|
|
@ -32,6 +45,8 @@ impl Utils {
|
|||
})
|
||||
}
|
||||
|
||||
// Note: You need to implement or update Highlighter::oneshot_with_highlight to accept line/column and highlight accordingly.
|
||||
|
||||
pub(super) fn preview_widget(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|_, (t, value): (Table, Value)| async move {
|
||||
let mut lock = PreviewLock::try_from(t)?;
|
||||
|
|
@ -59,3 +74,37 @@ impl Utils {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fn apply_highlight(text: &mut Text, column: usize, length: usize) {
|
||||
// use ratatui::text::Span;
|
||||
// if length == 0 {
|
||||
// return;
|
||||
// }
|
||||
// let Some(line) = text.inner.lines.first_mut() else { return };
|
||||
// let mut new_spans = Vec::new();
|
||||
// let mut char_pos = 0usize;
|
||||
// for span in std::mem::take(&mut line.spans) {
|
||||
// let n = span.content.chars().count();
|
||||
// let range = char_pos..char_pos + n;
|
||||
// if range.end <= column || range.start >= column + length || n == 0 {
|
||||
// new_spans.push(span);
|
||||
// } else {
|
||||
// let chars: Vec<char> = span.content.chars().collect();
|
||||
// let hl_start = column.saturating_sub(char_pos).min(n);
|
||||
// let hl_end = (column + length).saturating_sub(char_pos).min(n);
|
||||
// if hl_start > 0 {
|
||||
// new_spans.push(Span { content: chars[..hl_start].iter().collect(), style: span.style });
|
||||
// }
|
||||
// {
|
||||
// let mut hl_style = span.style;
|
||||
// hl_style.bg = hl_style.bg.or(Some(Color::Yellow));
|
||||
// new_spans.push(Span { content: chars[hl_start..hl_end].iter().collect(), style: hl_style });
|
||||
// }
|
||||
// if hl_end < n {
|
||||
// new_spans.push(Span { content: chars[hl_end..].iter().collect(), style: span.style });
|
||||
// }
|
||||
// }
|
||||
// char_pos = range.end;
|
||||
// }
|
||||
// line.spans = new_spans;
|
||||
// }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue