From be99b0aabbaf1dd6c866d992fba044ee4747620c Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Wed, 31 Jul 2024 07:32:42 +0200 Subject: [PATCH] Editing infobar applies changes to buffer --- src/basic/basic.h | 29 ++++++------ src/basic/string16.cpp | 39 +++++++++++++++++ src/text_editor/buffer.cpp | 1 + src/text_editor/commands.cpp | 24 +++++++++- src/text_editor/commands_window.cpp | 68 +++++++++++++++++++++++++++-- src/text_editor/management.cpp | 5 +++ src/text_editor/text_editor.cpp | 31 +++++++------ src/text_editor/text_editor.h | 1 + src/text_editor/todo.txt | 4 -- 9 files changed, 164 insertions(+), 38 deletions(-) diff --git a/src/basic/basic.h b/src/basic/basic.h index 6a6c356..c59ec27 100644 --- a/src/basic/basic.h +++ b/src/basic/basic.h @@ -700,7 +700,6 @@ struct CircularArray { T *data; int16_t cap; int16_t write; - int16_t buffer_is_full; }; template @@ -718,25 +717,23 @@ void Add(CircularArray *arr, T item) { arr->cap = 128; arr->data = AllocArray(arr->allocator, T, arr->cap); } - int idx = arr->write; - arr->write = (arr->write + 1) % arr->cap; - if (arr->write == 0) arr->buffer_is_full = 1; - arr->data[idx] = item; + int16_t i = arr->write; + arr->write = (arr->write + 1) % arr->cap; + arr->data[i] = item; +} + +static int GetCircularIndex(int cap, int idx) { + int result = idx % cap; + if (result < 0) result = cap + result; + return result; } template T Get(CircularArray *arr, int idx, T default_value) { - if (idx >= arr->cap) return default_value; - int i = arr->write - 1 - idx; - if (i < 0 && arr->buffer_is_full) { - i = arr->cap + i; - } - - if (i >= 0 && i < arr->cap) { - return arr->data[i]; - } else { - return default_value; - } + int idx = circ->write - 1 - i; + idx = GetCircularIndex(circ->size, idx); + int result = circ->data[idx]; + return result; } struct UTF32Result { diff --git a/src/basic/string16.cpp b/src/basic/string16.cpp index c7c92ff..72ea6bd 100644 --- a/src/basic/string16.cpp +++ b/src/basic/string16.cpp @@ -150,3 +150,42 @@ String16 CutPostfix(String16 *string, int64_t len) { *string = Chop(*string, len); return result; } + +String16 Trim(String16 string) { + if (string.len == 0) + return string; + + int64_t whitespace_begin = 0; + for (; whitespace_begin < string.len; whitespace_begin++) { + if (!IsWhitespace(string.data[whitespace_begin])) { + break; + } + } + + int64_t whitespace_end = string.len; + for (; whitespace_end != whitespace_begin; whitespace_end--) { + if (!IsWhitespace(string.data[whitespace_end - 1])) { + break; + } + } + + if (whitespace_begin == whitespace_end) { + string.len = 0; + } else { + string = GetSlice(string, whitespace_begin, whitespace_end); + } + + return string; +} + +String16 TrimEnd(String16 string) { + int64_t whitespace_end = string.len; + for (; whitespace_end != 0; whitespace_end--) { + if (!IsWhitespace(string.data[whitespace_end - 1])) { + break; + } + } + + String16 result = GetPrefix(string, whitespace_end); + return result; +} diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index 6ef7f92..9468899 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -170,6 +170,7 @@ void ReplaceText(Buffer *buffer, Range range, String16 string) { Assert(range.min >= 0 && range.min <= buffer->len); buffer->dirty = true; buffer->change_id += 1; + buffer->change_frame_id = FrameID; Int size_to_remove = range.max - range.min; Int size_to_add = string.len; diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index 88f5c4c..211df22 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -227,6 +227,23 @@ Array FindAllInBuffer(Allocator allocator, Buffer *buffer, String16 needl return result; } +void ToggleFullscreen() { + if (IsInFullscreen) { + SDL_SetWindowSize(SDLWindow, FullScreenSizeX, FullScreenSizeY); + SDL_SetWindowPosition(SDLWindow, FullScreenPositionX, FullScreenPositionY); + } else { + SDL_GetWindowSize(SDLWindow, &FullScreenSizeX, &FullScreenSizeY); + SDL_GetWindowPosition(SDLWindow, &FullScreenPositionX, &FullScreenPositionY); + + SDL_DisplayID display = SDL_GetDisplayForWindow(SDLWindow); + const SDL_DisplayMode *dm = SDL_GetCurrentDisplayMode(display); + SDL_SetWindowSize(SDLWindow, dm->w, dm->h); + SDL_SetWindowPosition(SDLWindow, 0, 0); + } + + IsInFullscreen = !IsInFullscreen; +} + bool GlobalCommand(Event event) { ProfileFunction(); bool run_window_command = true; @@ -314,6 +331,10 @@ bool GlobalCommand(Event event) { run_window_command = false; } + if (Press(SDLK_F11)) { + ToggleFullscreen(); + } + if (Ctrl(SDLK_P)) { Window *command_window = GetWindow(CommandWindowID); if (command_window->visible) { @@ -366,8 +387,7 @@ void ReportErrorf(const char *fmt, ...) { STRING_FORMAT(scratch, fmt, string); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error!", string.data, NULL); - Buffer *buffer = GetBuffer("*console*"); - if (!buffer) return; + Buffer *buffer = GetBuffer("*console*"); String16 string16 = ToString16(scratch, string); ReplaceText(buffer, {}, string16); } diff --git a/src/text_editor/commands_window.cpp b/src/text_editor/commands_window.cpp index 06b3991..dc1343e 100644 --- a/src/text_editor/commands_window.cpp +++ b/src/text_editor/commands_window.cpp @@ -266,12 +266,74 @@ void ReplaceDebugData() { Append(buffer, ToString16(scratch, window_list)); } +void ApplyInfobarChanges(Window *window, View *view, Buffer *buffer) { + String16 buffer_string = GetString(*buffer); + Range replace_range = {0, buffer->len}; + if (Seek(buffer_string, L" |", &replace_range.max)) { + } + buffer_string = GetString(*buffer, replace_range); + buffer_string = Trim(buffer_string); + + String16 col = {}; + for (int64_t i = buffer_string.len - 1; i >= 0; i -= 1) { + if (IsDigit(buffer_string.data[i])) { + col.data = buffer_string.data + i; + col.len += 1; + } else if (buffer_string.data[i] == L':') { + break; + } else { + return; + } + } + buffer_string = Chop(buffer_string, col.len + 1); + + String16 line = {}; + for (int64_t i = buffer_string.len - 1; i >= 0; i -= 1) { + if (IsDigit(buffer_string.data[i])) { + line.data = buffer_string.data + i; + line.len += 1; + } else if (buffer_string.data[i] == L':') { + break; + } else { + return; + } + } + buffer_string = Chop(buffer_string, line.len + 1); + + Window *last_window = GetWindow(GetLastActiveWindow()); + View *last_view = GetActiveView(last_window); + Buffer *last_buffer = GetBuffer(last_view->active_buffer); + + // @todo: maybe intern the filenames? + // @leak + String filepath = ToString(Perm, buffer_string); + if (!BufferNameExists(filepath)) { + last_buffer->name = filepath; + } + + Scratch scratch; + String line_string = ToString(scratch, line); + String col_string = ToString(scratch, col); + Int linei = strtoll(line_string.data, NULL, 10) - 1; + Int coli = strtoll(col_string.data, NULL, 10) - 1; + Int buffer_pos = XYToPos(*last_buffer, {coli, linei}); + + Caret &caret = last_view->carets[0]; + if (GetFront(caret) != buffer_pos) { + caret = MakeCaret(buffer_pos); + } +} + void ReplaceInfobarData() { Window *window = GetWindow(InfoBarWindowID); - if (IsActive(window)) return; - View *view = GetView(window->active_view); Buffer *buffer = GetBuffer(view->active_buffer); + if (IsActive(window)) { + if (buffer->change_frame_id == FrameID) { + ApplyInfobarChanges(window, view, buffer); + } + return; + } Window *last_window = GetWindow(GetLastActiveWindow()); View *last_view = GetActiveView(last_window); @@ -284,7 +346,7 @@ void ReplaceInfobarData() { String16 buffer_string = GetString(*buffer); Range replace_range = {0, buffer->len}; if (!Seek(buffer_string, L" |", &replace_range.max)) { - // ReplaceText(buffer, GetEndAsRange(*buffer), L" |"); + ReplaceText(buffer, GetEndAsRange(*buffer), L" |"); } // String s = Format(scratch, " %lld:%lld", (long long)xy.line + 1ll, (long long)xy.col + 1ll); diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp index 2c3096f..5446a56 100644 --- a/src/text_editor/management.cpp +++ b/src/text_editor/management.cpp @@ -39,6 +39,11 @@ inline Buffer *GetBuffer(String name) { return &Buffers[0]; } +inline Buffer *BufferNameExists(String name) { + For(Buffers) if (it.name == name) return ⁢ + return NULL; +} + inline View *GetView(ViewID id) { For(Views) if (it.id.id == id.id) return ⁢ return &Views[0]; diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index f8fe0c7..0926921 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -13,6 +13,11 @@ #include "external/stb_truetype.h" #include "external/stb_truetype.c" +SDL_Window *SDLWindow; +bool IsInFullscreen; +int FullScreenSizeX, FullScreenSizeY; +int FullScreenPositionX, FullScreenPositionY; + #include "platform/font.cpp" #include "platform/render_opengl.cpp" @@ -141,23 +146,23 @@ int main() SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window *sdl_window = SDL_CreateWindow("Text editor", 1280, 720, window_flags); - if (sdl_window == NULL) { + Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; + SDLWindow = SDL_CreateWindow("Text editor", 1280, 720, window_flags); + if (SDLWindow == NULL) { ReportErrorf("Couldn't create window! %s", SDL_GetError()); return 1; } - SDL_GLContext gl_context = SDL_GL_CreateContext(sdl_window); - SDL_GL_MakeCurrent(sdl_window, gl_context); + SDL_GLContext gl_context = SDL_GL_CreateContext(SDLWindow); + SDL_GL_MakeCurrent(SDLWindow, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync - SDL_ShowWindow(sdl_window); + SDL_ShowWindow(SDLWindow); // Set icon { uint32_t data = 0xddddddff; SDL_Surface *surface = SDL_CreateSurfaceFrom(1, 1, SDL_PIXELFORMAT_RGBA8888, &data, sizeof(uint32_t)); - SDL_SetWindowIcon(sdl_window, surface); + SDL_SetWindowIcon(SDLWindow, surface); SDL_DestroySurface(surface); } @@ -166,10 +171,10 @@ int main() return 1; } - SDL_StartTextInput(sdl_window); + SDL_StartTextInput(SDLWindow); SDL_GL_SetSwapInterval(1); // vsync { - float scale = SDL_GetWindowDisplayScale(sdl_window); + float scale = SDL_GetWindowDisplayScale(SDLWindow); if (scale != 1.0f) DPIScale = scale; } @@ -232,7 +237,7 @@ int main() WaitForEvents = true; int window_x, window_y; - SDL_GetWindowSize(sdl_window, &window_x, &window_y); + SDL_GetWindowSize(SDLWindow, &window_x, &window_y); WindowSize = {(float)window_x, (float)window_y}; BeginFrameRender(); LayoutWindows(); @@ -271,7 +276,7 @@ int main() Buffer *buffer = GetBuffer(view->active_buffer); const char *dirty = buffer->dirty ? "!" : ""; Format(scratch, "%.*s%s", buffer->name, dirty); - SDL_SetWindowTitle(sdl_window, buffer->name.data); + SDL_SetWindowTitle(SDLWindow, buffer->name.data); } ReplaceInfobarData(); ReplaceDebugData(); @@ -310,10 +315,10 @@ int main() DrawWindow(window); } EndFrameRender(ColorBackground); - SDL_GL_SwapWindow(sdl_window); + SDL_GL_SwapWindow(SDLWindow); } - SDL_DestroyWindow(sdl_window); + SDL_DestroyWindow(SDLWindow); SDL_Quit(); EndProfiler(); diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index c838fd2..87cfd09 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -24,6 +24,7 @@ struct Buffer { BufferID id; String name; Int change_id; + Int change_frame_id; union { U16 *data; diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index e89db5b..e73c6d5 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -1,6 +1,5 @@ - Windows - Mark windows as absolute or non-automatic layout and then just loop through windows - - Remove view children, replace with view history - layouting, resize windows - column based, choose number of columns and then evenly split - we can adjust sizes using mouse - maybe we can use first line number to use the window? @@ -9,12 +8,10 @@ - is this even practical if we have tab based design? - this would allow to create new windows just like that to inform user and so on - window borders as flag - - You should be able to edit buffer name, column and line in info bar which would apply to the last open view. Make sure name is unique - Implement console buffer mimicking vscode with ctrl+~ etc. - Reverse order of append in console buffer - it should be appending from top to bottom and scrolling - Modify error popups to not focus, introduce a interaction timer which after some time will make window invisible - Implement shell interaction in a console buffer - - Fullscreen - files - load directory @@ -29,7 +26,6 @@ - execution - experiment with using multiple cursors to select command and it's input - - - mouse - open selected string or auto enclosed word when right clicking or middle (this needs to be also handled on keyboard level)