aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2020-10-06 05:44:18 +0000
committerBlaž Hrastnik2020-10-13 14:13:56 +0000
commitb765c17896632e27857c7707a9d3d96bd49b8899 (patch)
tree8c9a95e1244c8839e2c21776bf73baee0a033d94
parent0926904d4c7f8851d53adfad337bac59ac8f8fb4 (diff)
Hacky undo/redo integration.
-rw-r--r--helix-core/src/state.rs6
-rw-r--r--helix-core/src/transaction.rs7
-rw-r--r--helix-term/src/editor.rs28
-rw-r--r--helix-view/src/commands.rs34
4 files changed, 36 insertions, 39 deletions
diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs
index 9d51c8c5..ed0df9cf 100644
--- a/helix-core/src/state.rs
+++ b/helix-core/src/state.rs
@@ -1,6 +1,6 @@
use crate::graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary, RopeGraphemes};
use crate::syntax::LOADER;
-use crate::{Position, Range, Rope, RopeSlice, Selection, Syntax};
+use crate::{ChangeSet, Position, Range, Rope, RopeSlice, Selection, Syntax};
use anyhow::Error;
use std::path::PathBuf;
@@ -25,6 +25,8 @@ pub struct State {
//
pub syntax: Option<Syntax>,
+ pub changes: Option<ChangeSet>,
+ pub old_state: Option<(Rope, Selection)>,
}
#[derive(Copy, Clone, PartialEq, Eq)]
@@ -50,6 +52,8 @@ impl State {
mode: Mode::Normal,
restore_cursor: false,
syntax: None,
+ changes: None,
+ old_state: None,
}
}
diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs
index d6b151ba..7871052a 100644
--- a/helix-core/src/transaction.rs
+++ b/helix-core/src/transaction.rs
@@ -369,6 +369,13 @@ impl Transaction {
return false;
}
+ // Compose this transaction with the previous one
+ let old_changes = state.changes.take();
+ state.changes = Some(old_changes.map_or_else(
+ || self.changes.clone(),
+ |changes| changes.compose(self.changes.clone()).unwrap(),
+ ));
+
if let Some(syntax) = &mut state.syntax {
// TODO: no unwrap
syntax.update(&old_doc, &state.doc, &self.changes).unwrap();
diff --git a/helix-term/src/editor.rs b/helix-term/src/editor.rs
index 0028521e..b7a385a1 100644
--- a/helix-term/src/editor.rs
+++ b/helix-term/src/editor.rs
@@ -426,31 +426,3 @@ impl Editor {
// TODO: scope matching: biggest union match? [string] & [html, string], [string, html] & [ string, html]
// can do this by sorting our theme matches based on array len (longest first) then stopping at the
// first rule that matches (rule.all(|scope| scopes.contains(scope)))
-//
-// let visual_x = 0;
-// let line = ?;
-// for span in spans {
-// start(scope) => scopes.push(scope)
-// span =>
-// let text = rope.slice(span.start..span.end);
-// let style = calculate_style(scopes);
-// for each grapheme in text.graphemes() {
-// // if newline += lines, continue
-//
-// if state.selection.ranges().any(|range| range.contains(char_index)) {
-// if exactly on cursor {
-// }
-// if on primary cursor? {
-// }
-// modify style temporarily
-// }
-//
-// // if in bounds
-//
-// // if tab, draw tab width
-// // draw(visual_x, line, grapheme, style)
-// // increment visual_x by grapheme_width(grapheme)
-// // increment char_index by grapheme.len_chars()
-// }
-// end => scopes.pop()
-// }
diff --git a/helix-view/src/commands.rs b/helix-view/src/commands.rs
index c92b33f5..9a6d2e5d 100644
--- a/helix-view/src/commands.rs
+++ b/helix-view/src/commands.rs
@@ -3,7 +3,7 @@ use helix_core::{
regex::Regex,
selection,
state::{Direction, Granularity, Mode, State},
- Range, Selection, Tendril, Transaction,
+ ChangeSet, Range, Selection, Tendril, Transaction,
};
use once_cell::sync::Lazy;
@@ -253,14 +253,16 @@ pub fn collapse_selection(view: &mut View, _count: usize) {
.transform(|range| Range::new(range.head, range.head))
}
-// insert mode:
-// first we calculate the correct cursors/selections
-// then we just append at each cursor
-// lastly, if it was append mode we shift cursor by 1?
+fn enter_insert_mode(view: &mut View) {
+ view.state.mode = Mode::Insert;
+ // HAXX
+ view.state.changes = Some(ChangeSet::new(view.state.doc()));
+ view.state.old_state = Some((view.state.doc().clone(), view.state.selection.clone()));
+}
// inserts at the start of each selection
pub fn insert_mode(view: &mut View, _count: usize) {
- view.state.mode = Mode::Insert;
+ enter_insert_mode(view);
view.state.selection = view
.state
@@ -270,7 +272,7 @@ pub fn insert_mode(view: &mut View, _count: usize) {
// inserts at the end of each selection
pub fn append_mode(view: &mut View, _count: usize) {
- view.state.mode = Mode::Insert;
+ enter_insert_mode(view);
view.state.restore_cursor = true;
// TODO: as transaction
@@ -303,21 +305,21 @@ fn selection_lines(state: &State) -> Vec<usize> {
// I inserts at the start of each line with a selection
pub fn prepend_to_line(view: &mut View, count: usize) {
- view.state.mode = Mode::Insert;
+ enter_insert_mode(view);
move_line_start(view, count);
}
// A inserts at the end of each line with a selection
pub fn append_to_line(view: &mut View, count: usize) {
- view.state.mode = Mode::Insert;
+ enter_insert_mode(view);
move_line_end(view, count);
}
// o inserts a new line after each line with a selection
pub fn open_below(view: &mut View, _count: usize) {
- view.state.mode = Mode::Insert;
+ enter_insert_mode(view);
let lines = selection_lines(&view.state);
@@ -356,6 +358,18 @@ pub fn open_below(view: &mut View, _count: usize) {
pub fn normal_mode(view: &mut View, _count: usize) {
view.state.mode = Mode::Normal;
+ if let Some(changes) = view.state.changes.take() {
+ // Instead of doing this messy merge we could always commit, and based on transaction
+ // annotations either add a new layer or compose into the previous one.
+ let transaction = Transaction::from(changes).with_selection(view.state.selection().clone());
+ let (doc, selection) = view.state.old_state.take().unwrap();
+ let mut old_state = State::new(doc);
+ old_state.selection = selection;
+
+ // TODO: take transaction by value?
+ view.history.commit_revision(&transaction, &old_state);
+ }
+
// if leaving append mode, move cursor back by 1
if view.state.restore_cursor {
let text = &view.state.doc.slice(..);