From 863f140edc55660cd79c2a90837a87ce724f78c9 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sun, 25 Jan 2026 00:16:23 +0100 Subject: [PATCH] WordComplete working --- src/text_editor/commands.cpp | 4 +- src/text_editor/globals.cpp | 3 +- src/text_editor/plugin_basic_commands.cpp | 4 +- src/text_editor/plugin_word_complete.cpp | 212 ++++++++++++++++++---- src/text_editor/window.cpp | 8 + 5 files changed, 192 insertions(+), 39 deletions(-) diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index 8ef1c24..6869447 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -218,14 +218,14 @@ void CMD_KillProcess() { void CMD_MakeFontLarger() { FontSize += 1; ReloadFont(PathToFont, (U32)FontSize); - CMD_CenterView(); + CenterPrimaryViews(); } RegisterCommand(CMD_MakeFontLarger, "ctrl-equals", "Increase the font size"); void CMD_MakeFontSmaller() { if (FontSize > 4) { FontSize -= 1; ReloadFont(PathToFont, (U32)FontSize); - CMD_CenterView(); + CenterPrimaryViews(); } } RegisterCommand(CMD_MakeFontSmaller, "ctrl-minus", "Decrease the font size"); diff --git a/src/text_editor/globals.cpp b/src/text_editor/globals.cpp index c3a23da..2273d1d 100644 --- a/src/text_editor/globals.cpp +++ b/src/text_editor/globals.cpp @@ -13,7 +13,8 @@ Int ErrorCount; #if 1 String16 InitialScratchContent; #else -String16 InitialScratchContent = uR"==(0 +String16 InitialScratchContent = uR"==(C:/text_editor/src/text_editor/text_editor.cpp +0 1 2 3 diff --git a/src/text_editor/plugin_basic_commands.cpp b/src/text_editor/plugin_basic_commands.cpp index cbd0e7c..2adc472 100644 --- a/src/text_editor/plugin_basic_commands.cpp +++ b/src/text_editor/plugin_basic_commands.cpp @@ -27,12 +27,12 @@ void CMD_KillSelectedLines() { void CMD_IndentSelectedLines() { BSet active = GetBSet(ActiveWindowID); IndentSelectedLines(active.view); -} RegisterCommand(CMD_IndentSelectedLines, "ctrl-rightbracket | tab", ""); +} RegisterCommand(CMD_IndentSelectedLines, "ctrl-rightbracket", ""); void CMD_DedentSelectedLines() { BSet active = GetBSet(ActiveWindowID); IndentSelectedLines(active.view, true); -} RegisterCommand(CMD_DedentSelectedLines, "ctrl-leftbracket | shift-tab", ""); +} RegisterCommand(CMD_DedentSelectedLines, "ctrl-leftbracket", ""); void CMD_DuplicateLineDown() { BSet active = GetBSet(ActiveWindowID); diff --git a/src/text_editor/plugin_word_complete.cpp b/src/text_editor/plugin_word_complete.cpp index 8ded20d..3ca31c1 100644 --- a/src/text_editor/plugin_word_complete.cpp +++ b/src/text_editor/plugin_word_complete.cpp @@ -1,3 +1,5 @@ +// MAAAAAAAAAAAAN I DONT LIKE THIS CODE, BUT HOPE IT WORKS + struct Lexer2 { char16_t *at; }; @@ -8,71 +10,213 @@ Lexer2 BeginLexing(String16 data) { } String16 Next(Lexer2 *lexer) { - while (lexer->at[0] != 0 && !IsAlphanumeric(lexer->at[0])) { + while (lexer->at[0] != 0 && IsNonWord(lexer->at[0])) { lexer->at += 1; } String16 result = {lexer->at, 0}; - while (IsAlphanumeric(lexer->at[0])) { + while (lexer->at[0] != 0 && IsWord(lexer->at[0])) { lexer->at += 1; result.len += 1; } return result; } -struct WordCompleteS { +struct StringAndDistance { String16 string; Int distance; }; -bool Contains(Array *arr, String16 string) { +bool Contains(Array *arr, String16 string) { For (*arr) { if (it.string == string) return true; } return false; } -inline bool MergeSortCompare(WordCompleteS *EntryA, WordCompleteS *EntryB) { +inline bool MergeSortCompare(StringAndDistance *EntryA, StringAndDistance *EntryB) { bool result = EntryA->distance > EntryB->distance; return result; } -void CMD_WordComplete() { - // @todo: handle multiple carets - // @todo: indent when shift otherwise wordcomplte - // @todo: loop through buffers - // @todo: iterate by pressing 'tab' continously - Scratch scratch; - BSet active = GetBSet(ActiveWindowID); - Caret caret = active.view->carets[0]; - Range range = caret.range; - if (GetSize(range) != 0) { - return; - } - range.min = GetWordStart(active.buffer, range.min); - String16 prefix = GetString(active.buffer, range); +struct { + BlockArena arena; + String16 prefix_string; + String16 last_string; + mco_coro *co; + Buffer *buffer; + View *view; + Int original_caret_pos; + Int direction; +} CWS; - String16 string = GetString(active.buffer); - - Array idents = {scratch}; +void CWSLexIdentifiers(Array *out_idents, Buffer *buffer) { + Array idents = {CWS.arena}; + String16 string = GetString(buffer); Lexer2 lexer = BeginLexing(string.data); for (int i = 0;; i += 1) { String16 token = Next(&lexer); - if (token.len <= 0) break; - if (StartsWith(token, prefix) && token != prefix && !Contains(&idents, token)) { - Int pos = token.data - active.buffer->str; - Int distance = Absolute(range.min - pos); - Add(&idents, {token, distance}); + if (token.len <= 0) { + break; + } + if (StartsWith(token, CWS.prefix_string) && token != CWS.prefix_string && !Contains(&idents, token)) { + Int pos = token.data - buffer->str; + Int distance = Absolute(CWS.original_caret_pos - pos); + Add(&idents, {Copy16(CWS.arena, token), distance}); } } if (idents.len > 1) { - Array temp = TightCopy(scratch, idents); + Array temp = TightCopy(CWS.arena, idents); MergeSort(idents.len, idents.data, temp.data); } - if (idents.len > 0) { - String16 ident = idents[0].string; - ident = Skip(ident, prefix.len); - ident = Copy16(scratch, ident); - Replace(active.view, ident); + For (idents) { + if (!Contains(out_idents, it.string)) Add(out_idents, it); } -} RegisterCommand(CMD_WordComplete, "ctrl-b", "Completes the current word"); \ No newline at end of file +} + +void CompleteWord2(mco_coro *co) { + Array buffers = {CWS.arena}; + { + Add(&buffers, CWS.buffer->id); + ForItem (window, Windows) { + if (window->visible) { + View *view = GetView(window->active_view); + Buffer *buffer = GetBuffer(view->active_buffer); + if (!Contains(buffers, buffer->id)) { + Add(&buffers, buffer->id); + } + } + Int len = 0; + For (IterateInReverse(&window->goto_history)) { + View *view = GetView(it.view_id); + Buffer *buffer = GetBuffer(view->active_buffer); + if (!Contains(buffers, buffer->id)) { + Add(&buffers, buffer->id); + len += 1; + if (len > 16) continue; + } + } + } + Window *active = GetWindow(ActiveWindowID); + + } + + Buffer *curr_buffer = NULL; + Int buffer_i = 0; + Array idents = {CWS.arena}; + Add(&idents, {CWS.prefix_string, 0}); + for (Int i = 1;;) { + if (i >= idents.len) { + while (buffer_i < buffers.len) { + curr_buffer = GetBuffer(buffers[buffer_i++]); + CWSLexIdentifiers(&idents, curr_buffer); + if (i < idents.len) { + break; + } + } + if (i >= idents.len) { + goto yield; + } + } + StringAndDistance it = idents[i]; + String16 ident = Copy16(CWS.arena, it.string); + CWS.last_string = ident; + Range range = EncloseWord(curr_buffer, CWS.original_caret_pos); + View *view = GetViewForFixingWhenBufferCommand(curr_buffer); + SelectRange(view, range); + Replace(view, ident); + yield:; + mco_yield(co); + i += CWS.direction; + i = Clamp(i, 0ll, idents.len - 1); + } +} + +void CompleteWord(View *view, Int pos) { + Buffer *buffer = GetBuffer(view->active_buffer); + Range prefix_string_range = {GetWordStart(buffer, pos), pos}; + String16 prefix = GetString(buffer, prefix_string_range); + bool continue_with_previous = CWS.co && CWS.last_string == prefix && CWS.buffer == buffer; + if (!continue_with_previous) { + if (CWS.co) { + mco_result res = mco_destroy(CWS.co); + Assert(res == MCO_SUCCESS); + CWS.co = NULL; + } + Release(&CWS.arena); + MemoryZero(&CWS, sizeof(CWS)); + + CWS.buffer = buffer; + CWS.view = view; + CWS.original_caret_pos = pos; + CWS.prefix_string = Copy16(CWS.arena, prefix); + + mco_desc desc = mco_desc_init(CompleteWord2, NULL); + mco_result res = mco_create(&CWS.co, &desc); + Assert(res == MCO_SUCCESS); + } + CWS.direction = 1; + mco_result res = mco_resume(CWS.co); + Assert(res == MCO_SUCCESS); + + if (mco_status(CWS.co) == MCO_DEAD) { + res = mco_destroy(CWS.co); + Assert(res == MCO_SUCCESS); + CWS.co = NULL; + } +} + + +void CompletePrevWord(View *view, Int pos) { + Buffer *buffer = GetBuffer(view->active_buffer); + Range prefix_string_range = {GetWordStart(buffer, pos), pos}; + String16 prefix = GetString(buffer, prefix_string_range); + bool continue_with_previous = CWS.co && CWS.last_string == prefix && CWS.buffer == buffer; + if (!continue_with_previous) { + return; + } + CWS.direction = -1; + mco_result res = mco_resume(CWS.co); + Assert(res == MCO_SUCCESS); + if (mco_status(CWS.co) == MCO_DEAD) { + res = mco_destroy(CWS.co); + Assert(res == MCO_SUCCESS); + CWS.co = NULL; + } +} + +void CMD_CompleteWord() { + BSet active = GetBSet(ActiveWindowID); + bool ok = active.view->carets.len == 1 && GetSize(active.view->carets[0].range) == 0; + if (!ok) { + return; + } + CompleteWord(active.view, active.view->carets[0].range.min); +} RegisterCommand(CMD_CompleteWord, "", "Completes the current word"); + +void CMD_CompletePrevWord() { + BSet active = GetBSet(ActiveWindowID); + bool ok = active.view->carets.len == 1 && GetSize(active.view->carets[0].range) == 0; + if (!ok) { + return; + } + CompletePrevWord(active.view, active.view->carets[0].range.min); +} RegisterCommand(CMD_CompletePrevWord, "", "Completes the current word"); + +void CMD_CompletePrevWordOrDedent() { + BSet active = GetBSet(ActiveWindowID); + if (active.view->carets.len == 1 && GetSize(active.view->carets[0].range) == 0) { + CMD_CompletePrevWord(); + } else { + IndentSelectedLines(active.view, true); + } +} RegisterCommand(CMD_CompletePrevWordOrDedent, "shift-tab", "Completes the current word or it indents it, when single caret with no selection it goes for word complete"); + +void CMD_CompleteWordOrIndent() { + BSet active = GetBSet(ActiveWindowID); + if (active.view->carets.len == 1 && GetSize(active.view->carets[0].range) == 0) { + CMD_CompleteWord(); + } else { + IndentSelectedLines(active.view); + } +} RegisterCommand(CMD_CompleteWordOrIndent, "tab", "Completes the current word or it indents it, when single caret with no selection it goes for word complete"); \ No newline at end of file diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index ecfdd09..91bbdbc 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -381,6 +381,14 @@ void CenterView(WindowID window) { } } +void CenterPrimaryViews() { + For (Windows) { + if (it->primary) { + CenterView(it->id); + } + } +} + BSet GetBSet(Window *window) { BSet set = {window}; set.view = GetView(set.window->active_view);