Redo working
This commit is contained in:
@@ -20,7 +20,8 @@ struct HistoryEntry {
|
||||
};
|
||||
|
||||
struct History {
|
||||
Array<HistoryEntry> entries;
|
||||
Array<HistoryEntry> undo_stack;
|
||||
Array<HistoryEntry> 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<HistoryEntry> *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<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);
|
||||
|
||||
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<Edit> 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<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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SaveHistoryBeforeApplyEdits(window, &window->history.undo_stack, edits);
|
||||
_ApplyEdits(&window->buffer, edits);
|
||||
}
|
||||
|
||||
@@ -368,7 +399,7 @@ void AfterEdit(Window *window, Array<Edit> 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);
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user