mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-24 00:01:03 +00:00
Merge 529ecbe6a6 into 6aa75594db
This commit is contained in:
commit
9bba3830f6
13 changed files with 271 additions and 53 deletions
|
|
@ -25,6 +25,8 @@ 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));
|
||||
|
||||
fields.add_static_field("folder", |_, me| {
|
||||
me.tab
|
||||
.hovered_folder()
|
||||
|
|
|
|||
|
|
@ -37,13 +37,13 @@ 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 {
|
||||
preview.skip = skip;
|
||||
}
|
||||
preview.skip = skip;
|
||||
}
|
||||
|
||||
if let Some(index) = form.search_idx {
|
||||
preview.search_idx = Some(index);
|
||||
}
|
||||
|
||||
if hovered.is_dir() {
|
||||
|
|
|
|||
44
yazi-binding/src/elements/highlight.rs
Normal file
44
yazi-binding/src/elements/highlight.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Result as LuaResult, Value};
|
||||
|
||||
const EXPECTED: &str = "expected a table containing a line and a length";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HighlightPosition {
|
||||
pub line: usize,
|
||||
pub col: usize,
|
||||
pub length: usize,
|
||||
}
|
||||
|
||||
impl HighlightPosition {
|
||||
pub fn compose(lua: &Lua) -> LuaResult<Value> {
|
||||
let new = lua.create_function(|_, (line, col, length): (usize, usize, usize)| {
|
||||
Ok(Self { line, col, length })
|
||||
})?;
|
||||
|
||||
let tbl = lua.create_table_from([("new", new)])?;
|
||||
tbl.into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for HighlightPosition {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(tbl) => Ok(Self {
|
||||
line: tbl.raw_get("line")?,
|
||||
col: tbl.raw_get("col")?,
|
||||
length: tbl.raw_get("length")?,
|
||||
}),
|
||||
_ => Err(EXPECTED.into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for HighlightPosition {
|
||||
fn into_lua(self, lua: &Lua) -> LuaResult<Value> {
|
||||
let tbl = lua.create_table()?;
|
||||
tbl.set("line", self.line)?;
|
||||
tbl.set("col", self.col)?;
|
||||
tbl.set("length", self.length)?;
|
||||
Ok(Value::Table(tbl))
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(align area bar border cell color constraint edge fill gauge layout line list pad rect row span spatial table text wrap);
|
||||
yazi_macro::mod_flat!(align area bar border cell color constraint edge fill gauge highlight layout line list pad rect row span spatial table text wrap);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::{io::{BufRead, BufReader, Cursor, Seek}, path::PathBuf, sync::OnceLock}
|
|||
use anyhow::{Result, anyhow, bail};
|
||||
use ratatui_core::{layout::Size, text::{Line, Span, Text}};
|
||||
use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}};
|
||||
use yazi_binding::elements::HighlightPosition;
|
||||
use yazi_config::{THEME, YAZI};
|
||||
use yazi_runner::previewer::PeekError;
|
||||
use yazi_shared::{id::{Id, Ids}, replace_to_printable};
|
||||
|
|
@ -25,12 +26,17 @@ pub struct Highlighter {
|
|||
}
|
||||
|
||||
impl Highlighter {
|
||||
pub async fn oneshot<P>(path: P, skip: usize, size: Size) -> Result<Text<'static>, PeekError>
|
||||
pub async fn oneshot<P>(
|
||||
path: P,
|
||||
skip: usize,
|
||||
size: Size,
|
||||
position: Option<HighlightPosition>,
|
||||
) -> Result<Text<'static>, PeekError>
|
||||
where
|
||||
P: Into<PathBuf>,
|
||||
{
|
||||
let path = path.into();
|
||||
tokio::task::spawn_blocking(move || Self::make(path, skip, size)?.highlight()).await?
|
||||
tokio::task::spawn_blocking(move || Self::make(path, skip, size)?.highlight(position)).await?
|
||||
}
|
||||
|
||||
fn make<P>(path: P, skip: usize, size: Size) -> Result<Self>
|
||||
|
|
@ -59,7 +65,7 @@ impl Highlighter {
|
|||
|
||||
pub fn abort() { INCR.next(); }
|
||||
|
||||
fn highlight(mut self) -> Result<Text<'static>, PeekError> {
|
||||
fn highlight(mut self, position: Option<HighlightPosition>) -> Result<Text<'static>, PeekError> {
|
||||
self.load_syntax()?;
|
||||
let mut plain = self.syntax.is_none();
|
||||
|
||||
|
|
@ -78,9 +84,9 @@ impl Highlighter {
|
|||
}
|
||||
|
||||
self.ensure_not_cancelled()?;
|
||||
if plain && !self.process_plain(&buf, &mut i, &mut lines)? {
|
||||
if plain && !self.process_plain(&buf, &mut i, &position, &mut lines)? {
|
||||
break;
|
||||
} else if !plain && !self.process_hyper(&buf, &mut i, &mut lines)? {
|
||||
} else if !plain && !self.process_hyper(&buf, &mut i, &position, &mut lines)? {
|
||||
break;
|
||||
}
|
||||
buf.clear();
|
||||
|
|
@ -89,11 +95,16 @@ impl Highlighter {
|
|||
if self.skip > 0 && i < self.skip + self.size.height as usize {
|
||||
return Err(PeekError::Exceeded(i.saturating_sub(self.size.height as _)));
|
||||
}
|
||||
|
||||
Ok(Text::from(lines))
|
||||
}
|
||||
|
||||
fn process_plain(&mut self, buf: &[u8], i: &mut usize, lines: &mut Vec<Line>) -> Result<bool> {
|
||||
fn process_plain(
|
||||
&mut self,
|
||||
buf: &[u8],
|
||||
i: &mut usize,
|
||||
position: &Option<HighlightPosition>,
|
||||
lines: &mut Vec<Line>,
|
||||
) -> Result<bool> {
|
||||
let b = replace_to_printable(buf, true, YAZI.preview.tab_size, false);
|
||||
let s = String::from_utf8_lossy(&b);
|
||||
|
||||
|
|
@ -107,20 +118,31 @@ impl Highlighter {
|
|||
if *i > self.skip + self.size.height as usize {
|
||||
return Ok(false);
|
||||
} else if *i > self.skip {
|
||||
lines.push(spans.into_static_line());
|
||||
let mut static_line = spans.into_static_line();
|
||||
if let Some(pos) = position
|
||||
&& pos.line == *i
|
||||
{
|
||||
static_line.style = ratatui_core::style::Style::new().bg(ratatui_core::style::Color::Red);
|
||||
}
|
||||
lines.push(static_line);
|
||||
}
|
||||
self.ensure_not_cancelled()?;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn process_hyper(&mut self, buf: &[u8], i: &mut usize, lines: &mut Vec<Line>) -> Result<bool> {
|
||||
fn process_hyper(
|
||||
&mut self,
|
||||
buf: &[u8],
|
||||
i: &mut usize,
|
||||
position: &Option<HighlightPosition>,
|
||||
lines: &mut Vec<Line>,
|
||||
) -> Result<bool> {
|
||||
let Some(syntax) = self.syntax else { bail!("No syntax") };
|
||||
let h = self.inner.get_or_insert_with(|| HighlightLines::new(syntax, self.theme));
|
||||
|
||||
let s = String::from_utf8_lossy(buf);
|
||||
let line = [Self::to_line_widget(h.highlight_line(&s, self.syntaxes)?)];
|
||||
|
||||
let line = [Self::to_line_widget(h.highlight_line(&s, self.syntaxes)?)];
|
||||
let mut it = LineIter::parsed(&line, YAZI.preview.tab_size);
|
||||
if let Some(wrap) = YAZI.preview.wrap.into() {
|
||||
it = it.wrapped(wrap, self.size.width);
|
||||
|
|
@ -131,10 +153,17 @@ impl Highlighter {
|
|||
if *i > self.skip + self.size.height as usize {
|
||||
return Ok(false);
|
||||
} else if *i > self.skip {
|
||||
lines.push(spans.into_static_line());
|
||||
let mut static_line = spans.into_static_line();
|
||||
if let Some(pos) = position
|
||||
&& pos.line == *i
|
||||
{
|
||||
static_line.style = ratatui_core::style::Style::new().bg(ratatui_core::style::Color::Red);
|
||||
}
|
||||
lines.push(static_line);
|
||||
}
|
||||
self.ensure_not_cancelled()?;
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,9 +48,10 @@ impl MgrProxy {
|
|||
cha: job.file.cha,
|
||||
mime: job.mime,
|
||||
|
||||
skip: job.skip,
|
||||
area: area.into(),
|
||||
data: vec![
|
||||
skip: job.skip,
|
||||
search_idx: job.search_idx,
|
||||
area: area.into(),
|
||||
data: vec![
|
||||
Renderable::Clear(Default::default()).with_area(area),
|
||||
Renderable::from(Error::custom(error)).with_area(area),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@ use yazi_vfs::{VfsEntries, VfsFilesOp};
|
|||
|
||||
use crate::{AppProxy, Highlighter, MgrProxy, tab::PreviewLock};
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Preview {
|
||||
pub lock: Option<PreviewLock>,
|
||||
pub skip: usize,
|
||||
pub lock: Option<PreviewLock>,
|
||||
pub skip: usize,
|
||||
pub search_idx: Option<usize>,
|
||||
|
||||
handle: Option<JoinHandle<()>>,
|
||||
pub folder_lock: Option<UrlBuf>,
|
||||
|
|
@ -35,7 +36,8 @@ impl Preview {
|
|||
};
|
||||
|
||||
self.abort();
|
||||
let job = PeekJob { previewer, file, mime, skip: self.skip };
|
||||
|
||||
let job = PeekJob { previewer, file, mime, skip: self.skip, search_idx: self.search_idx };
|
||||
|
||||
self.handle = Some(tokio::spawn(async move {
|
||||
let mut rx = RUNNER.peek(&job).await;
|
||||
|
|
@ -83,6 +85,7 @@ impl Preview {
|
|||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.search_idx = None;
|
||||
self.abort();
|
||||
ADAPTOR.image_hide().ok();
|
||||
render!(self.lock.take().is_some())
|
||||
|
|
@ -101,7 +104,8 @@ impl Preview {
|
|||
}
|
||||
|
||||
pub fn same_lock(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_file(file, mime) && matches!(&self.lock, Some(l) if l.skip == self.skip)
|
||||
self.same_file(file, mime)
|
||||
&& matches!(&self.lock, Some(l) if l.skip == self.skip && l.search_idx == self.search_idx)
|
||||
}
|
||||
|
||||
pub fn same_folder(&self, url: &UrlBuf) -> bool { self.folder_lock.as_ref() == Some(url) }
|
||||
|
|
|
|||
|
|
@ -11,9 +11,10 @@ pub struct PreviewLock {
|
|||
pub cha: Cha,
|
||||
pub mime: Symbol<str>,
|
||||
|
||||
pub skip: usize,
|
||||
pub area: Rect,
|
||||
pub data: Vec<Renderable>,
|
||||
pub skip: usize,
|
||||
pub search_idx: Option<usize>,
|
||||
pub area: Rect,
|
||||
pub data: Vec<Renderable>,
|
||||
}
|
||||
|
||||
impl_data_any!(PreviewLock);
|
||||
|
|
@ -29,9 +30,10 @@ impl TryFrom<Table> for PreviewLock {
|
|||
cha: f.cha,
|
||||
mime: t.raw_get::<LuaString>("mime")?.to_str()?.intern(),
|
||||
|
||||
skip: t.raw_get("skip")?,
|
||||
area: t.raw_get("area")?,
|
||||
data: Default::default(),
|
||||
skip: t.raw_get("skip")?,
|
||||
search_idx: t.raw_get("search_idx")?,
|
||||
area: t.raw_get("area")?,
|
||||
data: Default::default(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub struct PeekForm {
|
|||
pub force: bool,
|
||||
pub only_if: Option<UrlBuf>,
|
||||
pub upper_bound: bool,
|
||||
pub search_idx: Option<usize>,
|
||||
}
|
||||
|
||||
impl From<ActionCow> for PeekForm {
|
||||
|
|
@ -16,6 +17,7 @@ impl From<ActionCow> for PeekForm {
|
|||
force: a.bool("force"),
|
||||
only_if: a.take("only-if").ok(),
|
||||
upper_bound: a.bool("upper-bound"),
|
||||
search_idx: a.take("search-idx").ok(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,104 @@
|
|||
local M = {}
|
||||
|
||||
local function get_search_occurrences(url)
|
||||
if not url.is_search then
|
||||
return
|
||||
end
|
||||
-- Shoud we encode ~ too?
|
||||
local subject_len, occurrences = tostring(url):match("^search://([^~]+)~(.-)//")
|
||||
local lines = {}
|
||||
for occurrence in occurrences:gmatch("[^,]+") do
|
||||
local line, col = occurrence:match("(%d+)-(%d+)")
|
||||
table.insert(lines, { tonumber(line), tonumber(col) })
|
||||
end
|
||||
|
||||
if #lines == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
return tonumber(subject_len), lines
|
||||
end
|
||||
|
||||
local function get_next_occurrence_idx(search_idx, direction, occurrences_len)
|
||||
local index
|
||||
|
||||
if direction == "up" then
|
||||
index = (search_idx or 1) - 1
|
||||
if index < 1 then
|
||||
index = occurrences_len
|
||||
end
|
||||
else
|
||||
index = (search_idx or 1) + 1
|
||||
if index > occurrences_len then
|
||||
index = 1
|
||||
end
|
||||
end
|
||||
|
||||
return index
|
||||
end
|
||||
|
||||
function M:peek(job)
|
||||
local subject_len, search_occurrences = get_search_occurrences(job.file.url)
|
||||
local search_idx = job.search_idx
|
||||
|
||||
if search_idx == nil and search_occurrences then
|
||||
local occurrence = search_occurrences[1]
|
||||
local line = occurrence[1]
|
||||
local skip = math.max(0, line - 1)
|
||||
ya.emit("peek", {
|
||||
skip,
|
||||
only_if = job.file.url,
|
||||
search_idx = 1,
|
||||
})
|
||||
return
|
||||
end
|
||||
|
||||
local occurrence
|
||||
if search_occurrences and search_idx then
|
||||
occurrence = search_occurrences[search_idx]
|
||||
job.position = {
|
||||
line = occurrence[1],
|
||||
col = occurrence[2],
|
||||
length = subject_len,
|
||||
}
|
||||
end
|
||||
|
||||
local err, bound = ya.preview_code(job)
|
||||
if bound then
|
||||
ya.emit("peek", { bound, only_if = job.file.url, upper_bound = true })
|
||||
ya.emit("peek", { bound, only_if = job.file.url, upper_bound = true, search_idx = search_idx })
|
||||
elseif err and not err:find("cancelled", 1, true) then
|
||||
require("empty").msg(job, err)
|
||||
end
|
||||
end
|
||||
|
||||
function M:seek(job)
|
||||
local direction = job.units > 0 and "down" or "up"
|
||||
local search_idx = cx.active.preview.search_idx
|
||||
|
||||
local h = cx.active.current.hovered
|
||||
if not h or h.url ~= job.file.url then
|
||||
return
|
||||
end
|
||||
|
||||
local _, search_occurrences = get_search_occurrences(job.file.url)
|
||||
if search_occurrences then
|
||||
local next_occurrence_idx = get_next_occurrence_idx(search_idx, direction, #search_occurrences)
|
||||
local occurrence = search_occurrences[next_occurrence_idx]
|
||||
local line = occurrence[1]
|
||||
local skip = math.max(0, line - 1)
|
||||
|
||||
ya.emit("peek", { skip, only_if = job.file.url, search_idx = next_occurrence_idx })
|
||||
return
|
||||
end
|
||||
|
||||
local step = math.floor(job.units * job.area.h / 10)
|
||||
step = step == 0 and ya.clamp(-1, job.units, 1) or step
|
||||
local skip = math.max(0, cx.active.preview.skip + step)
|
||||
|
||||
ya.emit("peek", {
|
||||
math.max(0, cx.active.preview.skip + step),
|
||||
skip,
|
||||
only_if = job.file.url,
|
||||
search_idx = search_idx,
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
|||
71
yazi-plugin/src/external/rg.rs
vendored
71
yazi-plugin/src/external/rg.rs
vendored
|
|
@ -1,4 +1,4 @@
|
|||
use std::{path::Path, process::Stdio};
|
||||
use std::process::Stdio;
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::{self, UnboundedReceiver}};
|
||||
|
|
@ -15,10 +15,10 @@ pub struct RgOpt {
|
|||
|
||||
pub fn rg(opt: RgOpt) -> Result<UnboundedReceiver<File>> {
|
||||
let mut child = Command::new("rg")
|
||||
.args(["--color=never", "--files-with-matches", "--smart-case"])
|
||||
.args(["--color=never", "--no-heading", "--column", "--smart-case"])
|
||||
.arg(if opt.hidden { "--hidden" } else { "--no-hidden" })
|
||||
.args(opt.args)
|
||||
.arg(opt.subject)
|
||||
.arg(opt.subject.clone())
|
||||
.current_dir(&*opt.cwd.as_url().unified_path())
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
|
|
@ -29,18 +29,67 @@ pub fn rg(opt: RgOpt) -> Result<UnboundedReceiver<File>> {
|
|||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Ok(Some(line)) = it.next_line().await {
|
||||
if Path::new(&line).is_absolute() {
|
||||
continue;
|
||||
let mut current_file: String = String::new();
|
||||
let mut current_occurrences: Vec<(u32, u32)> = vec![];
|
||||
|
||||
while let Ok(Some(search_line)) = it.next_line().await {
|
||||
let Some((file_path, line, col)) = parse_rg_line(&search_line) else { continue };
|
||||
|
||||
if current_file != file_path {
|
||||
let Some(url) =
|
||||
build_file_url(opt.cwd.clone(), opt.subject.clone(), ¤t_file, ¤t_occurrences)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Ok(file) = File::new(url).await {
|
||||
tx.send(file).ok();
|
||||
}
|
||||
current_file = file_path.clone();
|
||||
current_occurrences = vec![];
|
||||
}
|
||||
let Ok(url) = opt.cwd.try_join(line) else {
|
||||
continue;
|
||||
};
|
||||
if let Ok(file) = File::new(url).await {
|
||||
tx.send(file).ok();
|
||||
|
||||
current_occurrences.push((line as u32, col as u32));
|
||||
}
|
||||
|
||||
if current_occurrences.len() > 0 {
|
||||
match build_file_url(opt.cwd, opt.subject, ¤t_file, ¤t_occurrences) {
|
||||
Some(url) => {
|
||||
if let Ok(file) = File::new(url).await {
|
||||
tx.send(file).ok();
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
child.wait().await.ok();
|
||||
});
|
||||
|
||||
Ok(rx)
|
||||
}
|
||||
|
||||
fn build_file_url(
|
||||
cwd: UrlBuf,
|
||||
subject: String,
|
||||
file_path: &str,
|
||||
occurences: &Vec<(u32, u32)>,
|
||||
) -> Option<UrlBuf> {
|
||||
let occurrences_str =
|
||||
occurences.iter().map(|(line, col)| format!("{line}-{col}")).collect::<Vec<_>>().join(",");
|
||||
let search_str = format!("{}~{}", subject.len(), occurrences_str);
|
||||
let url = cwd.try_join(file_path).ok().and_then(|u| u.into_search(search_str).ok());
|
||||
|
||||
url
|
||||
}
|
||||
|
||||
fn parse_rg_line(line: &str) -> Option<(String, usize, usize)> {
|
||||
let mut parts = line.split(':');
|
||||
|
||||
let (file, line, col) = (parts.next()?, parts.next()?, parts.next()?);
|
||||
if file.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((file.to_owned(), line.parse().ok()?, col.parse().ok()?))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use mlua::{ExternalError, Function, IntoLuaMulti, Lua, Table, Value};
|
||||
use yazi_binding::{Error, elements::Area};
|
||||
use yazi_binding::{Error, elements::{Area, HighlightPosition}};
|
||||
use yazi_core::{Highlighter, MgrProxy, tab::PreviewLock};
|
||||
use yazi_fs::FsUrl;
|
||||
use yazi_runner::previewer::PeekError;
|
||||
|
|
@ -15,10 +15,12 @@ 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 inner = match Highlighter::oneshot(path, lock.skip, area.size(), position).await {
|
||||
Ok(text) => text,
|
||||
Err(e @ PeekError::Exceeded(max)) => return (e, max).into_lua_multi(&lua),
|
||||
Err(e) => {
|
||||
|
|
@ -33,6 +35,9 @@ 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)?;
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ use yazi_shared::{data::Sendable, pool::Symbol};
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PeekJob {
|
||||
pub previewer: PreviewerArc,
|
||||
pub file: File,
|
||||
pub mime: Symbol<str>,
|
||||
pub skip: usize,
|
||||
pub previewer: PreviewerArc,
|
||||
pub file: File,
|
||||
pub mime: Symbol<str>,
|
||||
pub skip: usize,
|
||||
pub search_idx: Option<usize>,
|
||||
}
|
||||
|
||||
impl IntoLua for PeekJob {
|
||||
|
|
@ -21,6 +22,7 @@ impl IntoLua for PeekJob {
|
|||
("file", self.file.into_lua(lua)?),
|
||||
("mime", self.mime.into_lua(lua)?),
|
||||
("skip", self.skip.into_lua(lua)?),
|
||||
("search_idx", self.search_idx.into_lua(lua)?),
|
||||
])?
|
||||
.into_lua(lua)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue