Unknown state [2025-08-04]

This commit is contained in:
2025-08-04 22:28:49 -04:00
parent 6e4b76a6d9
commit 3b252de1ca
27 changed files with 24509 additions and 0 deletions

156
md/src/main.zig Normal file
View File

@@ -0,0 +1,156 @@
//! Markdown Parser.
//!
//! Leaf blocks
//! Thematic Breaks
//! ATX headings
//! Setext headings
//! Indented code blocks
//! Fenced code blocks
//! HTML blocks
//! Link reference definitions
//! Paragraphs
//! Blank lines
//!
//! Container blocks
//! Block Quotes
//! List Items
//! Lists
//!
//! Inlines
//! Code spans
//! emph, strong
//! Links
//! Images
//! Autolinks
//! Raw HTML
//! Hard line breaks
//! Soft line breaks
//! Text
const BlockType = enum {
// Leaf Blocks
Break,
Heading,
Code,
HTML,
LinkDefinition,
Paragraph,
Blank,
// Container Blocks
Quote,
List,
// ListItem,
};
const Block = struct {
type: BlockType,
text: []const u8,
depth: u8 = 0,
};
const std = @import("std");
const md = @import("md");
pub fn render(src: []const u8, alloc: std.mem.Allocator) !void {
var it = std.mem.splitScalar(u8, src, '\n');
var blocks = std.ArrayList(Block).init(alloc);
defer blocks.deinit();
line_search: while (it.next()) |line| {
// early check for blank line
for (line) |ch| {
if (!std.ascii.isWhitespace(ch)) break;
} else {
try blocks.append(.{ .type = .Blank, .text = line });
continue :line_search;
}
// figure out indentation
var depth: u8 = 0;
var start: u8 = 0;
for (line) |ch| {
switch (ch) {
' ' => depth += 1,
'\t' => depth += 4,
else => break,
}
start += 1;
}
// at this point, start will not be line.len because we checked
// it is not blank
if (depth >= 4) {
// todo something special has to happen. lists and code blocks.
}
// test thematic break
switch (line[start]) {
'*', '-', '_' => |kind| {
var count: u8 = 0;
for (line[start..]) |ch| {
if (ch == kind) {
count += 1;
continue;
}
if (std.ascii.isWhitespace(ch)) continue;
break;
} else {
if (count >= 3) {
try blocks.append(.{ .type = .Break, .text = line });
continue :line_search;
}
}
},
else => {},
}
}
for (blocks.items) |block| {
std.debug.print("{any}\n", .{block});
}
// TODO split into paragraphs, list elements
//
// const State = enum {
// Block,
// };
// mach: switch (State.Block) {
// .Block => {
// continue :mach .Block;
// },
// }
// while (it.next()) |line| {}
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
const args = try std.process.argsAlloc(alloc);
defer std.process.argsFree(alloc, args);
const buf = try alloc.alloc(u8, 1 << 20);
defer alloc.free(buf);
for (args[1..]) |path| {
const file = try std.fs.cwd().openFile(path, .{ .mode = .read_only });
defer file.close();
const stat = try file.stat();
if (stat.size > buf.len)
return error.FileTooBig;
const n = try file.readAll(buf);
const content = buf[0..n];
try render(content, alloc);
}
}

54
md/src/root.zig Normal file
View File

@@ -0,0 +1,54 @@
const std = @import("std");
pub fn parse(src: []const u8, alloc: std.mem.Allocator) ![][]const u8 {
var it = std.mem.splitScalar(u8, src, '\n');
var lines = std.ArrayList([]const u8).init(alloc);
while (it.next()) |line| {
try lines.append(line);
}
return try lines.toOwnedSlice();
}
// pub fn render(src: []const u8, alloc: std.mem.Allocator) ![]const u8 {
// // std.mem.tokenizeScalar(comptime T: type, buffer: []const T, delimiter: T)
// }
test "split-lines" {
const alloc = std.testing.allocator;
const src =
\\hello world!
\\
\\this is some content!
\\
;
const lines = try parse(src, alloc);
defer alloc.free(lines);
const expect: []const []const u8 = &.{
"hello world!",
"",
"this is some content!",
"",
};
try std.testing.expectEqualDeep(
expect,
lines,
);
}
test "2.2 Tabs" {
// const alloc = std.testing.allocator;
//
// const md = "\tfoo\tbaz\t\tbim";
// const expect = "<pre><code>foo\tbaz\t\tbim</code></pre>";
// const actual = try render(md, alloc);
// defer alloc.free(actual);
// std.testing.expectEqualStrings(expect, actual);
}