restructuring
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -161,3 +161,4 @@ API void ResetHistory(Buffer *buffer);
|
||||
|
||||
API void DeallocHistoryArray(Array<HistoryEntry> *entries);
|
||||
API void DeallocHistoryEntries(Array<HistoryEntry> *entries);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -394,9 +476,6 @@ 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
187
src/text_editor/globals.cpp
Normal 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);
|
||||
}
|
||||
@@ -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
255
src/text_editor/lua.cpp
Normal 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
10
src/text_editor/lua.h
Normal 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();
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
77
src/text_editor/view.cpp
Normal 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
32
src/text_editor/view.h
Normal 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);
|
||||
@@ -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;
|
||||
|
||||
|
||||
49
src/text_editor/window.h
Normal file
49
src/text_editor/window.h
Normal 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);
|
||||
Reference in New Issue
Block a user