// 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)
}
}