Redo working

This commit is contained in:
Krzosa Karol
2024-07-01 07:41:44 +02:00
parent d1f83fa669
commit 1a420e2f22
2 changed files with 86 additions and 49 deletions

View File

@@ -20,7 +20,8 @@ struct HistoryEntry {
}; };
struct History { struct History {
Array<HistoryEntry> entries; Array<HistoryEntry> undo_stack;
Array<HistoryEntry> redo_stack;
int debug_edit_phase; int debug_edit_phase;
}; };
@@ -287,14 +288,78 @@ void MergeCursors(Window *window) {
new_cursors.add(it); new_cursors.add(it);
} }
} }
Assert(new_cursors.len <= window->cursors.len);
window->cursors.dealloc(); window->cursors.dealloc();
window->cursors = new_cursors; window->cursors = new_cursors;
} }
void UndoEdit(Window *window) { void SaveHistoryBeforeMergeCursor(Window *window, Array<HistoryEntry> *stack) {
if (window->history.entries.len <= 0) return; 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<HistoryEntry> *stack, Array<Edit> 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<Edit> 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); _ApplyEdits(&window->buffer, entry.edits);
window->cursors.dealloc(); window->cursors.dealloc();
@@ -312,55 +377,21 @@ void UndoEdit(Window *window) {
void BeforeEdit(Window *window) { void BeforeEdit(Window *window) {
Assert(window->history.debug_edit_phase == 0); Assert(window->history.debug_edit_phase == 0);
window->history.debug_edit_phase += 1; window->history.debug_edit_phase += 1;
Assert(window->cursors.len);
{ SaveHistoryBeforeMergeCursor(window, &window->history.undo_stack);
History &h = window->history; For(window->history.redo_stack) {
HistoryEntry *entry = h.entries.alloc(); it.cursors.dealloc();
Allocator sys_allocator = GetSystemAllocator(); ForItem(edit, it.edits) Dealloc(it.edits.allocator, &edit.string.data);
Assert(window->cursors.len); it.edits.dealloc();
entry->cursors = window->cursors.tight_copy(sys_allocator);
} }
window->history.redo_stack.dealloc();
MergeCursors(window); MergeCursors(window);
} }
void ApplyEdits(Window *window, Array<Edit> edits) { void ApplyEdits(Window *window, Array<Edit> edits) {
Assert(window->history.debug_edit_phase == 1); Assert(window->history.debug_edit_phase == 1);
window->history.debug_edit_phase += 1; window->history.debug_edit_phase += 1;
SaveHistoryBeforeApplyEdits(window, &window->history.undo_stack, edits);
{
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<Edit> 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;
}
}
}
}
_ApplyEdits(&window->buffer, edits); _ApplyEdits(&window->buffer, edits);
} }
@@ -368,7 +399,7 @@ void AfterEdit(Window *window, Array<Edit> edits) {
Assert(window->history.debug_edit_phase == 2); Assert(window->history.debug_edit_phase == 2);
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->cursors.len);
Assert(entry->edits.len); Assert(entry->edits.len);

View File

@@ -316,8 +316,14 @@ int main() {
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
if (IsKeyDown(KEY_LEFT_CONTROL) && (IsKeyPressed(KEY_Z) || IsKeyPressedRepeat(KEY_Z))) { if ((IsKeyPressed(KEY_Z) || IsKeyPressedRepeat(KEY_Z))) {
UndoEdit(focused_window); if (IsKeyDown(KEY_LEFT_CONTROL)) {
if (IsKeyDown(KEY_LEFT_SHIFT)) {
RedoEdit(focused_window);
} else {
UndoEdit(focused_window);
}
}
} }
if (IsKeyPressed(KEY_DELETE) || IsKeyPressedRepeat(KEY_DELETE)) { if (IsKeyPressed(KEY_DELETE) || IsKeyPressedRepeat(KEY_DELETE)) {