From e053ba532f1e58bb54f286b950e3be7166ba3dcd Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 15 Apr 2026 14:41:33 +0200 Subject: feat(lexer): supports link and image --- src/lexer/lexed.zig | 2 ++ src/lexer/lexer.zig | 26 ++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'src/lexer') diff --git a/src/lexer/lexed.zig b/src/lexer/lexed.zig index a572c2a..59b6e31 100644 --- a/src/lexer/lexed.zig +++ b/src/lexer/lexed.zig @@ -13,6 +13,8 @@ pub const Kind = enum { bold, italic, ref, + list_ordored, + list_unordored, }; pub const Lexed = struct { diff --git a/src/lexer/lexer.zig b/src/lexer/lexer.zig index a29384e..b76cd50 100644 --- a/src/lexer/lexer.zig +++ b/src/lexer/lexer.zig @@ -30,14 +30,14 @@ pub const Lexer = struct { self.force_lit = true; current_kind = .literal; } else { - current_kind = self.getCurrentKind(rune, acc.items); + current_kind = self.getCurrentKind(current_kind, rune, acc.items); self.force_lit = false; try acc.appendSlice(alloc, rune); } // conds here to avoid creating complex condition in while const next_rune = self.iter.peek(1); if (next_rune.len > 0) { - if (self.getCurrentKind(next_rune, acc.items) != current_kind.?) { + if (self.getCurrentKind(current_kind, next_rune, acc.items) != current_kind.?) { if (!requiresSpace(current_kind.?)) break; if (std.mem.eql(u8, next_rune, " ")) { // consume next space @@ -55,13 +55,15 @@ pub const Lexer = struct { return lexed.Lexed.init(alloc, kind, acc); } - fn getCurrentKind(self: *Self, rune: []const u8, acc: []const u8) lexed.Kind { + fn getCurrentKind(self: *Self, before: ?lexed.Kind, rune: []const u8, acc: []const u8) lexed.Kind { if (self.force_lit) return .literal; if (std.mem.eql(u8, rune, ">")) return .quote; if (std.mem.eql(u8, rune, "\n")) return .delimiter; + if (std.mem.eql(u8, rune, "!")) return .image; if (is('#', 6, rune, acc)) return .title; if (is('`', 3, rune, acc)) return .code; if (is('$', 3, rune, acc)) return .math; + if (isIn(links, before, .link, rune, acc)) return .link; return .literal; } }; @@ -72,6 +74,21 @@ fn is(v: u8, maxLen: usize, rune: []const u8, acc: []const u8) bool { return std.mem.eql(u8, rune, &[_]u8{v}); } +const links = &[_][]const u8{ "[", "](", ")" }; + +fn isIn(ops: []const []const u8, before: ?lexed.Kind, now: lexed.Kind, rune: []const u8, p: []const u8) bool { + var acc = p; + if (before) |b| { + if (now != b) acc = &[_]u8{}; + } + for (ops) |op| { + const ln = acc.len + rune.len; + if (op.len >= ln and std.mem.eql(u8, acc, op[0..acc.len]) and std.mem.eql(u8, rune, op[acc.len..ln])) + return true; + } + return false; +} + fn requiresSpace(k: lexed.Kind) bool { return switch (k) { .title => true, @@ -98,7 +115,8 @@ test "lexer common" { var l = try Lexer.init("# hello world :)"); try doTest(alloc, &l, .title, "#"); - try doTest(alloc, &l, .literal, "hello world :)"); + try doTest(alloc, &l, .literal, "hello world :"); + try doTest(alloc, &l, .link, ")"); try expect(try l.next(alloc) == null); } -- cgit v1.2.3