From 659398dfe8d0fd0821600c8167db111e1474dba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 9 Jun 2026 15:55:55 +0900 Subject: [PATCH] deps: Remove content_inspector, we just need a tiny helper to detect binary --- Cargo.lock | 10 -------- helix-term/Cargo.toml | 2 -- helix-term/src/commands.rs | 6 ++--- helix-term/src/lib.rs | 46 +++++++++++++++++++++++++++++++++++++ helix-term/src/ui/picker.rs | 9 ++++---- 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4845705c..ea302cfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,15 +158,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59" -[[package]] -name = "content_inspector" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" -dependencies = [ - "memchr", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -1508,7 +1499,6 @@ version = "25.7.1" dependencies = [ "anyhow", "arc-swap", - "content_inspector", "crossterm", "dashmap", "futures-util", diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 3bd7015b..2f3809da 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -74,8 +74,6 @@ grep-searcher = "0.1" grep-matcher = "0.1" # markdown doc rendering pulldown-cmark = { version = "0.13", default-features = false } -# file type detection -content_inspector = "0.2.4" thiserror.workspace = true # opening URLs diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 3bc9714a..93f57a83 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1575,14 +1575,14 @@ fn should_open_url_externally(url: &Url) -> bool { return true; } - let content_type = std::fs::File::open(url.path()).and_then(|file| { + let is_binary = std::fs::File::open(url.path()).and_then(|file| { // Read up to 1kb to detect the content type let mut read_buffer = Vec::new(); let n = file.take(1024).read_to_end(&mut read_buffer)?; - Ok(content_inspector::inspect(&read_buffer[..n])) + Ok(crate::is_binary(&read_buffer[..n])) }); - matches!(content_type, Ok(content_inspector::ContentType::BINARY)) + matches!(is_binary, Ok(true)) } fn extend_word_impl(cx: &mut Context, extend_fn: F) diff --git a/helix-term/src/lib.rs b/helix-term/src/lib.rs index 48a16566..0555c530 100644 --- a/helix-term/src/lib.rs +++ b/helix-term/src/lib.rs @@ -47,6 +47,32 @@ fn true_color() -> bool { } } +/// Heuristic "is this a binary (non-text) file?" check over a leading chunk of a +/// file. Replaces the `content_inspector` crate — we only need the binary/text +/// verdict, not its encoding classification. +/// +/// A leading byte-order mark marks the content as text (UTF-16/32 text +/// legitimately contains NUL bytes, so it must be excluded before the NUL scan); +/// otherwise a NUL byte in the first kilobyte — or a known binary magic number — +/// means binary. +pub(crate) fn is_binary(buffer: &[u8]) -> bool { + // UTF-32 BOMs must be checked before UTF-16 (their BOMs overlap). + const BYTE_ORDER_MARKS: &[&[u8]] = &[ + &[0xEF, 0xBB, 0xBF], // UTF-8 + &[0x00, 0x00, 0xFE, 0xFF], // UTF-32BE + &[0xFF, 0xFE, 0x00, 0x00], // UTF-32LE + &[0xFE, 0xFF], // UTF-16BE + &[0xFF, 0xFE], // UTF-16LE + ]; + + if BYTE_ORDER_MARKS.iter().any(|bom| buffer.starts_with(bom)) { + return false; + } + + let scan = &buffer[..buffer.len().min(1024)]; + scan.contains(&0) || buffer.starts_with(b"%PDF") || buffer.starts_with(b"\x89PNG") +} + /// Function used for filtering dir entries in the various file pickers. fn filter_picker_entry(entry: &DirEntry, root: &Path, dedup_symlinks: bool) -> bool { // We always want to ignore popular VCS directories, otherwise if @@ -89,3 +115,23 @@ fn open_external_url_callback( }))) } } + +#[cfg(test)] +mod tests { + use super::is_binary; + + #[test] + fn binary_detection() { + assert!(!is_binary(b"")); + assert!(!is_binary(b"plain text\nsecond line")); + // a NUL byte in the scanned range -> binary + assert!(is_binary(b"text\0with nul")); + // binary magic numbers with no NUL prefix + assert!(is_binary(b"%PDF-1.7 ...")); + assert!(is_binary(b"\x89PNG\r\n")); + // a BOM marks the content as text even though it carries NUL bytes + assert!(!is_binary(b"\xFF\xFEt\0e\0x\0t\0")); // UTF-16LE + assert!(!is_binary(b"\x00\x00\xFE\xFFtext")); // UTF-32BE + assert!(!is_binary(b"\xEF\xBB\xBFtext")); // UTF-8 BOM + } +} diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 519a6003..81ad3df3 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -631,15 +631,14 @@ impl Picker { if metadata.len() > MAX_FILE_SIZE_FOR_PREVIEW { return Ok(CachedPreview::LargeFile); } - let content_type = std::fs::File::open(&path).and_then(|file| { + let is_binary = std::fs::File::open(&path).and_then(|file| { // Read up to 1kb to detect the content type let n = file.take(1024).read_to_end(&mut self.read_buffer)?; - let content_type = - content_inspector::inspect(&self.read_buffer[..n]); + let is_binary = crate::is_binary(&self.read_buffer[..n]); self.read_buffer.clear(); - Ok(content_type) + Ok(is_binary) })?; - if content_type.is_binary() { + if is_binary { return Ok(CachedPreview::Binary); } let mut doc = Document::open( -- 2.51.2