Trying to add undo

This commit is contained in:
Krzosa Karol
2024-06-29 12:15:39 +02:00
parent c8ad9222fd
commit ceecb6cc81
4 changed files with 116 additions and 30 deletions

View File

@@ -225,7 +225,7 @@ void MergeSort(int64_t Count, Edit *First, Edit *Temp) {
} }
} }
void ApplyEdits(Buffer *buffer, Array<Edit> edits) { void _ApplyEdits(Buffer *buffer, Array<Edit> edits) {
Scratch scratch((Arena *)buffer->allocator.object); Scratch scratch((Arena *)buffer->allocator.object);
Assert(buffer->data[0]); Assert(buffer->data[0]);
Assert(buffer->allocator.proc); Assert(buffer->allocator.proc);

View File

@@ -101,7 +101,7 @@ void EventRecording_SimulateGetCharPressed(Window *focused_window) {
For(focused_window->cursors) { For(focused_window->cursors) {
AddEdit(&edits, it.range, string); AddEdit(&edits, it.range, string);
} }
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
} }

View File

@@ -14,6 +14,16 @@ struct Layout {
Vec2 buffer_world_pixel_size; Vec2 buffer_world_pixel_size;
}; };
struct HistoryEntry {
Array<Cursor> cursors;
Array<Edit> edits;
};
struct History {
Array<HistoryEntry> entries;
int debug_edit_phase;
};
struct Window { struct Window {
Font font; Font font;
float font_size; float font_size;
@@ -25,6 +35,7 @@ struct Window {
Cursor main_cursor_begin_frame; Cursor main_cursor_begin_frame;
Array<Cursor> cursors; Array<Cursor> cursors;
Buffer buffer; Buffer buffer;
History history;
Arena layout_arena; Arena layout_arena;
Layout layout; Layout layout;
@@ -246,7 +257,7 @@ Array<LayoutColumn> CalculateVisibleColumns(Arena *arena, Window &window) {
return r; return r;
} }
void BeforeEdit(Window *window) { void MergeCursors(Window *window) {
Scratch scratch; Scratch scratch;
// Merge cursors that overlap, this needs to be handled before any edits to // Merge cursors that overlap, this needs to be handled before any edits to
// make sure overlapping edits won't happen. // make sure overlapping edits won't happen.
@@ -280,7 +291,67 @@ void BeforeEdit(Window *window) {
window->cursors = new_cursors; window->cursors = new_cursors;
} }
void UndoEdit(Window *window) {
if (window->history.entries.len <= 0) return;
HistoryEntry entry = window->history.entries.pop();
_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 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);
}
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);
For(entry->edits) {
// Need to compile reverse 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;
}
}
_ApplyEdits(&window->buffer, edits);
}
void AfterEdit(Window *window, Array<Edit> edits) { 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();
Assert(entry->cursors.len);
Assert(entry->edits.len);
// Offset all cursors by edits // Offset all cursors by edits
ForItem(edit, edits) { ForItem(edit, edits) {
int64_t remove_size = GetRangeSize(edit.range); int64_t remove_size = GetRangeSize(edit.range);
@@ -308,6 +379,7 @@ void AfterEdit(Window *window, Array<Edit> edits) {
// Make sure all cursors are in range // Make sure all cursors are in range
For(window->cursors) it.range = Clamp(window->buffer, it.range); For(window->cursors) it.range = Clamp(window->buffer, it.range);
// Generate layout
Clear(&window->layout_arena); Clear(&window->layout_arena);
window->layout = CalculateLayout(&window->layout_arena, window->buffer, window->font, window->font_size, window->font_spacing); window->layout = CalculateLayout(&window->layout_arena, window->buffer, window->font, window->font_size, window->font_spacing);
} }

View File

@@ -63,27 +63,26 @@ int main() {
window.font_size = font_size; window.font_size = font_size;
window.font_spacing; window.font_spacing;
InitArena(&window.layout_arena); InitArena(&window.layout_arena);
InitBuffer(GetSystemAllocator(), &window.buffer); InitBuffer(GetSystemAllocator(), &window.buffer);
if (1) {
// Array<Edit> edits = {FrameArena};
// AddEdit(&edits, GetEnd(window.buffer), Format(FrameArena, "line number: 1"));
// ApplyEdits(&window.buffer, edits);
for (int i = 0; i < 50; i += 1) {
Array<Edit> edits = {FrameArena};
AddEdit(&edits, GetEnd(window.buffer), Format(FrameArena, "line number: %d\n", i));
ApplyEdits(&window.buffer, edits);
}
}
window.cursors.allocator = GetSystemAllocator(); window.cursors.allocator = GetSystemAllocator();
window.cursors.add({}); window.cursors.add({});
AfterEdit(&window, {});
if (1) {
for (int i = 0; i < 50; i += 1) {
BeforeEdit(&window);
Array<Edit> edits = {FrameArena};
AddEdit(&edits, GetEnd(window.buffer), Format(FrameArena, "line number: %d\n", i));
ApplyEdits(&window, edits);
AfterEdit(&window, edits);
}
}
*window.cursors.last() = {};
windows.add(window); windows.add(window);
} }
// EnableEventWaiting(); int64_t frame = -1;
InitEventRecording(); InitEventRecording();
while (!WindowShouldClose()) { while (!WindowShouldClose()) {
For(windows) { For(windows) {
@@ -91,6 +90,9 @@ int main() {
it.main_cursor_begin_frame = it.cursors[0]; it.main_cursor_begin_frame = it.cursors[0];
} }
frame += 1;
Dbg("%lld", (long long)frame);
UpdateEventRecording(); UpdateEventRecording();
{ {
@@ -100,7 +102,7 @@ int main() {
focused_window->scroll.y -= mouse_wheel; focused_window->scroll.y -= mouse_wheel;
focused_window->scroll.y = ClampBottom(focused_window->scroll.y, 0.f); focused_window->scroll.y = ClampBottom(focused_window->scroll.y, 0.f);
BeforeEdit(focused_window); // Merge cursors MergeCursors(focused_window);
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_A)) { if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_A)) {
focused_window->cursors.clear(); focused_window->cursors.clear();
focused_window->cursors.add(MakeCursor(0, focused_window->buffer.len)); focused_window->cursors.add(MakeCursor(0, focused_window->buffer.len));
@@ -167,7 +169,7 @@ int main() {
cursors_to_add.add({front, front}); cursors_to_add.add({front, front});
} }
For(cursors_to_add) focused_window->cursors.add(it); For(cursors_to_add) focused_window->cursors.add(it);
BeforeEdit(focused_window); // Merge cursors MergeCursors(focused_window);
} else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_LEFT_ALT)) { // Default in VSCode seems to be Shift + Alt + down } else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_LEFT_ALT)) { // Default in VSCode seems to be Shift + Alt + down
BeforeEdit(focused_window); BeforeEdit(focused_window);
Array<Edit> edits = {FrameArena}; Array<Edit> edits = {FrameArena};
@@ -177,7 +179,7 @@ int main() {
String string = GetString(focused_window->buffer, line.range); String string = GetString(focused_window->buffer, line.range);
AddEdit(&edits, {line.range.max, line.range.max}, string); AddEdit(&edits, {line.range.max, line.range.max}, string);
} }
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
For(focused_window->cursors) { For(focused_window->cursors) {
it.range.max = it.range.min = MoveDown(focused_window->buffer, it.range.min); it.range.max = it.range.min = MoveDown(focused_window->buffer, it.range.min);
@@ -204,7 +206,7 @@ int main() {
cursors_to_add.add({front, front}); cursors_to_add.add({front, front});
} }
For(cursors_to_add) focused_window->cursors.add(it); For(cursors_to_add) focused_window->cursors.add(it);
BeforeEdit(focused_window); // Merge cursors MergeCursors(focused_window);
} else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_LEFT_ALT)) { // Default in VSCode seems to be Shift + Alt + up } else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_LEFT_ALT)) { // Default in VSCode seems to be Shift + Alt + up
BeforeEdit(focused_window); BeforeEdit(focused_window);
Array<Edit> edits = {FrameArena}; Array<Edit> edits = {FrameArena};
@@ -214,7 +216,7 @@ int main() {
String string = GetString(focused_window->buffer, line.range); String string = GetString(focused_window->buffer, line.range);
AddEdit(&edits, {line.range.min, line.range.min}, string); AddEdit(&edits, {line.range.min, line.range.min}, string);
} }
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
For(focused_window->cursors) { For(focused_window->cursors) {
it.range.max = it.range.min = MoveUp(focused_window->buffer, it.range.min); it.range.max = it.range.min = MoveUp(focused_window->buffer, it.range.min);
@@ -240,7 +242,7 @@ int main() {
if (Seek(to_seek, needle, &found_index, SeekFlag_IgnoreCase)) { if (Seek(to_seek, needle, &found_index, SeekFlag_IgnoreCase)) {
found_index += cursor.range.max; found_index += cursor.range.max;
focused_window->cursors.add(MakeCursor(found_index + needle.len, found_index)); focused_window->cursors.add(MakeCursor(found_index + needle.len, found_index));
BeforeEdit(focused_window); // Merge cursors MergeCursors(focused_window);
} }
} }
@@ -288,7 +290,7 @@ int main() {
For(focused_window->cursors) { For(focused_window->cursors) {
AddEdit(&edits, it.range, string); AddEdit(&edits, it.range, string);
} }
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
if (IsKeyDown(KEY_LEFT_CONTROL) && (IsKeyPressed(KEY_X) || IsKeyPressedRepeat(KEY_X))) { if (IsKeyDown(KEY_LEFT_CONTROL) && (IsKeyPressed(KEY_X) || IsKeyPressedRepeat(KEY_X))) {
@@ -310,10 +312,14 @@ int main() {
} }
String to_save = Merge(FrameArena, strings, "\n"); String to_save = Merge(FrameArena, strings, "\n");
SetClipboardText(to_save.data); SetClipboardText(to_save.data);
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
if (IsKeyDown(KEY_LEFT_CONTROL) && (IsKeyPressed(KEY_Z) || IsKeyPressedRepeat(KEY_Z))) {
UndoEdit(focused_window);
}
if (IsKeyPressed(KEY_DELETE) || IsKeyPressedRepeat(KEY_DELETE)) { if (IsKeyPressed(KEY_DELETE) || IsKeyPressedRepeat(KEY_DELETE)) {
// Select things to delete // Select things to delete
For(focused_window->cursors) { For(focused_window->cursors) {
@@ -334,7 +340,7 @@ int main() {
Array<Edit> edits = {FrameArena}; Array<Edit> edits = {FrameArena};
String string = {}; String string = {};
For(focused_window->cursors) AddEdit(&edits, it.range, string); For(focused_window->cursors) AddEdit(&edits, it.range, string);
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
@@ -358,7 +364,7 @@ int main() {
Array<Edit> edits = {FrameArena}; Array<Edit> edits = {FrameArena};
String string = {}; String string = {};
For(focused_window->cursors) AddEdit(&edits, it.range, string); For(focused_window->cursors) AddEdit(&edits, it.range, string);
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
@@ -366,7 +372,7 @@ int main() {
BeforeEdit(focused_window); BeforeEdit(focused_window);
Array<Edit> edits = {FrameArena}; Array<Edit> edits = {FrameArena};
For(focused_window->cursors) AddEdit(&edits, it.range, " "); For(focused_window->cursors) AddEdit(&edits, it.range, " ");
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
@@ -382,7 +388,7 @@ int main() {
BeforeEdit(focused_window); BeforeEdit(focused_window);
Array<Edit> edits = {FrameArena}; Array<Edit> edits = {FrameArena};
For(focused_window->cursors) AddEdit(&edits, it.range, "\n"); For(focused_window->cursors) AddEdit(&edits, it.range, "\n");
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
@@ -402,7 +408,7 @@ int main() {
For(focused_window->cursors) { For(focused_window->cursors) {
AddEdit(&edits, it.range, string); AddEdit(&edits, it.range, string);
} }
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(focused_window, edits);
AfterEdit(focused_window, edits); AfterEdit(focused_window, edits);
} }
EventRecording_SimulateGetCharPressed(focused_window); EventRecording_SimulateGetCharPressed(focused_window);
@@ -457,7 +463,7 @@ int main() {
window.cursors.clear(); window.cursors.clear();
} }
window.cursors.add({col->pos, col->pos}); window.cursors.add({col->pos, col->pos});
BeforeEdit(&window); // Merge cursors MergeCursors(&window);
window.mouse_selecting = true; window.mouse_selecting = true;
} }
@@ -572,6 +578,14 @@ int main() {
Dbg_Draw(); Dbg_Draw();
EventRecording_Draw(); EventRecording_Draw();
Window *focused_window = &windows[0];
if (focused_window->mouse_selecting || EventPlaying) {
DisableEventWaiting();
} else {
EnableEventWaiting();
}
EndDrawing(); EndDrawing();
} }
} }