Repository: microsoft/edit
File: src/buffer/mod.rs (Rust)

Code before:
                self.cursor_move_to_logical_internal(safe_cursor, change.cursor_before);
            change.cursor_before = self.cursor.logical_pos;
            // Can't use `set_cursor_internal` here, because we haven't updated the line stats yet.
            self.cursor = cursor_before;

            if self.undo_stack.is_empty() {
                self.last_history_type = HistoryType::Other;
            }
        }

        // Also takes care of clearing `cursor_for_rendering`.
        self.reflow(false);
    }

    /// For interfacing with ICU.
    pub(crate) fn read_backward(&self, off: usize) -> &[u8] {
        self.buffer.read_backward(off)
    }

    /// For interfacing with ICU.
    pub fn read_forward(&self, off: usize) -> &[u8] {
        self.buffer.read_forward(off)
    }

    /// Processes the replacement string when using regex for capture groups.
    fn get_regex_replacement<'a>(&mut self, replacement: &'a str) -> Cow<'a, str> {
        let search = if let Some(search) = &mut self.search {
            search.get_mut()
        } else {
            return Cow::Borrowed(replacement);
        };

        if !search.options.use_regex || !replacement.contains('$') {
            return Cow::Borrowed(replacement);
        }

        let scratch = scratch_arena(None);
        let mut result = String::with_capacity(replacement.len());
        let mut chars = replacement.chars().peekable();

        while let Some(ch) = chars.next() {
            match ch {
                '$' => {
                    let mut digits = ArenaString::new_in(&scratch);

                    while let Some(&next_ch) = chars.peek() {
                        if digits.is_empty() && next_ch == '$' {
                            // Consume the escaped dollar sign.
                            chars.next();
                            break;
                        }

Review comment (suggestion):
You can feel free to return an `ArenString` or better yet, `Vec<u8, &Arena>` here. You can find various places in this code that demonstrates how to do that. Allocating in the arena is very cheap and copying memory is as well. 🙂

This may help you below because then you won't need `String::from_utf8_lossy`.

Code after:
    /// Returns the current selection anchors.
    ///
    /// If there's no selection and `line_fallback` is `true`,
    /// the start/end of the current line are returned.
    /// This is meant to be used for Ctrl+C / Ctrl+X.
    fn selection_range_internal(&self, line_fallback: bool) -> Option<(Cursor, Cursor)> {
        let [beg, end] = match self.selection {
            None if !line_fallback => return None,
            None => [
                Point { x: 0, y: self.cursor.logical_pos.y },
                Point { x: 0, y: self.cursor.logical_pos.y + 1 },
            ],
            Some(TextBufferSelection { beg, end }) => minmax(beg, end),
        };

        let beg = self.cursor_move_to_logical_internal(self.cursor, beg);
        let end = self.cursor_move_to_logical_internal(beg, end);

        if beg.offset < end.offset { Some((beg, end)) } else { None }
    }

    /// Starts a new edit operation.
    /// This is used for tracking the undo/redo history.
    fn edit_begin(&mut self, history_type: HistoryType, cursor: Cursor) {
        self.active_edit_depth += 1;
        if self.active_edit_depth > 1 {
            return;
        }

        let cursor_before = self.cursor;
        self.set_cursor_internal(cursor);

        // If both the last and this are a Write/Delete operation, we skip allocating a new undo history item.
        if history_type != self.last_history_type
            || !matches!(history_type, HistoryType::Write | HistoryType::Delete)
        {
            self.redo_stack.clear();
            while self.undo_stack.len() > 1000 {
                self.undo_stack.pop_front();
            }

            self.last_history_type = history_type;
            self.undo_stack.push_back(SemiRefCell::new(HistoryEntry {
                cursor_before: cursor_before.logical_pos,
                selection_before: self.selection,
                stats_before: self.stats,
                generation_before: self.buffer.generation(),
                cursor: cursor.logical_pos,
                deleted: Vec::new(),
                added: Vec::new(),
            }));