restructuring

This commit is contained in:
Krzosa Karol
2025-12-14 10:32:42 +01:00
parent 0424ca62f2
commit a351d2eb41
20 changed files with 1076 additions and 1043 deletions

View File

@@ -388,7 +388,7 @@ GLuint UploadAtlas(Atlas *atlas) {
return tex;
}
void ReloadFont() {
void ReloadFont(String path, U32 size) {
if (PrimaryFont.texture_id) {
glDeleteTextures(1, &PrimaryFont.texture_id);
Dealloc(&PrimaryFont.glyphs);
@@ -397,7 +397,7 @@ void ReloadFont() {
Scratch scratch;
Atlas atlas = CreateAtlas(scratch, {2048, 2048});
PrimaryFont = CreateFont(&atlas, (uint32_t)ClampBottom(2u, (U32)StyleFontSize), StyleFont);
SecondaryFont = CreateFont(&atlas, 12, StyleFont);
PrimaryFont = CreateFont(&atlas, (uint32_t)ClampBottom(2u, (U32)size), path);
SecondaryFont = CreateFont(&atlas, 12, path);
SecondaryFont.texture_id = PrimaryFont.texture_id = UploadAtlas(&atlas);
}

View File

@@ -1202,7 +1202,6 @@ API void DeinitBuffer(Buffer *buffer) {
// Indexing starts from 0 not 1 because this routine creates also the zero buffer
// which is the buffer that often is defaulted to in case of errors
Int BufferIDs;
API Buffer *AllocBuffer(Allocator allocator, String name = "", Int size = 4096) {
Buffer *buffer = AllocType(allocator, Buffer);
buffer->id = {BufferIDs++, buffer};
@@ -1401,6 +1400,167 @@ void RunBufferTest() {
DeinitBuffer(&buffer);
TrackingAllocatorCheck();
}
}
///////////////////////////////
// Management
inline BufferID AllocBufferID(Buffer *buffer) {
return {BufferIDs++, buffer};
}
}
inline Buffer *GetBuffer(BufferID id) {
For(Buffers) {
if (it->id == id) return it;
}
return Buffers[0];
}
inline Buffer *FindBuffer(BufferID id) {
For(Buffers) {
if (it->id == id) return it;
}
return NULL;
}
inline Buffer *GetBuffer(String name) {
For(Buffers) {
if (it->name == name) return it;
}
return Buffers[0];
}
inline Buffer *FindBuffer(String name) {
For(Buffers) {
if (it->name == name) return it;
}
return NULL;
}
inline bool IsNull(Buffer *buffer) {
return buffer->id.id == 0;
}
Buffer *CreateBuffer(Allocator allocator, String name, Int size) {
Buffer *result = AllocBuffer(allocator, name, size);
Add(&Buffers, result);
return result;
}
String GetUniqueBufferName(String working_dir, String prepend_name, String extension = ".log") {
Scratch scratch;
String buffer_name = {};
for (int i = 1; i < INT_MAX; i += 1) {
buffer_name = Format(scratch, "%S/%S%d%S", working_dir, prepend_name, i, extension);
buffer_name = GetAbsolutePath(scratch, buffer_name);
Buffer *exists = FindBuffer(buffer_name);
if (!exists && !FileExists(buffer_name)) {
break;
}
}
buffer_name = Intern(&GlobalInternTable, buffer_name);
return buffer_name;
}
void InitBuffers() {
Allocator sys_allocator = GetSystemAllocator();
Scratch scratch;
Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(GetWorkingDir(scratch), "console"));
View *null_view = CreateView(null_buffer->id);
Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID);
TraceBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "trace"));
TraceView = CreateView(TraceBuffer->id);
GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "gc"));
EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "events"));
ScratchBuffer = BufferOpenFile(GetUniqueBufferName(WorkDir, "scratch"));
EventBuffer->no_history = true;
GCInfoBuffer->no_history = true;
}
Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) {
if (string.len == 0) {
return 0;
}
Int buffer_len = 0;
Assert(buffer_cap > string.len * 2);
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[buffer_len++] = u' ';
i += 1;
continue;
}
uint32_t u32 = '?';
UTF32Result decode = UTF8ToUTF32((uint8_t *)(string.data + i), (int64_t)(string.len - i));
if (!decode.error) {
i += decode.advance;
u32 = decode.out_str;
} else {
i += 1;
}
UTF16Result encode = UTF32ToUTF16(u32);
if (!encode.error) {
for (int64_t encode_i = 0; encode_i < encode.len; encode_i += 1) {
buffer[buffer_len++] = encode.out_str[encode_i];
Assert(buffer_len < buffer_cap);
}
} else {
buffer[buffer_len++] = u'?';
}
}
return buffer_len;
}
String16 ToUnixString16(Allocator allocator, String string_) {
Int cap = string_.len * 3;
char16_t *string16_buffer = AllocArray(allocator, char16_t, cap);
Int len = ConvertUTF8ToUTF16UnixLine(string_, string16_buffer, cap);
String16 string = {string16_buffer, len};
return string;
}
Buffer *BufferOpenFile(String path) {
Allocator sys_allocator = GetSystemAllocator();
Scratch scratch;
path = GetAbsolutePath(scratch, path);
Buffer *buffer = GetBuffer(path);
if (!IsNull(buffer) || (IsNull(buffer) && buffer->name == path)) {
return buffer;
}
if (!FileExists(path)) {
buffer = CreateBuffer(sys_allocator, path);
} else if (IsDir(path)) {
ReportWarningf("failed to open, it's a directory: %S", path);
return GetBuffer(NullBufferID);
} else {
String string = ReadFile(scratch, path);
buffer = CreateBuffer(sys_allocator, path, string.len * 4 + 4096);
buffer->len = ConvertUTF8ToUTF16UnixLine(string, buffer->str, buffer->cap);
buffer->file_mod_time = GetFileModTime(path);
UpdateLines(buffer, {}, String16{(char16_t *)buffer->data, buffer->len});
}
return buffer;
}
bool BufferIsReferenced(BufferID buffer_id) {
if (buffer_id == NullBufferID) {
return true;
}
if (FindView(buffer_id)) {
return true;
}
return false;
}

View File

@@ -160,4 +160,5 @@ API void UndoEdit(Buffer *buffer, Array<Caret> *carets);
API void ResetHistory(Buffer *buffer);
API void DeallocHistoryArray(Array<HistoryEntry> *entries);
API void DeallocHistoryEntries(Array<HistoryEntry> *entries);
API void DeallocHistoryEntries(Array<HistoryEntry> *entries);

View File

@@ -524,12 +524,12 @@ void OnCommand(Event event) {
if (CtrlPress(SDLK_EQUALS)) {
StyleFontSize += 1;
ReloadFont();
ReloadFont(StyleFont, (U32)StyleFontSize);
}
if (CtrlPress(SDLK_MINUS)) {
if (StyleFontSize > 4) {
StyleFontSize -= 1;
ReloadFont();
ReloadFont(StyleFont, (U32)StyleFontSize);
}
}

View File

@@ -1,60 +1,3 @@
#define EVENT_KINDS \
X(EVENT_NONE) \
X(EVENT_UPDATE) \
X(EVENT_QUIT) \
X(EVENT_MOUSE_LEFT) \
X(EVENT_MOUSE_RIGHT) \
X(EVENT_MOUSE_MIDDLE) \
X(EVENT_MOUSE_X1) \
X(EVENT_MOUSE_X2) \
X(EVENT_MOUSE_LEFT_UP) \
X(EVENT_MOUSE_RIGHT_UP) \
X(EVENT_MOUSE_MIDDLE_UP) \
X(EVENT_MOUSE_X1_UP) \
X(EVENT_MOUSE_X2_UP) \
X(EVENT_MOUSE_WHEEL) \
X(EVENT_KEY_PRESS) \
X(EVENT_TEXT_INPUT) \
X(EVENT_DROP_FILE)
enum EventKind {
#define X(TYPE) TYPE,
EVENT_KINDS
#undef X
EVENT_KIND_COUNT,
EVENT_KIND_INVALID = 111,
};
const char *EventKindStrings[] = {
#define X(TYPE) #TYPE,
EVENT_KINDS
#undef X
};
#define EVENT_FIELDS \
X(EventKind, Int, kind) \
X(SDL_Keycode, Int, key) \
X(int16_t, Int, xwindow) \
X(int16_t, Int, ywindow) \
X(int16_t, Int, xmouse) \
X(int16_t, Int, ymouse) \
X(uint8_t, Int, clicks) \
X(uint8_t, Int, shift) \
X(uint8_t, Int, ctrl) \
X(uint8_t, Int, alt) \
X(uint8_t, Int, super) \
X(float, Float, xwheel) \
X(float, Float, ywheel) \
X(char *, String, text)
#define EVENT_FIELD_COUNT 14
struct Event {
#define X(TYPE, KIND, NAME) TYPE NAME;
EVENT_FIELDS
#undef X
};
Array<Event> EventPlayback;
const char *SDLKeycodeToName(SDL_Keycode keycode) {
switch(keycode) {
case SDLK_UNKNOWN: return "SDLK_UNKNOWN"; break;
@@ -317,6 +260,145 @@ const char *SDLKeycodeToName(SDL_Keycode keycode) {
}
}
void FillEventWithBasicData(Event *event) {
SDL_Keymod mod = SDL_GetModState();
event->shift = (mod & SDL_KMOD_SHIFT) != 0;
event->ctrl = (mod & SDL_KMOD_CTRL) != 0;
event->alt = (mod & SDL_KMOD_ALT) != 0;
event->super = (mod & SDL_KMOD_GUI) != 0;
float xmouse, ymouse;
SDL_GetMouseState(&xmouse, &ymouse);
event->xmouse = (int16_t)xmouse;
event->ymouse = (int16_t)ymouse;
int xwindow, ywindow;
SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow);
event->xwindow = xwindow;
event->ywindow = ywindow;
event->text = "";
}
Event TranslateSDLEvent(SDL_Event *input_event) {
ProfileFunction();
Event event = {};
FillEventWithBasicData(&event);
switch (input_event->type) {
case SDL_EVENT_QUIT: {
event.kind = EVENT_QUIT;
} break;
case SDL_EVENT_KEY_DOWN: {
event.kind = EVENT_KEY_PRESS;
SDL_KeyboardEvent &key = input_event->key;
event.key = key.key;
} break;
case SDL_EVENT_TEXT_INPUT: {
event.kind = EVENT_TEXT_INPUT;
SDL_TextInputEvent &b = input_event->text;
String string = b.text;
event.text = Intern(&GlobalInternTable, string).data;
} break;
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
SDL_MouseButtonEvent &b = input_event->button;
event.xmouse = (int16_t)b.x;
event.ymouse = (int16_t)b.y;
event.clicks = b.clicks;
if (b.button == SDL_BUTTON_LEFT) {
event.kind = EVENT_MOUSE_LEFT;
} else if (b.button == SDL_BUTTON_RIGHT) {
event.kind = EVENT_MOUSE_RIGHT;
} else if (b.button == SDL_BUTTON_MIDDLE) {
event.kind = EVENT_MOUSE_MIDDLE;
} else if (b.button == SDL_BUTTON_X1) {
event.kind = EVENT_MOUSE_X1;
} else if (b.button == SDL_BUTTON_X2) {
event.kind = EVENT_MOUSE_X2;
} else {
event.kind = EVENT_NONE;
event.clicks = 0;
}
} break;
case SDL_EVENT_MOUSE_BUTTON_UP: {
SDL_MouseButtonEvent &b = input_event->button;
event.xmouse = (int16_t)b.x;
event.ymouse = (int16_t)b.y;
if (b.button == SDL_BUTTON_LEFT) {
event.kind = EVENT_MOUSE_LEFT_UP;
} else if (b.button == SDL_BUTTON_RIGHT) {
event.kind = EVENT_MOUSE_RIGHT_UP;
} else if (b.button == SDL_BUTTON_MIDDLE) {
event.kind = EVENT_MOUSE_MIDDLE_UP;
} else if (b.button == SDL_BUTTON_X1) {
event.kind = EVENT_MOUSE_X1_UP;
} else if (b.button == SDL_BUTTON_X2) {
event.kind = EVENT_MOUSE_X2_UP;
} else {
event.kind = EVENT_NONE;
}
} break;
case SDL_EVENT_MOUSE_WHEEL: {
event.kind = EVENT_MOUSE_WHEEL;
SDL_MouseWheelEvent &b = input_event->wheel;
event.xmouse = (int16_t)b.mouse_x;
event.ymouse = (int16_t)b.mouse_y;
event.xwheel = b.x;
event.ywheel = b.y;
} break;
case SDL_EVENT_MOUSE_MOTION: {
event.kind = EVENT_UPDATE;
} break;
case SDL_EVENT_DROP_FILE: {
event.kind = EVENT_DROP_FILE;
SDL_DropEvent &b = input_event->drop;
String string = b.data;
event.text = Intern(&GlobalInternTable, string).data;
} break;
default: {
};
}
return event;
}
Array<Event> GetEventsForFrame(Allocator allocator) {
Array<Event> result = {allocator};
if (EventPlayback.len) {
result = TightCopy(allocator, EventPlayback);
EventPlayback.len = 0;
}
SDL_Event event;
if (WaitForEvents) {
SDL_WaitEvent(&event);
Event ev = TranslateSDLEvent(&event);
if (ev.kind != EVENT_NONE) Add(&result, ev);
}
while (SDL_PollEvent(&event)) {
Event ev = TranslateSDLEvent(&event);
if (ev.kind != EVENT_NONE) Add(&result, ev);
}
if (result.len == 0) {
Event event = {};
FillEventWithBasicData(&event);
event.kind = EVENT_UPDATE;
Add(&result, event);
}
Assert(result.len);
return result;
}
struct Serializer {
Buffer *buffer; // for writing
};
@@ -386,17 +468,14 @@ void Serialize(Serializer *s, Event *e) {
SerializeEnd(s);
}
const int DIR_RIGHT = 0;
const int DIR_LEFT = 1;
const int DIR_DOWN = 2;
const int DIR_UP = 3;
const int DIR_COUNT = 4;
const bool CTRL_PRESSED = true;
const int DIR_RIGHT = 0;
const int DIR_LEFT = 1;
const int DIR_DOWN = 2;
const int DIR_UP = 3;
const int DIR_COUNT = 4;
const bool CTRL_PRESSED = true;
const bool SHIFT_PRESS = true;
bool AppIsRunning = true;
bool WaitForEvents = true;
#define Ctrl() event.ctrl
#define Alt() event.alt
#define Shift() event.shift

View File

@@ -1,33 +0,0 @@
void ReloadStyle() {
ColorText = GetColor("Text", ColorText);
ColorLoadTextHighlight = GetColor("LoadTextHighlight", ColorLoadTextHighlight);
ColorBackground = GetColor("Background", ColorBackground);
ColorInactiveWindow = GetColor("InactiveWindow", ColorInactiveWindow);
ColorTextLineNumbers = GetColor("TextLineNumbers", ColorTextLineNumbers);
ColorLineHighlight = GetColor("LineHighlight", ColorLineHighlight);
ColorMainCaret = GetColor("MainCaret", ColorMainCaret);
ColorSubCaret = GetColor("SubCaret", ColorSubCaret);
ColorSelection = GetColor("Selection", ColorSelection);
ColorWhitespaceDuringSelection = GetColor("WhitespaceDuringSelection", ColorWhitespaceDuringSelection);
ColorMouseUnderline = GetColor("MouseUnderline", ColorMouseUnderline);
ColorCaretUnderline = GetColor("CaretUnderline", ColorCaretUnderline);
ColorFuzzySearchLineHighlight = GetColor("FuzzySearchLineHighlight", ColorFuzzySearchLineHighlight);
ColorScrollbarBackground = GetColor("ScrollbarBackground", ColorScrollbarBackground);
ColorScrollbarScroller = GetColor("ScrollbarScroller", ColorScrollbarScroller);
ColorScrollbarScrollerSelected = GetColor("ScrollbarScrollerSelected", ColorScrollbarScrollerSelected);
ColorTitleBarText = GetColor("TitleBarText", ColorTitleBarText);
ColorTitleBarBackground = GetColor("TitleBarBackground", ColorTitleBarBackground);
ColorTitleBarActiveBackground = GetColor("TitleBarActiveBackground", ColorTitleBarActiveBackground);
ColorTitleBarSelection = GetColor("TitleBarSelection", ColorTitleBarSelection);
ColorResizerBackground = GetColor("ResizerBackground", ColorResizerBackground);
ColorResizerOutline = GetColor("ResizerOutline", ColorResizerOutline);
StyleWaitForEvents = GetStyleInt("WaitForEvents", StyleWaitForEvents);
StyleDrawLineNumbers = GetStyleInt("DrawLineNumbers", StyleDrawLineNumbers);
StyleDrawScrollbar = GetStyleInt("DrawScrollbar", StyleDrawScrollbar);
StyleIndentSize = GetStyleInt("IndentSize", StyleIndentSize);
StyleFontSize = GetStyleInt("FontSize", StyleFontSize);
StyleFontFilter = GetStyleInt("FontFilter", StyleFontFilter);
StyleFont = GetStyleString("Font", StyleFont);
StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall);
StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout);
}

View File

@@ -1,68 +0,0 @@
Color GruvboxDark0Hard = {0x1d, 0x20, 0x21, 0xff};
Color GruvboxDark0 = {0x28, 0x28, 0x28, 0xff};
Color GruvboxDark0Soft = {0x32, 0x30, 0x2f, 0xff};
Color GruvboxDark1 = {0x3c, 0x38, 0x36, 0xff};
Color GruvboxDark2 = {0x50, 0x49, 0x45, 0xff};
Color GruvboxDark3 = {0x66, 0x5c, 0x54, 0xff};
Color GruvboxDark4 = {0x7c, 0x6f, 0x64, 0xff};
Color GruvboxGray245 = {0x92, 0x83, 0x74, 0xff};
Color GruvboxGray244 = {0x92, 0x83, 0x74, 0xff};
Color GruvboxLight0Hard = {0xf9, 0xf5, 0xd7, 0xff};
Color GruvboxLight0 = {0xfb, 0xf1, 0xc7, 0xff};
Color GruvboxLight0Soft = {0xf2, 0xe5, 0xbc, 0xff};
Color GruvboxLight1 = {0xeb, 0xdb, 0xb2, 0xff};
Color GruvboxLight2 = {0xd5, 0xc4, 0xa1, 0xff};
Color GruvboxLight3 = {0xbd, 0xae, 0x93, 0xff};
Color GruvboxLight4 = {0xa8, 0x99, 0x84, 0xff};
Color GruvboxBrightRed = {0xfb, 0x49, 0x34, 0xff};
Color GruvboxBrightGreen = {0xb8, 0xbb, 0x26, 0xff};
Color GruvboxBrightYellow = {0xfa, 0xbd, 0x2f, 0xff};
Color GruvboxBrightBlue = {0x83, 0xa5, 0x98, 0xff};
Color GruvboxBrightPurple = {0xd3, 0x86, 0x9b, 0xff};
Color GruvboxBrightAqua = {0x8e, 0xc0, 0x7c, 0xff};
Color GruvboxBrightOrange = {0xfe, 0x80, 0x19, 0xff};
Color GruvboxNeutralRed = {0xcc, 0x24, 0x1d, 0xff};
Color GruvboxNeutralGreen = {0x98, 0x97, 0x1a, 0xff};
Color GruvboxNeutralYellow = {0xd7, 0x99, 0x21, 0xff};
Color GruvboxNeutralBlue = {0x45, 0x85, 0x88, 0xff};
Color GruvboxNeutralPurple = {0xb1, 0x62, 0x86, 0xff};
Color GruvboxNeutralAqua = {0x68, 0x9d, 0x6a, 0xff};
Color GruvboxNeutralOrange = {0xd6, 0x5d, 0x0e, 0xff};
Color GruvboxFadedRed = {0x9d, 0x00, 0x06, 0xff};
Color GruvboxFadedGreen = {0x79, 0x74, 0x0e, 0xff};
Color GruvboxFadedYellow = {0xb5, 0x76, 0x14, 0xff};
Color GruvboxFadedBlue = {0x07, 0x66, 0x78, 0xff};
Color GruvboxFadedPurple = {0x8f, 0x3f, 0x71, 0xff};
Color GruvboxFadedAqua = {0x42, 0x7b, 0x58, 0xff};
Color GruvboxFadedOrange = {0xaf, 0x3a, 0x03, 0xff};
Color ColorText = GruvboxDark0Hard;
Color ColorLoadTextHighlight = {0x00, 0x00, 0x00, 0x0F};
Color ColorBackground = GruvboxLight0Hard;
Color ColorInactiveWindow = {0x00, 0x00, 0x00, 0x0F};
Color ColorTextLineNumbers = GruvboxDark4;
Color ColorLineHighlight = GruvboxLight0Soft;
Color ColorMainCaret = GruvboxDark0Hard;
Color ColorSubCaret = GruvboxGray245;
Color ColorSelection = GruvboxLight1;
Color ColorWhitespaceDuringSelection = GruvboxLight4;
Color ColorMouseUnderline = GruvboxDark0Hard;
Color ColorCaretUnderline = GruvboxGray245;
Color ColorFuzzySearchLineHighlight = GruvboxDark0;
Color ColorScrollbarBackground = GruvboxLight2;
Color ColorScrollbarScroller = GruvboxLight1;
Color ColorScrollbarScrollerSelected = GruvboxLight0Hard;
Color ColorTitleBarText = GruvboxDark2;
Color ColorTitleBarBackground = GruvboxLight1;
Color ColorTitleBarActiveBackground = {0xfe, 0xfe, 0xfe, 0xfe};
Color ColorTitleBarSelection = GruvboxLight3;
Color ColorResizerBackground = GruvboxLight0Hard;
Color ColorResizerOutline = GruvboxLight3;
Int StyleWaitForEvents = 1;
Int StyleDrawLineNumbers = 1;
Int StyleDrawScrollbar = 1;
Int StyleIndentSize = 4;
Int StyleFontSize = 15;
Int StyleFontFilter = 0;
String StyleFont = "/home/krz/text_editor/package/CascadiaMono.ttf";
String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat";
double StyleUndoMergeTimeout = 0.3;

187
src/text_editor/globals.cpp Normal file
View File

@@ -0,0 +1,187 @@
SDL_Window *SDLWindow;
bool IsInFullscreen;
int FullScreenSizeX, FullScreenSizeY;
int FullScreenPositionX, FullScreenPositionY;
bool Testing = false;
bool AppIsRunning = true;
bool WaitForEvents = true;
WindowID WindowIDs;
ViewID ViewIDs;
Int BufferIDs;
Array<Window *> Windows;
Array<View *> Views;
Array<Buffer *> Buffers;
// console
BufferID NullBufferID;
ViewID NullViewID;
WindowID NullWindowID;
// hidden floating window
WindowID DebugWindowID;
ViewID DebugViewID;
BufferID DebugBufferID;
WindowID CommandBarWindowID;
WindowID StatusBarWindowID;
WindowID SearchBarWindowID;
ViewID SearchViewID;
BufferID SearchBufferID;
WindowID ActiveWindowID;
WindowID NextActiveWindowID;
WindowID LastActiveLayoutWindowID;
WindowID ScrollbarSelected = {-1};
WindowID DocumentSelected = {-1};
WindowID ResizerSelected = {-1};
WindowID ResizerHover = {-1};
Caret DocumentAnchor;
Buffer *LuaProjectBuffer;
Buffer *LuaConfigBuffer;
Buffer *GCInfoBuffer;
Buffer *EventBuffer;
Buffer *ScratchBuffer;
Buffer *TraceBuffer;
View *TraceView;
String WorkDir;
RandomSeed UniqueBufferNameSeed = {};
Array<Event> EventPlayback;
// lua
lua_State *LuaState = NULL;
String16 LuaCommandResult = {};
extern luaL_Reg LuaFunctions[];
// clipboard
BlockArena ClipboardArena;
String16 SavedClipboardString;
Array<String16> SavedClipboardCarets = {SysAllocator};
struct InternTable {
HashTable<String> strings; // general allocator
BlockArena arena;
};
String Intern(InternTable *table, String string) {
String *value = table->strings.get(string);
if (!value) {
String copy = Copy(table->arena, string);
table->strings.put(copy, copy);
return copy;
}
return *value;
}
// We use the intern table to optimize for space, I don't want to worry about freeing
// buffer names and event text data so let it all accumulate and interning will at least
// optimize worst offenders (like event text)
InternTable GlobalInternTable;
///////////////////////////////
// CONFIG
Color GruvboxDark0Hard = {0x1d, 0x20, 0x21, 0xff};
Color GruvboxDark0 = {0x28, 0x28, 0x28, 0xff};
Color GruvboxDark0Soft = {0x32, 0x30, 0x2f, 0xff};
Color GruvboxDark1 = {0x3c, 0x38, 0x36, 0xff};
Color GruvboxDark2 = {0x50, 0x49, 0x45, 0xff};
Color GruvboxDark3 = {0x66, 0x5c, 0x54, 0xff};
Color GruvboxDark4 = {0x7c, 0x6f, 0x64, 0xff};
Color GruvboxGray245 = {0x92, 0x83, 0x74, 0xff};
Color GruvboxGray244 = {0x92, 0x83, 0x74, 0xff};
Color GruvboxLight0Hard = {0xf9, 0xf5, 0xd7, 0xff};
Color GruvboxLight0 = {0xfb, 0xf1, 0xc7, 0xff};
Color GruvboxLight0Soft = {0xf2, 0xe5, 0xbc, 0xff};
Color GruvboxLight1 = {0xeb, 0xdb, 0xb2, 0xff};
Color GruvboxLight2 = {0xd5, 0xc4, 0xa1, 0xff};
Color GruvboxLight3 = {0xbd, 0xae, 0x93, 0xff};
Color GruvboxLight4 = {0xa8, 0x99, 0x84, 0xff};
Color GruvboxBrightRed = {0xfb, 0x49, 0x34, 0xff};
Color GruvboxBrightGreen = {0xb8, 0xbb, 0x26, 0xff};
Color GruvboxBrightYellow = {0xfa, 0xbd, 0x2f, 0xff};
Color GruvboxBrightBlue = {0x83, 0xa5, 0x98, 0xff};
Color GruvboxBrightPurple = {0xd3, 0x86, 0x9b, 0xff};
Color GruvboxBrightAqua = {0x8e, 0xc0, 0x7c, 0xff};
Color GruvboxBrightOrange = {0xfe, 0x80, 0x19, 0xff};
Color GruvboxNeutralRed = {0xcc, 0x24, 0x1d, 0xff};
Color GruvboxNeutralGreen = {0x98, 0x97, 0x1a, 0xff};
Color GruvboxNeutralYellow = {0xd7, 0x99, 0x21, 0xff};
Color GruvboxNeutralBlue = {0x45, 0x85, 0x88, 0xff};
Color GruvboxNeutralPurple = {0xb1, 0x62, 0x86, 0xff};
Color GruvboxNeutralAqua = {0x68, 0x9d, 0x6a, 0xff};
Color GruvboxNeutralOrange = {0xd6, 0x5d, 0x0e, 0xff};
Color GruvboxFadedRed = {0x9d, 0x00, 0x06, 0xff};
Color GruvboxFadedGreen = {0x79, 0x74, 0x0e, 0xff};
Color GruvboxFadedYellow = {0xb5, 0x76, 0x14, 0xff};
Color GruvboxFadedBlue = {0x07, 0x66, 0x78, 0xff};
Color GruvboxFadedPurple = {0x8f, 0x3f, 0x71, 0xff};
Color GruvboxFadedAqua = {0x42, 0x7b, 0x58, 0xff};
Color GruvboxFadedOrange = {0xaf, 0x3a, 0x03, 0xff};
Color ColorText = GruvboxDark0Hard;
Color ColorLoadTextHighlight = {0x00, 0x00, 0x00, 0x0F};
Color ColorBackground = GruvboxLight0Hard;
Color ColorInactiveWindow = {0x00, 0x00, 0x00, 0x0F};
Color ColorTextLineNumbers = GruvboxDark4;
Color ColorLineHighlight = GruvboxLight0Soft;
Color ColorMainCaret = GruvboxDark0Hard;
Color ColorSubCaret = GruvboxGray245;
Color ColorSelection = GruvboxLight1;
Color ColorWhitespaceDuringSelection = GruvboxLight4;
Color ColorMouseUnderline = GruvboxDark0Hard;
Color ColorCaretUnderline = GruvboxGray245;
Color ColorFuzzySearchLineHighlight = GruvboxDark0;
Color ColorScrollbarBackground = GruvboxLight2;
Color ColorScrollbarScroller = GruvboxLight1;
Color ColorScrollbarScrollerSelected = GruvboxLight0Hard;
Color ColorTitleBarText = GruvboxDark2;
Color ColorTitleBarBackground = GruvboxLight1;
Color ColorTitleBarActiveBackground = {0xfe, 0xfe, 0xfe, 0xfe};
Color ColorTitleBarSelection = GruvboxLight3;
Color ColorResizerBackground = GruvboxLight0Hard;
Color ColorResizerOutline = GruvboxLight3;
Int StyleWaitForEvents = 1;
Int StyleDrawLineNumbers = 1;
Int StyleDrawScrollbar = 1;
Int StyleIndentSize = 4;
Int StyleFontSize = 15;
Int StyleFontFilter = 0;
String StyleFont = "/home/krz/text_editor/package/CascadiaMono.ttf";
String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat";
double StyleUndoMergeTimeout = 0.3;
void ReloadStyle() {
ColorText = GetColor("Text", ColorText);
ColorLoadTextHighlight = GetColor("LoadTextHighlight", ColorLoadTextHighlight);
ColorBackground = GetColor("Background", ColorBackground);
ColorInactiveWindow = GetColor("InactiveWindow", ColorInactiveWindow);
ColorTextLineNumbers = GetColor("TextLineNumbers", ColorTextLineNumbers);
ColorLineHighlight = GetColor("LineHighlight", ColorLineHighlight);
ColorMainCaret = GetColor("MainCaret", ColorMainCaret);
ColorSubCaret = GetColor("SubCaret", ColorSubCaret);
ColorSelection = GetColor("Selection", ColorSelection);
ColorWhitespaceDuringSelection = GetColor("WhitespaceDuringSelection", ColorWhitespaceDuringSelection);
ColorMouseUnderline = GetColor("MouseUnderline", ColorMouseUnderline);
ColorCaretUnderline = GetColor("CaretUnderline", ColorCaretUnderline);
ColorFuzzySearchLineHighlight = GetColor("FuzzySearchLineHighlight", ColorFuzzySearchLineHighlight);
ColorScrollbarBackground = GetColor("ScrollbarBackground", ColorScrollbarBackground);
ColorScrollbarScroller = GetColor("ScrollbarScroller", ColorScrollbarScroller);
ColorScrollbarScrollerSelected = GetColor("ScrollbarScrollerSelected", ColorScrollbarScrollerSelected);
ColorTitleBarText = GetColor("TitleBarText", ColorTitleBarText);
ColorTitleBarBackground = GetColor("TitleBarBackground", ColorTitleBarBackground);
ColorTitleBarActiveBackground = GetColor("TitleBarActiveBackground", ColorTitleBarActiveBackground);
ColorTitleBarSelection = GetColor("TitleBarSelection", ColorTitleBarSelection);
ColorResizerBackground = GetColor("ResizerBackground", ColorResizerBackground);
ColorResizerOutline = GetColor("ResizerOutline", ColorResizerOutline);
StyleWaitForEvents = GetStyleInt("WaitForEvents", StyleWaitForEvents);
StyleDrawLineNumbers = GetStyleInt("DrawLineNumbers", StyleDrawLineNumbers);
StyleDrawScrollbar = GetStyleInt("DrawScrollbar", StyleDrawScrollbar);
StyleIndentSize = GetStyleInt("IndentSize", StyleIndentSize);
StyleFontSize = GetStyleInt("FontSize", StyleFontSize);
StyleFontFilter = GetStyleInt("FontFilter", StyleFontFilter);
StyleFont = GetStyleString("Font", StyleFont);
StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall);
StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout);
}

View File

@@ -1,19 +0,0 @@
struct InternTable {
HashTable<String> strings; // general allocator
BlockArena arena;
};
String Intern(InternTable *table, String string) {
String *value = table->strings.get(string);
if (!value) {
String copy = Copy(table->arena, string);
table->strings.put(copy, copy);
return copy;
}
return *value;
}
// We use the intern table to optimize for space, I don't want to worry about freeing
// buffer names and event text data so let it all accumulate and interning will at least
// optimize worst offenders (like event text)
InternTable GlobalInternTable;

255
src/text_editor/lua.cpp Normal file
View File

@@ -0,0 +1,255 @@
static void HookLuaForceExit(lua_State *L, lua_Debug *debug) {
SDL_PumpEvents();
int numkeys = 0;
const bool *keys = SDL_GetKeyboardState(&numkeys);
if (keys[SDL_SCANCODE_F9])
luaL_error(L, "lua execution got interrupted");
}
API double GetStyleFloat(String name, double default_float) {
double result = default_float;
lua_getglobal(LuaState, "Style");
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_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) {
lua_Number num = lua_tonumber(LuaState, -1);
result = (double)num;
}
}
return result;
}
API Int GetStyleInt(String name, Int default_int) {
Int result = default_int;
lua_getglobal(LuaState, "Style");
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_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) {
lua_Integer num = lua_tointeger(LuaState, -1);
result = (Int)num;
}
}
return result;
}
API String GetStyleString(String name, String default_string) {
String result = default_string;
lua_getglobal(LuaState, "Style");
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_isstring(LuaState, -1)) {
const char *string = lua_tostring(LuaState, -1);
result = Intern(&GlobalInternTable, string);
}
}
return result;
}
API Color GetColor(String name, Color default_color) {
Color result = default_color;
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;
}
API String GetFieldString(lua_State *L, String name) {
String result = {};
if (lua_istable(L, -1)) {
lua_pushlstring(L, name.data, name.len);
lua_gettable(L, -2);
defer { lua_pop(L, 1); };
if (lua_isstring(L, -1)) {
result = lua_tostring(L, -1);
}
}
return result;
}
Int GetFieldAInt(lua_State *L, const char *name) {
lua_getfield(L, -1, name);
lua_Integer num = lua_tointeger(L, -1);
lua_pop(L, 1);
return (Int)num;
}
double GetFieldAFloat(lua_State *L, const char *name) {
lua_getfield(L, -1, name);
double num = lua_tonumber(L, -1);
lua_pop(L, 1);
return num;
}
const char *GetFieldAString(lua_State *L, const char *name) {
lua_getfield(L, -1, name);
const char *result = lua_tostring(L, -1);
lua_pop(L, 1);
return result;
}
API void PushEvent(lua_State *L, Event *event) {
lua_createtable(L, 0, EVENT_FIELD_COUNT);
#define lua_pushInt lua_pushinteger
#define lua_pushString lua_pushstring
#define lua_pushFloat lua_pushnumber
#define X(TYPE, KIND, NAME) \
lua_push##KIND(L, event->NAME); \
lua_setfield(L, -2, #NAME);
EVENT_FIELDS
#undef X
}
// :Event
API int Lua_Play(lua_State *L) {
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
defer { lua_pop(L, 1); };
int size = (int)lua_rawlen(L, -1);
for (int i = 0; i < size; i += 1) {
lua_geti(L, -1, i + 1);
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
defer { lua_pop(L, 1); };
Event event = {};
#define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetFieldA##KIND(L, #NAME);
EVENT_FIELDS
#undef X
Add(&EventPlayback, event);
}
return 0;
}
void ReloadStyle();
extern String BaseLuaConfig;
API void LoadLuaBuffer(Buffer *lua_buffer) {
if (!lua_buffer) return;
ReportConsolef("reloading config: %S", lua_buffer->name);
Scratch scratch;
String string = AllocCharString(scratch, lua_buffer);
if (luaL_dostring(LuaState, string.data) == LUA_OK) {
if (lua_isstring(LuaState, -1)) {
const char *text = lua_tostring(LuaState, -1);
ReportConsolef(text);
lua_pop(LuaState, 1);
}
} else {
const char *error_message = lua_tostring(LuaState, -1);
ReportWarningf("Failed to load user config! %s", error_message);
lua_pop(LuaState, 1);
}
lua_buffer->user_change_id = lua_buffer->change_id;
}
API void ReloadLuaConfigs(bool reload) {
if (LuaConfigBuffer && !LuaConfigBuffer->dirty && LuaConfigBuffer->change_id != LuaConfigBuffer->user_change_id) {
reload = true;
}
if (LuaProjectBuffer && !LuaProjectBuffer->dirty && LuaProjectBuffer->change_id != LuaProjectBuffer->user_change_id) {
reload = true;
}
if (reload == false) {
return;
}
LoadLuaBuffer(LuaConfigBuffer);
LoadLuaBuffer(LuaProjectBuffer);
ReloadStyle();
ReloadFont(StyleFont, (U32)StyleFontSize);
For(Windows) {
it->draw_scrollbar = StyleDrawScrollbar;
it->draw_line_numbers = StyleDrawLineNumbers;
}
}
API bool CallLuaFunc(char *func_name, int arg_count, int ret_count) {
if (lua_pcall(LuaState, arg_count, ret_count, 0) != 0) {
const char *error_message = lua_tostring(LuaState, -1);
ReportWarningf("Failed to call a lua function: %s! %s", func_name, error_message);
lua_pop(LuaState, 1);
return false;
}
return true;
}
void CallLuaOnInit() {
lua_getglobal(LuaState, "OnInit");
CallLuaFunc("OnInit", 0, 0);
}
API void InitLuaConfig() {
LuaState = luaL_newstate();
luaL_openlibs(LuaState);
lua_sethook(LuaState, HookLuaForceExit, LUA_MASKCOUNT, 100000000);
for (int i = 0; LuaFunctions[i].name; i += 1) {
lua_pushcfunction(LuaState, LuaFunctions[i].func);
lua_setglobal(LuaState, LuaFunctions[i].name);
}
#if OS_WINDOWS
lua_pushinteger(LuaState, 0);
#else
lua_pushinteger(LuaState, 1);
#endif
lua_setglobal(LuaState, "OS_VALUE");
// Init base config, test that it works and initialize the lua stuff
if (!luaL_dostring(LuaState, BaseLuaConfig.data) == LUA_OK) {
const char *error_message = lua_tostring(LuaState, -1);
ReportErrorf("Failed to load base lua config! %s", error_message);
lua_pop(LuaState, 1);
Assert(!"Invalid codepath");
}
// Init user config
Buffer *lua_buffer = NULL;
Scratch scratch;
String lua_config_exe = Format(scratch, "%S/init.lua", GetExeDir(scratch));
if (FileExists(lua_config_exe)) {
lua_buffer = BufferOpenFile(lua_config_exe);
}
if (lua_buffer == NULL) {
String lua_config_remote = Format(scratch, "%S/init.lua", ConfigDir);
// #if DEBUG_BUILD
// // WARNING! Delete config to make sure we are running this code more frequently
// SDL_RemovePath(lua_config_remote.data);
// ReportConsolef("deleting config for debug purposes!");
// #endif
lua_buffer = BufferOpenFile(lua_config_remote);
if (lua_buffer->len == 0) {
String16 string16 = ToString16(scratch, BaseLuaConfig);
RawReplaceText(lua_buffer, {}, string16);
ReportConsolef("no config at: %S - creating config buffer", lua_config_remote);
}
}
LuaConfigBuffer = lua_buffer;
ReloadLuaConfigs(true);
CallLuaOnInit();
}

10
src/text_editor/lua.h Normal file
View File

@@ -0,0 +1,10 @@
API double GetStyleFloat(String name, double default_float);
API Int GetStyleInt(String name, Int default_int);
API String GetStyleString(String name, String default_string);
API Color GetColor(String name, Color default_color);
API String GetFieldString(lua_State *L, String name);
API int Lua_Play(lua_State *L);
API void LoadLuaBuffer(Buffer *lua_buffer);
API void ReloadLuaConfigs(bool reload = false);
API bool CallLuaFunc(char *func_name, int arg_count, int ret_count);
API void InitLuaConfig();

View File

@@ -110,204 +110,6 @@ int Lua_GetMainDir(lua_State *L) {
return 1;
}
static void HookLuaForceExit(lua_State *L, lua_Debug *debug) {
SDL_PumpEvents();
int numkeys = 0;
const bool *keys = SDL_GetKeyboardState(&numkeys);
if (keys[SDL_SCANCODE_F9])
luaL_error(L, "lua execution got interrupted");
}
double GetStyleFloat(String name, double default_float) {
double result = default_float;
lua_getglobal(LuaState, "Style");
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_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) {
lua_Number num = lua_tonumber(LuaState, -1);
result = (double)num;
}
}
return result;
}
Int GetStyleInt(String name, Int default_int) {
Int result = default_int;
lua_getglobal(LuaState, "Style");
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_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) {
lua_Integer num = lua_tointeger(LuaState, -1);
result = (Int)num;
}
}
return result;
}
String GetStyleString(String name, String default_string) {
String result = default_string;
lua_getglobal(LuaState, "Style");
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_isstring(LuaState, -1)) {
const char *string = lua_tostring(LuaState, -1);
result = Intern(&GlobalInternTable, string);
}
}
return result;
}
Color GetColor(String name, Color default_color) {
Color result = default_color;
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;
}
String GetFieldString(lua_State *L, String name) {
String result = {};
if (lua_istable(L, -1)) {
lua_pushlstring(L, name.data, name.len);
lua_gettable(L, -2);
defer { lua_pop(L, 1); };
if (lua_isstring(L, -1)) {
result = lua_tostring(L, -1);
}
}
return result;
}
Int GetFieldAInt(lua_State *L, const char *name) {
lua_getfield(L, -1, name);
lua_Integer num = lua_tointeger(L, -1);
lua_pop(L, 1);
return (Int)num;
}
double GetFieldAFloat(lua_State *L, const char *name) {
lua_getfield(L, -1, name);
double num = lua_tonumber(L, -1);
lua_pop(L, 1);
return num;
}
const char *GetFieldAString(lua_State *L, const char *name) {
lua_getfield(L, -1, name);
const char *result = lua_tostring(L, -1);
lua_pop(L, 1);
return result;
}
void PushEvent(lua_State *L, Event *event) {
lua_createtable(L, 0, EVENT_FIELD_COUNT);
#define lua_pushInt lua_pushinteger
#define lua_pushString lua_pushstring
#define lua_pushFloat lua_pushnumber
#define X(TYPE, KIND, NAME) \
lua_push##KIND(L, event->NAME); \
lua_setfield(L, -2, #NAME);
EVENT_FIELDS
#undef X
}
// :Event
int Lua_Play(lua_State *L) {
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
defer { lua_pop(L, 1); };
int size = (int)lua_rawlen(L, -1);
for (int i = 0; i < size; i += 1) {
lua_geti(L, -1, i + 1);
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
defer { lua_pop(L, 1); };
Event event = {};
#define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetFieldA##KIND(L, #NAME);
EVENT_FIELDS
#undef X
Add(&EventPlayback, event);
}
return 0;
}
void ReloadStyle();
extern String BaseLuaConfig;
void LoadLuaBuffer(Buffer *lua_buffer) {
if (!lua_buffer) return;
ReportConsolef("reloading config: %S", lua_buffer->name);
Scratch scratch;
String string = AllocCharString(scratch, lua_buffer);
if (luaL_dostring(LuaState, string.data) == LUA_OK) {
if (lua_isstring(LuaState, -1)) {
const char *text = lua_tostring(LuaState, -1);
ReportConsolef(text);
lua_pop(LuaState, 1);
}
} else {
const char *error_message = lua_tostring(LuaState, -1);
ReportWarningf("Failed to load user config! %s", error_message);
lua_pop(LuaState, 1);
}
lua_buffer->user_change_id = lua_buffer->change_id;
}
void ReloadLuaConfigs(bool reload = false) {
if (LuaConfigBuffer && !LuaConfigBuffer->dirty && LuaConfigBuffer->change_id != LuaConfigBuffer->user_change_id) {
reload = true;
}
if (LuaProjectBuffer && !LuaProjectBuffer->dirty && LuaProjectBuffer->change_id != LuaProjectBuffer->user_change_id) {
reload = true;
}
if (reload == false) {
return;
}
LoadLuaBuffer(LuaConfigBuffer);
LoadLuaBuffer(LuaProjectBuffer);
ReloadStyle();
ReloadFont();
For(Windows) {
it->draw_scrollbar = StyleDrawScrollbar;
it->draw_line_numbers = StyleDrawLineNumbers;
}
}
bool CallLuaFunc(char *func_name, int arg_count, int ret_count) {
if (lua_pcall(LuaState, arg_count, ret_count, 0) != 0) {
const char *error_message = lua_tostring(LuaState, -1);
ReportWarningf("Failed to call a lua function: %s! %s", func_name, error_message);
lua_pop(LuaState, 1);
return false;
}
return true;
}
struct OnOpenResult {
String kind;
String file_path;
@@ -388,65 +190,3 @@ void CallLuaOnUpdate(Event *event) {
PushEvent(LuaState, event);
CallLuaFunc("OnUpdate", 1, 0);
}
void CallLuaOnInit() {
lua_getglobal(LuaState, "OnInit");
CallLuaFunc("OnInit", 0, 0);
}
void InitLuaConfig() {
LuaState = luaL_newstate();
luaL_openlibs(LuaState);
lua_sethook(LuaState, HookLuaForceExit, LUA_MASKCOUNT, 100000000);
for (int i = 0; LuaFunctions[i].name; i += 1) {
lua_pushcfunction(LuaState, LuaFunctions[i].func);
lua_setglobal(LuaState, LuaFunctions[i].name);
}
#if OS_WINDOWS
lua_pushinteger(LuaState, 0);
#else
lua_pushinteger(LuaState, 1);
#endif
lua_setglobal(LuaState, "OS_VALUE");
// Init base config, test that it works and initialize the lua stuff
if (!luaL_dostring(LuaState, BaseLuaConfig.data) == LUA_OK) {
const char *error_message = lua_tostring(LuaState, -1);
ReportErrorf("Failed to load base lua config! %s", error_message);
lua_pop(LuaState, 1);
Assert(!"Invalid codepath");
}
// Init user config
Buffer *lua_buffer = NULL;
Scratch scratch;
String lua_config_exe = Format(scratch, "%S/init.lua", GetExeDir(scratch));
if (FileExists(lua_config_exe)) {
lua_buffer = BufferOpenFile(lua_config_exe);
}
if (lua_buffer == NULL) {
String lua_config_remote = Format(scratch, "%S/init.lua", ConfigDir);
// #if DEBUG_BUILD
// // WARNING! Delete config to make sure we are running this code more frequently
// SDL_RemovePath(lua_config_remote.data);
// ReportConsolef("deleting config for debug purposes!");
// #endif
lua_buffer = BufferOpenFile(lua_config_remote);
if (lua_buffer->len == 0) {
String16 string16 = ToString16(scratch, BaseLuaConfig);
RawReplaceText(lua_buffer, {}, string16);
ReportConsolef("no config at: %S - creating config buffer", lua_config_remote);
}
}
LuaConfigBuffer = lua_buffer;
ReloadLuaConfigs(true);
CallLuaOnInit();
}

View File

@@ -1,237 +1,3 @@
WindowID WindowIDs;
ViewID ViewIDs;
Array<Window *> Windows;
Array<View *> Views;
Array<Buffer *> Buffers;
// console
BufferID NullBufferID;
ViewID NullViewID;
WindowID NullWindowID;
// hidden floating window
WindowID DebugWindowID;
ViewID DebugViewID;
BufferID DebugBufferID;
WindowID CommandBarWindowID;
WindowID StatusBarWindowID;
WindowID SearchBarWindowID;
ViewID SearchViewID;
BufferID SearchBufferID;
WindowID ActiveWindowID;
WindowID NextActiveWindowID;
WindowID LastActiveLayoutWindowID;
WindowID ScrollbarSelected = {-1};
WindowID DocumentSelected = {-1};
WindowID ResizerSelected = {-1};
WindowID ResizerHover = {-1};
Caret DocumentAnchor;
Buffer *LuaProjectBuffer;
Buffer *LuaConfigBuffer;
Buffer *GCInfoBuffer;
Buffer *EventBuffer;
Buffer *ScratchBuffer;
Buffer *TraceBuffer;
View *TraceView;
String WorkDir;
RandomSeed UniqueBufferNameSeed = {};
// lua
lua_State *LuaState = NULL;
String16 LuaCommandResult = {};
extern luaL_Reg LuaFunctions[];
// clipboard
BlockArena ClipboardArena;
String16 SavedClipboardString;
Array<String16> SavedClipboardCarets = {SysAllocator};
String GetUniqueBufferName(String working_dir, String prepend_name, String extension = ".log") {
Scratch scratch;
String buffer_name = {};
for (int i = 1; i < INT_MAX; i += 1) {
buffer_name = Format(scratch, "%S/%S%d%S", working_dir, prepend_name, i, extension);
buffer_name = GetAbsolutePath(scratch, buffer_name);
Buffer *exists = FindBuffer(buffer_name);
if (!exists && !FileExists(buffer_name)) {
break;
}
}
buffer_name = Intern(&GlobalInternTable, buffer_name);
return buffer_name;
}
void InitBuffers() {
Allocator sys_allocator = GetSystemAllocator();
Scratch scratch;
Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(GetWorkingDir(scratch), "console"));
View *null_view = CreateView(null_buffer->id);
Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID);
TraceBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "trace"));
TraceView = CreateView(TraceBuffer->id);
GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "gc"));
EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "events"));
ScratchBuffer = BufferOpenFile(GetUniqueBufferName(WorkDir, "scratch"));
EventBuffer->no_history = true;
GCInfoBuffer->no_history = true;
}
inline bool IsDocumentSelectionValid() {
if (DocumentSelected.id == -1) return false;
return true;
}
inline bool IsScrollbarSelectionValid() {
if (ScrollbarSelected.id == -1) return false;
return true;
}
inline ViewID AllocViewID(View *view) { return {ViewIDs.id++, view}; }
inline WindowID AllocWindowID(Window *window) { return {WindowIDs.id++, window}; }
inline BufferID AllocBufferID(Buffer *buffer) { return {BufferIDs++, buffer}; }
inline Window *GetWindow(WindowID id, Window *default_window = Windows[0]) {
For(Windows) {
if (it->id == id) return it;
}
return default_window;
}
inline Buffer *GetBuffer(BufferID id) {
For(Buffers) {
if (it->id == id) return it;
}
return Buffers[0];
}
inline Buffer *FindBuffer(BufferID id) {
For(Buffers) {
if (it->id == id) return it;
}
return NULL;
}
inline Buffer *GetBuffer(String name) {
For(Buffers) {
if (it->name == name) return it;
}
return Buffers[0];
}
inline Buffer *FindBuffer(String name) {
For(Buffers) {
if (it->name == name) return it;
}
return NULL;
}
inline View *GetView(ViewID id) {
For(Views) {
if (it->id == id) return it;
}
return Views[0];
}
inline bool IsNull(Buffer *buffer) { return buffer->id.id == NullBufferID.id; }
inline Window *GetActiveWind() { return GetWindow(ActiveWindowID); }
Buffer *CreateBuffer(Allocator allocator, String name, Int size) {
Buffer *result = AllocBuffer(allocator, name, size);
Add(&Buffers, result);
return result;
}
Window *CreateWind() {
Allocator allocator = GetSystemAllocator();
Window *w = AllocType(allocator, Window);
w->font = &PrimaryFont;
w->visible = true;
w->layout = true;
w->draw_scrollbar = StyleDrawScrollbar;
w->draw_line_numbers = StyleDrawLineNumbers;
w->draw_line_highlight = true;
w->jump_history = true;
w->id = AllocWindowID(w);
w->weight = 1.0;
Add(&Windows, w);
return w;
}
View *CreateView(BufferID active_buffer) {
Allocator al = GetSystemAllocator();
View *view = AllocType(al, View);
view->id = AllocViewID(view);
view->active_buffer = active_buffer;
view->carets.allocator = al;
Add(&view->carets, {0, 0});
Add(&Views, view);
return view;
}
View *FindView(ViewID view_id, View *default_view = NULL) {
For(Views) {
if (it->id == view_id) {
return it;
}
}
return default_view;
}
View *FindView(BufferID buffer_id, View *default_view = NULL) {
For(Views) {
if (it->active_buffer == buffer_id) {
return it;
}
}
return default_view;
}
Window *FindWindow(ViewID view_id, Window *default_window = NULL) {
For(Windows) {
if (it->active_view == view_id) {
return it;
}
}
return default_window;
}
Window *FindWindow(String buffer_name, Window *default_window = NULL) {
For(Windows) {
View *it_view = GetView(it->active_view);
Buffer *it_buffer = GetBuffer(it_view->active_buffer);
if (it_buffer->name == buffer_name) {
return it;
}
}
return default_window;
}
Window *FindWindow(BufferID buffer_id) {
For(Windows) {
View *view = GetView(it->active_view);
if (view->active_buffer == buffer_id) return it;
}
return NULL;
}
View *FindView(String name, View *default_view = NULL) {
For(Views) {
Buffer *buffer = GetBuffer(it->active_buffer);
if (buffer->name == name) {
return it;
}
}
return default_view;
}
BSet GetBSet(Window *window) {
BSet set = {window};
set.view = GetView(set.window->active_view);
@@ -269,147 +35,6 @@ String GetMainDir() {
return name;
}
Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) {
if (string.len == 0) {
return 0;
}
Int buffer_len = 0;
Assert(buffer_cap > string.len * 2);
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[buffer_len++] = u' ';
i += 1;
continue;
}
uint32_t u32 = '?';
UTF32Result decode = UTF8ToUTF32((uint8_t *)(string.data + i), (int64_t)(string.len - i));
if (!decode.error) {
i += decode.advance;
u32 = decode.out_str;
} else {
i += 1;
}
UTF16Result encode = UTF32ToUTF16(u32);
if (!encode.error) {
for (int64_t encode_i = 0; encode_i < encode.len; encode_i += 1) {
buffer[buffer_len++] = encode.out_str[encode_i];
Assert(buffer_len < buffer_cap);
}
} else {
buffer[buffer_len++] = u'?';
}
}
return buffer_len;
}
String16 ToUnixString16(Allocator allocator, String string_) {
Int cap = string_.len * 3;
char16_t *string16_buffer = AllocArray(allocator, char16_t, cap);
Int len = ConvertUTF8ToUTF16UnixLine(string_, string16_buffer, cap);
String16 string = {string16_buffer, len};
return string;
}
Buffer *BufferOpenFile(String path) {
Allocator sys_allocator = GetSystemAllocator();
Scratch scratch;
path = GetAbsolutePath(scratch, path);
Buffer *buffer = GetBuffer(path);
if (!IsNull(buffer) || (IsNull(buffer) && buffer->name == path)) {
return buffer;
}
if (!FileExists(path)) {
buffer = CreateBuffer(sys_allocator, path);
} else if (IsDir(path)) {
ReportWarningf("failed to open, it's a directory: %S", path);
return GetBuffer(NullBufferID);
} else {
String string = ReadFile(scratch, path);
buffer = CreateBuffer(sys_allocator, path, string.len * 4 + 4096);
buffer->len = ConvertUTF8ToUTF16UnixLine(string, buffer->str, buffer->cap);
buffer->file_mod_time = GetFileModTime(path);
UpdateLines(buffer, {}, String16{(char16_t *)buffer->data, buffer->len});
}
return buffer;
}
View *OpenBufferView(String name) {
Buffer *buffer = BufferOpenFile(name);
View *view = CreateView(buffer->id);
return view;
}
View *WindowOpenBufferView(Window *new_parent_window, String name) {
View *view = FindView(name);
if (!view) {
View *result = OpenBufferView(name);
new_parent_window->active_view = result->id;
return result;
}
Window *window = FindWindow(view->id);
if (!window) {
new_parent_window->active_view = view->id;
return view;
}
if (window == new_parent_window) {
return view;
}
Assert(window->active_view.id == view->id.id);
View *result = OpenBufferView(name);
new_parent_window->active_view = result->id;
return result;
}
bool ViewIsCrumb(ViewID view_id) {
ForItem(window, Windows) {
For(window->goto_history) if (it.view_id == view_id) return true;
For(window->goto_redo) if (it.view_id == view_id) return true;
}
return false;
}
bool ViewIsReferenced(ViewID view) {
if (view == NullViewID) {
return true;
}
if (ViewIsCrumb(view)) {
return true;
}
For(Windows) {
if (it->active_view == view) {
return true;
}
}
return false;
}
bool BufferIsReferenced(BufferID buffer_id) {
if (buffer_id == NullBufferID) {
return true;
}
if (FindView(buffer_id)) {
return true;
}
return false;
}
void GarbageCollect() {
Allocator sys_allocator = GetSystemAllocator();

View File

@@ -12,24 +12,22 @@
#define LUA_USE_LONGJMP
#include "external/luaunity.c"
SDL_Window *SDLWindow;
bool IsInFullscreen;
int FullScreenSizeX, FullScreenSizeY;
int FullScreenPositionX, FullScreenPositionY;
bool Testing = false;
#include "generated_variables.cpp"
#include "render/generated_font.cpp"
#include "render/font.cpp"
#include "render/opengl.cpp"
#include "buffer.h"
#include "view.h"
#include "window.h"
#include "text_editor.h"
#include "intern_table.cpp"
#include "buffer.cpp"
#include "lua.h"
#include "management.cpp"
#include "globals.cpp"
#include "lua.cpp"
#include "buffer.cpp"
#include "view.cpp"
#include "window.cpp"
#include "management.cpp"
#include "process.cpp"
#include "event.cpp"
@@ -41,119 +39,11 @@ bool Testing = false;
#include "lua_api_generated.cpp"
#include "generated_config.cpp"
#include "generated.cpp"
#include "window_draw.cpp"
#include "draw.cpp"
#include "coroutines.cpp"
#include "test/tests.cpp"
void FillEventWithBasicData(Event *event) {
SDL_Keymod mod = SDL_GetModState();
event->shift = (mod & SDL_KMOD_SHIFT) != 0;
event->ctrl = (mod & SDL_KMOD_CTRL) != 0;
event->alt = (mod & SDL_KMOD_ALT) != 0;
event->super = (mod & SDL_KMOD_GUI) != 0;
float xmouse, ymouse;
SDL_GetMouseState(&xmouse, &ymouse);
event->xmouse = (int16_t)xmouse;
event->ymouse = (int16_t)ymouse;
int xwindow, ywindow;
SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow);
event->xwindow = xwindow;
event->ywindow = ywindow;
event->text = "";
}
Event TranslateSDLEvent(SDL_Event *input_event) {
ProfileFunction();
Event event = {};
FillEventWithBasicData(&event);
switch (input_event->type) {
case SDL_EVENT_QUIT: {
event.kind = EVENT_QUIT;
} break;
case SDL_EVENT_KEY_DOWN: {
event.kind = EVENT_KEY_PRESS;
SDL_KeyboardEvent &key = input_event->key;
event.key = key.key;
} break;
case SDL_EVENT_TEXT_INPUT: {
event.kind = EVENT_TEXT_INPUT;
SDL_TextInputEvent &b = input_event->text;
String string = b.text;
event.text = Intern(&GlobalInternTable, string).data;
} break;
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
SDL_MouseButtonEvent &b = input_event->button;
event.xmouse = (int16_t)b.x;
event.ymouse = (int16_t)b.y;
event.clicks = b.clicks;
if (b.button == SDL_BUTTON_LEFT) {
event.kind = EVENT_MOUSE_LEFT;
} else if (b.button == SDL_BUTTON_RIGHT) {
event.kind = EVENT_MOUSE_RIGHT;
} else if (b.button == SDL_BUTTON_MIDDLE) {
event.kind = EVENT_MOUSE_MIDDLE;
} else if (b.button == SDL_BUTTON_X1) {
event.kind = EVENT_MOUSE_X1;
} else if (b.button == SDL_BUTTON_X2) {
event.kind = EVENT_MOUSE_X2;
} else {
event.kind = EVENT_NONE;
event.clicks = 0;
}
} break;
case SDL_EVENT_MOUSE_BUTTON_UP: {
SDL_MouseButtonEvent &b = input_event->button;
event.xmouse = (int16_t)b.x;
event.ymouse = (int16_t)b.y;
if (b.button == SDL_BUTTON_LEFT) {
event.kind = EVENT_MOUSE_LEFT_UP;
} else if (b.button == SDL_BUTTON_RIGHT) {
event.kind = EVENT_MOUSE_RIGHT_UP;
} else if (b.button == SDL_BUTTON_MIDDLE) {
event.kind = EVENT_MOUSE_MIDDLE_UP;
} else if (b.button == SDL_BUTTON_X1) {
event.kind = EVENT_MOUSE_X1_UP;
} else if (b.button == SDL_BUTTON_X2) {
event.kind = EVENT_MOUSE_X2_UP;
} else {
event.kind = EVENT_NONE;
}
} break;
case SDL_EVENT_MOUSE_WHEEL: {
event.kind = EVENT_MOUSE_WHEEL;
SDL_MouseWheelEvent &b = input_event->wheel;
event.xmouse = (int16_t)b.mouse_x;
event.ymouse = (int16_t)b.mouse_y;
event.xwheel = b.x;
event.ywheel = b.y;
} break;
case SDL_EVENT_MOUSE_MOTION: {
event.kind = EVENT_UPDATE;
} break;
case SDL_EVENT_DROP_FILE: {
event.kind = EVENT_DROP_FILE;
SDL_DropEvent &b = input_event->drop;
String string = b.data;
event.text = Intern(&GlobalInternTable, string).data;
} break;
default: {
};
}
return event;
}
#if OS_WASM
EM_JS(void, JS_SetMouseCursor, (const char *cursor_str), {
@@ -262,36 +152,6 @@ void Update(Event event) {
}
}
Array<Event> GetEventsForFrame(Allocator allocator) {
Array<Event> result = {allocator};
if (EventPlayback.len) {
result = TightCopy(allocator, EventPlayback);
EventPlayback.len = 0;
}
SDL_Event event;
if (WaitForEvents) {
SDL_WaitEvent(&event);
Event ev = TranslateSDLEvent(&event);
if (ev.kind != EVENT_NONE) Add(&result, ev);
}
while (SDL_PollEvent(&event)) {
Event ev = TranslateSDLEvent(&event);
if (ev.kind != EVENT_NONE) Add(&result, ev);
}
if (result.len == 0) {
Event event = {};
FillEventWithBasicData(&event);
event.kind = EVENT_UPDATE;
Add(&result, event);
}
Assert(result.len);
return result;
}
void Windows_SetupVCVarsall(mco_coro *co) {
View *view = NULL;
{
@@ -486,7 +346,7 @@ int main(int argc, char **argv)
InitBuffers();
InitRender();
ReloadFont();
ReloadFont(StyleFont, (U32)StyleFontSize);
InitWindows();
InitOS(ReportWarningf);

View File

@@ -1,72 +1,61 @@
struct Window; struct View; struct WindowSplit;
struct ViewID { Int id; View *o; };
struct WindowID { Int id; Window *o; };
#define EVENT_KINDS \
X(EVENT_NONE) \
X(EVENT_UPDATE) \
X(EVENT_QUIT) \
X(EVENT_MOUSE_LEFT) \
X(EVENT_MOUSE_RIGHT) \
X(EVENT_MOUSE_MIDDLE) \
X(EVENT_MOUSE_X1) \
X(EVENT_MOUSE_X2) \
X(EVENT_MOUSE_LEFT_UP) \
X(EVENT_MOUSE_RIGHT_UP) \
X(EVENT_MOUSE_MIDDLE_UP) \
X(EVENT_MOUSE_X1_UP) \
X(EVENT_MOUSE_X2_UP) \
X(EVENT_MOUSE_WHEEL) \
X(EVENT_KEY_PRESS) \
X(EVENT_TEXT_INPUT) \
X(EVENT_DROP_FILE)
struct View {
ViewID id;
BufferID active_buffer;
Vec2I scroll;
Array<Caret> carets;
// window | view
Caret main_caret_on_begin_frame;
bool update_scroll;
bool fuzzy_search;
String16 prev_search_line;
enum EventKind {
#define X(TYPE) TYPE,
EVENT_KINDS
#undef X
EVENT_KIND_COUNT,
EVENT_KIND_INVALID = 111,
};
struct GotoCrumb {
ViewID view_id;
Caret caret;
double time;
const char *EventKindStrings[] = {
#define X(TYPE) #TYPE,
EVENT_KINDS
#undef X
};
struct Window {
WindowID id;
ViewID active_view;
#define EVENT_FIELDS \
X(EventKind, Int, kind) \
X(SDL_Keycode, Int, key) \
X(int16_t, Int, xwindow) \
X(int16_t, Int, ywindow) \
X(int16_t, Int, xmouse) \
X(int16_t, Int, ymouse) \
X(uint8_t, Int, clicks) \
X(uint8_t, Int, shift) \
X(uint8_t, Int, ctrl) \
X(uint8_t, Int, alt) \
X(uint8_t, Int, super) \
X(float, Float, xwheel) \
X(float, Float, ywheel) \
X(char *, String, text)
#define EVENT_FIELD_COUNT 14
Rect2I total_rect;
Rect2I document_rect;
Rect2I scrollbar_rect;
Rect2I line_numbers_rect;
Rect2I resizer_rect;
Font *font;
double mouse_scroller_offset;
int z;
double weight;
Int status_bar_last_buffer_change_id;
Array<GotoCrumb> goto_history;
Array<GotoCrumb> goto_redo;
ViewID active_goto_list;
Int goto_list_pos;
struct {
bool draw_scrollbar : 1;
bool draw_line_numbers : 1;
bool draw_darker : 1;
bool draw_line_highlight : 1;
bool visible : 1;
bool layout : 1;
bool kill : 1;
bool sync_visibility_with_focus : 1;
bool lose_focus_on_escape : 1;
bool jump_history : 1;
};
};
struct Scroller {
Rect2 rect;
double begin;
double end;
Int line_count;
struct Event {
#define X(TYPE, KIND, NAME) TYPE NAME;
EVENT_FIELDS
#undef X
};
struct BSet {
Window *window;
struct Window *window;
View *view;
Buffer *buffer;
};
@@ -81,7 +70,6 @@ Allocator SysAllocator = {SystemAllocatorProc};
String ConfigDir;
float DPIScale = 1.0f;
Rect2I GetVisibleCells(Window *window);
void AfterEdit(View *view, Array<Edit> edits);
Scroller ComputeScrollerRect(Window *window);
BSet Open(String path, String meta = "");
@@ -112,10 +100,8 @@ View *CreateView(BufferID active_buffer);
void ReopenBuffer(Buffer *buffer);
inline Buffer *FindBuffer(String name);
inline bool operator==(WindowID a, WindowID b) { return a.id == b.id; }
inline bool operator==(BufferID a, BufferID b) { return a.id == b.id; }
inline bool operator==(ViewID a, ViewID b) { return a.id == b.id; }
inline bool operator!=(WindowID a, WindowID b) { return a.id != b.id; }
inline bool operator!=(BufferID a, BufferID b) { return a.id != b.id; }
inline bool operator!=(ViewID a, ViewID b) { return a.id != b.id; }

77
src/text_editor/view.cpp Normal file
View File

@@ -0,0 +1,77 @@
API ViewID AllocViewID(View *view) {
return {ViewIDs.id++, view};
}
API View *CreateView(BufferID active_buffer) {
Allocator al = GetSystemAllocator();
View *view = AllocType(al, View);
view->id = AllocViewID(view);
view->active_buffer = active_buffer;
view->carets.allocator = al;
Add(&view->carets, {0, 0});
Add(&Views, view);
return view;
}
API View *FindView(ViewID view_id, View *default_view) {
For(Views) {
if (it->id == view_id) {
return it;
}
}
return default_view;
}
API View *FindView(BufferID buffer_id, View *default_view) {
For(Views) {
if (it->active_buffer == buffer_id) {
return it;
}
}
return default_view;
}
API View *FindView(String name, View *default_view) {
For(Views) {
Buffer *buffer = GetBuffer(it->active_buffer);
if (buffer->name == name) {
return it;
}
}
return default_view;
}
API View *GetView(ViewID id) {
return FindView(id, Views[0]);
}
API View *OpenBufferView(String name) {
Buffer *buffer = BufferOpenFile(name);
View *view = CreateView(buffer->id);
return view;
}
API bool ViewIsCrumb(ViewID view_id) {
ForItem(window, Windows) {
For(window->goto_history) if (it.view_id == view_id) return true;
For(window->goto_redo) if (it.view_id == view_id) return true;
}
return false;
}
API bool ViewIsReferenced(ViewID view) {
if (view == NullViewID) {
return true;
}
if (ViewIsCrumb(view)) {
return true;
}
For(Windows) {
if (it->active_view == view) {
return true;
}
}
return false;
}

32
src/text_editor/view.h Normal file
View File

@@ -0,0 +1,32 @@
struct View;
struct ViewID { Int id; View *o; };
struct View {
ViewID id;
BufferID active_buffer;
Vec2I scroll;
Array<Caret> carets;
// window | view
Caret main_caret_on_begin_frame;
bool update_scroll;
bool fuzzy_search;
String16 prev_search_line;
};
struct GotoCrumb {
ViewID view_id;
Caret caret;
double time;
};
API ViewID AllocViewID(View *view);
API View *CreateView(BufferID active_buffer);
API View *FindView(ViewID view_id, View *default_view = NULL);
API View *FindView(BufferID buffer_id, View *default_view = NULL);
API View *FindView(String name, View *default_view = NULL);
API View *GetView(ViewID id);
API View *OpenBufferView(String name);
API bool ViewIsCrumb(ViewID view_id);
API bool ViewIsReferenced(ViewID view);

View File

@@ -1,3 +1,72 @@
inline WindowID AllocWindowID(Window *window) {
return {WindowIDs.id++, window};
}
Window *CreateWind() {
Allocator allocator = GetSystemAllocator();
Window *w = AllocType(allocator, Window);
w->font = &PrimaryFont;
w->visible = true;
w->layout = true;
w->draw_scrollbar = StyleDrawScrollbar;
w->draw_line_numbers = StyleDrawLineNumbers;
w->draw_line_highlight = true;
w->jump_history = true;
w->id = AllocWindowID(w);
w->weight = 1.0;
Add(&Windows, w);
return w;
}
inline Window *GetWindow(WindowID id, Window *default_window = Windows[0]) {
For(Windows) {
if (it->id == id) return it;
}
return default_window;
}
Window *FindWindow(ViewID view_id, Window *default_window = NULL) {
For(Windows) {
if (it->active_view == view_id) {
return it;
}
}
return default_window;
}
Window *FindWindow(String buffer_name, Window *default_window = NULL) {
For(Windows) {
View *it_view = GetView(it->active_view);
Buffer *it_buffer = GetBuffer(it_view->active_buffer);
if (it_buffer->name == buffer_name) {
return it;
}
}
return default_window;
}
Window *FindWindow(BufferID buffer_id) {
For(Windows) {
View *view = GetView(it->active_view);
if (view->active_buffer == buffer_id) return it;
}
return NULL;
}
inline Window *GetActiveWind() {
return GetWindow(ActiveWindowID);
}
inline bool IsDocumentSelectionValid() {
if (DocumentSelected.id == -1) return false;
return true;
}
inline bool IsScrollbarSelectionValid() {
if (ScrollbarSelected.id == -1) return false;
return true;
}
Array<Window *> GetWindowZOrder(Allocator allocator) {
Array<Window *> order = {allocator};
For(Windows) if (it->z == 2) Add(&order, it);
@@ -13,6 +82,29 @@ Int GetExpandingBarSize(Window *window) {
return (Int)result;
}
View *WindowOpenBufferView(Window *new_parent_window, String name) {
View *view = FindView(name);
if (!view) {
View *result = OpenBufferView(name);
new_parent_window->active_view = result->id;
return result;
}
Window *window = FindWindow(view->id);
if (!window) {
new_parent_window->active_view = view->id;
return view;
}
if (window == new_parent_window) {
return view;
}
Assert(window->active_view.id == view->id.id);
View *result = OpenBufferView(name);
new_parent_window->active_view = result->id;
return result;
}
void InitWindows() {
Scratch scratch;
@@ -187,4 +279,4 @@ void LayoutWindows(int16_t wx, int16_t wy) {
CalcNiceties(n);
i += 1;
}
}
}

49
src/text_editor/window.h Normal file
View File

@@ -0,0 +1,49 @@
struct Window;
struct WindowID { Int id; Window *o; };
struct Window {
WindowID id;
ViewID active_view;
Rect2I total_rect;
Rect2I document_rect;
Rect2I scrollbar_rect;
Rect2I line_numbers_rect;
Rect2I resizer_rect;
Font *font;
double mouse_scroller_offset;
int z;
double weight;
Int status_bar_last_buffer_change_id;
Array<GotoCrumb> goto_history;
Array<GotoCrumb> goto_redo;
ViewID active_goto_list;
Int goto_list_pos;
struct {
bool draw_scrollbar : 1;
bool draw_line_numbers : 1;
bool draw_darker : 1;
bool draw_line_highlight : 1;
bool visible : 1;
bool layout : 1;
bool kill : 1;
bool sync_visibility_with_focus : 1;
bool lose_focus_on_escape : 1;
bool jump_history : 1;
};
};
struct Scroller {
Rect2 rect;
double begin;
double end;
Int line_count;
};
inline bool operator==(WindowID a, WindowID b) { return a.id == b.id; }
inline bool operator!=(WindowID a, WindowID b) { return a.id != b.id; }
Rect2I GetVisibleCells(Window *window);