Trying to add undo
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user