diff --git a/src/backup/todo.txt b/src/backup/todo.txt index b641460..cc37ad6 100644 --- a/src/backup/todo.txt +++ b/src/backup/todo.txt @@ -1,13 +1,12 @@ - What precise workflow do I need for me to be viable to use this? - From a user (novice) point of view, how does it look like? +Debug session: +- Report errorf - use coroutine dialogs + Use session 1: - OpenCommand in command window freezes the app -- SDL popups are not working on linux ... - - CloseAll idea: should create a buffer interface with list of buffers, user would be able to select which buffers to save and which not, then button UICloseAll -- Creating files more efficiently, renaming - - Dialog popup on save? Or ctrl-shift-s? - - Maybe rename in bar and do :Rename +- :Rename command that will ask New UI Session - Cleanup String16/String with Open and EvalCommands after lua refactor @@ -20,6 +19,7 @@ New UI Session - Database idea: use special buffers to store information - Editing the buffer doesn't seem to be the slow part rather, accessing the data and putting it into the buffer (potentially hitting many different memory locations) I have a crazy idea to use buffers in order to store the names in a serialized format - non editable buffers (raw ops ok, non-raw no op) + - DBBuffer - Guide on the first page for new users with links to configs, tutorials - Why constraint that name of buffer needs to be unique? For Open() and default behavior but is this required? diff --git a/src/basic/basic_string16.cpp b/src/basic/basic_string16.cpp index ff8f953..1d26945 100644 --- a/src/basic/basic_string16.cpp +++ b/src/basic/basic_string16.cpp @@ -427,6 +427,14 @@ API String16 SkipWhitespace(String16 *string) { return begin; } +API bool Chop(String16 *string, String16 ending) { + if (EndsWith(*string, ending)) { + *string = Chop(*string, ending.len); + return true; + } + return false; +} + // chop this - 324 API String16 ChopNumberEx(String16 *string) { String16 col = {}; diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index fb9482e..d023f7e 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -412,21 +412,6 @@ void Command_GotoPrevInList() { GotoNextInList(main.window, -1); } RegisterCommand(Command_GotoPrevInList, "alt-e"); -enum OpenKind { - OpenKind_Invalid, - OpenKind_Skip, - OpenKind_Exec, - OpenKind_BackgroundExec, - OpenKind_Goto, - OpenKind_Command, -}; - -struct ResolvedOpen { - OpenKind kind; - String path; - Int line, col; -}; - bool IsOpenBoundary(char c) { bool result = c == 0 || IsParen(c) || IsBrace(c) || c == ':' || c == '\t' || c == '\n' || c == '"' || c == '\''; return result; @@ -434,6 +419,7 @@ bool IsOpenBoundary(char c) { ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) { ResolvedOpen result = {}; + path = Trim(path); // Editor command { @@ -512,6 +498,7 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) { if (existing_buffer != NULL) { result.path = path; result.kind = OpenKind_Goto; + result.existing_buffer = true; return result; } @@ -521,14 +508,18 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) { return result; } else { String workspace_path = Format(scratch, "%S/%S", WorkDir, path); - if (GetBuffer(workspace_path, NULL) || FileExists(workspace_path)) { + bool existing_buffer = GetBuffer(workspace_path, NULL); + if (existing_buffer || FileExists(workspace_path)) { + result.existing_buffer = existing_buffer; result.path = workspace_path; result.kind = OpenKind_Goto; return result; } String rel_path = Format(scratch, "%S/%S", GetMainDir(), path); - if (GetBuffer(rel_path, NULL) || FileExists(rel_path)) { + existing_buffer = GetBuffer(rel_path, NULL); + if (existing_buffer || FileExists(rel_path)) { + result.existing_buffer = existing_buffer; result.path = rel_path; result.kind = OpenKind_Goto; return result; @@ -538,6 +529,7 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) { } if (meta == "dont_error") { + result.path = path; result.kind = OpenKind_Skip; return result; } @@ -548,7 +540,6 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta) { BSet Open(Window *window, String path, String meta, bool set_active = true) { Scratch scratch; BSet set = GetBSet(window); - path = Trim(path); ResolvedOpen o = ResolveOpen(scratch, path, meta); if (o.kind == OpenKind_Goto) { if (set_active) { @@ -702,6 +693,11 @@ void Command_CloseWindow() { Close(LastActiveLayoutWindowID); } RegisterCommand(Command_CloseWindow, ""); +void AddHook(Array *arr, String name, String binding, Function *function) { + CommandData n = {name, binding, function, ParseKeyCached(binding)}; + Add(arr, n); +} + String Coro_YesNoCancel(mco_coro *co, BSet main, String question) { JumpGarbageBuffer(&main); NextActiveWindowID = main.window->id; @@ -713,9 +709,9 @@ String Coro_YesNoCancel(mco_coro *co, BSet main, String question) { )==", question); main.view->carets[0] = FindNext(main.buffer, u":Yes", MakeCaret(0)); main.view->carets[0].range.min = main.view->carets[0].range.max; - Add(&main.view->hooks, {"Yes", "enter", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "Yes";}, ParseKeyCached("enter")}); - Add(&main.view->hooks, {"No", "", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "No";}, ParseKeyCached("")}); - Add(&main.view->hooks, {"Cancel", "escape", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "Cancel";}, ParseKeyCached("escape")}); + AddHook(&main.view->hooks, "Yes", "enter", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "Yes";}); + AddHook(&main.view->hooks, "No", "", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "No";}); + AddHook(&main.view->hooks, "Cancel", "escape", [](){BSet active = GetBSet(ActiveWindowID); active.view->hook_cmd = "Cancel";}); String result = "Cancel"; for (;;) { if (main.window->active_view != main.view->id || main.window->close) { diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index f34cf9c..d3ad028 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -368,13 +368,13 @@ void OnCommand(Event event) { if (mouse_in_scrollbar) { ScrollbarSelected = it->id; - View *view = GetView(it->active_view); - Vec2 mouse_vec2 = MouseVec2(); - Scroller s = ComputeScrollerRect(it); - double size_y = (double)GetSize(it->scrollbar_rect).y; - double p = mouse_vec2.y - it->scrollbar_rect.min.y; + View *view = GetView(it->active_view); + Vec2 mouse_vec2 = MouseVec2(); + Scroller s = ComputeScrollerRect(it); + double size_y = (double)GetSize(it->scrollbar_rect).y; + double p = mouse_vec2.y - it->scrollbar_rect.min.y; if (mouse_vec2.y < s.rect.min.y || mouse_vec2.y > s.rect.max.y) { - view->scroll.y = (Int)(p / size_y * (double)s.line_count * (double)it->font->line_spacing); + view->scroll.y = (Int)(p / size_y * (double)s.line_count * (double)it->font->line_spacing); it->mouse_scroller_offset = -(double)GetSize(s.rect).y / 2.0 / size_y; } else { it->mouse_scroller_offset = (s.rect.min.y - p) / size_y; diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index e80e9f7..519beb2 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -176,3 +176,22 @@ struct Register_Variable { type name = __VA_ARGS__; \ Register_Variable var_##name(&Variables, VariableType_##type, #name, &name) +void AddHook(Array *arr, String name, String binding, Function *function); + + +enum OpenKind { + OpenKind_Invalid, + OpenKind_Skip, + OpenKind_Exec, + OpenKind_BackgroundExec, + OpenKind_Goto, + OpenKind_Command, +}; + +struct ResolvedOpen { + OpenKind kind; + String path; + Int line, col; + bool existing_buffer; +}; +ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta); diff --git a/src/text_editor/window_status.cpp b/src/text_editor/window_status.cpp index 272be76..5540eca 100644 --- a/src/text_editor/window_status.cpp +++ b/src/text_editor/window_status.cpp @@ -14,6 +14,28 @@ void StatusWindowInit() { window->layout = false; window->jump_history = false; window->lose_focus_on_escape = true; + + AddHook(&view->hooks, "Rename", "ctrl-r", [](){ + BSet active = GetBSet(ActiveWindowID); + BSet last = GetBSet(LastActiveLayoutWindowID); + String16 buffer_string = GetString(active.buffer); + Range replace_range = {0, active.buffer->len}; + bool found_separator = Seek(buffer_string, u" |", &replace_range.max); + if (!found_separator) { + ReportErrorf("Failed to :Rename, didn't find '|' separator"); + return; + } + + Scratch scratch; + String16 buffer_name = GetString(active.buffer, replace_range); + String buffer_name8 = ToString(scratch, buffer_name); + ResolvedOpen o = ResolveOpen(scratch, buffer_name8, "dont_error"); + if (o.kind != OpenKind_Skip) { + ReportErrorf("%S already exists, either on disk as file or as buffer", buffer_name8); + return; + } + last.buffer->name = Intern(&GlobalInternTable, o.path); + }); } void StatusWindowLayout(Rect2I *rect, Int wx, Int wy) { @@ -52,17 +74,18 @@ void StatusWindowUpdate() { return; } String16 buffer_name = GetString(title.buffer, replace_range); - buffer_name = Skip(buffer_name, 1); buffer_name = Trim(buffer_name); Int column = ChopNumber(&buffer_name); if (column == -1) return; + Chop(&buffer_name, u":"); Int line = ChopNumber(&buffer_name); if (line == -1) { line = column; column = 0; } + Chop(&buffer_name, u":"); Int buffer_pos = XYToPos(main.buffer, {column, line}); Caret &caret = main.view->carets[0]; @@ -78,14 +101,14 @@ void StatusWindowUpdate() { // add separator at the end of buffer if (!found_separator) { SelectRange(title.view, GetBufferEndAsRange(title.buffer)); - Array edits = ReplaceEx(scratch, title.view, u" |"); + ReplaceEx(scratch, title.view, u" | :Rename"); } // replace data up to separator with filename and stuff const char *reopen = main.buffer->changed_on_disk ? " :Reopen" : ""; const char *case_sens = SearchCaseSensitive ? " C" : ""; const char *word_bound = SearchWordBoundary ? " W" : ""; - String s = Format(scratch, "# %S:%lld:%lld%s%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, case_sens, word_bound, reopen); + String s = Format(scratch, " %S:%lld:%lld%s%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, case_sens, word_bound, reopen); For (ActiveProcesses) { if (it.view_id == main.view->id.id) { s = Format(scratch, "%S %lld :KillProcess", s, (long long)it.id);