summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/suggestion.rs90
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)
+    }
+}