Skip to main content

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}