From abb2cfb1c4fc03a14a9e26d43c9d5903944da43f Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Tue, 6 May 2025 16:41:43 +0200 Subject: [PATCH] Fuzzy search, working dir as nullbuffer dir --- data/init.lua | 10 ++--- src/text_editor/commands_bindings.cpp | 58 ++++++++++++++++++++------- src/text_editor/generated.cpp | 10 ++--- src/text_editor/lua_api.cpp | 35 ++++++++++------ src/text_editor/lua_api_generated.cpp | 6 +-- src/text_editor/management.cpp | 16 +++++--- src/text_editor/text_editor.cpp | 4 +- src/text_editor/text_editor.h | 12 +++--- src/text_editor/title_bar.cpp | 2 - src/text_editor/todo.txt | 4 +- src/text_editor/window.cpp | 10 ++--- te.project.lua | 46 --------------------- 12 files changed, 102 insertions(+), 111 deletions(-) delete mode 100644 te.project.lua diff --git a/data/init.lua b/data/init.lua index 0146dfb..ef4f3cc 100644 --- a/data/init.lua +++ b/data/init.lua @@ -175,7 +175,7 @@ function MatchWindowsPath(_s) end if not drive then - local d = GetDir() + local d = GetMainDir() file_path = d..'/'..file_path end local line, col, s = SkipLineAndColumn(s) @@ -191,7 +191,7 @@ function MatchGitCommit(s) if i then s = s:sub(8) local command = "git --no-pager show "..s - return {kind = "exec", cmd = command, working_dir = GetDir()} + return {kind = "exec", cmd = command, working_dir = GetMainDir()} end return nil end @@ -199,7 +199,7 @@ end function MatchURL(s) local i, j = string.find(s, "^https://") if i then - return {kind = "exec_console", cmd = '"'..INTERNET_BROWSER..'" '..s, working_dir = GetDir()} + return {kind = "exec_console", cmd = '"'..INTERNET_BROWSER..'" '..s, working_dir = GetMainDir()} end return nil end @@ -222,7 +222,7 @@ function ApplyRules(s) end function CFiles() - Cmd({working_dir = GetProjectPath(), destination ="a", cmd = "dir /s/b | findstr .*\\.c"}) + Cmd({working_dir = GetProjectDir(), kind ="a", cmd = "dir /s/b | findstr .*\\.c"}) end Coroutines = {} @@ -238,7 +238,7 @@ table.insert(OnCommandCallbacks, function (e) if e.key == SDLK_F and e.ctrl == 1 and e.shift == 1 then C("git grep -n "..GetLoadWord().." :/") end if e.key == SDLK_B and e.ctrl == 1 then - Cmd { working_dir = GetProjectPath(), destination = "console", cmd = "build.bat" } end + Cmd { working_dir = GetProjectDir(), kind = "console", cmd = "build.bat" } end end) function OnUpdate(e) diff --git a/src/text_editor/commands_bindings.cpp b/src/text_editor/commands_bindings.cpp index 777e372..c934ea3 100644 --- a/src/text_editor/commands_bindings.cpp +++ b/src/text_editor/commands_bindings.cpp @@ -50,7 +50,7 @@ void Command_GetCFiles(void) { String buffer_name = GetUniqueBufferName(GetDir(main.buffer), "getcfiles"); Buffer *buffer = CreateBuffer(GetSystemAllocator(), buffer_name, 4096 * 4); - ListFilesRecursive(buffer, Command_GetDir()); + ListFilesRecursive(buffer, Command_GetMainDir()); WindowOpenBufferView(main.window, buffer_name); } @@ -632,17 +632,6 @@ void OnCommand(Event event) { Command_GotoNextInList(active.window, 1); } - if (CtrlShiftPress(SDLK_RETURN)) { - Command_MoveCursorsToSide(active.view, DIR_LEFT); - Command_IdentedNewLine(active.view); - Command_Move(active.view, DIR_UP); - } else if (CtrlPress(SDLK_RETURN)) { - Command_MoveCursorsToSide(active.view, DIR_RIGHT); - Command_IdentedNewLine(active.view); - } else if (Press(SDLK_RETURN)) { - Command_IdentedNewLine(active.view); - } - if (CtrlShiftPress(SDLK_F)) { // because using lua thing } else if (CtrlPress(SDLK_F)) { @@ -659,6 +648,44 @@ void OnCommand(Event event) { } } + if (CtrlShiftPress(SDLK_RETURN)) { + Command_MoveCursorsToSide(active.view, DIR_LEFT); + Command_IdentedNewLine(active.view); + Command_Move(active.view, DIR_UP); + } else if (CtrlPress(SDLK_RETURN)) { + Command_MoveCursorsToSide(active.view, DIR_RIGHT); + Command_IdentedNewLine(active.view); + } else if (Press(SDLK_RETURN)) { + Command_IdentedNewLine(active.view); + } + + + if (active.view->fuzzy_search) { + if (!ProcessIsActive(active.view->id)) { + Scratch scratch; + 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); + + Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap); + For(IterateInReverse(&ratings)) { + String16 s = GetLineStringWithoutNL(active.buffer, it.index); + if (s.len == 0) continue; + RawReplaceText(temp_buffer, GetEndAsRange(temp_buffer), s); + RawReplaceText(temp_buffer, GetEndAsRange(temp_buffer), u"\n"); + } + RawReplaceText(temp_buffer, GetEndAsRange(temp_buffer), last_line_string); + + Caret caret = active.view->carets[0]; + Command_SelectEntireBuffer(active.view); + Command_Replace(active.view, GetString(temp_buffer)); + active.view->carets[0] = caret; + } + } + } + + if (CtrlPress(SDLK_S)) { SaveBuffer(active.view); } @@ -689,6 +716,10 @@ void OnCommand(Event event) { Command_Eval(FetchLoadWord()); } else if (CtrlPress(SDLK_Q)) { Command_Open(FetchLoadWord()); + if (active.view->fuzzy_search) { + Range rng = GetLineRangeWithoutNL(active.buffer, active.buffer->line_starts.len - 1); + GetLast(active.window->goto_history)->caret = MakeCaret(rng.max, rng.min); + } } if (Press(SDLK_ESCAPE)) { @@ -703,9 +734,6 @@ void OnCommand(Event event) { } } - if (active.window->is_title_bar && buffer_change_id != active.buffer->change_id) { - } - if (active.window->is_search_bar && buffer_change_id != active.buffer->change_id) { Command_Find(main.view, GetSearchString(main.window), true); } diff --git a/src/text_editor/generated.cpp b/src/text_editor/generated.cpp index be65abe..1bf504b 100644 --- a/src/text_editor/generated.cpp +++ b/src/text_editor/generated.cpp @@ -247,7 +247,7 @@ function MatchWindowsPath(_s) end if not drive then - local d = GetDir() + local d = GetMainDir() file_path = d..'/'..file_path end local line, col, s = SkipLineAndColumn(s) @@ -263,7 +263,7 @@ function MatchGitCommit(s) if i then s = s:sub(8) local command = "git --no-pager show "..s - return {kind = "exec", cmd = command, working_dir = GetDir()} + return {kind = "exec", cmd = command, working_dir = GetMainDir()} end return nil end @@ -271,7 +271,7 @@ end function MatchURL(s) local i, j = string.find(s, "^https://") if i then - return {kind = "exec_console", cmd = '"'..INTERNET_BROWSER..'" '..s, working_dir = GetDir()} + return {kind = "exec_console", cmd = '"'..INTERNET_BROWSER..'" '..s, working_dir = GetMainDir()} end return nil end @@ -294,7 +294,7 @@ function ApplyRules(s) end function CFiles() - Cmd({working_dir = GetProjectPath(), destination ="a", cmd = "dir /s/b | findstr .*\\.c"}) + Cmd({working_dir = GetProjectDir(), kind ="a", cmd = "dir /s/b | findstr .*\\.c"}) end Coroutines = {} @@ -310,7 +310,7 @@ table.insert(OnCommandCallbacks, function (e) if e.key == SDLK_F and e.ctrl == 1 and e.shift == 1 then C("git grep -n "..GetLoadWord().." :/") end if e.key == SDLK_B and e.ctrl == 1 then - Cmd { working_dir = GetProjectPath(), destination = "console", cmd = "build.bat" } end + Cmd { working_dir = GetProjectDir(), kind = "console", cmd = "build.bat" } end end) function OnUpdate(e) diff --git a/src/text_editor/lua_api.cpp b/src/text_editor/lua_api.cpp index 23383e8..ce68ede 100644 --- a/src/text_editor/lua_api.cpp +++ b/src/text_editor/lua_api.cpp @@ -93,6 +93,7 @@ BSet Command_Open(String path) { ActiveWindow = main.window->id; if (IsDir(file_path)) { Command_JumpNew(&main); + main.buffer->name = GetUniqueBufferName(file_path, "temp"); Command_Appendf(main.view, "%.*s/..\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)); @@ -110,7 +111,7 @@ BSet Command_Open(String path) { } else if (FieldString(LuaState, "kind") == "exec") { String cmd = FieldString(LuaState, "cmd"); String working_dir = FieldString(LuaState, "working_dir"); - Command_Exec(cmd, Command_GetDir()); + Command_Exec(cmd, Command_GetMainDir()); } else if (FieldString(LuaState, "kind") == "exec_console") { // this shouldn't change the focus/window/view String cmd = FieldString(LuaState, "cmd"); @@ -132,7 +133,7 @@ BSet Command_Open(String16 path) { int Lua_C(lua_State *L) { String string = lua_tostring(L, 1); lua_pop(L, 1); - Command_Exec(string, Command_GetDir()); + Command_Exec(string, Command_GetMainDir()); return 0; } @@ -161,7 +162,7 @@ int Lua_NewBufferCMD(lua_State *L) { String string = lua_tostring(L, 1); lua_pop(L, 1); - String working_dir = Command_GetDir(); + String working_dir = Command_GetMainDir(); BSet set = GetActiveMainSet(); Command_ExecInNewBuffer(set, string, working_dir); return 0; @@ -172,21 +173,23 @@ int Lua_Cmd(lua_State *L) { defer { lua_pop(L, 1); }; lua_getfield(L, -1, "working_dir"); - if (!lua_isstring(L, -1)) luaL_error(L, "expected a string for working_dir param"); String working_dir = lua_tostring(L, -1); lua_pop(L, 1); + if (working_dir == "") { + working_dir = Command_GetMainDir(); + } lua_getfield(L, -1, "cmd"); if (!lua_isstring(L, -1)) luaL_error(L, "expected a string for cmd param"); String cmd = lua_tostring(L, -1); lua_pop(L, 1); - lua_getfield(L, -1, "destination"); - String destination = lua_tostring(L, -1); + lua_getfield(L, -1, "kind"); + String kind = lua_tostring(L, -1); lua_pop(L, 1); BSet main = GetActiveMainSet(); - if (destination == "console") { + if (kind == "console") { BSet set = GetConsoleSet(); main.window->active_goto_list = set.view->id; main.window->goto_list_pos = set.buffer->len; @@ -194,6 +197,11 @@ int Lua_Cmd(lua_State *L) { Command_BeginJump(&set); Exec(set.view->id, true, cmd, working_dir); Command_EndJump(set); + } else if (kind == "fuzzy") { + Command_JumpNew(&main); + Exec(main.view->id, true, cmd, working_dir); + main.view->fuzzy_search = true; + ActiveWindow = main.window->id; } else { Command_JumpNew(&main); Exec(main.view->id, true, cmd, working_dir); @@ -358,7 +366,7 @@ int Lua_GetFilename(lua_State *L) { return 1; } -int Lua_GetProjectPath(lua_State *L) { +int Lua_GetProjectDir(lua_State *L) { if (LuaProjectBuffer) { String path = ChopLastSlash(LuaProjectBuffer->name); lua_pushlstring(L, path.data, path.len); @@ -376,13 +384,14 @@ int Lua_FileExists(lua_State *L) { return 1; } -int Lua_GetWorkingDir(lua_State *L) { - lua_pushlstring(L, WorkingDir.data, WorkingDir.len); +int Lua_GetBaseDir(lua_State *L) { + String name = Command_GetBaseDir(); + lua_pushlstring(L, name.data, name.len); return 1; } -int Lua_GetDir(lua_State *L) { - String name = Command_GetDir(); +int Lua_GetMainDir(lua_State *L) { + String name = Command_GetMainDir(); lua_pushlstring(L, name.data, name.len); return 1; } @@ -551,7 +560,7 @@ void ReloadLuaConfigs() { ReloadStyle(); ReloadFont(); for (Window *it = FirstWindow; it; it = it->next) { - if (!it->visible || it->absolute_position || it->is_title_bar || it->is_search_bar) { + if (it->is_title_bar || it->is_search_bar) { continue; } it->draw_scrollbar = StyleDrawScrollbar; diff --git a/src/text_editor/lua_api_generated.cpp b/src/text_editor/lua_api_generated.cpp index cf8bef4..c66016b 100644 --- a/src/text_editor/lua_api_generated.cpp +++ b/src/text_editor/lua_api_generated.cpp @@ -21,10 +21,10 @@ luaL_Reg LuaFunctions[] = { {"GetEntireBuffer", Lua_GetEntireBuffer}, {"GetClipboard", Lua_GetClipboard}, {"GetFilename", Lua_GetFilename}, - {"GetProjectPath", Lua_GetProjectPath}, + {"GetProjectDir", Lua_GetProjectDir}, {"FileExists", Lua_FileExists}, - {"GetWorkingDir", Lua_GetWorkingDir}, - {"GetDir", Lua_GetDir}, + {"GetBaseDir", Lua_GetBaseDir}, + {"GetMainDir", Lua_GetMainDir}, {"SplitSize", Lua_SplitSize}, {"Play", Lua_Play}, {NULL, NULL}, diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp index d8c0f1d..6890b64 100644 --- a/src/text_editor/management.cpp +++ b/src/text_editor/management.cpp @@ -49,13 +49,14 @@ String GetUniqueBufferName(String working_dir, String prepend_name) { void InitScratchBuffer() { Allocator sys_allocator = GetSystemAllocator(); - Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "console")); + Scratch scratch; + Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(GetWorkingDir(scratch), "console")); View *null_view = CreateView(null_buffer->id); Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID); - GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "gc")); - EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "events")); - ScratchBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "scratch")); + GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(Command_GetBaseDir(), "gc")); + EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(Command_GetBaseDir(), "events")); + ScratchBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(Command_GetBaseDir(), "scratch")); EventBuffer->no_history = true; GCInfoBuffer->no_history = true; } @@ -293,12 +294,17 @@ String GetDir(Buffer *buffer) { return name; } -String Command_GetDir() { +String Command_GetMainDir() { BSet set = GetActiveMainSet(); String name = ChopLastSlash(set.buffer->name); return name; } +String Command_GetBaseDir() { + Buffer *buffer = GetBuffer(NullBufferID); + return ChopLastSlash(buffer->name); +} + Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) { if (string.len == 0) { return 0; diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index 017f0e9..a4e0735 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -226,7 +226,7 @@ void Windows_SetupVCVarsall(mco_coro *co) { View *view = NULL; { Scratch scratch; - String working_dir = Command_GetDir(); + String working_dir = Command_GetBaseDir(); String buffer_name = GetUniqueBufferName(working_dir, "vcvarsall-"); String cmd = Format(scratch, "\"%.*s\" && set", FmtString(StyleVCVarsall)); view = Command_ExecHidden(buffer_name, cmd, working_dir); @@ -266,8 +266,6 @@ int main(int argc, char **argv) InitArena(&Perm); // Prototype(); - WorkingDir = GetWorkingDir(Perm); - ExeDir = GetExeDir(Perm); { String sdl_config_path = SDL_GetPrefPath("krzosa", "text_editor"); if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '\\') { diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index a3d3c80..cfbbf0f 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -14,6 +14,9 @@ struct View { // window | view Caret main_caret_on_begin_frame; bool update_scroll; + + bool fuzzy_search; + String16 prev_search_line; }; struct GotoCrumb { @@ -52,7 +55,6 @@ struct Window { bool draw_line_numbers : 1; bool visible : 1; - bool absolute_position : 1; bool is_title_bar : 1; bool is_search_bar : 1; @@ -102,9 +104,7 @@ struct BSet { // Dont use it Int FrameID; -String WorkingDir; String ConfigDir; -String ExeDir; Arena Perm; float DPIScale = 1.0f; @@ -122,8 +122,10 @@ void Command_Append(View *view, String16 string, bool scroll_to_end_if_cu 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); +void Command_Eval(String string); +void Command_Eval(String16 string); +String Command_GetMainDir(); +String Command_GetBaseDir(); void Command_Copy(View *view); void Command_Paste(View *view); diff --git a/src/text_editor/title_bar.cpp b/src/text_editor/title_bar.cpp index c0d432c..3396e6e 100644 --- a/src/text_editor/title_bar.cpp +++ b/src/text_editor/title_bar.cpp @@ -16,8 +16,6 @@ void UpdateDebugBuffer() { SDL_GetMouseState(&xmouse, &ymouse); RawAppendf(buffer, "mouse: [%f, %f]\n", xmouse, ymouse); RawAppendf(buffer, "C:/Work/text_editor/src/text_editor/text_editor.cpp\n"); - RawAppendf(buffer, "working dir: %.*s\n", FmtString(WorkingDir)); - RawAppendf(buffer, "exe dir: %.*s\n", FmtString(ExeDir)); RawAppendf(buffer, "config dir: %.*s\n", FmtString(ConfigDir)); } diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index 1558df2..bb7f443 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -1,10 +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 | -- need a buffer for every window that will be cleared on command and replaced with new content - - buffer_list shouldn't be a thing - Scroll the console properly - commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top -- Maybe instead of WorkingDir use directory of null buffer? +- automatically generating lua bindings for simple commands -------------- buffer = make_buffer() diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index 3538bb1..38afe31 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -14,7 +14,7 @@ Window *CreateSearchBar(WindowID parent_window_id) { static int BarCount; Allocator sys_allocator = GetSystemAllocator(); - String name = Format(sys_allocator, "%.*s/searchbar%d", FmtString(WorkingDir), ++BarCount); + String name = Format(sys_allocator, "%.*s/searchbar%d", FmtString(Command_GetBaseDir()), ++BarCount); Buffer *b = CreateBuffer(sys_allocator, name); View *v = CreateView(b->id); @@ -37,7 +37,7 @@ Window *CreateTitlebar(WindowID parent_window_id) { static int TitlebarCount; Allocator sys_allocator = GetSystemAllocator(); - String name = Format(sys_allocator, "%.*s/titlebar%d", FmtString(WorkingDir), ++TitlebarCount); + String name = Format(sys_allocator, "%.*s/titlebar%d", FmtString(Command_GetBaseDir()), ++TitlebarCount); Buffer *b = CreateBuffer(sys_allocator, name); View *v = CreateView(b->id); @@ -189,9 +189,8 @@ void InitWindows() { { Window *window = CreateWindow(); - Buffer *buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "test_buffer")); + Buffer *buffer = ScratchBuffer; View *view = CreateView(buffer->id); - LoadTestBufferMessage(buffer); window->active_view = view->id; CreateTitlebar(window->id); CreateSearchBar(window->id); @@ -205,12 +204,11 @@ void InitWindows() { Window *window = CreateWindow(); DebugWindowID = window->id; window->draw_line_numbers = false; - window->absolute_position = true; window->draw_scrollbar = false; window->visible = false; window->z = 2; - Buffer *buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "debug")); + Buffer *buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(Command_GetBaseDir(), "debug")); DebugBufferID = buffer->id; buffer->no_history = true; diff --git a/te.project.lua b/te.project.lua deleted file mode 100644 index e900ffe..0000000 --- a/te.project.lua +++ /dev/null @@ -1,46 +0,0 @@ -function OnCommandTE(e) - if e.key == SDLK_B and e.ctrl == 1 then - Cmd { working_dir = GetProjectPath(), destination = "console", cmd = "build.bat" } - end -end - -function MatchProject(s) - if s:sub(1,1) == '"' then - s = s:sub(2) - end - - local s, file_path, drive = SkipPath(s) - if not file_path then - return nil - end - if drive ~= nil then - return nil - end - - local line, col, s = SkipLineAndColumn(s) - - local fp = GetDir().."/"..file_path - if FileExists(fp) then - return {kind = "text", file_path = fp, line = line, col = col} - end - - local fp = GetProjectPath().."/src/"..file_path - if FileExists(fp) then - return {kind = "text", file_path = fp, line = line, col = col} - end - - local fp = GetProjectPath().."/"..file_path - if FileExists(fp) then - return {kind = "text", file_path = fp, line = line, col = col} - end - - return nil -end - -function MatchGrep(s) - return {kind = "exec", cmd = "git grep -n "..GetLoadWord().." :/", working_dir = GetProjectPath()} -end - -table.insert(OnCommandCallbacks, OnCommandTE) -table.insert(Rules, 1, MatchGrep) -table.insert(Rules, MatchProject)