Fully drop State references.

This commit is contained in:
Blaž Hrastnik 2021-03-31 15:45:18 +09:00
parent dfc17becd5
commit 9eaef6e333
5 changed files with 48 additions and 37 deletions

View File

@ -96,13 +96,15 @@ fn test_find_line_comment() {
// comment // comment
let transaction = toggle_line_comments(&state.doc, &state.selection); let transaction = toggle_line_comments(&state.doc, &state.selection);
transaction.apply(&mut state); transaction.apply(&mut state.doc);
state.selection = state.selection.clone().map(transaction.changes());
assert_eq!(state.doc, " // 1\n\n // 2\n // 3"); assert_eq!(state.doc, " // 1\n\n // 2\n // 3");
// uncomment // uncomment
let transaction = toggle_line_comments(&state.doc, &state.selection); let transaction = toggle_line_comments(&state.doc, &state.selection);
transaction.apply(&mut state); transaction.apply(&mut state.doc);
state.selection = state.selection.clone().map(transaction.changes());
assert_eq!(state.doc, " 1\n\n 2\n 3"); assert_eq!(state.doc, " 1\n\n 2\n 3");
// TODO: account for no margin after comment // TODO: account for no margin after comment

View File

@ -33,7 +33,10 @@ fn default() -> Self {
impl History { impl History {
pub fn commit_revision(&mut self, transaction: &Transaction, original: &State) { pub fn commit_revision(&mut self, transaction: &Transaction, original: &State) {
// TODO: could store a single transaction, if deletes also stored the text they delete // TODO: could store a single transaction, if deletes also stored the text they delete
let revert = transaction.invert(original); let revert = transaction
.invert(&original.doc)
// Store the current cursor position
.with_selection(original.selection.clone());
let new_cursor = self.revisions.len(); let new_cursor = self.revisions.len();
self.revisions.push(Revision { self.revisions.push(Revision {
@ -100,7 +103,7 @@ fn test_undo_redo() {
// Need to commit before applying! // Need to commit before applying!
history.commit_revision(&transaction1, &state); history.commit_revision(&transaction1, &state);
transaction1.apply(&mut state); transaction1.apply(&mut state.doc);
assert_eq!("hello world!", state.doc); assert_eq!("hello world!", state.doc);
// --- // ---
@ -110,18 +113,18 @@ fn test_undo_redo() {
// Need to commit before applying! // Need to commit before applying!
history.commit_revision(&transaction2, &state); history.commit_revision(&transaction2, &state);
transaction2.apply(&mut state); transaction2.apply(&mut state.doc);
assert_eq!("hello 世界!", state.doc); assert_eq!("hello 世界!", state.doc);
// --- // ---
fn undo(history: &mut History, state: &mut State) { fn undo(history: &mut History, state: &mut State) {
if let Some(transaction) = history.undo() { if let Some(transaction) = history.undo() {
transaction.apply(state); transaction.apply(&mut state.doc);
} }
} }
fn redo(history: &mut History, state: &mut State) { fn redo(history: &mut History, state: &mut State) {
if let Some(transaction) = history.redo() { if let Some(transaction) = history.redo() {
transaction.apply(state); transaction.apply(&mut state.doc);
} }
} }

View File

@ -1593,7 +1593,7 @@ fn test_input_edits() {
&state.doc, &state.doc,
vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(), vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
); );
let edits = LanguageLayer::generate_edits(state.doc.slice(..), &transaction.changes); let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
// transaction.apply(&mut state); // transaction.apply(&mut state);
assert_eq!( assert_eq!(
@ -1622,8 +1622,8 @@ fn test_input_edits() {
let mut state = State::new("fn test() {}".into()); let mut state = State::new("fn test() {}".into());
let transaction = let transaction =
Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter()); Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
let edits = LanguageLayer::generate_edits(state.doc.slice(..), &transaction.changes); let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
transaction.apply(&mut state); transaction.apply(&mut state.doc);
assert_eq!(state.doc, "fn test(a: u32) {}"); assert_eq!(state.doc, "fn test(a: u32) {}");
assert_eq!( assert_eq!(

View File

@ -400,9 +400,7 @@ pub fn changes_iter(&self) -> ChangeIterator {
/// a single transaction. /// a single transaction.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Transaction { pub struct Transaction {
/// Changes made to the buffer. changes: ChangeSet,
pub(crate) changes: ChangeSet,
/// When set, explicitly updates the selection.
selection: Option<Selection>, selection: Option<Selection>,
// effects, annotations // effects, annotations
// scroll_into_view // scroll_into_view
@ -417,40 +415,35 @@ pub fn new(doc: &Rope) -> Self {
} }
} }
/// Changes made to the buffer.
pub fn changes(&self) -> &ChangeSet { pub fn changes(&self) -> &ChangeSet {
&self.changes &self.changes
} }
/// When set, explicitly updates the selection.
pub fn selection(&self) -> Option<&Selection> {
self.selection.as_ref()
}
/// Returns true if applied successfully. /// Returns true if applied successfully.
pub fn apply(&self, state: &mut State) -> bool { pub fn apply(&self, doc: &mut Rope) -> bool {
if !self.changes.is_empty() { if !self.changes.is_empty() {
// apply changes to the document // apply changes to the document
if !self.changes.apply(&mut state.doc) { if !self.changes.apply(doc) {
return false; return false;
} }
} }
// TODO: also avoid mapping the selection if not necessary
// update the selection: either take the selection specified in the transaction, or map the
// current selection through changes.
state.selection = self
.selection
.clone()
.unwrap_or_else(|| state.selection.clone().map(&self.changes));
true true
} }
/// Generate a transaction that reverts this one. /// Generate a transaction that reverts this one.
pub fn invert(&self, original: &State) -> Self { pub fn invert(&self, original: &Rope) -> Self {
let changes = self.changes.invert(&original.doc); let changes = self.changes.invert(original);
// Store the current cursor position
let selection = original.selection.clone();
Self { Self {
changes, changes,
selection: Some(selection), selection: None,
} }
} }
@ -675,7 +668,7 @@ fn transaction_change() {
// (1, 1, None) is a useless 0-width delete // (1, 1, None) is a useless 0-width delete
vec![(1, 1, None), (6, 11, Some("void".into())), (12, 17, None)].into_iter(), vec![(1, 1, None), (6, 11, Some("void".into())), (12, 17, None)].into_iter(),
); );
transaction.apply(&mut state); transaction.apply(&mut state.doc);
assert_eq!(state.doc, Rope::from_str("hello void! 123")); assert_eq!(state.doc, Rope::from_str("hello void! 123"));
} }
@ -691,15 +684,20 @@ fn changes_iter() {
fn optimized_composition() { fn optimized_composition() {
let mut state = State::new("".into()); let mut state = State::new("".into());
let t1 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('h')); let t1 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('h'));
t1.apply(&mut state); t1.apply(&mut state.doc);
state.selection = state.selection.clone().map(t1.changes());
let t2 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('e')); let t2 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('e'));
t2.apply(&mut state); t2.apply(&mut state.doc);
state.selection = state.selection.clone().map(t2.changes());
let t3 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('l')); let t3 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('l'));
t3.apply(&mut state); t3.apply(&mut state.doc);
state.selection = state.selection.clone().map(t3.changes());
let t4 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('l')); let t4 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('l'));
t4.apply(&mut state); t4.apply(&mut state.doc);
state.selection = state.selection.clone().map(t4.changes());
let t5 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('o')); let t5 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('o'));
t5.apply(&mut state); t5.apply(&mut state.doc);
state.selection = state.selection.clone().map(t5.changes());
assert_eq!(state.doc, Rope::from_str("hello")); assert_eq!(state.doc, Rope::from_str("hello"));

View File

@ -21,6 +21,7 @@ pub struct Document {
// rope + selection // rope + selection
pub(crate) id: DocumentId, pub(crate) id: DocumentId,
state: State, state: State,
path: Option<PathBuf>, path: Option<PathBuf>,
/// Current editing mode. /// Current editing mode.
@ -185,9 +186,16 @@ pub fn set_selection(&mut self, selection: Selection) {
fn _apply(&mut self, transaction: &Transaction) -> bool { fn _apply(&mut self, transaction: &Transaction) -> bool {
let old_doc = self.text().clone(); let old_doc = self.text().clone();
let success = transaction.apply(&mut self.state); let success = transaction.changes().apply(&mut self.state.doc);
if !transaction.changes().is_empty() { if !transaction.changes().is_empty() {
// update the selection: either take the selection specified in the transaction, or map the
// current selection through changes.
self.state.selection = transaction
.selection()
.cloned()
.unwrap_or_else(|| self.selection().clone().map(transaction.changes()));
self.version += 1; self.version += 1;
// update tree-sitter syntax tree // update tree-sitter syntax tree
@ -415,7 +423,7 @@ fn changeset_to_changes() {
// delete // delete
let transaction = transaction.invert(&old_doc); let transaction = transaction.invert(&old_doc.doc);
let old_doc = doc.state.clone(); let old_doc = doc.state.clone();
doc.apply(&transaction); doc.apply(&transaction);
let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes()); let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());