From 4221aa8fb712cbd28149e45b1f1118ef78ed6a31 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Fri, 26 Dec 2025 15:40:03 +0100 Subject: [PATCH] Finite size jump history, improving backtrace, redo, undo grouping, similar for jump history --- src/backup/todo.txt | 2 -- src/basic/basic_os.cpp | 20 ++++++++++++------ src/text_editor/buffer.cpp | 21 +++++++++++++------ src/text_editor/commands.cpp | 2 +- src/text_editor/globals.cpp | 4 +++- src/text_editor/scratch.cpp | 34 +++++++++++++++++++++++++++++++ src/text_editor/text_editor.cpp | 11 ++++++++++ src/text_editor/text_editor.h | 3 --- src/text_editor/window.cpp | 8 ++++---- src/text_editor/window_debug.cpp | 1 + src/text_editor/window_search.cpp | 1 + 11 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 src/text_editor/scratch.cpp diff --git a/src/backup/todo.txt b/src/backup/todo.txt index 7929f0d..d43baa4 100644 --- a/src/backup/todo.txt +++ b/src/backup/todo.txt @@ -2,8 +2,6 @@ - From a user (novice) point of view, how does it look like? - Open with seek string (open at pattern) filename:32 filename:/^Window$/ -- ctrl+f should insert selected text into search -- Do we need constrained jump history????? So that we can finally collect garbage buffers at some point. Or maybe only constrained to garbage buffers - build console window - Show what process/coroutines are running and allow to kill (active process buffer?) - Database idea: use special buffers to store information diff --git a/src/basic/basic_os.cpp b/src/basic/basic_os.cpp index 69b504d..36ecee0 100644 --- a/src/basic/basic_os.cpp +++ b/src/basic/basic_os.cpp @@ -1,3 +1,5 @@ +typedef void OSErrorReport(const char *, ...); + #if OS_POSIX #include #include @@ -54,13 +56,19 @@ void RegisterCrashHandler(void) { struct sigaction sa; sa.sa_sigaction = CrashHandler; sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART | SA_SIGINFO; + sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_RESETHAND; // Important flags! - sigaction(SIGSEGV, &sa, NULL); - sigaction(SIGABRT, &sa, NULL); - sigaction(SIGBUS, &sa, NULL); - sigaction(SIGILL, &sa, NULL); - sigaction(SIGFPE, &sa, NULL); + + sigaction(SIGSEGV, &sa, NULL); // Segmentation fault + sigaction(SIGABRT, &sa, NULL); // Abort + sigaction(SIGBUS, &sa, NULL); // Bus error + sigaction(SIGILL, &sa, NULL); // Illegal instruction + sigaction(SIGFPE, &sa, NULL); // Floating point exception + sigaction(SIGTRAP, &sa, NULL); // Breakpoint/trap + sigaction(SIGSYS, &sa, NULL); // Bad system call + sigaction(SIGXCPU, &sa, NULL); // CPU time limit exceeded + sigaction(SIGXFSZ, &sa, NULL); // File size limit exceeded + sigaction(SIGTERM, &sa, NULL); // Termination request (optional) } API void InitOS(void (*error_proc)(const char *, ...)) { diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index 39219d7..0215718 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -878,12 +878,13 @@ API void AddEdit(Array *e, Range range, String16 string) { // multicursor + history /////////////////////////////// -void SaveHistoryBeforeMergeCursor(Buffer *buffer, Array *stack, Array &carets) { - if (buffer->no_history) return; +HistoryEntry *SaveHistoryBeforeMergeCursor(Buffer *buffer, Array *stack, Array &carets) { + if (buffer->no_history) return NULL; HistoryEntry entry = {}; entry.time = GetTimeSeconds(); entry.carets = TightCopy(GetSystemAllocator(), carets); Add(stack, entry); + return GetLast(*stack); } void SaveHistoryBeforeApplyEdits(Buffer *buffer, Array *stack, Array &edits) { @@ -928,7 +929,8 @@ API void RedoEdit(Buffer *buffer, Array *carets) { HistoryEntry entry = Pop(&buffer->redo_stack); - SaveHistoryBeforeMergeCursor(buffer, &buffer->undo_stack, *carets); + HistoryEntry *e = SaveHistoryBeforeMergeCursor(buffer, &buffer->undo_stack, *carets); + e->time = entry.time; SaveHistoryBeforeApplyEdits(buffer, &buffer->undo_stack, entry.edits); ApplyEditsMultiCursor(buffer, entry.edits); @@ -938,6 +940,13 @@ API void RedoEdit(Buffer *buffer, Array *carets) { Allocator sys_allocator = GetSystemAllocator(); For(entry.edits) Dealloc(sys_allocator, it.string.data); Dealloc(&entry.edits); + + if (buffer->redo_stack.len > 0) { + HistoryEntry *next = GetLast(buffer->redo_stack); + if (next->time - entry.time <= ConfigUndoMergeTimeWindow) { + RedoEdit(buffer, carets); + } + } } API void UndoEdit(Buffer *buffer, Array *carets) { @@ -946,8 +955,8 @@ API void UndoEdit(Buffer *buffer, Array *carets) { if (buffer->undo_stack.len <= 0) return; HistoryEntry entry = Pop(&buffer->undo_stack); - - SaveHistoryBeforeMergeCursor(buffer, &buffer->redo_stack, *carets); + HistoryEntry *e = SaveHistoryBeforeMergeCursor(buffer, &buffer->redo_stack, *carets); + e->time = entry.time; SaveHistoryBeforeApplyEdits(buffer, &buffer->redo_stack, entry.edits); ApplyEditsMultiCursor(buffer, entry.edits); @@ -960,7 +969,7 @@ API void UndoEdit(Buffer *buffer, Array *carets) { if (buffer->undo_stack.len > 0) { HistoryEntry *next = GetLast(buffer->undo_stack); - if (entry.time - next->time <= ConfigUndoMergeTimeout) { + if (entry.time - next->time <= ConfigUndoMergeTimeWindow) { UndoEdit(buffer, carets); } } diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index d76bcd2..357e29f 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -851,7 +851,7 @@ void Command_GotoBackward() { void Command_GotoForward() { BSet main = GetBSet(LastActiveLayoutWindowID); GotoForward(main.window); -} RegisterCommand(Command_GotoForward, "mousex2"); +} RegisterCommand(Command_GotoForward, "alt-shift-q | mousex2"); void Command_OpenUpFolder() { BSet main = GetBSet(LastActiveLayoutWindowID); diff --git a/src/text_editor/globals.cpp b/src/text_editor/globals.cpp index 970dadc..1e75932 100644 --- a/src/text_editor/globals.cpp +++ b/src/text_editor/globals.cpp @@ -157,5 +157,7 @@ RegisterVariable(Int, ConfigFontSize, 15); RegisterVariable(Int, ConfigFontFilter, 0); RegisterVariable(String, ConfigFont, "/home/krz/text_editor/package/CascadiaMono.ttf"); RegisterVariable(String, ConfigVCVarsall, "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"); -RegisterVariable(Float, ConfigUndoMergeTimeout, 0.3); +RegisterVariable(Float, ConfigUndoMergeTimeWindow, 0.3); +RegisterVariable(Float, ConfigJumpHistoryMergeTimeWindow, 0.3); +RegisterVariable(Int, ConfigJumpHistorySize, 512); RegisterVariable(String, ConfigInternetBrowser, "firefox"); diff --git a/src/text_editor/scratch.cpp b/src/text_editor/scratch.cpp new file mode 100644 index 0000000..a2333e6 --- /dev/null +++ b/src/text_editor/scratch.cpp @@ -0,0 +1,34 @@ + + +void RunRingBufferTest() { + // Scratch scratch; + // RingBuffer buff = {}; + // Init(scratch, &buff, 4); + + // for (int i = 0; i < 4; i += 1) { + // Add(&buff, i); + // } + // for (int i = 0; i < 4; i += 1) { + // Assert(buff.data[i] == i); + // } + + // Add(&buff, 4); + // Assert(buff.data[0] == 4); + // Add(&buff, 5); + // Assert(buff.data[1] == 5); + // Assert(buff.data[2] == 2); + + // Assert(Pop(&buff) == 5); + // Assert(Pop(&buff) == 4); + // Assert(Pop(&buff) == 3); + // Assert(Pop(&buff) == 2); + // Assert(Pop(&buff) == 0); + // Assert(Pop(&buff) == 0); + // Assert(Pop(&buff) == 0); + // Assert(Pop(&buff) == 0); + // Assert(Pop(&buff) == 0); + + // // Assert(Pop(&buff) == 2); + + +} RegisterFunction(&TestFunctions, RunRingBufferTest); \ No newline at end of file diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index aca9486..ca3a2d9 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -39,6 +39,7 @@ #include "commands.cpp" #include "commands_clipboard.cpp" +#include "scratch.cpp" #include "draw.cpp" #include "test/tests.cpp" @@ -540,6 +541,15 @@ void Update(Event event) { LastActiveLayoutWindowID = ActiveWindowID; } } + + For (Windows) { + if (it->goto_history.len > ConfigJumpHistorySize) { + RemoveByIndex(&it->goto_history, 0); + } + if (it->goto_redo.len > ConfigJumpHistorySize) { + RemoveByIndex(&it->goto_redo, 0); + } + } } @@ -641,6 +651,7 @@ extern char **environ; int main(int argc, char **argv) #endif { + InitOS((OSErrorReport *)printf); #if _WIN32 int argc = __argc; char **argv = __argv; diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index db458e0..294d9dc 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -147,9 +147,6 @@ struct Register_Function { struct Register_Command { Register_Command(Array *fucs, Function *function, String name, String binding) { if (StartsWith(name, "Command_")) name = Skip(name, 8); Add(fucs, {name, binding, function}); } }; #define RegisterCommand(name, binding) Register_Command RC__##name(&CommandFunctions, name, #name, binding) -struct Register_Hook { Register_Hook(Array *functions, PFunction *function, String name) { if (StartsWith(name, "Hook_")) name = Skip(name, 5); Add(functions, {name, function}); } }; -#define RegisterHook(functions, name) Register_Hook RC__##name(functions, (PFunction *)name, #name) - const int DIR_RIGHT = 0; const int DIR_LEFT = 1; const int DIR_DOWN = 2; diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index e895866..08520d8 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -249,7 +249,7 @@ void CheckpointBeforeGoto(Window *window) { GotoCrumb GetCrumb(Array *cr) { for (; cr->len;) { GotoCrumb c = Pop(cr); - View *view = GetView(c.view_id); + View *view = FindView(c.view_id, NULL); if (view) { return c; } @@ -271,15 +271,15 @@ void GotoBackward(Window *window) { if (window->goto_history.len) { GotoCrumb *next = GetLast(window->goto_history); - if (c.time - next->time <= ConfigUndoMergeTimeout) { + if (c.view_id == next->view_id && c.time - next->time <= ConfigJumpHistoryMergeTimeWindow) { GotoBackward(window); } } } void GotoForward(Window *window) { - if (window->goto_redo.len <= 0) return; if (window->jump_history == false) return; + if (window->goto_redo.len <= 0) return; BSet set = GetBSet(window); Add(&window->goto_history, {set.view->id, set.view->carets[0], GetTimeSeconds()}); @@ -291,7 +291,7 @@ void GotoForward(Window *window) { if (window->goto_redo.len) { GotoCrumb *next = GetLast(window->goto_redo); - if (c.time - next->time <= ConfigUndoMergeTimeout) { + if (c.view_id == next->view_id && next->time - c.time <= ConfigJumpHistoryMergeTimeWindow) { GotoForward(window); } } diff --git a/src/text_editor/window_debug.cpp b/src/text_editor/window_debug.cpp index 26f6e9d..c841e32 100644 --- a/src/text_editor/window_debug.cpp +++ b/src/text_editor/window_debug.cpp @@ -6,6 +6,7 @@ void DebugWindowInit() { window->visible = false; window->z = 2; window->layout = false; + window->jump_history = false; Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug")); DebugBufferID = buffer->id; diff --git a/src/text_editor/window_search.cpp b/src/text_editor/window_search.cpp index e56c89b..ecad3a4 100644 --- a/src/text_editor/window_search.cpp +++ b/src/text_editor/window_search.cpp @@ -15,6 +15,7 @@ void SearchWindowInit() { window->layout = false; window->visible = false; window->lose_visibility_on_escape = true; + window->jump_history = false; } void SearchWindowLayout(Rect2I *rect, Int wx, Int wy) {