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]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.208"
|
version = "1.0.209"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
|
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
@ -2150,9 +2150,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.208"
|
version = "1.0.209"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
|
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -2161,9 +2161,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.125"
|
version = "1.0.127"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
|
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ parking_lot = "0.12.3"
|
||||||
ratatui = { version = "0.27.0", features = [ "unstable-rendered-line-info" ] }
|
ratatui = { version = "0.27.0", features = [ "unstable-rendered-line-info" ] }
|
||||||
regex = "1.10.6"
|
regex = "1.10.6"
|
||||||
scopeguard = "1.2.0"
|
scopeguard = "1.2.0"
|
||||||
serde = { version = "1.0.208", features = [ "derive" ] }
|
serde = { version = "1.0.209", features = [ "derive" ] }
|
||||||
serde_json = "1.0.125"
|
serde_json = "1.0.127"
|
||||||
shell-words = "1.1.0"
|
shell-words = "1.1.0"
|
||||||
tokio = { version = "1.39.3", features = [ "full" ] }
|
tokio = { version = "1.39.3", features = [ "full" ] }
|
||||||
tokio-stream = "0.1.15"
|
tokio-stream = "0.1.15"
|
||||||
|
|
|
||||||
|
|
@ -68,25 +68,25 @@ impl FilesSorter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sort_naturally(&self, items: &mut Vec<File>) {
|
fn sort_naturally(&self, items: &mut Vec<File>) {
|
||||||
let mut indices = Vec::with_capacity(items.len());
|
let mut indices: Vec<usize> = (0..items.len()).collect();
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
indices.sort_unstable_by(|&a, &b| {
|
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 {
|
if promote != Ordering::Equal {
|
||||||
return promote;
|
return promote;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ordering = if !self.translit {
|
let ordering = if self.translit {
|
||||||
natsort(entities[a], entities[b], !self.sensitive)
|
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 {
|
} else {
|
||||||
natsort(
|
natsort(
|
||||||
entities[a].transliterate().as_bytes(),
|
a.url.as_os_str().as_encoded_bytes(),
|
||||||
entities[b].transliterate().as_bytes(),
|
b.url.as_os_str().as_encoded_bytes(),
|
||||||
!self.sensitive,
|
!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)
|
(&r.0, &r.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_syntax(path: &Path) -> Result<&'static SyntaxReference> {
|
#[inline]
|
||||||
let (_, syntaxes) = Self::init().await;
|
pub fn abort() { INCR.fetch_add(1, Ordering::Relaxed); }
|
||||||
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"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn highlight(&self, skip: usize, limit: usize) -> Result<Text<'static>, PeekError> {
|
pub async fn highlight(&self, skip: usize, limit: usize) -> Result<Text<'static>, PeekError> {
|
||||||
let mut reader = BufReader::new(File::open(&self.path).await?);
|
let mut reader = BufReader::new(File::open(&self.path).await?);
|
||||||
|
|
@ -67,10 +52,13 @@ impl Highlighter {
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
|
let mut inspected = 0u16;
|
||||||
while reader.read_until(b'\n', &mut buf).await.is_ok() {
|
while reader.read_until(b'\n', &mut buf).await.is_ok() {
|
||||||
i += 1;
|
i += 1;
|
||||||
if buf.is_empty() || i > skip + limit {
|
if buf.is_empty() || i > skip + limit {
|
||||||
break;
|
break;
|
||||||
|
} else if Self::is_binary(&buf, &mut inspected) {
|
||||||
|
return Err("Binary file".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !plain && (buf.len() > 5000 || buf.contains(&0x1b)) {
|
if !plain && (buf.len() > 5000 || buf.contains(&0x1b)) {
|
||||||
|
|
@ -84,15 +72,8 @@ impl Highlighter {
|
||||||
buf.push(b'\n');
|
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 {
|
if i > skip {
|
||||||
|
buf.iter_mut().for_each(Self::carriage_return_to_line_feed);
|
||||||
after.push(String::from_utf8_lossy(&buf).into_owned());
|
after.push(String::from_utf8_lossy(&buf).into_owned());
|
||||||
} else if !plain {
|
} else if !plain {
|
||||||
before.push(String::from_utf8_lossy(&buf).into_owned());
|
before.push(String::from_utf8_lossy(&buf).into_owned());
|
||||||
|
|
@ -144,13 +125,75 @@ impl Highlighter {
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
async fn find_syntax(path: &Path) -> Result<&'static SyntaxReference> {
|
||||||
pub fn abort() { INCR.fetch_add(1, Ordering::Relaxed); }
|
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 {
|
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
|
// 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 {
|
if color.a == 0 {
|
||||||
// Themes can specify one of the user-configurable terminal colors by
|
// Themes can specify one of the user-configurable terminal colors by
|
||||||
// encoding them as #RRGGBBAA with AA set to 00 (transparent) and RR set
|
// 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))
|
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