diff --git a/src/basic/basic.h b/src/basic/basic.h index 61dcfc2..83b7345 100644 --- a/src/basic/basic.h +++ b/src/basic/basic.h @@ -1456,6 +1456,18 @@ String SkipToLastPeriod(String s) { return result; } +String CutPrefix(String *string, int64_t len) { + String result = GetPrefix(*string, len); + *string = Skip(*string, len); + return result; +} + +String CutPostfix(String *string, int64_t len) { + String result = GetPostfix(*string, len); + *string = Chop(*string, len); + return result; +} + String Merge(Allocator allocator, Array list, String separator = " ") { int64_t char_count = 0; For(list) char_count += it.len; diff --git a/src/basic/math_int.cpp b/src/basic/math_int.cpp index dc7bdee..405014e 100644 --- a/src/basic/math_int.cpp +++ b/src/basic/math_int.cpp @@ -8,11 +8,14 @@ struct Rect2I { Vec2I max; }; -struct Color { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; +union Color { + struct { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + uint32_t value; }; Vec2I GetSize(Rect2I r) { diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index 4b517be..6ef7f92 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -169,6 +169,7 @@ void ReplaceText(Buffer *buffer, Range range, String16 string) { Assert(range.max >= 0 && range.max <= buffer->len); Assert(range.min >= 0 && range.min <= buffer->len); buffer->dirty = true; + buffer->change_id += 1; Int size_to_remove = range.max - range.min; Int size_to_add = string.len; diff --git a/src/text_editor/commands_window.cpp b/src/text_editor/commands_window.cpp index bc3f6be..ffe6da8 100644 --- a/src/text_editor/commands_window.cpp +++ b/src/text_editor/commands_window.cpp @@ -81,19 +81,25 @@ void Command_MoveCursorsToSide(Window *window, int direction, bool shift = false } } -void Command_Delete(View *_view, int direction, bool ctrl = false) { +void Command_Delete(View *view, int direction, bool ctrl = false) { Assert(direction == DIR_LEFT || direction == DIR_RIGHT); - View &view = *_view; - Buffer *buffer = GetBuffer(view.active_buffer); + Scratch scratch; + Buffer *buffer = GetBuffer(view->active_buffer); + + BeforeEdit(buffer, view->carets); // Select things to delete - For(view.carets) { + For(view->carets) { if (GetSize(it.range)) continue; Int pos = MovePos(*buffer, it.range.min, direction, ctrl); it = MakeCaret(pos, it.range.min); } - Command_Replace(&view, {}); + MergeCarets(view); + Array edits = {scratch}; + For(view->carets) AddEdit(&edits, it.range, {}); + ApplyEdits(buffer, edits); + AfterEdit(buffer, &edits, &view->carets); } void Command_SelectAll(View *view, String16 needle) { @@ -163,9 +169,9 @@ void Command_EvalLua(View *view, String16 string) { } else { { Window *window = GetWindow(GetLastActiveWindow()); - View *view = GetView(window->active_view); SetActiveWindow(window->id); - Command_Replace(view, eval_result); + // View *view = GetView(window->active_view); + // Command_Replace(view, eval_result); } Range range = GetLineRangeWithoutNL(*buffer, 0); @@ -538,6 +544,7 @@ void WindowCommand(Event event, Window *window, View *view) { String string = ToString(scratch, string16); bool success = WriteFile(buffer->name, string); if (success) { + buffer->dirty = false; } else { String msg = Format(scratch, "Failed to save file with name: %.*s", FmtString(buffer->name)); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Failed to save!", msg.data, NULL); diff --git a/src/text_editor/lua_api.cpp b/src/text_editor/lua_api.cpp index 1cf4fba..beb0226 100644 --- a/src/text_editor/lua_api.cpp +++ b/src/text_editor/lua_api.cpp @@ -135,4 +135,23 @@ String16 EvalString(Allocator allocator, String16 string16) { } else { return {}; } +} + +Color GetColor(String name) { + Color result = {0xFF, 0, 0xFF, 0xFF}; + lua_getglobal(LuaState, "Color"); + defer { lua_pop(LuaState, 1); }; + if (lua_istable(LuaState, -1)) { + lua_pushlstring(LuaState, name.data, name.len); + lua_gettable(LuaState, -2); + defer { lua_pop(LuaState, 1); }; + if (lua_isnumber(LuaState, -1)) { + lua_Integer num = lua_tointeger(LuaState, -1); + result.r = (uint8_t)((0xFF000000 & num) >> 24); + result.g = (uint8_t)((0x00FF0000 & num) >> 16); + result.b = (uint8_t)((0x0000FF00 & num) >> 8); + result.a = (uint8_t)((0x000000FF & num) >> 0); + } + } + return result; } \ No newline at end of file diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index 6d75eb7..c5972df 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -30,12 +30,12 @@ #include "commands_clipboard.cpp" #include "commands_window.cpp" -#include "colors.cpp" -#include "window_draw.cpp" - #include "lua.hpp" #include "lua_api.cpp" +#include "colors.cpp" +#include "window_draw.cpp" + void HandleEvent(Event event) { bool run_window_command = GlobalCommand(event); if (run_window_command) { @@ -104,6 +104,63 @@ void ProcessSDLEvent(SDL_Event *input_event) { HandleEvent(event); } +uint64_t MapCharToNumber(char c) { + switch (c) { + case '0': return 0; break; + case '1': return 1; break; + case '2': return 2; break; + case '3': return 3; break; + case '4': return 4; break; + case '5': return 5; break; + case '6': return 6; break; + case '7': return 7; break; + case '8': return 8; break; + case '9': return 9; break; + case 'a': + case 'A': return 10; break; + case 'b': + case 'B': return 11; break; + case 'c': + case 'C': return 12; break; + case 'd': + case 'D': return 13; break; + case 'e': + case 'E': return 14; break; + case 'f': + case 'F': return 15; break; + default: return 255; + } +} + +uint64_t ParseInt(char *string, uint64_t len, uint64_t base) { + Assert(base >= 2 && base <= 16); + uint64_t acc = 0; + for (uint64_t i = 0; i < len; i++) { + uint64_t num = MapCharToNumber(string[i]); + if (num >= base) { + // @todo: error + return 0; + } + acc *= base; + acc += num; + } + return acc; +} + +Color ParseColor(String string) { + Color result = {0xFF, 0xFF, 0, 0xFF}; + String hex = CutPrefix(&string, 1); + String red = CutPrefix(&string, 2); + result.r = (uint8_t)ParseInt(red.data, red.len, 16); + String green = CutPrefix(&string, 2); + result.g = (uint8_t)ParseInt(green.data, green.len, 16); + String blue = CutPrefix(&string, 2); + result.b = (uint8_t)ParseInt(blue.data, blue.len, 16); + String alpha = CutPrefix(&string, 2); + result.a = (uint8_t)ParseInt(alpha.data, alpha.len, 16); + return result; +} + #if _WIN32 int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nShowCmd) #else @@ -115,6 +172,7 @@ int main() InitScratch(); InitArena(&Perm); WorkingDir = GetWorkingDir(Perm); + ExeDir = GetExeDir(Perm); if (SDL_Init(SDL_INIT_VIDEO) == -1) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); @@ -161,7 +219,27 @@ int main() ReloadFont(16); InitLua(); + Buffer *lua_buffer = NULL; + Int lua_buffer_change_id = 0; + { + Allocator sys_allocator = GetSystemAllocator(); + Buffer *buffer = CreateBuffer(sys_allocator, "*scratch*"); + View *view = CreateView(buffer->id); + + Scratch scratch; + String lua_config_path = Format(scratch, "%.*s/init.lua", FmtString(ExeDir)); + lua_buffer = BufferOpenFile(lua_config_path); + String16 string16 = GetString(*lua_buffer); + String string = ToString(scratch, string16); + if (luaL_dostring(LuaState, string.data) == LUA_OK) { + } else { + __debugbreak(); + } + lua_buffer_change_id = lua_buffer->change_id; + } + InitWindows(); + while (AppIsRunning) { FrameID += 1; int window_x, window_y; @@ -204,6 +282,16 @@ int main() ReplaceInfobarData(); ReplaceDebugbarData(); + if (lua_buffer->dirty == false && lua_buffer->change_id != lua_buffer_change_id) { + Scratch scratch; + String16 string16 = GetString(*lua_buffer); + String string = ToString(scratch, string16); + if (luaL_dostring(LuaState, string.data) == LUA_OK) { + } else { + } + lua_buffer_change_id = lua_buffer->change_id; + } + For(IterateInReverse(&order)) { Window *window = &Windows[it]; { diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 8e8cb5f..e46e8e5 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -23,6 +23,7 @@ struct HistoryEntry { struct Buffer { BufferID id; String name; + Int change_id; union { U16 *data; @@ -90,6 +91,7 @@ struct Scroller { Int FrameID; String WorkingDir; +String ExeDir; Arena Perm; String16 EvalString(Allocator allocator, String16 string16); diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index a87ec1e..139db51 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -1,4 +1,5 @@ - Save file (utf16->utf8) + - make sure we only save file buffers - Some kind of plumbing, linking - resize windows - laying out windows, more choice diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index c36c1af..c2f6426 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -8,10 +8,6 @@ Array GetWindowZOrder(Allocator allocator) { void InitWindows() { Allocator sys_allocator = GetSystemAllocator(); - { - Buffer *buffer = CreateBuffer(sys_allocator, "*scratch*"); - View *view = CreateView(buffer->id); - } { Window *w = CreateWindow(); diff --git a/src/text_editor/window_draw.cpp b/src/text_editor/window_draw.cpp index eccb2f3..094c01b 100644 --- a/src/text_editor/window_draw.cpp +++ b/src/text_editor/window_draw.cpp @@ -40,7 +40,7 @@ Scroller ComputeScrollerRect(Window *window) { void DrawVisibleText(Window *window) { ProfileFunction(); - Color tint = ColorText; + Color tint = GetColor("Text"); View *view = GetActiveView(window); Buffer *buffer = GetBuffer(view->active_buffer); @@ -125,11 +125,11 @@ void DrawWindow(Window *window) { DrawRect(rect, ColorSelection); if (line_string[col] == ' ' || line_string[col] == '\t') { - DrawCircle({pos.x + (float)FontCharSpacing / 2.f, (float)pos.y - MainFont.ascent / 2.f}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); + DrawCircle({pos.x + (float)FontCharSpacing / 2.f, (float)pos.y + MainFont.ascent - MainFont.descent}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); } else if (line_string[col] == '\n') { - DrawCircle({pos.x + (float)FontCharSpacing / 2.f, pos.y - MainFont.ascent / 2.f}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); + DrawCircle({pos.x + (float)FontCharSpacing / 2.f, pos.y + MainFont.ascent - MainFont.descent}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); } else if (line_string[col] == '\r') { - DrawCircle({pos.x + (float)FontCharSpacing / 2.f, pos.y - MainFont.ascent / 2.f}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); + DrawCircle({pos.x + (float)FontCharSpacing / 2.f, pos.y + MainFont.ascent - MainFont.descent}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); } } }