feat: pass highlight position from code.lua to highlight.rs module

This commit is contained in:
Jed 2026-06-15 22:06:28 +02:00
parent d95d323a89
commit 04501c6aa9
4 changed files with 43 additions and 33 deletions

View file

@ -1,20 +1,20 @@
use std::{
io::{BufRead, BufReader, Cursor, Seek},
path::PathBuf,
sync::OnceLock,
};
use anyhow::{Result, anyhow, bail};
use ratatui::{
layout::Size,
text::{Line, Span, Text},
};
use std::{
io::{BufRead, BufReader, Cursor, Seek},
path::PathBuf,
sync::OnceLock,
};
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, Ids, replace_to_printable};
@ -37,12 +37,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>
@ -75,7 +80,7 @@ impl Highlighter {
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();
@ -84,7 +89,6 @@ impl Highlighter {
let mut lines = Vec::with_capacity(self.size.height as usize);
let mut inspected = 0u16;
while self.reader.read_until(b'\n', &mut buf).is_ok_and(|n| n > 0) {
// tracing::debug!("{:?}", buf);
if Self::is_binary(&buf, &mut inspected) {
Err(anyhow!("Binary file"))?;
}
@ -95,9 +99,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();
@ -110,7 +114,13 @@ impl Highlighter {
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);
@ -131,11 +141,18 @@ impl Highlighter {
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);
tracing::debug!("s {:?}", s);
let line = [Self::to_line_widget(h.highlight_line(&s, self.syntaxes)?)];
let mut it = LineIter::parsed(&line, YAZI.preview.tab_size);

View file

@ -45,8 +45,6 @@ impl Preview {
let job = PeekJob { previewer, file, mime, skip: self.skip, search_idx: self.search_idx };
tracing::debug!("preview before to peek {:?}", self.search_idx);
self.handle = Some(tokio::spawn(async move {
let mut rx = RUNNER.peek(&job).await;
match rx.recv().await.unwrap_or(Err(PeekError::Cancelled)) {

View file

@ -4,7 +4,8 @@ local function get_search_occurrences(url)
if not url.is_search then
return
end
local occurrences = tostring(url):match("^search://(.-)//")
-- 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+)")
@ -15,7 +16,7 @@ local function get_search_occurrences(url)
return
end
return lines
return tonumber(subject_len), lines
end
local function get_next_occurrence_idx(search_idx, direction, occurrences_len)
@ -37,18 +38,19 @@ local function get_next_occurrence_idx(search_idx, direction, occurrences_len)
end
function M:peek(job)
local search_occurrences = get_search_occurrences(job.file.url)
local subject_len, search_occurrences = get_search_occurrences(job.file.url)
local search_idx = job.search_idx
ya.dbg("code.lua: search_occurrences:", search_occurrences)
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
ya.dbg("code.lua: Occurrence:", occurrence)
-- Todo: Pass the occurrence for highlighting
local err, bound = ya.preview_code(job)
if bound then
ya.emit("peek", { bound, only_if = job.file.url, upper_bound = true })
@ -61,14 +63,13 @@ function M:seek(job)
local direction = job.units > 0 and "down" or "up"
local search_idx = cx.active.preview.search_idx
ya.dbg("search index before to set it in seek", 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)
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]

View file

@ -7,7 +7,7 @@ use yazi_binding::{
use yazi_core::{Highlighter, MgrProxy, tab::PreviewLock};
use yazi_fs::FsUrl;
use yazi_runner::previewer::PeekError;
use yazi_shared::url::AsUrl;
use yazi_shared::url::{AsUrl, UrlLike};
use super::Utils;
@ -20,16 +20,10 @@ impl Utils {
let area: Area = t.raw_get("area")?;
let position: Option<HighlightPosition> = t.raw_get("position").ok();
tracing::debug!("{:?}", position);
let mut lock = PreviewLock::try_from(t)?;
let path = lock.url.as_url().unified_path();
let search_subject = lock.url.as_url().scheme().domain();
tracing::debug!("search subject{:?}", search_subject);
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) => {
// tracing::debug!("{:?}", text);
text