mirror of https://github.com/helix-editor/helix
File picker config (#988)
* squashed WIP commits * hide_gitignore working with config * pass reference to new config parameter of file_picker() * update config option name to match name on walk builder * add comments to config and documentation of option to book * add git_ignore option to WalkBuilder within prompt in commands.rs * WIP: add FilePickerConfig struct * WIP: cleanup * WIP: add more options including max_depth * WIP: changed defaults to match ignore crate defaults * WIP: change WalkBuilder in global_search() to use config options * WIP: removed follow_links, changed max_depth to follow config setting * WIP: update book with file-picker inline table notation * update documentation for file-picker config in book * adjusted to [editor.file-picker] in book configuration.md * adjust comments in editor.rs to be doc comments, cleanup * adjust comments * adjust bookpull/1140/head
parent
05c6cb1d0b
commit
6a4d9693ba
|
@ -24,6 +24,18 @@ To override global configuration parameters, create a `config.toml` file located
|
||||||
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
|
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
|
||||||
| `auto-info` | Whether to display infoboxes | `true` |
|
| `auto-info` | Whether to display infoboxes | `true` |
|
||||||
|
|
||||||
|
`[editor.filepicker]` section of the config. Sets options for file picker and global search. All but the last key listed in the default file-picker configuration below are IgnoreOptions: whether hidden files and files listed within ignore files are ignored by (not visible in) the helix file picker and global search. There is also one other key, `max-depth` available, which is not defined by default.
|
||||||
|
|
||||||
|
| Key | Description | Default |
|
||||||
|
|--|--|---------|
|
||||||
|
|`hidden` | Enables ignoring hidden files. | true
|
||||||
|
|`parents` | Enables reading ignore files from parent directories. | true
|
||||||
|
|`ignore` | Enables reading `.ignore` files. | true
|
||||||
|
|`git-ignore` | Enables reading `.gitignore` files. | true
|
||||||
|
|`git-global` | Enables reading global .gitignore, whose path is specified in git's config: `core.excludefile` option. | true
|
||||||
|
|`git-exclude` | Enables reading `.git/info/exclude` files. | true
|
||||||
|
|`max-depth` | Set with an integer value for maximum depth to recurse. | Defaults to `None`.
|
||||||
|
|
||||||
## LSP
|
## LSP
|
||||||
|
|
||||||
To display all language server messages in the status line add the following to your `config.toml`:
|
To display all language server messages in the status line add the following to your `config.toml`:
|
||||||
|
|
|
@ -120,7 +120,7 @@ impl Application {
|
||||||
if first.is_dir() {
|
if first.is_dir() {
|
||||||
std::env::set_current_dir(&first)?;
|
std::env::set_current_dir(&first)?;
|
||||||
editor.new_file(Action::VerticalSplit);
|
editor.new_file(Action::VerticalSplit);
|
||||||
compositor.push(Box::new(ui::file_picker(".".into())));
|
compositor.push(Box::new(ui::file_picker(".".into(), &config.editor)));
|
||||||
} else {
|
} else {
|
||||||
let nr_of_files = args.files.len();
|
let nr_of_files = args.files.len();
|
||||||
editor.open(first.to_path_buf(), Action::VerticalSplit)?;
|
editor.open(first.to_path_buf(), Action::VerticalSplit)?;
|
||||||
|
|
|
@ -1440,6 +1440,7 @@ fn global_search(cx: &mut Context) {
|
||||||
let (all_matches_sx, all_matches_rx) =
|
let (all_matches_sx, all_matches_rx) =
|
||||||
tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>();
|
tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>();
|
||||||
let smart_case = cx.editor.config.smart_case;
|
let smart_case = cx.editor.config.smart_case;
|
||||||
|
let file_picker_config = cx.editor.config.file_picker.clone();
|
||||||
|
|
||||||
let completions = search_completions(cx, None);
|
let completions = search_completions(cx, None);
|
||||||
let prompt = ui::regex_prompt(
|
let prompt = ui::regex_prompt(
|
||||||
|
@ -1468,41 +1469,55 @@ fn global_search(cx: &mut Context) {
|
||||||
|
|
||||||
let search_root = std::env::current_dir()
|
let search_root = std::env::current_dir()
|
||||||
.expect("Global search error: Failed to get current dir");
|
.expect("Global search error: Failed to get current dir");
|
||||||
WalkBuilder::new(search_root).build_parallel().run(|| {
|
WalkBuilder::new(search_root)
|
||||||
let mut searcher_cl = searcher.clone();
|
.hidden(file_picker_config.hidden)
|
||||||
let matcher_cl = matcher.clone();
|
.parents(file_picker_config.parents)
|
||||||
let all_matches_sx_cl = all_matches_sx.clone();
|
.ignore(file_picker_config.ignore)
|
||||||
Box::new(move |dent: Result<DirEntry, ignore::Error>| -> WalkState {
|
.git_ignore(file_picker_config.git_ignore)
|
||||||
let dent = match dent {
|
.git_global(file_picker_config.git_global)
|
||||||
Ok(dent) => dent,
|
.git_exclude(file_picker_config.git_exclude)
|
||||||
Err(_) => return WalkState::Continue,
|
.max_depth(file_picker_config.max_depth)
|
||||||
};
|
.build_parallel()
|
||||||
|
.run(|| {
|
||||||
|
let mut searcher_cl = searcher.clone();
|
||||||
|
let matcher_cl = matcher.clone();
|
||||||
|
let all_matches_sx_cl = all_matches_sx.clone();
|
||||||
|
Box::new(move |dent: Result<DirEntry, ignore::Error>| -> WalkState {
|
||||||
|
let dent = match dent {
|
||||||
|
Ok(dent) => dent,
|
||||||
|
Err(_) => return WalkState::Continue,
|
||||||
|
};
|
||||||
|
|
||||||
match dent.file_type() {
|
match dent.file_type() {
|
||||||
Some(fi) => {
|
Some(fi) => {
|
||||||
if !fi.is_file() {
|
if !fi.is_file() {
|
||||||
return WalkState::Continue;
|
return WalkState::Continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
None => return WalkState::Continue,
|
||||||
}
|
}
|
||||||
None => return WalkState::Continue,
|
|
||||||
}
|
|
||||||
|
|
||||||
let result_sink = sinks::UTF8(|line_num, _| {
|
let result_sink = sinks::UTF8(|line_num, _| {
|
||||||
match all_matches_sx_cl
|
match all_matches_sx_cl
|
||||||
.send((line_num as usize - 1, dent.path().to_path_buf()))
|
.send((line_num as usize - 1, dent.path().to_path_buf()))
|
||||||
{
|
{
|
||||||
Ok(_) => Ok(true),
|
Ok(_) => Ok(true),
|
||||||
Err(_) => Ok(false),
|
Err(_) => Ok(false),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let result =
|
||||||
|
searcher_cl.search_path(&matcher_cl, dent.path(), result_sink);
|
||||||
|
|
||||||
|
if let Err(err) = result {
|
||||||
|
log::error!(
|
||||||
|
"Global search error: {}, {}",
|
||||||
|
dent.path().display(),
|
||||||
|
err
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
WalkState::Continue
|
||||||
let result = searcher_cl.search_path(&matcher_cl, dent.path(), result_sink);
|
})
|
||||||
|
});
|
||||||
if let Err(err) = result {
|
|
||||||
log::error!("Global search error: {}, {}", dent.path().display(), err);
|
|
||||||
}
|
|
||||||
WalkState::Continue
|
|
||||||
})
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// Otherwise do nothing
|
// Otherwise do nothing
|
||||||
// log::warn!("Global Search Invalid Pattern")
|
// log::warn!("Global Search Invalid Pattern")
|
||||||
|
@ -2742,7 +2757,7 @@ fn command_mode(cx: &mut Context) {
|
||||||
|
|
||||||
fn file_picker(cx: &mut Context) {
|
fn file_picker(cx: &mut Context) {
|
||||||
let root = find_root(None).unwrap_or_else(|| PathBuf::from("./"));
|
let root = find_root(None).unwrap_or_else(|| PathBuf::from("./"));
|
||||||
let picker = ui::file_picker(root);
|
let picker = ui::file_picker(root, &cx.editor.config);
|
||||||
cx.push_layer(Box::new(picker));
|
cx.push_layer(Box::new(picker));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,13 +93,22 @@ pub fn regex_prompt(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_picker(root: PathBuf) -> FilePicker<PathBuf> {
|
pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePicker<PathBuf> {
|
||||||
use ignore::{types::TypesBuilder, WalkBuilder};
|
use ignore::{types::TypesBuilder, WalkBuilder};
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
// We want to exclude files that the editor can't handle yet
|
// We want to exclude files that the editor can't handle yet
|
||||||
let mut type_builder = TypesBuilder::new();
|
let mut type_builder = TypesBuilder::new();
|
||||||
let mut walk_builder = WalkBuilder::new(&root);
|
let mut walk_builder = WalkBuilder::new(&root);
|
||||||
|
walk_builder
|
||||||
|
.hidden(config.file_picker.hidden)
|
||||||
|
.parents(config.file_picker.parents)
|
||||||
|
.ignore(config.file_picker.ignore)
|
||||||
|
.git_ignore(config.file_picker.git_ignore)
|
||||||
|
.git_global(config.file_picker.git_global)
|
||||||
|
.git_exclude(config.file_picker.git_exclude)
|
||||||
|
.max_depth(config.file_picker.max_depth);
|
||||||
|
|
||||||
let walk_builder = match type_builder.add(
|
let walk_builder = match type_builder.add(
|
||||||
"compressed",
|
"compressed",
|
||||||
"*.{zip,gz,bz2,zst,lzo,sz,tgz,tbz2,lz,lz4,lzma,lzo,z,Z,xz,7z,rar,cab}",
|
"*.{zip,gz,bz2,zst,lzo,sz,tgz,tbz2,lz,lz4,lzma,lzo,z,Z,xz,7z,rar,cab}",
|
||||||
|
|
|
@ -35,6 +35,46 @@ where
|
||||||
Ok(Duration::from_millis(millis))
|
Ok(Duration::from_millis(millis))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
|
||||||
|
pub struct FilePickerConfig {
|
||||||
|
/// IgnoreOptions
|
||||||
|
/// Enables ignoring hidden files.
|
||||||
|
/// Whether to hide hidden files in file picker and global search results. Defaults to true.
|
||||||
|
pub hidden: bool,
|
||||||
|
/// Enables reading ignore files from parent directories. Defaults to true.
|
||||||
|
pub parents: bool,
|
||||||
|
/// Enables reading `.ignore` files.
|
||||||
|
/// Whether to hide files listed in .ignore in file picker and global search results. Defaults to true.
|
||||||
|
pub ignore: bool,
|
||||||
|
/// Enables reading `.gitignore` files.
|
||||||
|
/// Whether to hide files listed in .gitignore in file picker and global search results. Defaults to true.
|
||||||
|
pub git_ignore: bool,
|
||||||
|
/// Enables reading global .gitignore, whose path is specified in git's config: `core.excludefile` option.
|
||||||
|
/// Whether to hide files listed in global .gitignore in file picker and global search results. Defaults to true.
|
||||||
|
pub git_global: bool,
|
||||||
|
/// Enables reading `.git/info/exclude` files.
|
||||||
|
/// Whether to hide files listed in .git/info/exclude in file picker and global search results. Defaults to true.
|
||||||
|
pub git_exclude: bool,
|
||||||
|
/// WalkBuilder options
|
||||||
|
/// Maximum Depth to recurse directories in file picker and global search. Defaults to `None`.
|
||||||
|
pub max_depth: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FilePickerConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
hidden: true,
|
||||||
|
parents: true,
|
||||||
|
ignore: true,
|
||||||
|
git_ignore: true,
|
||||||
|
git_global: true,
|
||||||
|
git_exclude: true,
|
||||||
|
max_depth: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
|
#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
@ -62,6 +102,7 @@ pub struct Config {
|
||||||
pub completion_trigger_len: u8,
|
pub completion_trigger_len: u8,
|
||||||
/// Whether to display infoboxes. Defaults to true.
|
/// Whether to display infoboxes. Defaults to true.
|
||||||
pub auto_info: bool,
|
pub auto_info: bool,
|
||||||
|
pub file_picker: FilePickerConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||||
|
@ -93,6 +134,7 @@ impl Default for Config {
|
||||||
idle_timeout: Duration::from_millis(400),
|
idle_timeout: Duration::from_millis(400),
|
||||||
completion_trigger_len: 2,
|
completion_trigger_len: 2,
|
||||||
auto_info: true,
|
auto_info: true,
|
||||||
|
file_picker: FilePickerConfig::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue