Repository: helix-editor/helix
File: helix-view/src/document.rs (Rust)

Code before:
            }

            // if specified, the current selection should instead be replaced by transaction.selection
            if let Some(selection) = transaction.selection() {
                self.selections.insert(
                    view_id,
                    selection.clone().ensure_invariants(self.text.slice(..)),
                );
                helix_event::dispatch(SelectionDidChange {
                    doc: self,
                    view: view_id,
                });
            }

            self.modified_since_accessed = true;
        }

        if !transaction.changes().is_empty() {
            self.version += 1;
            // start computing the diff in parallel
            if let Some(diff_handle) = &self.diff_handle {
                diff_handle.update_document(self.text.clone(), false);
            }

            // generate revert to savepoint
            if !self.savepoints.is_empty() {
                let revert = transaction.invert(&old_doc);
                self.savepoints
                    .retain_mut(|save_point| match save_point.upgrade() {
                        Some(savepoint) => {
                            let mut revert_to_savepoint = savepoint.revert.lock();
                            *revert_to_savepoint =
                                revert.clone().compose(mem::take(&mut revert_to_savepoint));
                            true
                        }
                        None => false,
                    })
            }

            // update tree-sitter syntax tree
            if let Some(syntax) = &mut self.syntax {
                // TODO: no unwrap
                let res = syntax.update(
                    old_doc.slice(..),
                    self.text.slice(..),
                    transaction.changes(),
                );
                if res.is_err() {
                    log::error!("TS parser failed, disabling TS for the current buffer: {res:?}");
                    self.syntax = None;
                }

Review comment (suggestion):
@pascalkuthe this is the only remaining direct access of view_position outside of the access methods, but I think we should keep it because:

1. Since this involves mutating map entries, I think the alternatives of getting view positions then mutating and calling `set_view_position`, or making a specialised method to map them will be messier.
2. If/when we move other parts of `View` in to `ViewData` (`jumps`, `object_selections`) it would make sense to mutate them together in this for loop.
3. This is internal to `mod document`

Code after:

        let success = transaction.changes().apply(&mut self.text);

        if success {
            if emit_lsp_notification {
                helix_event::dispatch(DocumentDidChange {
                    doc: self,
                    view: view_id,
                    old_text: &old_doc,
                });
            }

            for selection in self.selections.values_mut() {
                *selection = selection
                    .clone()
                    // Map through changes
                    .map(transaction.changes())
                    // Ensure all selections across all views still adhere to invariants.
                    .ensure_invariants(self.text.slice(..));
            }

            for view_data in self.view_data.values_mut() {
                view_data.view_position.anchor = transaction
                    .changes()
                    .map_pos(view_data.view_position.anchor, Assoc::Before);
            }

            // if specified, the current selection should instead be replaced by transaction.selection
            if let Some(selection) = transaction.selection() {
                self.selections.insert(
                    view_id,
                    selection.clone().ensure_invariants(self.text.slice(..)),
                );
                helix_event::dispatch(SelectionDidChange {
                    doc: self,
                    view: view_id,
                });
            }

            self.modified_since_accessed = true;
        }

        if !transaction.changes().is_empty() {
            self.version += 1;
            // start computing the diff in parallel
            if let Some(diff_handle) = &self.diff_handle {
                diff_handle.update_document(self.text.clone(), false);
            }

            // generate revert to savepoint
            if !self.savepoints.is_empty() {