mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
perf: only scan the first 1024 bytes to detect if it's binary, apply \r fixes only to content within the visible range, avoid unnecessary allocations during natural sorting
This commit is contained in:
parent
9cf85c09d2
commit
6ec7a7e3cd
4 changed files with 91 additions and 78 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -2131,9 +2131,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.208"
|
||||
version = "1.0.209"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
|
||||
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
|
@ -2150,9 +2150,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.208"
|
||||
version = "1.0.209"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
|
||||
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -2161,9 +2161,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.125"
|
||||
version = "1.0.127"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
|
||||
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ parking_lot = "0.12.3"
|
|||
ratatui = { version = "0.27.0", features = [ "unstable-rendered-line-info" ] }
|
||||
regex = "1.10.6"
|
||||
scopeguard = "1.2.0"
|
||||
serde = { version = "1.0.208", features = [ "derive" ] }
|
||||
serde_json = "1.0.125"
|
||||
serde = { version = "1.0.209", features = [ "derive" ] }
|
||||
serde_json = "1.0.127"
|
||||
shell-words = "1.1.0"
|
||||
tokio = { version = "1.39.3", features = [ "full" ] }
|
||||
tokio-stream = "0.1.15"
|
||||
|
|
|
|||
|
|
@ -68,25 +68,25 @@ impl FilesSorter {
|
|||
}
|
||||
|
||||
fn sort_naturally(&self, items: &mut Vec<File>) {
|
||||
let mut indices = Vec::with_capacity(items.len());
|
||||
let mut entities = Vec::with_capacity(items.len());
|
||||
for (i, file) in items.iter().enumerate() {
|
||||
indices.push(i);
|
||||
entities.push(file.url.as_os_str().as_encoded_bytes());
|
||||
}
|
||||
|
||||
let mut indices: Vec<usize> = (0..items.len()).collect();
|
||||
indices.sort_unstable_by(|&a, &b| {
|
||||
let promote = self.promote(&items[a], &items[b]);
|
||||
let (a, b) = (&items[a], &items[b]);
|
||||
|
||||
let promote = self.promote(a, b);
|
||||
if promote != Ordering::Equal {
|
||||
return promote;
|
||||
}
|
||||
|
||||
let ordering = if !self.translit {
|
||||
natsort(entities[a], entities[b], !self.sensitive)
|
||||
let ordering = if self.translit {
|
||||
natsort(
|
||||
a.url.as_os_str().as_encoded_bytes().transliterate().as_bytes(),
|
||||
b.url.as_os_str().as_encoded_bytes().transliterate().as_bytes(),
|
||||
!self.sensitive,
|
||||
)
|
||||
} else {
|
||||
natsort(
|
||||
entities[a].transliterate().as_bytes(),
|
||||
entities[b].transliterate().as_bytes(),
|
||||
a.url.as_os_str().as_encoded_bytes(),
|
||||
b.url.as_os_str().as_encoded_bytes(),
|
||||
!self.sensitive,
|
||||
)
|
||||
};
|
||||
|
|
|
|||
129
yazi-plugin/src/external/highlighter.rs
vendored
129
yazi-plugin/src/external/highlighter.rs
vendored
|
|
@ -38,23 +38,8 @@ impl Highlighter {
|
|||
(&r.0, &r.1)
|
||||
}
|
||||
|
||||
async fn find_syntax(path: &Path) -> Result<&'static SyntaxReference> {
|
||||
let (_, syntaxes) = Self::init().await;
|
||||
let name = path.file_name().map(|n| n.to_string_lossy()).unwrap_or_default();
|
||||
if let Some(s) = syntaxes.find_syntax_by_extension(&name) {
|
||||
return Ok(s);
|
||||
}
|
||||
|
||||
let ext = path.extension().map(|e| e.to_string_lossy()).unwrap_or_default();
|
||||
if let Some(s) = syntaxes.find_syntax_by_extension(&ext) {
|
||||
return Ok(s);
|
||||
}
|
||||
|
||||
let mut line = String::new();
|
||||
let mut reader = BufReader::new(File::open(&path).await?);
|
||||
reader.read_line(&mut line).await?;
|
||||
syntaxes.find_syntax_by_first_line(&line).ok_or_else(|| anyhow!("No syntax found"))
|
||||
}
|
||||
#[inline]
|
||||
pub fn abort() { INCR.fetch_add(1, Ordering::Relaxed); }
|
||||
|
||||
pub async fn highlight(&self, skip: usize, limit: usize) -> Result<Text<'static>, PeekError> {
|
||||
let mut reader = BufReader::new(File::open(&self.path).await?);
|
||||
|
|
@ -67,10 +52,13 @@ impl Highlighter {
|
|||
|
||||
let mut i = 0;
|
||||
let mut buf = vec![];
|
||||
let mut inspected = 0u16;
|
||||
while reader.read_until(b'\n', &mut buf).await.is_ok() {
|
||||
i += 1;
|
||||
if buf.is_empty() || i > skip + limit {
|
||||
break;
|
||||
} else if Self::is_binary(&buf, &mut inspected) {
|
||||
return Err("Binary file".into());
|
||||
}
|
||||
|
||||
if !plain && (buf.len() > 5000 || buf.contains(&0x1b)) {
|
||||
|
|
@ -84,15 +72,8 @@ impl Highlighter {
|
|||
buf.push(b'\n');
|
||||
}
|
||||
|
||||
for b in &mut buf {
|
||||
match *b {
|
||||
b'\0' => return Err("Binary file".into()),
|
||||
b'\r' => *b = b'\n', // '\r' occurs in the middle of a line
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if i > skip {
|
||||
buf.iter_mut().for_each(Self::carriage_return_to_line_feed);
|
||||
after.push(String::from_utf8_lossy(&buf).into_owned());
|
||||
} else if !plain {
|
||||
before.push(String::from_utf8_lossy(&buf).into_owned());
|
||||
|
|
@ -144,13 +125,75 @@ impl Highlighter {
|
|||
.await?
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn abort() { INCR.fetch_add(1, Ordering::Relaxed); }
|
||||
async fn find_syntax(path: &Path) -> Result<&'static SyntaxReference> {
|
||||
let (_, syntaxes) = Self::init().await;
|
||||
let name = path.file_name().map(|n| n.to_string_lossy()).unwrap_or_default();
|
||||
if let Some(s) = syntaxes.find_syntax_by_extension(&name) {
|
||||
return Ok(s);
|
||||
}
|
||||
|
||||
let ext = path.extension().map(|e| e.to_string_lossy()).unwrap_or_default();
|
||||
if let Some(s) = syntaxes.find_syntax_by_extension(&ext) {
|
||||
return Ok(s);
|
||||
}
|
||||
|
||||
let mut line = String::new();
|
||||
let mut reader = BufReader::new(File::open(&path).await?);
|
||||
reader.read_line(&mut line).await?;
|
||||
syntaxes.find_syntax_by_first_line(&line).ok_or_else(|| anyhow!("No syntax found"))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_binary(buf: &[u8], inspected: &mut u16) -> bool {
|
||||
if let Some(n) = 1024u16.checked_sub(*inspected) {
|
||||
*inspected += n.min(buf.len() as u16);
|
||||
buf.iter().take(n as usize).any(|&b| b == 0)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn carriage_return_to_line_feed(c: &mut u8) {
|
||||
if *c == b'\r' {
|
||||
*c = b'\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Highlighter {
|
||||
pub fn to_line_widget(regions: Vec<(highlighting::Style, &str)>, indent: &str) -> Line<'static> {
|
||||
let spans: Vec<_> = regions
|
||||
.into_iter()
|
||||
.map(|(style, s)| {
|
||||
let mut modifier = ratatui::style::Modifier::empty();
|
||||
if style.font_style.contains(highlighting::FontStyle::BOLD) {
|
||||
modifier |= ratatui::style::Modifier::BOLD;
|
||||
}
|
||||
if style.font_style.contains(highlighting::FontStyle::ITALIC) {
|
||||
modifier |= ratatui::style::Modifier::ITALIC;
|
||||
}
|
||||
if style.font_style.contains(highlighting::FontStyle::UNDERLINE) {
|
||||
modifier |= ratatui::style::Modifier::UNDERLINED;
|
||||
}
|
||||
|
||||
Span {
|
||||
content: s.replace('\t', indent).into(),
|
||||
style: ratatui::style::Style {
|
||||
fg: Self::to_ansi_color(style.foreground),
|
||||
// bg: Self::to_ansi_color(style.background),
|
||||
add_modifier: modifier,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Line::from(spans)
|
||||
}
|
||||
|
||||
// Copy from https://github.com/sharkdp/bat/blob/master/src/terminal.rs
|
||||
pub fn to_ansi_color(color: highlighting::Color) -> Option<ratatui::style::Color> {
|
||||
fn to_ansi_color(color: highlighting::Color) -> Option<ratatui::style::Color> {
|
||||
if color.a == 0 {
|
||||
// Themes can specify one of the user-configurable terminal colors by
|
||||
// encoding them as #RRGGBBAA with AA set to 00 (transparent) and RR set
|
||||
|
|
@ -188,34 +231,4 @@ impl Highlighter {
|
|||
Some(ratatui::style::Color::Rgb(color.r, color.g, color.b))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_line_widget(regions: Vec<(highlighting::Style, &str)>, indent: &str) -> Line<'static> {
|
||||
let spans: Vec<_> = regions
|
||||
.into_iter()
|
||||
.map(|(style, s)| {
|
||||
let mut modifier = ratatui::style::Modifier::empty();
|
||||
if style.font_style.contains(highlighting::FontStyle::BOLD) {
|
||||
modifier |= ratatui::style::Modifier::BOLD;
|
||||
}
|
||||
if style.font_style.contains(highlighting::FontStyle::ITALIC) {
|
||||
modifier |= ratatui::style::Modifier::ITALIC;
|
||||
}
|
||||
if style.font_style.contains(highlighting::FontStyle::UNDERLINE) {
|
||||
modifier |= ratatui::style::Modifier::UNDERLINED;
|
||||
}
|
||||
|
||||
Span {
|
||||
content: s.replace('\t', indent).into(),
|
||||
style: ratatui::style::Style {
|
||||
fg: Self::to_ansi_color(style.foreground),
|
||||
// bg: Self::to_ansi_color(style.background),
|
||||
add_modifier: modifier,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Line::from(spans)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue