summary refs log blame commit diff stats
path: root/src/suggestion.rs
blob: bad9793f50e30dbf296724c62bb71696e0a41533 (plain) (tree)
















































































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