Fix merge carets

This commit is contained in:
Krzosa Karol
2024-07-26 07:37:02 +02:00
parent d4136ef0e3
commit 7eefa2e6c2
10 changed files with 192 additions and 91 deletions

View File

@@ -213,3 +213,14 @@ void ReplaceText(Buffer *buffer, Range range, String16 string) {
ValidateLineStarts(buffer);
#endif
}
void Append(Buffer *buffer, String16 string) {
ReplaceText(buffer, GetEndAsRange(*buffer), string);
}
void Appendf(Buffer *buffer, const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
String16 string16 = ToString16(scratch, string);
ReplaceText(buffer, GetEndAsRange(*buffer), string16);
}

View File

@@ -117,6 +117,17 @@ bool AreEqual(Caret a, Caret b) {
return result;
}
bool AreOverlapping(Range a, Range b) {
bool r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
bool r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
return r1 || r2;
}
bool AreOverlapping(Caret a, Caret b) {
bool result = AreOverlapping(a.range, b.range);
return result;
}
bool InRange(Int a, Range b) {
bool result = a >= b.min && a < b.max;
return result;

View File

@@ -1,45 +1,56 @@
// mouse_selection_anchor is special case for mouse handling !
void MergeCarets(Buffer &buffer, Array<Caret> *_carets, Range *mouse_selection_anchor = NULL) {
void MergeSort(int64_t Count, Caret *First, Caret *Temp) {
ProfileFunction();
Array<Caret> &carets = *_carets;
Scratch scratch;
// SortKey = range.min
if (Count == 1) {
// NOTE(casey): No work to do.
} else if (Count == 2) {
Caret *EntryA = First;
Caret *EntryB = First + 1;
if (EntryA->range.min > EntryB->range.min) {
Swap(EntryA, EntryB);
}
} else {
int64_t Half0 = Count / 2;
int64_t Half1 = Count - Half0;
// Clamp carets
For(carets) it.range = Clamp(buffer, it.range);
Assert(Half0 >= 1);
Assert(Half1 >= 1);
// Merge carets that overlap, this needs to be handled before any edits to
// make sure overlapping edits won't happen.
Caret *InHalf0 = First;
Caret *InHalf1 = First + Half0;
Caret *End = First + Count;
// @optimize @refactor: this is retarded, I hit so many array removal bugs here
Array<Caret *> deleted_carets = {scratch};
ForItem(caret, carets) {
if (Contains(deleted_carets, &caret)) goto end_of_caret_loop;
MergeSort(Half0, InHalf0, Temp);
MergeSort(Half1, InHalf1, Temp);
For(carets) {
if (&it == &caret) continue;
bool a = caret.range.max >= it.range.min && caret.range.max <= it.range.max;
bool b = caret.range.min >= it.range.min && caret.range.min <= it.range.max;
if ((a || b) && !Contains(deleted_carets, &it)) {
Add(&deleted_carets, &it);
caret.range.max = Max(caret.range.max, it.range.max);
caret.range.min = Min(caret.range.min, it.range.min);
if (mouse_selection_anchor) *mouse_selection_anchor = caret.range;
goto end_of_caret_loop;
Caret *ReadHalf0 = InHalf0;
Caret *ReadHalf1 = InHalf1;
Caret *Out = Temp;
for (int64_t Index = 0;
Index < Count;
++Index) {
if (ReadHalf0 == InHalf1) {
*Out++ = *ReadHalf1++;
} else if (ReadHalf1 == End) {
*Out++ = *ReadHalf0++;
} else if (ReadHalf0->range.min < ReadHalf1->range.min) {
*Out++ = *ReadHalf0++;
} else {
*Out++ = *ReadHalf1++;
}
}
end_of_caret_loop:;
}
Assert(Out == (Temp + Count));
Assert(ReadHalf0 == InHalf1);
Assert(ReadHalf1 == End);
Array<Caret> new_carets = {scratch};
For(carets) {
if (Contains(deleted_carets, &it) == false) {
Add(&new_carets, it);
// TODO(casey): Not really necessary if we ping-pong
for (int64_t Index = 0;
Index < Count;
++Index) {
First[Index] = Temp[Index];
}
}
Assert(new_carets.len <= carets.len);
carets.len = 0;
For(new_carets) Add(&carets, it);
}
void MergeSort(int64_t Count, Edit *First, Edit *Temp) {

View File

@@ -3,7 +3,7 @@ Array<String16> SavedClipboardCursors;
void Command_Copy(View *view) {
Allocator sys_allocator = GetSystemAllocator();
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
SavedClipboardCursors.allocator = sys_allocator;
if (SavedClipboardCursors.data) {
@@ -39,7 +39,7 @@ void Command_Copy(View *view) {
void Command_Paste(View *view) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
const char *text = GetClipboardText();
String string_ = text;
String16 string = ToString16(scratch, string_);
@@ -47,7 +47,7 @@ void Command_Paste(View *view) {
// Regular paste
if (string != SavedClipboardString || SavedClipboardCursors.len != view->carets.len) {
BeforeEdit(buffer, view->carets);
MergeCarets(*buffer, &view->carets);
MergeCarets(view);
Array<Edit> edits = {scratch};
For(view->carets) AddEdit(&edits, it.range, string);
ApplyEdits(buffer, edits);
@@ -57,7 +57,7 @@ void Command_Paste(View *view) {
// Multicursor paste
BeforeEdit(buffer, view->carets);
MergeCarets(*buffer, &view->carets);
MergeCarets(view);
Array<Edit> edits = {scratch};
for (int64_t i = 0; i < view->carets.len; i += 1) {
String16 string = SavedClipboardCursors[i];

View File

@@ -1,8 +1,8 @@
void Command_Replace(View *view, String16 string) {
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
Scratch scratch;
BeforeEdit(buffer, view->carets);
MergeCarets(*buffer, &view->carets);
MergeCarets(view);
Array<Edit> edits = {scratch};
For(view->carets) AddEdit(&edits, it.range, string);
ApplyEdits(buffer, edits);
@@ -11,10 +11,10 @@ void Command_Replace(View *view, String16 string) {
void Command_DuplicateLine(View *view, int direction) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
BeforeEdit(buffer, view->carets);
For(view->carets) it = MakeCaret(GetFront(it));
MergeCarets(*buffer, &view->carets);
MergeCarets(view);
Scratch scratch;
Array<Edit> edits = {scratch};
@@ -35,7 +35,7 @@ bool SHIFT_PRESSED = true;
void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
View &view = *GetActiveView(window);
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
Rect2I visible_cells_rect = GetVisibleCells(*window);
Int y = GetSize(visible_cells_rect).y - 2;
@@ -63,7 +63,7 @@ void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = f
void Command_MoveCursorsToSide(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
View &view = *GetActiveView(window);
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
For(view.carets) {
Range line_range = GetLineRangeWithoutNL(*buffer, PosToLine(*buffer, GetFront(it)));
@@ -84,7 +84,7 @@ void Command_MoveCursorsToSide(Window *window, int direction, bool shift = false
void Command_Delete(View *_view, int direction, bool ctrl = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
View &view = *_view;
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
// Select things to delete
For(view.carets) {
@@ -96,10 +96,29 @@ void Command_Delete(View *_view, int direction, bool ctrl = false) {
Command_Replace(&view, {});
}
void Command_SelectAll(View *view, String16 needle) {
Buffer *buffer = GetBuffer(view->active_buffer);
String16 string_buffer = GetString(*buffer);
Int debug_id = 0;
for (Int pos = 0;;) {
Int index = 0;
String16 medium = Skip(string_buffer, pos);
if (!Seek(medium, needle, &index)) {
break;
}
Add(&view->carets, MakeCaret(pos + index + needle.len, pos + index));
pos += needle.len;
debug_id += 1;
}
MergeCarets(view);
}
void Command_CreateCursorVertical(View *_view, int direction) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
View &view = *_view;
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
Scratch scratch;
Array<Caret> arr = {scratch};
@@ -115,24 +134,24 @@ void Command_CreateCursorVertical(View *_view, int direction) {
}
}
For(arr) Add(&view.carets, it);
MergeCarets(*buffer, &view.carets);
MergeCarets(_view);
}
void Command_SelectRangeOneCursor(View *view, Range range) {
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
view->carets.len = 1;
view->carets[0] = MakeCaret(range.min, range.max);
}
void Command_SelectEntireBuffer(View *view) {
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
view->carets.len = 1;
view->carets[0] = MakeCaret(0, buffer->len);
}
void Command_EvalLua(View *view, String16 string) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
String16 eval_result = EvalString(scratch, string);
if (eval_result.len) {
@@ -156,15 +175,62 @@ void Command_EvalLua(View *view, String16 string) {
}
void Command_EvalLua(View *view) {
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
Int line = PosToLine(*buffer, GetFront(view->carets[0]));
String16 string = GetLineStringWithoutNL(*buffer, line);
Command_EvalLua(view, string);
}
void PrintDebugCarets(View *view, const char *msg) {
Buffer *null_buffer = GetBuffer(NullBufferID);
Appendf(null_buffer, "%s id: %d sel_anchor(%d, %d)\n", msg, view->caret_change_id, view->selection_anchor.min, view->selection_anchor.max);
For(view->carets) {
Appendf(null_buffer, " min: %lld max: %lld front: %d\n", (long long)it.range.min, (long long)it.range.max, it.ifront);
}
}
// Merge carets that overlap, this needs to be handled before any edits to
// make sure overlapping edits won't happen.
//
// mouse_selection_anchor is special case for mouse handling !
void MergeCarets(View *view, Range *mouse_selection_anchor) {
ProfileFunction();
PrintDebugCarets(view, "before");
view->caret_change_id = CaretChangeID++;
Buffer *buffer = GetBuffer(view->active_buffer);
For(view->carets) it.range = Clamp(*buffer, it.range);
Caret first_caret = view->carets.data[0];
Scratch scratch;
Array<Caret> c1 = TightCopy(scratch, view->carets);
MergeSort(view->carets.len, c1.data, view->carets.data);
view->carets.len = 0;
Int first_caret_index = 0;
Add(&view->carets, c1[0]);
for (Int i = 1; i < c1.len; i += 1) {
Caret &it = c1[i];
Caret *last = GetLast(view->carets);
if (AreOverlapping(*last, it)) {
last->range.max = Max(last->range.max, it.range.max);
if (mouse_selection_anchor) *mouse_selection_anchor = last->range;
} else {
Add(&view->carets, it);
}
if (AreEqual(it, first_caret)) first_caret_index = view->carets.len - 1;
}
Swap(&view->carets[first_caret_index], &view->carets[0]);
PrintDebugCarets(view, "after");
}
void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
View &view = *GetActiveView(window);
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
if (CtrlPress(KEY_F2)) {
LoadBigLine(buffer);
} else if (Press(KEY_F2)) {
@@ -343,7 +409,7 @@ void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
String16 string = GetString(*buffer, view.carets[0].range);
Caret caret = FindInBuffer(buffer, string, view.carets[0], true);
Insert(&view.carets, caret, 0);
MergeCarets(*buffer, &view.carets);
MergeCarets(&view);
}
if (Press(KEY_F3)) {
@@ -352,7 +418,7 @@ void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
Caret caret = FindInBuffer(buffer, search_string, view.carets[0], true);
if (Ctrl()) {
Insert(&view.carets, caret, 0);
MergeCarets(*buffer, &view.carets);
MergeCarets(&view);
} else {
view.carets.len = 1;
view.carets[0] = caret;
@@ -362,22 +428,20 @@ void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
if (window->id.id == SearchWindowID.id) {
Window *seek_window = GetWindow(GetLastActiveWindow());
View *seek_view = GetView(seek_window->active_view);
Buffer *seek_buffer = GetBuffer(seek_view->buffer_id);
Buffer *seek_buffer = GetBuffer(seek_view->active_buffer);
String16 needle = GetString(*buffer);
if (search) {
seek_view->carets[0] = FindInBuffer(seek_buffer, needle, seek_view->carets[0]);
seek_view->carets.len = 1;
}
if (AltPress(KEY_ENTER)) {
Scratch scratch;
Array<Range> finds = FindAllInBuffer(scratch, seek_buffer, needle);
For(finds) Add(&seek_view->carets, MakeCaret(it.max, it.min));
MergeCarets(*buffer, &view.carets);
Command_SelectAll(seek_view, needle);
} else if (Press(KEY_ENTER)) {
Caret caret = FindInBuffer(seek_buffer, needle, seek_view->carets[0], true);
SetActiveWindow(seek_window->id);
if (Ctrl()) {
Insert(&seek_view->carets, caret, 0);
MergeCarets(*buffer, &view.carets);
MergeCarets(seek_view);
} else {
seek_view->carets.len = 1;
seek_view->carets[0] = caret;
@@ -436,7 +500,7 @@ void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
if (mouse_in_view && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
if (IsDoubleClick()) {
Caret *c = GetLast(view.carets);
Caret *c = &view.carets[0];
if (InBounds({c->range.min - 1, c->range.max + 1}, p)) {
c->range = EncloseWord(*buffer, p);
view.selection_anchor = c->range;
@@ -445,11 +509,11 @@ void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
if (!IsKeyDown(KEY_LEFT_CONTROL)) {
view.carets.len = 0;
}
Add(&view.carets, MakeCaret(p, p));
view.selection_anchor = GetLast(view.carets)->range;
Insert(&view.carets, MakeCaret(p, p), 0);
view.selection_anchor = view.carets[0].range;
}
MergeCarets(*buffer, &view.carets);
MergeCarets(&view, &view.selection_anchor);
} else if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
window->mouse_selecting = true;
}
@@ -457,7 +521,7 @@ void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
if (window->mouse_selecting) {
if (!IsMouseButtonDown(MOUSE_BUTTON_LEFT)) window->mouse_selecting = false;
Caret &caret = *GetLast(view.carets);
Caret &caret = view.carets[0];
if (view.selection_anchor.min > p) {
caret = MakeCaret(p, view.selection_anchor.max);
} else if (view.selection_anchor.max < p) {
@@ -465,7 +529,7 @@ void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
} else {
caret = MakeCaret(view.selection_anchor.max, view.selection_anchor.min);
}
MergeCarets(*buffer, &view.carets, &view.selection_anchor);
MergeCarets(&view, &view.selection_anchor);
}
} else if (!(mouse_in_view || window->mouse_selecting) && mouse_in_scrollbar || window->mouse_selecting_scrollbar) {
Scroller s = ComputeScrollerRect(*window);
@@ -499,7 +563,7 @@ void HandleActiveWindowBindings(Window *window, bool *update_scroll) {
void HandleWindowBindings(Window *window) {
ProfileFunction();
View *view = GetActiveView(window);
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
bool update_scroll = true;
if (IsActive(window)) {
@@ -587,11 +651,11 @@ void ReplaceInfobarData() {
if (IsActive(window)) return;
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
Window *last_window = GetWindow(GetLastActiveWindow());
View *last_view = GetActiveView(last_window);
Buffer *last_buffer = GetBuffer(last_view->buffer_id);
Buffer *last_buffer = GetBuffer(last_view->active_buffer);
Scratch scratch;
Caret caret = last_view->carets[0];
XY xy = PosToXY(*last_buffer, GetFront(caret));

View File

@@ -56,7 +56,7 @@ int LuaListViews(lua_State *L) {
Scratch scratch;
Array<String> strings = {scratch};
For(Views) {
Buffer *buffer = GetBuffer(it.buffer_id);
Buffer *buffer = GetBuffer(it.active_buffer);
String string = Format(scratch, "view = %lld buffer = %lld name = %.*s", (long long)it.id.id, (long long)buffer->id.id, FmtString(buffer->name));
Add(&strings, string);
}
@@ -70,12 +70,12 @@ int LuaListWindows(lua_State *L) {
Array<String> strings = {scratch};
For(Windows) {
View *view = GetActiveView(&it);
Buffer *buffer = GetBuffer(view->buffer_id);
Buffer *buffer = GetBuffer(view->active_buffer);
String string = Format(scratch, "window = %lld active_view = %lld buffer_name = %.*s", (long long)it.id.id, (long long)it.active_view.id, FmtString(buffer->name));
Add(&strings, string);
ForItem(child_view_id, it.views) {
View *child_view = GetView(child_view_id);
Buffer *child_buffer = GetBuffer(child_view->buffer_id);
Buffer *child_buffer = GetBuffer(child_view->active_buffer);
String child_string = Format(scratch, " view = %lld buffer = %lld name = %.*s", (long long)child_view->id.id, (long long)child_buffer->id.id, FmtString(child_buffer->name));
Add(&strings, child_string);
}

View File

@@ -42,10 +42,10 @@ void AddView(Window *w, ViewID view) {
Add(&w->views, view);
}
View *CreateView(BufferID buffer_id) {
View *CreateView(BufferID active_buffer) {
View *w = Alloc(&Views);
w->id = AllocViewID();
w->buffer_id = buffer_id;
w->active_buffer = active_buffer;
Add(&w->carets, {0, 0});
return w;
}
@@ -84,7 +84,7 @@ Window *FindParentWindow(ViewID view_id) {
View *FindViewWithBufferName(String name) {
For(Views) {
Buffer *buffer = GetBuffer(it.buffer_id);
Buffer *buffer = GetBuffer(it.active_buffer);
if (buffer->name == name) {
return &it;
}
@@ -175,7 +175,7 @@ void UnlinkView(Window *window, ViewID view) {
View *ViewOpenFile(Window *new_parent_window, String name) {
For(new_parent_window->views) {
View *it_view = GetView(it);
Buffer *it_buffer = GetBuffer(it_view->buffer_id);
Buffer *it_buffer = GetBuffer(it_view->active_buffer);
if (it_buffer->name == name) {
new_parent_window->active_view = it;
return it_view;

View File

@@ -97,8 +97,7 @@ int main(void) {
}
{
Window *w = CreateWindow();
Buffer *b = CreateBuffer(sys_allocator, "*load_line*");
LoadLine(b);
Buffer *b = GetBuffer({0});
View *v = CreateView(b->id);
AddView(w, v->id);
}

View File

@@ -40,8 +40,10 @@ struct Buffer {
struct View {
ViewID id;
BufferID buffer_id;
BufferID active_buffer;
Vec2I scroll;
Int caret_change_id; // @debug
Array<Caret> carets;
// window | view
@@ -111,16 +113,18 @@ Int FontCharSpacing;
Int FrameID;
Int LastFrameIDWhenScrolled = -1;
Int CaretChangeID;
String WorkingDir;
Int LastFrameIDWhenSwitchedActiveWindow;
Array<WindowID> WindowSwitchHistory; // @todo: probably better as a circular buffer
WindowID ActiveWindow;
WindowID ActiveWindow; // @todo: maybe NextActiveWindow and change at end of frame
String16 EvalString(Allocator allocator, String16 string16);
Rect2I GetVisibleCells(Window &window);
void AfterEdit(View *view, Array<Edit> edits);
Scroller ComputeScrollerRect(Window &window);
void Command_EvalLua(View *view, String16 string);
void MergeCarets(View *view, Range *mouse_selection_anchor = NULL);
inline ViewID AllocViewID() { return {ViewIDs.id++}; }
inline WindowID AllocWindowID() { return {WindowIDs.id++}; }

View File

@@ -22,7 +22,7 @@ Rect2I GetVisibleCells(Window &window) {
Scroller ComputeScrollerRect(Window &window) {
View &view = *GetActiveView(&window);
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
Vec2I size = GetSize(window.scrollbar_rect);
Rect2I vis = GetVisibleCells(window);
Int line_count = buffer->line_starts.len + GetSize(vis).y - 1;
@@ -42,7 +42,7 @@ void DrawVisibleText(Window &window) {
ProfileFunction();
Color tint = ColorText;
View &view = *GetActiveView(&window);
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
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) {
@@ -107,7 +107,7 @@ void DrawLineHighlight(Window &window, XY fxy, Color color) {
void DrawSelection(Window &window, Caret &it) {
ProfileFunction();
View &view = *GetActiveView(&window);
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
Int front = GetFront(it);
Int back = GetBack(it);
if (front != back) {
@@ -151,7 +151,7 @@ void DrawSelection(Window &window, Caret &it) {
void DrawWindow(Window &window) {
View &view = *GetActiveView(&window);
Buffer *buffer = GetBuffer(view.buffer_id);
Buffer *buffer = GetBuffer(view.active_buffer);
DrawRectangleRec(ToRectangle(window.total_rect), ColorBackground);
bool is_active = IsActive(&window) || window.id.id == GetLastActiveWindow().id;
@@ -175,10 +175,11 @@ void DrawWindow(Window &window) {
For(view.carets) {
Int front = GetFront(it);
XY fxy = PosToXY(*buffer, front);
if (fxy.col >= visible.min.x && fxy.col < visible.min.x && fxy.line >= visible.min.y && fxy.line <= visible.max.y) {
// @todo:
// if (fxy.col >= visible.min.x && fxy.col < visible.min.x && fxy.line >= visible.min.y && fxy.line <= visible.max.y) {
bool main_caret = &it == &view.carets.data[0];
DrawCaret(window, fxy, 0.3f, main_caret ? ColorMainCaret : ColorSubCaret);
}
// }
}
EndProfileScope();
EndScissorMode();