mirror of https://github.com/helix-editor/helix
edits
* Use a BTreeSet instead of a Vec. `Vec::dedup` only works on consecutive entries so we need a set to deduplicate instead. * Use the `filename` completer as-is in `repeating_filenames` when the input is empty. This makes `:sh cat <cursor here>` for example show all files (same as`:open <cursor here>`). * Refactor `shell` completer in terms of `repeating_filenames` (and inline `get_last_argument` helper) * Remove comment about bash completion scripts. If anything that could be a plugin but we shouldn't be parsing bash in core: any shell can be configured for use in `:sh`.pull/12883/head
parent
db032faaa4
commit
83c467ecf6
|
@ -371,7 +371,7 @@ fn directory_content(path: &Path) -> Result<Vec<(PathBuf, bool)>, std::io::Error
|
||||||
pub mod completers {
|
pub mod completers {
|
||||||
use super::Utf8PathBuf;
|
use super::Utf8PathBuf;
|
||||||
use crate::ui::prompt::Completion;
|
use crate::ui::prompt::Completion;
|
||||||
use helix_core::command_line::{self, Token, Tokenizer};
|
use helix_core::command_line::{self, Tokenizer};
|
||||||
use helix_core::fuzzy::fuzzy_match;
|
use helix_core::fuzzy::fuzzy_match;
|
||||||
use helix_core::syntax::LanguageServerFeature;
|
use helix_core::syntax::LanguageServerFeature;
|
||||||
use helix_view::document::SCRATCH_BUFFER_NAME;
|
use helix_view::document::SCRATCH_BUFFER_NAME;
|
||||||
|
@ -379,6 +379,7 @@ pub mod completers {
|
||||||
use helix_view::{editor::Config, Editor};
|
use helix_view::{editor::Config, Editor};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use tui::text::Span;
|
use tui::text::Span;
|
||||||
|
|
||||||
pub type Completer = fn(&Editor, &str) -> Vec<Completion>;
|
pub type Completer = fn(&Editor, &str) -> Vec<Completion>;
|
||||||
|
@ -680,27 +681,24 @@ pub mod completers {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn program(_editor: &Editor, input: &str) -> Vec<Completion> {
|
pub fn program(_editor: &Editor, input: &str) -> Vec<Completion> {
|
||||||
static PROGRAMS_IN_PATH: Lazy<Vec<String>> = Lazy::new(|| {
|
static PROGRAMS_IN_PATH: Lazy<BTreeSet<String>> = Lazy::new(|| {
|
||||||
// Go through the entire PATH and read all files into a vec.
|
// Go through the entire PATH and read all files into a set.
|
||||||
let Some(path) = std::env::var_os("PATH") else {
|
let Some(path) = std::env::var_os("PATH") else {
|
||||||
return Vec::new();
|
return Default::default();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut vec = std::env::split_paths(&path)
|
std::env::split_paths(&path)
|
||||||
.flat_map(|s| {
|
.filter_map(|path| std::fs::read_dir(path).ok())
|
||||||
std::fs::read_dir(s)
|
.flatten()
|
||||||
.map_or_else(|_| vec![], |res| res.into_iter().collect::<Vec<_>>())
|
.filter_map(|res| {
|
||||||
|
let entry = res.ok()?;
|
||||||
|
if entry.metadata().ok()?.is_file() {
|
||||||
|
entry.file_name().into_string().ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.filter_map(|it| it.ok())
|
.collect()
|
||||||
.map(|f| f.path())
|
|
||||||
.filter(|p| !p.is_dir())
|
|
||||||
.filter_map(|p| p.file_name().and_then(|s| s.to_str().map(|s| s.to_owned())))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Paths can share programs like /bin and /usr/bin sometimes contain the same.
|
|
||||||
vec.dedup();
|
|
||||||
|
|
||||||
vec
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fuzzy_match(input, PROGRAMS_IN_PATH.iter(), false)
|
fuzzy_match(input, PROGRAMS_IN_PATH.iter(), false)
|
||||||
|
@ -709,22 +707,15 @@ pub mod completers {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_last_argument(input: &str) -> Option<Token> {
|
|
||||||
let tokenizer = Tokenizer::new(input, false);
|
|
||||||
let last = tokenizer.last()?;
|
|
||||||
|
|
||||||
Some(last.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This expects input to be a raw string of arguments, because this is what Signature's raw_after does.
|
/// This expects input to be a raw string of arguments, because this is what Signature's raw_after does.
|
||||||
pub fn repeating_filenames(editor: &Editor, input: &str) -> Vec<Completion> {
|
pub fn repeating_filenames(editor: &Editor, input: &str) -> Vec<Completion> {
|
||||||
let Some(token) = get_last_argument(input) else {
|
let token = match Tokenizer::new(input, false).last() {
|
||||||
return Vec::new();
|
Some(token) => token.unwrap(),
|
||||||
|
None => return filename(editor, input),
|
||||||
};
|
};
|
||||||
|
|
||||||
let offset = token.content_start;
|
let offset = token.content_start;
|
||||||
|
|
||||||
// Theoretically one could now parse bash completion scripts, but filename should suffice for now.
|
|
||||||
let mut completions = filename(editor, &input[offset..]);
|
let mut completions = filename(editor, &input[offset..]);
|
||||||
for completion in completions.iter_mut() {
|
for completion in completions.iter_mut() {
|
||||||
completion.0.start += offset;
|
completion.0.start += offset;
|
||||||
|
@ -733,20 +724,16 @@ pub mod completers {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shell(editor: &Editor, input: &str) -> Vec<Completion> {
|
pub fn shell(editor: &Editor, input: &str) -> Vec<Completion> {
|
||||||
let (_, _, complete_command) = command_line::split(input);
|
let (command, args, complete_command) = command_line::split(input);
|
||||||
|
|
||||||
if complete_command {
|
if complete_command {
|
||||||
return program(editor, input);
|
return program(editor, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(token) = get_last_argument(input) else {
|
let mut completions = repeating_filenames(editor, args);
|
||||||
return Vec::new();
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut completions = repeating_filenames(editor, &token.content);
|
|
||||||
|
|
||||||
for completion in completions.iter_mut() {
|
for completion in completions.iter_mut() {
|
||||||
completion.0.start += token.content_start;
|
// + 1 for separator between `command` and `args`
|
||||||
|
completion.0.start += command.len() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
completions
|
completions
|
||||||
|
|
Loading…
Reference in New Issue