Skip to content

Commit 0c5f981

Browse files
authored
Don't slice line in DefaultCompleter (#695)
* 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
1 parent 3e2c0fe commit 0c5f981

File tree

6 files changed

+40
-17
lines changed

6 files changed

+40
-17
lines changed

src/completion/base.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ impl Span {
2424
}
2525
}
2626

27-
/// A trait that defines how to convert a line and position to a list of potential completions in that position.
27+
/// A trait that defines how to convert some text and a position to a list of potential completions in that position.
28+
/// 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.
2829
pub trait Completer: Send {
2930
/// the action that will take the line and position and convert it to a vector of completions, which include the
3031
/// span to replace and the contents of that replacement

src/completion/default.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ impl Completer for DefaultCompleter {
7171
fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
7272
let mut span_line_whitespaces = 0;
7373
let mut completions = vec![];
74+
// Trimming in case someone passes in text containing stuff after the cursor, if
75+
// `only_buffer_difference` is false
76+
let line = if line.len() > pos { &line[..pos] } else { line };
7477
if !line.is_empty() {
75-
let mut split = line[0..pos].split(' ').rev();
78+
let mut split = line.split(' ').rev();
7679
let mut span_line: String = String::new();
7780
for _ in 0..split.clone().count() {
7881
if let Some(s) = split.next() {

src/completion/history.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ impl<'menu> HistoryCompleter<'menu> {
5252

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

5959
Suggestion {

src/menu/columnar_menu.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -526,13 +526,16 @@ impl Menu for ColumnarMenu {
526526

527527
/// Updates menu values
528528
fn update_values(&mut self, editor: &mut Editor, completer: &mut dyn Completer) {
529-
if self.only_buffer_difference {
529+
self.values = if self.only_buffer_difference {
530530
if let Some(old_string) = &self.input {
531531
let (start, input) = string_difference(editor.get_buffer(), old_string);
532532
if !input.is_empty() {
533-
self.values = completer.complete(input, start);
534-
self.reset_position();
533+
completer.complete(input, start + input.len())
534+
} else {
535+
completer.complete("", editor.insertion_point())
535536
}
537+
} else {
538+
completer.complete("", editor.insertion_point())
536539
}
537540
} else {
538541
// If there is a new line character in the line buffer, the completer
@@ -541,9 +544,13 @@ impl Menu for ColumnarMenu {
541544
// Also, by replacing the new line character with a space, the insert
542545
// position is maintain in the line buffer.
543546
let trimmed_buffer = editor.get_buffer().replace('\n', " ");
544-
self.values = completer.complete(trimmed_buffer.as_str(), editor.insertion_point());
545-
self.reset_position();
546-
}
547+
completer.complete(
548+
&trimmed_buffer[..editor.insertion_point()],
549+
editor.insertion_point(),
550+
)
551+
};
552+
553+
self.reset_position();
547554
}
548555

549556
/// The working details for the menu changes based on the size of the lines

src/menu/list_menu.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -395,20 +395,23 @@ impl Menu for ListMenu {
395395
/// Collecting the value from the completer to be shown in the menu
396396
fn update_values(&mut self, editor: &mut Editor, completer: &mut dyn Completer) {
397397
let line_buffer = editor.line_buffer();
398-
let (start, input) = if self.only_buffer_difference {
398+
let (pos, input) = if self.only_buffer_difference {
399399
match &self.input {
400400
Some(old_string) => {
401401
let (start, input) = string_difference(line_buffer.get_buffer(), old_string);
402402
if input.is_empty() {
403403
(line_buffer.insertion_point(), "")
404404
} else {
405-
(start, input)
405+
(start + input.len(), input)
406406
}
407407
}
408408
None => (line_buffer.insertion_point(), ""),
409409
}
410410
} else {
411-
(line_buffer.insertion_point(), line_buffer.get_buffer())
411+
(
412+
line_buffer.insertion_point(),
413+
&line_buffer.get_buffer()[..line_buffer.insertion_point()],
414+
)
412415
};
413416

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

423426
self.values = if parsed.remainder.is_empty() {
424-
self.query_size = Some(completer.total_completions(parsed.remainder, start));
427+
self.query_size = Some(completer.total_completions(parsed.remainder, pos));
425428

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

433-
completer.partial_complete(input, start, skip, take)
436+
completer.partial_complete(input, pos, skip, take)
434437
} else {
435438
self.query_size = None;
436-
completer.complete(input, start)
439+
completer.complete(input, pos)
437440
}
438441
}
439442

src/menu/menu_functions.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ pub fn string_difference<'a>(new_string: &'a str, old_string: &str) -> (usize, &
209209
false
210210
}
211211
} else {
212-
*c == old_chars[old_char_index].1
212+
old_char_index == new_char_index && *c == old_chars[old_char_index].1
213213
};
214214

215215
if equal {
@@ -479,6 +479,15 @@ mod tests {
479479
assert_eq!(res, (6, "she"));
480480
}
481481

482+
#[test]
483+
fn string_difference_with_repeat() {
484+
let new_string = "ee";
485+
let old_string = "e";
486+
487+
let res = string_difference(new_string, old_string);
488+
assert_eq!(res, (1, "e"));
489+
}
490+
482491
#[test]
483492
fn find_common_string_with_ansi() {
484493
use crate::Span;

0 commit comments

Comments
 (0)