diff --git a/dub.json b/dub.json index 987ce02..b8ec654 100644 --- a/dub.json +++ b/dub.json @@ -16,7 +16,7 @@ "versions": ["VULKAN_DEBUG", "ENABLE_RENDERER", "DLIB"], "preGenerateCommands-linux": ["./build.sh"], "preGenerateCommands-windows": [], - "dflags": ["-P-I/usr/include/freetype2", "-Jbuild", "-Jassets", "-P-DBUILD_VULKAN"], + "dflags": ["-P-I/usr/include/freetype2", "-Jbuild", "-Jassets", "-P-DBUILD_VULKAN", "-verrors=100"], "dflags-ldc2": ["-link-debuglib", "--Xcc=-DBUILD_VULKAN"], "dflags-dmd": ["-Xcc=-DBUILD_VULKAN"] }, diff --git a/src/dlib b/src/dlib index 53eb211..f3d1f55 160000 --- a/src/dlib +++ b/src/dlib @@ -1 +1 @@ -Subproject commit 53eb211a1e227d1cf3d8036a0e8ecfb79f514eed +Subproject commit f3d1f551ccfa37de73d626479252bada0fc17cb2 diff --git a/src/editor/buffer.d b/src/editor/buffer.d index 78a9606..7e2e0ce 100644 --- a/src/editor/buffer.d +++ b/src/editor/buffer.d @@ -1,39 +1,39 @@ import dlib; -import dlib.alloc : Reset; -import core.stdc.stdio : EOF; +import dlib.alloc : Reset; +import core.stdc.stdio : EOF; +import core.stdc.string : memcpy; import parsing; -import parsing : SetBuffers; import std.format : sformat; import std.math.algebraic : abs; import editor; +import buffer : Reset; struct FlatBuffer { - Tokenizer tk; - Arena arena; - Arena ls_arena; - LineBuffers linebufs; - BufferInfo info; + Tokenizer tokenizer; + Arena arena; + Arena line_start_arena; + LineBuffers linebufs; - string file_name; - u8[] data; - u64 length; + string file_name; + u8[] data; + u64 length; - Line[] lines; - i64 pos; - i64 col_pos; - SelectMode sel_mode; + Line[] lines; + u64 line_count; - bool dirty; - - alias info this; + bool fixed; + bool changed; + FlatBuffer* list_next; } -struct BufferInfo +struct BufferViewInfo { - u64 line_count; - I64Vec2 selection; - IVec2 position; + i64 pos; + i64 column_position; + SelectMode selection_mode; + I64Vec2 selection; + i64 line_offset; } enum SelectMode @@ -41,16 +41,14 @@ enum SelectMode None, Normal, Line, -} - -alias SM = SelectMode; +} alias SM = SelectMode; struct Line { u64 pos; u64 length; u32 line; - u16 level; + u32 level; } struct LineBuffers @@ -75,89 +73,152 @@ enum WalkDir } const bool[128] SYM_TOKENS = [ - '`': true, - '"': true, + '`': true, + '"': true, '\'': true, - '[': true, - ']': true, - '~': true, - '!': true, - '@': true, - '#': true, - '$': true, - '%': true, - '^': true, - '&': true, - '*': true, - '(': true, - ')': true, - '-': true, - '_': true, - '=': true, - '+': true, - '|': true, - '}': true, - '{': true, - ',': true, - '.': true, - '?': true, - '>': true, - '<': true, - ':': true, - '/': true, + '[': true, + ']': true, + '~': true, + '!': true, + '@': true, + '#': true, + '$': true, + '%': true, + '^': true, + '&': true, + '*': true, + '(': true, + ')': true, + '-': true, + '_': true, + '=': true, + '+': true, + '|': true, + '}': true, + '{': true, + ',': true, + '.': true, + '?': true, + '>': true, + '<': true, + ':': true, + '/': true, '\\': true, - ';': true, + ';': true, ]; -const LineBuffer g_nil_line_buf; -LineBuffer* g_NIL_LINE_BUF; +__gshared LineBuffer g_nil_line_buf; +__gshared LineBuffer* g_NIL_LINE_BUF = &g_nil_line_buf; const u64 SPACING = 2; const u64 BUF_START = 1; -FlatBuffer -CreateFlatBuffer(u8[] data, string file_name) +FlatBuffer* +CreateFlatBuffer(ref Ctx ctx, u8[] data = [], string file_name = "") { - FlatBuffer fb = { - arena: CreateArena(MB(1)), - ls_arena: CreateArena(KB(512)), - }; + if(ctx.text_buffer_count == ctx.text_buffers.length) + { + ctx.text_buffers = Realloc(ctx.text_buffers, ctx.text_buffers.length+ARRAY_COUNT_INCREMENT); + } - g_NIL_LINE_BUF = cast(LineBuffer*)&g_nil_line_buf; + FlatBuffer* fb = &ctx.text_buffers[ctx.text_buffer_count++]; - Init(&fb, data, file_name); - fb.tk = CreateTokenizer(&fb); - Fix(&fb); + fb.arena = CreateArena(MB(1)); + fb.line_start_arena = CreateArena(KB(512)); + + u64 capacity = data.length > 0 ? RoundUp(cast(u64)(data.length)*2, KB(4)) : KB(4); + + u8[] buffer = Alloc!(u8)(capacity); + + MemCpy(buffer.ptr, data.ptr, data.length); + + fb.file_name = file_name; + fb.line_count = CountLF(data); + fb.length = data.length; + fb.linebufs = CreateLineBuffers(MB(1)); + fb.data = buffer; + fb.tokenizer = CreateTokenizer(fb); + + Fix(fb); return fb; } void -Init(FlatBuffer* fb, u8[] data, string file_name) +OpenFile(Editor* editor, string file_name) { - u64 capacity = data.length > 0 ? RoundUp(cast(u64)(data.length)*2, KB(4)) : KB(4); + ref Ctx ctx = GetCtx(); - u8[] buf = Alloc!(u8)(capacity); + string file_path = AbsolutePath(file_name); - fb.file_name = file_name; - fb.line_count = CountLF(data); - fb.length = data.length; - fb.selection = -1; - fb.sel_mode = SM.None; - fb.linebufs = CreateLineBuffers(MB(1)); - fb.pos = 0; + FlatBuffer* text_buffer; + foreach(i; 0 .. ctx.text_buffer_count) + { + if(file_path == ctx.text_buffers[i].file_name) + { + text_buffer = &ctx.text_buffers[i]; + break; + } + } - SetBuffers(fb, buf); + auto buffer_view_key_pair = Search(&editor.view_info_table, file_path); + if(!buffer_view_key_pair) + { + BufferViewInfo view_info; + ResetViewInfo(&view_info); + Push(&editor.view_info_table, file_path, view_info); + buffer_view_key_pair = Search(&editor.view_info_table, file_path); + } - MemCpy(fb.data.ptr, data.ptr, data.length); + editor.view_info = &buffer_view_key_pair.value; + + if(text_buffer) + { + editor.buffer = text_buffer; + } + else + { + char[] file_name_buffer = Alloc!(char)(file_path.length+1); + file_name_buffer[0 .. file_path.length] = file_path[0 .. $]; + file_name_buffer[file_name_buffer.length-1] = '\0'; + + file_path = Str(file_name_buffer); + + u8[] file_data; + auto file = fopen(file_path.ptr, "rb"); + if(file) + { + fseek(file, 0, SEEK_END); + i64 length = ftell(file); + fseek(file, 0, SEEK_SET); + + if(length) + { + file_data = ScratchAlloc!(u8)(length); + fread(file_data.ptr, u8.sizeof, length, file); + } + + editor.buffer = CreateFlatBuffer(ctx, file_data, Str(file_name_buffer)); + } + else + { + // TODO: show error.. + } + + fclose(file); + } } void -SetBuffers(FlatBuffer* fb, u8[] data) +ResetViewInfo(BufferViewInfo* info) { - fb.data = data; + info.selection = -1; + info.selection_mode = SM.None; + info.pos = 0; + info.column_position = 0; } +/* void Change(FlatBuffer* fb, u8[] data, string file_name) { @@ -168,6 +229,7 @@ Change(FlatBuffer* fb, u8[] data, string file_name) ResetTokenizer(&fb.tk, fb.data.length); Fix(fb); } +*/ u64 CountLF(u8[] data) @@ -181,7 +243,7 @@ CountLF(u8[] data) return lf_count; } -pragma(inline) bool +pragma(inline, true) bool ScanLineRightBrace(u8* data, u64 start, u64 len) { bool result; @@ -202,77 +264,75 @@ ScanLineRightBrace(u8* data, u64 start, u64 len) } void -Fix(FlatBuffer* fb) +Fix(T)(T* buffer) + if(is(T == FlatBuffer) || is(T == Editor)) { - with(fb) + Reset(&buffer.line_start_arena); + + buffer.lines = Alloc!(Line)(&buffer.line_start_arena, buffer.line_count); + buffer.lines[0].pos = 0; + + Line* prev = null; + u32 ignore, pending_level, level; + u64 ls_idx = 1; + for(u64 i = 0; i < buffer.length; i += 1) { - Reset(&ls_arena); - - lines = Alloc!(Line)(&ls_arena, line_count); - lines[0].pos = 0; - - Line* prev = null; - u16 ignore, pending_level, level; - u64 ls_idx = 1; - for(u64 i = 0; i < length; i += 1) + if(buffer.data[i] == '{' || buffer.data[i] == '(' || buffer.data[i] == '[') { - if(data[i] == '{' || data[i] == '(' || data[i] == '[') + if(pending_level > 0) { - if(pending_level > 0) - { - ignore += 1; - } - else - { - pending_level = 1; - } + ignore += 1; } - - else if(data[i] == '}' || data[i] == ')' || data[i] == ']') + else { - if(ignore > 0) - { - ignore -= 1; - } - else if(pending_level == 1) - { - pending_level = 0; - } - else if(level > 0) - { - if(prev) - { - prev.level = cast(u16)Max(prev.level-u16(1), 0); - } - level -= 1; - } + pending_level = 1; } + } - if(data[i] == '\n') + else if(buffer.data[i] == '}' || buffer.data[i] == ')' || buffer.data[i] == ']') + { + if(ignore > 0) + { + ignore -= 1; + } + else if(pending_level == 1) { - level += pending_level; pending_level = 0; - - lines[ls_idx].pos = i+1; - lines[ls_idx].level = level; - - prev = &lines[ls_idx]; - - ls_idx += 1; + } + else if(level > 0) + { + if(prev) + { + prev.level = Max(prev.level-u16(1), 0); + } + level -= 1; } } - for(u64 i = 0; i < line_count-1; i += 1) + if(buffer.data[i] == '\n') { - lines[i].length = lines[i+1].pos - lines[i+0].pos; + level += pending_level; + pending_level = 0; + + buffer.lines[ls_idx].pos = i+1; + buffer.lines[ls_idx].level = level; + + prev = &buffer.lines[ls_idx]; + + ls_idx += 1; } - - lines[line_count-1].length = length - lines[line_count-1].pos; - - dirty = false; - - TokenizeD(fb); } + + for(u64 i = 0; i < buffer.line_count-1; i += 1) + { + buffer.lines[i].length = buffer.lines[i+1].pos - buffer.lines[i+0].pos; + } + + buffer.lines[buffer.line_count-1].length = buffer.length - buffer.lines[buffer.line_count-1].pos; + + buffer.fixed = true; + + TokenizeD(buffer); } LineBuffers @@ -282,19 +342,23 @@ CreateLineBuffers(u64 arena_size) } void -Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos) +Insert(Editor* editor, u8[] insert, u64 length, u64 insert_position) { - if(fb.length + length > fb.data.length-SPACING) + editor.changed = true; + + if(editor.length + length > editor.data.length-SPACING) { - SetBuffers(&fb.tk, Realloc(fb.tk.tokens, fb.data.length*2)); - SetBuffers(fb, Realloc(fb.data, fb.data.length*2)); + editor.tokenizer.tokens = Realloc(editor.tokenizer.tokens, editor.data.length*2); + editor.data = Realloc(editor.data, editor.data.length*2); } + BufferViewInfo* view_info = editor.view_info; + u64 new_lines; for(u64 i = 0; i < length; i += 1) { - fb.pos += 1; - new_lines += u64(insert.ptr[i] == '\n'); + view_info.pos += 1; + new_lines += u64(insert.ptr[i] == '\n'); } if(length == 1) @@ -302,22 +366,22 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos) u8 new_ch; switch(insert[0]) { - case '[': new_ch = ']'; break; - case '(': new_ch = ')'; break; - case '{': new_ch = '}'; break; + case '[': new_ch = ']'; break; + case '(': new_ch = ')'; break; + case '{': new_ch = '}'; break; case '\'', '"', '`', '\n': new_ch = insert[0]; break; default: break; } - if(new_ch == '\n' && pos > 0) + if(new_ch == '\n' && insert_position > 0) { - u8 l = fb.data[pos-1]; - u8 r = fb.data[pos]; + u8 l = editor.data[insert_position-1]; + u8 r = editor.data[insert_position]; bool expand = (l == '(' && r == ')') || (l == '{' && r == '}') || (l == '[' && r == ']'); - u32 level = LevelFromPos(fb, pos) + u32(expand); + u32 level = LevelFromPos(editor, insert_position) + u32(expand); u64 limit = level + length; - for(; length < limit; length += 1, fb.pos += 1) + for(; length < limit; length += 1, view_info.pos += 1) { insert[length] = '\t'; } @@ -341,96 +405,94 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos) } } - u64 temp_len = fb.length-pos; + u64 temp_length = editor.length-insert_position; + u8[] temp = Alloc!(u8)(&editor.arena, editor.data[insert_position .. insert_position+temp_length]); - u8[] temp = Alloc!(u8)(&fb.arena, fb.data[pos .. pos+temp_len]); + editor.data[insert_position .. insert_position+length] = insert[0 .. length]; + insert_position += length; + editor.data[insert_position .. insert_position+temp_length] = temp[0 .. temp_length]; - fb.data[pos .. pos+length] = insert[0 .. length]; - pos += length; - fb.data[pos .. pos+temp_len] = temp[0 .. temp_len]; + editor.length += length; + editor.line_count += new_lines; - fb.length += length; + Fix(editor); - fb.line_count += new_lines; - - Fix(fb); - - Reset(&fb.arena); + Reset(&editor.arena); } void -ToggleSelection(FlatBuffer* fb, SelectMode mode) +ToggleSelection(Editor* editor, SelectMode mode) { - if(fb.sel_mode == SM.None) + if(editor.view_info.selection_mode == SM.None) { - StartSelection(fb, mode); + StartSelection(editor, mode); } else { - EndSelection(fb); + EndSelection(editor); } } void -StartSelection(FlatBuffer* fb, SelectMode mode) +StartSelection(Editor* editor, SelectMode mode) { - fb.sel_mode = mode; + editor.view_info.selection_mode = mode; if(mode == SM.Normal) { - fb.selection = fb.pos; + editor.view_info.selection = editor.view_info.pos; } else if(mode == SM.Line) { - fb.selection = CurrentLine(fb); + editor.view_info.selection = CurrentLine(editor); } } void -EndSelection(FlatBuffer* fb) +EndSelection(Editor* editor) { - fb.selection = -1; - fb.sel_mode = SM.None; + editor.view_info.selection = -1; + editor.view_info.selection_mode = SM.None; } void -Insert(FlatBuffer* fb, u8[] insert, u64 length) +Insert(Editor* ed, u8[] insert, u64 length) { - Insert(fb, insert, length, fb.pos); + Insert(ed, insert, length, ed.view_info.pos); } -pragma(inline) i64 -CurrentLine(FlatBuffer* fb) +pragma(inline, true) i64 +CurrentLine(Editor* ed) { - return LineFromPos(fb, fb.pos); + return LineFromPos(ed, ed.view_info.pos); } -pragma(inline) i64 -CurrentCol(FlatBuffer* fb) +pragma(inline, true) i64 +CurrentCol(Editor* ed) { - return LinePos(fb, fb.pos); + return LinePos(ed, ed.view_info.pos); } -pragma(inline) i64 -LinePos(FlatBuffer* fb, u64 pos) +pragma(inline, true) i64 +LinePos(Editor* editor, u64 pos) { - u64 line = LineFromPos(fb, pos); - return pos - fb.lines[line].pos; + u64 line = LineFromPos(editor, pos); + return pos - editor.lines[line].pos; } -pragma(inline) I64Vec2 -VecPos(FlatBuffer* fb) +pragma(inline, true) I64Vec2 +VecPos(Editor* editor) { - return I64Vec2(CurrentCol(fb), CurrentLine(fb)); + return I64Vec2(CurrentCol(editor), CurrentLine(editor)); } -pragma(inline) i64 -LineFromPos(FlatBuffer* fb, u64 pos) +pragma(inline, true) i64 +LineFromPos(Editor* editor, u64 pos) { i64 line = 0; - for(i64 i = 0; i < fb.line_count; i += 1) + for(i64 i = 0; i < editor.line_count; i += 1) { - if(fb.lines[i].pos > pos) + if(editor.lines[i].pos > pos) { break; } @@ -441,66 +503,61 @@ LineFromPos(FlatBuffer* fb, u64 pos) return line; } -pragma(inline) u16 -LevelFromPos(FlatBuffer* fb, u64 pos) +pragma(inline, true) u32 +LevelFromPos(Editor* editor, u64 pos) { - u64 line = LineFromPos(fb, pos); - return fb.lines[line].level; + u64 line = LineFromPos(editor, pos); + return editor.lines[line].level; } -pragma(inline) u64 -LineLength(FlatBuffer* fb, u64 line) +pragma(inline, true) u64 +LineLength(Editor* editor, u64 line) { - return fb.lines[line].length; + return editor.lines[line].length; } LineBuffer* -GetLine(FlatBuffer* fb, u64 line) +GetLine(Editor* editor, u64 line) { LineBuffer* lbuf = g_NIL_LINE_BUF; - if(line < fb.lines.length) + if(line < editor.lines.length) { - lbuf = SliceLineBuffer(fb, &fb.lines[line]); + lbuf = SliceLineBuffer(editor, &editor.lines[line]); } return lbuf; } -pragma(inline) LineBuffer* -SliceLineBuffer(FlatBuffer* fb, Line* ls) +pragma(inline, true) LineBuffer* +SliceLineBuffer(Editor* editor, Line* ls) { - LineBuffer* lbuf = Alloc!(LineBuffer)(&fb.linebufs.arena); + LineBuffer* lbuf = Alloc!(LineBuffer)(&editor.linebufs.arena); - lbuf.text = fb.data[ls.pos .. ls.pos+ls.length]; - lbuf.style = fb.tk.tokens[ls.pos .. ls.pos+ls.length]; + lbuf.text = editor.data[ls.pos .. ls.pos+ls.length]; + lbuf.style = editor.tokenizer.tokens[ls.pos .. ls.pos+ls.length]; return lbuf; } -void -Clear(Editor* ed) +pragma(inline, true) void +ResetBuffer(Editor* editor) { - Change(&ed.buf, [], ""); - ed.line_offset = 0; -} - -pragma(inline) void -ResetBuffer(FlatBuffer* fb) -{ - Reset(&fb.linebufs.arena); + Reset(&editor.linebufs.arena); } void -MoveToEOL(FlatBuffer* fb) +MoveToEOL(Editor* editor) { - if(fb.data[fb.pos] != '\n') + ref i64 pos = editor.view_info.pos; + + if(editor.data[pos] != '\n') { - for(u64 i = 0; i < fb.lines.length; i += 1) + for(u64 i = 0; i < editor.lines.length; i += 1) { - if(fb.pos < fb.lines[i].pos) + if(pos < editor.lines[i].pos) { - fb.pos = 0 < i ? fb.lines[i].pos-1 : fb.length; + pos = 0 < i ? editor.lines[i].pos-1 : editor.length; break; } } @@ -508,15 +565,17 @@ MoveToEOL(FlatBuffer* fb) } void -MoveToSOL(FlatBuffer* fb) +MoveToSOL(Editor* editor) { - if(fb.pos != 0 && fb.data[fb.pos-1] != '\n') + ref i64 pos = editor.view_info.pos; + + if(pos != 0 && editor.data[pos-1] != '\n') { - for(u64 i = 0; i < fb.lines.length; i += 1) + for(u64 i = 0; i < editor.lines.length; i += 1) { - if(fb.pos < fb.lines[i].pos) + if(pos < editor.lines[i].pos) { - fb.pos = i > 0 ? fb.lines[i-1].pos : 0; + pos = i > 0 ? editor.lines[i-1].pos : 0; break; } } @@ -524,79 +583,81 @@ MoveToSOL(FlatBuffer* fb) } void -MoveUp(FlatBuffer* fb) +MoveUp(Editor* editor) { - MoveUp(fb, LinePos(fb, fb.pos)); + MoveUp(editor, LinePos(editor, editor.view_info.pos)); } void -MoveUp(FlatBuffer* fb, u64 col) +MoveUp(Editor* editor, u64 col) { - u64 line = CurrentLine(fb); + u64 line = CurrentLine(editor); if(line > 0) { - u64 end = fb.lines[line].pos-1; - line -= 1; - col = Max(col, fb.col_pos); - fb.pos = Min(fb.lines[line].pos+col, end); + u64 end = editor.lines[line].pos-1; + line -= 1; + col = Max(col, editor.view_info.column_position); + editor.view_info.pos = Min(editor.lines[line].pos+col, end); } } void -MoveDown(FlatBuffer* fb) +MoveDown(Editor* editor) { - MoveDown(fb, LinePos(fb, fb.pos)); + MoveDown(editor, LinePos(editor, editor.view_info.pos)); } void -MoveDown(FlatBuffer* fb, u64 col) +MoveDown(Editor* editor, u64 col) { - u64 line = CurrentLine(fb); - if(line+1 < fb.lines.length) + BufferViewInfo* info = editor.view_info; + u64 line = CurrentLine(editor); + if(line+1 < editor.lines.length) { - line += 1; - fb.pos = fb.lines[line].pos; - u64 end = fb.lines.length > line+1 ? fb.lines[line+1].pos-1 : fb.length; - col = Max(col, fb.col_pos); - fb.pos = Min(fb.pos+col, end); + line += 1; + info.pos = editor.lines[line].pos; + u64 end = editor.lines.length > line+1 ? editor.lines[line+1].pos-1 : editor.length; + col = Max(col, info.column_position); + info.pos = Min(info.pos+col, end); } } void -MoveToEmptyLine(bool up)(FlatBuffer* fb) +MoveToEmptyLine(bool up)(Editor* editor) { - static if(!up) u64 lf_pos; + u64 lf_pos; bool started; u64 step = up ? -1 : 1; + ref i64 position = editor.view_info.pos; u8 ch = 0; - if((fb.pos != 0 && up) || (fb.pos != fb.length && !up)) + if((position != 0 && up) || (position != editor.length && !up)) { - for(u64 i = fb.pos + step; true; i += step) + for(u64 i = position+step; true; i += step) { static if(!up) { - if(i == fb.length-1) + if(i == editor.length-1) { - fb.pos = fb.length; + position = editor.length; break; } - ch = fb.data[i]; + ch = editor.data[i]; } static if(up) { if(i == 0) { - fb.pos = 0; + position = 0; break; } - ch = fb.data[i-1]; + ch = editor.data[i-1]; } - if(started && !CheckWhiteSpace(fb.data[i])) + if(started && !CheckWhiteSpace(editor.data[i])) { started = false; } @@ -610,31 +671,17 @@ MoveToEmptyLine(bool up)(FlatBuffer* fb) if(started && ch == '\n') { - fb.pos = i; - MoveToSOL(fb); + position = i; + MoveToSOL(editor); break; } } } } -pragma(inline) bool -IsLetter(u8 ch) -{ - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); -} - -pragma(inline) bool -IsNumber(u8 ch) -{ - return ch >= '0' && ch <= '9'; -} - -pragma(inline) bool -IsSymbol(u8 ch) -{ - return ch < 128 && SYM_TOKENS[ch]; -} +pragma(inline, true) bool IsLetter(u8 ch) => (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); +pragma(inline, true) bool IsNumber(u8 ch) => ch >= '0' && ch <= '9'; +pragma(inline, true) bool IsSymbol(u8 ch) => ch < 128 && SYM_TOKENS[ch]; enum ChType { @@ -673,82 +720,84 @@ GetChType(u8 ch) } void -MoveToWordEdge(bool forward)(FlatBuffer* fb) +MoveToWordEdge(bool forward)(Editor* editor) { - u64 step = forward ? 1 : -1; + u64 step = forward ? 1 : -1; + ref i64 position = editor.view_info.pos; - if((forward && fb.pos < fb.length-1) || (!forward && fb.pos > 0)) + if((forward && position < editor.length-1) || (!forward && position > 0)) { - ChType type = GetChType(fb.data[fb.pos]); - if(type != GetChType(fb.data[fb.pos+step])) + ChType type = GetChType(editor.data[position]); + if(type != GetChType(editor.data[position+step])) { - fb.pos += step; + position += step; } - else for(u64 i = fb.pos+step; true; i += step) + else for(u64 i = position+step; true; i += step) { static if(forward) { - u8 next = i < fb.length-1 ? fb.data[i+1] : 0; + u8 next = i < editor.length-1 ? editor.data[i+1] : 0; } else { - u8 next = i > 1 ? fb.data[i-1] : 0; + u8 next = i > 1 ? editor.data[i-1] : 0; } - static if(forward) if(i == fb.length-2) + static if(forward) if(i == editor.length-2) { - fb.pos = i; - fb.pos += u64(GetChType(next) == type); + position = i; + position += u64(GetChType(next) == type); break; } static if(!forward) if(i == 1) { - fb.pos = i; - fb.pos += GetChType(next) == type ? -1 : 0; + position = i; + position += GetChType(next) == type ? -1 : 0; break; } if(CheckChMatch(next, type)) { - fb.pos = i; + position = i; break; } } - while(CheckWhiteSpace(fb.data[fb.pos])) + while(CheckWhiteSpace(editor.data[position])) { - bool exit = forward ? fb.pos == fb.length-1 : fb.pos == 0; + bool exit = forward ? position == editor.length-1 : position == 0; if(exit) break; - fb.pos += step; + position += step; } } } void -MoveToNextWord(bool forward)(FlatBuffer* fb) +MoveToNextWord(bool forward)(Editor* editor) { - ChType type = GetChType(fb.data[fb.pos]); + ref i64 position = editor.view_info.pos; + ChType type = GetChType(editor.data[position]); bool hit_ws; u64 step = forward ? 1 : -1; - for(u64 i = fb.pos; true; i += step) with(ChType) + for(u64 i = position; true; i += step) with(ChType) { - static if(forward) if(i == fb.length-1) + static if(forward) if(i == editor.length-1) { - fb.pos = i; + position = i; break; } static if(!forward) if(i == 0) { - fb.pos = i; + position = i; break; } - u8 ch = fb.data[i]; + u8 ch = editor.data[i]; if(CheckWhiteSpace(ch)) { @@ -758,25 +807,26 @@ MoveToNextWord(bool forward)(FlatBuffer* fb) if(hit_ws) { - fb.pos = i; + position = i; break; } if(CheckChMatch(ch, type)) { - fb.pos = i; + position = i; break; } } - assert(fb.pos >= 0 && fb.pos <= fb.length); + assert(position >= 0 && position <= editor.length); } bool -Move(FlatBuffer* fb, Input key, Modifier md) +Move(Editor* editor, Input key, Modifier md) { bool taken; + ref i64 position = editor.view_info.pos; if(md & (MD.LeftShift | MD.RightShift)) { @@ -784,32 +834,32 @@ Move(FlatBuffer* fb, Input key, Modifier md) { case Up: { - MoveToEmptyLine!(true)(fb); + MoveToEmptyLine!(true)(editor); taken = true; } break; case Down: { - MoveToEmptyLine!(false)(fb); + MoveToEmptyLine!(false)(editor); taken = true; } break; case Left: { - if(fb.pos > 0) + if(position > 0) { - MoveToWordEdge!(false)(fb); + MoveToWordEdge!(false)(editor); taken = true; } } break; case Right: { - if(fb.pos < fb.length) + if(position < editor.length) { - MoveToWordEdge!(true)(fb); + MoveToWordEdge!(true)(editor); taken = true; } } break; - case Home: fb.pos = 0; taken = true; break; - case End: fb.pos = fb.length; taken = true; break; + case Home: position = 0; taken = true; break; + case End: position = editor.length; taken = true; break; default: break; } } @@ -825,17 +875,17 @@ Move(FlatBuffer* fb, Input key, Modifier md) } break; case Left: { - if(fb.pos > 0) + if(position > 0) { - MoveToNextWord!(false)(fb); + MoveToNextWord!(false)(editor); taken = true; } } break; case Right: { - if(fb.pos < fb.length) + if(position < editor.length) { - MoveToNextWord!(true)(fb); + MoveToNextWord!(true)(editor); taken = true; } } break; @@ -848,102 +898,101 @@ Move(FlatBuffer* fb, Input key, Modifier md) { case Down: { - MoveDown(fb); + MoveDown(editor); taken = true; } break; case Up: { - MoveUp(fb); + MoveUp(editor); taken = true; } break; case Left: { - if(fb.pos > 0 && fb.data[fb.pos-1] != '\n') + if(position > 0 && editor.data[position-1] != '\n') { - fb.pos -= 1; - taken = true; + position -= 1; + taken = true; } } break; case Right: { - if(fb.pos < fb.length && fb.data[fb.pos] != '\n') + if(position < editor.length && editor.data[position] != '\n') { - fb.pos += 1; - taken = true; + position += 1; + taken = true; } } break; - case Home: MoveToSOL(fb); taken = true; break; - case End: MoveToEOL(fb); taken = true; break; + case Home: MoveToSOL(editor); taken = true; break; + case End: MoveToEOL(editor); taken = true; break; default: break; } } if(key == Input.Left || key == Input.Right) { - fb.col_pos = LinePos(fb, fb.pos); + editor.view_info.column_position = LinePos(editor, position); } - UpdateSelection(fb); + UpdateSelection(editor); return taken; } void -UpdateSelection(FlatBuffer* fb) +UpdateSelection(Editor* editor) { - if(fb.sel_mode == SM.Normal) + BufferViewInfo* info = editor.view_info; + switch(info.selection_mode) { - fb.selection.y = fb.pos; - } - - if(fb.sel_mode == SM.Line) - { - fb.selection.y = CurrentLine(fb); + case SM.Normal: info.selection.y = info.pos; break; + case SM.Line: info.selection.y = CurrentLine(editor); break; + default: break; } } void -Backspace(FlatBuffer* fb) +Backspace(Editor* editor) { - if(fb.pos-1 >= 0) + ref i64 position = editor.view_info.pos; + if(position-1 >= 0) { - fb.pos -= 1; - Delete(fb, 1, fb.pos); + position -= 1; + Delete(editor, 1, position); } } void -Delete(FlatBuffer* fb, u64 length, u64 pos) +Delete(Editor* editor, u64 length, u64 delete_position) { - u64 end = pos+length; - assert(end <= fb.length, "Delete failure: pos+length is not in range"); + u64 end = delete_position+length; + assert(end <= editor.length, "Delete failure: delete_position+length is not in range"); - for(u64 i = pos; i < fb.length && i < pos+length; i += 1) + for(u64 i = delete_position; i < editor.length && i < delete_position+length; i += 1) { - if(fb.data[i] == '\n') + if(editor.data[i] == '\n') { - fb.line_count -= 1; + editor.line_count -= 1; } } u8[] temp; - if(end != fb.length) + if(end != editor.length) { - temp = Alloc!(u8)(&fb.arena, fb.length-end); - temp[0 .. temp.length] = fb.data[end .. fb.length]; - fb.data[pos .. pos+temp.length] = temp[0 .. temp.length]; + temp = Alloc!(u8)(&editor.arena, editor.length-end); + memcpy(temp.ptr, editor.data.ptr+end, temp.length); + memcpy(editor.data.ptr+delete_position, temp.ptr, temp.length); } - fb.length -= length; + editor.length -= length; - Fix(fb); + Fix(editor); } void -Replace(FlatBuffer* fb, u8[] insert, u64 length, u64 pos, u64 delete_length) +Replace(Editor* editor, u8[] insert, u64 length, u64 pos, u64 delete_length) { - Delete(fb, delete_length, pos); - Insert(fb, insert, insert.length, pos); + Delete(editor, delete_length, pos); + Insert(editor, insert, insert.length, pos); } unittest diff --git a/src/editor/editor.d b/src/editor/editor.d index b805c4e..8b09216 100644 --- a/src/editor/editor.d +++ b/src/editor/editor.d @@ -1,5 +1,6 @@ import dlib; -import dlib.util : Str; +import dlib.util : Str; +import dlib.alloc : Reset; import vulkan; import std.format : sformat; @@ -16,8 +17,12 @@ import std.file; import std.string; import core.stdc.stdio; +const u64 ARRAY_COUNT_INCREMENT = 32; + f32 g_delta = 0.0; +alias UIHashTable = HashTable!(UIHash, UIItem*); + struct RenderCtx { PlatformWindow* window; @@ -25,7 +30,6 @@ struct RenderCtx Descriptor default_tex; Descriptor sampler; Pipeline pipeline; - Pipeline slug_pipeline; DescSetLayout desc_set_layout; DescSet[FO] desc_sets; PipelineLayout pipeline_layout; @@ -34,70 +38,73 @@ struct RenderCtx struct Ctx { - RenderCtx rd_ctx; + RenderCtx rd_ctx; - HashTable!(UIHash, UIItem*) items; - UIItem* free_items; - UIItem* last_item; + UIHashTable items; + UIItem* free_items; + UIItem* last_item; - Arena arena; - Arena temp_arena; - Arena[FO] str_arenas; + Arena arena; + Arena temp_arena; + Arena[FO] str_arenas; - Inputs* inputs; - u64 frame; - u64 f_idx; + Inputs* inputs; + u64 frame; + u64 frame_index; - Notification* active_notifications; - Notification* free_notifications; + Notification* active_notifications; + Notification* free_notifications; - LinkedList!(UIInput) events; - IVec2 mouse_pos; + LinkedList!(UIInput) events; + IVec2 mouse_pos; - SlugFont slug_font; - FontFace font; - FontSet[FS] font_sets; - u32 font_sets_used; - bool[FO] fonts_to_load; - bool prev_has_tex; - u32 prev_atlas_index; + FontFace font; + FontSet[FS] font_sets; + u32 font_sets_used; + bool[FO] fonts_to_load; + bool prev_has_tex; + u32 prev_atlas_index; - UIBuffer[FO] buffers; - - SlugBuffer[FO] slug_buffers; - MappedBuffer!(SlugVertex)[FO] slug_vertex_buffers; - MappedBuffer!(u32)[FO] slug_index_buffers; + UIBuffer[FO] buffers; - u32 tab_width; - Vec4[TS.max][UISH.max] syntax_colors; + u32 tab_width; + Vec4[TS.max][UISH.max] syntax_colors; - UIKey drag_key; - UIKey hover_key; - UIKey focus_key; + UIKey drag_key; + UIKey hover_key; + UIKey focus_key; - UIPanel* base_panel; - UIPanel* focused_panel; - UIPanel* free_panels; + UIPanel* base_panel; + UIPanel* focused_panel; + UIPanel* free_panels; - u64 last_hover_frame; + u64 last_hover_frame; - f32 pos_rate; - f32 scroll_rate; - f32 animation_rate; - f32 fade_rate; + f32 pos_rate; + f32 scroll_rate; + f32 animation_rate; + f32 fade_rate; - ConfigValue[CO.max] config_values; + ConfigValue[CO.max] config_values; - EditState state; - u8[128] input_buf; - u32 icount; - u64 editor_id_incr; - Timer timer; - CmdPalette cmd; - string[] file_names; - u64 panel_id; + EditState state; + u8[128] input_buf; + u32 icount; + u64 editor_id_incr; + Timer timer; + CmdPalette cmd; + string[] file_names; + u64 panel_id; + Editor[] editors; + u64 editor_count; + Editor* free_editors; + FlatBuffer[] text_buffers; + u64 text_buffer_count; + FlatBuffer* free_text_buffers; - debug bool dbg; + @property ref DescSet desc_set() => this.rd_ctx.desc_sets[this.frame_index]; + + debug bool dbg; alias rd_ctx this; } @@ -131,21 +138,17 @@ struct CmdPalette struct Editor { - Arena arena; - u64 editor_id; - - FlatBuffer buf; - Tokenizer tk; + alias BufferViewTable = HashTable!(string, BufferViewInfo); - I64Vec2 cursor_pos; - Vec2 select_start; - Vec2 select_end; - i64 line_offset; - i64 line_height; + BufferViewInfo view_info_default; + FlatBuffer* buffer; + Editor* list_next; + BufferViewInfo* view_info; + u64 editor_id; + i64 line_height; + BufferViewTable view_info_table; - Editor* free_next; - - alias buf this; + alias buffer this; } struct ChangeStacks @@ -165,7 +168,7 @@ struct EditorChange EditorChange* next; } -alias CmdFn = bool function(Ctx* ctx); // return true when completed +alias CmdFn = bool function(ref Ctx ctx); // return true when completed struct Command { @@ -235,17 +238,19 @@ enum EditState SetPanelFocus, // if moving left/right move up parent tree until one is found with a2d.x, same thing for up/down a2d.y } alias ES = EditState; -__gshared Ctx g_ctx; -__gshared const Editor g_nil_ed; -__gshared Editor* g_NIL_ED; -__gshared const UIItem g_ui_nil_item; -__gshared UIItem* g_UI_NIL; -__gshared const UIInput g_ui_nil_input; -__gshared UIInput* g_UI_NIL_INPUT; -__gshared const UIPanel g_nil_panel; -__gshared UIPanel* g_NIL_PANEL; -__gshared const Notification g_nil_notif; -__gshared Notification* g_NIL_NOTIF; +__gshared Ctx g_ctx; + +__gshared Editor g_nil_ed; +__gshared UIItem g_ui_nil_item; +__gshared UIInput g_ui_nil_input; +__gshared UIPanel g_nil_panel; +__gshared Notification g_nil_notif; + +__gshared Editor* g_NIL_ED = &g_nil_ed; +__gshared UIItem* g_UI_NIL_ITEM = &g_ui_nil_item; +__gshared UIInput* g_UI_NIL_INPUT = &g_ui_nil_input; +__gshared UIPanel* g_NIL_PANEL = &g_nil_panel; +__gshared Notification* g_NIL_NOTIF = &g_nil_notif; const Command NO_CMD = { name: [], @@ -402,10 +407,24 @@ Command[21] CMD_LIST = [ }, ]; +ref Ctx GetCtx() => g_ctx; + bool -ClosePanelCmd(Ctx* ctx) +ClosePanelCmd(ref Ctx ctx) { - Clear(ctx.focused_panel.ed); + Editor* editor = ctx.focused_panel.ed; + ctx.focused_panel.ed = null; + if(editor.file_name.length == 0 && editor.length == 0) + { + editor.buffer.list_next = ctx.free_text_buffers; + ctx.free_text_buffers = editor.buffer; + } + + FreeHashTable(editor.view_info_table); + memset(editor, 0, Editor.sizeof); + editor.list_next = ctx.free_editors; + ctx.free_editors = editor; + if(ctx.focused_panel != ctx.base_panel) { DLLRemove(ctx.focused_panel.parent, ctx.focused_panel, g_NIL_PANEL); @@ -456,38 +475,27 @@ ClosePanelCmd(Ctx* ctx) } bool -SplitVertically(Ctx* ctx) +SplitVertically(ref Ctx ctx) { AddPanel(ctx.focused_panel, A2D.X); return true; } bool -SplitHorizontally(Ctx* ctx) +SplitHorizontally(ref Ctx ctx) { AddPanel(ctx.focused_panel, A2D.Y); return true; } - bool -NotImplementedCallback(Ctx* ctx) +NotImplementedCallback(ref Ctx ctx) { Logf("Not yet implemented!"); return true; } -bool -CmdModeActive() -{ - return g_ctx.state == ES.CmdPalette; -} - -bool -Active(EditState state) -{ - return g_ctx.state == state; -} +bool Active(EditState state) => g_ctx.state == state; UIPanel* MakePanel(UIPanel* parent = g_NIL_PANEL) @@ -511,7 +519,7 @@ Cycle(Inputs* inputs) BeginUI(inputs); - Ctx* ctx = GetCtx(); + ref Ctx ctx = GetCtx(); Panel(ctx, ctx.base_panel); @@ -538,12 +546,7 @@ Focus(UIPanel* panel) void InitCtx(PlatformWindow* window) { - Ctx* ctx = &g_ctx; - - g_NIL_ED = cast(Editor*)&g_nil_ed; - g_UI_NIL = cast(UIItem*)&g_ui_nil_item; - g_UI_NIL_INPUT = cast(UIInput*)&g_ui_nil_input; - g_NIL_PANEL = cast(UIPanel*)&g_nil_panel; + ref Ctx ctx = GetCtx(); ctx.window = window; ctx.arena = CreateArena(MB(2)); @@ -552,6 +555,8 @@ InitCtx(PlatformWindow* window) ctx.cmd.exec_cmd_arena = CreateArena(MB(1)); ctx.timer = CreateTimer(); ctx.free_panels = g_NIL_PANEL; + ctx.text_buffers = Alloc!(FlatBuffer)(ARRAY_COUNT_INCREMENT); + ctx.editors = Alloc!(Editor)(ARRAY_COUNT_INCREMENT); InitUI(ctx); @@ -569,7 +574,7 @@ InitCtx(PlatformWindow* window) if(indexOf(e.name, ".git") != -1 || e.isDir) continue; u64 start = indexOf(e.name, "./") == 0 ? 2 : 0; - count += 1; + count += 1; } ctx.file_names = Alloc!(string)(&ctx.arena, count); @@ -579,7 +584,7 @@ InitCtx(PlatformWindow* window) { if(indexOf(e.name, ".git") != -1 || e.isDir) continue; - u64 start = indexOf(e.name, "./") == 0 ? 2 : 0; + u64 start = indexOf(e.name, "./") == 0 ? 2 : 0; ctx.file_names[count++] = Alloc(&ctx.arena, e.name); } } @@ -590,86 +595,36 @@ InitCtx(PlatformWindow* window) } } -Ctx* -GetCtx() -{ - return &g_ctx; -} - -char[] -ToAbsolutePath(string file_name) -{ - import core.stdc.string : strlen; - - char[1024] name_buf = '\0'; - char[1024] wd_buf = '\0'; - version(linux) - { - import core.sys.posix.unistd; - getcwd(wd_buf.ptr, wd_buf.length); - } - - version(Windows) - { - import core.sys.windows.direct; - _getcwd(wd_buf.ptr, wd_buf.length); - } - - char[] wd = wd_buf[0 .. strlen(wd_buf.ptr)]; - - version(linux) - { - if(file_name[0] != '/') - { - name_buf.sformat("%s/%s", wd, cast(char[])file_name); - } - else - { - name_buf.sformat("%s", cast(char[])file_name); - } - } - - version(Windows) - { - name_buf.sformat("%s/%s", wd, cast(char[])file_name); - } - - char[] path_buf = ScratchAlloc!(char)(strlen(name_buf.ptr)+1); - path_buf[0 .. $] = name_buf[0 .. path_buf.length]; - - return path_buf; -} - void SaveFile(Editor* ed, string file_name) { import core.stdc.stdio; - file_name = file_name.length == 0 ? Str(ed.buf.file_name) : file_name; + file_name = file_name.length == 0 ? Str(ed.file_name) : file_name; if(file_name.length > 0) { - char[] file_path = ToAbsolutePath(file_name); + string file_path = AbsolutePath(file_name); auto f = fopen(cast(char*)file_path.ptr, "wb"); if(f != null) { u64 tab_count; - for(u64 i = 0; i < ed.buf.length; i += 1) + for(u64 i = 0; i < ed.length; i += 1) { - if(ed.buf.data[i] == '\t') + if(ed.data[i] == '\t') { tab_count += 1; } } u64 tab_width = GetCtx().tab_width; - u64 buf_size = ed.buf.length + ((tab_width-1) * tab_count); + u64 buf_size = ed.length + ((tab_width-1) * tab_count); u8[] temp_buf = ScratchAlloc!(u8)(buf_size); u64 buf_pos; - for(u64 i = 0; i < ed.buf.length; i += 1) + for(u64 i = 0; i < ed.length; i += 1) { - if(ed.buf.data[i] == '\t') + if(ed.data[i] == '\t') { for(u64 j = 0; j < tab_width; j += 1) { @@ -678,7 +633,7 @@ SaveFile(Editor* ed, string file_name) } else { - temp_buf[buf_pos++] = ed.buf.data[i]; + temp_buf[buf_pos++] = ed.data[i]; } } @@ -689,40 +644,6 @@ SaveFile(Editor* ed, string file_name) } } -void -OpenFile(Editor* ed, string file_name) -{ - import core.stdc.stdio; - import std.file; - import std.conv; - - if(file_name.length > 0) - { - char[] file_path = ToAbsolutePath(file_name); - auto f = fopen(file_path.ptr, "rb"); - if(f != null) - { - fseek(f, 0, SEEK_END); - i64 len = ftell(f); - fseek(f, 0, SEEK_SET); - - if(len > 0) - { - u8[] buf = ScratchAlloc!(u8)(len); - fread(buf.ptr, u8.sizeof, len, f); - Change(&ed.buf, buf, file_name); - ed.buf.file_name = file_name; - } - - fclose(f); - } - else - { - perror("[Error] Unable to open file"); - } - } -} - string Str(TextInputBuffer text_buffer) { @@ -732,20 +653,48 @@ Str(TextInputBuffer text_buffer) Editor* CreateEditor() { - Editor* ed = Alloc!(Editor)(&g_ctx.arena); - ed.arena = CreateArena(MB(4)); - ed.buf = CreateFlatBuffer([], []); - ed.editor_id = g_ctx.editor_id_incr++; + ref Ctx ctx = GetCtx(); + + if(ctx.editor_count == ctx.editors.length) + { + ctx.editors = Realloc(ctx.editors, ctx.editors.length+ARRAY_COUNT_INCREMENT); + } + + Editor* editor = ctx.free_editors; + if(editor) + { + ctx.free_editors = editor.list_next; + } + else + { + editor = &ctx.editors[ctx.editor_count++]; + } + + editor.view_info_table = CreateHashTable!(string, BufferViewInfo)(4); + ResetViewInfo(&editor.view_info_default); + editor.view_info = &editor.view_info_default; + + editor.buffer = ctx.free_text_buffers; + if(editor.buffer) + { + ctx.free_text_buffers = editor.buffer.list_next; + } + else + { + editor.buffer = CreateFlatBuffer(ctx); + } + + editor.editor_id = g_ctx.editor_id_incr++; - return ed; + return editor; } pragma(inline) void -InsertInputToBuf(Ctx* ctx, Editor* ed) +InsertInputToBuf(ref Ctx ctx, Editor* ed) { if(ctx.icount > 0) { - Insert(&ed.buf, ctx.input_buf, ctx.icount); + Insert(ed, ctx.input_buf, ctx.icount); ctx.icount = 0; } } @@ -753,12 +702,12 @@ InsertInputToBuf(Ctx* ctx, Editor* ed) void ResetCtx(Editor* ed) { - InsertInputToBuf(&g_ctx, ed); + InsertInputToBuf(GetCtx(), ed); ResetCtx(); } void -ResetCmd(Ctx* ctx) +ResetCmd(ref Ctx ctx) { ctx.cmd.text_input.length = 0; ctx.cmd.selected = 0; @@ -836,9 +785,8 @@ bool HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focused) { Editor* ed = p.ed; - Ctx* ctx = &g_ctx; - FlatBuffer* fb = &ed.buf; - u64 initial_len = p.ed.buf.length; + ref Ctx ctx = GetCtx(); + u64 initial_len = p.ed.length; u8[] cb_text; for(auto node = inputs.first; node != null; node = node.next) @@ -896,17 +844,17 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse { case a, i: { - if(key == a && Shift(md) && fb) + if(key == a && Shift(md)) { - MoveToEOL(fb); + MoveToEOL(ed); } else if(key == a) { - Move(fb, Right, MD.None); + Move(ed, Right, MD.None); } else if(key == i && Shift(md)) { - MoveToSOL(fb); + MoveToSOL(ed); } ctx.state = ES.InputMode; @@ -916,7 +864,7 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse { if(Shift(node.md)) { - ctx.state = ES.CmdPalette; + ctx.state = ES.CmdPalette; ResetCmd(ctx); taken = true; @@ -930,11 +878,11 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse } if(Shift(md)) { - ToggleSelection(fb, SM.Line); + ToggleSelection(ed, SM.Line); } else { - ToggleSelection(fb, SM.Normal); + ToggleSelection(ed, SM.Normal); } } break; case c: @@ -984,22 +932,22 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse if(cb_text.length > 0) { - Insert(fb, cb_text, cb_text.length); + Insert(ed, cb_text, cb_text.length); } - return initial_len != p.ed.buf.length; + return initial_len != p.ed.length; } void SetOffset(Editor* ed, i64 adjust) { - i64 max_offset = ed.buf.line_count-ed.line_height; + i64 max_offset = ed.line_count-ed.line_height; if(max_offset < 0) { max_offset = 0; } - ed.line_offset = clamp(ed.line_offset+adjust, 0, max_offset); + ed.view_info.line_offset = clamp(ed.view_info.line_offset+adjust, 0, max_offset); } bool @@ -1009,15 +957,15 @@ MoveCursor(Editor* ed, UIInput* ev) switch(ev.key) with(Input) { - case Up, Down, Left, Right: taken = Move(&ed.buf, ev.key, ev.md); break; + case Up, Down, Left, Right: taken = Move(ed, ev.key, ev.md); break; default: break; } if(taken) { - I64Vec2 pos = VecPos(&ed.buf); - i64 min = ed.line_offset+2; - i64 max = clamp(ed.line_offset+ed.line_height-3, 0, ed.buf.line_count); + I64Vec2 pos = VecPos(ed); + i64 min = ed.view_info.line_offset+2; + i64 max = clamp(ed.view_info.line_offset+ed.line_height-3, 0, ed.line_count); if(pos.y > max) { SetOffset(ed, pos.y-max); @@ -1032,7 +980,7 @@ MoveCursor(Editor* ed, UIInput* ev) } pragma(inline) void -InsertChar(Ctx* ctx, Input input, bool modified) +InsertChar(ref Ctx ctx, Input input, bool modified) { ctx.input_buf[ctx.icount++] = InputToChar(input, modified); } @@ -1055,7 +1003,7 @@ CharCases() } bool -HandleInputMode(Ctx* ctx, UIPanel* p, UIInput* ev) +HandleInputMode(ref Ctx ctx, UIPanel* p, UIInput* ev) { bool taken; @@ -1064,7 +1012,7 @@ HandleInputMode(Ctx* ctx, UIPanel* p, UIInput* ev) mixin(CharCases()); case Input.Backspace: { - Backspace(&p.ed.buf); + Backspace(p.ed); taken = true; } break; case Input.Escape: @@ -1168,7 +1116,7 @@ StrContains(bool begins_with)(string str, string match) } void -HandleCmdMode(Ctx* ctx, bool* enter_hit, bool* buffer_changed, bool* selection_changed) +HandleCmdMode(ref Ctx ctx, bool* enter_hit, bool* buffer_changed, bool* selection_changed) { UIPanel* panel = ctx.focused_panel; Editor* ed = panel.ed; diff --git a/src/editor/parsing.d b/src/editor/parsing.d index 5e2c993..8c06a1a 100644 --- a/src/editor/parsing.d +++ b/src/editor/parsing.d @@ -1,5 +1,8 @@ import dlib; +import dlib.alloc : Reset; + +import editor; import buffer; enum TokenStyle : u8 @@ -399,28 +402,22 @@ struct Tokenizer } bool -Nil(Token* tk) +Nil(Token* token) { - return tk == g_NIL_TOKEN || tk == null; -} - -void -SetBuffers(Tokenizer* tk, TokenStyle[] tokens) -{ - tk.tokens = tokens; + return token == g_NIL_TOKEN || token == null; } Tokenizer -CreateTokenizer(FlatBuffer* fb) +CreateTokenizer(FlatBuffer* buffer) { - Tokenizer tk = { + Tokenizer tokenizer = { arena: CreateArena(MB(4)), }; - SetBuffers(&tk, Alloc!(TS)(fb.data.length)); + tokenizer.tokens = Alloc!(TS)(buffer.data.length); g_NIL_TOKEN = cast(Token*)&g_nil_tk; - tk.first = tk.last = g_NIL_TOKEN; + tokenizer.first = tokenizer.last = g_NIL_TOKEN; for(u64 i = 0; i < D_KEYWORDS.length; i += 1) { @@ -438,132 +435,133 @@ CreateTokenizer(FlatBuffer* fb) } } - return tk; + return tokenizer; } void -ResetTokenizer(Tokenizer* tk, u64 len) +ResetTokenizer(Tokenizer* tokenizer, u64 length) { - Reset(&tk.arena); - Free(tk.tokens); + Reset(&tokenizer.arena); + Free(tokenizer.tokens); - SetBuffers(tk, Alloc!(TS)(len)); - tk.pos = 0; - tk.first = tk.last = g_NIL_TOKEN; + tokenizer.tokens = Alloc!(TS)(length); + tokenizer.pos = 0; + tokenizer.first = tokenizer.last = g_NIL_TOKEN; } Token* -MakeToken(Tokenizer* tk, TokenType type, u64 start, u64 end) +MakeToken(Tokenizer* tokenizer, TokenType type, u64 length) { - Token* t = Alloc!(Token)(&tk.arena); + Token* token = Alloc!(Token)(&tokenizer.arena); - t.type = type; - t.start = start; - t.end = end; + token.type = type; + token.start = tokenizer.pos; + token.end = tokenizer.pos+length; - DLLPush(tk, t, g_NIL_TOKEN); + DLLPush(tokenizer, token, g_NIL_TOKEN); - return t; + return token; } u8 -Peek(FlatBuffer* fb) +Peek(T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer)) { - return fb.tk.pos+1 < fb.length ? fb.data[fb.tk.pos+1] : 0; + return buffer.tokenizer.pos+1 < buffer.length ? buffer.data[buffer.tokenizer.pos+1] : 0; } void -TokenizeD(FlatBuffer* fb) +TokenizeD(T)(T* buffer) + if(is(T == Editor) || is(T == FlatBuffer)) { - Tokenizer* tk = &fb.tk; + Tokenizer* tokenizer = &buffer.tokenizer; - Reset(&tk.arena); - tk.pos = 0; - tk.first = tk.last = g_NIL_TOKEN; + Reset(&tokenizer.arena); + tokenizer.pos = 0; + tokenizer.first = tokenizer.last = g_NIL_TOKEN; - for(; tk.pos < fb.length;) + for(; tokenizer.pos < buffer.length;) { - u8 ch = fb.data[tk.pos]; + u8 ch = buffer.data[tokenizer.pos]; bool alpha = (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); if(ch == ' ' || ch == '\t') { - Token* t = MakeToken(tk, TT.Whitespace, tk.pos, tk.pos+1); + Token* token = MakeToken(tokenizer, TT.Whitespace, 1); - for(tk.pos += 1; tk.pos < fb.length; tk.pos += 1) + for(tokenizer.pos += 1; tokenizer.pos < buffer.length; tokenizer.pos += 1) { - if(fb.data[tk.pos] != ' ' && fb.data[tk.pos] != '\t') + if(buffer.data[tokenizer.pos] != ' ' && buffer.data[tokenizer.pos] != '\t') { break; } } - t.end = tk.pos; + token.end = tokenizer.pos; } else if(ch == '\n') { - Token* t = MakeToken(tk, TT.NewLine, tk.pos, tk.pos+1); - tk.pos += 1; + Token* token = MakeToken(tokenizer, TT.NewLine, 1); + tokenizer.pos += 1; } else if(ch == 'r') { - u8 next = Peek(fb); + u8 next = Peek(buffer); if(next == '"') { - tk.pos += 1; - ParseStr!('"')(fb); + tokenizer.pos += 1; + ParseStr!('"')(buffer); } else { - ParseId(fb); + ParseId(buffer); } } else if(ch >= '0' && ch <= '9') { - ParseNum(fb); + ParseNum(buffer); } else if(ch == 'P' || ch == 'E' || ch == 'e' || ch == 'p') { - u8 next = Peek(fb); + u8 next = Peek(buffer); if(next == '-' || next == '+' || (next >= '0' && next <= '9')) { - ParseNum(fb); + ParseNum(buffer); } else { - ParseId(fb); + ParseId(buffer); } } else if(alpha || ch == '_') { - ParseId(fb); + ParseId(buffer); } else if(ch < 128 && D_STD_TOKEN[ch] != TT.None) { - Token* t = MakeToken(tk, D_STD_TOKEN[ch], tk.pos, tk.pos+1); - tk.pos += 1; + Token* token = MakeToken(tokenizer, D_STD_TOKEN[ch], 1); + tokenizer.pos += 1; } else if(ch < 128 && D_OP_TOKEN[ch] != TT.None) { - Token* t = MakeToken(tk, D_OP_TOKEN[ch], tk.pos, tk.pos+1); - tk.pos += 1; - FixOpAssign(fb, t); + Token* token = MakeToken(tokenizer, D_OP_TOKEN[ch], 1); + tokenizer.pos += 1; + FixOpAssign(buffer, token); } else if(ch < 128 && D_STR_TOKEN[ch] != TT.None) { if(ch == '"') { - ParseStr!('"')(fb); + ParseStr!('"')(buffer); } else if(ch == '`') { - ParseStr!('`')(fb); + ParseStr!('`')(buffer); } else { - ParseStr!('\'')(fb); + ParseStr!('\'')(buffer); } } else @@ -572,108 +570,108 @@ TokenizeD(FlatBuffer* fb) { case '@': { - Token* t = MakeToken(tk, TT.At, tk.pos, tk.pos+1); - tk.pos += 1; + Token* token = MakeToken(tokenizer, TT.At, 1); + tokenizer.pos += 1; - for(; tk.pos < fb.length; tk.pos += 1) + for(; tokenizer.pos < buffer.length; tokenizer.pos += 1) { - u8 c = fb.data[tk.pos]; + u8 c = buffer.data[tokenizer.pos]; if(CheckWhiteSpace(c)) break; if(!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z')) break; } - t.end = tk.pos; + token.end = tokenizer.pos; } break; case '.': { - Token* t = MakeToken(tk, TT.Dot, tk.pos, tk.pos+1); + Token* token = MakeToken(tokenizer, TT.Dot, 1); - for(; tk.pos < fb.length; tk.pos += 1) + for(; tokenizer.pos < buffer.length; tokenizer.pos += 1) { - if(fb.data[tk.pos] != '.') break; + if(buffer.data[tokenizer.pos] != '.') break; } - t.end = tk.pos; + token.end = tokenizer.pos; } break; case '#': { - Token* t = MakeToken(tk, TT.Import, tk.pos, tk.pos+1); + Token* token = MakeToken(tokenizer, TT.Import, 1); - for(; tk.pos < fb.length; tk.pos += 1) + for(; tokenizer.pos < buffer.length; tokenizer.pos += 1) { - if(CheckWhiteSpace(fb.data[tk.pos])) break; + if(CheckWhiteSpace(buffer.data[tokenizer.pos])) break; } - t.end = tk.pos; + token.end = tokenizer.pos; } break; case '/': { - Token* t = MakeToken(tk, TT.Slash, tk.pos, tk.pos+1); + Token* token = MakeToken(tokenizer, TT.Slash, 1); - u8 next = Peek(fb); + u8 next = Peek(buffer); if(next == '/') { - tk.pos += 1; - t.type = TT.Comment; + tokenizer.pos += 1; + token.type = TT.Comment; - for(; tk.pos < fb.length; tk.pos += 1) + for(; tokenizer.pos < buffer.length; tokenizer.pos += 1) { - if(CheckEOL(fb.data[tk.pos])) + if(CheckEOL(buffer.data[tokenizer.pos])) { break; } } - t.end = tk.pos+1; + token.end = tokenizer.pos+1; } else if(next == '*') { - tk.pos += 1; - t.type = TT.Comment; + tokenizer.pos += 1; + token.type = TT.Comment; - for(; tk.pos < fb.length; tk.pos += 1) + for(; tokenizer.pos < buffer.length; tokenizer.pos += 1) { - if(fb.data[tk.pos] == '/' && fb.data[tk.pos-1] == '*') + if(buffer.data[tokenizer.pos] == '/' && buffer.data[tokenizer.pos-1] == '*') { break; } } - tk.pos += 1; - t.end = tk.pos; + tokenizer.pos += 1; + token.end = tokenizer.pos; } else { - tk.pos += 1; - FixOpAssign(fb, t); + tokenizer.pos += 1; + FixOpAssign(buffer, token); } } break; default: { - Token* t = MakeToken(tk, TT.None, tk.pos, tk.pos+1); + Token* token = MakeToken(tokenizer, TT.None, 1); - for(; tk.pos < fb.length; tk.pos += 1) + for(; tokenizer.pos < buffer.length; tokenizer.pos += 1) { - if(CheckWhiteSpace(fb.data[tk.pos])) + if(CheckWhiteSpace(buffer.data[tokenizer.pos])) { break; } } - t.end = tk.pos; - tk.pos += 1; + token.end = tokenizer.pos; + tokenizer.pos += 1; } break; } } } - for(auto n = tk.first; !Nil(n); n = Next(n)) + for(auto n = tokenizer.first; !Nil(n); n = Next(n)) { Token* prev = Prev(n); Token* next = Next(n); - if(CheckFuncOrTemplateSig(fb, n)) + if(CheckFuncOrTemplateSig(n)) { continue; } @@ -688,7 +686,7 @@ TokenizeD(FlatBuffer* fb) else if(prev.type == TT.TypeKeyword && n.type == TT.Identifier) { n.type = TT.Type; - CheckTypeDeclaration(fb, n); + CheckTypeDeclaration(n); continue; } else if(prev.type == TT.EnumKeyword && n.type == TT.Identifier) @@ -715,9 +713,9 @@ TokenizeD(FlatBuffer* fb) CheckVarDeclaration(n); } - for(auto token = tk.first; !Nil(token); token = token.next) + for(auto token = tokenizer.first; !Nil(token); token = token.next) { - tk.tokens[token.start .. token.end] = TOKEN_STYLES[token.type]; + tokenizer.tokens[token.start .. token.end] = TOKEN_STYLES[token.type]; } } @@ -767,20 +765,20 @@ CheckVarDeclaration(Token* token) } void -CheckTypeDeclaration(FlatBuffer* fb, Token* token) +CheckTypeDeclaration(Token* token) { - for(Token* tk = Next(token); !Nil(tk) && tk.type != TT.RightBrace; tk = Next(tk)) + for(Token* next_token = Next(token); !Nil(next_token) && next_token.type != TT.RightBrace; next_token = Next(next_token)) { - Token* prev = Prev(tk); + Token* prev = Prev(next_token); if(prev.type == TT.LeftBrace || prev.type == TT.Semicolon) { - tk.type = TT.Type; + next_token.type = TT.Type; } } } bool -CheckFuncOrTemplateSig(FlatBuffer* fb, Token* token) +CheckFuncOrTemplateSig(Token* token) { bool found = false; @@ -825,18 +823,18 @@ CheckFuncOrTemplateSig(FlatBuffer* fb, Token* token) } u8[] -TokenStr(FlatBuffer* fb, Token* t) +TokenStr(Editor* editor, Token* token) { - return fb.data[t.start .. t.end]; + return editor.data[token.start .. token.end]; } Token* -Prev(types...)(Token* t) +Prev(types...)(Token* token) { Token* res = g_NIL_TOKEN; PrevMain: - for(auto p = t.prev; !Nil(p); p = p.prev) + for(auto p = token.prev; !Nil(p); p = p.prev) { if(p.type == TT.NewLine || p.type == TT.Whitespace || p.type == TT.Comment) { @@ -865,12 +863,12 @@ PrevMain: alias PrevFnToken = Prev!(TT.Identifier, TT.LeftParen, TT.RightParen, TT.Comma, TT.Keyword, TT.Dot, TT.Exclamation, TT.Type); Token* -Next(types...)(Token* t) +Next(types...)(Token* token) { Token* res = g_NIL_TOKEN; NextMain: - for(auto n = t.next; !Nil(n); n = n.next) + for(auto n = token.next; !Nil(n); n = n.next) { if(n.type == TT.NewLine || n.type == TT.Whitespace || n.type == TT.Comment) { @@ -899,20 +897,20 @@ NextMain: alias NextFnToken = Next!(TT.Identifier, TT.LeftParen, TT.RightParen, TT.Comma, TT.Keyword, TT.Dot, TT.Exclamation, TT.Type); void -ParseNum(FlatBuffer* fb) +ParseNum(T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer)) { - Tokenizer* tk = &fb.tk; + Tokenizer* tokenizer = &buffer.tokenizer; - Token* t = Alloc!(Token)(&tk.arena); - t.type = TT.Number; - t.start = tk.pos; + Token* token = Alloc!(Token)(&tokenizer.arena); + token.type = TT.Number; + token.start = tokenizer.pos; bool first = true; - while (tk.pos < fb.length) + while (tokenizer.pos < buffer.length) { - tk.pos += 1; + tokenizer.pos += 1; - u8 ch = fb.data[tk.pos]; + u8 ch = buffer.data[tokenizer.pos]; if(ch != '_' && ch != '.' && !(ch >= '0' && ch <= '9') && ch != 'x' && ch != 'X' && !((ch == '-' || ch == '+') && first)) { @@ -922,76 +920,76 @@ ParseNum(FlatBuffer* fb) first = false; } - while (tk.pos < fb.length) + while (tokenizer.pos < buffer.length) { - u8 ch = fb.data[tk.pos]; + u8 ch = buffer.data[tokenizer.pos]; if(ch != 'l' && ch != 'u' && ch != 'U' && ch != 'L' && ch != 'f' && ch != 'F') { break; } - tk.pos += 1; + tokenizer.pos += 1; } - t.end = tk.pos; + token.end = tokenizer.pos; - DLLPush(tk, t, g_NIL_TOKEN); + DLLPush(tokenizer, token, g_NIL_TOKEN); } void -ParseStr(u8 str_ch)(FlatBuffer* fb) +ParseStr(u8 str_ch, T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer)) { static assert(str_ch == '`' || str_ch == '\'' || str_ch == '"'); - Tokenizer* tk = &fb.tk; + Tokenizer* tokenizer = &buffer.tokenizer; - Token* t = Alloc!(Token)(&tk.arena); + Token* token = Alloc!(Token)(&tokenizer.arena); - t.type = D_STR_TOKEN[str_ch]; - t.start = tk.pos; + token.type = D_STR_TOKEN[str_ch]; + token.start = tokenizer.pos; - static if(str_ch == '`') tk.pos += 1; + static if(str_ch == '`') tokenizer.pos += 1; bool ignore = str_ch != '`'; - for(; (fb.data[tk.pos] != str_ch || ignore) && tk.pos < fb.length; tk.pos += 1) + for(; (buffer.data[tokenizer.pos] != str_ch || ignore) && tokenizer.pos < buffer.length; tokenizer.pos += 1) { - static if(str_ch != '`') ignore = fb.data[tk.pos] == '\\'; + static if(str_ch != '`') ignore = buffer.data[tokenizer.pos] == '\\'; } - tk.pos += 1; - t.end = tk.pos; + tokenizer.pos += 1; + token.end = tokenizer.pos; - DLLPush(tk, t, g_NIL_TOKEN); + DLLPush(tokenizer, token, g_NIL_TOKEN); } void -ParseId(FlatBuffer* fb) +ParseId(T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer)) { - Tokenizer* tk = &fb.tk; - Token* t = MakeToken(tk, TT.Identifier, tk.pos, tk.pos+1); + Tokenizer* tokenizer = &buffer.tokenizer; + Token* token = MakeToken(tokenizer, TT.Identifier, 1); - for(; tk.pos < fb.length; tk.pos += 1) + for(; tokenizer.pos < buffer.length; tokenizer.pos += 1) { - u8 ch = fb.data[tk.pos]; + u8 ch = buffer.data[tokenizer.pos]; if(!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && ch != '.' && ch != '_' && !(ch >= '0' && ch <= '9')) { - t.end = tk.pos; + token.end = tokenizer.pos; break; } } - u8 ch = fb.data[t.start]; + u8 ch = buffer.data[token.start]; if(ch < D_KEYWORDS.length && D_KEYWORDS[ch] != null && D_KEYWORDS[ch].length > 0) { bool found = false; - u8[] id = fb.data[t.start .. t.end]; + u8[] id = buffer.data[token.start .. token.end]; foreach(ref k; D_TYPES[ch]) { if(id == k) { - t.type = TT.Type; + token.type = TT.Type; found = true; break; } @@ -1005,19 +1003,19 @@ ParseId(FlatBuffer* fb) { if(k == r"import") { - t.type = TT.Import; + token.type = TT.Import; } else if(k == r"class" || k == r"struct") { - t.type = TT.TypeKeyword; + token.type = TT.TypeKeyword; } else if(k == r"enum") { - t.type = TT.EnumKeyword; + token.type = TT.EnumKeyword; } else { - t.type = TT.Keyword; + token.type = TT.Keyword; } break; @@ -1025,15 +1023,15 @@ ParseId(FlatBuffer* fb) } } - assert(t.start < t.end, "ParseId failure: start is lower or equal to end"); + assert(token.start < token.end, "ParseId failure: start is lower or equal to end"); } void -FixOpAssign(FlatBuffer* fb, Token* t) +FixOpAssign(T)(T* buffer, Token* token) if(is(T == Editor) || is(T == FlatBuffer)) { - if(t.end+1 < fb.length) + if(token.end+1 < buffer.length) { - u8[] str = fb.data[t.start .. t.end+1]; + u8[] str = buffer.data[token.start .. token.end+1]; if( str == "/=" || str == "+=" || @@ -1044,8 +1042,8 @@ FixOpAssign(FlatBuffer* fb, Token* t) str == "!=" ) { - fb.tk.pos += 1; - t.end += 1; + buffer.tokenizer.pos += 1; + token.end += 1; } } } @@ -1072,11 +1070,11 @@ CheckWhiteSpace(u8 ch) } void -SkipWhiteSpace(FlatBuffer* fb) +SkipWhiteSpace(Editor* editor) { - while (fb.tk.pos < fb.length) + while (editor.tokenizer.pos < editor.length) { - u8 ch = fb.data[fb.tk.pos]; + u8 ch = editor.data[editor.tokenizer.pos]; bool white_space = CheckWhiteSpace(ch); @@ -1085,7 +1083,7 @@ SkipWhiteSpace(FlatBuffer* fb) break; } - fb.tk.pos += 1; + editor.tokenizer.pos += 1; } } diff --git a/src/editor/ui.d b/src/editor/ui.d index 4b13d92..4e24479 100644 --- a/src/editor/ui.d +++ b/src/editor/ui.d @@ -1,6 +1,7 @@ import dlib; import dlib.util : HTPush = Push; import dlib.math : Clamp; +import dlib.alloc : Reset; import vulkan; import vulkan : RendererGetExtent = GetExtent; @@ -64,8 +65,8 @@ u8[] FONT_BYTES = cast(u8[])import("jetbrains-mono/JetBrainsMono-Regula u8[] VERTEX_BYTES = cast(u8[])import("gui.vert.spv"); u8[] FRAGMENT_BYTES = cast(u8[])import("gui.frag.spv"); -const SEP_FLAGS = UIF.Drag|UIF.Priority|UIF.TargetLeniency; -const PANEL_FLAGS = UIF.Click|UIF.Drag; +const SEP_FLAGS = UIF.Drag | UIF.Priority | UIF.TargetLeniency; +const PANEL_FLAGS = UIF.Click | UIF.Drag; const UI_COUNT = 5000; @@ -322,10 +323,27 @@ Attribute[10] attributes = [ { binding: 0, location: 9, format: FMT.R_U32, offset: Vertex.has_texture.offsetof }, ]; -union Rect +struct Rect { - Vec2[2] v; - struct { Vec2 p0, p1; alias p0 pos; }; + union + { + Vec2[2] v; + struct + { + Vec2 p0, p1; + alias p0 pos; + }; + }; + + ref Vec2 opIndex(usize index) + { + return this.v[index]; + } + + ref Vec2 opIndexAssign(usize index, Vec2 value) + { + return this.v[index] = value; + } } alias UIHash = u64; @@ -341,53 +359,11 @@ struct UIKey bool opCast(T)() if(is(T == bool)) => this.hash != 0; } -/* - "atlas": { - "type": "mtsdf", - "distanceRange": 2, - "distanceRangeMiddle": 0, - "size": 32.5, - "width": 216, - "height": 216, - "yOrigin": "bottom" - }, - "metrics": { - "emSize": 1, - "lineHeight": 1.3200000000000001, - "ascender": 1.02, - "descender": -0.29999999999999999, - "underlineY": -0.17999999999999999, - "underlineThickness": 0.050000000000000003 - }, - "glyphs": [ - { - "unicode": 32, - "advance": 0.59999999999999998 - }, - { - "unicode": 33, - "advance": 0.59999999999999998, - "planeBounds": { - "left": 0.19230769230769232, - "bottom": -0.046153846153846149, - "right": 0.40769230769230769, - "top": 0.78461538461538449 - }, - "atlasBounds": { - "left": 19.5, - "bottom": 151.5, - "right": 26.5, - "top": 178.5 - } - }, - -*/ - enum bool KeyType(T) = (StringType!(T) || is(T == UIKey) || is(T == const(UIKey))); enum bool ItemAndKeyType(T) = (KeyType!(T) || is(T == UIItem*)); void -InitUI(Ctx* ctx) +InitUI(ref Ctx ctx) { version(ENABLE_RENDERER) { @@ -438,18 +414,13 @@ InitUI(Ctx* ctx) for(u64 i = 0; i < FRAME_OVERLAP; i += 1) { - ctx.buffers[i].m_vtx = CreateMappedBuffer!(Vertex)(BT.Vertex, VERTEX_MAX_COUNT); - ctx.buffers[i].m_idx = CreateMappedBuffer!(u32)(BT.Index, 6); - ctx.buffers[i].vtx = ctx.buffers[i].m_vtx.data; - ctx.buffers[i].idx = ctx.buffers[i].m_idx.data; + ctx.buffers[i].m_vtx = CreateMappedBuffer!(Vertex)(BT.Vertex, VERTEX_MAX_COUNT); + ctx.buffers[i].m_idx = CreateMappedBuffer!(u32)(BT.Index, 6); + ctx.buffers[i].vtx = ctx.buffers[i].m_vtx.data; + ctx.buffers[i].idx = ctx.buffers[i].m_idx.data; ctx.buffers[i].idx[0 .. $] = [0, 1, 2, 2, 1, 3]; - ctx.desc_sets[i] = AllocDescSet(ctx.desc_set_layout); - ctx.str_arenas[i] = CreateArena(MB(1)); - - ctx.slug_vertex_buffers[i] = CreateMappedBuffer!(SlugVertex)(BT.Vertex, 1000); - ctx.slug_index_buffers[i] = CreateMappedBuffer!(u32)(BT.Index, 1000); - ctx.slug_buffers[i].vertices = ctx.slug_vertex_buffers[i].data; - ctx.slug_buffers[i].indices = ctx.slug_index_buffers[i].data; + ctx.desc_sets[i] = AllocDescSet(ctx.desc_set_layout); + ctx.str_arenas[i] = CreateArena(MB(1)); } GfxPipelineInfo ui_info = { @@ -550,16 +521,16 @@ PushFree(string next_member = "free_next", T)(T** top, T* node) *top = node; } -f32 -GetLineHeight(u32 size) -{ - return GetFontSet(size).line_height; -} +f32 +GetLineHeight(u32 size) => GetFontSet(size).line_height; + +FontSet* +GetFontSet(T)(T font_set) if(is(T == FontSet*)) => font_set; FontSet* -GetFontSet(u32 size) +GetFontSet(T)(T size) if(is(T: u32)) { - Ctx* ctx = GetCtx(); + ref Ctx ctx = GetCtx(); FontSet* fs = null; for(u64 i = 0; i < ctx.font_sets_used; i += 1) @@ -570,7 +541,7 @@ GetFontSet(u32 size) break; } } - + if(!fs) { fs = &ctx.font_sets[ctx.font_sets_used++]; @@ -590,30 +561,30 @@ GetFontSet(u32 size) void LoadFontSet() { - Ctx* ctx = GetCtx(); - u64 fi = ctx.f_idx; + ref Ctx ctx = GetCtx(); for(u64 i = 0; i < ctx.font_sets_used; i += 1) { - FontSet* fs = ctx.font_sets.ptr + i; + FontSet* fs = ctx.font_sets.ptr + i; + ref bool descriptor_written = fs.descriptor_written[ctx.frame_index]; if(!fs.texture_loaded) { Transfer!(true)(&ctx.font_descs[i], fs.atlas.data); fs.texture_loaded = true; } - if(!fs.descriptor_written[fi]) + if(!descriptor_written) { - Write(ctx.desc_sets[fi], ctx.font_descs); - fs.descriptor_written[fi] = true; + Write(ctx.desc_set, ctx.font_descs); + descriptor_written = true; } } - ctx.fonts_to_load[fi] = false; + ctx.fonts_to_load[ctx.frame_index] = false; } void -Scissor(Ctx* ctx, Rect rect, Style* style) +Scissor(ref Ctx ctx, Rect rect, Style* style) { DrawUI(ctx); @@ -630,14 +601,14 @@ Scissor(Ctx* ctx, Rect rect, Style* style) } void -EndScissor(Ctx* ctx) +EndScissor(ref Ctx ctx) { DrawUI(ctx); ResetScissor(); } void -Panel(Ctx* ctx, UIPanel* panel) +Panel(ref Ctx ctx, UIPanel* panel) { panel.item = MakeItem!(PANEL_FLAGS)("###panel_%s", panel.id); Axis2D p_axis = Nil(panel.parent) ? A2D.X : panel.parent.axis; @@ -682,16 +653,16 @@ Panel(Ctx* ctx, UIPanel* panel) panel.move_text_with_cursor = false; } - panel.scroll_target.y = cast(f32)(panel.ed.line_offset)*fs.line_height; + panel.scroll_target.y = cast(f32)(panel.ed.view_info.line_offset)*fs.line_height; - f32 max_px = panel.ed.buf.line_count*fs.line_height; + f32 max_px = panel.ed.line_count*fs.line_height; f32 offset = -(panel.item.scroll_offset.y%fs.line_height); u64 start_ln = cast(u64)(floor(panel.scroll_offset.y/fs.line_height)); const f32 PAD = 4.0f; // Line counter - u64 lc_chars = panel.ed.buf.line_count.toChars().length; + u64 lc_chars = panel.ed.line_count.toChars().length; f32 lc_width = PAD*2.0 + cast(f32)(lc_chars)*fs.max_advance; Style style = PANEL_STYLE; @@ -709,7 +680,7 @@ Panel(Ctx* ctx, UIPanel* panel) f32 panel_height = Size!(A2D.Y)(line_count_rect); panel.ed.line_height = cast(i64)ceil(panel_height/fs.line_height); - u64 max_ln = Min(panel.ed.line_height + start_ln, panel.ed.buf.line_count); + u64 max_ln = Min(panel.ed.line_height + start_ln, panel.ed.line_count); for(u64 i = start_ln; i < max_ln; i += 1) { @@ -729,12 +700,12 @@ Panel(Ctx* ctx, UIPanel* panel) text_rect = Pad(text_view_rect, PAD); - I64Vec2 cursor_coords = VecPos(&panel.ed.buf); - LineBuffer* current_lbuf = GetLine(&panel.ed.buf, cursor_coords.y); + I64Vec2 cursor_coords = VecPos(panel.ed); + LineBuffer* current_lbuf = GetLine(panel.ed, cursor_coords.y); UIItem* cursor = MakeItem("###cursor_%s", panel.id); if(ctx.focused_panel == panel) { - i64 y_pos = cursor_coords.y - panel.ed.line_offset; + i64 y_pos = cursor_coords.y - panel.ed.view_info.line_offset; cursor.size.x = Active(ES.InputMode) ? 2.0 : fs.max_advance; cursor.size.y = fs.line_height; @@ -760,7 +731,7 @@ Panel(Ctx* ctx, UIPanel* panel) { if(Active(ES.InputMode) && panel.move_text_with_cursor) { - for(LineBuffer* lbuf = GetLine(&panel.ed.buf, i); i < max_ln && !CheckNil(g_NIL_LINE_BUF, lbuf); lbuf = GetLine(&panel.ed.buf, ++i)) + for(LineBuffer* lbuf = GetLine(panel.ed, i); i < max_ln && !CheckNil(g_NIL_LINE_BUF, lbuf); lbuf = GetLine(panel.ed, ++i)) { if(i == cursor_coords.y) { @@ -799,7 +770,7 @@ Panel(Ctx* ctx, UIPanel* panel) DrawLines(ctx, panel, start_ln, max_ln, text_rect, fs); } - ResetBuffer(&panel.ed.buf); + ResetBuffer(panel.ed); EndScissor(ctx); DrawBorder(ctx, text_view_rect, &style); @@ -844,10 +815,10 @@ Panel(Ctx* ctx, UIPanel* panel) } void -DrawLines(bool hl = false)(Ctx* ctx, UIPanel* panel, u64 start_line, u64 end_line, Rect text_rect, FontSet* fs, I64Vec2 cursor_coords = I64Vec2(-1)) +DrawLines(bool hl = false)(ref Ctx ctx, UIPanel* panel, u64 start_line, u64 end_line, Rect text_rect, FontSet* fs, I64Vec2 cursor_coords = I64Vec2(-1)) { u64 i = start_line; - for(LineBuffer* lbuf = GetLine(&panel.ed.buf, i); i < end_line && !CheckNil(g_NIL_LINE_BUF, lbuf); lbuf = GetLine(&panel.ed.buf, ++i)) + for(LineBuffer* lbuf = GetLine(panel.ed, i); i < end_line && !CheckNil(g_NIL_LINE_BUF, lbuf); lbuf = GetLine(panel.ed, ++i)) { static if(hl) { @@ -873,7 +844,7 @@ struct SearchWindowCtx(T) void SearchInputWindow(T)(string hash_text, SearchWindowCtx!(T)* window_ctx, bool ready_cond) if(is(T == Command) || is(T == string)) { - Ctx* ctx = GetCtx(); + ref Ctx ctx = GetCtx(); Vec2 extent = GetExtent(); f32 x = extent.x * 0.1; f32 y = extent.y * 0.2; @@ -955,7 +926,7 @@ SearchInputWindow(T)(string hash_text, SearchWindowCtx!(T)* window_ctx, bool rea Rect opt_rect = inner_rect; opt_rect.p0.y -= opt_start_offset; - UIItem* selected_opt_item = g_UI_NIL; + UIItem* selected_opt_item = g_UI_NIL_ITEM; if(start_opt_index < options.length) foreach(i; start_opt_index .. options.length) { Rect[2] opt_rects = Split(opt_rect, full_opt_height, A2D.Y); @@ -1058,9 +1029,9 @@ SearchInputWindow(T)(string hash_text, SearchWindowCtx!(T)* window_ctx, bool rea } bool -SaveFileWindow(Ctx* ctx) +SaveFileWindow(ref Ctx ctx) { - bool exit; + bool exit; Editor* ed = ctx.focused_panel.ed; static bool init = false; @@ -1068,7 +1039,6 @@ SaveFileWindow(Ctx* ctx) { ctx.cmd.exec_cmd_input.data[0 .. ed.file_name.length] = Arr!(u8)(ed.file_name[0 .. $]); ctx.cmd.exec_cmd_input.length = ed.file_name.length; - init = true; } const PAD = 4.0f; @@ -1133,19 +1103,16 @@ SaveFileWindow(Ctx* ctx) } } - if(exit) - { - init = false; - } + init = !exit; return exit; } bool -OpenFileWindow(Ctx* ctx) +OpenFileWindow(ref Ctx ctx) { - bool exit; - CmdPalette* cmd = &ctx.cmd; + bool exit; + ref CmdPalette cmd = ctx.cmd; if(!cmd.exec_cmd_opts.length && !cmd.exec_cmd_input.length) { @@ -1218,9 +1185,9 @@ OpenFileWindow(Ctx* ctx) } void -CommandPalette(Ctx* ctx) +CommandPalette(ref Ctx ctx) { - CmdPalette* cmd = &ctx.cmd; + ref CmdPalette cmd = ctx.cmd; bool enter_hit, buffer_changed, selection_changed; if(ctx.state == ES.CmdPalette) @@ -1416,15 +1383,9 @@ CreatePanel(Editor* ed = null) else { bool allocated; - p = GetOrAlloc(&g_ctx.arena, &g_ctx.free_panels, g_NIL_PANEL, &allocated); - if(allocated) - { - p.id = panel_id++; - } - if(!p.ed) - { - p.ed = CreateEditor(); - } + p = GetOrAlloc(&g_ctx.arena, &g_ctx.free_panels, g_NIL_PANEL, &allocated); + p.id = panel_id++; + p.ed = CreateEditor(); } p.item = MakeItem!(PANEL_FLAGS)("###panel_%s", p.id); @@ -1500,7 +1461,7 @@ Hovered(bool current_frame, T, U)(T param, U* ptr, U index) bool Hovered(bool current_frame, T)(T param) { - Ctx* ctx = GetCtx(); + ref Ctx ctx = GetCtx(); bool result; UIKey key = mixin(AssignKey!(T, param)); @@ -1521,7 +1482,7 @@ Hovered(bool current_frame, T)(T param) } void -PushUIEvent(Ctx* ctx, UIInput input) +PushUIEvent(ref Ctx ctx, UIInput input) { UIInput* ev = Alloc!(UIInput)(&ctx.temp_arena); *ev = input; @@ -1530,7 +1491,7 @@ PushUIEvent(Ctx* ctx, UIInput input) } void -DrawUI(Ctx* ctx, u32 atlas_index) +DrawUI(ref Ctx ctx, u32 atlas_index) { if(ctx.pc.atlas_index != atlas_index) { @@ -1541,33 +1502,17 @@ DrawUI(Ctx* ctx, u32 atlas_index) } void -DrawSlug(Ctx* ctx) +DrawUI(ref Ctx ctx) { version(ENABLE_RENDERER) { - // TODO: fix this - SlugBuffer* buffer = ctx.slug_buffers.ptr + ctx.f_idx; - - auto vertex_buffer = ctx.slug_vertex_buffers.ptr + ctx.f_idx; - auto index_buffer = ctx.slug_index_buffers.ptr + ctx.f_idx; - - BindBuffers(index_buffer, vertex_buffer); - DrawIndexed(buffer.quad_offset*6, 1, 0, 0, 0); - } -} - -void -DrawUI(Ctx* ctx) -{ - version(ENABLE_RENDERER) - { - UIBuffer* b = ctx.buffers.ptr + ctx.f_idx; - if(b.vtx_offset != b.count) + ref UIBuffer buffer = ctx.buffers[ctx.frame_index]; + if(buffer.vtx_offset != buffer.count) { - u32 count = b.count - b.vtx_offset; - BindBuffers(&b.m_idx, &b.m_vtx); - DrawIndexed(6, count, 0, 0, b.vtx_offset); - b.vtx_offset += count; + u32 count = buffer.count - buffer.vtx_offset; + BindBuffers(&buffer.m_idx, &buffer.m_vtx); + DrawIndexed(6, count, 0, 0, buffer.vtx_offset); + buffer.vtx_offset += count; } } } @@ -1575,10 +1520,10 @@ DrawUI(Ctx* ctx) void BeginUI(Inputs* inputs) { - Ctx* ctx = GetCtx(); - Arena* a = &ctx.temp_arena; + ref Ctx ctx = GetCtx(); + ref Arena arena = ctx.temp_arena; - Reset(a); + Reset(&arena); // Convert Inputs ctx.events.first = ctx.events.last = null; @@ -1687,11 +1632,11 @@ BeginUI(Inputs* inputs) // Ctx state ctx.frame = next_frame; - ctx.f_idx = ctx.frame%FRAME_OVERLAP; + ctx.frame_index = ctx.frame%FRAME_OVERLAP; ctx.inputs = inputs; - ctx.last_item = g_UI_NIL; + ctx.last_item = g_UI_NIL_ITEM; - Reset(&ctx.str_arenas[ctx.f_idx]); + Reset(&ctx.str_arenas[ctx.frame_index]); assert(!mouse_moved || ZeroKey(ctx.hover_key) || (ctx.frame == ctx.last_hover_frame)); @@ -1704,7 +1649,7 @@ BeginUI(Inputs* inputs) { BeginFrame(); - if(ctx.fonts_to_load[ctx.f_idx]) + if(ctx.fonts_to_load[ctx.frame_index]) { LoadFontSet(); } @@ -1714,22 +1659,19 @@ BeginUI(Inputs* inputs) SetStencilTest(false); PushConstants(ctx.pipeline, &ctx.pc); - Bind(ctx.pipeline, ctx.desc_sets[ctx.f_idx]); + Bind(ctx.pipeline, ctx.desc_sets[ctx.frame_index]); } - UIBuffer* buffer = ctx.buffers.ptr + ctx.f_idx; - SlugBuffer* slug_buffer = ctx.slug_buffers.ptr + ctx.f_idx; + UIBuffer* buffer = ctx.buffers.ptr + ctx.frame_index; - memset(buffer.vtx.ptr, 0, Vertex.sizeof * buffer.count); - memset(slug_buffer.vertices.ptr, 0, SlugVertex.sizeof * slug_buffer.quad_offset); + memset(buffer.vtx.ptr, 0, Vertex.sizeof * buffer.count); buffer.count = 0; buffer.vtx_offset = 0; - slug_buffer.quad_offset = 0; } UIKey -FindHoverKey(bool priority)(Ctx* ctx) +FindHoverKey(bool priority)(ref Ctx ctx) { UIKey hovered; @@ -1762,11 +1704,11 @@ FindHoverKey(bool priority)(Ctx* ctx) void EndUI() { - Ctx* ctx = GetCtx(); + ref Ctx ctx = GetCtx(); - if(ctx.dbg) + debug if(ctx.dbg) { - const PAD = 4.0f; + const f32 PAD = 4.0f; static FontSet* fs; if(!fs) { @@ -1780,7 +1722,7 @@ EndUI() Rect debug_rect; - debug_rect.p0.x = ext.x - text_width - PAD*2.0f; + debug_rect.p0.x = ext.x - text_width - PAD*2.0f; debug_rect.p0.y = ext.y - fs.line_height - PAD*2.0f; debug_rect.p1 = ext; @@ -1814,7 +1756,7 @@ SetNil(Args...)(Args args) { static if(is(typeof(Args[i]) == UIItem**)) { - *args[i] = g_UI_NIL; + *args[i] = g_UI_NIL_ITEM; } else { @@ -1824,7 +1766,7 @@ SetNil(Args...)(Args args) } void -Clamp(Ctx* ctx, Vertex* v) +Clamp(ref Ctx ctx, Vertex* v) { v.dst_start = Clamp(v.dst_start, Vec2(0.0), cast(Vec2)ctx.pc.resolution); v.dst_end = Clamp(v.dst_end, Vec2(0.0), cast(Vec2)ctx.pc.resolution); @@ -1853,7 +1795,7 @@ UpdateState(f32* v, bool cond) } void -UpdateState(ISF flags)(Ctx* ctx, UIItem* item) +UpdateState(ISF flags)(ref Ctx ctx, UIItem* item) { static if(flags & ISF.Hot) UpdateState(&item.hot_t, cast(bool)(flags & ISF.SetHot) || Hovered!(true)(item)); static if(flags & ISF.Ready) UpdateState(&item.ready_t, cast(bool)(flags & ISF.SetReady)); @@ -1892,7 +1834,7 @@ AnimateReady(Args...)(f32 ready, Args cols) } void -DrawDropShadow(Ctx* ctx, Rect rect, f32 ready_t = 1.0) +DrawDropShadow(ref Ctx ctx, Rect rect, f32 ready_t = 1.0) { Vec2 size = Vec2(rect.p1.x-rect.p0.x, rect.p1.y-rect.p0.y); @@ -1911,7 +1853,7 @@ DrawDropShadow(Ctx* ctx, Rect rect, f32 ready_t = 1.0) } void -DrawBorder(Ctx* ctx, Rect rect, Style* style, f32 hot_t = 0.0, f32 ready_t = 1.0) +DrawBorder(ref Ctx ctx, Rect rect, Style* style, f32 hot_t = 0.0, f32 ready_t = 1.0) { Vec4 col = style.border_col; AnimateHot(hot_t, style.border_hl_col, &col); @@ -1929,7 +1871,7 @@ DrawBorder(Ctx* ctx, Rect rect, Style* style, f32 hot_t = 0.0, f32 ready_t = 1.0 } void -DrawRect(Ctx* ctx, Rect rect, Style* style, f32 hot_t = 0.0f, f32 ready_t = 1.0f) +DrawRect(ref Ctx ctx, Rect rect, Style* style, f32 hot_t = 0.0f, f32 ready_t = 1.0f) { Vec4 col = style.col; AnimateHot(hot_t, style.hl_col, &col); @@ -1955,19 +1897,11 @@ enum TextAlign } alias TA = TextAlign; void -DrawText(T, U, V)(Ctx* ctx, T text_param, U col_param, V text_size_param, Rect rect, TextAlign text_align, i64 hl_char = -1, f32 ready = 1.0) +DrawText(T, U, V)(ref Ctx ctx, T text_param, U col_param, V text_size_param, Rect rect, TextAlign text_align, i64 hl_char = -1, f32 ready = 1.0) + if(is(V: u32) || is(V == FontSet*)) { - static if(is(V == FontSet*)) - { - FontSet* fs = text_size_param; - } - else if(is(V == u32)) - { - FontSet* fs = GetFontSet(text_size_param); - } - else static assert(false, "invalid input parameter, V must be FontSet* or u32"); - - string text = Str(text_param); + FontSet* fs = GetFontSet(text_size_param); + string text = Str(text_param); DrawUI(ctx, fs.index); @@ -2031,7 +1965,7 @@ InvertCol(Vec4 col) } void -BeginScissor(Ctx* ctx, UIItem* item, bool scissor_x = true, bool scissor_y = true) +BeginScissor(ref Ctx ctx, UIItem* item, bool scissor_x = true, bool scissor_y = true) { DrawUI(ctx); @@ -2050,7 +1984,10 @@ BeginScissor(Ctx* ctx, UIItem* item, bool scissor_x = true, bool scissor_y = tru Vec2 GetExtent() { - version(ENABLE_RENDERER) return Vec2(RendererGetExtent()); else return Vec2(1280, 720); + version(ENABLE_RENDERER) + return Vec2(RendererGetExtent()); + else + return Vec2(1280, 720); } template @@ -2187,10 +2124,10 @@ ZeroKey(T)(T param) if(is(T == UIItem*) || is(T == UIKey)) } UIItem* -NewItem(Ctx* ctx) +NewItem(ref Ctx ctx) { bool allocated; - return GetOrAlloc(&ctx.arena, &ctx.free_items, g_UI_NIL, &allocated); + return GetOrAlloc(&ctx.arena, &ctx.free_items, g_UI_NIL_ITEM, &allocated); } UIItem* @@ -2205,7 +2142,7 @@ MakeItem(UIFlags flags = UIF.None, Args...)(string str, Args args) } } - char[] key = sformat(Alloc!(char)(&g_ctx.str_arenas[g_ctx.f_idx], len), str, args); + char[] key = sformat(Alloc!(char)(&g_ctx.str_arenas[g_ctx.frame_index], len), str, args); return MakeItem(key, flags); } @@ -2213,7 +2150,7 @@ pragma(inline) UIItem* MakeItem(T)(T k, UIFlags flags = UIF.None) if(KeyType!(T)) { UIKey key = mixin(AssignKey!(T, k)); - Ctx* ctx = GetCtx(); + ref Ctx ctx = GetCtx(); UIItem* item; Result!(UIItem*) res = ctx.items[key.hash]; @@ -2309,14 +2246,7 @@ SetHot(UIItem* item, bool hot) f32 CalcTextWidth(T, U)(T text, U param) if((is(T == string) || StringType!T) && (is(U: u32) || is(U == FontSet*) )) { - static if(is(T == string)) - { - string str = text; - } - else - { - string str = Str(text); - } + string str = Str(text); static if(is(U: u32)) { @@ -2349,7 +2279,7 @@ DrawGlyph(Rect rect, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, u32 size, { if(glyph) { - Ctx* ctx = GetCtx(); + ref Ctx ctx = GetCtx(); Vertex* v = null; f32 advance = glyph.advance; @@ -2412,24 +2342,24 @@ DrawGlyph(Rect rect, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, u32 size, } pragma(inline) Vertex* -GetVertex(Ctx* ctx) +GetVertex(ref Ctx ctx) { - assert(ctx.buffers[ctx.f_idx].count < VERTEX_MAX_COUNT); - return ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count++; + assert(ctx.buffers[ctx.frame_index].count < VERTEX_MAX_COUNT); + return ctx.buffers[ctx.frame_index].vtx.ptr + ctx.buffers[ctx.frame_index].count++; } bool Nil(T)(T item) { - static if(is(T == UIItem*)) return item == null || item == g_UI_NIL; + static if(is(T == UIItem*)) return item == null || item == g_UI_NIL_ITEM; else static if(is(T == UIInput*)) return item == null || item == g_UI_NIL_INPUT; else static if(is(T == UIPanel*)) return item == null || item == g_NIL_PANEL; else static assert(false, "Invalid nil type checked"); } bool -Dragged(Ctx* ctx, UIItem* item, IVec2* dragged) +Dragged(ref Ctx ctx, UIItem* item, IVec2* dragged) { if(item.key == ctx.drag_key || (!ctx.drag_key && item.key == ctx.hover_key)) { @@ -2459,7 +2389,7 @@ Dragged(Ctx* ctx, UIItem* item, IVec2* dragged) } bool -Clicked(Ctx* ctx, UIItem* item) +Clicked(ref Ctx ctx, UIItem* item) { bool result; @@ -2550,7 +2480,7 @@ OklabToSRGB(Vec4 v) string EdScratchf(Args...)(string fmt, Args args) { - char[] buf = Alloc!(char)(&g_ctx.str_arenas[g_ctx.f_idx], fmt.length < 16 ? 32 : 128); + char[] buf = Alloc!(char)(&g_ctx.str_arenas[g_ctx.frame_index], fmt.length < 16 ? 32 : 128); return Str(sformat(buf, fmt, args)); }