diff --git a/src/text_editor/layout.cpp b/src/text_editor/layout.cpp index 1648e9d..52faed9 100644 --- a/src/text_editor/layout.cpp +++ b/src/text_editor/layout.cpp @@ -20,7 +20,8 @@ struct HistoryEntry { }; struct History { - Array entries; + Array undo_stack; + Array redo_stack; int debug_edit_phase; }; @@ -287,14 +288,78 @@ void MergeCursors(Window *window) { new_cursors.add(it); } } + Assert(new_cursors.len <= window->cursors.len); window->cursors.dealloc(); window->cursors = new_cursors; } -void UndoEdit(Window *window) { - if (window->history.entries.len <= 0) return; +void SaveHistoryBeforeMergeCursor(Window *window, Array *stack) { + HistoryEntry *entry = stack->alloc(); + Allocator sys_allocator = GetSystemAllocator(); + entry->cursors = window->cursors.tight_copy(sys_allocator); +} - HistoryEntry entry = window->history.entries.pop(); +void SaveHistoryBeforeApplyEdits(Window *window, Array *stack, Array edits) { + HistoryEntry *entry = stack->last(); + Allocator sys_allocator = GetSystemAllocator(); + entry->edits = edits.tight_copy(sys_allocator); + + // Make reverse edits + For(entry->edits) { + Range new_range = {it.range.min, it.range.min + it.string.len}; + String string = GetString(window->buffer, it.range); + it.string = Copy(sys_allocator, string); + it.range = new_range; + } + + Array temp_edits = entry->edits.tight_copy(sys_allocator); + defer { temp_edits.dealloc(); }; + + // Fix reverse edits + ForItem(edit, edits) { + int64_t remove_size = GetRangeSize(edit.range); + int64_t insert_size = edit.string.len; + int64_t offset = insert_size - remove_size; + + for (int64_t i = 0; i < entry->edits.len; i += 1) { + Edit &new_edit = entry->edits.data[i]; + Edit &old_edit = temp_edits.data[i]; + if (old_edit.range.min > edit.range.min) { + new_edit.range.min += offset; + new_edit.range.max += offset; + } + } + } +} + +void RedoEdit(Window *window) { + if (window->history.redo_stack.len <= 0) return; + + HistoryEntry entry = window->history.redo_stack.pop(); + + SaveHistoryBeforeMergeCursor(window, &window->history.undo_stack); + SaveHistoryBeforeApplyEdits(window, &window->history.undo_stack, entry.edits); + _ApplyEdits(&window->buffer, entry.edits); + + window->cursors.dealloc(); + window->cursors = entry.cursors; + + Allocator sys_allocator = GetSystemAllocator(); + For(entry.edits) Dealloc(sys_allocator, &it.string.data); + entry.edits.dealloc(); + + // Generate layout + Clear(&window->layout_arena); + window->layout = CalculateLayout(&window->layout_arena, window->buffer, window->font, window->font_size, window->font_spacing); +} + +void UndoEdit(Window *window) { + if (window->history.undo_stack.len <= 0) return; + + HistoryEntry entry = window->history.undo_stack.pop(); + + SaveHistoryBeforeMergeCursor(window, &window->history.redo_stack); + SaveHistoryBeforeApplyEdits(window, &window->history.redo_stack, entry.edits); _ApplyEdits(&window->buffer, entry.edits); window->cursors.dealloc(); @@ -312,55 +377,21 @@ void UndoEdit(Window *window) { void BeforeEdit(Window *window) { Assert(window->history.debug_edit_phase == 0); window->history.debug_edit_phase += 1; - - { - History &h = window->history; - HistoryEntry *entry = h.entries.alloc(); - Allocator sys_allocator = GetSystemAllocator(); - Assert(window->cursors.len); - entry->cursors = window->cursors.tight_copy(sys_allocator); + Assert(window->cursors.len); + SaveHistoryBeforeMergeCursor(window, &window->history.undo_stack); + For(window->history.redo_stack) { + it.cursors.dealloc(); + ForItem(edit, it.edits) Dealloc(it.edits.allocator, &edit.string.data); + it.edits.dealloc(); } - + window->history.redo_stack.dealloc(); MergeCursors(window); } void ApplyEdits(Window *window, Array edits) { Assert(window->history.debug_edit_phase == 1); window->history.debug_edit_phase += 1; - - { - HistoryEntry *entry = window->history.entries.last(); - Allocator sys_allocator = GetSystemAllocator(); - entry->edits = edits.tight_copy(sys_allocator); - - // Make reverse edits - For(entry->edits) { - Range new_range = {it.range.min, it.range.min + it.string.len}; - String string = GetString(window->buffer, it.range); - it.string = Copy(sys_allocator, string); - it.range = new_range; - } - - Array temp_edits = entry->edits.tight_copy(sys_allocator); - defer { temp_edits.dealloc(); }; - - // Fix reverse edits - ForItem(edit, edits) { - int64_t remove_size = GetRangeSize(edit.range); - int64_t insert_size = edit.string.len; - int64_t offset = insert_size - remove_size; - - for (int64_t i = 0; i < entry->edits.len; i += 1) { - Edit &new_edit = entry->edits.data[i]; - Edit &old_edit = temp_edits.data[i]; - if (old_edit.range.min > edit.range.min) { - new_edit.range.min += offset; - new_edit.range.max += offset; - } - } - } - } - + SaveHistoryBeforeApplyEdits(window, &window->history.undo_stack, edits); _ApplyEdits(&window->buffer, edits); } @@ -368,7 +399,7 @@ void AfterEdit(Window *window, Array edits) { Assert(window->history.debug_edit_phase == 2); window->history.debug_edit_phase -= 2; - HistoryEntry *entry = window->history.entries.last(); + HistoryEntry *entry = window->history.undo_stack.last(); Assert(entry->cursors.len); Assert(entry->edits.len); diff --git a/src/text_editor/main.cpp b/src/text_editor/main.cpp index f779026..f3ef322 100644 --- a/src/text_editor/main.cpp +++ b/src/text_editor/main.cpp @@ -316,8 +316,14 @@ int main() { AfterEdit(focused_window, edits); } - if (IsKeyDown(KEY_LEFT_CONTROL) && (IsKeyPressed(KEY_Z) || IsKeyPressedRepeat(KEY_Z))) { - UndoEdit(focused_window); + if ((IsKeyPressed(KEY_Z) || IsKeyPressedRepeat(KEY_Z))) { + if (IsKeyDown(KEY_LEFT_CONTROL)) { + if (IsKeyDown(KEY_LEFT_SHIFT)) { + RedoEdit(focused_window); + } else { + UndoEdit(focused_window); + } + } } if (IsKeyPressed(KEY_DELETE) || IsKeyPressedRepeat(KEY_DELETE)) {