mirror of
https://github.com/ilyakooo0/helix.git
synced 2024-11-30 00:35:26 +03:00
Improve completion: src/<tab> will now correctly complete to src/main.rs
This commit is contained in:
parent
f29f01858d
commit
a32806b490
@ -723,20 +723,26 @@ pub fn command_mode(cx: &mut Context) {
|
||||
// simple heuristic: if there's no space, complete command.
|
||||
// if there's a space, file completion kicks in. We should specialize by command later.
|
||||
if parts.len() <= 1 {
|
||||
use std::{borrow::Cow, ops::Range};
|
||||
let end = 0..;
|
||||
COMMAND_LIST
|
||||
.iter()
|
||||
.filter(|command| command.contains(input))
|
||||
.map(|command| std::borrow::Cow::Borrowed(*command))
|
||||
.map(|command| (end.clone(), Cow::Borrowed(*command)))
|
||||
.collect()
|
||||
} else {
|
||||
let part = parts.last().unwrap();
|
||||
ui::completers::filename(part)
|
||||
.into_iter()
|
||||
.map(|(range, file)| {
|
||||
// offset ranges to input
|
||||
let offset = input.len() - part.len();
|
||||
let range = (range.start + offset)..;
|
||||
(range, file)
|
||||
})
|
||||
.collect()
|
||||
|
||||
// TODO
|
||||
// completion needs to be more advanced: need to return starting index for replace
|
||||
// for example, "src/" completion application.rs needs to insert after /, but "hx"
|
||||
// completion helix-core needs to replace the text.
|
||||
//
|
||||
// additionally, completion items could have a info section that would get
|
||||
// displayed in a popup above the prompt when items are tabbed over
|
||||
}
|
||||
|
@ -137,9 +137,9 @@ pub fn buffer_picker(views: &[View], current: usize) -> Picker<(Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub mod completers {
|
||||
use std::borrow::Cow;
|
||||
use std::{borrow::Cow, ops::RangeFrom};
|
||||
// TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
|
||||
pub fn filename(input: &str) -> Vec<Cow<'static, str>> {
|
||||
pub fn filename(input: &str) -> Vec<(RangeFrom<usize>, Cow<'static, str>)> {
|
||||
// Rust's filename handling is really annoying.
|
||||
|
||||
use ignore::WalkBuilder;
|
||||
@ -163,6 +163,8 @@ pub mod completers {
|
||||
(path, file_name)
|
||||
};
|
||||
|
||||
let end = (input.len()..);
|
||||
|
||||
let mut files: Vec<_> = WalkBuilder::new(dir.clone())
|
||||
.max_depth(Some(1))
|
||||
.build()
|
||||
@ -178,10 +180,11 @@ pub mod completers {
|
||||
if is_dir {
|
||||
path.push("");
|
||||
}
|
||||
Cow::from(path.to_str().unwrap().to_string())
|
||||
let path = path.to_str().unwrap().to_string();
|
||||
(end.clone(), Cow::from(path))
|
||||
})
|
||||
}) // TODO: unwrap or skip
|
||||
.filter(|path| !path.is_empty()) // TODO
|
||||
.filter(|(_, path)| !path.is_empty()) // TODO
|
||||
.collect();
|
||||
|
||||
// if empty, return a list of dirs and files in current dir
|
||||
@ -195,15 +198,20 @@ pub mod completers {
|
||||
// inefficient, but we need to calculate the scores, filter out None, then sort.
|
||||
let mut matches: Vec<_> = files
|
||||
.into_iter()
|
||||
.filter_map(|file| {
|
||||
.filter_map(|(range, file)| {
|
||||
matcher
|
||||
.fuzzy_match(&file, &file_name)
|
||||
.map(|score| (file, score))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let range = ((input.len() - file_name.len())..);
|
||||
|
||||
matches.sort_unstable_by_key(|(_file, score)| Reverse(*score));
|
||||
files = matches.into_iter().map(|(file, _)| file).collect();
|
||||
files = matches
|
||||
.into_iter()
|
||||
.map(|(file, _)| (range.clone(), file))
|
||||
.collect();
|
||||
|
||||
// TODO: complete to longest common match
|
||||
}
|
||||
|
@ -3,16 +3,15 @@ use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
|
||||
use helix_core::Position;
|
||||
use helix_view::Editor;
|
||||
use helix_view::Theme;
|
||||
use std::borrow::Cow;
|
||||
use std::string::String;
|
||||
use std::{borrow::Cow, ops::RangeFrom};
|
||||
|
||||
pub struct Prompt {
|
||||
prompt: String,
|
||||
pub line: String,
|
||||
cursor: usize,
|
||||
completion: Vec<Cow<'static, str>>,
|
||||
completion: Vec<(RangeFrom<usize>, Cow<'static, str>)>,
|
||||
completion_selection_index: Option<usize>,
|
||||
completion_fn: Box<dyn FnMut(&str) -> Vec<Cow<'static, str>>>,
|
||||
completion_fn: Box<dyn FnMut(&str) -> Vec<(RangeFrom<usize>, Cow<'static, str>)>>,
|
||||
callback_fn: Box<dyn FnMut(&mut Editor, &str, PromptEvent)>,
|
||||
}
|
||||
|
||||
@ -29,7 +28,7 @@ pub enum PromptEvent {
|
||||
impl Prompt {
|
||||
pub fn new(
|
||||
prompt: String,
|
||||
mut completion_fn: impl FnMut(&str) -> Vec<Cow<'static, str>> + 'static,
|
||||
mut completion_fn: impl FnMut(&str) -> Vec<(RangeFrom<usize>, Cow<'static, str>)> + 'static,
|
||||
callback_fn: impl FnMut(&mut Editor, &str, PromptEvent) + 'static,
|
||||
) -> Prompt {
|
||||
Prompt {
|
||||
@ -85,15 +84,9 @@ impl Prompt {
|
||||
self.completion_selection_index.map(|i| i + 1).unwrap_or(0) % self.completion.len();
|
||||
self.completion_selection_index = Some(index);
|
||||
|
||||
let item = &self.completion[index];
|
||||
let (range, item) = &self.completion[index];
|
||||
|
||||
// replace the last arg
|
||||
if let Some(pos) = self.line.rfind(' ') {
|
||||
self.line.replace_range(pos + 1.., item);
|
||||
} else {
|
||||
// need toowned_clone_into nightly feature to reuse allocation
|
||||
self.line = item.to_string();
|
||||
}
|
||||
self.line.replace_range(range.clone(), item);
|
||||
|
||||
self.move_end();
|
||||
// TODO: recalculate completion when completion item is accepted, (Enter)
|
||||
@ -135,7 +128,7 @@ impl Prompt {
|
||||
Rect::new(0, area.height - col_height - 2, area.width, col_height),
|
||||
theme.get("ui.statusline"),
|
||||
);
|
||||
for (i, command) in self.completion.iter().enumerate() {
|
||||
for (i, (_range, completion)) in self.completion.iter().enumerate() {
|
||||
let color = if self.completion_selection_index.is_some()
|
||||
&& i == self.completion_selection_index.unwrap()
|
||||
{
|
||||
@ -146,7 +139,7 @@ impl Prompt {
|
||||
surface.set_stringn(
|
||||
1 + col * BASE_WIDTH,
|
||||
area.height - col_height - 2 + row,
|
||||
&command,
|
||||
&completion,
|
||||
BASE_WIDTH as usize - 1,
|
||||
color,
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user