Skip to content

feat: add option tto ignore binary files #13775

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book/src/editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
30 changes: 28 additions & 2 deletions helix-term/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -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
}

Expand Down
6 changes: 4 additions & 2 deletions helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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");
Expand Down
15 changes: 4 additions & 11 deletions helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -31,7 +31,6 @@ use tui::widgets::Widget;
use std::{
borrow::Cow,
collections::HashMap,
io::Read,
path::Path,
sync::{
atomic::{self, AtomicUsize},
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion helix-term/tests/test/commands/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion helix-term/tests/test/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
4 changes: 4 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -218,6 +221,7 @@ impl Default for FilePickerConfig {
git_global: true,
git_exclude: true,
max_depth: None,
binary_files: false,
}
}
}
Expand Down