From 46c109dce45aa955fb07ddc3ece276d0d91e3641 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Thu, 8 May 2025 22:42:04 +0200 Subject: [PATCH] Fix garbage collect bug, ReplaceWithoutMovingCarets takes buffer now, Reopen buffer happens automatically when not dirty --- build_file.cpp | 3 ++ data/init.lua | 6 +-- src/text_editor/buffer.cpp | 10 ++-- src/text_editor/buffer.h | 4 +- src/text_editor/commands.cpp | 76 +++++++++++++++++++-------- src/text_editor/generated.cpp | 6 +-- src/text_editor/lua_api.cpp | 15 ++---- src/text_editor/lua_api_generated.cpp | 2 +- src/text_editor/management.cpp | 59 +++++++++++---------- src/text_editor/process.cpp | 9 +++- src/text_editor/text_editor.cpp | 2 +- src/text_editor/text_editor.h | 5 +- src/text_editor/todo.txt | 26 ++++++--- 13 files changed, 133 insertions(+), 90 deletions(-) diff --git a/build_file.cpp b/build_file.cpp index cacd1ca..f4c0d1b 100644 --- a/build_file.cpp +++ b/build_file.cpp @@ -318,7 +318,10 @@ void GenerateConfig() { void GenerateLuaApi() { MA_Scratch scratch; S8_String file = OS_ReadFile(scratch, "../src/text_editor/lua_api.cpp"); + S8_String file2 = OS_ReadFile(scratch, "../src/text_editor/commands.cpp"); S8_List list = S8_Split(scratch, file, "\n"); + S8_List list2 = S8_Split(scratch, file2, "\n"); + list = S8_ConcatLists(scratch, list, list2); S8_List funcs = {}; for (S8_Node *it = list.first; it; it = it->next) { diff --git a/data/init.lua b/data/init.lua index ef4f3cc..1537f25 100644 --- a/data/init.lua +++ b/data/init.lua @@ -210,7 +210,7 @@ Rules = { MatchURL, } -function ApplyRules(s) +function OnOpen(s) for i = #Rules,1,-1 do rule = Rules[i] result = rule(s) @@ -221,10 +221,6 @@ function ApplyRules(s) return nil end -function CFiles() - Cmd({working_dir = GetProjectDir(), kind ="a", cmd = "dir /s/b | findstr .*\\.c"}) -end - Coroutines = {} function AddCo(f) local i = #Coroutines + 1 diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index 8d30e55..8e3de18 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -1070,12 +1070,12 @@ void AdjustCarets(Array edits, Array *carets) { Int offset = insert_size - remove_size; for (Int i = 0; i < carets->len; i += 1) { - Caret &old_cursor = carets->data[i]; - Caret &new_cursor = new_carets.data[i]; + Caret &oldc = carets->data[i]; + Caret &newc = new_carets.data[i]; - if (old_cursor.range.min > edit.range.min) { - new_cursor.range.min += offset; - new_cursor.range.max += offset; + if (oldc.range.min > edit.range.min) { + newc.range.min += offset; + newc.range.max += offset; } } } diff --git a/src/text_editor/buffer.h b/src/text_editor/buffer.h index df681d2..04ae69d 100644 --- a/src/text_editor/buffer.h +++ b/src/text_editor/buffer.h @@ -63,7 +63,9 @@ void AddEdit(Array *e, Range range, String16 string); // mouse_selection_anchor is special case for mouse handling ! void MergeCarets(Buffer *buffer, Array *carets); -// was part of: Command_ReplaceWithoutMovingCarets, ReplaceTitleBarData +// Adjusts caret copies after edit to make them not move after for example +// a bar modification. Sometimes works, sometimes doesn't, depends, not an all solving tool. +// For example in case of ReopenBuffer, when we select and replace entire buffer, it didn't quite work. void AdjustCarets(Array edits, Array *carets); void RedoEdit(Buffer *buffer, Array *carets); diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index 38ef0be..361cd46 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -16,8 +16,7 @@ void ToggleFullscreen() { } void CheckpointBeforeGoto(Window *window, View *view) { - Buffer *buffer = GetBuffer(view->active_buffer); - Add(&window->goto_history, {buffer->id, view->carets[0]}); + Add(&window->goto_history, {view->id, view->carets[0]}); window->goto_redo.len = 0; } @@ -27,9 +26,9 @@ void CheckpointBeforeGoto(Window *window) { GotoCrumb GetCrumb(Array *cr) { for (; cr->len;) { - GotoCrumb c = Pop(cr); - Buffer *buffer = GetBufferStrict(c.buffer_id); - if (buffer) return c; + GotoCrumb c = Pop(cr); + View *view = FindView(c.view_id); + if (view) return c; } return {}; } @@ -37,11 +36,11 @@ GotoCrumb GetCrumb(Array *cr) { void GotoBackward(Window *window) { BSet set = GetBSet(window); if (window->goto_history.len <= 0) return; - Add(&window->goto_redo, {set.buffer->id, set.view->carets[0]}); + Add(&window->goto_redo, {set.view->id, set.view->carets[0]}); - GotoCrumb c = GetCrumb(&window->goto_history); - Buffer *buffer = GetBuffer(c.buffer_id); - View *view = WindowOpenBufferView(window, buffer->name); + GotoCrumb c = GetCrumb(&window->goto_history); + window->active_view = c.view_id; + View *view = GetView(c.view_id); view->carets[0] = c.caret; UpdateScroll(window, true); } @@ -49,11 +48,11 @@ void GotoBackward(Window *window) { void GotoForward(Window *window) { BSet set = GetBSet(window); if (window->goto_redo.len <= 0) return; - Add(&window->goto_history, {set.buffer->id, set.view->carets[0]}); + Add(&window->goto_history, {set.view->id, set.view->carets[0]}); GotoCrumb c = GetCrumb(&window->goto_redo); - Buffer *buffer = GetBuffer(c.buffer_id); - View *view = WindowOpenBufferView(window, buffer->name); + window->active_view = c.view_id; + View *view = GetView(c.view_id); view->carets[0] = c.caret; UpdateScroll(window, true); } @@ -96,18 +95,28 @@ void MouseLoadWord(Event event, void (*cmd_function)(String16 string)) { } } -void Command_ReplaceWithoutMovingCarets(View *view, Range range, String16 string) { - Buffer *buffer = GetBuffer(view->active_buffer); - Array caret_copy = Copy(GetSystemAllocator(), view->carets); - defer { - Dealloc(&view->carets); - view->carets = caret_copy; - }; - +void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) { Scratch scratch; + View *view = NULL; + for (View *it = FirstView; it; it = it->next) { + if (it->active_buffer != buffer->id) { + continue; + } + view = it; + break; + } + + if (!view) { + view = CreateView(buffer->id); + } + + Array carets = Copy(GetSystemAllocator(), view->carets); + Command_SelectRangeOneCursor(view, range); Array edits = Command_ReplaceEx(scratch, view, string); - AdjustCarets(edits, &caret_copy); + + Dealloc(&view->carets); + view->carets = carets; } // @todo: revamp interface since it scrolls ALL VIEWS??? or maybe not?? @@ -589,7 +598,7 @@ void SaveBuffer(View *view) { Scratch scratch; String string = AllocCharString(scratch, buffer); Buffer *temp_buffer = ExecAndWait(scratch, "clang-format", GetDir(buffer), string); - Command_ReplaceWithoutMovingCarets(view, GetRange(buffer), {temp_buffer->str, temp_buffer->len}); + ReplaceWithoutMovingCarets(buffer, GetRange(buffer), {temp_buffer->str, temp_buffer->len}); } Scratch scratch; @@ -834,3 +843,26 @@ void Command_FuzzySort(View *view, String16 needle) { Command_Replace(view, GetString(temp_buffer)); Command_SelectRangeOneCursor(view, Rng(0)); } + +void ReopenBuffer(Buffer *buffer) { + Scratch scratch; + String string = ReadFile(scratch, buffer->name); + if (string.len == 0) { + return; + } + + String16 string16 = ToUnixString16(scratch, string); + ReplaceWithoutMovingCarets(buffer, GetRange(buffer), string16); + buffer->file_mod_time = GetFileModTime(buffer->name); + buffer->changed_on_disk = false; + buffer->dirty = false; +} +void Command_Reopen() { + BSet set = GetActiveMainSet(); + ReopenBuffer(set.buffer); + ActiveWindow = set.window->id; +} +int Lua_Reopen(lua_State *L) { + Command_Reopen(); + return 0; +} \ No newline at end of file diff --git a/src/text_editor/generated.cpp b/src/text_editor/generated.cpp index 1bf504b..5b338d9 100644 --- a/src/text_editor/generated.cpp +++ b/src/text_editor/generated.cpp @@ -282,7 +282,7 @@ Rules = { MatchURL, } -function ApplyRules(s) +function OnOpen(s) for i = #Rules,1,-1 do rule = Rules[i] result = rule(s) @@ -293,10 +293,6 @@ function ApplyRules(s) return nil end -function CFiles() - Cmd({working_dir = GetProjectDir(), kind ="a", cmd = "dir /s/b | findstr .*\\.c"}) -end - Coroutines = {} function AddCo(f) local i = #Coroutines + 1 diff --git a/src/text_editor/lua_api.cpp b/src/text_editor/lua_api.cpp index ce68ede..d782e3d 100644 --- a/src/text_editor/lua_api.cpp +++ b/src/text_editor/lua_api.cpp @@ -72,11 +72,11 @@ BSet Command_Exec(String cmd, String working_dir) { BSet Command_Open(String path) { Scratch scratch; - lua_getglobal(LuaState, "ApplyRules"); + lua_getglobal(LuaState, "OnOpen"); lua_pushlstring(LuaState, path.data, path.len); if (lua_pcall(LuaState, 1, 1, 0) != 0) { const char *error_message = lua_tostring(LuaState, -1); - ReportWarningf("Failed the call to ApplyRules! %s", error_message); + ReportWarningf("Failed the call to OnOpen! %s", error_message); lua_pop(LuaState, 1); return {}; } @@ -94,9 +94,9 @@ BSet Command_Open(String path) { if (IsDir(file_path)) { Command_JumpNew(&main); main.buffer->name = GetUniqueBufferName(file_path, "temp"); - Command_Appendf(main.view, "%.*s/..\n", FmtString(file_path)); + Command_Appendf(main.view, "..\n", FmtString(file_path)); for (FileIter it = IterateFiles(scratch, file_path); IsValid(it); Advance(&it)) { - Command_Appendf(main.view, "%.*s\n", FmtString(it.absolute_path)); + Command_Appendf(main.view, "%.*s\n", FmtString(it.filename)); } } else { CheckpointBeforeGoto(main.window); @@ -118,7 +118,7 @@ BSet Command_Open(String path) { String working_dir = FieldString(LuaState, "working_dir"); Exec(NullViewID, true, cmd, working_dir); } else { - ReportWarningf("Failed to match any of ApplyRules results!"); + ReportWarningf("Failed to match any of OnOpen results!"); } return main; @@ -287,11 +287,6 @@ int Lua_ListCommands(lua_State *L) { return 0; } -int Lua_Reopen(lua_State *L) { - ReopenBuffer(GetActiveMainSet()); - return 0; -} - int Lua_ToggleFullscreen(lua_State *L) { ToggleFullscreen(); return 0; diff --git a/src/text_editor/lua_api_generated.cpp b/src/text_editor/lua_api_generated.cpp index c66016b..8f876ff 100644 --- a/src/text_editor/lua_api_generated.cpp +++ b/src/text_editor/lua_api_generated.cpp @@ -10,7 +10,6 @@ luaL_Reg LuaFunctions[] = { {"Open", Lua_Open}, {"SetProjectFile", Lua_SetProjectFile}, {"ListCommands", Lua_ListCommands}, - {"Reopen", Lua_Reopen}, {"ToggleFullscreen", Lua_ToggleFullscreen}, {"ListBuffers", Lua_ListBuffers}, {"GetBufferList", Lua_GetBufferList}, @@ -27,5 +26,6 @@ luaL_Reg LuaFunctions[] = { {"GetMainDir", Lua_GetMainDir}, {"SplitSize", Lua_SplitSize}, {"Play", Lua_Play}, + {"Reopen", Lua_Reopen}, {NULL, NULL}, }; diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp index 6890b64..219750e 100644 --- a/src/text_editor/management.cpp +++ b/src/text_editor/management.cpp @@ -179,6 +179,15 @@ View *CreateView(BufferID active_buffer) { return view; } +View *FindView(ViewID view_id, View *default_view = NULL) { + for (View *it = FirstView; it; it = it->next) { + if (it->id == view_id) { + return it; + } + } + return default_view; +} + View *FindView(BufferID buffer_id, View *default_view = NULL) { for (View *it = FirstView; it; it = it->next) { if (it->active_buffer == buffer_id) { @@ -354,20 +363,6 @@ String16 ToUnixString16(Allocator allocator, String string_) { return string; } -void ReopenBuffer(BSet set) { - Scratch scratch; - String string = ReadFile(scratch, set.buffer->name); - if (string.len == 0) { - return; - } - - String16 string16 = ToUnixString16(scratch, string); - Command_ReplaceWithoutMovingCarets(set.view, GetRange(set.buffer), string16); - set.buffer->file_mod_time = GetFileModTime(set.buffer->name); - set.buffer->changed_on_disk = false; - ActiveWindow = set.window->id; -} - // This function as name suggests tries to open a buffer, // there is no name resolution here, path should already be resolved etc. // @@ -439,11 +434,23 @@ View *WindowOpenBufferView(Window *new_parent_window, String name) { return result; } +bool ViewIsCrumb(ViewID view_id) { + for (Window *window = FirstWindow; window; window = window->next) { + For(window->goto_history) if (it.view_id == view_id) return true; + For(window->goto_redo) if (it.view_id == view_id) return true; + } + return false; +} + bool ViewIsReferenced(ViewID view) { if (view == NullViewID) { return true; } + if (ViewIsCrumb(view)) { + return true; + } + for (Window *it = FirstWindow; it; it = it->next) { if (it->active_view == view || it->active_goto_list == view) { return true; @@ -452,25 +459,12 @@ bool ViewIsReferenced(ViewID view) { return false; } -bool BufferIsCrumb(BufferID buffer_id) { - for (Window *window = FirstWindow; window; window = window->next) { - For(window->goto_history) if (it.buffer_id == buffer_id) return true; - For(window->goto_redo) if (it.buffer_id == buffer_id) return true; - } - return false; -} - bool BufferIsReferenced(BufferID buffer_id) { if (buffer_id == NullBufferID) { return true; } - View *view = FindView(buffer_id); - if (view) { - return true; - } - - if (BufferIsCrumb(buffer_id)) { + if (FindView(buffer_id)) { return true; } @@ -484,6 +478,7 @@ void GarbageCollect() { int64_t new_file_mod_time = GetFileModTime(it->name); if (it->file_mod_time != new_file_mod_time) { it->changed_on_disk = true; + if (it->dirty == false) ReopenBuffer(it); } } } @@ -496,6 +491,10 @@ void GarbageCollect() { continue; } + // if (!ViewIsReferenced(it->id)) { + // int a = 10; + // } + bool ref = ViewIsReferenced(it->id); if (ref) { continue; @@ -513,6 +512,10 @@ void GarbageCollect() { continue; } + // if (!BufferIsReferenced(it->id)) { + // int a = 10; + // } + bool ref = BufferIsReferenced(it->id); if (ref) { continue; diff --git a/src/text_editor/process.cpp b/src/text_editor/process.cpp index 02436bc..88b275c 100644 --- a/src/text_editor/process.cpp +++ b/src/text_editor/process.cpp @@ -18,8 +18,13 @@ void UpdateProcesses() { String poll = PollStdout(scratch, &it); View *view = GetView({it.view_id}); - if (poll.len) Command_Append(view, poll, it.scroll_to_end); - if (!IsValid(&it)) remove_item = true; + if (poll.len) { + Command_Append(view, poll, it.scroll_to_end); + } + if (!IsValid(&it)) { + Command_Append(view, Format(scratch, "process exited with code: %d\n", it.exit_code), it.scroll_to_end); + remove_item = true; + } } } diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index a4e0735..0229f7f 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -16,6 +16,7 @@ #include "external/stb_truetype.c" #define MINICORO_IMPL #include "external/minicoro.h" +#include "lua.hpp" #include "backup_font.cpp" SDL_Window *SDLWindow; @@ -42,7 +43,6 @@ int FullScreenPositionX, FullScreenPositionY; #include "commands_bindings.cpp" #include "title_bar.cpp" -#include "lua.hpp" #include "lua_api.cpp" #include "lua_api_generated.cpp" #include "generated.cpp" diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index cfbbf0f..74ea13e 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -20,7 +20,7 @@ struct View { }; struct GotoCrumb { - BufferID buffer_id; + ViewID view_id; Caret caret; }; @@ -121,12 +121,12 @@ void Command_SelectRangeOneCursor(View *view, Range range); void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line); void Command_Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line); Array Command_ReplaceEx(Allocator scratch, View *view, String16 string); -void Command_ReplaceWithoutMovingCarets(View *view, Range range, String16 string); void Command_Eval(String string); void Command_Eval(String16 string); String Command_GetMainDir(); String Command_GetBaseDir(); +void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string); void Command_Copy(View *view); void Command_Paste(View *view); @@ -137,6 +137,7 @@ void Command_Appendf(View *view, const char *fmt, ...); Buffer *CreateBuffer(Allocator allocator, String name, Int size = 4096); View *CreateView(BufferID active_buffer); +void ReopenBuffer(Buffer *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; } diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index bb7f443..40456f3 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -2,14 +2,18 @@ - maybe we could allow user to change window titles which would make them special in some way. A:/text_editor/+test_buffer:1:1:ADE | - Scroll the console properly - commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top -- automatically generating lua bindings for simple commands - --------------- -buffer = make_buffer() -buffer.append(list_files("src/basic")) -activate_buffer --------------- +- organize commands and lua bindings somehow, it's kinda confusing right now, maybe group command->luacommand, the command name implies it also doubles as lua command? +- Add metadata to Lua bindings so that we would get a better listing (function args?, what else?) +- rules, interface for opening files using the F4 (aka next path from build output) + - for now add ./ and .\ to valid line starters +- make search bar standout!! +- relative paths instead of absolute when opening directories +- change console resize behaviour, maybe on tilde, not on click, it borks, selects wrongly because of the change in size +- Kill buffer command (it should be marked for deletion and deleted at the end of frame!) +- Delete directory/file on disk command +- Create directory command (probably should enter it automatically +- save all relevant buffers and build - shift down on last line should move the cursor to end of line!!! same for up - maybe most of the bindings should be in lua, but actual code in C - LoadWord, EncloseWord configurable? @@ -38,7 +42,7 @@ activate_buffer backlog - expose a coroutine based scripting enviorment where user can execute shell commands wait for them and perform actions in very linear manner - Test stdin writing code -- Implement shell interaction (last line should have a '$'' symbols, if you press enter it should send that line to stdin of a running shell) +- Implement shell interaction (the valid cmd lines should start with '>' or '$', user can add more lines like this to expand the command size maybe?, if we have a case where we have a line with '>' but the last line doesn't have (just a space) then it should execute?) - drop text into window - I think the way sublime text and we display line highlights is confusing with multiple cursors (line highlight can be confused with selection) - text_editor --record events.txt text_editor --playback events.txt @@ -51,3 +55,9 @@ backlog - redo tree - gap buffer - optimize rendering - command buffer, and vertice buffer instead of vertice buffer with scissor + +-------------- +buffer = make_buffer() +buffer.append(list_files("src/basic")) +activate_buffer +--------------