on master help sign in
File picker config (#988)
6a4d969Dan Nases Sha
book/src/configuration.md+12
@@ -24,6 +24,18 @@ To override global configuration parameters, create a `config.toml` file located
24| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
24| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
25| `auto-info` | Whether to display infoboxes | `true` |
25| `auto-info` | Whether to display infoboxes | `true` |
26
26
27+`[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.
28+
29+| Key | Description | Default |
30+|--|--|---------|
31+|`hidden` | Enables ignoring hidden files. | true
32+|`parents` | Enables reading ignore files from parent directories. | true
33+|`ignore` | Enables reading `.ignore` files. | true
34+|`git-ignore` | Enables reading `.gitignore` files. | true
35+|`git-global` | Enables reading global .gitignore, whose path is specified in git's config: `core.excludefile` option. | true
36+|`git-exclude` | Enables reading `.git/info/exclude` files. | true
37+|`max-depth` | Set with an integer value for maximum depth to recurse. | Defaults to `None`.
38+
27## LSP
39## LSP
28
40
29To display all language server messages in the status line add the following to your `config.toml`:
41To display all language server messages in the status line add the following to your `config.toml`:
helix-term/src/application.rs+1−1
@@ -120,7 +120,7 @@ impl Application {
120 if first.is_dir() {
120 if first.is_dir() {
121 std::env::set_current_dir(&first)?;
121 std::env::set_current_dir(&first)?;
122 editor.new_file(Action::VerticalSplit);
122 editor.new_file(Action::VerticalSplit);
123− compositor.push(Box::new(ui::file_picker(".".into())));
123+ compositor.push(Box::new(ui::file_picker(".".into(), &config.editor)));
124 } else {
124 } else {
125 let nr_of_files = args.files.len();
125 let nr_of_files = args.files.len();
126 editor.open(first.to_path_buf(), Action::VerticalSplit)?;
126 editor.open(first.to_path_buf(), Action::VerticalSplit)?;
helix-term/src/commands.rs+47−32
@@ -1440,6 +1440,7 @@ fn global_search(cx: &mut Context) {
1440 let (all_matches_sx, all_matches_rx) =
1440 let (all_matches_sx, all_matches_rx) =
1441 tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>();
1441 tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>();
1442 let smart_case = cx.editor.config.smart_case;
1442 let smart_case = cx.editor.config.smart_case;
1443+ let file_picker_config = cx.editor.config.file_picker.clone();
1443
1444
1444 let completions = search_completions(cx, None);
1445 let completions = search_completions(cx, None);
1445 let prompt = ui::regex_prompt(
1446 let prompt = ui::regex_prompt(
@@ -1468,41 +1469,55 @@ fn global_search(cx: &mut Context) {
1468
1469
1469 let search_root = std::env::current_dir()
1470 let search_root = std::env::current_dir()
1470 .expect("Global search error: Failed to get current dir");
1471 .expect("Global search error: Failed to get current dir");
1471− WalkBuilder::new(search_root).build_parallel().run(|| {
1472+ WalkBuilder::new(search_root)
1473+ .hidden(file_picker_config.hidden)
1474+ .parents(file_picker_config.parents)
1475+ .ignore(file_picker_config.ignore)
1476+ .git_ignore(file_picker_config.git_ignore)
1477+ .git_global(file_picker_config.git_global)
1478+ .git_exclude(file_picker_config.git_exclude)
1479+ .max_depth(file_picker_config.max_depth)
1480+ .build_parallel()
1481+ .run(|| {
1472− let mut searcher_cl = searcher.clone();
1482+ let mut searcher_cl = searcher.clone();
1473− let matcher_cl = matcher.clone();
1483+ let matcher_cl = matcher.clone();
1474− let all_matches_sx_cl = all_matches_sx.clone();
1484+ let all_matches_sx_cl = all_matches_sx.clone();
1475− Box::new(move |dent: Result<DirEntry, ignore::Error>| -> WalkState {
1485+ Box::new(move |dent: Result<DirEntry, ignore::Error>| -> WalkState {
1476− let dent = match dent {
1486+ let dent = match dent {
1477− Ok(dent) => dent,
1487+ Ok(dent) => dent,
1478− Err(_) => return WalkState::Continue,
1488+ Err(_) => return WalkState::Continue,
1479− };
1489+ };
1480−
1490+
1481− match dent.file_type() {
1491+ match dent.file_type() {
1482− Some(fi) => {
1492+ Some(fi) => {
1483− if !fi.is_file() {
1493+ if !fi.is_file() {
1484− return WalkState::Continue;
1494+ return WalkState::Continue;
1495+ }
1485 }
1496 }
1497+ None => return WalkState::Continue,
1486 }
1498 }
1487− None => return WalkState::Continue,
1488− }
1489
1499
1490− let result_sink = sinks::UTF8(|line_num, _| {
1500+ let result_sink = sinks::UTF8(|line_num, _| {
1491− match all_matches_sx_cl
1501+ match all_matches_sx_cl
1492− .send((line_num as usize - 1, dent.path().to_path_buf()))
1502+ .send((line_num as usize - 1, dent.path().to_path_buf()))
1493− {
1503+ {
1494− Ok(_) => Ok(true),
1504+ Ok(_) => Ok(true),
1495− Err(_) => Ok(false),
1505+ Err(_) => Ok(false),
1506+ }
1507+ });
1508+ let result =
1509+ searcher_cl.search_path(&matcher_cl, dent.path(), result_sink);
1510+
1511+ if let Err(err) = result {
1512+ log::error!(
1513+ "Global search error: {}, {}",
1514+ dent.path().display(),
1515+ err
1516+ );
1496 }
1517 }
1497− });
1498− let result = searcher_cl.search_path(&matcher_cl, dent.path(), result_sink);
1499−
1500− if let Err(err) = result {
1501− log::error!("Global search error: {}, {}", dent.path().display(), err);
1502− }
1503− WalkState::Continue
1518+ WalkState::Continue
1519+ })
1504− })
1520+ });
1505− });
1506 } else {
1521 } else {
1507 // Otherwise do nothing
1522 // Otherwise do nothing
1508 // log::warn!("Global Search Invalid Pattern")
1523 // log::warn!("Global Search Invalid Pattern")
@@ -2742,7 +2757,7 @@ fn command_mode(cx: &mut Context) {
2742
2757
2743fn file_picker(cx: &mut Context) {
2758fn file_picker(cx: &mut Context) {
2744 let root = find_root(None).unwrap_or_else(|| PathBuf::from("./"));
2759 let root = find_root(None).unwrap_or_else(|| PathBuf::from("./"));
2745− let picker = ui::file_picker(root);
2760+ let picker = ui::file_picker(root, &cx.editor.config);
2746 cx.push_layer(Box::new(picker));
2761 cx.push_layer(Box::new(picker));
2747}
2762}
2748
2763
helix-term/src/ui/mod.rs+10−1
@@ -93,13 +93,22 @@ pub fn regex_prompt(
93 )
93 )
94}
94}
95
95
96−pub fn file_picker(root: PathBuf) -> FilePicker<PathBuf> {
96+pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePicker<PathBuf> {
97 use ignore::{types::TypesBuilder, WalkBuilder};
97 use ignore::{types::TypesBuilder, WalkBuilder};
98 use std::time;
98 use std::time;
99
99
100 // We want to exclude files that the editor can't handle yet
100 // We want to exclude files that the editor can't handle yet
101 let mut type_builder = TypesBuilder::new();
101 let mut type_builder = TypesBuilder::new();
102 let mut walk_builder = WalkBuilder::new(&root);
102 let mut walk_builder = WalkBuilder::new(&root);
103+ walk_builder
104+ .hidden(config.file_picker.hidden)
105+ .parents(config.file_picker.parents)
106+ .ignore(config.file_picker.ignore)
107+ .git_ignore(config.file_picker.git_ignore)
108+ .git_global(config.file_picker.git_global)
109+ .git_exclude(config.file_picker.git_exclude)
110+ .max_depth(config.file_picker.max_depth);
111+
103 let walk_builder = match type_builder.add(
112 let walk_builder = match type_builder.add(
104 "compressed",
113 "compressed",
105 "*.{zip,gz,bz2,zst,lzo,sz,tgz,tbz2,lz,lz4,lzma,lzo,z,Z,xz,7z,rar,cab}",
114 "*.{zip,gz,bz2,zst,lzo,sz,tgz,tbz2,lz,lz4,lzma,lzo,z,Z,xz,7z,rar,cab}",
helix-view/src/editor.rs+42
@@ -35,6 +35,46 @@ where
35 Ok(Duration::from_millis(millis))
35 Ok(Duration::from_millis(millis))
36}
36}
37
37
38+#[derive(Debug, Clone, PartialEq, Deserialize)]
39+#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
40+pub struct FilePickerConfig {
41+ /// IgnoreOptions
42+ /// Enables ignoring hidden files.
43+ /// Whether to hide hidden files in file picker and global search results. Defaults to true.
44+ pub hidden: bool,
45+ /// Enables reading ignore files from parent directories. Defaults to true.
46+ pub parents: bool,
47+ /// Enables reading `.ignore` files.
48+ /// Whether to hide files listed in .ignore in file picker and global search results. Defaults to true.
49+ pub ignore: bool,
50+ /// Enables reading `.gitignore` files.
51+ /// Whether to hide files listed in .gitignore in file picker and global search results. Defaults to true.
52+ pub git_ignore: bool,
53+ /// Enables reading global .gitignore, whose path is specified in git's config: `core.excludefile` option.
54+ /// Whether to hide files listed in global .gitignore in file picker and global search results. Defaults to true.
55+ pub git_global: bool,
56+ /// Enables reading `.git/info/exclude` files.
57+ /// Whether to hide files listed in .git/info/exclude in file picker and global search results. Defaults to true.
58+ pub git_exclude: bool,
59+ /// WalkBuilder options
60+ /// Maximum Depth to recurse directories in file picker and global search. Defaults to `None`.
61+ pub max_depth: Option<usize>,
62+}
63+
64+impl Default for FilePickerConfig {
65+ fn default() -> Self {
66+ Self {
67+ hidden: true,
68+ parents: true,
69+ ignore: true,
70+ git_ignore: true,
71+ git_global: true,
72+ git_exclude: true,
73+ max_depth: None,
74+ }
75+ }
76+}
77+
38#[derive(Debug, Clone, PartialEq, Deserialize)]
78#[derive(Debug, Clone, PartialEq, Deserialize)]
39#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
79#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
40pub struct Config {
80pub struct Config {
@@ -62,6 +102,7 @@ pub struct Config {
62 pub completion_trigger_len: u8,
102 pub completion_trigger_len: u8,
63 /// Whether to display infoboxes. Defaults to true.
103 /// Whether to display infoboxes. Defaults to true.
64 pub auto_info: bool,
104 pub auto_info: bool,
105+ pub file_picker: FilePickerConfig,
65}
106}
66
107
67#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
108#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
@@ -93,6 +134,7 @@ impl Default for Config {
93 idle_timeout: Duration::from_millis(400),
134 idle_timeout: Duration::from_millis(400),
94 completion_trigger_len: 2,
135 completion_trigger_len: 2,
95 auto_info: true,
136 auto_info: true,
137+ file_picker: FilePickerConfig::default(),
96 }
138 }
97 }
139 }
98}
140}