Skip to content

Commit

Permalink
fix: replace control characters to printable characters in plain text…
Browse files Browse the repository at this point in the history
… preview (#1704)
  • Loading branch information
sxyazi authored Sep 29, 2024
1 parent a7b9275 commit 40211df
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 10 deletions.
17 changes: 11 additions & 6 deletions yazi-plugin/src/external/highlighter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ratatui::{layout::Rect, text::{Line, Span, Text}};
use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}};
use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}, sync::OnceCell};
use yazi_config::{PREVIEW, THEME, preview::PreviewWrap};
use yazi_shared::PeekError;
use yazi_shared::{PeekError, replace_to_printable};

static INCR: AtomicUsize = AtomicUsize::new(0);
static SYNTECT: OnceCell<(Theme, SyntaxSet)> = OnceCell::const_new();
Expand Down Expand Up @@ -58,7 +58,7 @@ impl Highlighter {
return Err("Binary file".into());
}

if !plain && (buf.len() > 5000 || buf.contains(&0x1b)) {
if !plain && (buf.len() > 5000 || Self::contains_control_chars(&buf)) {
plain = true;
drop(mem::take(&mut before));
}
Expand Down Expand Up @@ -93,7 +93,7 @@ impl Highlighter {
}

Ok(if plain {
Text::from(after.join("").replace('\x1b', "^[").replace('\t', &PREVIEW.indent()))
Text::from(replace_to_printable(&after.join(""), PREVIEW.tab_size))
} else {
Self::highlight_with(before, after, syntax.unwrap()).await?
})
Expand Down Expand Up @@ -186,9 +186,14 @@ impl Highlighter {
}

#[inline(always)]
fn carriage_return_to_line_feed(c: &mut u8) {
if *c == b'\r' {
*c = b'\n';
fn contains_control_chars(buf: &[u8]) -> bool {
buf.iter().any(|&b| b.is_ascii_control() && !matches!(b, b'\t' | b'\n' | b'\r'))
}

#[inline(always)]
fn carriage_return_to_line_feed(b: &mut u8) {
if *b == b'\r' {
*b = b'\n';
}
}
}
Expand Down
33 changes: 29 additions & 4 deletions yazi-shared/src/chars.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::str;

pub const MIME_DIR: &str = "inode/directory";

#[derive(Clone, Copy, PartialEq, Eq)]
Expand All @@ -20,11 +22,34 @@ impl CharKind {
}

pub fn strip_trailing_newline(mut s: String) -> String {
if s.ends_with('\n') {
s.pop();
}
if s.ends_with('\r') {
while s.ends_with('\n') || s.ends_with('\r') {
s.pop();
}
s
}

pub fn replace_to_printable(s: &str, tab_size: u8) -> String {
let mut buf = Vec::new();
buf.try_reserve_exact(s.len() | 15).unwrap_or_else(|_| panic!());

for &b in s.as_bytes() {
match b {
b'\n' => buf.push(b'\n'),
b'\t' => {
for _ in 0..tab_size {
buf.push(b' ');
}
}
b'\0'..=b'\x1F' => {
buf.push(b'^');
buf.push(b + b'@');
}
0x7f => {
buf.push(b'^');
buf.push(b'?');
}
_ => buf.push(b),
}
}
unsafe { String::from_utf8_unchecked(buf) }
}

0 comments on commit 40211df

Please sign in to comment.