summaryrefslogtreecommitdiff
path: root/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'buffer.c')
-rw-r--r--buffer.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/buffer.c b/buffer.c
index 7cb1208..640e64c 100644
--- a/buffer.c
+++ b/buffer.c
@@ -446,6 +446,8 @@ static void buffer_print_undo_history(TextBuffer *buffer) {
static void buffer_edit(TextBuffer *buffer, BufferPos start, u32 prev_len, u32 new_len) {
BufferEdit edit = {0};
if (buffer_edit_create(buffer, &edit, start, prev_len, new_len)) {
+ edit.chain = buffer->chaining_edits;
+ if (buffer->will_chain_edits) buffer->chaining_edits = true;
buffer_append_edit(buffer, &edit);
}
}
@@ -489,10 +491,11 @@ static bool buffer_edit_does_anything(TextBuffer *buffer, BufferEdit *edit) {
// has enough time passed since the last edit that we should create a new one?
static bool buffer_edit_split(TextBuffer *buffer) {
- double curr_time = time_get_seconds();
- double undo_time_cutoff = buffer_settings(buffer)->undo_save_time; // only keep around edits for this long (in seconds).
BufferEdit *last_edit = arr_lastp(buffer->undo_history);
if (!last_edit) return true;
+ if (buffer->chaining_edits) return false;
+ double curr_time = time_get_seconds();
+ double undo_time_cutoff = buffer_settings(buffer)->undo_save_time; // only keep around edits for this long (in seconds).
return curr_time - last_edit->time > undo_time_cutoff;
}
@@ -1632,12 +1635,18 @@ static void buffer_cursor_to_edit(TextBuffer *buffer, BufferEdit *edit) {
buffer_center_cursor(buffer); // whenever we undo an edit, put the cursor in the center, to make it clear where the undo happened
}
+// a <-b <-c
+// c <-b <-a
+
void buffer_undo(TextBuffer *buffer, i64 ntimes) {
+ bool chain_next = false;
for (i64 i = 0; i < ntimes; ++i) {
BufferEdit *edit = arr_lastp(buffer->undo_history);
if (edit) {
+ bool chain = edit->chain;
BufferEdit inverse = {0};
if (buffer_undo_edit(buffer, edit, &inverse)) {
+ inverse.chain = chain_next;
if (i == ntimes - 1) {
// if we're on the last undo, put cursor where edit is
buffer_cursor_to_edit(buffer, edit);
@@ -1647,16 +1656,21 @@ void buffer_undo(TextBuffer *buffer, i64 ntimes) {
buffer_edit_free(edit);
arr_remove_last(buffer->undo_history);
}
- }
+ if (chain) --i;
+ chain_next = chain;
+ } else break;
}
}
void buffer_redo(TextBuffer *buffer, i64 ntimes) {
+ bool chain_next = false;
for (i64 i = 0; i < ntimes; ++i) {
BufferEdit *edit = arr_lastp(buffer->redo_history);
if (edit) {
+ bool chain = edit->chain;
BufferEdit inverse = {0};
if (buffer_undo_edit(buffer, edit, &inverse)) {
+ inverse.chain = chain_next;
if (i == ntimes - 1)
buffer_cursor_to_edit(buffer, edit);
@@ -1667,7 +1681,9 @@ void buffer_redo(TextBuffer *buffer, i64 ntimes) {
buffer_edit_free(edit);
arr_remove_last(buffer->redo_history);
}
- }
+ if (chain) --i;
+ chain_next = chain;
+ } else break;
}
}
@@ -2176,3 +2192,19 @@ void buffer_render(TextBuffer *buffer, Rect r) {
}
}
}
+
+// if you do:
+// buffer_start_edit_chain(buffer)
+// buffer_insert_text_at_pos(buffer, some position, "text1")
+// buffer_insert_text_at_pos(buffer, another position, "text2")
+// buffer_end_edit_chain(buffer)
+// pressing ctrl+z will undo both the insertion of text1 and text2.
+static void buffer_start_edit_chain(TextBuffer *buffer) {
+ assert(!buffer->chaining_edits);
+ assert(!buffer->will_chain_edits);
+ buffer->will_chain_edits = true;
+}
+
+static void buffer_end_edit_chain(TextBuffer *buffer) {
+ buffer->chaining_edits = buffer->will_chain_edits = false;
+}