From 6a30dfc1372fd05b6038c1fe659275854857551b Mon Sep 17 00:00:00 2001 From: Lex Moskovski Date: Sat, 8 Jun 2024 15:12:22 -0700 Subject: [PATCH] word wrap in preview --- Cargo.lock | 24 +++++++++++++++ yazi-config/preset/yazi.toml | 1 + yazi-config/src/preview/preview.rs | 3 ++ yazi-plugin/Cargo.toml | 1 + yazi-plugin/src/external/highlighter.rs | 39 ++++++++++++++++++------- yazi-plugin/src/utils/preview.rs | 3 +- 6 files changed, 60 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1afd63ed..4e14bd7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1830,6 +1830,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "socket2" version = "0.5.7" @@ -1941,6 +1947,17 @@ dependencies = [ "walkdir", ] +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.59" @@ -2242,6 +2259,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + [[package]] name = "unicode-normalization" version = "0.1.23" @@ -2864,6 +2887,7 @@ dependencies = [ "shell-escape", "shell-words", "syntect", + "textwrap", "tokio", "tokio-stream", "tokio-util", diff --git a/yazi-config/preset/yazi.toml b/yazi-config/preset/yazi.toml index 47b37cf2..30e166a8 100644 --- a/yazi-config/preset/yazi.toml +++ b/yazi-config/preset/yazi.toml @@ -17,6 +17,7 @@ mouse_events = [ "click", "scroll" ] [preview] tab_size = 2 +word_wrap = false max_width = 600 max_height = 900 cache_dir = "" diff --git a/yazi-config/src/preview/preview.rs b/yazi-config/src/preview/preview.rs index d58b0440..d7b2a9be 100644 --- a/yazi-config/src/preview/preview.rs +++ b/yazi-config/src/preview/preview.rs @@ -9,6 +9,7 @@ use crate::{validation::check_validation, Xdg, MERGED_YAZI}; #[derive(Debug, Serialize)] pub struct Preview { pub tab_size: u8, + pub word_wrap: bool, pub max_width: u32, pub max_height: u32, @@ -31,6 +32,7 @@ impl Default for Preview { #[derive(Deserialize, Validate)] struct Shadow { tab_size: u8, + word_wrap: bool, max_width: u32, max_height: u32, @@ -55,6 +57,7 @@ impl Default for Preview { Preview { tab_size: preview.tab_size, + word_wrap: preview.word_wrap, max_width: preview.max_width, max_height: preview.max_height, diff --git a/yazi-plugin/Cargo.toml b/yazi-plugin/Cargo.toml index 467999aa..72f13dcb 100644 --- a/yazi-plugin/Cargo.toml +++ b/yazi-plugin/Cargo.toml @@ -39,6 +39,7 @@ tokio = { version = "1.38.0", features = [ "full" ] } tokio-stream = "0.1.15" tokio-util = "0.7.11" unicode-width = "0.1.13" +textwrap = "0.14.2" yazi-prebuild = "0.1.2" # Logging diff --git a/yazi-plugin/src/external/highlighter.rs b/yazi-plugin/src/external/highlighter.rs index 0e681b96..b6f7b671 100644 --- a/yazi-plugin/src/external/highlighter.rs +++ b/yazi-plugin/src/external/highlighter.rs @@ -6,6 +6,8 @@ use syntect::{dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet} use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}}; use yazi_config::{PREVIEW, THEME}; use yazi_shared::PeekError; +use ratatui::prelude::Rect; +use textwrap::wrap as textwrap_wrap; static INCR: AtomicUsize = AtomicUsize::new(0); static SYNTECT_SYNTAX: OnceLock = OnceLock::new(); @@ -56,20 +58,20 @@ impl Highlighter { syntaxes.find_syntax_by_first_line(&line).ok_or_else(|| anyhow!("No syntax found")) } - pub async fn highlight(&self, skip: usize, limit: usize) -> Result, PeekError> { + pub async fn highlight(&self, skip: usize, area: Rect, wrap: bool) -> Result, PeekError> { let mut reader = BufReader::new(File::open(&self.path).await?); let syntax = Self::find_syntax(&self.path).await; let mut plain = syntax.is_err(); let mut before = Vec::with_capacity(if plain { 0 } else { skip }); - let mut after = Vec::with_capacity(limit); + let mut after = Vec::with_capacity(area.height as usize); let mut i = 0; let mut buf = vec![]; while reader.read_until(b'\n', &mut buf).await.is_ok() { i += 1; - if buf.is_empty() || i > skip + limit { + if buf.is_empty() || i > skip + area.height as usize { break; } @@ -84,23 +86,40 @@ impl Highlighter { buf.push(b'\n'); } + let line = String::from_utf8_lossy(&buf).into_owned(); + if i > skip { - after.push(String::from_utf8_lossy(&buf).into_owned()); + after.push(line); } else if !plain { - before.push(String::from_utf8_lossy(&buf).into_owned()); + before.push(line); } buf.clear(); } - if skip > 0 && i < skip + limit { - return Err(PeekError::Exceed(i.saturating_sub(limit))); + if skip > 0 && i < skip + area.height as usize { + return Err(PeekError::Exceed(i.saturating_sub(area.height as usize))); } + let indent = " ".repeat(PREVIEW.tab_size as usize); + let after_text = after.join("").replace('\t', &indent); + if plain { - let indent = " ".repeat(PREVIEW.tab_size as usize); - Ok(Text::from(after.join("").replace('\t', &indent))) + let wrapped_text = if wrap { + textwrap_wrap(&after_text, area.width as usize).join("\n") + } else { + after_text + }; + Ok(Text::from(wrapped_text)) } else { - Self::highlight_with(before, after, syntax.unwrap()).await + let wrapped_after: Vec = if wrap { + textwrap_wrap(&after_text, area.width as usize) + .into_iter() + .map(|cow| cow.trim_end_matches('\n').to_string()) + .collect() + } else { + after + }; + Self::highlight_with(before, wrapped_after, syntax.unwrap()).await } } diff --git a/yazi-plugin/src/utils/preview.rs b/yazi-plugin/src/utils/preview.rs index 73a6aed9..6cacdf61 100644 --- a/yazi-plugin/src/utils/preview.rs +++ b/yazi-plugin/src/utils/preview.rs @@ -2,6 +2,7 @@ use mlua::{AnyUserData, IntoLuaMulti, Lua, Table, Value}; use yazi_shared::{emit, event::Cmd, Layer, PeekError}; use super::Utils; +use yazi_config::PREVIEW; use crate::{bindings::{FileRef, Window}, cast_to_renderable, elements::{Paragraph, RectRef, Renderable}, external::{self, Highlighter}}; pub struct PreviewLock { @@ -37,7 +38,7 @@ impl Utils { let mut lock = PreviewLock::try_from(t)?; let text = - match Highlighter::new(&lock.url).highlight(lock.skip, area.height as usize).await { + match Highlighter::new(&lock.url).highlight(lock.skip, *area, PREVIEW.word_wrap).await { Ok(text) => text, Err(PeekError::Exceed(max)) => return (false, max).into_lua_multi(lua), Err(_) => return (false, Value::Nil).into_lua_multi(lua),