summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs14
-rw-r--r--src/suggestion.rs81
2 files changed, 95 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 2900669..d8c7582 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,18 @@
+// Copyright (c) 2021 Soni L.
+
+//! Iosonism is a command parsing library. It parses commands from strings, in
+//! contrast with an argument parsing library, which parses arrays of strings.
+//!
+//! Iosonism is based on [Brigadier](https://github.com/Mojang/brigadier).
+
+// quick overview of brigadier vs iosonism:
+//
+// - brigadier.StringReader -> iosonism::strcursor::StringReader + Cursor<&str>
+// - brigadier.context.StringRange -> Range<usize>
+// - brigadier.suggestion.Suggestion -> iosonism::suggestion::Suggestion;
+
 pub mod strcursor;
+pub mod suggestion;
 
 #[cfg(test)]
 mod tests {
diff --git a/src/suggestion.rs b/src/suggestion.rs
new file mode 100644
index 0000000..bad9793
--- /dev/null
+++ b/src/suggestion.rs
@@ -0,0 +1,81 @@
+// Copyright (c) 2021 Soni L.
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+//! A Suggestion.
+
+use ::std::ops::Range;
+
+/// A suggested editing operation.
+///
+/// # Examples
+///
+/// ```rust
+/// use iosonism::suggestion::Suggestion;
+///
+/// let s = Suggestion::new(3..3, "home".into());
+/// assert_eq!(s.apply("Go ".into()), "Go home");
+/// ```
+#[derive(Debug, PartialEq, Eq, Hash)]
+pub struct Suggestion {
+    range: Range<usize>,
+    text: String,
+}
+
+impl Suggestion {
+    /// Creates a new `Suggestion` for `text` for the given `range`.
+    pub fn new(range: Range<usize>, text: String) -> Self {
+        Self {
+            range: range,
+            text: text,
+        }
+    }
+
+    /// Returns the range associated with this suggestion.
+    pub fn get_range(&self) -> Range<usize> {
+        self.range.clone()
+    }
+
+    /// Returns the replacement text associated with this suggestion.
+    pub fn get_text(&self) -> &str {
+        &self.text
+    }
+
+    /// Applies this suggestion on the `input`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the range is outside the `input`'s bounds, or not on an UTF-8
+    /// boundary.
+    pub fn apply(&self, mut input: String) -> String {
+        // the use of String here actually has a performance reason:
+        // either you already have a String, in which case this is fast,
+        // or you need a String anyway, in which case it's your responsibility
+        // to make your &str into one.
+        input.replace_range(self.range.clone(), &self.text);
+        input
+    }
+
+    /// Creates a new `Suggestion` by applying this `Suggestion` on the
+    /// `range` part of the given `input`.
+    ///
+    /// # Panics
+    ///
+    /// May panic if this suggestion's range is outside the bounds given by
+    /// `range`. Panics if the given `range` is outside `input`'s bounds, or any
+    /// range is not on an UTF-8 boundary.
+    // FIXME: This function could really use a better description.
+    pub fn expand(&self, mut input: String, range: Range<usize>) -> Self {
+        // It is our understanding that both ranges must be within input.
+        // It's also our understanding that self.range must be within the passed
+        // range.
+        // So we just do our best to enforce those.
+        input.truncate(range.end);
+        input.drain(..range.start);
+        input.replace_range(
+            (self.range.start-range.start)..(self.range.end-range.start),
+            &self.text,
+        );
+        Self::new(range, input)
+    }
+}