feat: add option tto ignore binary files

pull/13775/head
Tatesa Uradnik 2025-06-16 17:12:55 +02:00
parent 362e97e927
commit e33e8a678c
No known key found for this signature in database
8 changed files with 44 additions and 18 deletions

View File

@ -195,6 +195,7 @@ All git related options are only enabled in a git repository.
| Key | Description | Default |
|--|--|---------|
|`hidden` | Enables ignoring hidden files | `true`
|`binary` | Enables ignoring binary files | `false`
|`follow-symlinks` | Follow symlinks instead of ignoring them | `true`
|`deduplicate-links` | Ignore symlinks that point at files already shown in the picker | `true`
|`parents` | Enables reading ignore files from parent directories | `true`

View File

@ -2552,7 +2552,7 @@ fn global_search(cx: &mut Context) {
.git_exclude(config.file_picker_config.git_exclude)
.max_depth(config.file_picker_config.max_depth)
.filter_entry(move |entry| {
filter_picker_entry(entry, &absolute_root, dedup_symlinks)
filter_picker_entry(entry, &absolute_root, dedup_symlinks, false)
})
.add_custom_ignore_filename(helix_loader::config_dir().join("ignore"))
.add_custom_ignore_filename(".helix/ignore")

View File

@ -12,7 +12,11 @@ pub mod job;
pub mod keymap;
pub mod ui;
use std::path::Path;
use std::{
fs::File,
io::{self, Read},
path::Path,
};
use futures_util::Future;
mod handlers;
@ -44,8 +48,24 @@ fn true_color() -> bool {
}
}
fn is_binary(path: &Path, read_buffer: &mut Vec<u8>) -> io::Result<bool> {
let content_type = File::open(path).and_then(|file| {
// Read up to 1kb to detect the content type
let n = file.take(1024).read_to_end(read_buffer)?;
let content_type = content_inspector::inspect(&read_buffer[..n]);
read_buffer.clear();
Ok(content_type)
})?;
Ok(content_type.is_binary())
}
/// Function used for filtering dir entries in the various file pickers.
fn filter_picker_entry(entry: &DirEntry, root: &Path, dedup_symlinks: bool) -> bool {
fn filter_picker_entry(
entry: &DirEntry,
root: &Path,
dedup_symlinks: bool,
ignore_binary_files: bool,
) -> bool {
// We always want to ignore popular VCS directories, otherwise if
// `ignore` is turned off, we end up with a lot of noise
// in our picker.
@ -66,6 +86,12 @@ fn filter_picker_entry(entry: &DirEntry, root: &Path, dedup_symlinks: bool) -> b
.is_some_and(|path| !path.starts_with(root));
}
if ignore_binary_files {
if let Ok(is_binary) = is_binary(entry.path(), &mut Vec::new()) {
return !is_binary;
}
}
true
}

View File

@ -205,8 +205,8 @@ pub fn file_picker(editor: &Editor, root: PathBuf) -> FilePicker {
let now = Instant::now();
let dedup_symlinks = config.file_picker.deduplicate_links;
let ignore_binaries = config.file_picker.binary_files;
let absolute_root = root.canonicalize().unwrap_or_else(|_| root.clone());
let mut walk_builder = WalkBuilder::new(&root);
walk_builder
.hidden(config.file_picker.hidden)
@ -218,7 +218,9 @@ pub fn file_picker(editor: &Editor, root: PathBuf) -> FilePicker {
.git_exclude(config.file_picker.git_exclude)
.sort_by_file_name(|name1, name2| name1.cmp(name2))
.max_depth(config.file_picker.max_depth)
.filter_entry(move |entry| filter_picker_entry(entry, &absolute_root, dedup_symlinks));
.filter_entry(move |entry| {
filter_picker_entry(entry, &absolute_root, dedup_symlinks, ignore_binaries)
});
walk_builder.add_custom_ignore_filename(helix_loader::config_dir().join("ignore"));
walk_builder.add_custom_ignore_filename(".helix/ignore");

View File

@ -4,7 +4,7 @@ mod query;
use crate::{
alt,
compositor::{self, Component, Compositor, Context, Event, EventResult},
ctrl, key, shift,
ctrl, is_binary, key, shift,
ui::{
self,
document::{render_document, LinePos, TextRenderer},
@ -31,7 +31,6 @@ use tui::widgets::Widget;
use std::{
borrow::Cow,
collections::HashMap,
io::Read,
path::Path,
sync::{
atomic::{self, AtomicUsize},
@ -612,17 +611,11 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
if metadata.len() > MAX_FILE_SIZE_FOR_PREVIEW {
return Ok(CachedPreview::LargeFile);
}
let content_type = 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]);
self.read_buffer.clear();
Ok(content_type)
})?;
if content_type.is_binary() {
if is_binary(&path, &mut self.read_buffer)? {
return Ok(CachedPreview::Binary);
}
let mut doc = Document::open(
&path,
None,

View File

@ -746,7 +746,7 @@ async fn test_hardlink_write() -> anyhow::Result<()> {
async fn edit_file_with_content(file_content: &[u8]) -> anyhow::Result<()> {
let mut file = tempfile::NamedTempFile::new()?;
file.as_file_mut().write_all(&file_content)?;
file.as_file_mut().write_all(file_content)?;
helpers::test_key_sequence(
&mut helpers::AppBuilder::new()

View File

@ -425,7 +425,7 @@ pub fn reload_file(file: &mut NamedTempFile) -> anyhow::Result<()> {
let f = std::fs::OpenOptions::new()
.write(true)
.read(true)
.open(&path)?;
.open(path)?;
*file.as_file_mut() = f;
Ok(())
}

View File

@ -182,6 +182,9 @@ pub struct FilePickerConfig {
/// Enables ignoring hidden files.
/// Whether to hide hidden files in file picker and global search results. Defaults to true.
pub hidden: bool,
/// Enables ignoring binary files.
/// Whether to hide binary files in file picker. Defaults to false.
pub binary_files: bool,
/// Enables following symlinks.
/// Whether to follow symbolic links in file picker and file or directory completions. Defaults to true.
pub follow_symlinks: bool,
@ -218,6 +221,7 @@ impl Default for FilePickerConfig {
git_global: true,
git_exclude: true,
max_depth: None,
binary_files: false,
}
}
}