From f125a38c50da50deb9eb9a6a14f793bac8649ef2 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Tue, 13 Aug 2024 16:02:22 +0200 Subject: [PATCH] Improve GC --- src/text_editor/buffer_history.cpp | 21 +++++-- src/text_editor/commands.cpp | 12 +++- src/text_editor/lua_api.cpp | 5 +- src/text_editor/lua_api_generated.cpp | 2 +- src/text_editor/management.cpp | 85 ++++++++++++++++++--------- src/text_editor/text_editor.h | 21 ++++++- src/text_editor/todo.txt | 5 ++ src/text_editor/window.cpp | 13 ---- 8 files changed, 110 insertions(+), 54 deletions(-) diff --git a/src/text_editor/buffer_history.cpp b/src/text_editor/buffer_history.cpp index 2872ee6..5822957 100644 --- a/src/text_editor/buffer_history.cpp +++ b/src/text_editor/buffer_history.cpp @@ -86,13 +86,22 @@ void IKnowWhatImDoing_ApplyEdits(Buffer *buffer, Array &edits) { IKnowWhatImDoing__ApplyEditsMultiCursor(buffer, edits); } -void ClearRedoStack(Buffer *buffer) { - ForItem(entry, buffer->redo_stack) { - Dealloc(&entry.carets); - ForItem(edit, entry.edits) Dealloc(entry.edits.allocator, &edit.string.data); - Dealloc(&entry.edits); +void DeallocHistoryEntries(Array *entries) { + For(*entries) { + Dealloc(&it.carets); + ForItem(edit, it.edits) Dealloc(it.edits.allocator, &edit.string.data); + Dealloc(&it.edits); } - buffer->redo_stack.len = 0; + entries->len = 0; +} + +void ClearRedoStack(Buffer *buffer) { + DeallocHistoryEntries(&buffer->redo_stack); +} + +void DeallocHistoryArray(Array *entries) { + DeallocHistoryEntries(entries); + Dealloc(entries); } // @note: !! diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index 3f2276d..01f00c9 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -162,8 +162,10 @@ void Command_ListBuffers() { String result = Merge(scratch, strings, "\n"); String16 string16 = ToString16(scratch, result); - String buffer_name = GetUniqueBufferName(scratch, GetDir(main.buffer), "+list_buffers-"); - View *new_view = WindowOpenBufferView(main.window, buffer_name); + String buffer_name = GetUniqueBufferName(scratch, GetDir(main.buffer), "+list_buffers-"); + View *new_view = WindowOpenBufferView(main.window, buffer_name); + Buffer *new_buffer = GetBuffer(new_view->active_buffer); + new_buffer->gc = true; Command_SelectEntireBuffer(new_view); Command_Replace(new_view, string16); @@ -236,6 +238,12 @@ void Command_Append(View *view, String string, bool scroll_to_end_if_cursor_on_l Command_Append(view, string16, scroll_to_end_if_cursor_on_last_line); } +void Command_Appendf(View *view, const char *fmt, ...) { + Scratch scratch; + STRING_FORMAT(scratch, fmt, string); + Command_Append(view, string, true); +} + void ReportErrorf(const char *fmt, ...) { Scratch scratch; STRING_FORMAT(scratch, fmt, string); diff --git a/src/text_editor/lua_api.cpp b/src/text_editor/lua_api.cpp index 902ba97..8151d33 100644 --- a/src/text_editor/lua_api.cpp +++ b/src/text_editor/lua_api.cpp @@ -23,8 +23,9 @@ void ExecInNewBuffer(String cmd, String working_dir) { View *view = WindowOpenBufferView(main.window, buffer_name); Buffer *buffer = GetBuffer(view->active_buffer); + buffer->gc = true; + Command_SelectRangeOneCursor(view, Rng(0)); - view->carets[0] = MakeCaret({}); Exec(view->id, false, cmd, working_dir); ActiveWindow = main.window->id; } @@ -92,7 +93,7 @@ int Lua_AppendCmd(lua_State *L) { return 0; } -int Lua_NewCmd(lua_State *L) { +int Lua_C(lua_State *L) { String string = lua_tostring(L, 1); lua_pop(L, 1); diff --git a/src/text_editor/lua_api_generated.cpp b/src/text_editor/lua_api_generated.cpp index b2ceff1..03d2521 100644 --- a/src/text_editor/lua_api_generated.cpp +++ b/src/text_editor/lua_api_generated.cpp @@ -1,7 +1,7 @@ luaL_Reg LuaFunctions[] = { {"FuzzySort", Lua_FuzzySort}, {"AppendCmd", Lua_AppendCmd}, - {"NewCmd", Lua_NewCmd}, + {"C", Lua_C}, {"Kill", Lua_Kill}, {"Open", Lua_Open}, {"Print", Lua_Print}, diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp index 8ef6e9c..d9d68ac 100644 --- a/src/text_editor/management.cpp +++ b/src/text_editor/management.cpp @@ -6,7 +6,6 @@ Array Buffers = {}; Array Views = {}; Array Windows = {}; -WindowID NullWindowID; BufferID NullBufferID; // +buffer ViewID NullViewID; @@ -20,12 +19,18 @@ WindowID ScrollbarSelected = {-1}; WindowID DocumentSelected = {-1}; Range DocumentRangeAnchor; -inline bool operator==(WindowID a, WindowID b) { return a.id == b.id; } -inline bool operator==(BufferID a, BufferID b) { return a.id == b.id; } -inline bool operator==(ViewID a, ViewID b) { return a.id == b.id; } -inline bool operator!=(WindowID a, WindowID b) { return a.id != b.id; } -inline bool operator!=(BufferID a, BufferID b) { return a.id != b.id; } -inline bool operator!=(ViewID a, ViewID b) { return a.id != b.id; } +View *GCInfoView; +Buffer *GCInfoBuffer; + +void InitScratchBuffer() { + Allocator sys_allocator = GetSystemAllocator(); + Buffer *null_buffer = CreateBuffer(sys_allocator, BuffCWD("+console")); + View *null_view = CreateView(null_buffer->id); + Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID); + + GCInfoBuffer = CreateBuffer(sys_allocator, BuffCWD("+gc")); + GCInfoView = CreateView(GCInfoBuffer->id); +} inline bool IsDocumentSelectionValid() { if (DocumentSelected.id == -1) return false; @@ -73,7 +78,13 @@ inline View *GetView(ViewID id) { inline bool IsNull(Buffer *buffer) { return buffer->id.id == NullBufferID.id; } inline Window *GetActiveWindow() { return GetWindow(ActiveWindow); } -// inline View *GetActiveView(Window *window) { return GetView(window->active_view); } + +String BuffCWD(String string) { + Scratch scratch; + String result = Format(scratch, "%.*s/%.*s", FmtString(WorkingDir), FmtString(string)); + result = Intern(&GlobalInternTable, result); + return result; +} void InitBuffer(Allocator allocator, Buffer *buffer, String name, Int size = 4096) { buffer->id = AllocBufferID(buffer); @@ -86,7 +97,7 @@ void InitBuffer(Allocator allocator, Buffer *buffer, String name, Int size = 409 Add(&buffer->line_starts, (Int)0); } -Buffer *CreateBuffer(Allocator allocator, String name, Int size = 4096) { +Buffer *CreateBuffer(Allocator allocator, String name, Int size) { Buffer *result = AllocType(allocator, Buffer); InitBuffer(allocator, result, name, size); Add(&Buffers, result->id); @@ -336,48 +347,68 @@ View *WindowOpenBufferView(Window *new_parent_window, String name) { return result; } -bool ViewIsReferenced(ViewID view) { +Window *ViewIsReferenced(ViewID view) { For(Windows) { Window *window = it.o; - if (window->active_view == view) return true; - if (window->active_goto_list == view) return true; + if (window->active_view == view) return window; + if (window->active_goto_list == view) return window; } - return false; + return NULL; } -bool BufferIsReferenced(BufferID buffer_id) { - if (buffer_id == NullBufferID) return true; - if (buffer_id == DebugBufferID) return true; - if (buffer_id == LuaBufferID) return true; +View *BufferIsReferenced(BufferID buffer_id) { For(Views) { View *view = it.o; - if (view->active_buffer == buffer_id) return true; + if (view->active_buffer == buffer_id) return view; } - return false; + return NULL; +} + +Window *BufferIsCrumb(BufferID buffer_id) { + For(Windows) { + Window *window = it.o; + For(window->goto_history) if (it.buffer_id == buffer_id) return window; + For(window->goto_redo) if (it.buffer_id == buffer_id) return window; + } + return NULL; } void GarbageCollect() { IterRemove(Views) { IterRemovePrepare(Views); - View *view = it.o; - if (!ViewIsReferenced(view->id)) { + View *view = it.o; + Buffer *buffer = GetBuffer(view->active_buffer); + bool gc = buffer->gc || buffer->is_directory; + + Window *ref = ViewIsReferenced(view->id); + if (gc && !ref) { Dealloc(&view->carets); - // @todo: add view to free list remove_item = true; + // @todo: add view to free list + + Command_Appendf(GCInfoView, "view %.*s", FmtString(buffer->name)); } } IterRemove(Buffers) { IterRemovePrepare(Buffers); Buffer *buffer = it.o; - if (!BufferIsReferenced(buffer->id)) { + bool gc = buffer->gc; + if (buffer->is_directory) { + Window *ref = BufferIsCrumb(buffer->id); + if (!ref) gc = true; + } + + View *ref = BufferIsReferenced(buffer->id); + if (gc && !ref) { Dealloc(&buffer->line_starts); - Dealloc(&buffer->undo_stack); - Dealloc(&buffer->redo_stack); + DeallocHistoryArray(&buffer->undo_stack); + DeallocHistoryArray(&buffer->redo_stack); Dealloc(buffer->line_starts.allocator, &buffer->data); - // @todo: add buffer to free list remove_item = true; - ReportConsolef("collected = %.*s", FmtString(buffer->name)); + // @todo: add buffer to free list + + Command_Appendf(GCInfoView, "buffer %.*s", FmtString(buffer->name)); } } } \ No newline at end of file diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 9f34006..e4f21de 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -37,9 +37,12 @@ struct Buffer { Array undo_stack; Array redo_stack; int edit_phase; - bool no_history; - bool dirty; - bool is_directory; + struct { + int no_history : 1; + int dirty : 1; + int is_directory : 1; + int gc : 1; + }; }; struct View { @@ -139,6 +142,18 @@ void Command_ReplaceWithoutMovingCarets(View *view, Range range, String16 void ReportConsolef(const char *fmt, ...); void ReportErrorf(const char *fmt, ...); void ReportWarningf(const char *fmt, ...); +void Command_Appendf(View *view, const char *fmt, ...); + +String BuffCWD(String string); +Buffer *CreateBuffer(Allocator allocator, String name, Int size = 4096); +View *CreateView(BufferID active_buffer); + +inline bool operator==(WindowID a, WindowID b) { return a.id == b.id; } +inline bool operator==(BufferID a, BufferID b) { return a.id == b.id; } +inline bool operator==(ViewID a, ViewID b) { return a.id == b.id; } +inline bool operator!=(WindowID a, WindowID b) { return a.id != b.id; } +inline bool operator!=(BufferID a, BufferID b) { return a.id != b.id; } +inline bool operator!=(ViewID a, ViewID b) { return a.id != b.id; } #if DEBUG_BUILD #define IF_DEBUG(x) x diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index c88354e..cb98d0f 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -11,6 +11,10 @@ - Find matches using grep, change things in that buffer then apply those changes to all items - group history entries so the you can rollback through multiple ones at once and not waste time on skipping whitespace trimming or deleting every character +- Check if file exists in ApplyRules otherwise return null +- Different buffers should be GCed differently +- Special buffers that store metadata + - OnWindowCommand allow config user to overwrite the WindowCommand keybinding, introduce his own - some split selection commands @@ -20,6 +24,7 @@ - word complete - Search all buffers in 10X style, incrementally searched results popping up on every key press (maybe we need coroutine library in C so this is easier?) +- To implement that I think it would be best to load all files into memory - Search and replace - kill view - killing all views for buffer ejects buffer (maybe also introduce kill buffer) diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index f60695b..374c7f1 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -120,19 +120,6 @@ bool ToggleVisibility(WindowID window_id) { return visible; } -String BuffCWD(String string) { - Scratch scratch; - String result = Format(scratch, "%.*s/%.*s", FmtString(WorkingDir), FmtString(string)); - result = Intern(&GlobalInternTable, result); - return result; -} - -void InitScratchBuffer() { - Allocator sys_allocator = GetSystemAllocator(); - Buffer *null_buffer = CreateBuffer(sys_allocator, BuffCWD("+console")); - View *null_view = CreateView(null_buffer->id); -} - void InitWindows() { Allocator sys_allocator = Perm; #if !ARRAY_DEBUG