From ef6a7be285473afa311be47b51a46ebb348af459 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sun, 7 Dec 2025 13:57:51 +0100 Subject: [PATCH] Command bar, undo merge time --- data/init.lua | 3 +- src/basic/basic_os.cpp | 4 + src/text_editor/buffer.cpp | 14 ++++ src/text_editor/buffer.h | 2 + src/text_editor/commands.cpp | 2 +- src/text_editor/commands_bindings.cpp | 106 ++++++++++++++---------- src/text_editor/generated.cpp | 1 + src/text_editor/generated_config.cpp | 3 +- src/text_editor/generated_variables.cpp | 3 +- src/text_editor/lua_api.cpp | 25 +++++- src/text_editor/management.cpp | 8 +- src/text_editor/text_editor.cpp | 1 + src/text_editor/text_editor.h | 1 + src/text_editor/title_bar.cpp | 1 + src/text_editor/window.cpp | 66 ++++++++++----- 15 files changed, 161 insertions(+), 79 deletions(-) diff --git a/data/init.lua b/data/init.lua index 30a9262..cf09c89 100644 --- a/data/init.lua +++ b/data/init.lua @@ -68,6 +68,7 @@ Style.Font = GetExeDir().."/CascadiaMono.ttf" Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat" Style.TrimWhitespaceOnSave = true Style.ClangFormatOnSave = false +Style.StyleUndoMergeTimeout = 0.3 INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe' OS_WINDOWS = 0 @@ -332,7 +333,7 @@ function MatchExec(s, meta) end Eval(s) - return {kind = "skip"} + return nil end BuiltinOnOpenMatchers = { diff --git a/src/basic/basic_os.cpp b/src/basic/basic_os.cpp index 3d60dd6..7111bb6 100644 --- a/src/basic/basic_os.cpp +++ b/src/basic/basic_os.cpp @@ -1097,3 +1097,7 @@ API void CloseStdin(Process *process) { } #endif + +API double GetTimeSeconds() { + return GetTimeMicros() / 1000000.0; +} \ No newline at end of file diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index b958a39..7cd5155 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -917,6 +917,7 @@ API void AddEdit(Array *e, Range range, String16 string) { void SaveHistoryBeforeMergeCursor(Buffer *buffer, Array *stack, Array &carets) { if (buffer->no_history) return; HistoryEntry entry = {}; + entry.time = GetTimeSeconds(); entry.carets = TightCopy(GetSystemAllocator(), carets); Add(stack, entry); } @@ -992,8 +993,16 @@ API void UndoEdit(Buffer *buffer, Array *carets) { Allocator sys_allocator = GetSystemAllocator(); For(entry.edits) Dealloc(sys_allocator, it.string.data); Dealloc(&entry.edits); + + if (buffer->undo_stack.len > 0) { + HistoryEntry *next = GetLast(buffer->undo_stack); + if (entry.time - next->time <= 0.3) { + UndoEdit(buffer, carets); + } + } } + API void DeallocHistoryEntries(Array *entries) { For(*entries) { Dealloc(&it.carets); @@ -1003,6 +1012,11 @@ API void DeallocHistoryEntries(Array *entries) { entries->len = 0; } +API void ResetHistory(Buffer *buffer) { + DeallocHistoryEntries(&buffer->redo_stack); + DeallocHistoryEntries(&buffer->undo_stack); +} + void ClearRedoStack(Buffer *buffer) { DeallocHistoryEntries(&buffer->redo_stack); } diff --git a/src/text_editor/buffer.h b/src/text_editor/buffer.h index 5cc8a54..b0f4c2b 100644 --- a/src/text_editor/buffer.h +++ b/src/text_editor/buffer.h @@ -12,6 +12,7 @@ struct Edit { struct HistoryEntry { Array edits; Array carets; + double time; }; struct Buffer { @@ -156,6 +157,7 @@ API void AssertRanges(Array carets); API void RedoEdit(Buffer *buffer, Array *carets); API void UndoEdit(Buffer *buffer, Array *carets); +API void ResetHistory(Buffer *buffer); API void DeallocHistoryArray(Array *entries); API void DeallocHistoryEntries(Array *entries); \ No newline at end of file diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index 75f9cfd..3d053ed 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -1141,7 +1141,7 @@ int Lua_Cmd(lua_State *L) { } void Command_ListBuffers() { - BSet main = GetLastActiveLayoutSet(); + BSet main = GetActiveSet(); ActiveWindow = main.window->id; JumpGarbageBuffer(&main); For(Buffers) { diff --git a/src/text_editor/commands_bindings.cpp b/src/text_editor/commands_bindings.cpp index d329d76..348716a 100644 --- a/src/text_editor/commands_bindings.cpp +++ b/src/text_editor/commands_bindings.cpp @@ -46,6 +46,29 @@ void UpdateScroll(Window *window, bool update_caret_scrolling) { } } +void FuzzySearchOpen(BSet active) { + bool success = false; + Range range = active.view->carets[0].range; + if (GetSize(range) == 0) { + Int line = PosToLine(active.buffer, range.min); + if ((active.buffer->line_starts.len - 1) == line) { + line = ClampBottom(0ll, line - 1ll); + } + + String16 string = GetLineStringWithoutNL(active.buffer, line); + Int idx = 0; + if (Seek(string, u"||", &idx)) { + string = Skip(string, idx + 3); + Command_Open(string); + success = true; + } + } + + if (!success) { + Command_Open(FetchLoadWord()); + } +} + void OnCommand(Event event) { ProfileFunction(); // @@ -196,9 +219,7 @@ void OnCommand(Event event) { } } - if (Shift() && Ctrl() && Mouse(LEFT)) { - MouseLoadWord(event, "exec"); - } else if (Ctrl() && Mouse(LEFT)) { + if (Ctrl() && Mouse(LEFT)) { MouseLoadWord(event); } else if (Mouse(LEFT)) { // Uses Alt and shift Vec2I mouse = MouseVec2I(); @@ -270,23 +291,21 @@ void OnCommand(Event event) { main.window->kill = true; } - if (CtrlAltPress(SDLK_P)) { - Command_ListBuffers(); } else if (CtrlPress(SDLK_P)) { - Command_ListCode(); + // Command_ListCode(); + Window *window = GetWindow(CommandBarWindowID); + window->visible = !window->visible; + ActiveWindow = window->id; + BSet set = GetBSet(window); + Command_ListBuffers(); } if (CtrlPress(SDLK_0)) { - ToggleVisibility(DebugWindowID); + Window *window = GetWindow(DebugWindowID); + window->visible = !window->visible; } - if (CtrlPress(SDLK_GRAVE)) { - if (ActiveWindow != NullWindowID) { - ActiveWindow = NullWindowID; - } else { - } - } if (CtrlPress(SDLK_1)) { ActiveWindow = GetOverlappingWindow({0,0}, GetWindow(ActiveWindow))->id; } @@ -309,7 +328,7 @@ void OnCommand(Event event) { } BSet main = GetLastActiveLayoutSet(); - BSet active = GetActiveSet(); + BSet active = GetActiveSet(); Int buffer_change_id = active.buffer->change_id; bool skip = CallOnCommand(&event); @@ -320,8 +339,12 @@ void OnCommand(Event event) { return; } - - + if (active.view->fuzzy_search) { + if (Press(SDLK_RETURN)) { + FuzzySearchOpen(active); + return; + } + } if (event.kind == EVENT_DROP_FILE) { WindowOpenBufferView(active.window, event.text); @@ -465,7 +488,7 @@ void OnCommand(Event event) { if (event.kind == EVENT_TEXT_INPUT) { Scratch scratch; - String string = event.text; + String string = event.text; String16 string16 = ToString16(scratch, string); Command_Replace(active.view, string16); } @@ -510,7 +533,7 @@ void OnCommand(Event event) { String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1); if (active.view->prev_search_line != last_line_string) { active.view->prev_search_line = last_line_string; - Array ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string); + Array ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string); Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap); For(IterateInReverse(&ratings)) { @@ -522,6 +545,7 @@ void OnCommand(Event event) { RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string); Caret caret = active.view->carets[0]; + SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets); Command_SelectEntireBuffer(active.view); Command_Replace(active.view, GetString(temp_buffer)); active.view->carets[0] = caret; @@ -562,32 +586,9 @@ void OnCommand(Event event) { } - if (CtrlPress(SDLK_SEMICOLON) || CtrlShiftPress(SDLK_Q)) { - Command_Open(FetchLoadWord(), "exec"); - } - else if (CtrlPress(SDLK_Q)) { + if (CtrlPress(SDLK_Q)) { if (active.view->fuzzy_search) { - bool success = false; - Range range = active.view->carets[0].range; - if (GetSize(range) == 0) { - Int line = PosToLine(active.buffer, range.min); - if ((active.buffer->line_starts.len - 1) == line) { - line = ClampBottom(0ll, line - 1ll); - } - - String16 string = GetLineStringWithoutNL(active.buffer, line); - Int idx = 0; - if (Seek(string, u"||", &idx)) { - string = Skip(string, idx + 3); - Command_Open(string); - success = true; - } - } - - if (!success) { - Command_Open(FetchLoadWord()); - } - + FuzzySearchOpen(active); } else { Command_Open(FetchLoadWord()); } @@ -602,3 +603,22 @@ void OnCommand(Event event) { MergeCarets(active.buffer, &active.view->carets); IF_DEBUG(AssertRanges(active.view->carets)); } + +void PostCommandUpdate() { + For (Windows) { + if (it->sync_visibility_with_focus) { + if (it->id == ActiveWindow) { + it->visible = true; + } else { + it->visible = false; + } + } + } + + if (ActiveWindow.id != LastActiveLayoutWindowID.id) { + Window *window = GetWindow(ActiveWindow); + if (window->layout) { + LastActiveLayoutWindowID = ActiveWindow; + } + } +} \ No newline at end of file diff --git a/src/text_editor/generated.cpp b/src/text_editor/generated.cpp index 7e7f1b6..fe57599 100644 --- a/src/text_editor/generated.cpp +++ b/src/text_editor/generated.cpp @@ -29,4 +29,5 @@ void ReloadStyle() { StyleFontFilter = GetStyleInt("FontFilter", StyleFontFilter); StyleFont = GetStyleString("Font", StyleFont); StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall); + StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout); } \ No newline at end of file diff --git a/src/text_editor/generated_config.cpp b/src/text_editor/generated_config.cpp index 48eab6d..a71f437 100644 --- a/src/text_editor/generated_config.cpp +++ b/src/text_editor/generated_config.cpp @@ -69,6 +69,7 @@ Style.Font = GetExeDir().."/CascadiaMono.ttf" Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat" Style.TrimWhitespaceOnSave = true Style.ClangFormatOnSave = false +Style.StyleUndoMergeTimeout = 0.3 INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe' OS_WINDOWS = 0 @@ -333,7 +334,7 @@ function MatchExec(s, meta) end Eval(s) - return {kind = "skip"} + return nil end BuiltinOnOpenMatchers = { diff --git a/src/text_editor/generated_variables.cpp b/src/text_editor/generated_variables.cpp index 4b93640..768d060 100644 --- a/src/text_editor/generated_variables.cpp +++ b/src/text_editor/generated_variables.cpp @@ -64,4 +64,5 @@ Int StyleIndentSize = 4; Int StyleFontSize = 15; Int StyleFontFilter = 0; String StyleFont = "/home/krz/text_editor/package/CascadiaMono.ttf"; -String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"; \ No newline at end of file +String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"; +double StyleUndoMergeTimeout = 0.3; \ No newline at end of file diff --git a/src/text_editor/lua_api.cpp b/src/text_editor/lua_api.cpp index e8ebfaf..faca795 100644 --- a/src/text_editor/lua_api.cpp +++ b/src/text_editor/lua_api.cpp @@ -130,6 +130,22 @@ static void HookLuaForceExit(lua_State *L, lua_Debug *debug) { luaL_error(L, "lua execution got interrupted"); } +double GetStyleFloat(String name, double default_float) { + double result = default_float; + lua_getglobal(LuaState, "Style"); + defer { lua_pop(LuaState, 1); }; + if (lua_istable(LuaState, -1)) { + lua_pushlstring(LuaState, name.data, name.len); + lua_gettable(LuaState, -2); + defer { lua_pop(LuaState, 1); }; + if (lua_isnumber(LuaState, -1) || lua_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) { + lua_Number num = lua_tonumber(LuaState, -1); + result = (double)num; + } + } + return result; +} + Int GetStyleInt(String name, Int default_int) { Int result = default_int; lua_getglobal(LuaState, "Style"); @@ -194,23 +210,24 @@ String GetFieldString(lua_State *L, String name) { return result; } -Int GetInt(lua_State *L, const char *name) { +Int GetFieldInt(lua_State *L, const char *name) { lua_getfield(L, -1, name); lua_Integer num = lua_tointeger(L, -1); lua_pop(L, 1); return (Int)num; } -double GetFloat(lua_State *L, const char *name) { +double GetFieldFloat(lua_State *L, const char *name) { lua_getfield(L, -1, name); double num = lua_tonumber(L, -1); lua_pop(L, 1); return num; } -const char *GetString(lua_State *L, const char *name) { +const char *GetFieldString(lua_State *L, const char *name) { lua_getfield(L, -1, name); const char *result = lua_tostring(L, -1); + lua_pop(L, 1); return result; } @@ -239,7 +256,7 @@ int Lua_Play(lua_State *L) { defer { lua_pop(L, 1); }; Event event = {}; -#define X(TYPE, KIND, NAME) event.NAME = (TYPE)Get##KIND(L, #NAME); +#define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetField##KIND(L, #NAME); EVENT_FIELDS #undef X Add(&EventPlayback, event); diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp index 854c708..39be11d 100644 --- a/src/text_editor/management.cpp +++ b/src/text_editor/management.cpp @@ -15,6 +15,7 @@ WindowID DebugWindowID; ViewID DebugViewID; BufferID DebugBufferID; +WindowID CommandBarWindowID; WindowID StatusBarWindowID; WindowID SearchBarWindowID; ViewID SearchViewID; @@ -407,13 +408,6 @@ bool BufferIsReferenced(BufferID buffer_id) { void GarbageCollect() { Allocator sys_allocator = GetSystemAllocator(); - if (ActiveWindow.id != LastActiveLayoutWindowID.id) { - Window *window = GetWindow(ActiveWindow); - if (window->layout) { - LastActiveLayoutWindowID = ActiveWindow; - } - } - For(Buffers) { if (it->file_mod_time) { int64_t new_file_mod_time = GetFileModTime(it->name); diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index dc87eee..7babb97 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -246,6 +246,7 @@ void Update(Event event) { } OnCommand(event); + PostCommandUpdate(); UpdateProcesses(); CoUpdate(&event); ReloadLuaConfigs(); diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 70a27dd..5e9aa8c 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -40,6 +40,7 @@ struct Window { bool visible : 1; bool layout : 1; bool kill : 1; + bool sync_visibility_with_focus : 1; }; }; diff --git a/src/text_editor/title_bar.cpp b/src/text_editor/title_bar.cpp index 2d957ca..cf27f02 100644 --- a/src/text_editor/title_bar.cpp +++ b/src/text_editor/title_bar.cpp @@ -110,4 +110,5 @@ void StatusBarUpdate() { } Command_SelectRangeOneCursor(title.view, MakeRange(0)); + ResetHistory(title.buffer); } \ No newline at end of file diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index c0fec81..dc26a97 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -6,19 +6,7 @@ Array GetWindowZOrder(Allocator allocator) { return order; } -void SetVisibility(WindowID window_id, bool v) { - Window *window = GetWindow(window_id); - window->visible = v; -} - -bool ToggleVisibility(WindowID window_id) { - Window *window = GetWindow(window_id); - bool visible = !window->visible; - SetVisibility(window_id, visible); - return visible; -} - -Int GetTitleBarSize(Window *window) { +Int GetExpandingBarSize(Window *window) { View *view = GetView(window->active_view); Buffer *buffer = GetBuffer(view->active_buffer); float result = (float)buffer->line_starts.len * window->font->line_spacing; @@ -40,6 +28,23 @@ void InitWindows() { } } + // COMMAND BAR + { + Window *window = CreateWind(); + CommandBarWindowID = window->id; + Buffer *buffer = CreateBuffer(SysAllocator, "command_bar"); + View *view = CreateView(buffer->id); + window->active_view = view->id; + window->draw_line_numbers = false; + window->draw_scrollbar = false; + window->draw_darker = true; + window->draw_line_highlight = false; + window->layout = false; + window->visible = false; + window->sync_visibility_with_focus = true; + buffer->no_history = true; + } + // SEARCH BAR { Window *window = CreateWind(); @@ -64,7 +69,6 @@ void InitWindows() { Buffer *buffer = CreateBuffer(SysAllocator, "status_bar"); View *view = CreateView(buffer->id); window->active_view = view->id; - buffer->no_history = true; window->font = &SecondaryFont; window->draw_line_numbers = false; window->draw_scrollbar = false; @@ -91,7 +95,7 @@ void InitWindows() { DebugViewID = view->id; window->active_view = view->id; - SetVisibility(window->id, false); + window->visible = false; } } @@ -118,25 +122,45 @@ double WindowCalcEvenResizerValue(Int screen_size_x, Int *out_count = NULL) { void LayoutWindows(int16_t wx, int16_t wy) { Rect2I screen_rect = RectI0Size(wx, wy); + // Command bar + { + Window *n = GetWindow(CommandBarWindowID); + Rect2I *rect = &screen_rect; + Rect2I copy_rect = screen_rect; + if (!n->visible) { + rect = ©_rect; + } + Int barsize = Clamp((Int)n->font->line_spacing*10, (Int)0, (Int)wx - 100); + n->document_rect = n->total_rect = CutBottom(rect, barsize); + } + // bar at the bottom { Window *n = GetWindow(StatusBarWindowID); - Int barsize = GetTitleBarSize(n); - n->document_rect = n->total_rect = CutBottom(&screen_rect, barsize); + Rect2I *rect = &screen_rect; + Rect2I copy_rect = screen_rect; + if (!n->visible) { + rect = ©_rect; + } + Int barsize = GetExpandingBarSize(n); + n->document_rect = n->total_rect = CutBottom(rect, barsize); } // search bar { Window *n = GetWindow(SearchBarWindowID); - if (n->visible) { - Int barsize = GetTitleBarSize(n); - n->document_rect = n->total_rect = CutBottom(&screen_rect, barsize); + Rect2I *rect = &screen_rect; + Rect2I copy_rect = screen_rect; + if (!n->visible) { + rect = ©_rect; } + Int barsize = GetExpandingBarSize(n); + n->document_rect = n->total_rect = CutBottom(rect, barsize); } // floating debug window { - Window *n = GetWindow(DebugWindowID); + Window *n = GetWindow(DebugWindowID); Rect2 screen_rect = Rect0Size(wx, wy); Vec2 size = GetSize(screen_rect);