diff options
-rw-r--r-- | src/suggestion.rs | 90 |
1 files changed, 87 insertions, 3 deletions
diff --git a/src/suggestion.rs b/src/suggestion.rs index 128d025..ca99b3c 100644 --- a/src/suggestion.rs +++ b/src/suggestion.rs @@ -4,8 +4,9 @@ //! Suggestion machinery. -//use ::std::collections::HashSet; +use ::std::future::Future; use ::std::ops::Range; +use ::std::pin::Pin; /// A suggested editing operation. /// @@ -89,6 +90,7 @@ impl Suggestion { /// Editing suggestions. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct Suggestions { + // brigadier also supports "tooltips". FIXME revisit this. range: Range<usize>, suggestions: Vec<Suggestion>, } @@ -184,5 +186,87 @@ impl Suggestions { } } -///// Helper for building suggestions. -//pub struct SuggestionsBuilder<'a>(&'a str); +/// Helper for building suggestions. +pub struct SuggestionsBuilder<'a> { + // brigadier throws an inputLowerCase/remainingLowerCase in here. + // given we're using 'a, it feels *weird* to use String with it. + // so for now we don't bother. FIXME revisit this? + // also note that brigadier exists for minecraft, whereas we're porting it + // for use with a debugger. we can assume our users are familiar with and/or + // prefer case-sensitivity. + input: &'a str, + start: usize, + remaining: &'a str, + result: Vec<Suggestion>, +} + +impl<'a> SuggestionsBuilder<'a> { + /// Creates a new `SuggestionsBuilder`. + pub fn new(input: &'a str, start: usize) -> Self { + Self { + input: input, + start: start, + remaining: &input[start..], + result: Vec::new(), + } + } + + /// Returns the full input. + pub fn get_input(&self) -> &'a str { + self.input + } + + /// Returns the start position. + pub fn get_start(&self) -> usize { + self.start + } + + /// Returns the remaining input. + pub fn get_remaining(&self) -> &'a str { + self.remaining + } + + /// Builds the final `Suggestions`, draining this builder. + pub fn drain_build(&mut self) -> Suggestions { + Suggestions::create(self.input, ::std::mem::take(&mut self.result)) + } + + /// Builds the final `Suggestions`, as a `Future`, draining this builder. + pub fn drain_build_future( + &mut self, + ) -> Pin<Box<dyn Future<Output=Suggestions> + Send + 'a>> { + let input = self.input; + let result = ::std::mem::take(&mut self.result); + Box::pin(async move { + Suggestions::create(input, result) + }) + } + + /// Adds a new suggestion. + pub fn suggest(&mut self, text: String) -> &mut Self { + if text != self.remaining { + self.result.push({ + Suggestion::new(self.start..self.input.len(), text) + }); + } + self + } + + /// Adds all the suggestions from the given SuggestionBuilder, draining it. + pub fn add_drain(&mut self, other: &mut SuggestionsBuilder) -> &mut Self { + self.result.extend(std::mem::take(&mut other.result)); + self + } + + /// Creates a *new* `SuggestionsBuilder`, with no suggestions, starting at + /// the given position. + pub fn starting_from(&self, start: usize) -> Self { + Self::new(self.input, start) + } + + /// Creates a *new* `SuggestionsBuilder`, with no suggestions, starting from + /// the same position as this one. + pub fn restart(&self) -> Self { + self.starting_from(self.start) + } +} |