From 86d299b313cbf07b867cc1a1eb51227388230354 Mon Sep 17 00:00:00 2001 From: Tristan Pemble Date: Mon, 13 Apr 2026 21:23:48 -0700 Subject: [PATCH 1/5] update to Zig 0.16.0 --- .gitignore | 1 + CLAUDE.md | 2 +- build.zig | 10 +-- build.zig.zon | 9 +-- mise.toml | 4 +- src/Document.zig | 4 +- src/Node.zig | 2 +- src/formatters/markdown.zig | 58 +++++++-------- src/main.zig | 142 +++++++++++++++--------------------- src/parser.zig | 2 +- src/root.zig | 2 +- src/tokenizer.zig | 4 +- 12 files changed, 102 insertions(+), 138 deletions(-) diff --git a/.gitignore b/.gitignore index 8bc6d2a..6a951fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ zig-out/ +zig-pkg/ .zig-cache/ .claude/settings.local.json .DS_store diff --git a/CLAUDE.md b/CLAUDE.md index 6bd1b26..0366ff0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -92,4 +92,4 @@ Tests are embedded in each module using Zig's built-in testing framework. Run `z ## Dependencies - Uses `cli` dependency for command-line argument parsing in the executable -- Requires Zig 0.15.1 (specified in `mise.toml`) \ No newline at end of file +- Requires Zig 0.16.0 (specified in `mise.toml`) diff --git a/build.zig b/build.zig index 11e78f3..c93d5a4 100644 --- a/build.zig +++ b/build.zig @@ -6,6 +6,8 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, + .link_libc = true, + .link_libcpp = true, }); const lib = b.addLibrary(.{ @@ -13,8 +15,6 @@ pub fn build(b: *std.Build) void { .name = "bbcodez", .root_module = lib_mod, }); - lib.linkLibC(); - lib.linkLibCpp(); var install = b.addInstallArtifact(lib, .{}); @@ -34,16 +34,12 @@ pub fn build(b: *std.Build) void { docs_step.dependOn(&install_docs.step); install.step.dependOn(docs_step); - const cli_dep = b.dependency("cli", .{}); - const cli_mod = cli_dep.module("cli"); - const exe_mod = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }); - exe_mod.addImport("cli", cli_mod); - exe_mod.addImport("lib", lib_mod); + exe_mod.addImport("bbcodez", lib_mod); const exe = b.addExecutable(.{ .name = "bbcodez", diff --git a/build.zig.zon b/build.zig.zon index 1d883bd..060b971 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,13 +2,8 @@ .name = .bbcodez, .version = "0.0.1-dev", .fingerprint = 0x9e2aa21706ce5a62, // Changing this has security and trust implications. - .minimum_zig_version = "0.15.1", - .dependencies = .{ - .cli = .{ - .url = "git+https://github.com/sam701/zig-cli#f9a516ddc9771ddd2c8c46a280a9ab6cab8261f2", - .hash = "cli-0.10.0-2eKe_5kEAQBeHqKxUHNTGnETzu81rqKWwT1WPt1jXBt0", - }, - }, + .minimum_zig_version = "0.16.0", + .dependencies = .{}, .paths = .{ "build.zig", "build.zig.zon", diff --git a/mise.toml b/mise.toml index a42cce9..f00482d 100644 --- a/mise.toml +++ b/mise.toml @@ -1,5 +1,5 @@ [tools] -zig = "0.15.1" -zls = "0.15.0" +zig = "0.16.0" +zls = "0.16.0" pre-commit = "latest" "ubi:DonIsaac/zlint" = "latest" diff --git a/src/Document.zig b/src/Document.zig index 9f529c3..a049712 100644 --- a/src/Document.zig +++ b/src/Document.zig @@ -74,7 +74,7 @@ pub const Options = struct { /// /// Args: /// bbcode: BBCode string to parse -pub fn load(allocator: Allocator, reader: *std.io.Reader, options: Options) !Document { +pub fn load(allocator: Allocator, reader: *std.Io.Reader, options: Options) !Document { var tokenizer_options: tokenizer.Options = options.tokenizer_options orelse .{}; var parser_options: parser.Options = options.parser_options orelse .{}; @@ -105,7 +105,7 @@ pub fn load(allocator: Allocator, reader: *std.io.Reader, options: Options) !Doc /// Returns: A new Document containing the parsed tree structure /// Errors: OutOfMemory or any parsing errors from `load()` pub fn loadFromBuffer(allocator: Allocator, bbcode: []const u8, options: Options) !Document { - var fixed_reader = std.io.Reader.fixed(bbcode); + var fixed_reader = std.Io.Reader.fixed(bbcode); return try load(allocator, &fixed_reader, options); } diff --git a/src/Node.zig b/src/Node.zig index 1312176..493c548 100644 --- a/src/Node.zig +++ b/src/Node.zig @@ -238,7 +238,7 @@ pub fn print(self: Node, writer: anytype, depth: usize) !void { pub const NodePrinter = struct { const indent_size = 4; - writer: *std.io.Writer, + writer: *std.Io.Writer, depth: usize = 0, indent: bool = true, diff --git a/src/formatters/markdown.zig b/src/formatters/markdown.zig index 630678a..a6f787f 100644 --- a/src/formatters/markdown.zig +++ b/src/formatters/markdown.zig @@ -74,7 +74,7 @@ pub const WriteContext = struct { /// The document being rendered document: Document, /// Output writer for the generated Markdown - writer: *std.io.Writer, + writer: *std.Io.Writer, /// Optional custom element handler function write_element_fn: ?WriteElementFunction = null, /// Optional user data for custom handlers @@ -151,7 +151,7 @@ const element_map = std.StaticStringMap(MarkdownElement).initComptime(&.{ /// writer: Output writer for the Markdown text /// options: Rendering configuration options /// Errors: Any writer errors or allocation failures during rendering -pub fn renderDocument(allocator: Allocator, doc: Document, writer: *std.io.Writer, options: Options) !void { +pub fn renderDocument(allocator: Allocator, doc: Document, writer: *std.Io.Writer, options: Options) !void { var ctx: WriteContext = .{ .allocator = allocator, .document = doc, @@ -406,11 +406,11 @@ test render { var document = try Document.loadFromBuffer(testing.allocator, bbcode_document, .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/basic.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/basic.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); @@ -423,11 +423,11 @@ test "single lines" { var document = try Document.loadFromBuffer(testing.allocator, "[b]hello, world![/b]", .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/single_line_bold.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/single_line_bold.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); try writer.flush(); @@ -437,11 +437,11 @@ test "single lines" { var document = try Document.loadFromBuffer(testing.allocator, "[email=user@example.com]Email[/email]", .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/single_line_email.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/single_line_email.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); try writer.flush(); @@ -451,11 +451,11 @@ test "single lines" { var document = try Document.loadFromBuffer(testing.allocator, "[url=https://example.com]Link[/url]", .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/single_line_url.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/single_line_url.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); try writer.flush(); @@ -465,11 +465,11 @@ test "single lines" { var document = try Document.loadFromBuffer(testing.allocator, "[code]code[/code]", .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/single_line_code.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/single_line_code.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); try writer.flush(); @@ -479,11 +479,11 @@ test "single lines" { var document = try Document.loadFromBuffer(testing.allocator, "[i]italic[/i]", .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/single_line_italic.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/single_line_italic.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); try writer.flush(); @@ -493,11 +493,11 @@ test "single lines" { var document = try Document.loadFromBuffer(testing.allocator, "[b]Hello[/b], world! [i]italic[/i] [u]underline[/u] [s]strike[/s]", .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/single_line_mixed.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/single_line_mixed.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); try writer.flush(); @@ -509,11 +509,11 @@ test "lists" { var document = try Document.loadFromBuffer(testing.allocator, "[list][*]item 1[*]item 2[/list]", .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/single_line_list.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/single_line_list.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); try writer.flush(); @@ -523,11 +523,11 @@ test "lists" { var document = try Document.loadFromBuffer(testing.allocator, "[list]\n[*] item 1\n[*] item 2\n[/list]", .{}); defer document.deinit(); - var file = try std.fs.cwd().createFile("snapshots/md/multi_line_list.md", .{}); - defer file.close(); + var file = try std.Io.Dir.cwd().createFile(testing.io, "snapshots/md/multi_line_list.md", .{}); + defer file.close(testing.io); var buf: [1024]u8 = undefined; - var file_writer = file.writer(&buf); + var file_writer = file.writer(testing.io, &buf); var writer = &file_writer.interface; try renderDocument(testing.allocator, document, writer, .{}); try writer.flush(); diff --git a/src/main.zig b/src/main.zig index a4818ab..b2074ad 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2,97 +2,60 @@ pub const std_options: Options = .{ .log_level = Level.err, }; -var config = struct { - input: ?[]const u8 = null, - output: ?[]const u8 = null, - convert_tab_size: ?[]const u8 = null, -}{}; - -const StreamSource = enum { - file, - stdin, -}; - -const StreamDestination = enum { - file, - stdout, -}; - -pub fn main() !void { - var r = try cli.AppRunner.init(std.heap.page_allocator); - - const app = cli.App{ - .command = cli.Command{ - .name = "bbcodez", - .options = try r.allocOptions(&.{ - .{ - .long_name = "input", - .help = "input file", - .value_ref = r.mkRef(&config.input), - }, - .{ - .long_name = "output", - .help = "output file", - .value_ref = r.mkRef(&config.output), - }, - .{ - .long_name = "convert_tab_size", - .help = "Convert tabs to given number of spaces within [0, 255]", - .value_ref = r.mkRef(&config.convert_tab_size), - }, - }), - .target = cli.CommandTarget{ - .action = cli.CommandAction{ .exec = processConfig }, - }, - }, - }; - return r.run(&app); -} +pub fn main(init: std.process.Init) !void { + const io = init.io; + var out_buf: [1024]u8 = undefined; + var input_path: ?[]const u8 = null; + var output_path: ?[]const u8 = null; + var convert_tab_size_str: ?[]const u8 = null; + + var args = std.process.Args.Iterator.init(init.minimal.args); + _ = args.skip(); // skip program name + while (args.next()) |arg| { + if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) { + var stderr = File.stderr().writer(io, &out_buf); + stderr.interface.print(usage, .{}) catch {}; + try stderr.interface.flush(); + return; + } else if (std.mem.eql(u8, arg, "--input") or std.mem.eql(u8, arg, "-i")) { + input_path = args.next() orelse return error.MissingArgValue; + } else if (std.mem.eql(u8, arg, "--output") or std.mem.eql(u8, arg, "-o")) { + output_path = args.next() orelse return error.MissingArgValue; + } else if (std.mem.eql(u8, arg, "--convert-tab-size")) { + convert_tab_size_str = args.next() orelse return error.MissingArgValue; + } + } -fn processConfig() !void { - const input_source: StreamSource = if (config.input == null) .stdin else .file; - const output_source: StreamDestination = if (config.output == null) .stdout else .file; - const convert_tab_size: ?u8 = if (config.convert_tab_size == null) - null - else - std.fmt.parseInt(u8, config.convert_tab_size.?, 10) catch { + const convert_tab_size: ?u8 = if (convert_tab_size_str) |s| + std.fmt.parseInt(u8, s, 10) catch { std.log.err("convert_tab_size must be an integer in range of [0, 255]", .{}); return error.ConvertTabSizeInvalid; - }; - - var input_file: File = undefined; - defer input_file.close(); + } + else + null; - var output_file: File = undefined; - defer output_file.close(); + const cwd = std.Io.Dir.cwd(); - switch (input_source) { - .file => { - input_file = try cwd().openFile(config.input.?, .{}); - }, - .stdin => { - input_file = std.fs.File.stdin(); - }, - } + const input_file: File = if (input_path) |p| + try cwd.openFile(io, p, .{}) + else + File.stdin(); + defer if (input_path != null) input_file.close(io); - switch (output_source) { - .file => { - output_file = try cwd().createFile(config.output.?, .{}); - }, - .stdout => { - output_file = std.fs.File.stdout(); - }, - } + const output_file: File = if (output_path) |p| + try cwd.createFile(io, p, .{}) + else + File.stdout(); + defer if (output_path != null) output_file.close(io); var in_buf: [1024]u8 = undefined; - var out_buf: [1024]u8 = undefined; - var file_reader = input_file.reader(&in_buf); + var file_reader = input_file.reader(io, &in_buf); const reader = &file_reader.interface; - var file_writer = output_file.writer(&out_buf); + var file_writer = output_file.writer(io, &out_buf); const writer = &file_writer.interface; - var arena = ArenaAllocator.init(std.heap.page_allocator); + var arena = ArenaAllocator.init(init.gpa); defer arena.deinit(); const allocator = arena.allocator(); @@ -104,16 +67,25 @@ fn processConfig() !void { }); } -const cwd = std.fs.cwd; +const usage = + \\Usage: bbcodez [options] + \\ + \\Convert BBCode to Markdown. + \\ + \\Options: + \\ -i, --input Input file (default: stdin) + \\ -o, --output Output file (default: stdout) + \\ --convert-tab-size Convert tabs to n spaces [0-255] + \\ -h, --help Show this help + \\ +; + const renderDocument = lib.fmt.md.renderDocument; -const File = std.fs.File; -const AnyReader = std.io.AnyReader; -const AnyWriter = std.io.AnyWriter; +const File = std.Io.File; const ArenaAllocator = std.heap.ArenaAllocator; const Level = std.log.Level; const Options = std.Options; const std = @import("std"); -const cli = @import("cli"); -const lib = @import("lib"); +const lib = @import("bbcodez"); diff --git a/src/parser.zig b/src/parser.zig index 2b1c108..c66419b 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -221,7 +221,7 @@ test "complex parsing" { \\[b]Note:[/b] Output displayed in the editor supports clickable [code skip-lint][url=address]text[/url][/code] tags. The [code skip-lint][url][/code] tag's [code]address[/code] value is handled by [method OS.shell_open] when clicked. ; - var fixed_reader = std.io.Reader.fixed(bbcode); + var fixed_reader = std.Io.Reader.fixed(bbcode); var tokens = try tokenizer.tokenize(testing.allocator, &fixed_reader, .{ .equals_required_in_parameters = false, diff --git a/src/root.zig b/src/root.zig index 1947823..9b50ad9 100644 --- a/src/root.zig +++ b/src/root.zig @@ -108,5 +108,5 @@ pub const fmt = struct { }; test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } diff --git a/src/tokenizer.zig b/src/tokenizer.zig index abb705b..303a6bc 100644 --- a/src/tokenizer.zig +++ b/src/tokenizer.zig @@ -268,7 +268,7 @@ pub const TokenResult = struct { /// Returns: TokenResult containing all parsed tokens /// Errors: OutOfMemory if allocation fails during tokenization pub fn tokenizeBuffer(allocator: std.mem.Allocator, buffer: []const u8, options: Options) !TokenResult { - var fixed_reader = std.io.Reader.fixed(buffer); + var fixed_reader = std.Io.Reader.fixed(buffer); var tokenizer = try tokenize(allocator, &fixed_reader, options); try tokenizer.buffer.ensureTotalCapacity(allocator, buffer.len); @@ -383,7 +383,7 @@ fn getTagName(tag: []const u8) []const u8 { /// options: Tokenization configuration options /// Returns: TokenResult containing all parsed tokens /// Errors: OutOfMemory if allocation fails, or any reader errors -pub fn tokenize(allocator: std.mem.Allocator, reader: *std.io.Reader, options: Options) !TokenResult { +pub fn tokenize(allocator: std.mem.Allocator, reader: *std.Io.Reader, options: Options) !TokenResult { var state: State = .text; var start: usize = 0; var last_byte: u8 = 0; From e90373fae62e0aba33f360c63f58e84f1622f66f Mon Sep 17 00:00:00 2001 From: Simon Hartcher Date: Fri, 17 Apr 2026 11:31:26 +1000 Subject: [PATCH 2/5] build: add mise.lock and pin tool versions for reproducible installs --- mise.lock | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ mise.toml | 4 +- 2 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 mise.lock diff --git a/mise.lock b/mise.lock new file mode 100644 index 0000000..1696a7d --- /dev/null +++ b/mise.lock @@ -0,0 +1,139 @@ +# @generated - this file is auto-generated by `mise lock` https://mise.jdx.dev/dev-tools/mise-lock.html + +[[tools."github:DonIsaac/zlint"]] +version = "0.7.9" +backend = "github:DonIsaac/zlint" + +[tools."github:DonIsaac/zlint"."platforms.linux-arm64"] +checksum = "sha256:fb73191c680ac9303605ba8a05974f06827c980ea593316abc00934c6bd17faf" +url = "https://github.com/DonIsaac/zlint/releases/download/v0.7.9/zlint-linux-aarch64" +url_api = "https://api.github.com/repos/DonIsaac/zlint/releases/assets/273295160" +provenance = "github-attestations" + +[tools."github:DonIsaac/zlint"."platforms.linux-arm64-musl"] +checksum = "sha256:fb73191c680ac9303605ba8a05974f06827c980ea593316abc00934c6bd17faf" +url = "https://github.com/DonIsaac/zlint/releases/download/v0.7.9/zlint-linux-aarch64" +url_api = "https://api.github.com/repos/DonIsaac/zlint/releases/assets/273295160" +provenance = "github-attestations" + +[tools."github:DonIsaac/zlint"."platforms.linux-x64"] +checksum = "sha256:388c501bfb8ffe0e4ffb5ac633b71c1b74e4465a0d1cf8cb2f23f99b08299a29" +url = "https://github.com/DonIsaac/zlint/releases/download/v0.7.9/zlint-linux-x86_64" +url_api = "https://api.github.com/repos/DonIsaac/zlint/releases/assets/273295161" +provenance = "github-attestations" + +[tools."github:DonIsaac/zlint"."platforms.linux-x64-musl"] +checksum = "sha256:388c501bfb8ffe0e4ffb5ac633b71c1b74e4465a0d1cf8cb2f23f99b08299a29" +url = "https://github.com/DonIsaac/zlint/releases/download/v0.7.9/zlint-linux-x86_64" +url_api = "https://api.github.com/repos/DonIsaac/zlint/releases/assets/273295161" +provenance = "github-attestations" + +[tools."github:DonIsaac/zlint"."platforms.macos-arm64"] +checksum = "sha256:39e49f1fba0ffa636082a317c2970d1c5fa4d5db3dd059569fbc95c808788f1f" +url = "https://github.com/DonIsaac/zlint/releases/download/v0.7.9/zlint-macos-aarch64" +url_api = "https://api.github.com/repos/DonIsaac/zlint/releases/assets/273295157" +provenance = "github-attestations" + +[tools."github:DonIsaac/zlint"."platforms.macos-x64"] +checksum = "sha256:72b9abead168bd5d70a26de1da193a495f2ef243be80b02e41dfebdafb5345cf" +url = "https://github.com/DonIsaac/zlint/releases/download/v0.7.9/zlint-macos-x86_64" +url_api = "https://api.github.com/repos/DonIsaac/zlint/releases/assets/273295159" +provenance = "github-attestations" + +[tools."github:DonIsaac/zlint"."platforms.windows-x64"] +checksum = "sha256:565a1b5847205920a63f300587a4c8bac6191e7ebd268260d60d521c42df3a76" +url = "https://github.com/DonIsaac/zlint/releases/download/v0.7.9/zlint-windows-x86_64.exe" +url_api = "https://api.github.com/repos/DonIsaac/zlint/releases/assets/273295158" +provenance = "github-attestations" + +[[tools.pre-commit]] +version = "4.5.0" +backend = "aqua:pre-commit/pre-commit" + +[tools.pre-commit."platforms.linux-arm64"] +checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" +url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" + +[tools.pre-commit."platforms.linux-arm64-musl"] +checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" +url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" + +[tools.pre-commit."platforms.linux-x64"] +checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" +url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" + +[tools.pre-commit."platforms.linux-x64-musl"] +checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" +url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" + +[tools.pre-commit."platforms.macos-arm64"] +checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" +url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" + +[tools.pre-commit."platforms.macos-x64"] +checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" +url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" + +[[tools.zig]] +version = "0.16.0" +backend = "core:zig" + +[tools.zig."platforms.linux-arm64"] +checksum = "sha256:ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17" +url = "https://ziglang.org/download/0.16.0/zig-aarch64-linux-0.16.0.tar.xz" + +[tools.zig."platforms.linux-arm64-musl"] +checksum = "sha256:ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17" +url = "https://ziglang.org/download/0.16.0/zig-aarch64-linux-0.16.0.tar.xz" + +[tools.zig."platforms.linux-x64"] +checksum = "sha256:70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00" +url = "https://ziglang.org/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz" + +[tools.zig."platforms.linux-x64-musl"] +checksum = "sha256:70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00" +url = "https://ziglang.org/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz" + +[tools.zig."platforms.macos-arm64"] +checksum = "sha256:b23d70deaa879b5c2d486ed3316f7eaa53e84acf6fc9cc747de152450d401489" +url = "https://ziglang.org/download/0.16.0/zig-aarch64-macos-0.16.0.tar.xz" + +[tools.zig."platforms.macos-x64"] +checksum = "sha256:0387557ed1877bc6a2e1802c8391953baddba76081876301c522f52977b52ba7" +url = "https://ziglang.org/download/0.16.0/zig-x86_64-macos-0.16.0.tar.xz" + +[tools.zig."platforms.windows-x64"] +checksum = "sha256:68659eb5f1e4eb1437a722f1dd889c5a322c9954607f5edcf337bc3684a75a7e" +url = "https://ziglang.org/download/0.16.0/zig-x86_64-windows-0.16.0.zip" + +[[tools.zls]] +version = "0.16.0" +backend = "aqua:zigtools/zls" + +[tools.zls."platforms.linux-arm64"] +url = "https://builds.zigtools.org/zls-aarch64-linux-0.16.0.tar.xz" +provenance = "minisign" + +[tools.zls."platforms.linux-arm64-musl"] +url = "https://builds.zigtools.org/zls-aarch64-linux-0.16.0.tar.xz" +provenance = "minisign" + +[tools.zls."platforms.linux-x64"] +url = "https://builds.zigtools.org/zls-x86_64-linux-0.16.0.tar.xz" +provenance = "minisign" + +[tools.zls."platforms.linux-x64-musl"] +url = "https://builds.zigtools.org/zls-x86_64-linux-0.16.0.tar.xz" +provenance = "minisign" + +[tools.zls."platforms.macos-arm64"] +url = "https://builds.zigtools.org/zls-aarch64-macos-0.16.0.tar.xz" +provenance = "minisign" + +[tools.zls."platforms.macos-x64"] +url = "https://builds.zigtools.org/zls-x86_64-macos-0.16.0.tar.xz" +provenance = "minisign" + +[tools.zls."platforms.windows-x64"] +url = "https://builds.zigtools.org/zls-x86_64-windows-0.16.0.zip" +provenance = "minisign" diff --git a/mise.toml b/mise.toml index f00482d..f975412 100644 --- a/mise.toml +++ b/mise.toml @@ -1,5 +1,5 @@ [tools] zig = "0.16.0" zls = "0.16.0" -pre-commit = "latest" -"ubi:DonIsaac/zlint" = "latest" +pre-commit = "4.5.0" +"github:DonIsaac/zlint" = "latest" From 6b9cbc42abd4b4b8c5e14021a1256c949f025eb8 Mon Sep 17 00:00:00 2001 From: Simon Hartcher Date: Fri, 17 Apr 2026 11:48:08 +1000 Subject: [PATCH 3/5] build: replace pre-commit with hk for git hooks management --- .pre-commit-config.yaml | 23 ------------ hk.pkl | 45 ++++++++++++++++++++++++ mise.lock | 78 ++++++++++++++++++++++++++++++----------- mise.toml | 4 ++- 4 files changed, 105 insertions(+), 45 deletions(-) delete mode 100644 .pre-commit-config.yaml create mode 100644 hk.pkl diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 35ca186..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,23 +0,0 @@ -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-added-large-files - - - repo: https://github.com/batmac/pre-commit-zig - rev: v0.3.0 - hooks: - - id: zig-fmt - - id: zig-build - - id: zig-build-test - - repo: local - hooks: - - id: zlint - name: Run zlint - entry: zlint - args: ["--deny-warnings", "--fix"] - language: system - types: [zig] diff --git a/hk.pkl b/hk.pkl new file mode 100644 index 0000000..106d211 --- /dev/null +++ b/hk.pkl @@ -0,0 +1,45 @@ +amends "package://github.com/jdx/hk/releases/download/v1.42.0/hk@1.42.0#/Config.pkl" +import "package://github.com/jdx/hk/releases/download/v1.42.0/hk@1.42.0#/Builtins.pkl" + +local linters: Mapping = new { + ["trailing_whitespace"] = (Builtins.trailing_whitespace) { + exclude = List("snapshots/**") + } + ["newlines"] = (Builtins.newlines) { + exclude = List("snapshots/**") + } + ["check_added_large_files"] = Builtins.check_added_large_files + ["yamllint"] = (Builtins.yamllint) { + check = "yamllint {{files}}" + } + ["zig_fmt"] = new Step { + glob = List("*.zig") + check = "zig fmt --check {{files}}" + fix = "zig fmt {{files}}" + } + ["zlint"] = new Step { + glob = List("*.zig") + check = "zlint --deny-warnings {{files}}" + fix = "zlint --deny-warnings --fix {{files}}" + } +} + +hooks { + ["pre-commit"] { + fix = true + stash = "git" + steps = linters + } + ["pre-push"] { + steps { + ["zig_build"] { + exclusive = true + check = "zig build" + } + ["zig_build_test"] { + exclusive = true + check = "zig build test" + } + } + } +} diff --git a/mise.lock b/mise.lock index 1696a7d..141869f 100644 --- a/mise.lock +++ b/mise.lock @@ -46,33 +46,69 @@ url = "https://github.com/DonIsaac/zlint/releases/download/v0.7.9/zlint-windows- url_api = "https://api.github.com/repos/DonIsaac/zlint/releases/assets/273295158" provenance = "github-attestations" -[[tools.pre-commit]] -version = "4.5.0" -backend = "aqua:pre-commit/pre-commit" +[[tools.hk]] +version = "1.42.0" +backend = "aqua:jdx/hk" -[tools.pre-commit."platforms.linux-arm64"] -checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" -url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" +[tools.hk."platforms.linux-arm64"] +checksum = "sha256:291ed6215703fc3aa6a9fcbb96a72b88751c50888a00a6a73140ae0fbc3eef70" +url = "https://github.com/jdx/hk/releases/download/v1.42.0/hk-aarch64-unknown-linux-gnu.tar.gz" -[tools.pre-commit."platforms.linux-arm64-musl"] -checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" -url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" +[tools.hk."platforms.linux-arm64-musl"] +checksum = "sha256:291ed6215703fc3aa6a9fcbb96a72b88751c50888a00a6a73140ae0fbc3eef70" +url = "https://github.com/jdx/hk/releases/download/v1.42.0/hk-aarch64-unknown-linux-gnu.tar.gz" -[tools.pre-commit."platforms.linux-x64"] -checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" -url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" +[tools.hk."platforms.linux-x64"] +checksum = "sha256:a4f8898a83c1521c3e184b8af613ddf8d121df21a4026c679b18b54e8b5953db" +url = "https://github.com/jdx/hk/releases/download/v1.42.0/hk-x86_64-unknown-linux-gnu.tar.gz" -[tools.pre-commit."platforms.linux-x64-musl"] -checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" -url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" +[tools.hk."platforms.linux-x64-musl"] +checksum = "sha256:a4f8898a83c1521c3e184b8af613ddf8d121df21a4026c679b18b54e8b5953db" +url = "https://github.com/jdx/hk/releases/download/v1.42.0/hk-x86_64-unknown-linux-gnu.tar.gz" -[tools.pre-commit."platforms.macos-arm64"] -checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" -url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" +[tools.hk."platforms.macos-arm64"] +checksum = "sha256:29c4d4aabda87ed8e0a3bcd97cffe288a6932f22ae0a49d77f8a1bb9430afdbe" +url = "https://github.com/jdx/hk/releases/download/v1.42.0/hk-aarch64-apple-darwin.tar.gz" -[tools.pre-commit."platforms.macos-x64"] -checksum = "sha256:fbbfa47d19b98e03eb11963094ac3644a97cba105a8c660d8dab4c409c89cebe" -url = "https://github.com/pre-commit/pre-commit/releases/download/v4.5.0/pre-commit-4.5.0.pyz" +[tools.hk."platforms.windows-x64"] +checksum = "sha256:9706dab06f3ed468bb1247ce540dad677acea7bc9a023e8cdbdc5f79b2e4015a" +url = "https://github.com/jdx/hk/releases/download/v1.42.0/hk-x86_64-pc-windows-msvc.zip" + +[[tools.pkl]] +version = "0.30.0" +backend = "aqua:apple/pkl" + +[tools.pkl."platforms.linux-arm64"] +checksum = "sha256:a876085548bba146854d0e96df16df828a8b39d75b57674eb3ad73edd9e52d96" +url = "https://github.com/apple/pkl/releases/download/0.30.0/pkl-linux-aarch64" + +[tools.pkl."platforms.linux-arm64-musl"] +checksum = "sha256:a876085548bba146854d0e96df16df828a8b39d75b57674eb3ad73edd9e52d96" +url = "https://github.com/apple/pkl/releases/download/0.30.0/pkl-linux-aarch64" + +[tools.pkl."platforms.linux-x64"] +checksum = "sha256:182a50a2c84bb002010ea45c8982c1e63b54e7e6a40e939bb5eb70beaad38cd7" +url = "https://github.com/apple/pkl/releases/download/0.30.0/pkl-linux-amd64" + +[tools.pkl."platforms.linux-x64-musl"] +checksum = "sha256:182a50a2c84bb002010ea45c8982c1e63b54e7e6a40e939bb5eb70beaad38cd7" +url = "https://github.com/apple/pkl/releases/download/0.30.0/pkl-linux-amd64" + +[tools.pkl."platforms.macos-arm64"] +checksum = "sha256:923a636f2c858029d9bf93f35aeae58ebd9783fbe0209f4787c4eed950142212" +url = "https://github.com/apple/pkl/releases/download/0.30.0/pkl-macos-aarch64" + +[tools.pkl."platforms.macos-x64"] +checksum = "sha256:215c5c2b02bf4bfb5f7421d4bd81ce1f8781cc9aba93b09f86156c99553de143" +url = "https://github.com/apple/pkl/releases/download/0.30.0/pkl-macos-amd64" + +[tools.pkl."platforms.windows-x64"] +checksum = "sha256:3af84f8f6753ae6cfab50f7127fbfb3b53d374c03079ca0cec27eddffc492b3c" +url = "https://github.com/apple/pkl/releases/download/0.30.0/pkl-windows-amd64.exe" + +[[tools.yamllint]] +version = "1.38.0" +backend = "pipx:yamllint" [[tools.zig]] version = "0.16.0" diff --git a/mise.toml b/mise.toml index f975412..8ce7f11 100644 --- a/mise.toml +++ b/mise.toml @@ -1,5 +1,7 @@ [tools] zig = "0.16.0" zls = "0.16.0" -pre-commit = "4.5.0" +hk = "1.42.0" +pkl = "0.30.0" +yamllint = "1.38.0" "github:DonIsaac/zlint" = "latest" From 1aa3775aaa619759f315636e72a97b5801544186 Mon Sep 17 00:00:00 2001 From: Simon Hartcher Date: Fri, 17 Apr 2026 11:48:09 +1000 Subject: [PATCH 4/5] docs: update git hooks documentation to reflect hk migration --- CLAUDE.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0366ff0..fdd40da 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,17 +17,19 @@ zig build run # Run the bbcodez executable ``` ### Code Quality -The project uses pre-commit hooks with the following linters: -```bash -zlint --deny-warnings --fix # Run zlint for Zig code quality -zig fmt # Format Zig code -``` +The project uses [hk](https://hk.jdx.dev/) for git hooks (configured in `hk.pkl`). + +Pre-commit hooks (run on `git commit`): +- `trailing_whitespace`, `newlines`, `yamllint`, `check_added_large_files` +- `zig fmt` (fix mode) on `*.zig` +- `zlint --deny-warnings --fix` on `*.zig` + +Pre-push hooks (run on `git push`): +- `zig build` +- `zig build test` -Pre-commit hooks automatically run: -- `zig fmt` for formatting -- `zig build` to ensure compilation -- `zig build test` to run tests -- `zlint --deny-warnings --fix` for linting +To install the git hooks after cloning: `hk install` +To run a hook manually: `hk run pre-commit` / `hk run pre-push` ## Architecture From 929f96609178f742ace0f57bfc36264bd4e276b0 Mon Sep 17 00:00:00 2001 From: Simon Hartcher Date: Fri, 17 Apr 2026 11:56:08 +1000 Subject: [PATCH 5/5] fix: use initAllocator for Windows-compatible argument parsing --- src/main.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index b2074ad..38b552c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -9,7 +9,8 @@ pub fn main(init: std.process.Init) !void { var output_path: ?[]const u8 = null; var convert_tab_size_str: ?[]const u8 = null; - var args = std.process.Args.Iterator.init(init.minimal.args); + var args = try std.process.Args.Iterator.initAllocator(init.minimal.args, init.gpa); + defer args.deinit(); _ = args.skip(); // skip program name while (args.next()) |arg| { if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {