From 0ebfedbf4db6d0d1cbeb0f6d381586a2c6f98c17 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Tue, 23 Jul 2024 16:49:13 +0200 Subject: [PATCH] Lua and better cursor movement --- build_file.cpp | 27 +++++++++++++++ src/text_editor/buffer.cpp | 51 ++++++++++++++++++++++++++--- src/text_editor/commands.cpp | 34 ++++++++++++++----- src/text_editor/commands_window.cpp | 7 +++- src/text_editor/lua_api.cpp | 32 ++++++++++++++++++ src/text_editor/string16.cpp | 5 +++ src/text_editor/text_editor.cpp | 26 ++++++++++----- src/text_editor/text_editor.h | 2 ++ src/text_editor/window.cpp | 3 +- src/text_editor/window_draw.cpp | 1 + 10 files changed, 164 insertions(+), 24 deletions(-) create mode 100644 src/text_editor/lua_api.cpp diff --git a/build_file.cpp b/build_file.cpp index 52168a7..b747335 100644 --- a/build_file.cpp +++ b/build_file.cpp @@ -48,6 +48,32 @@ Library PrepareRaylib() { return l; } +Library PrepareLua() { + Library l = {}; + l.include_paths.add("../src/external/lua/src"); + + MA_Scratch scratch; + for (OS_FileIter it = OS_IterateFiles(scratch, "../src/external/lua/src"); OS_IsValid(it); OS_Advance(&it)) { + if (it.filename == "luac.c") continue; + if (it.filename == "lua.c") continue; + if (S8_EndsWith(it.filename, ".c", true)) { + l.sources.add(it.absolute_path); + S8_String file = S8_ChopLastPeriod(it.filename); + l.objects.add(Fmt("%.*s.obj", S8_Expand(file))); + } + } + + if (!OS_FileExists(l.objects[0])) { + Array cmd = {}; + cmd.add("cl.exe -c"); + AddCommonFlags(&cmd); + For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it))); + cmd += l.sources; + Run(cmd); + } + return l; +} + Library PrepareGlad() { Library l = {}; l.sources.add("../src/external/glad/glad.c"); @@ -69,6 +95,7 @@ int CompileTextEditor() { Array libs = {}; libs.add(PrepareRaylib()); + libs.add(PrepareLua()); Array cmd = {}; cmd.add("cl.exe"); diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index 8ec6e66..867b924 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -3,17 +3,17 @@ https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation */ #define BUFFER_DEBUG 0 -void InitBuffer(Allocator allocator, Buffer *buffer) { +void InitBuffer(Allocator allocator, Buffer *buffer, Int size = 4096) { buffer->id = AllocBufferID(); - buffer->cap = 4096; + buffer->cap = size; buffer->data = AllocArray(allocator, U16, buffer->cap); buffer->line_starts.allocator = allocator; Add(&buffer->line_starts, (Int)0); } -Buffer *CreateBuffer(Allocator allocator) { +Buffer *CreateBuffer(Allocator allocator, Int size = 4096) { Buffer *result = Alloc(&Buffers); - InitBuffer(allocator, result); + InitBuffer(allocator, result, size); return result; } @@ -188,6 +188,49 @@ void ReplaceText(Buffer *buffer, Range range, String16 string) { #endif } +Buffer *OpenFile(String path) { + Scratch scratch; + String string = ReadFile(scratch, path); + + Allocator sys_allocator = GetSystemAllocator(); + Buffer *buffer = CreateBuffer(sys_allocator, string.len * 4); + + for (Int i = 0; i < string.len;) { + if (string.data[i] == '\r') { + i += 1; + continue; + } + if (string.data[i] == '\t') { + // @WARNING: DONT INCREASE THE SIZE CARELESSLY, WE NEED TO ADJUST BUFFER SIZE + for (Int i = 0; i < 4; i += 1) buffer->data[buffer->len++] = L' '; + i += 1; + continue; + } + + uint32_t u32 = '?'; + UTF32Result decode = UTF8ToUTF32(string.data + i, (int64_t)(string.len - i)); + if (!decode.error) { + i += decode.advance; + u32 = decode.out_str; + } else { + i += 1; + } + + UTF16Result encode = UTF32ToUTF16(decode.out_str); + if (!encode.error) { + for (int64_t encode_i = 0; encode_i < encode.len; encode_i += 1) { + buffer->data[buffer->len++] = encode.out_str[encode_i]; + Assert(buffer->len < buffer->cap); + } + } else { + buffer->data[buffer->len++] = L'?'; + } + } + UpdateLines(buffer, {}, String16{(wchar_t *)buffer->data, buffer->len}); + + return buffer; +} + void TestBuffer() { Scratch scratch; { diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index d4caabe..0e7524b 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -63,18 +63,27 @@ bool IsDoubleClick() { Int MoveOnWhitespaceBoundaryForward(Buffer &buffer, Int pos) { pos = Clamp(pos, (Int)0, buffer.len); bool standing_on_whitespace = IsWhitespace(buffer.str[pos]); + bool standing_on_symbol = IsSymbol(buffer.str[pos]); + bool standing_on_word = !standing_on_whitespace && !standing_on_symbol; bool seek_whitespace = standing_on_whitespace == false; - bool seek_word = standing_on_whitespace; + bool seek_word = standing_on_whitespace || standing_on_symbol; + bool seek_symbol = standing_on_whitespace || standing_on_word; Int result = buffer.len; Int prev_pos = pos; for (Int i = pos; i < buffer.len; i += 1) { - bool whitespace = IsWhitespace(buffer.str[i]); - if (seek_word && !whitespace) { + bool is_whitespace = IsWhitespace(buffer.str[i]); + bool is_symbol = IsSymbol(buffer.str[i]); + bool is_word = !is_whitespace && !is_symbol; + if (seek_word && is_word) { result = i; break; } - if (seek_whitespace && whitespace) { + if (seek_whitespace && is_whitespace) { + result = i; + break; + } + if (seek_symbol && is_symbol) { result = i; break; } @@ -86,18 +95,27 @@ Int MoveOnWhitespaceBoundaryForward(Buffer &buffer, Int pos) { Int MoveOnWhitespaceBoundaryBackward(Buffer &buffer, Int pos) { pos = Clamp(pos - 1, (Int)0, buffer.len); bool standing_on_whitespace = IsWhitespace(buffer.str[pos]); + bool standing_on_symbol = IsSymbol(buffer.str[pos]); + bool standing_on_word = !standing_on_whitespace && !standing_on_symbol; bool seek_whitespace = standing_on_whitespace == false; - bool seek_word = standing_on_whitespace; + bool seek_word = standing_on_whitespace || standing_on_symbol; + bool seek_symbol = standing_on_whitespace || standing_on_word; Int result = 0; Int prev_pos = pos; for (Int i = pos; i >= 0; i -= 1) { - bool whitespace = IsWhitespace(buffer.str[i]); - if (seek_word && !whitespace) { + bool is_whitespace = IsWhitespace(buffer.str[i]); + bool is_symbol = IsSymbol(buffer.str[i]); + bool is_word = !is_whitespace && !is_symbol; + if (seek_word && is_word) { result = prev_pos; break; } - if (seek_whitespace && whitespace) { + if (seek_whitespace && is_whitespace) { + result = prev_pos; + break; + } + if (seek_symbol && is_symbol) { result = prev_pos; break; } diff --git a/src/text_editor/commands_window.cpp b/src/text_editor/commands_window.cpp index 56a185a..f382a34 100644 --- a/src/text_editor/commands_window.cpp +++ b/src/text_editor/commands_window.cpp @@ -271,7 +271,12 @@ void HandleActiveWindowBindings(Window *window) { Command_MoveCursorsToSide(window, DIR_RIGHT); } - if (window->banish_new_lines == false && Press(KEY_ENTER)) { + if (CtrlPress(KEY_ENTER)) { + Int line = PosToLine(*buffer, GetFront(view.carets[0])); + Range range = GetLineRange(*buffer, line); + String16 string = GetString(*buffer, range); + EvalString(string); + } else if (window->banish_new_lines == false && Press(KEY_ENTER)) { Command_Replace(&view, L"\n"); } diff --git a/src/text_editor/lua_api.cpp b/src/text_editor/lua_api.cpp new file mode 100644 index 0000000..7535260 --- /dev/null +++ b/src/text_editor/lua_api.cpp @@ -0,0 +1,32 @@ +lua_State *LuaState = NULL; + +int LuaOpenFile(lua_State *L) { + const char *text = luaL_checkstring(L, 1); + String string = text; + Buffer *buffer = OpenFile(string); + View *view = CreateView(buffer->id); + Window *window = GetWindow({1}); + AddView(window, view->id); + window->active_view = view->id; + SetActiveWindow(window->id); + return 0; // number of results +} + +void InitLua() { + LuaState = luaL_newstate(); + luaL_openlibs(LuaState); + + lua_pushcfunction(LuaState, LuaOpenFile); + lua_setglobal(LuaState, "open"); +} + +void EvalString(String16 string16) { + if (!LuaState) InitLua(); + Scratch scratch; + String string = ToString(scratch, string16); + if (luaL_dostring(LuaState, string.data) != LUA_OK) { + const char *text = lua_tostring(LuaState, -1); + printf("lua error: %s", text); + } + // @todo: send error or data to some buffer +} \ No newline at end of file diff --git a/src/text_editor/string16.cpp b/src/text_editor/string16.cpp index bef8ce1..4a2266d 100644 --- a/src/text_editor/string16.cpp +++ b/src/text_editor/string16.cpp @@ -13,6 +13,11 @@ bool IsWhitespace(wchar_t w) { return result; } +bool IsSymbol(wchar_t w) { + bool result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~'); + return result; +} + bool IsAlphabetic(wchar_t a) { bool result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); return result; diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index cd84e85..961792c 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -1,5 +1,6 @@ #define BASIC_IMPL #include "../basic/basic.h" +#include "../basic/filesystem.h" #include "../profiler/profiler.cpp" #include "new_basic.cpp" #include "string16.cpp" @@ -24,17 +25,25 @@ #include "window.cpp" #include "window_draw.cpp" +#include "lua.hpp" +#include "lua_api.cpp" + /* - Open file (utf8->utf16), process determine line endings, tabs to spaces?, Save file (utf16->utf8) + - line endings - resize windows - command window - maybe use lua and have there be lua commands that you choose with cursor - open "asd/asd/asd/asd" +- file dock on left side + - We can actually combine this with command window and lua, it's just going to be a buffer of + - open "asd/asd/asd/asd" + +- Ctrl + F +- Better enclosure and word hopping -- line endings - word completion - Colored strings -- file dock on left side - move off raylib - Adjust text position a little bit down? @@ -79,7 +88,7 @@ int main(void) { View *view = CreateView(buffer->id); Window *window = CreateWindow(); window->visible = false; - AddView(window->id, view->id); + AddView(window, view->id); } { @@ -87,7 +96,7 @@ int main(void) { Buffer *b = CreateBuffer(sys_allocator); View *v = CreateView(b->id); LoadTextA(b); - AddView(w->id, v->id); + AddView(w, v->id); } ActiveWindow.id = 1; @@ -96,14 +105,13 @@ int main(void) { Buffer *b = CreateBuffer(sys_allocator); View *v = CreateView(b->id); LoadUnicode(b); - AddView(w->id, v->id); + AddView(w, v->id); } { Window *w = CreateWindow(); - Buffer *b = CreateBuffer(sys_allocator); + Buffer *b = OpenFile("C:/Work/text_editor/src/text_editor/text_editor.cpp"); View *v = CreateView(b->id); - LoadLine(b); - AddView(w->id, v->id); + AddView(w, v->id); } { Window *w = CreateWindow(); @@ -114,7 +122,7 @@ int main(void) { Buffer *b = CreateBuffer(sys_allocator); View *v = CreateView(b->id); LoadLine(b); - AddView(w->id, v->id); + AddView(w, v->id); CommandWindowID = w->id; } diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 201a5a3..80defd9 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -134,3 +134,5 @@ inline View *GetActiveView(Window *window) { if (window->active_view.id == 0) return GetView(window->views[0]); else return GetView(window->active_view); } + +void EvalString(String16 string16); \ No newline at end of file diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index c858cd7..52fba80 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -8,8 +8,7 @@ Window *CreateWindow() { return w; } -void AddView(WindowID window, ViewID view) { - Window *w = GetWindow(window); +void AddView(Window *w, ViewID view) { if (w->active_view.id == 0) w->active_view = view; For(w->views) if (it.id == view.id) return; Add(&w->views, view); diff --git a/src/text_editor/window_draw.cpp b/src/text_editor/window_draw.cpp index 8c31ca2..45b8b0d 100644 --- a/src/text_editor/window_draw.cpp +++ b/src/text_editor/window_draw.cpp @@ -52,6 +52,7 @@ void DrawVisibleText(Window &window) { Vec2I pos = {visible.min.x * (Int)FontCharSpacing, line_index * (Int)FontLineSpacing}; pos -= view.scroll; pos += window.document_rect.min; + // pos.y += (Int)(0.3 * (double)FontSize); // @todo: descent float text_offset_x = 0; for (Int col_index = visible.min.x; col_index < visible.max.x && col_index >= 0 && col_index < line_string.len; col_index += 1) {