Skip to content

Commit

Permalink
Don't slice line in DefaultCompleter (#695)
Browse files Browse the repository at this point in the history
* Don't slice line in DefaultCompleter

* Revert completions example

* Fix clippy lint

* Treat input as '' if None

* Update values even if string_difference empty

* Rename start to pos in list_menu

* Fix string_diff bug with repeated char

* Trim before completing in DefaultCompleter

* Remove TODO

* Make HistoryCompleter take end as pos
  • Loading branch information
ysthakur authored Jan 11, 2024
1 parent 3e2c0fe commit 0c5f981
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 17 deletions.
3 changes: 2 additions & 1 deletion src/completion/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ impl Span {
}
}

/// A trait that defines how to convert a line and position to a list of potential completions in that position.
/// A trait that defines how to convert some text and a position to a list of potential completions in that position.
/// The text could be a part of the whole line, and the position is the index of the end of the text in the original line.
pub trait Completer: Send {
/// the action that will take the line and position and convert it to a vector of completions, which include the
/// span to replace and the contents of that replacement
Expand Down
5 changes: 4 additions & 1 deletion src/completion/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ impl Completer for DefaultCompleter {
fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
let mut span_line_whitespaces = 0;
let mut completions = vec![];
// Trimming in case someone passes in text containing stuff after the cursor, if
// `only_buffer_difference` is false
let line = if line.len() > pos { &line[..pos] } else { line };
if !line.is_empty() {
let mut split = line[0..pos].split(' ').rev();
let mut split = line.split(' ').rev();
let mut span_line: String = String::new();
for _ in 0..split.clone().count() {
if let Some(s) = split.next() {
Expand Down
4 changes: 2 additions & 2 deletions src/completion/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ impl<'menu> HistoryCompleter<'menu> {

fn create_suggestion(&self, line: &str, pos: usize, value: &str) -> Suggestion {
let span = Span {
start: pos,
end: pos + line.len(),
start: pos - line.len(),
end: pos,
};

Suggestion {
Expand Down
19 changes: 13 additions & 6 deletions src/menu/columnar_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,13 +526,16 @@ impl Menu for ColumnarMenu {

/// Updates menu values
fn update_values(&mut self, editor: &mut Editor, completer: &mut dyn Completer) {
if self.only_buffer_difference {
self.values = if self.only_buffer_difference {
if let Some(old_string) = &self.input {
let (start, input) = string_difference(editor.get_buffer(), old_string);
if !input.is_empty() {
self.values = completer.complete(input, start);
self.reset_position();
completer.complete(input, start + input.len())
} else {
completer.complete("", editor.insertion_point())
}
} else {
completer.complete("", editor.insertion_point())
}
} else {
// If there is a new line character in the line buffer, the completer
Expand All @@ -541,9 +544,13 @@ impl Menu for ColumnarMenu {
// Also, by replacing the new line character with a space, the insert
// position is maintain in the line buffer.
let trimmed_buffer = editor.get_buffer().replace('\n', " ");
self.values = completer.complete(trimmed_buffer.as_str(), editor.insertion_point());
self.reset_position();
}
completer.complete(
&trimmed_buffer[..editor.insertion_point()],
editor.insertion_point(),
)
};

self.reset_position();
}

/// The working details for the menu changes based on the size of the lines
Expand Down
15 changes: 9 additions & 6 deletions src/menu/list_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,20 +395,23 @@ impl Menu for ListMenu {
/// Collecting the value from the completer to be shown in the menu
fn update_values(&mut self, editor: &mut Editor, completer: &mut dyn Completer) {
let line_buffer = editor.line_buffer();
let (start, input) = if self.only_buffer_difference {
let (pos, input) = if self.only_buffer_difference {
match &self.input {
Some(old_string) => {
let (start, input) = string_difference(line_buffer.get_buffer(), old_string);
if input.is_empty() {
(line_buffer.insertion_point(), "")
} else {
(start, input)
(start + input.len(), input)
}
}
None => (line_buffer.insertion_point(), ""),
}
} else {
(line_buffer.insertion_point(), line_buffer.get_buffer())
(
line_buffer.insertion_point(),
&line_buffer.get_buffer()[..line_buffer.insertion_point()],
)
};

let parsed = parse_selection_char(input, SELECTION_CHAR);
Expand All @@ -421,7 +424,7 @@ impl Menu for ListMenu {
}

self.values = if parsed.remainder.is_empty() {
self.query_size = Some(completer.total_completions(parsed.remainder, start));
self.query_size = Some(completer.total_completions(parsed.remainder, pos));

let skip = self.pages.iter().take(self.page).sum::<Page>().size;
let take = self
Expand All @@ -430,10 +433,10 @@ impl Menu for ListMenu {
.map(|page| page.size)
.unwrap_or(self.page_size);

completer.partial_complete(input, start, skip, take)
completer.partial_complete(input, pos, skip, take)
} else {
self.query_size = None;
completer.complete(input, start)
completer.complete(input, pos)
}
}

Expand Down
11 changes: 10 additions & 1 deletion src/menu/menu_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ pub fn string_difference<'a>(new_string: &'a str, old_string: &str) -> (usize, &
false
}
} else {
*c == old_chars[old_char_index].1
old_char_index == new_char_index && *c == old_chars[old_char_index].1
};

if equal {
Expand Down Expand Up @@ -479,6 +479,15 @@ mod tests {
assert_eq!(res, (6, "she"));
}

#[test]
fn string_difference_with_repeat() {
let new_string = "ee";
let old_string = "e";

let res = string_difference(new_string, old_string);
assert_eq!(res, (1, "e"));
}

#[test]
fn find_common_string_with_ansi() {
use crate::Span;
Expand Down

0 comments on commit 0c5f981

Please sign in to comment.