From 4c9c0e521037bf98673718a671131eff5087da79 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sat, 10 Jan 2026 10:28:12 +0100 Subject: [PATCH] Continuing the hook refactor, BeforeSaveBuffer --- src/text_editor/buffer.cpp | 22 ++++--- src/text_editor/commands.cpp | 8 ++- src/text_editor/text_editor.cpp | 1 + src/text_editor/text_editor.h | 106 ++++++++++++++++---------------- 4 files changed, 75 insertions(+), 62 deletions(-) diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index 47f4851..1ed89ef 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -1142,6 +1142,7 @@ API void InitBuffer(Allocator allocator, Buffer *buffer, BufferID id = {}, Strin API void DeinitBuffer(Buffer *buffer) { Allocator allocator = buffer->line_starts.allocator; Dealloc(allocator, buffer->data); + Dealloc(&buffer->hooks); Dealloc(&buffer->line_starts); DeallocHistoryArray(&buffer->undo_stack); DeallocHistoryArray(&buffer->redo_stack); @@ -1548,7 +1549,18 @@ void ReopenBuffer(Buffer *buffer) { buffer->dirty = false; } -void BasicSaveBuffer(Buffer *buffer) { +void SaveBuffer(Buffer *buffer) { + ProfileFunction(); + + For (GlobalHooks) { + if (it.kind == HookKind_BeforeBufferSave) { + ProfileScopeEx(it.name); + HookParam param = {}; + param.buffer = buffer; + it.function(param); + } + } + Scratch scratch; String string = AllocCharString(scratch, buffer); bool success = WriteFile(buffer->name, string); @@ -1561,11 +1573,3 @@ void BasicSaveBuffer(Buffer *buffer) { ReportWarningf("Failed to save file with name: %S", buffer->name); } } - -void SaveBuffer(Buffer *buffer) { - if (TrimTrailingWhitespace) { - TrimWhitespace(buffer); - } - - BasicSaveBuffer(buffer); -} diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index 1395172..fbbd7c7 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -291,6 +291,12 @@ void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret) { view->update_scroll = false; } +void HOOK_TrimTrailingWhitespace(HookParam param) { + if (TrimTrailingWhitespace) { + TrimWhitespace(param.buffer, false); + } +} RegisterHook(HOOK_TrimTrailingWhitespace, HookKind_BeforeBufferSave, "", "Cleans trailing whitespace before saving to file"); + void ConvertLineEndingsToLF(Buffer *buffer, bool trim_lines_with_caret = false) { Scratch scratch; @@ -486,7 +492,7 @@ void CMD_SaveAll(HookParam param) { For(Buffers) { // NOTE: file_mod_time is only set when buffer got read or written to disk already so should be saved if (it->file_mod_time && it->dirty) { - BasicSaveBuffer(it); + SaveBuffer(it); } } } RegisterCommand(CMD_SaveAll, "ctrl-shift-s"); diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index 940c121..00fb328 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -511,6 +511,7 @@ void GarbageCollect() { RawAppendf(GCInfoBuffer, "View %d %S\n", (int)it->id.id, buffer ? buffer->name : String{"NULL"}); remove_item = true; + Dealloc(&it->hooks); Dealloc(it); } diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index ae94877..90b8911 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -25,6 +25,59 @@ struct HistoryEntry { double time; }; +enum HookKind { + HookKind_Invalid, + + HookKind_AppInit, + HookKind_AppUpdate, + HookKind_AppQuit, + + // Should we have commands like PostCommand, PreCommand? what would be the purpose? + HookKind_Command, + + // Currently we are only basically allowing control over non-layouted windows. + // How can this be expanded? + // - Changing the layout algorithm: this seems like a decent one + // - What beside that? + HookKind_LayoutWindow, + HookKind_RenderWindow, + + HookKind_BeforeBufferSave, + // HookKind_BufferSave, + // HookKind_AfterBufferSave, + + // HookKind_ResolveOpen, + + // HookKind_BeforeBufferOpen, + // HookKind_BufferOpen, + // HookKind_AfterBufferOpen, + +}; + +// Global hooks, per (window, view, buffer) hooks + +struct HookParam { + union { + Buffer *buffer; + struct { + Window *window; + Rect2I *rect; + int16_t wx; + int16_t wy; + } layout; + }; +}; + +typedef void HookFunction(HookParam param); +struct Hook { + HookKind kind; + String name; + String docs; + HookFunction *function; + String binding; + struct Trigger *trigger; +}; + struct Buffer { BufferID id; String name; @@ -44,6 +97,7 @@ struct Buffer { Array undo_stack; Array redo_stack; int edit_phase; + Array hooks; struct { unsigned no_history : 1; unsigned no_line_starts : 1; @@ -57,58 +111,6 @@ struct Buffer { }; }; -enum HookKind { - HookKind_Invalid, - - HookKind_AppInit, - HookKind_AppUpdate, - HookKind_AppQuit, - - // Should we have commands like PostCommand, PreCommand? what would be the purpose? - HookKind_Command, - - - // Currently we are only basically allowing control over non-layouted windows. - // How can this be expanded? - // - Changing the layout algorithm: this seems like a decent one - // - What beside that? - HookKind_LayoutWindow, - HookKind_RenderWindow - - HookKind_BeforeBufferSave, - HookKind_BufferSave, - HookKind_AfterBufferSave, - - HookKind_BeforeBufferOpen, - HookKind_BufferOpen, - HookKind_AfterBufferOpen, - - HookKind_ViewUpdate, -}; - -// Global hooks, per (window, view, buffer) hooks - -struct HookParam { - union { - struct { - Window *window; - Rect2I *rect; - int16_t wx; - int16_t wy; - } layout; - }; -}; - -typedef void HookFunction(HookParam param); -struct Hook { - HookKind kind; - String name; - String docs; - HookFunction *function; - String binding; - struct Trigger *trigger; -}; - struct View { ViewID id; BufferID active_buffer;