// 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, text: String, } impl Suggestion { /// Creates a new `Suggestion` for `text` for the given `range`. pub fn new(range: Range, text: String) -> Self { Self { range: range, text: text, } } /// Returns the range associated with this suggestion. pub fn get_range(&self) -> Range { 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) -> 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) } }