BIG OPTIMIZATIONS: WTF IT WORKS SO FAST NOW, 9000 files open easy WHAAAT

This commit is contained in:
Krzosa Karol
2026-01-22 22:59:17 +01:00
parent b0a0fca8ee
commit 9a64fd8e01
11 changed files with 105 additions and 94 deletions

View File

@@ -226,11 +226,9 @@ API String16 GetLineStringWithoutNL(Buffer *buffer, Int line) {
API Int PosToLine(Buffer *buffer, Int pos) {
Add(&buffer->line_starts, buffer->len + 1);
// binary search
Int low = 0;
// -2 here because we use 2 indices and combine them into one line range so we
// don't want to access last item since that would index past array.
Int low = 0;
Int high = buffer->line_starts.len - 2;
Int result = 0;
@@ -745,7 +743,6 @@ inline bool MergeSortCompare(Edit *EntryA, Edit *EntryB) {
template<class T>
void MergeSort(int64_t Count, T *First, T *Temp) {
ProfileFunction();
// SortKey = range.min
if (Count == 1) {
// NOTE(casey): No work to do.
@@ -823,7 +820,9 @@ API void ApplyEditsMultiCursor(Buffer *buffer, Array<Edit> edits) {
// We need to sort from lowest to highest based on range.min
Scratch scratch(buffer->line_starts.allocator);
Array<Edit> edits_copy = TightCopy(scratch, edits);
if (edits.len > 1) MergeSort(edits.len, edits_copy.data, edits.data);
if (edits.len > 1) {
MergeSort(edits.len, edits_copy.data, edits.data);
}
edits = edits_copy;
#if BUFFER_DEBUG
@@ -1368,14 +1367,28 @@ BufferID AllocBufferID(Buffer *buffer) {
}
Buffer *GetBuffer(BufferID id, Buffer *default_buffer = Buffers[0]) {
For(Buffers) {
if (it->id == id) return it;
Int left = 0;
Int right = Buffers.len - 1;
Buffer *result = default_buffer;
while (left <= right) {
Int mid = left + (right - left) / 2;
Buffer *it = Buffers[mid];
if (it->id == id) {
result = it;
break;
} else if (it->id.id < id.id) {
left = mid + 1;
} else {
right = mid - 1;
}
return default_buffer;
}
return result;
}
Buffer *GetBuffer(String name, Buffer *default_buffer = Buffers[0]) {
For(Buffers) {
For (Buffers) {
if (it->name == name) return it;
}
return default_buffer;
@@ -1506,18 +1519,6 @@ Buffer *BufferOpenFile(String path) {
return buffer;
}
bool BufferIsReferenced(Buffer *buffer) {
if (buffer->special) {
return true;
}
if (FindView(buffer->id, NULL)) {
return true;
}
return false;
}
void ReopenBuffer(Buffer *buffer) {
Scratch scratch;
@@ -1566,3 +1567,15 @@ String GetDirectory(Buffer *buffer) {
String result = ChopLastSlash(buffer->name);
return result;
}
void TryReopeningWhenModified(Buffer *it) {
if (it->file_mod_time) {
int64_t new_file_mod_time = GetFileModTime(it->name);
if (it->file_mod_time != new_file_mod_time) {
it->changed_on_disk = true;
if (it->dirty == false) {
ReopenBuffer(it);
}
}
}
}

View File

@@ -103,18 +103,14 @@ void ReportErrorf(const char *fmt, ...) {
BREAK();
}
View *view = GetView(LogViewID);
if (view) {
Appendf(view, "%S\n", string);
}
Appendf(LogView, "%S\n", string);
ShowUIMessagef("%S", string);
}
void ReportConsolef(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
View *view = GetView(LogViewID);
Appendf(view, "%S\n", string);
Appendf(LogView, "%S\n", string);
}
void ReportWarningf(const char *fmt, ...) {
@@ -124,8 +120,7 @@ void ReportWarningf(const char *fmt, ...) {
if (BreakOnError) {
BREAK();
}
View *null_view = GetView(LogViewID);
Appendf(null_view, "%S\n", string);
Appendf(LogView, "%S\n", string);
}
void CMD_CenterView() {
@@ -177,8 +172,7 @@ void ApplyFormattingTool(Buffer *buffer, String tool) {
if (exec_result.exit_code == 0) {
ReplaceWithoutMovingCarets(buffer, GetRange(buffer), string16);
} else {
View *view = GetView(LogViewID);
Append(view, string16, true);
Append(LogView, string16, true);
}
}
@@ -250,8 +244,7 @@ void CMD_ToggleFullscreen() {
void CMD_OpenLogs() {
ErrorCount = 0;
Buffer *buffer = GetBuffer(LogBufferID);
Open(buffer->name);
Open(LogBuffer->name);
} RegisterCommand(CMD_OpenLogs, "", "Opens the text editor logs and clear error counter");
void CMD_Errors() {

View File

@@ -29,8 +29,8 @@ Array<Window *> Windows;
Array<View *> Views;
Array<Buffer *> Buffers;
BufferID LogBufferID;
ViewID LogViewID;
View *LogView;
Buffer *LogBuffer;
BufferID NullBufferID;
ViewID NullViewID;

View File

@@ -2111,7 +2111,7 @@ bool RDBG_InitConnection(mco_coro *co, bool create_session = true) {
String session_name = Format(CoCurr->arena, "te%llu", GetTimeNanos());
String remedy_string = Format(CoCurr->arena, "%S --servername %S", RemedyBGPath, session_name);
ReportConsolef("Remedybg: %S", remedy_string);
Exec(LogViewID, true, remedy_string, GetPrimaryDirectory());
Exec(LogView->id, true, remedy_string, GetPrimaryDirectory());
MemoryZero(&RDBG_Ctx, sizeof(RDBG_Ctx));
RDBG_Ctx.cmd.data = command_buf;
RDBG_Ctx.cmd.capacity = sizeof(command_buf);

View File

@@ -89,15 +89,17 @@ void LayoutSearchWindow(Rect2I *rect, int16_t wx, int16_t wy) {
window->line_numbers_rect = CutLeft(&window->document_rect, window->font->char_spacing * 6);
}
Int SearchBufferChangeID;
void UpdateSearchWindow() {
if (ActiveWindowID == SearchWindowID) {
BSet active = GetBSet(ActiveWindowID);
if (active.buffer->begin_frame_change_id != active.buffer->change_id) {
if (SearchBufferChangeID != active.buffer->change_id) {
BSet main = GetBSet(PrimaryWindowID);
main.view->carets[0] = main.window->search_bar_anchor;
String16 seek = GetString(active.buffer, GetRange(active.buffer));
Find(main.view, seek, true);
CenterView(main.window->id);
SearchBufferChangeID = active.buffer->change_id;
}
}
}

View File

@@ -8,7 +8,7 @@ void UpdateProcesses() {
IterRemove(ActiveProcesses) {
IterRemovePrepare(ActiveProcesses);
Scratch scratch;
View *view = GetView({it.view_id});
View *view = GetView(ViewID{it.view_id});
String poll = PollStdout(scratch, &it, false);
if (poll.len) {

View File

@@ -572,7 +572,7 @@ void GarbageCollect() {
Dealloc(sys_allocator, it);
remove_item = true;
} else {
View *view = FindView(it->active_view, NULL);
View *view = GetView(it->active_view, NULL);
if (!view) {
JumpToLastValidView(it);
}
@@ -685,14 +685,6 @@ void Update(Event event) {
UpdateScroll(it, !AreEqual(view->main_caret_on_begin_frame, view->carets[0]) && view->update_scroll);
}
// We update it here despite the name to make it sure that all the possible changes are
// included albeit with delayed response. If we did this at the beginning of the frame
// and the DebugWindowUpdated we wouldnt get to know that in the OnCommand.
// @todo: this is slow, we don't want to loop through every buffer on every frame :(
For (Buffers) {
it->begin_frame_change_id = it->change_id;
}
{
ProfileScope(UpdateWindows);
For (Windows) {
@@ -775,20 +767,10 @@ void Update(Event event) {
}
}
// Reopen modified buffers
// @todo: This is O(n) so could see slow downs with number of buffers, likely need OS help to make it more
// efficient
// @todo: maybe instead go through windows and only reopen active buffers
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) {
it->changed_on_disk = true;
if (it->dirty == false) {
ReopenBuffer(it);
}
}
}
// IS THIS ENOUGH? Previously reopened everything
For (Windows) {
BSet set = GetBSet(it);
TryReopeningWhenModified(set.buffer);
}
GarbageCollect();
@@ -984,10 +966,10 @@ int main(int argc, char **argv)
Buffer *logs_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(ProjectDirectory, "logs", ""));
logs_buffer->special = true;
LogBufferID = logs_buffer->id;
View *logs_view = CreateView(logs_buffer->id);
logs_view->special = true;
LogViewID = logs_view->id;
LogBuffer = logs_buffer;
LogView = logs_view;
#if PLUGIN_RECORD_GC
GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(ProjectDirectory, "gc"));

View File

@@ -70,9 +70,7 @@ struct ResolvedOpen {
struct Buffer {
BufferID id;
String name;
Int begin_frame_change_id;
Int change_id;
Int user_change_id;
Int file_mod_time;
union {
@@ -338,7 +336,6 @@ BSet Open(String16 path, ResolveOpenMeta meta = ResolveOpenMeta_Normal);
void CenterView(WindowID window);
void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret = false);
void JumpTempBuffer(BSet *set, String buffer_name = "");
View *FindView(BufferID buffer_id, View *default_view = NULL);
bool operator==(BufferID a, BufferID b) { return a.id == b.id; }
bool operator==(ViewID a, ViewID b) { return a.id == b.id; }

View File

@@ -365,7 +365,7 @@ BSet Open(Window *window, String path, ResolveOpenMeta meta, bool set_active = t
Exec(set.view->id, false, o.path, GetPrimaryDirectory());
} else if (o.kind == OpenKind_BackgroundExec) {
// this shouldn't change the focus/window/view
Exec(LogViewID, false, o.path, GetPrimaryDirectory());
Exec(LogView->id, false, o.path, GetPrimaryDirectory());
} else if (o.kind == OpenKind_Command) {
EvalCommand(o.path);
}

View File

@@ -20,18 +20,29 @@ void Dealloc(View *view) {
Dealloc(view->carets.allocator, view);
}
// TODO: default_view should probably be Views[0] but could break stuff
API View *FindView(ViewID view_id, View *default_view = NULL) {
For(Views) {
if (it->id == view_id) {
return it;
View *GetView(ViewID id, View *default_view = Views[0]) {
Int left = 0;
Int right = Views.len - 1;
View *result = default_view;
while (left <= right) {
Int mid = left + (right - left) / 2;
View *it = Views[mid];
if (it->id == id) {
result = it;
break;
} else if (it->id.id < id.id) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return default_view;
return result;
}
API View *FindView(BufferID buffer_id, View *default_view) {
For(Views) {
API View *GetView(BufferID buffer_id, View *default_view = Views[0]) {
For (Views) {
if (it->active_buffer == buffer_id) {
return it;
}
@@ -39,8 +50,8 @@ API View *FindView(BufferID buffer_id, View *default_view) {
return default_view;
}
API View *FindView(String name, View *default_view = NULL) {
For(Views) {
API View *GetView(String name, View *default_view = Views[0]) {
For (Views) {
Buffer *buffer = GetBuffer(it->active_buffer);
if (buffer->name == name) {
return it;
@@ -49,10 +60,6 @@ API View *FindView(String name, View *default_view = NULL) {
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);
@@ -88,10 +95,22 @@ API bool ViewIsReferenced(View *view) {
return ViewIsActive(view->id);
}
bool BufferIsReferenced(Buffer *buffer) {
if (buffer->special) {
return true;
}
if (GetView(buffer->id, NULL)) {
return true;
}
return false;
}
void Close(ViewID id) {
View *view = GetView(id);
View *view = GetView(id, NULL);
if (view) {
if (view->id.id == 0) {
if (view->special) {
return;
}
view->close = true;

View File

@@ -45,19 +45,24 @@ Window *FindWindow(ViewID view_id, Window *default_window = NULL) {
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) {
View *it_view = GetView(it->active_view, NULL);
if (it_view) {
Buffer *it_buffer = GetBuffer(it_view->active_buffer, NULL);
Assert(it_buffer); // Probably we are missing something when GCing / closing
if (it_buffer && 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;
For (Windows) {
View *view = GetView(it->active_view, Views[0]);
if (view->active_buffer == buffer_id) {
return it;
}
}
return NULL;
}
@@ -92,7 +97,7 @@ Int GetExpandingBarSize(Window *window) {
}
View *WindowOpenBufferView(Window *new_parent_window, String name) {
View *view = FindView(name);
View *view = GetView(name, NULL);
if (!view) {
View *result = OpenBufferView(name);
new_parent_window->active_view = result->id;
@@ -192,7 +197,7 @@ Int ScreenSpaceToBufferPosErrorOutOfBounds(Window *window, View *view, Buffer *b
GotoCrumb PopCrumb(Array<GotoCrumb> *cr) {
for (; cr->len;) {
GotoCrumb c = Pop(cr);
View *view = FindView(c.view_id, NULL);
View *view = GetView(c.view_id, NULL);
if (view) {
return c;
}
@@ -203,12 +208,12 @@ GotoCrumb PopCrumb(Array<GotoCrumb> *cr) {
View *GetLastValidView(Window *window) {
For (IterateInReverse(&window->goto_redo)) {
if (it.view_id == window->active_view) continue;
View *view = FindView(it.view_id, NULL);
View *view = GetView(it.view_id, NULL);
if (view) return view;
}
For (IterateInReverse(&window->goto_history)) {
if (it.view_id == window->active_view) continue;
View *view = FindView(it.view_id, NULL);
View *view = GetView(it.view_id, NULL);
if (view) return view;
}
return Views[0];