From 93c1ba606ae2a19303860dedfafa12e6552d0c6c Mon Sep 17 00:00:00 2001 From: krzosa Date: Fri, 2 May 2025 22:20:09 +0200 Subject: [PATCH] Console update --- src/text_editor/commands.cpp | 52 ++++++++---- src/text_editor/commands_bindings.cpp | 110 ++++++++++++++------------ src/text_editor/lua_api.cpp | 69 ++++++++-------- src/text_editor/management.cpp | 23 ++++-- src/text_editor/text_editor.cpp | 15 ++-- src/text_editor/text_editor.h | 2 +- src/text_editor/todo.txt | 4 + src/text_editor/window.cpp | 53 +++++++++++-- 8 files changed, 207 insertions(+), 121 deletions(-) diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index f021e95..75b33cb 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -90,7 +90,7 @@ void Command_ListBuffers() { String result = Merge(scratch, strings, "\n"); String16 string16 = ToString16(scratch, result); - String buffer_name = GetUniqueBufferName(GetDir(main.buffer), "+list_buffers-"); + String buffer_name = GetUniqueBufferName(GetDir(main.buffer), "buffer_list"); View *new_view = WindowOpenBufferView(main.window, buffer_name); Buffer *new_buffer = GetBuffer(new_view->active_buffer); new_buffer->gc = true; @@ -133,29 +133,49 @@ void Command_ReplaceWithoutMovingCarets(View *view, Range range, String16 string AdjustCarets(edits, &caret_copy); } +// @todo: revamp interface since it scrolls ALL VIEWS??? or maybe not?? void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line) { + Scratch scratch; Buffer *buffer = GetBuffer(view->active_buffer); - bool scroll_to_end = false; - if (scroll_to_end_if_cursor_on_last_line) { - Int line = PosToLine(buffer, GetFront(view->carets[0])); - if (line == buffer->line_starts.len - 1) scroll_to_end = true; - } - - Array caret_copy = {}; - if (!scroll_to_end) caret_copy = Copy(GetSystemAllocator(), view->carets); - defer { - if (!scroll_to_end) { - Dealloc(&view->carets); - view->carets = caret_copy; - } + struct ViewInfo { + View *view; + Array carets; + bool scroll_to_end; }; + Array view_info = {scratch}; + For (Views) { + View *it_view = GetView(it); + if (it_view->active_buffer != buffer->id) { + continue; + } + + ViewInfo vi = {it_view}; + if (scroll_to_end_if_cursor_on_last_line) { + Int line = PosToLine(buffer, GetFront(it_view->carets[0])); + if (line == buffer->line_starts.len - 1) { + vi.scroll_to_end = true; + } + } + + if (!vi.scroll_to_end) { + vi.carets = Copy(GetSystemAllocator(), it_view->carets); + } + + Add(&view_info, vi); + } + Command_SelectRangeOneCursor(view, GetEndAsRange(buffer)); Command_Replace(view, string); - if (scroll_to_end) { - view->carets[0] = MakeCaret(GetEndAsRange(buffer).min); + For (view_info) { + if (it.scroll_to_end) { + it.view->carets[0] = MakeCaret(GetEndAsRange(buffer).min); + } else { + Dealloc(&it.view->carets); + it.view->carets = it.carets; + } } } diff --git a/src/text_editor/commands_bindings.cpp b/src/text_editor/commands_bindings.cpp index 6920d92..86fe894 100644 --- a/src/text_editor/commands_bindings.cpp +++ b/src/text_editor/commands_bindings.cpp @@ -47,17 +47,64 @@ void Command_GetCFiles(void) { BSet main = GetActiveMainSet(); Scratch scratch; - String buffer_name = GetUniqueBufferName(GetDir(main.buffer), "+ls-"); + String buffer_name = GetUniqueBufferName(GetDir(main.buffer), "getcfiles"); Buffer *buffer = CreateBuffer(GetSystemAllocator(), buffer_name, 4096 * 4); ListFilesRecursive(buffer, Command_GetDir()); WindowOpenBufferView(main.window, buffer_name); } +void UpdateScroll(Window *window, bool update_caret_scrolling) { + ProfileFunction(); + BSet set = GetBSet(window); + + // Scrolling with caret + if (update_caret_scrolling) { + Caret c = set.view->carets[0]; + Int front = GetFront(c); + XY xy = PosToXY(set.buffer, front); + + Rect2I visible = GetVisibleCells(window); + Vec2I visible_cells = GetSize(visible); + Vec2I visible_size = visible_cells * Vec2I{FontCharSpacing, FontLineSpacing}; + Vec2I rect_size = GetSize(window->document_rect); + + if (xy.line >= visible.max.y - 2) { + Int set_view_at_line = xy.line - (visible_cells.y - 1); + Int cut_off_y = Max((Int)0, visible_size.y - rect_size.y); + set.view->scroll.y = (set_view_at_line * FontLineSpacing) + cut_off_y; + } + + if (xy.line < visible.min.y + 1) { + set.view->scroll.y = xy.line * FontLineSpacing; + } + + if (xy.col >= visible.max.x - 1) { + Int set_view_at_line = xy.col - (visible_cells.x - 1); + Int cut_off_x = Max((Int)0, visible_size.x - rect_size.x); + set.view->scroll.x = (set_view_at_line * FontCharSpacing) + cut_off_x; + } + + if (xy.col <= visible.min.x) { + set.view->scroll.x = xy.col * FontCharSpacing; + } + } + + // Clip scroll + { + Int last_line = LastLine(set.buffer); + set.view->scroll.y = Clamp(set.view->scroll.y, (Int)0, Max((Int)0, (last_line - 1) * FontLineSpacing)); + + // @note: + // GetCharCountOfLongestLine is a bottleneck, there is probably an algorithm for + // calculating this value incrementally but do we even need X scrollbar or x clipping? + set.view->scroll.x = ClampBottom(set.view->scroll.x, (Int)0); + } +} + +static bool update_scroll_memes; void OnCommand(Event event) { ProfileFunction(); - WindowID start_command_active_window = ActiveWindow; - // // Window cursor setting // @@ -288,6 +335,12 @@ void OnCommand(Event event) { } } + if (CtrlPress(SDLK_GRAVE)) { + if (ActiveWindow != NullWindowID) { + ActiveWindow = NullWindowID; + // GetView(NullViewID); + } + } if (CtrlPress(SDLK_P)) { Command_ListBuffers(); } @@ -330,6 +383,9 @@ void OnCommand(Event event) { void CallOnCommand(Event * event); CallOnCommand(&event); + + + if (event.kind == EVENT_DROP_FILE) { WindowOpenBufferView(active.window, event.text); } @@ -562,51 +618,3 @@ void OnCommand(Event event) { MergeCarets(active.buffer, &active.view->carets); IF_DEBUG(AssertRanges(active.view->carets)); } - -void UpdateScroll(Window *window, bool update_caret_scrolling) { - ProfileFunction(); - BSet set = GetBSet(window); - - // Scrolling with caret - if (update_caret_scrolling) { - Caret c = set.view->carets[0]; - Int front = GetFront(c); - XY xy = PosToXY(set.buffer, front); - - Rect2I visible = GetVisibleCells(window); - Vec2I visible_cells = GetSize(visible); - Vec2I visible_size = visible_cells * Vec2I{FontCharSpacing, FontLineSpacing}; - Vec2I rect_size = GetSize(window->document_rect); - - if (xy.line >= visible.max.y - 2) { - Int set_view_at_line = xy.line - (visible_cells.y - 1); - Int cut_off_y = Max((Int)0, visible_size.y - rect_size.y); - set.view->scroll.y = (set_view_at_line * FontLineSpacing) + cut_off_y; - } - - if (xy.line < visible.min.y + 1) { - set.view->scroll.y = xy.line * FontLineSpacing; - } - - if (xy.col >= visible.max.x - 1) { - Int set_view_at_line = xy.col - (visible_cells.x - 1); - Int cut_off_x = Max((Int)0, visible_size.x - rect_size.x); - set.view->scroll.x = (set_view_at_line * FontCharSpacing) + cut_off_x; - } - - if (xy.col <= visible.min.x) { - set.view->scroll.x = xy.col * FontCharSpacing; - } - } - - // Clip scroll - { - Int last_line = LastLine(set.buffer); - set.view->scroll.y = Clamp(set.view->scroll.y, (Int)0, Max((Int)0, (last_line - 1) * FontLineSpacing)); - - // @note: - // GetCharCountOfLongestLine is a bottleneck, there is probably an algorithm for - // calculating this value incrementally but do we even need X scrollbar or x clipping? - set.view->scroll.x = ClampBottom(set.view->scroll.x, (Int)0); - } -} \ No newline at end of file diff --git a/src/text_editor/lua_api.cpp b/src/text_editor/lua_api.cpp index 34cb34a..781889c 100644 --- a/src/text_editor/lua_api.cpp +++ b/src/text_editor/lua_api.cpp @@ -18,7 +18,7 @@ void Command_ExecInNewBuffer(BSet set, String cmd, String working_dir) { CheckpointBeforeGoto(set.window); Scratch scratch; - String buffer_name = GetUniqueBufferName(working_dir, "+cmd-"); + String buffer_name = GetUniqueBufferName(working_dir, "shell_command"); View *view = WindowOpenBufferView(set.window, buffer_name); Buffer *buffer = GetBuffer(view->active_buffer); @@ -38,28 +38,28 @@ View *Command_ExecHidden(String buffer_name, String cmd, String working_dir) { return view; } -BSet Command_BeginConsoleJump() { - BSet main = GetActiveMainSet(); - CheckpointBeforeGoto(main.window); - main.buffer = GetBuffer(NullBufferID); - main.view = WindowOpenBufferView(main.window, main.buffer->name); - return main; +void Command_BeginConsoleJump(BSet *set) { + CheckpointBeforeGoto(set->window); + set->buffer = GetBuffer(NullBufferID); + set->view = WindowOpenBufferView(set->window, set->buffer->name); } -void Command_EndConsoleJump(BSet main) { - Int pos = XYToPos(main.buffer, {0, main.buffer->line_starts.len - 1}); - main.view->carets[0] = MakeCaret(pos); - UpdateScroll(main.window, true); - ActiveWindow = main.window->id; +void Command_EndConsoleJump(BSet set) { + Int pos = XYToPos(set.buffer, {0, set.buffer->line_starts.len - 1}); + set.view->carets[0] = MakeCaret(pos); + UpdateScroll(set.window, true); } -void Command_Exec(String cmd, String working_dir) { - BSet set = Command_BeginConsoleJump(); +BSet Command_Exec(String cmd, String working_dir) { + BSet set = GetActiveMainSet(); + Command_BeginConsoleJump(&set); Exec(set.view->id, true, cmd, working_dir); Command_EndConsoleJump(set); + ActiveWindow = set.window->id; + return set; } -void Command_Open(String path) { +BSet Command_Open(String path) { Scratch scratch; lua_getglobal(LuaState, "ApplyRules"); @@ -68,7 +68,7 @@ void Command_Open(String path) { const char *error_message = lua_tostring(LuaState, -1); ReportWarningf("Failed the call to ApplyRules! %s", error_message); lua_pop(LuaState, 1); - return; + return {}; } BSet main = GetActiveMainSet(); @@ -81,12 +81,13 @@ void Command_Open(String path) { Int col = strtoll(col_string.data, NULL, 10); if (IsDir(file_path)) { - BSet set = Command_BeginConsoleJump(); - Command_Appendf(set.view, "%.*s..\n", FmtString(file_path)); + Command_BeginConsoleJump(&main); + Command_Appendf(main.view, "%.*s/..\n", FmtString(file_path)); for (FileIter it = IterateFiles(scratch, file_path); IsValid(it); Advance(&it)) { - Command_Appendf(set.view, "%.*s\n", FmtString(it.absolute_path)); + Command_Appendf(main.view, "%.*s\n", FmtString(it.absolute_path)); } - Command_EndConsoleJump(set); + Command_EndConsoleJump(main); + ActiveWindow = main.window->id; } else { CheckpointBeforeGoto(main.window); View *view = WindowOpenBufferView(main.window, file_path); @@ -110,6 +111,8 @@ void Command_Open(String path) { } else { ReportWarningf("Failed to match any of ApplyRules results!"); } + + return main; } void Command_Open(String16 path) { @@ -174,19 +177,19 @@ int Lua_Cmd(lua_State *L) { String destination = lua_tostring(L, -1); lua_pop(L, 1); - BSet active = GetActiveMainSet(); BSet set = {}; - if (destination == "next") { - Window *next_window = GetNextLayoutWindow(active.window); - set = GetBSet(next_window); - } else if (destination == "3") { - Window *next_window = GetLayoutWindow(2); - if (!next_window) next_window = active.window; - set = GetBSet(next_window); + if (destination == "console") { + set = GetConsoleSet(); } else { - set = active; + set = GetActiveMainSet(); + } + + Command_BeginConsoleJump(&set); + Exec(set.view->id, true, cmd, working_dir); + Command_EndConsoleJump(set); + if (destination != "console") { + ActiveWindow = set.window->id; } - Command_ExecInNewBuffer(set, cmd, working_dir); return 0; } @@ -245,9 +248,8 @@ int Lua_Open(lua_State *L) { } int Lua_SetProjectFile(lua_State *L) { - String name = luaL_checkstring(L, 1); - lua_pop(L, 1); - LuaProjectBuffer = BufferOpenFile(name); + BSet set = GetActiveMainSet(); + LuaProjectBuffer = set.buffer; LuaProjectBuffer->user_change_id = -1; return 0; } @@ -272,7 +274,6 @@ int Lua_GetBufferList(lua_State *L) { int i = 1; For(Buffers) { - if (StartsWith(it.o->name, "+titlebar")) continue; lua_pushinteger(L, i++); lua_pushlstring(L, it.o->name.data, it.o->name.len); lua_settable(L, -3); /* 3rd element from the stack top */ diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp index db1bf22..2c3cac0 100644 --- a/src/text_editor/management.cpp +++ b/src/text_editor/management.cpp @@ -8,11 +8,15 @@ Array Windows; BufferID NullBufferID; // +buffer ViewID NullViewID; +WindowID NullWindowID; +Int NullWindowSize = 5; WindowID DebugWindowID; // +debug BufferID DebugBufferID; WindowID ActiveWindow; +WindowID ActiveWindowCounterID; +Int ActiveWindowCounter; WindowID ScrollbarSelected = {-1}; WindowID DocumentSelected = {-1}; @@ -22,6 +26,7 @@ Buffer *LuaProjectBuffer; Buffer *LuaConfigBuffer; Buffer *GCInfoBuffer; Buffer *EventBuffer; +Buffer *ScratchBuffer; RandomSeed UniqueBufferNameSeed = {}; String GetUniqueBufferName(String working_dir, String prepend_name) { @@ -44,7 +49,9 @@ void InitScratchBuffer() { GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "gc")); EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "events")); + ScratchBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "scratch")); EventBuffer->no_history = true; + GCInfoBuffer->no_history = true; } inline bool IsDocumentSelectionValid() { @@ -231,6 +238,14 @@ BSet GetActiveMainSet() { return GetBSet(window); } +BSet GetConsoleSet() { + BSet result = {}; + result.window = GetWindow(NullWindowID); + result.view = GetView(NullViewID); + result.buffer = GetBuffer(NullBufferID); + return result; +} + BSet GetActiveTitleSet() { Window *window = GetWindow(ActiveWindow); if (!window->is_title_bar) window = GetWindow(window->title_bar_window); @@ -338,13 +353,7 @@ Buffer *BufferOpenFile(String path) { if (!FileExists(path)) { buffer = CreateBuffer(sys_allocator, path); } else if (IsDir(path)) { - String buffer_name = GetUniqueBufferName(path, "+dir-"); - buffer = CreateBuffer(sys_allocator, buffer_name, 4096 * 2); - - RawAppendf(buffer, "..\n"); - for (FileIter it = IterateFiles(scratch, path); IsValid(it); Advance(&it)) { - RawAppendf(buffer, "%.*s\n", FmtString(it.filename)); - } + Assert(!"Invalid codepath"); } else { String string = ReadFile(scratch, path); buffer = CreateBuffer(sys_allocator, path, string.len * 4 + 4096); diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index b174eab..3274f2b 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -67,6 +67,7 @@ void FillEventWithBasicData(Event *event) { SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow); event->xwindow = xwindow; event->ywindow = ywindow; + event->text = ""; } Event TranslateSDLEvent(SDL_Event *input_event) { @@ -220,11 +221,14 @@ Array GetEventsForFrame(Allocator allocator) { } void Windows_SetupVCVarsall(mco_coro *co) { - Scratch scratch; - String working_dir = Command_GetDir(); - String buffer_name = GetUniqueBufferName(working_dir, "+cmd-"); - String cmd = Format(scratch, "\"%.*s\" && set", FmtString(StyleVCVarsall)); - View *view = Command_ExecHidden(buffer_name, cmd, working_dir); + View *view = NULL; + { + Scratch scratch; + String working_dir = Command_GetDir(); + String buffer_name = GetUniqueBufferName(working_dir, "+cmd-"); + String cmd = Format(scratch, "\"%.*s\" && set", FmtString(StyleVCVarsall)); + view = Command_ExecHidden(buffer_name, cmd, working_dir); + } for (;;) { if (!ProcessIsActive(view->id)) { break; @@ -232,6 +236,7 @@ void Windows_SetupVCVarsall(mco_coro *co) { Yield(co); } + Scratch scratch; Buffer *buffer = GetBuffer(view->active_buffer); String16 string16 = GetString(buffer); String string = ToString(scratch, string16); diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 1671748..9d41edb 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -82,7 +82,7 @@ float DPIScale = 1.0f; Rect2I GetVisibleCells(Window *window); void AfterEdit(View *view, Array edits); Scroller ComputeScrollerRect(Window *window); -void Command_Open(String path); +BSet Command_Open(String path); void Command_Open(String16 path); void UpdateScroll(Window *window, bool update_caret_scrolling); diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index 661c8a2..74901dd 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -1,5 +1,8 @@ !!As little lua code as possible, but lua code should be powerful just in case of quick edits - 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 | +- Windows, Buffers, Views should not be in a dynamic list it risks memory errors. Should be instead in a Double linked list, any freeing should happen at GC stage +- Fix B: not opening +- Scroll the console properly -------------- buffer = make_buffer() @@ -7,6 +10,7 @@ buffer.append(list_files("src/basic")) activate_buffer -------------- +- 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? - dump text editor state to file, restore state diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index d6f94f2..49e681a 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -109,7 +109,7 @@ Int GetTitleBarSize(Window *window) { void AddColumnWindow() { Window *window = CreateWindow(); window->is_column = true; - View *view = OpenBufferView("+scratch"); + View *view = OpenBufferView(ScratchBuffer->name); window->active_view = view->id; CreateTitlebar(window->id); CreateSearchBar(window->id); @@ -127,7 +127,7 @@ Int GetWindowIndex(WindowID window_id) { void AddRowWindow() { Window *active_window = GetActiveWindow(); Window *window = CreateWindow(); - View *view = OpenBufferView("+scratch"); + View *view = OpenBufferView(ScratchBuffer->name); window->active_view = view->id; CreateTitlebar(window->id); CreateSearchBar(window->id); @@ -213,8 +213,20 @@ void InitWindows() { Reserve(&Views, 256); #endif + { + Window *window = CreateWindow(); + window->active_view = NullViewID; + Assert(NullWindowID.id == 0); + // @todo - Windows, Buffers, Views should not be in a dynamic list it risks memory errors. Should be instead in a Double linked list, any freeing should happen at GC stage + WindowID id = window->id; + + CreateTitlebar(id); + CreateSearchBar(id); + } + { Window *window = CreateWindow(); + // @todo - Windows, Buffers, Views should not be in a dynamic list it risks memory errors. Should be instead in a Double linked list, any freeing should happen at GC stage WindowID window_id = window->id; window->is_column = true; Buffer *buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "test_buffer")); @@ -223,10 +235,14 @@ void InitWindows() { window->active_view = view->id; CreateTitlebar(window_id); CreateSearchBar(window->id); + + ActiveWindow = ActiveWindowCounterID = window_id; } + { Window *window = CreateWindow(); + // @todo - Windows, Buffers, Views should not be in a dynamic list it risks memory errors. Should be instead in a Double linked list, any freeing should happen at GC stage WindowID window_id = window->id; DebugWindowID = window->id; window->draw_line_numbers = false; @@ -249,20 +265,43 @@ void InitWindows() { SetVisibility(window_id, false); } - - ActiveWindow = {0}; } -void -LayoutWindows(int16_t wx, int16_t wy) { +void LayoutWindows(int16_t wx, int16_t wy) { float ScrollBarSize = (10.f * DPIScale); Rect2I screen_rect = RectI0Size(wx, wy); float line_numbers_size = (float)FontCharSpacing * 10; float sizex = (float)GetSize(screen_rect).x; + { + Window *window = GetWindow(NullWindowID); + if (ActiveWindow == window->id) { + NullWindowSize = 20; + } else { + NullWindowSize = 5; + } + + Rect2I rect = CutBottom(&screen_rect, FontLineSpacing*NullWindowSize); + + Window *title_bar_window = GetWindow(window->title_bar_window); + title_bar_window->total_rect = CutBottom(&window->total_rect, GetTitleBarSize(title_bar_window)); + title_bar_window->document_rect = title_bar_window->total_rect; + + Rect2I save_rect = window->document_rect; + CutLeft(&save_rect, GetSize(save_rect).x/2); + Window *search_bar_window = GetWindow(window->search_bar_window); + search_bar_window->total_rect = CutTop(&save_rect, GetTitleBarSize(search_bar_window)); + search_bar_window->document_rect = search_bar_window->total_rect; + + window->document_rect = window->total_rect; + if (window->draw_scrollbar) window->scrollbar_rect = CutRight(&window->document_rect, (Int)ScrollBarSize); + if (window->draw_line_numbers) window->line_numbers_rect = CutLeft(&window->document_rect, (Int)line_numbers_size); + + window->total_rect = rect; + } + Scratch scratch; Array columns = GetVisualColumns(scratch); - float delta_column = 1.0f / (float)columns.len; ForItem(col, columns) { Int add = 0;