Skip to main content

strop_engine/editor/transact/
capability.rs

1//! Editor-owned mutation leases publish the core journal even on early return.
2use super::super::{Document, Editor};
3use std::ops::{Deref, DerefMut};
4use strop_core::id::{ByteOffset, DocumentId};
5use strop_core::{Buffer, Range};
6
7pub struct DocumentEdit<'a> {
8    editor: &'a mut Editor,
9    document: DocumentId,
10    map_active: bool,
11}
12impl<'a> DocumentEdit<'a> {
13    pub(crate) fn new(editor: &'a mut Editor, document: DocumentId) -> Self {
14        assert!(
15            editor.docs.get(document).is_some(),
16            "mutation lease requires a live document"
17        );
18        Self {
19            editor,
20            document,
21            map_active: true,
22        }
23    }
24
25    /// A replacement snapshot has its own position correspondence, not the
26    /// ordinary "deleted bytes collapse to the edit start" rule. Publish the
27    /// same journal once, with that mapping for every view and saved anchor.
28    pub(crate) fn replace_snapshot(
29        mut self,
30        rope: ropey::Rope,
31        position: impl Fn(usize) -> usize,
32    ) -> Result<(), strop_core::EditError> {
33        debug_assert!(self.buf.changes().is_empty());
34        self.buf.system_edit().replace_rope(rope)?;
35        self.editor
36            .sync_document_positions(self.document, true, |offset, _| position(offset));
37        Ok(())
38    }
39}
40impl Deref for DocumentEdit<'_> {
41    type Target = Document;
42    fn deref(&self) -> &Document {
43        match self.editor.docs.get(self.document) {
44            Some(document) => document,
45            None => unreachable!("exclusive mutation lease preserves its document"),
46        }
47    }
48}
49impl DerefMut for DocumentEdit<'_> {
50    fn deref_mut(&mut self) -> &mut Document {
51        match self.editor.docs.get_mut(self.document) {
52            Some(document) => document,
53            None => unreachable!("exclusive mutation lease preserves its document"),
54        }
55    }
56}
57impl Drop for DocumentEdit<'_> {
58    fn drop(&mut self) {
59        self.editor.sync_document(self.document, self.map_active);
60    }
61}
62
63pub struct BufferEdit<'a>(DocumentEdit<'a>);
64impl<'a> BufferEdit<'a> {
65    pub(crate) fn new(mut document: DocumentEdit<'a>) -> Self {
66        // Input commands place their own active cursors; document transactions
67        // and worker publications instead remap every view automatically.
68        document.map_active = false;
69        Self(document)
70    }
71    pub fn insert(&mut self, at: impl Into<ByteOffset>, text: &str) -> bool {
72        match self.0.buf.edit().insert(at, text) {
73            Ok(()) => true,
74            Err(error) => {
75                self.0.editor.message = format!("edit failed: {error}");
76                false
77            }
78        }
79    }
80    pub fn delete(&mut self, range: Range) -> String {
81        match self.0.buf.edit().delete(range) {
82            Ok(text) => text,
83            Err(error) => {
84                self.0.editor.message = format!("edit failed: {error}");
85                String::new()
86            }
87        }
88    }
89}
90impl Deref for BufferEdit<'_> {
91    type Target = Buffer;
92    fn deref(&self) -> &Buffer {
93        &self.0.buf
94    }
95}
96impl DerefMut for BufferEdit<'_> {
97    fn deref_mut(&mut self) -> &mut Buffer {
98        &mut self.0.buf
99    }
100}