mymarkdown

My markdown
git clone https://git.grace.moe/mymarkdown
Log | Files | Refs

commit 872212778fa2fe51462122f2bfc0a0463d0b564e
parent a293f5b6aea00d2a3465b0aa4a513953b60f4bfa
Author: gracefu <81774659+gracefuu@users.noreply.github.com>
Date:   Fri, 16 May 2025 16:22:59 +0800

v0

Diffstat:
Mbuild.zig | 36++++++++++++++++++++++++++++++------
Mbuild.zig.zon | 3+++
Msrc/Ast.zig | 7+++++--
Msrc/AstGen.zig | 250++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/AstGen/test.zig | 91++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/main.zig | 10++++++++++
6 files changed, 254 insertions(+), 143 deletions(-)

diff --git a/build.zig b/build.zig @@ -1,33 +1,54 @@ const std = @import("std"); -pub fn build(b: *std.Build) void { +pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); + const llvm = b.option( + bool, + "llvm", + "Force llvm to be used or not (default: compiler default for markdown_cli, false for tests)", + ); + + const enable_tracy = b.option( + bool, + "tracy", + "Enable Tracy profiling", + ) orelse false; + + const tracy = b.dependency("tracy", .{ .enable = enable_tracy }); + const mymarkdown = b.addModule("mymarkdown", .{ .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, }); mymarkdown.addImport("ziggy", b.dependency("ziggy", .{}).module("ziggy")); + mymarkdown.addImport("tracy", tracy.module("tracy")); const mymarkdown_cli = b.addModule("mymarkdown", .{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }); mymarkdown_cli.addImport("mymarkdown", mymarkdown); + mymarkdown_cli.addImport("tracy", tracy.module("tracy")); const mymarkdown_cli_compile = b.addExecutable(.{ .name = "mymarkdown", .root_module = mymarkdown_cli, + .use_llvm = llvm, }); - b.installArtifact(mymarkdown_cli_compile); - const check = b.step("check", "Check if the mymarkdown CLI compiles"); - check.dependOn(&mymarkdown_cli_compile.step); - - setupTestStep(b, target, optimize, mymarkdown, mymarkdown_cli, check); + setupTestStep(b, target, optimize, mymarkdown, mymarkdown_cli, check, llvm); setupRunStep(b, mymarkdown_cli_compile); + try installAndCheck(b, check, mymarkdown_cli_compile); +} + +fn installAndCheck(b: *std.Build, check: *std.Build.Step, exe: *std.Build.Step.Compile) !void { + const copy = try b.allocator.create(std.Build.Step.Compile); + copy.* = exe.*; + check.dependOn(&copy.step); + b.installArtifact(exe); } fn setupTestStep( @@ -37,6 +58,7 @@ fn setupTestStep( mymarkdown: *std.Build.Module, mymarkdown_cli: *std.Build.Module, check: *std.Build.Step, + llvm: ?bool, ) void { const test_step = b.step("test", "Run unit tests"); test_step.dependOn(check); @@ -44,11 +66,13 @@ fn setupTestStep( .root_module = mymarkdown, .target = target, .optimize = optimize, + .use_llvm = llvm orelse true, })).step); test_step.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = mymarkdown_cli, .target = target, .optimize = optimize, + .use_llvm = llvm orelse true, })).step); } diff --git a/build.zig.zon b/build.zig.zon @@ -7,6 +7,9 @@ .ziggy = .{ .path = "../../../manual-software/ziggy", }, + .tracy = .{ + .path = "../../../manual-software/tracy-zig", + }, }, .paths = .{ "build.zig", diff --git a/src/Ast.zig b/src/Ast.zig @@ -1,5 +1,6 @@ const std = @import("std"); const ziggy = @import("ziggy"); +const tracy = @import("tracy"); const utils = @import("utils.zig"); const Allocator = std.mem.Allocator; const Ast = @This(); @@ -197,6 +198,8 @@ pub fn toTagged(self: Ast, gpa: Allocator) !Tagged { } pub fn render(self: Ast, writer: anytype, input: []const u8, start_: ?Node.Idx) !?Node.Idx { + const tracy_frame = tracy.trace(@src()); + defer tracy_frame.end(); const start: Node.Idx = start_ orelse @enumFromInt(0); switch (self.nodes[@intFromEnum(start)].tag) { .document => try writer.writeAll("<body>\n"), @@ -210,7 +213,7 @@ pub fn render(self: Ast, writer: anytype, input: []const u8, start_: ?Node.Idx) try writer.writeByte(' '); try writer.writeAll(input[data.off .. data.off + data.len]); }, - else => unreachable, + else => {}, } var cur_idx: ?Node.Idx = start.next(); switch (self.nodes[@intFromEnum(start)].tag) { @@ -230,7 +233,7 @@ pub fn render(self: Ast, writer: anytype, input: []const u8, start_: ?Node.Idx) .document => try writer.writeAll("</body>\n"), .paragraph => try writer.writeAll("</p>\n"), .text, .space_text => {}, - else => unreachable, + else => {}, } return cur_idx; } diff --git a/src/AstGen.zig b/src/AstGen.zig @@ -1,5 +1,6 @@ const std = @import("std"); const ziggy = @import("ziggy"); +const tracy = @import("tracy"); const utils = @import("utils.zig"); const str = @import("str.zig"); const ArenaAllocator = std.heap.ArenaAllocator; @@ -45,14 +46,22 @@ pub fn deinit(self: *AstGen, gpa: Allocator) void { } pub fn parse(gpa: Allocator, output_gpa: ?Allocator, input: []const u8) error{ InputTooLarge, OutOfMemory }!Ast { + const tracy_frame = tracy.trace(@src()); + defer tracy_frame.end(); + if (input.len > std.math.maxInt(u32)) { return error.InputTooLarge; } - const input_copy = try gpa.dupe(u8, input); - defer gpa.free(input_copy); + const tracy_frame2 = tracy.traceNamed(@src(), "Allocate input copy"); + // const input_copy = try gpa.dupe(u8, input); + // defer gpa.free(input_copy); + var input_copy: std.ArrayListUnmanaged(u8) = .empty; + defer input_copy.deinit(gpa); + try input_copy.ensureTotalCapacityPrecise(gpa, input.len + 1); + tracy_frame2.end(); var ast: AstGen = .{ - .input_base = input_copy.ptr, + .input_base = input_copy.items.ptr, .nodes = .empty, .errors = .empty, .extra = .empty, @@ -63,12 +72,23 @@ pub fn parse(gpa: Allocator, output_gpa: ?Allocator, input: []const u8) error{ I var lines: std.ArrayListUnmanaged([]u8) = .empty; defer lines.deinit(gpa); - var lines_it = std.mem.splitScalar(u8, input_copy, '\n'); + const tracy_frame3 = tracy.traceNamed(@src(), "Split into lines and copy"); + var lines_it = std.mem.splitScalar(u8, input, '\n'); var maybe_line: ?[]u8 = @constCast(lines_it.first()); + var off: usize = 0; while (maybe_line) |line| : (maybe_line = @constCast(lines_it.next())) { - try lines.append(gpa, line); + input_copy.appendSliceAssumeCapacity(line); + input_copy.appendAssumeCapacity('\n'); + if (str.lastIndexOfNone(line, " \t\r\n")) |idx| { + try lines.append(gpa, input_copy.items[off .. off + idx + 1]); + } else { + try lines.append(gpa, input_copy.items[off..off]); + } + off += line.len + 1; } - stripTrailingWhitespace(&lines.items); + tracy_frame3.end(); + + // stripTrailingWhitespace(&lines.items); try ast.parseColumn(gpa, lines.items, root); @@ -90,6 +110,8 @@ pub fn parse(gpa: Allocator, output_gpa: ?Allocator, input: []const u8) error{ I } fn stripTrailingWhitespace(lines: *[][]u8) void { + const tracy_frame = tracy.trace(@src()); + defer tracy_frame.end(); for (lines.*) |*line| { if (str.lastIndexOfNone(line.*, " \t\r\n")) |idx| { line.* = line.*[0 .. idx + 1]; @@ -104,6 +126,8 @@ fn calcOffset(self: *AstGen, c: *u8) u32 { } fn findIndentedColumn(self: *AstGen, gpa: Allocator, lines_: [][]u8, node_idx: Node.Idx) ![][]u8 { + const tracy_frame = tracy.trace(@src()); + defer tracy_frame.end(); var lines = lines_; // empty lines at the start of the inline block are fine, just skip these @@ -144,6 +168,8 @@ fn findIndentedColumn(self: *AstGen, gpa: Allocator, lines_: [][]u8, node_idx: N } fn parseInlineBlock(self: *AstGen, gpa: Allocator, lines_: [][]u8, parent_idx: Node.Idx) !void { + const tracy_frame = tracy.trace(@src()); + defer tracy_frame.end(); var lines = lines_; var empty_line_off: ?u32 = null; @@ -159,12 +185,6 @@ fn parseInlineBlock(self: *AstGen, gpa: Allocator, lines_: [][]u8, parent_idx: N self.getNode(parent_idx).incrementNumChildren(); - // determine indentation - const indentation_idx = str.indexOfNone(lines[0], " \t\r\n") orelse unreachable; - const indentation = lines[0][0..indentation_idx]; - - lines[0] = lines[0][indentation.len..]; - if (lines[0].len <= std.math.maxInt(Ast.StrLen)) { _ = try self.appendNode(gpa, .{ .text = .{ @@ -203,19 +223,6 @@ fn parseInlineBlock(self: *AstGen, gpa: Allocator, lines_: [][]u8, parent_idx: N })); } - const diff_idx = std.mem.indexOfDiff(u8, lines[0], indentation) orelse unreachable; - std.debug.assert(diff_idx != lines[0].len); - if (diff_idx != indentation.len) { - try self.errors.append(gpa, .fromTagged(.{ - .inconsistent_indentation = .{ .idx = self.nextNodeIdx(), .off = self.calcOffset(&lines[0][0]) }, - })); - // Recover by stripping all whitespace on this line - const recover_indentation_idx = std.mem.indexOfNone(u8, lines[0], " \t\r\n") orelse unreachable; - lines[0] = lines[0][recover_indentation_idx..]; - } else { - lines[0] = lines[0][indentation.len..]; - } - self.getNode(parent_idx).incrementNumChildren(); if (lines[0].len <= std.math.maxInt(Ast.StrLen)) { @@ -252,19 +259,26 @@ fn parseInlineBlock(self: *AstGen, gpa: Allocator, lines_: [][]u8, parent_idx: N } fn parseColumn(self: *AstGen, gpa: Allocator, lines_: [][]u8, parent_idx: Node.Idx) !void { + const tracy_frame = tracy.trace(@src()); + defer tracy_frame.end(); var lines = lines_; outer: while (true) { // Skip empty lines // special case: the first line consist of only whitespace // because they may have been introduced via marker replacement - if (lines.len > 0 and str.indexOfNone(lines[0], " \t\r\n") == null) lines = lines[1..]; - while (true) : (lines = lines[1..]) { - if (lines.len == 0) break :outer; - if (lines[0].len != 0) break; + { + const tracy_frame_skip = tracy.traceNamed(@src(), "skip empty lines"); + defer tracy_frame_skip.end(); + if (lines.len > 0 and str.indexOfNone(lines[0], " \t\r\n") == null) lines = lines[1..]; + while (true) : (lines = lines[1..]) { + if (lines.len == 0) break :outer; + if (lines[0].len != 0) break; + } } // Use first character to determine marker const mode, const child = try self.parseBlockStart(gpa, lines[0]); + self.getNode(parent_idx).incrementNumChildren(); switch (mode) { @@ -273,7 +287,9 @@ fn parseColumn(self: *AstGen, gpa: Allocator, lines_: [][]u8, parent_idx: Node.I var num_lines: usize = 1; for (lines[1..]) |line| { if (line.len == 0) break; - if (block_specs[line[0]] != null) break; + if (line[0] == '*') { + if (std.mem.eql(u8, line, "***")) break; + } else if (block_specs[line[0]] != null) break; num_lines += 1; } @@ -322,6 +338,7 @@ const ParseMode = union(enum) { }; const MarkerSpec = union(enum) { + paragraph, exact: []const u8, starts_with: []const u8, starts_with_multi: struct { @@ -357,6 +374,12 @@ const block_specs = blockSpecs(struct { .mode = .no_children, .store_marker_child = .no_store, }, + .{ + .tag = .paragraph, + .marker = .paragraph, + .mode = .paragraph, + .store_marker_child = .no_store, + }, }; pub const @"#": BlockSpec = &.{ .{ @@ -412,83 +435,130 @@ const block_specs = blockSpecs(struct { .store_marker_child = .no_store, }, }; + pub const @";": BlockSpec = &.{ + .{ + .tag = .paragraph, + .marker = .{ .starts_with = ";" }, + .mode = .indented_inline_block, + .store_marker_child = .no_store, + }, + }; }); /// Appends the suitable block node to the ast, /// then returns how parsing should proceed for the children of this block. /// Also returns the idx of the container node created. fn parseBlockStart(self: *AstGen, gpa: Allocator, line: []u8) !struct { ParseMode, Node.Idx } { + const tracy_frame = tracy.trace(@src()); + defer tracy_frame.end(); + if (block_specs[line[0]] == null) { + return .{ + .paragraph, + try self.appendNode(gpa, .{ + .paragraph = .{ + .off = self.calcOffset(&line[0]), + }, + }), + }; + } + + // Inline switch by starting character so codegen proceeds as if each blockspec was converted to code then concatenated. + // Note that we separately handle the null case above, then make the inline case below `unreachable`. + // That makes it so that we don't have 240+ branches that all just do exactly the same thing. + // + // Regardless, the blockspec must be comptime known (the inline for is mandatory) because we do @unionInit with case.tag. switch (line[0]) { inline else => |c| { - const spec_or_null = block_specs[c]; - if (spec_or_null) |spec| { - inline for (spec) |case| { - switch (case.marker) { - .exact, .starts_with => |marker| { - if (std.mem.startsWith(u8, line, marker)) { - const node = if (case.mode == .no_children) try self.appendNode(gpa, @unionInit(Node.Tagged, @tagName(case.tag), @as(Node.Tagged.Leaf, .{ - .off = self.calcOffset(&line[0]), - .len = marker.len, - }))) else try self.appendNode(gpa, @unionInit(Node.Tagged, @tagName(case.tag), @as(Node.Tagged.Container, .{ + if (block_specs[c] == null) unreachable; + inline for (block_specs[c].?) |case| { + switch (case.marker) { + .exact, .starts_with => |marker| { + if (std.mem.startsWith(u8, line, marker)) { + const node = if (case.mode == .no_children) + try self.appendNode(gpa, @unionInit( + Node.Tagged, + @tagName(case.tag), + @as(Node.Tagged.Leaf, .{ + .off = self.calcOffset(&line[0]), + .len = marker.len, + }), + )) + else + try self.appendNode(gpa, @unionInit( + Node.Tagged, + @tagName(case.tag), + @as(Node.Tagged.Container, .{ + .off = self.calcOffset(&line[0]), + .num_children = if (case.store_marker_child == .store) 1 else 0, + }), + )); + @memset(line[0..marker.len], ' '); + if (case.store_marker_child == .store) { + _ = try self.appendNode(gpa, .{ .marker = .{ .off = self.calcOffset(&line[0]), - .num_children = if (case.store_marker_child == .store) 1 else 0, - }))); - @memset(line[0..marker.len], ' '); + .len = case.marker.len, + } }); + } + return .{ case.mode, node }; + } + }, + .starts_with_multi => |marker_spec| { + var marker_len = str.indexOfNotChar(line, marker_spec.marker_char) orelse line.len; + + inline for (marker_spec.extra) |extra| { + if (std.mem.startsWith(u8, line[marker_len..], extra)) { + marker_len += extra.len; + + const node = if (case.mode == .no_children) + try self.appendNode(gpa, @unionInit( + Node.Tagged, + @tagName(case.tag), + @as(Node.Tagged.Leaf, .{ + .off = self.calcOffset(&line[0]), + .len = marker_len, + }), + )) + else + try self.appendNode(gpa, @unionInit( + Node.Tagged, + @tagName(case.tag), + @as(Node.Tagged.Container, .{ + .off = self.calcOffset(&line[0]), + .num_children = if (case.store_marker_child == .store) 1 else 0, + }), + )); + + if (marker_spec.max_chars) |max| + if (marker_len > max) + try self.errors.append(gpa, .fromTagged(.{ + .marker_too_long = .{ + .idx = if (case.store_marker_child == .no_store) + self.lastNodeIdx() + else + self.nextNodeIdx(), + }, + })); + + @memset(line[0..marker_len], ' '); if (case.store_marker_child == .store) { _ = try self.appendNode(gpa, .{ .marker = .{ .off = self.calcOffset(&line[0]), - .len = case.marker.len, + .len = utils.safeIntCast(Ast.StrLen, marker_len), } }); } return .{ case.mode, node }; } - }, - .starts_with_multi => |marker_spec| { - var marker_len = str.indexOfNotChar(line, marker_spec.marker_char) orelse line.len; - - inline for (marker_spec.extra) |extra| { - if (std.mem.startsWith(u8, line[marker_len..], extra)) { - marker_len += extra.len; - - const node = try self.appendNode(gpa, @unionInit(Node.Tagged, @tagName(case.tag), @as(Node.Tagged.Container, .{ - .off = self.calcOffset(&line[0]), - .num_children = if (case.store_marker_child == .store) 1 else 0, - }))); - - if (marker_spec.max_chars) |max| - if (marker_len > max) - try self.errors.append(gpa, .fromTagged(.{ - .marker_too_long = .{ - .idx = if (case.store_marker_child == .no_store) - self.lastNodeIdx() - else - self.nextNodeIdx(), - }, - })); - - @memset(line[0..marker_len], ' '); - if (case.store_marker_child == .store) { - _ = try self.appendNode(gpa, .{ .marker = .{ - .off = self.calcOffset(&line[0]), - .len = utils.safeIntCast(Ast.StrLen, marker_len), - } }); - } - return .{ case.mode, node }; - } - } - }, - } + } + }, + .paragraph => return .{ + .paragraph, + try self.appendNode(gpa, .{ + .paragraph = .{ + .off = self.calcOffset(&line[0]), + }, + }), + }, } - } else { - // Default behaviour is to parse a paragraph until the next newline or block character - return .{ - .paragraph, - try self.appendNode(gpa, .{ - .paragraph = .{ - .off = self.calcOffset(&line[0]), - }, - }), - }; } }, } diff --git a/src/AstGen/test.zig b/src/AstGen/test.zig @@ -238,9 +238,11 @@ test "Thematic break" { try testParse( \\a \\*** - \\b + \\bb \\* - \\c + \\ccc + \\ + \\**bold text** \\ , .{ .nodes = &.{ @@ -248,15 +250,14 @@ test "Thematic break" { .{ .paragraph = .{ .off = 0, .num_children = 1 } }, .{ .text = .{ .off = 0, .len = 1 } }, .{ .thematic_break = .{ .off = 2, .len = 3 } }, - .{ .paragraph = .{ .off = 6, .num_children = 1 } }, - .{ .text = .{ .off = 6, .len = 1 } }, - .{ .paragraph = .{ .off = 8, .num_children = 2 } }, - .{ .text = .{ .off = 8, .len = 1 } }, - .{ .space_text = .{ .off = 10, .len = 1 } }, - }, - .errors = &.{ - .{ .invalid_marker = .{ .idx = @enumFromInt(6), .off = 8 } }, + .{ .paragraph = .{ .off = 6, .num_children = 3 } }, + .{ .text = .{ .off = 6, .len = 2 } }, + .{ .space_text = .{ .off = 9, .len = 1 } }, + .{ .space_text = .{ .off = 11, .len = 3 } }, + .{ .paragraph = .{ .off = 16, .num_children = 1 } }, + .{ .text = .{ .off = 16, .len = 13 } }, }, + .errors = &.{}, .extra = &.{}, }); } @@ -307,40 +308,40 @@ test "Empty line in heading" { }); } -// test "Super long line" { -// const input = try std.testing.allocator.create([(1 << 24) * 4]u8); -// defer std.testing.allocator.destroy(input); -// @memset(input, 'a'); -// input[1] = '\n'; -// try testParse(input, .{ -// .nodes = &.{ -// .{ .document = .{ .num_children = 1 } }, -// .{ .paragraph = .{ .off = 0, .num_children = 2 } }, -// .{ .text = .{ .off = 0, .len = 1 } }, -// .{ .space_text = .{ .off = 2, .len = 16777215 } }, -// .{ .text = .{ .off = 2, .len = 16777215 } }, -// .{ .text = .{ .off = 2, .len = 16777215 } }, -// .{ .text = .{ .off = 2, .len = 16777215 } }, -// .{ .text = .{ .off = 2, .len = 2 } }, -// }, -// .errors = &.{}, -// .extra = &.{}, -// }); -// } +test "Super long line" { + const input = try std.testing.allocator.create([(1 << 24) * 4]u8); + defer std.testing.allocator.destroy(input); + @memset(input, 'a'); + input[1] = '\n'; + try testParse(input, .{ + .nodes = &.{ + .{ .document = .{ .num_children = 1 } }, + .{ .paragraph = .{ .off = 0, .num_children = 2 } }, + .{ .text = .{ .off = 0, .len = 1 } }, + .{ .space_text = .{ .off = 2, .len = 16777215 } }, + .{ .text = .{ .off = 2, .len = 16777215 } }, + .{ .text = .{ .off = 2, .len = 16777215 } }, + .{ .text = .{ .off = 2, .len = 16777215 } }, + .{ .text = .{ .off = 2, .len = 2 } }, + }, + .errors = &.{}, + .extra = &.{}, + }); +} -// test "Many short lines" { -// const input = try std.testing.allocator.create([(1 << 23) - 2][2]u8); -// defer std.testing.allocator.destroy(input); -// @memset(input, [2]u8{ 'a', '\n' }); +test "Many short lines" { + const input = try std.testing.allocator.create([(1 << 23) - 2][2]u8); + defer std.testing.allocator.destroy(input); + @memset(input, [2]u8{ 'a', '\n' }); -// var arena: ArenaAllocator = .init(std.testing.allocator); -// defer arena.deinit(); -// const ast = try parse(std.testing.allocator, arena.allocator(), @as([*]u8, @ptrCast(input))[0 .. (1 << 23) * 2 - 4]); -// try std.testing.expectEqual(1 << 23, ast.nodes.len); -// try std.testing.expectEqual(@as(Ast.Node.Tagged, .{ .document = .{ .num_children = 1 } }), ast.nodes[0].toTagged()); -// try std.testing.expectEqual(@as(Ast.Node.Tagged, .{ .paragraph = .{ .off = 0, .num_children = (1 << 23) - 2 } }), ast.nodes[1].toTagged()); -// try std.testing.expectEqual(@as(Ast.Node.Tagged, .{ .text = .{ .off = 0, .len = 1 } }), ast.nodes[2].toTagged()); -// for (1..(1 << 23) - 2) |i| { -// try std.testing.expectEqual(@as(Ast.Node.Tagged, .{ .space_text = .{ .off = @intCast(i * 2), .len = 1 } }), ast.nodes[i + 2].toTagged()); -// } -// } + var arena: ArenaAllocator = .init(std.testing.allocator); + defer arena.deinit(); + const ast = try parse(std.testing.allocator, arena.allocator(), @as([*]u8, @ptrCast(input))[0 .. (1 << 23) * 2 - 4]); + try std.testing.expectEqual(1 << 23, ast.nodes.len); + try std.testing.expectEqual(@as(Ast.Node.Tagged, .{ .document = .{ .num_children = 1 } }), ast.nodes[0].toTagged()); + try std.testing.expectEqual(@as(Ast.Node.Tagged, .{ .paragraph = .{ .off = 0, .num_children = (1 << 23) - 2 } }), ast.nodes[1].toTagged()); + try std.testing.expectEqual(@as(Ast.Node.Tagged, .{ .text = .{ .off = 0, .len = 1 } }), ast.nodes[2].toTagged()); + for (1..(1 << 23) - 2) |i| { + try std.testing.expectEqual(@as(Ast.Node.Tagged, .{ .space_text = .{ .off = @intCast(i * 2), .len = 1 } }), ast.nodes[i + 2].toTagged()); + } +} diff --git a/src/main.zig b/src/main.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const tracy = @import("tracy"); const mymarkdown = @import("mymarkdown"); const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator(.{}); @@ -11,12 +12,21 @@ pub fn main() !void { const input = try std.io.getStdIn().readToEndAlloc(arena.allocator(), std.math.maxInt(u32)); + const parse_tracy_frame = tracy.namedFrame("parse"); const ast = try mymarkdown.parse(gpa.allocator(), arena.allocator(), input); + parse_tracy_frame.end(); // std.mem.doNotOptimizeAway(ast); var bw = std.io.bufferedWriter(std.io.getStdOut().writer()); const stdout = bw.writer(); // try stdout.print("{}\n", .{ast}); + const render_tracy_frame = tracy.namedFrame("render"); _ = try ast.render(stdout, input, null); + render_tracy_frame.end(); try bw.flush(); + + if (tracy.enable) { + tracy.frameMarkNamed("waiting for tracy"); + std.Thread.sleep(100 * std.time.ns_per_ms); + } }