starting work on syntax highlighting

This commit is contained in:
Matthew 2025-08-19 06:09:15 +10:00
parent 39aa8af6e2
commit 3b67ffd066
2 changed files with 319 additions and 15 deletions

View File

@ -2,9 +2,11 @@ import aliases;
import math; import math;
import alloc; import alloc;
import util; import util;
import core.stdc.stdio : EOF;
struct FlatBuffer struct FlatBuffer
{ {
Tokenizer tk;
Arena arena; Arena arena;
u8[] data; u8[] data;
u64 length; u64 length;
@ -42,12 +44,18 @@ CreateFlatBuffer(u8[] data)
} }
} }
return FlatBuffer( FlatBuffer fb = {
arena: CreateArena(MB(1)), arena: CreateArena(MB(1)),
data: buf, data: buf,
length: cast(u64)data.length, length: cast(u64)data.length,
line_count: line_count, line_count: line_count,
); };
fb.tk = CreateTokenizer(&fb);
Highlight(&fb);
return fb;
} }
LineBuffers LineBuffers
@ -218,6 +226,261 @@ Replace(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos, u64 delete_length)
Insert(buffer, insert, insert.length, pos); Insert(buffer, insert, insert.length, pos);
} }
enum TokenType : u8
{
None = 0,
Keyword,
Import,
ImportTarget,
Type,
Identifier,
Op,
Bracket,
Function,
Macro,
Comment,
String,
Number,
Char,
}
alias TT = TokenType;
struct Tokenizer
{
TokenType[] buffer;
u64 pos;
u64 token_end;
u64 length;
TokenType prev_token;
TokenType current_token;
}
Tokenizer
CreateTokenizer(FlatBuffer* buffer)
{
Tokenizer tokenizer = {
buffer: MAllocArray!(TT)(buffer.data.length),
};
return tokenizer;
}
bool
Advance(FlatBuffer* fb)
{
Tokenizer* tk = &fb.tk;
tk.pos = tk.token_end;
u8[] buf = fb.data;
bool result = false;
bool started = false;
for(u64 i = tk.pos; i < buf.length; i += 1)
{
if (!started && buf.ptr[i] != ' ' && buf.ptr[i] != '\t' && buf.ptr[i] != '\n' && buf.ptr[i] != EOF)
{
tk.pos = i;
started = true;
continue;
}
if (started && (buf.ptr[i] == ' ' || buf.ptr[i] == '\t' || buf.ptr[i] == '\n' || buf.ptr[i] == EOF))
{
result = true;
tk.token_end = i;
break;
}
}
return result;
}
static string
StrToU8(string str)
{
string res = "[";
foreach(ch; str)
{
res ~= "'" ~ ch ~ "',";
}
res ~= "]";
return res;
}
void
Highlight(FlatBuffer* fb)
{
const const(u8[])[]['z'-95] keywords = [
'_'-95: [
mixin(StrToU8("__FILE__")),
mixin(StrToU8("__FILE_FULL_PATH__")),
mixin(StrToU8("__FUNCTION__")),
mixin(StrToU8("__LINE__")),
mixin(StrToU8("__MODULE__")),
mixin(StrToU8("__PRETTY_FUNCTION__")),
mixin(StrToU8("__gshared")),
mixin(StrToU8("__parameters")),
mixin(StrToU8("__rvalue")),
mixin(StrToU8("__traits")),
mixin(StrToU8("__vector")),
],
'a'-95: [
mixin(StrToU8("abstract")),
mixin(StrToU8("alias")),
mixin(StrToU8("align")),
mixin(StrToU8("asm")),
mixin(StrToU8("assert")),
mixin(StrToU8("auto")),
],
'b'-95: [
mixin(StrToU8("bool")),
mixin(StrToU8("break")),
mixin(StrToU8("byte")),
],
'c'-95: [
mixin(StrToU8("case")),
mixin(StrToU8("cast")),
mixin(StrToU8("catch")),
mixin(StrToU8("char")),
mixin(StrToU8("class")),
mixin(StrToU8("const")),
mixin(StrToU8("continue")),
],
'd'-95: [
mixin(StrToU8("dchar")),
mixin(StrToU8("debug")),
mixin(StrToU8("default")),
mixin(StrToU8("delegate")),
mixin(StrToU8("deprecated")),
mixin(StrToU8("do")),
mixin(StrToU8("double")),
],
'e'-95: [
mixin(StrToU8("else")),
mixin(StrToU8("enum")),
mixin(StrToU8("export")),
mixin(StrToU8("extern")),
],
'f'-95: [
mixin(StrToU8("false")),
mixin(StrToU8("final")),
mixin(StrToU8("finally")),
mixin(StrToU8("float")),
mixin(StrToU8("for")),
mixin(StrToU8("foreach")),
mixin(StrToU8("foreach_reverse")),
mixin(StrToU8("function")),
],
'g'-95: [
mixin(StrToU8("goto")),
],
'i'-95: [
mixin(StrToU8("if")),
mixin(StrToU8("immutable")),
mixin(StrToU8("import")),
mixin(StrToU8("in")),
mixin(StrToU8("inout")),
mixin(StrToU8("int")),
mixin(StrToU8("interface")),
mixin(StrToU8("invariant")),
mixin(StrToU8("is")),
],
'l'-95: [
mixin(StrToU8("lazy")),
mixin(StrToU8("long")),
],
'm'-95: [
mixin(StrToU8("mixin")),
mixin(StrToU8("module")),
],
'n'-95: [
mixin(StrToU8("new")),
mixin(StrToU8("nothrow")),
mixin(StrToU8("null")),
],
'o'-95: [
mixin(StrToU8("out")),
mixin(StrToU8("override")),
],
'p'-95: [
mixin(StrToU8("package")),
mixin(StrToU8("pragma")),
mixin(StrToU8("private")),
mixin(StrToU8("protected")),
mixin(StrToU8("public")),
mixin(StrToU8("pure")),
],
'r'-95: [
mixin(StrToU8("real")),
mixin(StrToU8("ref")),
mixin(StrToU8("return")),
],
's'-95: [
mixin(StrToU8("scope")),
mixin(StrToU8("shared")),
mixin(StrToU8("short")),
mixin(StrToU8("static")),
mixin(StrToU8("struct")),
mixin(StrToU8("super")),
mixin(StrToU8("switch")),
mixin(StrToU8("synchronized")),
],
't'-95: [
mixin(StrToU8("template")),
mixin(StrToU8("this")),
mixin(StrToU8("throw")),
mixin(StrToU8("true")),
mixin(StrToU8("try")),
mixin(StrToU8("typeid")),
mixin(StrToU8("typeof")),
],
'u'-95: [
mixin(StrToU8("ubyte")),
mixin(StrToU8("uint")),
mixin(StrToU8("ulong")),
mixin(StrToU8("union")),
mixin(StrToU8("unittest")),
mixin(StrToU8("ushort")),
],
'v'-95: [
mixin(StrToU8("version")),
mixin(StrToU8("void")),
],
'w'-95: [
mixin(StrToU8("wchar")),
mixin(StrToU8("while")),
mixin(StrToU8("with")),
],
];
Tokenizer* tk = &fb.tk;
TokenStream:
while (Advance(fb))
{
u8[] token = fb.data[tk.pos .. tk.token_end];
if ((token[0] >= 'a' && token[0] <= 'z') || (token[0] >= 'A' && token[0] <= 'Z') || token[0] == '_')
{
u8 index = cast(u8)(token[0]-cast(u8)95);
if (index > 0 && index < keywords.length)
{
// TODO: look at simd string comparison
const(u8[])[] key_table = keywords[index];
foreach(key; key_table)
{
if (token == key)
{
tk.buffer[tk.pos .. tk.token_end] = TT.Keyword;
continue TokenStream;
}
}
}
}
}
}
unittest unittest
{ {
import std.stdio; import std.stdio;

View File

@ -32,6 +32,7 @@ struct Editor
u32 ui_count; u32 ui_count;
FlatBuffer[] buffers; FlatBuffer[] buffers;
Tokenizer[] tokenizers;
u8[][] buffer_names; u8[][] buffer_names;
u32 buffer_count; u32 buffer_count;
FlatBuffer* active_buffer; FlatBuffer* active_buffer;
@ -65,11 +66,7 @@ Cycle(Editor* ed)
f32 pos = 0.0; f32 pos = 0.0;
f32 h = ed.atlas_buf.atlas.size; f32 h = ed.atlas_buf.atlas.size;
foreach(i, line; ed.linebufs.lines) DrawBuffer(ed, 0.0, 0.0, h, ed.active_buffer);
{
DrawText(ed, 0.0, pos, h, line[0 .. ed.linebufs.lengths[i]]);
pos += h;
}
BeginFrame(&ed.rd); BeginFrame(&ed.rd);
@ -159,10 +156,10 @@ CreateEditor(PlatformWindow* window, u8[] buffer_data, u8[] buffer_name)
editor.buffer_count += 1; editor.buffer_count += 1;
editor.active_buffer = &editor.buffers[0]; editor.active_buffer = &editor.buffers[0];
GetLines(editor.active_buffer, &editor.linebufs, 0, editor.active_buffer.line_count);
} }
editor.active_buffer = &editor.buffers[0];
DescLayoutBinding[2] layout_bindings = [ DescLayoutBinding[2] layout_bindings = [
{ binding: 0, descriptorType: DT.Image, descriptorCount: 1, stageFlags: SS.All }, { binding: 0, descriptorType: DT.Image, descriptorCount: 1, stageFlags: SS.All },
{ binding: 1, descriptorType: DT.Storage, descriptorCount: 1, stageFlags: SS.All }, { binding: 1, descriptorType: DT.Storage, descriptorCount: 1, stageFlags: SS.All },
@ -212,6 +209,54 @@ DrawText(Editor* ed, f32 x, f32 y, f32 px, string str)
DrawText(ed, x, y, px, str_buf); DrawText(ed, x, y, px, str_buf);
} }
void
DrawBuffer(Editor* ed, f32 x, f32 y, f32 px, FlatBuffer* fb)
{
const Vec4[TT.max] cols = [
TT.None: Vec4(1.0, 1.0, 1.0, 1.0),
TT.Keyword: Vec4(1.0, 0.0, 0.0, 1.0),
];
u32 tab_count = 2;
f32 x_pos = x;
f32 y_pos = y;
f32 scale = px / ed.atlas_buf.atlas.size;
foreach(i; 0 .. fb.length)
{
u8 ch = fb.data[i];
foreach(glyph; ed.atlas_buf.atlas.glyphs)
{
if (ch == glyph.ch)
{
if (ch == '\t')
{
Glyph g = glyph;
g.atlas_left = g.atlas_right = 0.0;
foreach(j; 0 .. tab_count)
{
DrawGlyph(ed, &g, scale, &x_pos, y_pos);
}
}
else if (ch == '\n')
{
Glyph g = glyph;
g.atlas_left = g.atlas_right = 0.0;
DrawGlyph(ed, &g, scale, &x_pos, y_pos);
y_pos += px;
x_pos = 0.0;
}
else
{
DrawGlyph(ed, &glyph, scale, &x_pos, y_pos, cols[fb.tk.buffer[i]]);
break;
}
}
}
}
}
void void
DrawText(Editor* ed, f32 x, f32 y, f32 px, u8[] str) DrawText(Editor* ed, f32 x, f32 y, f32 px, u8[] str)
{ {
@ -251,7 +296,7 @@ DrawText(Editor* ed, f32 x, f32 y, f32 px, u8[] str)
} }
pragma(inline): void pragma(inline): void
DrawGlyph(Editor* ed, Glyph* glyph, f32 scale, f32* x_pos, f32 y) DrawGlyph(Editor* ed, Glyph* glyph, f32 scale, f32* x_pos, f32 y, Vec4 col = Vec4(1.0))
{ {
if (glyph.atlas_left != glyph.atlas_right) if (glyph.atlas_left != glyph.atlas_right)
{ {
@ -273,11 +318,7 @@ DrawGlyph(Editor* ed, Glyph* glyph, f32 scale, f32* x_pos, f32 y)
v.src_end.x = glyph.atlas_right; v.src_end.x = glyph.atlas_right;
v.src_end.y = glyph.atlas_bottom; v.src_end.y = glyph.atlas_bottom;
v.col = Vec4(1.0, 1.0, 1.0, 1.0); v.col = col;
if (glyph.atlas_left == glyph.atlas_right)
{
v.col.r = v.col.g = v.col.b = 0.0;
}
AddUIIndices(ed); AddUIIndices(ed);
} }