reedline/completion/base.rs
1use nu_ansi_term::Style;
2use std::ops::Range;
3
4/// A span of source code, with positions in bytes
5#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
6pub struct Span {
7 /// The starting position of the span, in bytes
8 pub start: usize,
9
10 /// The ending position of the span, in bytes
11 pub end: usize,
12}
13
14impl Span {
15 /// Creates a new `Span` from start and end inputs.
16 /// The end parameter must be greater than or equal to the start parameter.
17 ///
18 /// # Panics
19 /// If `end < start`
20 pub fn new(start: usize, end: usize) -> Span {
21 assert!(
22 end >= start,
23 "Can't create a Span whose end < start, start={start}, end={end}"
24 );
25
26 Span { start, end }
27 }
28}
29
30/// A trait that defines how to convert some text and a position to a list of potential completions in that position.
31/// 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.
32pub trait Completer: Send {
33 /// the action that will take the line and position and convert it to a vector of completions, which include the
34 /// span to replace and the contents of that replacement
35 fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion>;
36
37 /// same as [`Completer::complete`] but it will return a vector of ranges of the strings
38 /// the suggestions are based on
39 fn complete_with_base_ranges(
40 &mut self,
41 line: &str,
42 pos: usize,
43 ) -> (Vec<Suggestion>, Vec<Range<usize>>) {
44 let mut ranges = vec![];
45 let suggestions = self.complete(line, pos);
46 for suggestion in &suggestions {
47 ranges.push(suggestion.span.start..suggestion.span.end);
48 }
49 ranges.dedup();
50 (suggestions, ranges)
51 }
52
53 /// action that will return a partial section of available completions
54 /// this command comes handy when trying to avoid to pull all the data at once
55 /// from the completer
56 fn partial_complete(
57 &mut self,
58 line: &str,
59 pos: usize,
60 start: usize,
61 offset: usize,
62 ) -> Vec<Suggestion> {
63 self.complete(line, pos)
64 .into_iter()
65 .skip(start)
66 .take(offset)
67 .collect()
68 }
69
70 /// number of available completions
71 fn total_completions(&mut self, line: &str, pos: usize) -> usize {
72 self.complete(line, pos).len()
73 }
74}
75
76/// Suggestion returned by the Completer
77#[derive(Debug, Default, Clone, PartialEq, Eq)]
78pub struct Suggestion {
79 /// String replacement that will be introduced to the the buffer
80 pub value: String,
81 /// If given, overrides `value` as text displayed to user
82 pub display_override: Option<String>,
83 /// Optional description for the replacement
84 pub description: Option<String>,
85 /// Optional style for the replacement
86 pub style: Option<Style>,
87 /// Optional vector of strings in the suggestion. These can be used to
88 /// represent examples coming from a suggestion
89 pub extra: Option<Vec<String>>,
90 /// Replacement span in the buffer
91 pub span: Span,
92 /// Whether to append a space after selecting this suggestion.
93 /// This helps to avoid that a completer repeats the complete suggestion.
94 pub append_whitespace: bool,
95 /// Indices of the graphemes in the suggestion that matched the typed text.
96 /// Useful if using fuzzy matching.
97 pub match_indices: Option<Vec<usize>>,
98}
99
100impl Suggestion {
101 /// Get value to display to user for this suggestion
102 pub fn display_value(&self) -> &str {
103 self.display_override.as_ref().unwrap_or(&self.value)
104 }
105}