Compare commits

...

10 Commits

Author SHA1 Message Date
Krzosa Karol
a351d2eb41 restructuring 2025-12-14 10:32:42 +01:00
Krzosa Karol
0424ca62f2 Fix eval error 2025-12-14 08:18:17 +01:00
Krzosa Karol
83d5ddff9d Fix lua bug 2025-12-09 08:31:31 +01:00
Krzosa Karol
b600361278 Refactor Command_s 2025-12-08 09:23:07 +01:00
Krzosa Karol
9d29a1c187 Refactoring Command_s, NextWindowID 2025-12-08 09:16:31 +01:00
Krzosa Karol
20207e6040 jump history 2025-12-08 08:37:52 +01:00
Krzosa Karol
ef6a7be285 Command bar, undo merge time 2025-12-07 13:57:51 +01:00
Krzosa Karol
df84d1605d Bring back status bar with new design, fixing bugs 2025-12-07 10:40:30 +01:00
Krzosa Karol
88a5adaa0a Big refactor new layout 2025-12-06 19:12:06 +01:00
Krzosa Karol
e6e1ae0223 Switch to using arrays for Windows, Views, Buffers list, try to make DeleteWindow work 2025-12-05 08:58:46 +01:00
30 changed files with 1771 additions and 1927 deletions

View File

@@ -68,6 +68,7 @@ Style.Font = GetExeDir().."/CascadiaMono.ttf"
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
Style.TrimWhitespaceOnSave = true
Style.ClangFormatOnSave = false
Style.StyleUndoMergeTimeout = 0.3
INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
OS_WINDOWS = 0
@@ -323,10 +324,6 @@ function MatchGotoBuild(s, meta)
end
function MatchExec(s, meta)
if meta ~= "exec" then
return nil
end
if s:match(".exe$") or s:match(".bat$") or s:match(".sh$") then
return {kind = "exec_console", cmd = s, working_dir = GetMainDir()}
end
@@ -335,8 +332,7 @@ function MatchExec(s, meta)
return {kind = "exec_console", cmd = s:sub(2, -1), working_dir = GetMainDir()}
end
Eval(s)
return {kind = "skip"}
return nil
end
BuiltinOnOpenMatchers = {

View File

@@ -13,7 +13,6 @@ Needs to change:
- How to design Command view?
- How to design popup view (input field)?
- How to design search view? or search and replace view?
- Window management, splitting, GC
Things I like:
- Basic editing
@@ -24,15 +23,24 @@ Splits:
- Buffer16 Buffer8?
- Why constraint that name of buffer needs to be unique? For Open() and default behavior but is this required?
- Try to add Tracking Allocator and rewrite the app, free all memory at the end of the app and check all is well
- SpawnProcess wrong memory allocation there
- Trying to fix the testing, Command_Open doesn't work on first frame because window is not metricly OK?
- window->document_rect is null
- move titlebar, search to splits?
Linux
- Add backtrace
Commands TODO:
- Search
- Ctrl + F
- Next occurence: Enter
- Prev occurence: Shift + Enter
- next occurence: F3
- prev occurence: Shift + F3
- Console: OK concept but constrain
- Turned off by default
- Special: non editable, hotkeys don't work etc.

View File

@@ -759,7 +759,6 @@ API Process SpawnProcess(String command_line, String working_dir, String write_s
String16 cmd = ToString16(scratch, command_line);
char *env = NULL;
// TODO: FIX ARENA ALLOCATION USING PushSize, Prealloc maybe? Maybe we want a block arena
if (enviroment.len) {
Int size = GetSize(enviroment) + enviroment.len + 1;
env = (char *)PushSize(scratch, size);
@@ -1098,3 +1097,7 @@ API void CloseStdin(Process *process) {
}
#endif
API double GetTimeSeconds() {
return GetTimeMicros() / 1000000.0;
}

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, 10, 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

@@ -140,8 +140,8 @@ void PlayTestOpen(mco_coro *co) {
}
void Test(mco_coro *co) {
Wait(co); // First phase starts immediately but stuff is not initialized so Command_Open acts weird
Command_Open(TestDir);
Wait(co); // First phase starts immediately but stuff is not initialized so Open acts weird
Open(TestDir);
PlayTestOpen(co);
Release(&TestArena);

View File

@@ -1,6 +1,5 @@
#define BUFFER_DEBUG 0
API Range MakeRange(Int a, Int b) {
Range result = {Min(a, b), Max(a, b)};
return result;
@@ -917,16 +916,17 @@ API void AddEdit(Array<Edit> *e, Range range, String16 string) {
void SaveHistoryBeforeMergeCursor(Buffer *buffer, Array<HistoryEntry> *stack, Array<Caret> &carets) {
if (buffer->no_history) return;
HistoryEntry entry = {};
entry.carets = TightCopy(GetSystemAllocator(), carets);
entry.time = GetTimeSeconds();
entry.carets = TightCopy(GetSystemAllocator(), carets);
Add(stack, entry);
}
void SaveHistoryBeforeApplyEdits(Buffer *buffer, Array<HistoryEntry> *stack, Array<Edit> &edits) {
ProfileFunction();
if (buffer->no_history) return;
HistoryEntry *entry = GetLast(*stack);
Allocator sys_allocator = GetSystemAllocator();
entry->edits = TightCopy(sys_allocator, edits);
HistoryEntry *entry = GetLast(*stack);
Allocator sys_allocator = GetSystemAllocator();
entry->edits = TightCopy(sys_allocator, edits);
// Make reverse edits
For(entry->edits) {
@@ -992,8 +992,16 @@ API void UndoEdit(Buffer *buffer, Array<Caret> *carets) {
Allocator sys_allocator = GetSystemAllocator();
For(entry.edits) Dealloc(sys_allocator, it.string.data);
Dealloc(&entry.edits);
if (buffer->undo_stack.len > 0) {
HistoryEntry *next = GetLast(buffer->undo_stack);
if (entry.time - next->time <= StyleUndoMergeTimeout) {
UndoEdit(buffer, carets);
}
}
}
API void DeallocHistoryEntries(Array<HistoryEntry> *entries) {
For(*entries) {
Dealloc(&it.carets);
@@ -1003,6 +1011,21 @@ API void DeallocHistoryEntries(Array<HistoryEntry> *entries) {
entries->len = 0;
}
API void ResetHistory(Buffer *buffer) {
DeallocHistoryEntries(&buffer->redo_stack);
DeallocHistoryEntries(&buffer->undo_stack);
}
API void ResetBuffer(Buffer *buffer) {
ResetHistory(buffer);
buffer->change_id += 1;
buffer->line_starts.len = 0;
buffer->len = 0;
if (!buffer->no_line_starts) {
Add(&buffer->line_starts, (Int)0);
}
}
void ClearRedoStack(Buffer *buffer) {
DeallocHistoryEntries(&buffer->redo_stack);
}
@@ -1170,8 +1193,6 @@ API void InitBuffer(Allocator allocator, Buffer *buffer, BufferID id = {}, Strin
}
API void DeinitBuffer(Buffer *buffer) {
Assert(buffer->next == NULL);
Assert(buffer->prev == NULL);
Allocator allocator = buffer->line_starts.allocator;
Dealloc(allocator, buffer->data);
Dealloc(&buffer->line_starts);
@@ -1181,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};
@@ -1380,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

@@ -12,12 +12,11 @@ struct Edit {
struct HistoryEntry {
Array<Edit> edits;
Array<Caret> carets;
double time;
};
struct Buffer {
BufferID id;
Buffer *next;
Buffer *prev;
String name;
Int change_id;
Int user_change_id;
@@ -158,6 +157,8 @@ API void AssertRanges(Array<Caret> carets);
API void RedoEdit(Buffer *buffer, Array<Caret> *carets);
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

@@ -1,5 +1,6 @@
void CheckpointBeforeGoto(Window *window, View *view) {
Add(&window->goto_history, {view->id, view->carets[0]});
if (window->jump_history == false) return;
Add(&window->goto_history, {view->id, view->carets[0], GetTimeSeconds()});
window->goto_redo.len = 0;
}
@@ -17,27 +18,43 @@ GotoCrumb GetCrumb(Array<GotoCrumb> *cr) {
}
void GotoBackward(Window *window) {
BSet set = GetBSet(window);
if (window->jump_history == false) return;
if (window->goto_history.len <= 0) return;
Add(&window->goto_redo, {set.view->id, set.view->carets[0]});
BSet set = GetBSet(window);
Add(&window->goto_redo, {set.view->id, set.view->carets[0], GetTimeSeconds()});
GotoCrumb c = GetCrumb(&window->goto_history);
window->active_view = c.view_id;
View *view = GetView(c.view_id);
view->carets[0] = c.caret;
UpdateScroll(window, true);
if (window->goto_history.len) {
GotoCrumb *next = GetLast(window->goto_history);
if (c.time - next->time <= StyleUndoMergeTimeout) {
GotoBackward(window);
}
}
}
void GotoForward(Window *window) {
BSet set = GetBSet(window);
if (window->goto_redo.len <= 0) return;
Add(&window->goto_history, {set.view->id, set.view->carets[0]});
if (window->jump_history == false) return;
BSet set = GetBSet(window);
Add(&window->goto_history, {set.view->id, set.view->carets[0], GetTimeSeconds()});
GotoCrumb c = GetCrumb(&window->goto_redo);
GotoCrumb c = GetCrumb(&window->goto_redo);
window->active_view = c.view_id;
View *view = GetView(c.view_id);
view->carets[0] = c.caret;
UpdateScroll(window, true);
if (window->goto_redo.len) {
GotoCrumb *next = GetLast(window->goto_redo);
if (c.time - next->time <= StyleUndoMergeTimeout) {
GotoForward(window);
}
}
}
void JumpGarbageBuffer(BSet *set, String buffer_name = "") {
@@ -51,13 +68,13 @@ void JumpGarbageBuffer(BSet *set, String buffer_name = "") {
set->buffer->garbage = true;
}
void Command_BeginJump(BSet *set, BufferID buffer_id = NullBufferID) {
void BeginJump(BSet *set, BufferID buffer_id = NullBufferID) {
CheckpointBeforeGoto(set->window);
set->buffer = GetBuffer(buffer_id);
set->view = WindowOpenBufferView(set->window, set->buffer->name);
}
void Command_EndJump(BSet set) {
void EndJump(BSet set) {
Int pos = XYToPos(set.buffer, {0, set.buffer->line_starts.len - 1});
set.view->carets[0] = MakeCaret(pos);
UpdateScroll(set.window, true);
@@ -83,7 +100,7 @@ Int ScreenSpaceToBufferPosErrorOutOfBounds(Window *window, View *view, Buffer *b
void MouseLoadWord(Event event, String meta = "") {
Vec2I mouse = MouseVec2I();
BSet active = GetActiveSet();
BSet active = GetBSet(ActiveWindowID);
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
if (mouse_in_document) {
@@ -95,7 +112,7 @@ void MouseLoadWord(Event event, String meta = "") {
active.view->carets.len = 1;
active.view->carets[0] = MakeCaret(p);
Command_Open(string, meta);
Open(string, meta);
}
}
}
@@ -106,16 +123,15 @@ View *GetViewForFixingWhenBufferCommand(Buffer *buffer, bool *is_active = NULL)
*is_active = false;
}
Window *active_window = GetWindow(ActiveWindow);
View *active_view = GetView(active_window->active_view);
if (active_view->active_buffer == buffer->id) {
BSet active = GetBSet(ActiveWindowID);
if (active.buffer->id == buffer->id) {
if (is_active) {
*is_active = true;
}
return active_view;
return active.view;
}
for (View *it = FirstView; it; it = it->next) {
For(Views) {
if (it->active_buffer != buffer->id) {
continue;
}
@@ -135,15 +151,15 @@ void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) {
Array<Caret> carets = Copy(GetSystemAllocator(), view->carets);
Scratch scratch;
Command_SelectRangeOneCursor(view, range);
Command_ReplaceEx(scratch, view, string);
SelectRange(view, range);
ReplaceEx(scratch, view, string);
Dealloc(&view->carets);
view->carets = carets;
}
// @todo: revamp interface since it scrolls ALL VIEWS??? or maybe not??
void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line) {
void Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
@@ -154,7 +170,7 @@ void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on
};
Array<ViewInfo> view_info = {scratch};
for (View *it_view = FirstView; it_view; it_view = it_view->next) {
ForItem(it_view, Views) {
if (it_view->active_buffer != buffer->id) {
continue;
}
@@ -174,8 +190,8 @@ void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on
Add(&view_info, vi);
}
Command_SelectRangeOneCursor(view, GetBufferEndAsRange(buffer));
Command_Replace(view, string);
SelectRange(view, GetBufferEndAsRange(buffer));
Replace(view, string);
For (view_info) {
if (it.scroll_to_end) {
@@ -187,16 +203,16 @@ void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on
}
}
void Command_Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line) {
void Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line) {
Scratch scratch;
String16 string16 = ToString16(scratch, string);
Command_Append(view, string16, scroll_to_end_if_cursor_on_last_line);
Append(view, string16, scroll_to_end_if_cursor_on_last_line);
}
void Command_Appendf(View *view, const char *fmt, ...) {
void Appendf(View *view, const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
Command_Append(view, string, true);
Append(view, string, true);
}
void ReportErrorf(const char *fmt, ...) {
@@ -205,8 +221,8 @@ void ReportErrorf(const char *fmt, ...) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error!", string.data, NULL);
View *view = GetView(NullViewID);
if (view) {
Command_Appendf(view, "%S\n", string);
ActiveWindow = NullWindowID;
Appendf(view, "%S\n", string);
NextActiveWindowID = NullWindowID;
}
}
@@ -214,23 +230,23 @@ void ReportConsolef(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
View *view = GetView(NullViewID);
Command_Appendf(view, "%S\n", string);
Appendf(view, "%S\n", string);
}
void ReportWarningf(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
View *null_view = GetView(NullViewID);
Command_Appendf(null_view, "%S\n", string);
Appendf(null_view, "%S\n", string);
}
void ReportDebugf(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
Command_Appendf(TraceView, "%S\n", string);
Appendf(TraceView, "%S\n", string);
}
void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) {
void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
BSet set = GetBSet(window);
@@ -257,7 +273,7 @@ void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = f
}
}
void Command_MoveCursorsToSide(View *view, int direction, bool shift = false) {
void MoveCursorToSide(View *view, int direction, bool shift = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
Buffer *buffer = GetBuffer(view->active_buffer);
@@ -383,7 +399,7 @@ Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool
return it;
}
void Command_Move(View *view, int direction, bool ctrl = false, bool shift = false) {
void MoveCarets(View *view, int direction, bool ctrl = false, bool shift = false) {
Assert(direction < DIR_COUNT);
Buffer *buffer = GetBuffer(view->active_buffer);
For(view->carets) {
@@ -391,7 +407,7 @@ void Command_Move(View *view, int direction, bool ctrl = false, bool shift = fal
}
}
void Command_MoveLine(View *view, int direction) {
void MoveCaretsLine(View *view, int direction) {
Assert(direction == DIR_DOWN || direction == DIR_UP);
Scratch scratch;
@@ -450,7 +466,7 @@ void Command_MoveLine(View *view, int direction) {
}
}
Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string) {
Array<Edit> ReplaceEx(Allocator scratch, View *view, String16 string) {
Buffer *buffer = GetBuffer(view->active_buffer);
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
MergeCarets(buffer, &view->carets);
@@ -459,12 +475,12 @@ Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string) {
return edits;
}
void Command_Replace(View *view, String16 string) {
void Replace(View *view, String16 string) {
Scratch scratch;
Command_ReplaceEx(scratch, view, string);
ReplaceEx(scratch, view, string);
}
void Command_DuplicateLine(View *view, int direction) {
void DuplicateLine(View *view, int direction) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
Scratch scratch;
@@ -530,7 +546,7 @@ Array<Range> GetSelectedLinesSorted(Allocator allocator, View *view) {
return result;
}
void Command_IndentSelectedLines(View *view, bool shift = false) {
void IndentSelectedLines(View *view, bool shift = false) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
@@ -685,28 +701,31 @@ void SaveBuffer(Buffer *buffer) {
ReportWarningf("Failed to save file with name: %S", buffer->name);
}
}
void Command_Save() {
BSet set = GetActiveMainSet();
SaveBuffer(set.buffer);
BSet active = GetBSet(LastActiveLayoutWindowID);
SaveBuffer(active.buffer);
}
int Lua_Save(lua_State *L) {
Command_Save();
return 0;
}
void Command_SaveAll() {
for (Buffer *it = FirstBuffer; it; it = it->next) {
For(Buffers) {
if (it->file_mod_time) {
SaveBuffer(it);
}
}
}
int Lua_SaveAll(lua_State *L) {
Command_SaveAll();
return 0;
}
void Command_KillSelectedLines(View *view) {
void KillSelectedLines(View *view) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
SaveCaretHistoryBeforeBeginEdit(buffer, view->carets);
@@ -717,7 +736,7 @@ void Command_KillSelectedLines(View *view) {
it.range.min = GetFullLineStart(buffer, it.range.min);
it.range.min -= Clamp(eof, (Int)0, buffer->len);
}
Command_Replace(view, u"");
Replace(view, u"");
}
void EncloseLine(View *view) {
@@ -746,7 +765,7 @@ void EncloseSpace(View *view) {
}
}
void Command_Delete(View *view, int direction, bool ctrl = false) {
void Delete(View *view, int direction, bool ctrl = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
Scratch scratch;
@@ -782,7 +801,7 @@ void Command_Delete(View *view, int direction, bool ctrl = false) {
EndEdit(buffer, &edits, &view->carets, true);
}
void Command_SelectAll(View *view, String16 needle) {
void SelectAll(View *view, String16 needle) {
Buffer *buffer = GetBuffer(view->active_buffer);
String16 string_buffer = GetString(buffer);
@@ -799,7 +818,7 @@ void Command_SelectAll(View *view, String16 needle) {
MergeCarets(buffer, &view->carets);
}
void Command_CreateCursorVertical(View *view, int direction) {
void CreateCursorVertical(View *view, int direction) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
Buffer *buffer = GetBuffer(view->active_buffer);
@@ -823,18 +842,18 @@ void Command_CreateCursorVertical(View *view, int direction) {
MergeCarets(buffer, &view->carets);
}
void Command_SelectRangeOneCursor(View *view, Caret caret) {
void SelectRange(View *view, Caret caret) {
view->carets.len = 1;
view->carets[0] = caret;
}
void Command_SelectRangeOneCursor(View *view, Range range) {
Command_SelectRangeOneCursor(view, MakeCaret(range.min, range.max));
void SelectRange(View *view, Range range) {
SelectRange(view, MakeCaret(range.min, range.max));
}
void Command_SelectEntireBuffer(View *view) {
void SelectEntireBuffer(View *view) {
Buffer *buffer = GetBuffer(view->active_buffer);
Command_SelectRangeOneCursor(view, GetRange(buffer));
SelectRange(view, GetRange(buffer));
}
Caret FindPrev(Buffer *buffer, String16 needle, Caret caret) {
@@ -873,7 +892,7 @@ Caret FindNext(Buffer *buffer, String16 needle, Caret caret) {
return result;
}
void Command_IdentedNewLine(View *view) {
void IdentedNewLine(View *view) {
Buffer *buffer = GetBuffer(view->active_buffer);
Scratch scratch;
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
@@ -889,17 +908,17 @@ void Command_IdentedNewLine(View *view) {
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
}
void Command_Find(View *seek_view, String16 needle, bool forward = true) {
void Find(View *seek_view, String16 needle, bool forward = true) {
Buffer *seek_buffer = GetBuffer(seek_view->active_buffer);
Caret caret = seek_view->carets[0];
if (forward) caret = FindNext(seek_buffer, needle, caret);
if (!forward) caret = FindPrev(seek_buffer, needle, caret);
Command_SelectRangeOneCursor(seek_view, caret);
SelectRange(seek_view, caret);
IF_DEBUG(AssertRanges(seek_view->carets));
}
void Command_GotoNextInList(Window *window, Int line_offset = 1) {
void GotoNextInList(Window *window, Int line_offset = 1) {
Assert(line_offset == 1 || line_offset == -1);
View *active_view = GetView(window->active_view);
@@ -924,7 +943,7 @@ void Command_GotoNextInList(Window *window, Int line_offset = 1) {
continue;
}
BSet set = Command_Open(line, "goto_build");
BSet set = Open(line, "goto_build");
if (set.window == NULL) {
continue;
}
@@ -936,7 +955,7 @@ void Command_GotoNextInList(Window *window, Int line_offset = 1) {
if (!opened) window->active_view = active_view->id;
}
void Command_FuzzySort(View *view, String16 needle) {
void FuzzySortView(View *view, String16 needle) {
Buffer *buffer = GetBuffer(view->active_buffer);
Scratch scratch;
@@ -950,9 +969,9 @@ void Command_FuzzySort(View *view, String16 needle) {
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
}
Command_SelectEntireBuffer(view);
Command_Replace(view, GetString(temp_buffer));
Command_SelectRangeOneCursor(view, MakeRange(0));
SelectEntireBuffer(view);
Replace(view, GetString(temp_buffer));
SelectRange(view, MakeRange(0));
}
void ReopenBuffer(Buffer *buffer) {
@@ -970,9 +989,9 @@ void ReopenBuffer(Buffer *buffer) {
}
void Command_Reopen() {
BSet set = GetActiveMainSet();
ReopenBuffer(set.buffer);
ActiveWindow = set.window->id;
BSet main = GetBSet(LastActiveLayoutWindowID);
ReopenBuffer(main.buffer);
NextActiveWindowID = main.window->id;
}
int Lua_Reopen(lua_State *L) {
@@ -998,7 +1017,7 @@ void New(Window *window, String name = "") {
}
void Command_New(String name = "") {
BSet main = GetActiveMainSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
New(main.window, name);
}
@@ -1025,13 +1044,13 @@ void NewDir(Window *window, String name = "") {
}
MakeDir(name);
Command_Open(name);
Open(name);
}
int Lua_NewDir(lua_State *L) {
String name = lua_tostring(L, 1);
lua_pop(L, 1);
BSet main = GetActiveMainSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
NewDir(main.window, name);
return 0;
}
@@ -1076,64 +1095,61 @@ void ListFilesRecursive(Buffer *buffer, String dir) {
}
}
void Command_ListCode(String dir = WorkDir) {
BSet main = GetActiveMainSet();
void Command_ListCode() {
BSet main = GetBSet(LastActiveLayoutWindowID);
JumpGarbageBuffer(&main);
ListFilesRecursive(main.buffer, dir);
ListFilesRecursive(main.buffer, WorkDir);
main.view->fuzzy_search = true;
main.view->update_scroll = true;
Command_SelectRangeOneCursor(main.view, GetBufferEndAsRange(main.buffer));
SelectRange(main.view, GetBufferEndAsRange(main.buffer));
}
int Lua_ListCode(lua_State *L) {
String string = lua_tostring(L, 1);
lua_pop(L, 1);
if (string.len == 0) {
string = WorkDir;
}
Command_ListCode(string);
Command_ListCode();
return 0;
}
View *Command_ExecHidden(String buffer_name, String cmd, String working_dir) {
View *ExecHidden(String buffer_name, String cmd, String working_dir) {
View *view = OpenBufferView(buffer_name);
Exec(view->id, true, cmd, working_dir);
return view;
}
BSet Command_Exec(String cmd, String working_dir, bool set_active = true) {
BSet set = GetActiveMainSet();
if (set_active) ActiveWindow = set.window->id;
JumpGarbageBuffer(&set);
Exec(set.view->id, true, cmd, working_dir);
return set;
BSet Exec(String cmd, String working_dir, bool set_active = true) {
BSet main = GetBSet(LastActiveLayoutWindowID);
if (set_active) {
NextActiveWindowID = main.window->id;
}
JumpGarbageBuffer(&main);
Exec(main.view->id, true, cmd, working_dir);
return main;
}
int Lua_C(lua_State *L) {
String string = lua_tostring(L, 1);
lua_pop(L, 1);
Command_Exec(string, Command_GetMainDir());
Exec(string, GetMainDir());
return 0;
}
BSet Command_Open(Window *window, String path, String meta, bool set_active = true) {
BSet Open(Window *window, String path, String meta, bool set_active = true) {
Scratch scratch;
BSet set = GetBSet(window);
path = Trim(path);
OnOpenResult ores = CallOnOpen(scratch, path, meta);
if (ores.kind == "text") {
if (set_active) {
ActiveWindow = set.window->id;
NextActiveWindowID = set.window->id;
}
if (IsDir(ores.file_path)) {
JumpGarbageBuffer(&set, GetUniqueBufferName(ores.file_path, "temp", ".dirlisting"));
Command_Appendf(set.view, "..\n");
Appendf(set.view, "..\n");
for (FileIter it = IterateFiles(scratch, ores.file_path); IsValid(it); Advance(&it)) {
Command_Appendf(set.view, "%S\n", it.filename);
Appendf(set.view, "%S\n", it.filename);
}
} else {
CheckpointBeforeGoto(set.window);
View *view = WindowOpenBufferView(set.window, ores.file_path);
View *view = WindowOpenBufferView(set.window, ores.file_path);
Buffer *buffer = GetBuffer(view->active_buffer);
if (ores.line != -1) {
if (ores.col == -1) ores.col = 1;
@@ -1144,7 +1160,7 @@ BSet Command_Open(Window *window, String path, String meta, bool set_active = tr
UpdateScroll(set.window, true);
} else if (ores.kind == "exec") {
if (set_active) {
ActiveWindow = set.window->id;
NextActiveWindowID = set.window->id;
}
JumpGarbageBuffer(&set);
Exec(set.view->id, true, ores.cmd, ores.working_dir);
@@ -1161,23 +1177,23 @@ BSet Command_Open(Window *window, String path, String meta, bool set_active = tr
return set;
}
BSet Command_Open(String path, String meta) {
BSet main = GetActiveMainSet();
main = Command_Open(main.window, path, meta);
BSet Open(String path, String meta) {
BSet main = GetBSet(LastActiveLayoutWindowID);
main = Open(main.window, path, meta);
return main;
}
BSet Command_Open(String16 path, String meta) {
BSet Open(String16 path, String meta) {
Scratch scratch;
String string = ToString(scratch, path);
return Command_Open(string, meta);
return Open(string, meta);
}
int Lua_Open(lua_State *L) {
Scratch scratch;
String path = luaL_checkstring(L, 1);
lua_pop(L, 1);
Command_Open(path);
Open(path);
return 0;
}
@@ -1189,7 +1205,7 @@ int Lua_Cmd(lua_State *L) {
String working_dir = lua_tostring(L, -1);
lua_pop(L, 1);
if (working_dir == "") {
working_dir = Command_GetMainDir();
working_dir = GetMainDir();
}
lua_getfield(L, -1, "cmd");
@@ -1201,56 +1217,68 @@ int Lua_Cmd(lua_State *L) {
String kind = lua_tostring(L, -1);
lua_pop(L, 1);
BSet main = GetActiveMainSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
if (kind == "console") {
BSet set = GetConsoleSet();
main.window->active_goto_list = set.view->id;
main.window->goto_list_pos = set.buffer->len;
Command_SelectRangeOneCursor(set.view, MakeRange(set.buffer->len));
Command_BeginJump(&set);
SelectRange(set.view, MakeRange(set.buffer->len));
BeginJump(&set);
Exec(set.view->id, true, cmd, working_dir);
Command_EndJump(set);
EndJump(set);
} else if (kind == "fuzzy") {
JumpGarbageBuffer(&main);
Exec(main.view->id, true, cmd, working_dir);
main.view->fuzzy_search = true;
ActiveWindow = main.window->id;
NextActiveWindowID = main.window->id;
} else {
JumpGarbageBuffer(&main);
main.window->active_goto_list = main.view->id;
main.window->goto_list_pos = 0;
Exec(main.view->id, true, cmd, working_dir);
ActiveWindow = main.window->id;
NextActiveWindowID = main.window->id;
}
return 0;
}
void Command_ListBuffers() {
BSet main = GetActiveMainSet();
ActiveWindow = main.window->id;
JumpGarbageBuffer(&main);
for (Buffer *it = FirstBuffer; it; it = it->next) {
RawAppendf(main.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
void Command_ShowBufferList() {
BSet command_bar = GetBSet(CommandBarWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
For(Buffers) {
RawAppendf(command_bar.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
}
main.view->fuzzy_search = true;
main.view->update_scroll = true;
Command_SelectRangeOneCursor(main.view, GetBufferEndAsRange(main.buffer));
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
}
int Lua_ListBuffers(lua_State *L) {
Command_ListBuffers();
return 0;
void Command_ShowCommandList() {
BSet command_bar = GetBSet(CommandBarWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
for (int i = 0; LuaFunctions[i].name != NULL; i += 1) {
Appendf(command_bar.view, "%s()\n ", LuaFunctions[i].name);
}
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
}
void Command_ListViews() {
BSet main = GetActiveMainSet();
ActiveWindow = main.window->id;
JumpGarbageBuffer(&main);
for (View *it = FirstView; it; it = it->next) {
BSet command_bar = GetBSet(CommandBarWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
For(Views) {
Buffer *buffer = GetBuffer(it->active_buffer);
Command_Appendf(main.view, "%d %S\n", (int)it->id.id, buffer->name);
Appendf(command_bar.view, "%d %S\n", (int)it->id.id, buffer->name);
}
command_bar.view->fuzzy_search = true;
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
}
int Lua_ListViews(lua_State *L) {
@@ -1258,7 +1286,7 @@ int Lua_ListViews(lua_State *L) {
return 0;
}
void Command_Eval(String string) {
void Eval(String string) {
if (luaL_dostring(LuaState, string.data) != LUA_OK) {
const char *error_message = lua_tostring(LuaState, -1);
ReportWarningf("Execution error! %s", error_message);
@@ -1266,15 +1294,15 @@ void Command_Eval(String string) {
}
}
void Command_Eval(String16 string) {
void Eval(String16 string) {
Scratch scratch;
Command_Eval(ToString(scratch, string));
Eval(ToString(scratch, string));
}
int Lua_Eval(lua_State *L) {
String string = lua_tostring(L, 1);
lua_pop(L, 1);
Command_Eval(string);
Eval(string);
return 0;
}
@@ -1285,42 +1313,55 @@ void SetProjectFile(Buffer *buffer) {
LuaProjectBuffer->user_change_id = -1;
}
void Command_SetProjectFile() {
BSet main = GetBSet(LastActiveLayoutWindowID);
SetProjectFile(main.buffer);
}
void Command_SetWorkDir() {
String dir = lua_tostring(LuaState, -1);
if (dir.len == 0) {
BSet main = GetBSet(LastActiveLayoutWindowID);
WorkDir = ChopLastSlash(main.buffer->name);
} else {
WorkDir = dir;
}
}
void Command_SetProject() {
Command_SetWorkDir();
Command_SetProjectFile();
}
int Lua_SetProjectFile(lua_State *L) {
BSet set = GetActiveMainSet();
SetProjectFile(set.buffer);
Command_SetProjectFile();
return 0;
}
int Lua_SetWorkDir(lua_State *L) {
String dir = lua_tostring(L, -1);
if (dir.len == 0) {
BSet set = GetActiveMainSet();
WorkDir = ChopLastSlash(set.buffer->name);
} else {
WorkDir = dir;
}
Command_SetWorkDir();
return 0;
}
int Lua_ListCommands(lua_State *L) {
BSet main = GetActiveMainSet();
Command_BeginJump(&main);
BSet main = GetBSet(LastActiveLayoutWindowID);
BeginJump(&main);
for (int i = 0; LuaFunctions[i].name != NULL; i += 1) {
Command_Appendf(main.view, "%20s() ", LuaFunctions[i].name);
Appendf(main.view, "%20s() ", LuaFunctions[i].name);
if (((i + 1) % 6) == 0) {
Command_Appendf(main.view, "\n");
Appendf(main.view, "\n");
}
}
Command_EndJump(main);
ActiveWindow = main.window->id;
EndJump(main);
NextActiveWindowID = main.window->id;
return 0;
}
int Lua_GetBufferList(lua_State *L) {
lua_createtable(L, 0, (int)BufferCount);
lua_createtable(L, 0, (int)Buffers.len);
int i = 1;
for (Buffer *it = FirstBuffer; it; it = it->next) {
For(Buffers) {
lua_pushinteger(L, i++);
lua_pushlstring(L, it->name.data, it->name.len);
lua_settable(L, -3); /* 3rd element from the stack top */
@@ -1330,7 +1371,7 @@ int Lua_GetBufferList(lua_State *L) {
}
Window *GetOverlappingWindow(Vec2I p, Window *default_window = NULL) {
for (Window *it = FirstWindow; it; it = it->next) {
For(Windows) {
if (AreOverlapping(p, it->total_rect)) {
return it;
}
@@ -1360,28 +1401,14 @@ Vec2I GetSideOfWindow(Window *window, int direction) {
}
Window *SwitchWindow(int direction) {
Window *window = GetWindow(ActiveWindow);
Window *window = GetWindow(ActiveWindowID);
Vec2I p = GetSideOfWindow(window, direction);
Window *result = GetOverlappingWindow(p, window);
return result;
}
String16 GetSearchString(Window *window) {
if (!window->is_search_bar) {
if (window->search_bar_window.id == 0) {
return {};
}
window = GetWindow(window->search_bar_window);
}
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
String16 string = GetString(buffer);
return string;
}
String16 FetchLoadWord(void) {
BSet active = GetActiveSet();
BSet active = GetBSet(ActiveWindowID);
Caret caret = active.view->carets[0];
Range range = caret.range;
if (GetSize(caret.range) == 0) range = EncloseLoadWord(active.buffer, GetFront(caret));
@@ -1389,23 +1416,27 @@ String16 FetchLoadWord(void) {
return string;
}
void SplitWindow(WindowSplitKind kind) {
Window *window = CreateWind();
View *view = OpenBufferView(ScratchBuffer->name);
window->active_view = view->id;
CreateTitlebar(window->id);
CreateSearchBar(window->id);
Window *active_window = GetActiveWind();
SplitWindowEx(NULL, &WindowSplits, active_window, window, kind);
ActiveWindow = window->id;
void Command_ToggleDebug() {
Window *window = GetWindow(DebugWindowID);
window->visible = !window->visible;
}
int Lua_Split(lua_State *L) {
lua_Integer kind = lua_tointeger(L, -1);
lua_pop(L, 1);
if (kind == 1 || kind == 2) {
SplitWindow((WindowSplitKind)kind);
}
void Command_KillProcess() {
BSet main = GetBSet(LastActiveLayoutWindowID);
KillProcess(main.view);
}
int Lua_KillProcess(lua_State *L) {
Command_KillProcess();
return 0;
}
void Command_KillWindow() {
BSet main = GetBSet(LastActiveLayoutWindowID);
main.window->kill = true;
}
int Lua_KillWindow(lua_State *L) {
Command_KillWindow();
return 0;
}

View File

@@ -46,21 +46,27 @@ void UpdateScroll(Window *window, bool update_caret_scrolling) {
}
}
void ResizerDetectMouse(Event event, WindowSplit *split) {
if (split == NULL) {
return;
}
void FuzzySearchOpen(BSet active) {
bool success = false;
Range range = active.view->carets[0].range;
if (GetSize(range) == 0) {
Int line = PosToLine(active.buffer, range.min);
if ((active.buffer->line_starts.len - 1) == line) {
line = ClampBottom(0ll, line - 1ll);
}
Vec2I mouse = MouseVec2I();
bool mouse_in_rect = AreOverlapping(mouse, split->resizer_rect);
if (mouse_in_rect) {
ResizerHover = split;
if (Mouse(LEFT)) {
ResizerSelected = split;
String16 string = GetLineStringWithoutNL(active.buffer, line);
Int idx = 0;
if (Seek(string, u"||", &idx)) {
string = Skip(string, idx + 3);
Open(string);
success = true;
}
}
ResizerDetectMouse(event, split->left);
ResizerDetectMouse(event, split->right);
if (!success) {
Open(FetchLoadWord());
}
}
void OnCommand(Event event) {
@@ -111,7 +117,7 @@ void OnCommand(Event event) {
view->scroll.y = (Int)(v * (double)s.line_count * (double)window->font->line_spacing);
}
if (DocumentSelected != ActiveWindow) {
if (DocumentSelected != ActiveWindowID) {
DocumentSelected.id = -1;
} else if (IsDocumentSelectionValid() && MouseUp()) {
Assert(ScrollbarSelected.id == -1);
@@ -120,6 +126,7 @@ void OnCommand(Event event) {
Assert(ScrollbarSelected.id == -1);
BSet selected = GetBSet(DocumentSelected);
Vec2I mouse = MouseVec2I();
// Special case for full-screen where we can have document
// aligned with monitor screen in which case mouse cursor cannot
@@ -134,26 +141,33 @@ void OnCommand(Event event) {
Int p = ScreenSpaceToBufferPos(selected.window, selected.view, selected.buffer, mouse);
Caret &caret = selected.view->carets[0];
caret = SetFrontWithAnchor(caret, DocumentAnchor, p);
}
if (ResizerSelected && Mouse(LEFT_UP)) {
if (ResizerSelected.id != -1 && Mouse(LEFT_UP)) {
Assert(DocumentSelected.id == -1);
Assert(ScrollbarSelected.id == -1);
ResizerSelected = NULL;
} else if (ResizerSelected) {
Vec2I mouse = MouseVec2I();
mouse -= ResizerSelected->total_rect.min;
Vec2I size = GetSize(ResizerSelected->total_rect);
Vec2 p = ToVec2(mouse) / ToVec2(size);
if (ResizerSelected->kind == WindowSplitKind_Vertical) {
ResizerSelected->value = p.x;
} else {
ResizerSelected->value = p.y;
ResizerSelected.id = {-1};
} else if (ResizerSelected.id != -1) {
Window *window = GetWindow(ResizerSelected);
if (window->layout) {
Vec2I mouse = MouseVec2I();
Int offx = mouse.x - window->resizer_rect.min.x;
window->weight += (double)offx / (double)WindowCalcEvenResizerValue(event.xwindow);
window->weight = Clamp(window->weight, 0.1, 100.0);
}
} else {
ResizerDetectMouse(event, &WindowSplits);
ResizerHover = {-1};
For(Windows) {
Vec2I mouse = MouseVec2I();
bool mouse_in_rect = AreOverlapping(mouse, it->resizer_rect);
if (mouse_in_rect) {
ResizerHover = it->id;
if (Mouse(LEFT)) {
ResizerSelected = it->id;
}
}
}
}
// Set active window on click
@@ -165,17 +179,19 @@ void OnCommand(Event event) {
}
bool mouse_in_document = AreOverlapping(mouse, it->document_rect);
if (mouse_in_document) {
ActiveWindow = it->id;
NextActiveWindowID = it->id;
break;
}
}
}
if (Mouse(X2)) {
GotoForward(GetActiveMainSet().window);
BSet main = GetBSet(LastActiveLayoutWindowID);
GotoForward(main.window);
}
if (Mouse(X1)) {
GotoBackward(GetActiveMainSet().window);
BSet main = GetBSet(LastActiveLayoutWindowID);
GotoBackward(main.window);
}
if (Ctrl() && Shift() && Mouse(RIGHT)) {
@@ -185,8 +201,8 @@ void OnCommand(Event event) {
} else if (Alt() && Mouse(RIGHT)) {
} else if (Mouse(RIGHT)) {
Vec2I mouse = MouseVec2I();
BSet active = GetActiveSet();
Vec2I mouse = MouseVec2I();
BSet active = GetBSet(ActiveWindowID);
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
if (mouse_in_document) {
Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse);
@@ -213,9 +229,7 @@ void OnCommand(Event event) {
}
}
if (Shift() && Ctrl() && Mouse(LEFT)) {
MouseLoadWord(event, "exec");
} else if (Ctrl() && Mouse(LEFT)) {
if (Ctrl() && Mouse(LEFT)) {
MouseLoadWord(event);
} else if (Mouse(LEFT)) { // Uses Alt and shift
Vec2I mouse = MouseVec2I();
@@ -223,12 +237,13 @@ void OnCommand(Event event) {
Assert(ScrollbarSelected.id == -1);
Assert(DocumentSelected.id == -1);
BSet active = GetActiveSet();
BSet active = GetBSet(NextActiveWindowID); // using next to make sure mouse works on first click after switching the window
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect);
if (mouse_in_document || mouse_in_line_numbers) {
CheckpointBeforeGoto(active.window);
DocumentSelected = active.window->id;
CheckpointBeforeGoto(active.window);
Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse);
if (Alt()) Insert(&active.view->carets, MakeCaret(p, p), 0);
@@ -283,41 +298,28 @@ void OnCommand(Event event) {
}
}
if (CtrlAltPress(SDLK_P)) {
Command_ListBuffers();
} else if (CtrlPress(SDLK_P)) {
Command_ListCode();
if (CtrlPress(SDLK_W)) {
Command_KillWindow();
}
if (CtrlShiftPress(SDLK_BACKSLASH)) {
SplitWindow(WindowSplitKind_Horizontal);
} else if (CtrlPress(SDLK_BACKSLASH)) {
SplitWindow(WindowSplitKind_Vertical);
if (CtrlAltPress(SDLK_P)) {
} else if (CtrlShiftPress(SDLK_P)) {
Command_ShowCommandList();
} else if (CtrlPress(SDLK_P)) {
Command_ShowBufferList();
}
if (CtrlPress(SDLK_0)) {
ToggleVisibility(DebugWindowID);
Command_ToggleDebug();
}
if (CtrlPress(SDLK_GRAVE)) {
if (ActiveWindow != NullWindowID) {
ActiveWindow = NullWindowID;
} else {
if (WindowSplits.value + 0.01 < 0.9) {
WindowSplits.value = (double)0.9;
} else {
WindowSplits.value = (double)0.6;
}
}
}
if (CtrlPress(SDLK_1)) {
ActiveWindow = GetOverlappingWindow({0,0}, GetWindow(ActiveWindow))->id;
NextActiveWindowID = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID))->id;
}
if (CtrlPress(SDLK_2)) {
Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindow));
Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID));
Vec2I p = GetSideOfWindow(first, DIR_RIGHT);
ActiveWindow = GetOverlappingWindow(p, GetWindow(ActiveWindow))->id;
NextActiveWindowID = GetOverlappingWindow(p, GetWindow(ActiveWindowID))->id;
}
if (CtrlPress(SDLK_3)) {
Window *first = GetOverlappingWindow({0,0});
@@ -326,14 +328,14 @@ void OnCommand(Event event) {
if (second) {
Window *third = GetOverlappingWindow(GetSideOfWindow(second, DIR_RIGHT));
if (third) {
ActiveWindow = third->id;
NextActiveWindowID = third->id;
}
}
}
}
BSet main = GetActiveMainSet();
BSet active = GetActiveSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
BSet active = GetBSet(ActiveWindowID);
Int buffer_change_id = active.buffer->change_id;
bool skip = CallOnCommand(&event);
@@ -344,67 +346,75 @@ void OnCommand(Event event) {
return;
}
if (active.view->fuzzy_search) {
if (Press(SDLK_RETURN)) {
FuzzySearchOpen(active);
return;
}
}
if (event.kind == EVENT_DROP_FILE) {
WindowOpenBufferView(active.window, event.text);
}
if (Press(SDLK_DOWN) || Press(SDLK_RIGHT) || Press(SDLK_LEFT) || Press(SDLK_UP)) {
CheckpointBeforeGoto(active.window);
}
if (CtrlAltPress(SDLK_DOWN)) {
Command_DuplicateLine(active.view, DIR_DOWN);
DuplicateLine(active.view, DIR_DOWN);
} else if (AltShiftPress(SDLK_DOWN)) {
Command_CreateCursorVertical(active.view, DIR_DOWN);
CreateCursorVertical(active.view, DIR_DOWN);
} else if (CtrlShiftPress(SDLK_DOWN)) {
Command_Move(active.view, DIR_DOWN, CTRL_PRESSED, SHIFT_PRESS);
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED, SHIFT_PRESS);
} else if (AltPress(SDLK_DOWN)) {
Command_MoveLine(active.view, DIR_DOWN);
MoveCaretsLine(active.view, DIR_DOWN);
} else if (CtrlPress(SDLK_DOWN)) {
Command_Move(active.view, DIR_DOWN, CTRL_PRESSED);
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED);
} else if (ShiftPress(SDLK_DOWN)) {
Command_Move(active.view, DIR_DOWN, false, SHIFT_PRESS);
MoveCarets(active.view, DIR_DOWN, false, SHIFT_PRESS);
} else if (Press(SDLK_DOWN)) {
Command_Move(active.view, DIR_DOWN);
MoveCarets(active.view, DIR_DOWN);
}
if (CtrlAltPress(SDLK_UP)) {
Command_DuplicateLine(active.view, DIR_UP);
DuplicateLine(active.view, DIR_UP);
} else if (AltShiftPress(SDLK_UP)) {
Command_CreateCursorVertical(active.view, DIR_UP);
CreateCursorVertical(active.view, DIR_UP);
} else if (CtrlShiftPress(SDLK_UP)) {
Command_Move(active.view, DIR_UP, CTRL_PRESSED, SHIFT_PRESS);
MoveCarets(active.view, DIR_UP, CTRL_PRESSED, SHIFT_PRESS);
} else if (AltPress(SDLK_UP)) {
Command_MoveLine(active.view, DIR_UP);
MoveCaretsLine(active.view, DIR_UP);
} else if (CtrlPress(SDLK_UP)) {
Command_Move(active.view, DIR_UP, CTRL_PRESSED);
MoveCarets(active.view, DIR_UP, CTRL_PRESSED);
} else if (ShiftPress(SDLK_UP)) {
Command_Move(active.view, DIR_UP, false, SHIFT_PRESS);
MoveCarets(active.view, DIR_UP, false, SHIFT_PRESS);
} else if (Press(SDLK_UP)) {
Command_Move(active.view, DIR_UP);
MoveCarets(active.view, DIR_UP);
}
if (CtrlShiftPress(SDLK_LEFT)) {
Command_Move(active.view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESS);
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESS);
} else if (CtrlPress(SDLK_LEFT)) {
Command_Move(active.view, DIR_LEFT, CTRL_PRESSED);
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED);
} else if (ShiftPress(SDLK_LEFT)) {
Command_Move(active.view, DIR_LEFT, false, SHIFT_PRESS);
MoveCarets(active.view, DIR_LEFT, false, SHIFT_PRESS);
} else if (AltPress(SDLK_LEFT)) {
ActiveWindow = SwitchWindow(DIR_LEFT)->id;
NextActiveWindowID = SwitchWindow(DIR_LEFT)->id;
} else if (Press(SDLK_LEFT)) {
Command_Move(active.view, DIR_LEFT);
MoveCarets(active.view, DIR_LEFT);
}
if (CtrlShiftPress(SDLK_RIGHT)) {
Command_Move(active.view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESS);
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESS);
} else if (CtrlPress(SDLK_RIGHT)) {
Command_Move(active.view, DIR_RIGHT, CTRL_PRESSED);
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED);
} else if (ShiftPress(SDLK_RIGHT)) {
Command_Move(active.view, DIR_RIGHT, false, SHIFT_PRESS);
MoveCarets(active.view, DIR_RIGHT, false, SHIFT_PRESS);
} else if (AltPress(SDLK_RIGHT)) {
ActiveWindow = SwitchWindow(DIR_RIGHT)->id;
NextActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
} else if (Press(SDLK_RIGHT)) {
Command_Move(active.view, DIR_RIGHT);
MoveCarets(active.view, DIR_RIGHT);
}
if (CtrlShiftPress(SDLK_Z)) {
@@ -414,152 +424,128 @@ void OnCommand(Event event) {
}
if (CtrlPress(SDLK_C)) {
Command_Copy(active.view);
ClipboardCopy(active.view);
} else if (CtrlPress(SDLK_V)) {
Command_Paste(active.view);
ClipboardPaste(active.view);
} else if (CtrlPress(SDLK_X)) {
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
Command_Copy(active.view);
Command_Replace(active.view, u"");
ClipboardCopy(active.view);
Replace(active.view, u"");
}
if (CtrlPress(SDLK_A)) {
Command_SelectEntireBuffer(active.view);
SelectEntireBuffer(active.view);
active.view->update_scroll = false;
}
if (ShiftPress(SDLK_PAGEUP)) {
Command_MoveCursorsByPageSize(active.window, DIR_UP, SHIFT_PRESS);
CheckpointBeforeGoto(active.window);
MoveCursorByPageSize(active.window, DIR_UP, SHIFT_PRESS);
} else if (CtrlPress(SDLK_PAGEUP)) {
Command_SelectRangeOneCursor(active.view, MakeRange(0));
CheckpointBeforeGoto(active.window);
SelectRange(active.view, MakeRange(0));
} else if (Press(SDLK_PAGEUP)) {
Command_MoveCursorsByPageSize(active.window, DIR_UP);
CheckpointBeforeGoto(active.window);
MoveCursorByPageSize(active.window, DIR_UP);
}
if (ShiftPress(SDLK_PAGEDOWN)) {
Command_MoveCursorsByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
CheckpointBeforeGoto(active.window);
MoveCursorByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
} else if (CtrlPress(SDLK_PAGEDOWN)) {
Command_SelectRangeOneCursor(active.view, MakeRange(active.buffer->len));
CheckpointBeforeGoto(active.window);
SelectRange(active.view, MakeRange(active.buffer->len));
} else if (Press(SDLK_PAGEDOWN)) {
Command_MoveCursorsByPageSize(active.window, DIR_DOWN);
CheckpointBeforeGoto(active.window);
MoveCursorByPageSize(active.window, DIR_DOWN);
}
if (ShiftPress(SDLK_HOME)) {
Command_MoveCursorsToSide(active.view, DIR_LEFT, SHIFT_PRESS);
CheckpointBeforeGoto(active.window);
MoveCursorToSide(active.view, DIR_LEFT, SHIFT_PRESS);
} else if (Press(SDLK_HOME)) {
Command_MoveCursorsToSide(active.view, DIR_LEFT);
CheckpointBeforeGoto(active.window);
MoveCursorToSide(active.view, DIR_LEFT);
}
if (ShiftPress(SDLK_END)) {
Command_MoveCursorsToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
CheckpointBeforeGoto(active.window);
MoveCursorToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
} else if (Press(SDLK_END)) {
Command_MoveCursorsToSide(active.view, DIR_RIGHT);
CheckpointBeforeGoto(active.window);
MoveCursorToSide(active.view, DIR_RIGHT);
}
if (CtrlShiftPress(SDLK_TAB)) {
GotoForward(main.window);
} else if (ShiftPress(SDLK_TAB)) {
Command_IndentSelectedLines(active.view, SHIFT_PRESS);
IndentSelectedLines(active.view, SHIFT_PRESS);
} else if (CtrlPress(SDLK_TAB)) {
GotoBackward(main.window);
} else if (Press(SDLK_TAB)) {
Command_IndentSelectedLines(active.view);
IndentSelectedLines(active.view);
}
if (CtrlPress(SDLK_LEFTBRACKET)) {
Command_IndentSelectedLines(active.view, SHIFT_PRESS);
IndentSelectedLines(active.view, SHIFT_PRESS);
}
if (CtrlPress(SDLK_RIGHTBRACKET)) {
Command_IndentSelectedLines(active.view);
IndentSelectedLines(active.view);
}
if (CtrlShiftPress(SDLK_K)) {
Command_KillSelectedLines(active.view);
KillSelectedLines(active.view);
}
if (CtrlPress(SDLK_BACKSPACE)) {
Command_Delete(active.view, DIR_LEFT, CTRL_PRESSED);
Delete(active.view, DIR_LEFT, CTRL_PRESSED);
} else if (Press(SDLK_BACKSPACE)) {
Command_Delete(active.view, DIR_LEFT);
Delete(active.view, DIR_LEFT);
}
if (CtrlPress(SDLK_DELETE)) {
Command_Delete(active.view, DIR_RIGHT, CTRL_PRESSED);
Delete(active.view, DIR_RIGHT, CTRL_PRESSED);
} else if (Press(SDLK_DELETE)) {
Command_Delete(active.view, DIR_RIGHT);
Delete(active.view, DIR_RIGHT);
}
if (event.kind == EVENT_TEXT_INPUT) {
Scratch scratch;
String string = event.text;
String string = event.text;
String16 string16 = ToString16(scratch, string);
Command_Replace(active.view, string16);
Replace(active.view, string16);
}
if (CtrlPress(SDLK_D)) {
CheckpointBeforeGoto(active.window);
String16 string = GetString(active.buffer, active.view->carets[0].range);
Caret caret = FindNext(active.buffer, string, active.view->carets[0]);
Insert(&active.view->carets, caret, 0);
MergeCarets(active.buffer, &active.view->carets);
}
if (CtrlShiftPress(SDLK_N)) {
Scratch scratch;
String16 search_string = GetSearchString(main.window);
Caret caret = FindPrev(main.buffer, search_string, main.view->carets[0]);
BSet search = GetBSet(main.window->search_bar_window);
search.window->search_bar_anchor = caret;
Command_SelectRangeOneCursor(main.view, caret);
} else if (CtrlPress(SDLK_N)) {
Scratch scratch;
String16 search_string = GetSearchString(main.window);
Caret caret = FindNext(main.buffer, search_string, main.view->carets[0]);
BSet search = GetBSet(main.window->search_bar_window);
search.window->search_bar_anchor = caret;
Command_SelectRangeOneCursor(main.view, caret);
}
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);
}
}
if (CtrlPress(SDLK_E)) {
Command_GotoNextInList(active.window, 1);
} else if (AltPress(SDLK_E)) {
Command_GotoNextInList(active.window, -1);
}
if (CtrlPress(SDLK_F)) {
if (!active.window->is_search_bar) {
BSet search = GetBSet(main.window->search_bar_window);
String16 string = GetString(main.buffer, main.view->carets[0].range);
if (string.len) {
Command_SelectEntireBuffer(search.view);
Command_Replace(search.view, string);
}
Command_SelectEntireBuffer(search.view);
search.window->visible = 1;
search.window->search_bar_anchor = main.view->carets[0];
ActiveWindow = search.window->id;
}
}
if (CtrlShiftPress(SDLK_RETURN)) {
Command_MoveCursorsToSide(active.view, DIR_LEFT);
Command_IdentedNewLine(active.view);
Command_Move(active.view, DIR_UP);
MoveCursorToSide(active.view, DIR_LEFT);
IdentedNewLine(active.view);
MoveCarets(active.view, DIR_UP);
} else if (CtrlPress(SDLK_RETURN)) {
Command_MoveCursorsToSide(active.view, DIR_RIGHT);
Command_IdentedNewLine(active.view);
MoveCursorToSide(active.view, DIR_RIGHT);
IdentedNewLine(active.view);
} else if (Press(SDLK_RETURN)) {
Command_IdentedNewLine(active.view);
IdentedNewLine(active.view);
}
@@ -569,7 +555,7 @@ void OnCommand(Event event) {
String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
if (active.view->prev_search_line != last_line_string) {
active.view->prev_search_line = last_line_string;
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);
Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap);
For(IterateInReverse(&ratings)) {
@@ -581,16 +567,18 @@ void OnCommand(Event event) {
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);
Caret caret = active.view->carets[0];
Command_SelectEntireBuffer(active.view);
Command_Replace(active.view, GetString(temp_buffer));
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
SelectEntireBuffer(active.view);
Replace(active.view, GetString(temp_buffer));
active.view->carets[0] = caret;
}
}
}
// if (CtrlPress(SDLK_N)) {
// Command_New();
// }
if (CtrlPress(SDLK_F)) {
Window *window = GetWindow(SearchBarWindowID);
window->visible = !window->visible;
}
if (CtrlPress(SDLK_S)) {
SaveBuffer(active.buffer);
@@ -601,16 +589,10 @@ void OnCommand(Event event) {
if (EndsWith(main.buffer->name, "dirlisting")) {
name = ChopLastSlash(name);
}
Command_Open(name);
Open(name);
}
if (CtrlPress(SDLK_T)) {
ActiveWindow = GetWindow(active.window->title_bar_window)->id;
}
if (CtrlShiftPress(SDLK_L)) {
if (CtrlShiftPress(SDLK_L)) {
EncloseSpace(active.view);
} else if (CtrlPress(SDLK_L)) {
EncloseLine(active.view);
@@ -621,57 +603,30 @@ void OnCommand(Event event) {
}
if (CtrlPress(SDLK_SEMICOLON) || CtrlShiftPress(SDLK_Q)) {
Command_Open(FetchLoadWord(), "exec");
if (AltPress(SDLK_Q)) {
GotoBackward(main.window);
}
else if (CtrlPress(SDLK_Q)) {
if (CtrlPress(SDLK_Q)) {
if (active.view->fuzzy_search) {
bool success = false;
Range range = active.view->carets[0].range;
if (GetSize(range) == 0) {
Int line = PosToLine(active.buffer, range.min);
if ((active.buffer->line_starts.len - 1) == line) {
line = ClampBottom(0ll, line - 1ll);
}
String16 string = GetLineStringWithoutNL(active.buffer, line);
Int idx = 0;
if (Seek(string, u"||", &idx)) {
string = Skip(string, idx + 3);
Command_Open(string);
success = true;
}
}
if (!success) {
Command_Open(FetchLoadWord());
}
{
Range rng = GetLineRangeWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
GetLast(active.window->goto_history)->caret = MakeCaret(rng.max, rng.min);
}
FuzzySearchOpen(active);
} else {
Command_Open(FetchLoadWord());
Open(FetchLoadWord());
}
}
if (Press(SDLK_ESCAPE)) {
if (active.window->is_search_bar) {
ActiveWindow = main.window->id;
active.window->visible = 0;
} else if (active.window->deactivate_on_escape) {
ActiveWindow = main.window->id;
} else {
active.view->carets.len = 1;
active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));
}
}
active.view->carets.len = 1;
active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));
if (active.window->is_search_bar && buffer_change_id != active.buffer->change_id) {
main.view->carets[0] = active.window->search_bar_anchor;
Command_Find(main.view, GetSearchString(main.window), true);
if (active.window->lose_focus_on_escape && active.window->id == ActiveWindowID) {
if (active.window->layout) {
//
} else {
NextActiveWindowID = LastActiveLayoutWindowID;
}
}
}
// :OnCommandEnding

View File

@@ -33,7 +33,7 @@ void SaveStringInClipboard(String16 string) {
_SetClipboardText(ToString(scratch, SavedClipboardString).data);
}
void Command_Copy(View *view) {
void ClipboardCopy(View *view) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
@@ -59,7 +59,7 @@ void Command_Copy(View *view) {
_SetClipboardText(ToString(scratch, SavedClipboardString).data);
}
void Command_Paste(View *view) {
void ClipboardPaste(View *view) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
const char *text = GetClipboardText();

View File

@@ -46,7 +46,7 @@ void DrawVisibleText(Window *window, Color tint) {
Rect2I visible = GetVisibleCells(window);
for (Int line_index = visible.min.y; line_index < visible.max.y && line_index >= 0 && line_index < buffer->line_starts.len; line_index += 1) {
String16 line_string = GetLineString(buffer, line_index);
Vec2I pos = Vec2I{visible.min.x, line_index} * (Int)window->font->line_spacing - view->scroll + window->document_rect.min;
Vec2I pos = Vec2I{visible.min.x, line_index} * Vec2I{(Int)window->font->char_spacing, (Int)window->font->line_spacing} - view->scroll + window->document_rect.min;
float text_offset_x = 0;
for (Int col_index = visible.min.x; col_index < visible.max.x && col_index >= 0 && col_index < line_string.len; col_index += 1) {
@@ -105,8 +105,8 @@ void DrawWindow(Window *window, Event &event) {
Rect2 screen_rect = Rect0Size(event.xwindow, event.ywindow);
SetScissor(screen_rect);
bool is_actib = window->id == ActiveWindow || window->title_bar_window == ActiveWindow || window->search_bar_window == ActiveWindow;
bool is_active = window->id == ActiveWindow;
bool is_active = window->id == ActiveWindowID;
bool active_layed_out_doc = window->id == LastActiveLayoutWindowID;
Color color_whitespace_during_selection = ColorWhitespaceDuringSelection;
Color color_background = ColorBackground;
@@ -116,7 +116,8 @@ void DrawWindow(Window *window, Event &event) {
Color color_sub_caret = ColorSubCaret;
Color color_text_line_numbers = ColorTextLineNumbers;
Color color_text = ColorText;
if (window->is_title_bar || window->is_search_bar) {
if (window->draw_darker) {
if (is_active) {
color_background = ColorTitleBarActiveBackground;
} else {
@@ -127,7 +128,12 @@ void DrawWindow(Window *window, Event &event) {
color_line_highlight = ColorTitleBarBackground;
}
DrawRect(window->total_rect, color_background);
if (window->draw_darker) {
Rect2I rect = window->total_rect;
DrawRect(CutTop(&rect, 1), ColorResizerOutline);
}
Rect2I combined_document_line_number = window->document_rect;
if (window->draw_line_numbers) combined_document_line_number.min.x = window->line_numbers_rect.min.x;
@@ -182,7 +188,7 @@ void DrawWindow(Window *window, Event &event) {
}
}
}
} else if (!window->is_title_bar && !window->is_search_bar) {
} else if (window->draw_line_highlight) {
//
// Draw highlight
Int front = GetFront(it);
@@ -226,8 +232,9 @@ void DrawWindow(Window *window, Event &event) {
EndProfileScope();
DrawVisibleText(window, color_text);
BeginProfileScope(draw_carets);
if (is_actib) {
// Draw caret "|" markings
if (is_active) {
BeginProfileScope(draw_carets);
For(view->carets) {
Int front = GetFront(it);
XY fxy = PosToXY(buffer, front);
@@ -236,8 +243,8 @@ void DrawWindow(Window *window, Event &event) {
DrawCaret(window, fxy, 0.3f, main_caret ? color_main_caret : color_sub_caret);
}
}
EndProfileScope();
}
EndProfileScope();
// Draw line numbers
if (window->draw_line_numbers) {
@@ -271,31 +278,22 @@ void DrawWindow(Window *window, Event &event) {
DrawRect(rect, color);
}
if (window->z == 1) {
// color the floating object to make it stand out
if (window->z >= 1) {
SetScissor(window->total_rect);
DrawRect(window->total_rect, {255, 255, 255, 25});
}
if (!is_actib) {
// darken the inactive windows
if (!is_active) {
SetScissor(screen_rect);
DrawRect(window->total_rect, ColorInactiveWindow);
}
}
void DrawSplits(WindowSplit *split) {
if (split == NULL) {
return;
// Draw resizer rect
{
Rect2I rect = window->resizer_rect;
DrawRect(rect, ColorResizerBackground);
DrawRect(CutRight(&rect, 1), ColorResizerOutline);
}
Rect2I rect = split->resizer_rect;
DrawRect(split->resizer_rect, ColorResizerBackground);
if (split->kind == WindowSplitKind_Vertical) {
Rect2I s = CutRight(&rect, 1);
DrawRect(s, ColorResizerOutline);
} else if (split->kind == WindowSplitKind_Horizontal) {
Rect2I s = CutBottom(&rect, 1);
DrawRect(s, ColorResizerOutline);
}
DrawSplits(split->left);
DrawSplits(split->right);
}

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,32 +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);
}

View File

@@ -69,6 +69,7 @@ Style.Font = GetExeDir().."/CascadiaMono.ttf"
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
Style.TrimWhitespaceOnSave = true
Style.ClangFormatOnSave = false
Style.StyleUndoMergeTimeout = 0.3
INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
OS_WINDOWS = 0
@@ -324,10 +325,6 @@ function MatchGotoBuild(s, meta)
end
function MatchExec(s, meta)
if meta ~= "exec" then
return nil
end
if s:match(".exe$") or s:match(".bat$") or s:match(".sh$") then
return {kind = "exec_console", cmd = s, working_dir = GetMainDir()}
end
@@ -336,8 +333,7 @@ function MatchExec(s, meta)
return {kind = "exec_console", cmd = s:sub(2, -1), working_dir = GetMainDir()}
end
Eval(s)
return {kind = "skip"}
return nil
end
BuiltinOnOpenMatchers = {

View File

@@ -1,67 +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";

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

@@ -4,9 +4,9 @@ int Lua_print(lua_State *L) {
View *null_view = GetView(NullViewID);
for (int i = 1; i <= nargs; i += 1) {
String string = lua_tostring(L, i);
Command_Appendf(null_view, "%S ", string);
Appendf(null_view, "%S ", string);
}
Command_Appendf(null_view, "\n");
Appendf(null_view, "\n");
lua_pop(L, nargs);
return 0;
}
@@ -16,21 +16,15 @@ int Lua_Print(lua_State *L) {
int nargs = lua_gettop(L);
for (int i = 1; i <= nargs; i += 1) {
String string = lua_tostring(L, i);
Command_Appendf(TraceView, "%S ", string);
Appendf(TraceView, "%S ", string);
}
Command_Appendf(TraceView, "\n");
Appendf(TraceView, "\n");
lua_pop(L, nargs);
return 0;
}
int Lua_Kill(lua_State *L) {
BSet main = GetActiveMainSet();
KillProcess(main.view);
return 0;
}
int Lua_GetLoadWord(lua_State *L) {
BSet active = GetActiveSet();
BSet active = GetBSet(ActiveWindowID);
Range range = active.view->carets[0].range;
if (GetSize(range) == 0) {
range = EncloseLoadWord(active.buffer, range.min);
@@ -52,7 +46,7 @@ int Lua_BufferExists(lua_State *L) {
int Lua_GetSelection(lua_State *L) {
Scratch scratch;
BSet main = GetActiveMainSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
String16 string16 = GetString(main.buffer, main.view->carets[0].range);
String string = ToString(scratch, string16);
lua_pushlstring(L, string.data, string.len);
@@ -61,7 +55,7 @@ int Lua_GetSelection(lua_State *L) {
int Lua_GetEntireBuffer(lua_State *L) {
Scratch scratch;
BSet main = GetActiveMainSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
String16 string16 = GetString(main.buffer);
String string = ToString(scratch, string16);
lua_pushlstring(L, string.data, string.len);
@@ -76,13 +70,13 @@ int Lua_GetClipboard(lua_State *L) {
}
int Lua_GetFilename(lua_State *L) {
BSet main = GetActiveMainSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
lua_pushlstring(L, main.buffer->name.data, main.buffer->name.len);
return 1;
}
int Lua_GetLine(lua_State *L) {
BSet main = GetActiveMainSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
Caret caret = main.view->carets[0];
Int front = GetFront(caret);
Int line = PosToLine(main.buffer, front);
@@ -111,211 +105,11 @@ int Lua_GetExeDir(lua_State *L) {
}
int Lua_GetMainDir(lua_State *L) {
String name = Command_GetMainDir();
String name = GetMainDir();
lua_pushlstring(L, name.data, name.len);
return 1;
}
int Lua_SplitSize(lua_State *L) {
lua_Number num = lua_tonumber(L, 1);
lua_pop(L, 1);
BSet set = GetActiveMainSet();
WindowSplit *split = set.window->split_ref;
split->parent->value = num;
return 0;
}
int Lua_KillWindow(lua_State *L) {
BSet set = GetActiveMainSet();
set.window->kill = true;
return 0;
}
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");
}
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 GetInt(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 GetFloat(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 *GetString(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)Get##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 (Window *it = FirstWindow; it; it = it->next) {
if (it->is_title_bar || it->is_search_bar) {
continue;
}
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;
@@ -344,7 +138,7 @@ OnOpenResult CallOnOpen(Allocator allocator, String path, String meta) {
result.working_dir = working_dir;
result.file_path = file_path;
if (!IsAbsolute(result.file_path)) {
String dir = Command_GetMainDir();
String dir = GetMainDir();
result.file_path = Format(allocator, "%S/%S", dir, result.file_path);
}
if (col_string.len) {
@@ -396,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

@@ -2,7 +2,7 @@ luaL_Reg LuaFunctions[] = {
{"print", Lua_print},
{"Print", Lua_Print},
{"SaveAll", Lua_SaveAll},
{"Kill", Lua_Kill},
{"KillProcess", Lua_KillProcess},
{"GetLoadWord", Lua_GetLoadWord},
{"BufferExists", Lua_BufferExists},
{"GetSelection", Lua_GetSelection},
@@ -14,7 +14,6 @@ luaL_Reg LuaFunctions[] = {
{"GetWorkDir", Lua_GetWorkDir},
{"GetExeDir", Lua_GetExeDir},
{"GetMainDir", Lua_GetMainDir},
{"SplitSize", Lua_SplitSize},
{"KillWindow", Lua_KillWindow},
{"Play", Lua_Play},
{"TrimTrailingWhitespace", Lua_TrimTrailingWhitespace},
@@ -30,13 +29,11 @@ luaL_Reg LuaFunctions[] = {
{"C", Lua_C},
{"Open", Lua_Open},
{"Cmd", Lua_Cmd},
{"ListBuffers", Lua_ListBuffers},
{"ListViews", Lua_ListViews},
{"Eval", Lua_Eval},
{"SetProjectFile", Lua_SetProjectFile},
{"SetWorkDir", Lua_SetWorkDir},
{"ListCommands", Lua_ListCommands},
{"GetBufferList", Lua_GetBufferList},
{"Split", Lua_Split},
{NULL, NULL},
};

View File

@@ -1,277 +1,3 @@
WindowID WindowIDs;
ViewID ViewIDs;
Window *FirstWindow;
Window *LastWindow;
Int WindowCount;
View *FirstView;
View *LastView;
Int ViewCount;
Buffer *FirstBuffer;
Buffer *LastBuffer;
Int BufferCount;
// console
BufferID NullBufferID;
ViewID NullViewID;
WindowID NullWindowID;
// hidden floating window
WindowID DebugWindowID;
ViewID DebugViewID;
BufferID DebugBufferID;
WindowSplit WindowSplits;
WindowID ActiveWindow;
WindowSplit *ResizerSelected = NULL;
WindowSplit *ResizerHover = NULL;
WindowID ScrollbarSelected = {-1};
WindowID DocumentSelected = {-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) {
for (Window *it = FirstWindow; it; it = it->next) {
if (it->id == id) return it;
}
return FirstWindow;
}
inline Buffer *GetBuffer(BufferID id) {
for (Buffer *it = FirstBuffer; it; it = it->next) {
if (it->id == id) return it;
}
return FirstBuffer;
}
inline Buffer *FindBuffer(BufferID id) {
for (Buffer *it = FirstBuffer; it; it = it->next) {
if (it->id == id) return it;
}
return NULL;
}
inline Buffer *GetBuffer(String name) {
for (Buffer *it = FirstBuffer; it; it = it->next) {
if (it->name == name) return it;
}
return FirstBuffer;
}
inline Buffer *FindBuffer(String name) {
for (Buffer *it = FirstBuffer; it; it = it->next) {
if (it->name == name) return it;
}
return NULL;
}
inline View *GetView(ViewID id) {
for (View *it = FirstView; it; it = it->next) {
if (it->id == id) return it;
}
return FirstView;
}
inline bool IsNull(Buffer *buffer) { return buffer->id.id == NullBufferID.id; }
inline Window *GetActiveWind() { return GetWindow(ActiveWindow); }
Buffer *CreateBuffer(Allocator allocator, String name, Int size) {
Buffer *result = AllocBuffer(allocator, name, size);
DLL_QUEUE_ADD(FirstBuffer, LastBuffer, result);
BufferCount += 1;
return result;
}
Window *CreateWind(bool create_command_buffer = true) {
Window *w = AllocType(SysAllocator, Window);
w->font = &PrimaryFont;
w->visible = true;
w->draw_scrollbar = StyleDrawScrollbar;
w->draw_line_numbers = StyleDrawLineNumbers;
w->id = AllocWindowID(w);
DLL_QUEUE_ADD(FirstWindow, LastWindow, w);
WindowCount += 1;
return w;
}
// void DestroyWindow(Window *window) {
// WindowSplit *split = window->split_ref;
// if (split->parent == NULL) {
// Assert(split->kind == WindowSplitKind_Window);
// return;
// }
//
// WindowSplit *p = split->parent;
// WindowSplit *valid_node = p->left == split ? p->right : p->left;
// if (p->parent == NULL) {
// // @todo:
// } else {
// valid_node->parent = p->parent;
// *p = *valid_node;
// }
//
// // @leak window
// DLL_QUEUE_REMOVE(FirstWindow, LastWindow, window);
// WindowCount -= 1;
//
// if (window->search_bar_window.id) {
// Window *s = GetWindow(window->search_bar_window);
// DLL_QUEUE_REMOVE(FirstWindow, LastWindow, s);
// WindowCount -= 1;
// }
//
// if (window->title_bar_window.id) {
// Window *s = GetWindow(window->title_bar_window);
// DLL_QUEUE_REMOVE(FirstWindow, LastWindow, s);
// WindowCount -= 1;
// }
// }
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});
DLL_QUEUE_ADD(FirstView, LastView, view);
ViewCount += 1;
return view;
}
View *FindView(ViewID view_id, View *default_view = NULL) {
for (View *it = FirstView; it; it = it->next) {
if (it->id == view_id) {
return it;
}
}
return default_view;
}
View *FindView(BufferID buffer_id, View *default_view = NULL) {
for (View *it = FirstView; it; it = it->next) {
if (it->active_buffer == buffer_id) {
return it;
}
}
return default_view;
}
Window *FindWindow(ViewID view_id, Window *default_window = NULL) {
for (Window *it = FirstWindow; it; it = it->next) {
if (it->active_view == view_id) {
return it;
}
}
return default_window;
}
Window *FindWindow(String buffer_name, Window *default_window = NULL) {
for (Window *it = FirstWindow; it; it = it->next) {
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 (Window *it = FirstWindow; it; it = it->next) {
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 (View *it = FirstView; it; it = it->next) {
Buffer *buffer = GetBuffer(it->active_buffer);
if (buffer->name == name) {
return it;
}
}
return default_view;
}
Window *GetTitlebarWindow(WindowID id) {
Window *window = GetWindow(id);
if (!window->is_title_bar) window = GetWindow(window->title_bar_window);
Assert(window->is_title_bar);
return window;
}
BSet GetBSet(Window *window) {
BSet set = {window};
set.view = GetView(set.window->active_view);
@@ -285,30 +11,6 @@ BSet GetBSet(WindowID window_id) {
return result;
}
BSet GetTitleSet(Window *window) {
if (!window->is_title_bar) window = GetWindow(window->title_bar_window);
BSet result = GetBSet(window);
return result;
}
BSet GetMainSet(Window *window) {
if (window->is_title_bar) window = GetWindow(window->title_bar_window);
BSet result = GetBSet(window);
return result;
}
BSet GetActiveSet() {
Window *window = GetWindow(ActiveWindow);
return GetBSet(window);
}
BSet GetActiveMainSet() {
Window *window = GetWindow(ActiveWindow);
if (window->is_title_bar) window = GetWindow(window->title_bar_window);
if (window->is_search_bar) window = GetWindow(window->search_bar_window);
return GetBSet(window);
}
BSet GetConsoleSet() {
BSet result = {};
result.window = GetWindow(NullWindowID);
@@ -317,15 +19,9 @@ BSet GetConsoleSet() {
return result;
}
BSet GetActiveTitleSet() {
Window *window = GetWindow(ActiveWindow);
if (!window->is_title_bar) window = GetWindow(window->title_bar_window);
return GetBSet(window);
}
String Command_GetFilename() {
BSet set = GetActiveMainSet();
return set.buffer->name;
String GetCurrentFilename() {
BSet main = GetBSet(LastActiveLayoutWindowID);
return main.buffer->name;
}
String GetDir(Buffer *buffer) {
@@ -333,156 +29,36 @@ String GetDir(Buffer *buffer) {
return name;
}
String Command_GetMainDir() {
BSet set = GetActiveMainSet();
String name = ChopLastSlash(set.buffer->name);
String GetMainDir() {
BSet main = GetBSet(LastActiveLayoutWindowID);
String name = ChopLastSlash(main.buffer->name);
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) {
for (Window *window = FirstWindow; window; window = window->next) {
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 (Window *it = FirstWindow; it; it = it->next) {
if (it->active_view == view || it->active_goto_list == 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();
for (Buffer *it = FirstBuffer; it; it = it->next) {
ActiveWindowID = NextActiveWindowID;
For (Windows) {
if (it->sync_visibility_with_focus) {
if (it->id == ActiveWindowID) {
it->visible = true;
} else {
it->visible = false;
}
}
}
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
Window *window = GetWindow(ActiveWindowID);
if (window->layout) {
LastActiveLayoutWindowID = ActiveWindowID;
}
}
For(Buffers) {
if (it->file_mod_time) {
int64_t new_file_mod_time = GetFileModTime(it->name);
if (it->file_mod_time != new_file_mod_time) {
@@ -492,8 +68,8 @@ void GarbageCollect() {
}
}
for (View *it = FirstView, *next = NULL; it; it = next) {
next = it->next;
IterRemove(Views) {
IterRemovePrepare(Views);
Buffer *buffer = GetBuffer(it->active_buffer);
if (!buffer->garbage) {
@@ -505,13 +81,13 @@ void GarbageCollect() {
continue;
}
DLL_QUEUE_REMOVE(FirstView, LastView, it);
remove_item = true;
Dealloc(&it->carets);
Dealloc(sys_allocator, it);
}
for (Buffer *it = FirstBuffer, *next = NULL; it; it = next) {
next = it->next;
IterRemove(Buffers) {
IterRemovePrepare(Buffers);
if (!it->garbage) {
continue;
@@ -522,14 +98,17 @@ void GarbageCollect() {
continue;
}
DLL_QUEUE_REMOVE(FirstBuffer, LastBuffer, it);
remove_item = true;
DeallocBuffer(it);
}
// for (Window *it = FirstWindow, *next = NULL; it; it = next) {
// next = it->next;
// if (it->kill) {
// DestroyWindow(it);
// }
// }
IterRemove(Windows) {
IterRemovePrepare(Windows);
if (it->kill) {
Dealloc(&it->goto_history);
Dealloc(&it->goto_redo);
Dealloc(sys_allocator, it);
remove_item = true;
}
}
}

View File

@@ -15,7 +15,7 @@ void UpdateProcesses() {
String poll = PollStdout(scratch, &it, false);
if (poll.len) {
Command_Append(view, poll, it.scroll_to_end);
Append(view, poll, it.scroll_to_end);
}
if (!IsValid(&it)) {
ReportDebugf("process %lld exit code = %d", it.id, it.exit_code);
@@ -60,7 +60,7 @@ void KillProcess(View *view) {
KillProcess(&it);
remove_item = true;
String string = "process was killed by user\n";
Command_Append(view, string, it.scroll_to_end);
Append(view, string, it.scroll_to_end);
// dont break because that will fuck with removal ...
}
}

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 = true;
#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 = true;
#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), {
@@ -194,12 +84,21 @@ void SetMouseCursor(Event event) {
Array<Window *> order = GetWindowZOrder(scratch);
Vec2I mouse = MouseVec2I();
if (ResizerSelected) {
WindowSplit *split = ResizerSelected;
if (split->kind == WindowSplitKind_Vertical) {
if (ResizerSelected.id != -1) {
Window *window = GetWindow(ResizerSelected);
if (window->layout) {
SetMouseCursor(SDL_SYSTEM_CURSOR_EW_RESIZE);
} else {
SetMouseCursor(SDL_SYSTEM_CURSOR_NS_RESIZE);
}
return;
}
if (ResizerHover.id != -1) {
Window *window = GetWindow(ResizerHover);
if (window->layout) {
SetMouseCursor(SDL_SYSTEM_CURSOR_EW_RESIZE);
} else {
Assert(split->kind == WindowSplitKind_Horizontal);
SetMouseCursor(SDL_SYSTEM_CURSOR_NS_RESIZE);
}
return;
@@ -219,16 +118,7 @@ void SetMouseCursor(Event event) {
}
}
if (ResizerHover) {
WindowSplit *split = ResizerHover;
if (split->kind == WindowSplitKind_Vertical) {
SetMouseCursor(SDL_SYSTEM_CURSOR_EW_RESIZE);
} else {
Assert(split->kind == WindowSplitKind_Horizontal);
SetMouseCursor(SDL_SYSTEM_CURSOR_NS_RESIZE);
}
return;
}
SetMouseCursor(SDL_SYSTEM_CURSOR_DEFAULT);
}
@@ -246,14 +136,12 @@ void Update(Event event) {
}
OnCommand(event);
for (Window *it = FirstWindow; it; it = it->next) {
if (it->is_title_bar) ReplaceTitleBarData(it);
}
UpdateProcesses();
CoUpdate(&event);
ReloadLuaConfigs();
CallLuaOnUpdate(&event);
StatusBarUpdate();
UpdateDebugBuffer();
CallLuaOnUpdate(&event);
GarbageCollect();
For(IterateInReverse(&order)) {
@@ -264,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;
{
@@ -301,7 +159,7 @@ void Windows_SetupVCVarsall(mco_coro *co) {
String working_dir = WorkDir;
String buffer_name = GetUniqueBufferName(working_dir, "vcvarsall-");
String cmd = Format(scratch, "\"%S\" && set", StyleVCVarsall);
view = Command_ExecHidden(buffer_name, cmd, working_dir);
view = ExecHidden(buffer_name, cmd, working_dir);
}
for (;;) {
if (!ProcessIsActive(view->id)) {
@@ -368,7 +226,6 @@ void MainLoop() {
SetMouseCursor(*event);
LayoutWindows(event->xwindow, event->ywindow); // This is here to render changes in title bar size without a frame of delay
BeginFrameRender(event->xwindow, event->ywindow);
DrawSplits(&WindowSplits);
Array<Window *> order = GetWindowZOrder(scratch);
For(IterateInReverse(&order)) {
@@ -489,7 +346,7 @@ int main(int argc, char **argv)
InitBuffers();
InitRender();
ReloadFont();
ReloadFont(StyleFont, (U32)StyleFontSize);
InitWindows();
InitOS(ReportWarningf);

View File

@@ -1,97 +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;
View *next;
View *prev;
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;
const char *EventKindStrings[] = {
#define X(TYPE) #TYPE,
EVENT_KINDS
#undef X
};
struct Window {
WindowID id;
ViewID active_view;
Window *next;
Window *prev;
WindowSplit *split_ref;
#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
WindowID title_bar_window;
Int title_bar_last_buffer_change_id; // @todo: bring back the changes to title bar?
WindowID search_bar_window;
Rect2I total_rect;
Rect2I document_rect;
Rect2I scrollbar_rect;
Rect2I line_numbers_rect;
Array<GotoCrumb> goto_history;
Array<GotoCrumb> goto_redo;
ViewID active_goto_list;
Int goto_list_pos;
Font *font;
Caret search_bar_anchor;
double mouse_scroller_offset;
int z;
struct {
bool draw_scrollbar : 1;
bool draw_line_numbers : 1;
bool visible : 1;
bool is_title_bar : 1;
bool is_search_bar : 1;
bool deactivate_on_escape : 1;
bool kill : 1;
};
};
enum WindowSplitKind {
WindowSplitKind_Window,
WindowSplitKind_Vertical,
WindowSplitKind_Horizontal,
};
struct WindowSplit {
WindowSplitKind kind;
WindowSplit *left;
WindowSplit *right;
WindowSplit *parent;
Rect2I total_rect;
Rect2I resizer_rect;
Window *window;
double value;
};
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;
};
@@ -106,42 +70,38 @@ 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 Command_Open(String path, String meta = "");
BSet Command_Open(String16 path, String meta = "");
BSet Open(String path, String meta = "");
BSet Open(String16 path, String meta = "");
void UpdateScroll(Window *window, bool update_caret_scrolling);
void Command_SelectEntireBuffer(View *view);
void Command_Replace(View *view, String16 string);
void Command_SelectRangeOneCursor(View *view, Range range);
void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line);
void Command_Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line);
Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string);
void Command_Eval(String string);
void Command_Eval(String16 string);
String Command_GetMainDir();
void SelectEntireBuffer(View *view);
void Replace(View *view, String16 string);
void SelectRange(View *view, Range range);
void Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line);
void Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line);
Array<Edit> ReplaceEx(Allocator scratch, View *view, String16 string);
void Eval(String string);
void Eval(String16 string);
void ReportDebugf(const char *fmt, ...);
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string);
void Command_Copy(View *view);
void Command_Paste(View *view);
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string);
void ClipboardCopy(View *view);
void ClipboardPaste(View *view);
void ReportConsolef(const char *fmt, ...);
void ReportErrorf(const char *fmt, ...);
void ReportWarningf(const char *fmt, ...);
void Command_Appendf(View *view, const char *fmt, ...);
void Appendf(View *view, const char *fmt, ...);
Buffer *CreateBuffer(Allocator allocator, String name, Int size = 4096);
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; }

View File

@@ -5,7 +5,7 @@ void UpdateDebugBuffer() {
View *view = GetView(window->active_view);
if (view->active_buffer.id == buffer->id.id) return;
BSet main = GetActiveMainSet();
BSet main = GetBSet(LastActiveLayoutWindowID);
Scratch scratch;
String s = Format(scratch, "wid: %d\nvid: %d\nbid: %d\nframe: %lld\n", (int)main.window->id.id, (int)main.view->id.id, (int)main.buffer->id.id, (long long)FrameID);
@@ -17,8 +17,6 @@ void UpdateDebugBuffer() {
RawAppendf(buffer, "mouse: [%f, %f]\n", xmouse, ymouse);
RawAppendf(buffer, "BufferID id = %d\n", main.buffer->id.id);
RawAppendf(buffer, "Buffer *next = %zu\n", main.buffer->next);
RawAppendf(buffer, "Buffer *prev = %zu\n", main.buffer->prev);
RawAppendf(buffer, "String name = %S\n", main.buffer->name);
RawAppendf(buffer, "Int change_id = %lld\n", (long long)main.buffer->change_id);
RawAppendf(buffer, "Int user_change_id = %lld\n", (long long)main.buffer->user_change_id);
@@ -43,10 +41,15 @@ void UpdateDebugBuffer() {
RawAppendf(buffer, "int garbage = %d\n", main.buffer->garbage);
}
void ReplaceTitleBarData(Window *window) {
void StatusBarUpdate() {
Window *status_bar_window = GetWindow(StatusBarWindowID, NULL);
if (status_bar_window == NULL) {
return;
}
Scratch scratch;
BSet main = GetMainSet(window);
BSet title = GetBSet(window);
BSet main = GetBSet(LastActiveLayoutWindowID);
BSet title = GetBSet(status_bar_window);
title.view->scroll.y = 0;
String16 buffer_string = GetString(title.buffer);
@@ -54,11 +57,12 @@ void ReplaceTitleBarData(Window *window) {
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
// Parse the title and line
if (window->id == ActiveWindow) {
if (title.buffer->change_id == title.window->title_bar_last_buffer_change_id) {
if (title.window->id == ActiveWindowID) {
if (title.buffer->change_id == title.window->status_bar_last_buffer_change_id) {
return;
}
String16 buffer_name = GetString(title.buffer, replace_range);
buffer_name = Skip(buffer_name, 1);
buffer_name = Trim(buffer_name);
Int column = ChopNumber(&buffer_name);
@@ -70,64 +74,41 @@ void ReplaceTitleBarData(Window *window) {
column = 0;
}
String name = ToString(scratch, buffer_name);
if (name != main.buffer->name) {
name = GetAbsolutePath(scratch, name);
if (FindBuffer(name)) {
title.window->title_bar_last_buffer_change_id = title.buffer->change_id;
ReportConsolef("there is already buffer with name: %S", name);
return;
}
if (name != main.buffer->name) {
main.buffer->name = Intern(&GlobalInternTable, name);
title.window->title_bar_last_buffer_change_id = title.buffer->change_id;
main.buffer->file_mod_time = 0;
main.buffer->changed_on_disk = false;
main.buffer->dirty = true;
}
}
Int buffer_pos = XYToPos(main.buffer, {column, line});
Caret &caret = main.view->carets[0];
if (GetFront(caret) != buffer_pos) {
caret = MakeCaret(buffer_pos);
}
title.window->status_bar_last_buffer_change_id = title.buffer->change_id;
return;
}
Caret caret = main.view->carets[0];
XY xy = PosToXY(main.buffer, GetFront(caret));
Array<Caret> caret_copy = Copy(GetSystemAllocator(), title.view->carets);
defer {
Dealloc(&title.view->carets);
title.view->carets = caret_copy;
};
// add separator at the end of buffer
if (!found_separator) {
Command_SelectRangeOneCursor(title.view, GetBufferEndAsRange(title.buffer));
Array<Edit> edits = Command_ReplaceEx(scratch, title.view, u" |");
AdjustCarets(edits, &caret_copy);
SelectRange(title.view, GetBufferEndAsRange(title.buffer));
Array<Edit> edits = ReplaceEx(scratch, title.view, u" |");
}
// replace data up to separator with filename and stuff
const char *reopen = main.buffer->changed_on_disk ? " Reopen()" : "";
String s = Format(scratch, "%S:%lld:%lld%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen);
String s = Format(scratch, "# %S:%lld:%lld%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen);
For (ActiveProcesses) {
if (it.view_id == main.view->id.id) {
s = Format(scratch, "%S %lld", s, (long long)it.id);
s = Format(scratch, "%S %lld Kill()", s, (long long)it.id);
}
}
String16 string = ToString16(scratch, s);
String16 string_to_replace = GetString(title.buffer, replace_range);
if (string_to_replace != string) {
Command_SelectRangeOneCursor(title.view, replace_range);
Array<Edit> edits = Command_ReplaceEx(scratch, title.view, string);
Command_SelectRangeOneCursor(title.view, MakeRange(0));
AdjustCarets(edits, &caret_copy);
SelectRange(title.view, replace_range);
Array<Edit> edits = ReplaceEx(scratch, title.view, string);
}
SelectRange(title.view, MakeRange(0));
ResetHistory(title.buffer);
}

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,188 +1,169 @@
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 (Window *it = FirstWindow; it; it = it->next) if (it->z == 2) Add(&order, it);
for (Window *it = FirstWindow; it; it = it->next) if (it->z == 1) Add(&order, it);
for (Window *it = FirstWindow; it; it = it->next) if (it->z == 0) Add(&order, it);
For(Windows) if (it->z == 2) Add(&order, it);
For(Windows) if (it->z == 1) Add(&order, it);
For(Windows) if (it->z == 0) Add(&order, it);
return order;
}
Window *CreateSearchBar(WindowID parent_window_id) {
Window *window = CreateWind(false);
window->draw_scrollbar = false;
window->deactivate_on_escape = true;
window->is_search_bar = true;
static int BarCount;
Allocator sys_allocator = GetSystemAllocator();
String name = Format(sys_allocator, "%S/searchbar%d", WorkDir, ++BarCount);
Buffer *b = CreateBuffer(sys_allocator, name);
View *v = CreateView(b->id);
window->active_view = v->id;
Window *parent_window = GetWindow(parent_window_id);
parent_window->search_bar_window = window->id;
window->search_bar_window = parent_window->id;
window->z = parent_window->z + 1;
window->visible = false;
return window;
}
Window *CreateTitlebar(WindowID parent_window_id) {
Window *window = CreateWind(false);
window->font = &SecondaryFont;
window->draw_scrollbar = false;
window->deactivate_on_escape = true;
window->is_title_bar = true;
static int TitlebarCount;
Allocator sys_allocator = GetSystemAllocator();
String name = Format(sys_allocator, "%S/titlebar%d", WorkDir, ++TitlebarCount);
Buffer *b = CreateBuffer(sys_allocator, name);
View *v = CreateView(b->id);
window->active_view = v->id;
Window *parent_window = GetWindow(parent_window_id);
parent_window->title_bar_window = window->id;
window->title_bar_window = parent_window->id;
void ReplaceTitleBarData(Window * window);
ReplaceTitleBarData(window);
return window;
}
Int GetTitleBarSize(Window *window) {
Int GetExpandingBarSize(Window *window) {
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
float result = (float)buffer->line_starts.len * window->font->line_spacing;
return (Int)result;
}
WindowSplit *CreateSplitForWindow(WindowSplit *parent, Window *window) {
WindowSplit *split = AllocType(SysAllocator, WindowSplit);
split->kind = WindowSplitKind_Window;
split->window = window;
split->parent = parent;
window->split_ref = split;
return split;
}
void SplitWindowEx(WindowSplit **node, WindowSplit *split, Window *target, Window *new_window, WindowSplitKind kind) {
if (split->kind == WindowSplitKind_Horizontal || split->kind == WindowSplitKind_Vertical) {
SplitWindowEx(&split->left, split->left, target, new_window, kind);
SplitWindowEx(&split->right, split->right, target, new_window, kind);
} else {
Assert(split->kind == WindowSplitKind_Window);
if (target != split->window) {
return;
}
WindowSplit *hori = AllocType(SysAllocator, WindowSplit);
hori->parent = node[0]->parent;
hori->kind = kind;
hori->value = 0.5;
hori->left = *node;
hori->right = CreateSplitForWindow(hori, new_window);
*node = hori;
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;
}
}
void SetVisibility(WindowID window_id, bool v) {
Window *window = GetWindow(window_id);
window->visible = v;
if (window->title_bar_window.id != 0) {
Window *title_bar = GetWindow(window->title_bar_window);
title_bar->visible = v;
Window *window = FindWindow(view->id);
if (!window) {
new_parent_window->active_view = view->id;
return view;
}
if (window->search_bar_window.id != 0) {
Window *search_bar = GetWindow(window->search_bar_window);
search_bar->visible = v;
if (window == new_parent_window) {
return view;
}
}
bool ToggleVisibility(WindowID window_id) {
Window *window = GetWindow(window_id);
bool visible = !window->visible;
SetVisibility(window_id, visible);
return visible;
}
void LoadBigText(Buffer *buffer, int size = 5000000) {
for (int i = 0; i < size; i += 1) {
RawReplaceText(buffer, GetBufferEndAsRange(buffer), u"Line number or something of the sort which is here or there or maybe somewhere else\n");
}
}
void LoadBigLine(Buffer *buffer, int size = 5000000) {
for (int i = 0; i < size; i += 1) {
RawReplaceText(buffer, GetBufferEndAsRange(buffer), u"Line number or something of the sort which is here or there or maybe somewhere else | ");
}
}
void LoadBigTextAndBigLine(Buffer *buffer, int size = 2500000) {
LoadBigLine(buffer, size);
LoadBigText(buffer, size);
}
void LoadTextA(Buffer *buffer) {
Scratch scratch;
for (int i = 0; i < 1000; i += 1) {
String s = Format(scratch, "line1: %d line2: %d line3: %d line4: %d line5: %d line6: %d line1: %d line2: %d line3: %d line4: %d line5: %d line6: %d\r\n", i, i, i, i, i, i, i, i, i, i, i, i);
String16 s16 = ToString16(scratch, s);
RawReplaceText(buffer, GetBufferEndAsRange(buffer), s16);
}
}
void LoadLine(Buffer *buffer) {
Scratch scratch;
String s = "Line number and so on óźćż";
RawReplaceText(buffer, {}, ToString16(scratch, s));
}
void LoadTestBufferMessage(Buffer *buffer) {
String text = R"===(
commit 225d1ffc067da0723898ade68fb9492bbe308feb
https://www.lua.org/manual/5.4/
)===";
Scratch scratch;
RawReplaceText(buffer, {}, ToString16(scratch, text));
// RawReplaceText(buffer, GetBufferEndAsRange(buffer), ToString16(scratch, text));
Assert(window->active_view.id == view->id.id);
View *result = OpenBufferView(name);
new_parent_window->active_view = result->id;
return result;
}
void InitWindows() {
WindowSplit *split = &WindowSplits;
split->kind = WindowSplitKind_Horizontal;
split->value = (double)0.9;
Scratch scratch;
CreateWind();
CreateWind();
// COMMAND BAR
{
Window *window = CreateWind();
window->active_view = NullViewID;
Assert(window->id.id == 0);
CreateTitlebar(window->id);
CreateSearchBar(window->id);
split->right = CreateSplitForWindow(split, window);
}
{
Window *window = CreateWind();
Buffer *buffer = ScratchBuffer;
View *view = CreateView(buffer->id);
CommandBarWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, "command_bar");
View *view = CreateView(buffer->id);
window->active_view = view->id;
CreateTitlebar(window->id);
CreateSearchBar(window->id);
ActiveWindow = window->id;
split->left = CreateSplitForWindow(split, window);
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->draw_darker = true;
window->draw_line_highlight = false;
window->layout = false;
window->visible = false;
window->sync_visibility_with_focus = true;
window->lose_focus_on_escape = true;
window->jump_history = false;
view->fuzzy_search = true;
}
// SEARCH BAR
{
Window *window = CreateWind();
SearchBarWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, "search_bar");
SearchBufferID = buffer->id;
View *view = CreateView(buffer->id);
SearchViewID = view->id;
window->active_view = view->id;
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->draw_darker = true;
window->draw_line_highlight = false;
window->layout = false;
window->visible = false;
window->lose_focus_on_escape = true;
}
// STATUS BAR at the bottom
{
Window *window = CreateWind();
StatusBarWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, "status_bar");
View *view = CreateView(buffer->id);
window->active_view = view->id;
window->font = &SecondaryFont;
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->draw_line_highlight = false;
window->draw_darker = true;
window->layout = false;
}
// DEBUG WINDOW
{
Window *window = CreateWind();
DebugWindowID = window->id;
@@ -190,6 +171,7 @@ void InitWindows() {
window->draw_scrollbar = false;
window->visible = false;
window->z = 2;
window->layout = false;
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug"));
DebugBufferID = buffer->id;
@@ -199,86 +181,102 @@ void InitWindows() {
DebugViewID = view->id;
window->active_view = view->id;
Window *titlebar = CreateTitlebar(window->id);
Window *searchbar = CreateSearchBar(window->id);
titlebar->z = 2;
searchbar->z = 2;
SetVisibility(window->id, false);
window->visible = false;
}
}
void LayoutWindowSplit(WindowSplit *split, Rect2I rect) {
float scrollbar_size = (10.f * DPIScale);
float resizer_size = (float)PrimaryFont.char_spacing*0.5f;
void CalcNiceties(Window *n) {
float scrollbar_size = (10.f * DPIScale);
float line_numbers_size = (float)n->font->char_spacing * 10.f;
if (n->draw_scrollbar) n->scrollbar_rect = CutRight(&n->document_rect, (Int)scrollbar_size);
if (n->draw_line_numbers) n->line_numbers_rect = CutLeft(&n->document_rect, (Int)line_numbers_size);
}
if (split->kind == WindowSplitKind_Window) {
Window *it = split->window;
float line_numbers_size = (float)it->font->char_spacing * 10;
Assert(it->split_ref);
it->total_rect = rect;
Window *title_bar_window = GetWindow(it->title_bar_window);
title_bar_window->total_rect = CutBottom(&it->total_rect, GetTitleBarSize(title_bar_window));
title_bar_window->document_rect = title_bar_window->total_rect;
Rect2I save_rect = it->document_rect;
CutLeft(&save_rect, GetSize(save_rect).x/2);
Window *search_bar_window = GetWindow(it->search_bar_window);
search_bar_window->total_rect = CutTop(&save_rect, GetTitleBarSize(search_bar_window));
search_bar_window->document_rect = search_bar_window->total_rect;
it->document_rect = it->total_rect;
if (it->draw_scrollbar) it->scrollbar_rect = CutRight(&it->document_rect, (Int)scrollbar_size);
if (it->draw_line_numbers) it->line_numbers_rect = CutLeft(&it->document_rect, (Int)line_numbers_size);
} else if (split->kind == WindowSplitKind_Vertical) {
Rect2I rect2 = {0};
split->total_rect = rect;
rect2 = CutLeft(&rect, (Int)round((double)GetSize(rect).x * split->value));
split->resizer_rect = CutRight(&rect2, (Int)resizer_size);
LayoutWindowSplit(split->left, rect2);
LayoutWindowSplit(split->right, rect);
} else if (split->kind == WindowSplitKind_Horizontal) {
Rect2I rect2 = {0};
split->total_rect = rect;
rect2 = CutTop(&rect, (Int)round((double)GetSize(rect).y * split->value));
split->resizer_rect = CutTop(&rect, (Int)resizer_size);
LayoutWindowSplit(split->left, rect2);
LayoutWindowSplit(split->right, rect);
} else {
Assert(!"Invalid codepath");
double WindowCalcEvenResizerValue(Int screen_size_x, Int *out_count = NULL) {
double w = 0;
Int c = 0;
ForItem(n, Windows) {
if (n->layout) {
w += n->weight;
c += 1;
}
}
if (out_count) *out_count = c;
return (double)screen_size_x / w;
}
void LayoutWindows(int16_t wx, int16_t wy) {
Rect2I screen_rect = RectI0Size(wx, wy);
LayoutWindowSplit(&WindowSplits, screen_rect);
Rect2I screen_rect = RectI0Size(wx, wy);
// layout debug window
// Command bar
{
Window *window = GetWindow(DebugWindowID);
Window *n = GetWindow(CommandBarWindowID);
Rect2I *rect = &screen_rect;
Rect2I copy_rect = screen_rect;
if (!n->visible) {
rect = &copy_rect;
}
Int barsize = Clamp((Int)n->font->line_spacing*10, (Int)0, (Int)wx - 100);
n->document_rect = n->total_rect = CutBottom(rect, barsize);
}
// bar at the bottom
{
Window *n = GetWindow(StatusBarWindowID);
Rect2I *rect = &screen_rect;
Rect2I copy_rect = screen_rect;
if (!n->visible) {
rect = &copy_rect;
}
Int barsize = GetExpandingBarSize(n);
n->document_rect = n->total_rect = CutBottom(rect, barsize);
}
// search bar
{
Window *n = GetWindow(SearchBarWindowID);
Rect2I *rect = &screen_rect;
Rect2I copy_rect = screen_rect;
if (!n->visible) {
rect = &copy_rect;
}
Int barsize = GetExpandingBarSize(n);
n->document_rect = n->total_rect = CutBottom(rect, barsize);
}
// floating debug window
{
Window *n = GetWindow(DebugWindowID);
Rect2 screen_rect = Rect0Size(wx, wy);
Vec2 size = GetSize(screen_rect);
Rect2 a = CutLeft(&screen_rect, 0.3f * size.x);
Rect2 b = CutBottom(&a, 0.4f * size.y);
Rect2 c = Shrink(b, 20);
window->total_rect = ToRect2I(c);
Window *title_bar_window = GetWindow(window->title_bar_window);
title_bar_window->total_rect = CutBottom(&window->total_rect, GetTitleBarSize(title_bar_window));
title_bar_window->document_rect = title_bar_window->total_rect;
Rect2I save_rect = window->document_rect;
CutLeft(&save_rect, GetSize(save_rect).x/2);
Window *search_bar_window = GetWindow(window->search_bar_window);
search_bar_window->total_rect = CutTop(&save_rect, GetTitleBarSize(search_bar_window));
search_bar_window->document_rect = search_bar_window->total_rect;
window->document_rect = window->total_rect;
n->document_rect = n->total_rect = ToRect2I(c);
}
}
// Column layout
Int c = 0;
double size = WindowCalcEvenResizerValue(wx, &c);
if (c == 0) {
return;
}
int i = 0;
ForItem(n, Windows) {
if (!n->layout) {
continue;
}
n->total_rect = n->document_rect = CutLeft(&screen_rect, (Int)(size * n->weight));
if (i != (c - 1)) {
Int resizer_size = (Int)(PrimaryFont.char_spacing*0.5f);
n->resizer_rect = CutRight(&n->document_rect, resizer_size);
} else {
n->resizer_rect = {};
}
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);