summary refs log tree commit diff stats
path: root/src/suggestion.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/suggestion.rs')
-rw-r--r--src/suggestion.rs81
1 files changed, 81 insertions, 0 deletions
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)
+    }
+}