From 36303c5e5cf0e4179e1cc7795b45a62135ff357c Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Fri, 18 Sep 2026 08:06:26 +1000 Subject: [PATCH 1/2] feat(woad): create woad.Zig 0.0.1 implementation and build Add the Zig implementation of the woad ANSI colour library under woad/woad.Zig matching sibling projects: - export woad module and static library in build.zig; - define fixed CSI SGR constants in src/root.zig matching C/Go/Rust/Ruby; - add unit tests and examples/show_colours.zig; - add standard Synesis documentation, configuration, and CI workflow; - register woad.Zig in .management/projects.yaml. --- .gitattributes | 5 + .github/workflows/ci.yml | 57 ++++++++++++ .gitignore | 20 ++++ .vimrc | 64 +++++++++++++ .vscode/settings.json | 38 ++++++++ CHANGES.md | 9 ++ LICENSE | 30 ++++++ NEWS.md | 8 ++ README.md | 125 ++++++++++++++++++++++++- TODO.md | 21 +++++ build.zig | 50 ++++++++++ build.zig.zon | 20 ++++ examples/show_colours.zig | 42 +++++++++ src/root.zig | 186 ++++++++++++++++++++++++++++++++++++++ 14 files changed, 673 insertions(+), 2 deletions(-) create mode 100644 .gitattributes create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .vimrc create mode 100644 .vscode/settings.json create mode 100644 CHANGES.md create mode 100644 LICENSE create mode 100644 NEWS.md create mode 100644 TODO.md create mode 100644 build.zig create mode 100644 build.zig.zon create mode 100644 examples/show_colours.zig create mode 100644 src/root.zig diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c7a1b95 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +*.zig linguist-language=Zig + +*.html linguist-detectable=false +*.sh linguist-detectable=false +*.vimrc linguist-detectable=false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7ce3330 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +name: CI + +on: + push: + branches: + - master + - dev + - boilerplate + - idiomatic + - rc1 + - rc2 + - rc3 + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Lint & Format + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Zig + uses: mlugg/setup-zig@v2 + with: + version: 0.16.0 + + - name: Check Formatting + run: zig fmt --check . + + test: + name: Build & Test (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Zig + uses: mlugg/setup-zig@v2 + with: + version: 0.16.0 + + - name: Run Unit Tests + run: zig build test --global-cache-dir .zig-cache + + - name: Run Example + run: zig build run-example --global-cache-dir .zig-cache diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8185211 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# directories (by name) + +/scratch/ +/scripts/__pycache__/ +/.zig-cache/ +/zig-out/ + +# directories (by pattern) + + +# files (by name) + +.DS_Store + +# files (by pattern) + +*~ +*.swp +*.tmp +*.zip diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..0f12357 --- /dev/null +++ b/.vimrc @@ -0,0 +1,64 @@ +" Synesis C/C++ & Zig project .vimrc — aligned with .vscode/settings.json + +set nocompatible +filetype indent plugin on +syntax enable +set autoindent +set backspace=indent,eol,start +set hlsearch +set incsearch +set number + +" files.insertFinalNewline +set eol +set fixeol + +" editor.renderWhitespace: all +set list +set listchars=tab:->,trail:-,extends:>,precedes:<,nbsp:+ + +" editor.detectIndentation: false — global defaults (editor.tabSize: 4, insertSpaces: true) +set tabstop=4 +set shiftwidth=4 +set softtabstop=4 +set expandtab +set colorcolumn=76 + +if has('termguicolors') + " set termguicolors +endif + +function! s:ConfigureColorColumn() abort + highlight ColorColumn ctermbg=236 guibg=#2a2a2a cterm=NONE gui=NONE +endfunction + +call s:ConfigureColorColumn() +autocmd ColorScheme * call s:ConfigureColorColumn() + +" files.trimTrailingWhitespace +autocmd BufWritePre * %s/\s\+$//e + +augroup sis_c_cxx_zig + autocmd! + + " [c] / [cpp] + autocmd FileType c,cpp setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,64,68,72,76 + + " [zig] + autocmd FileType zig setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=76 + + " [cmake] + autocmd FileType cmake setlocal noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 + + " [shellscript] + autocmd FileType sh,bash,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 + + " [bat] + autocmd FileType bat,dosbatch setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + + " [json] / [markdown] / [yaml] / [ruby] + autocmd FileType json,markdown,yaml,ruby setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 + + " [toml] + autocmd FileType toml setlocal noexpandtab tabstop=2 shiftwidth=2 softtabstop=2 +augroup END diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2abd7ac --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,38 @@ +{ + "[json]": { + "editor.insertSpaces": false, + "editor.tabSize": 2, + }, + "[markdown]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[python]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 4, + }, + "[ruby]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 2, + }, + "[toml]": { + "editor.insertSpaces": false, + "editor.tabSize": 2, + }, + "[zig]": { + "editor.insertSpaces": true, + "editor.tabSize": 4, + "editor.formatOnSave": true, + "editor.defaultFormatter": "ziglang.vscode-zig" + }, + "editor.detectIndentation": false, + "editor.insertSpaces": false, + "editor.renderWhitespace": "all", + "editor.rulers": [ 76 ], + "editor.tabSize": 2, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "git.mergeEditor": false, +} diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..838f2de --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,9 @@ +# woad.Zig - Changes + + +## 0.0.1 - 18th September 2026 + +* SGR colour and reset codes (`RESET`, `FG_*`, `BG_*`, including bright variants); + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..95082c3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ +woad.Zig - BSD 3-Clause License + +Copyright (c) 2026, Matthew Wilson and Synesis Information Systems +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..53fc92d --- /dev/null +++ b/NEWS.md @@ -0,0 +1,8 @@ +# woad.Zig - News + +| Date | News Item | Details | +| ------------------- | --------- | ------- | +| 18th September 2026 | [**woad.Zig** 0.0.1](https://github.com/synesissoftware/woad.Zig/releases/tag/0.0.1) | initial version | + + + diff --git a/README.md b/README.md index 89fb672..d341386 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,123 @@ -# woad.Zig -Rock-bottom colour library, for Zig +# woad.Zig + +Minimal ANSI terminal colour codes, for Zig + +![Language](https://img.shields.io/badge/Zig-F7A41D?style=flat&logo=zig&logoColor=white) +[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) +[![GitHub release](https://img.shields.io/github/v/release/synesissoftware/woad.Zig.svg)](https://github.com/synesissoftware/woad.Zig/releases/latest) +[![Last Commit](https://img.shields.io/github/last-commit/synesissoftware/woad.Zig)](https://github.com/synesissoftware/woad.Zig/commits/master) +[![CI](https://github.com/synesissoftware/woad.Zig/actions/workflows/ci.yml/badge.svg)](https://github.com/synesissoftware/woad.Zig/actions/workflows/ci.yml) + + +## Table of Contents + +- [Introduction](#introduction) +- [Installation](#installation) +- [Components](#components) +- [Project Information](#project-information) + - [Where to get help](#where-to-get-help) + - [Contribution guidelines](#contribution-guidelines) + - [Dependencies](#dependencies) + - [Efferent (fan-out)](#efferent-fan-out) + - [Development Dependencies](#development-dependencies) + - [Afferent (fan-in)](#afferent-fan-in) + - [Related projects](#related-projects) + - [License](#license) + + +## Introduction + +**woad** provides the smallest useful set of fixed ANSI SGR colour sequences for library authors. It is not a console or TUI framework. + +**woad.Zig** is the **Zig** implementation. + + +## Installation + +Add **woad.Zig** to your `build.zig.zon`: + +```zig +.{ + .name = "my-project", + .version = "0.1.0", + .dependencies = .{ + .woad = .{ + .url = "https://github.com/synesissoftware/woad.Zig/archive/refs/tags/0.0.1.tar.gz", + // .hash = "...", + }, + }, +} +``` + +Then import and expose the module in your `build.zig`: + +```zig +const woad_dep = b.dependency("woad", .{ + .target = target, + .optimize = optimize, +}); +exe.root_module.addImport("woad", woad_dep.module("woad")); +``` + + +## Components + +**woad.Zig** ships SGR string constants (`RESET`, `FG_*`, `BG_*`, including bright variants) and `VERSION`. TTY/stream gating and Windows virtual-terminal opt-in are not implemented yet. + +```zig +const std = @import("std"); +const woad = @import("woad"); + +pub fn main() !void { + const stdout = std.io.getStdOut().writer(); + try stdout.print("{s}ok{s}\n", .{ woad.FG_GREEN, woad.RESET }); +} +``` + + +## Project Information + + +### Where to get help + +[GitHub Page](https://github.com/synesissoftware/woad.Zig "GitHub Page") + + +### Contribution guidelines + +Defect reports, feature requests, and pull requests are welcome on https://github.com/synesissoftware/woad.Zig. + + +### Dependencies + + +#### Efferent (fan-out) + +None. + + +#### Development Dependencies + +None. + + +#### Afferent (fan-in) + +None (currently). + + +### Related projects + +* [**woad**](https://github.com/synesissoftware/woad/) +* [**woad.Go**](https://github.com/synesissoftware/woad.Go/) +* [**woad.Python**](https://github.com/synesissoftware/woad.Python/) +* [**woad.Ruby**](https://github.com/synesissoftware/woad.Ruby/) +* [**woad.Rust**](https://github.com/synesissoftware/woad.Rust/) + + +### License + +**woad.Zig** is released under the 3-clause BSD license. See [LICENSE](./LICENSE) for details. + + + diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..373f160 --- /dev/null +++ b/TODO.md @@ -0,0 +1,21 @@ +# woad.Zig - TODO + + +## Functional improvements + +* [x] ~~~SGR colour and reset codes~~~ - ✅; +* [ ] TTY-conditional colour codes (process and per-stream); +* [ ] Windows virtual-terminal gating (OS build + `GetConsoleMode`); + + +## Performance improvements + +* \ + + +## Packaging improvements + +* \ + + + diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..64880f7 --- /dev/null +++ b/build.zig @@ -0,0 +1,50 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // Create a module for other packages to import + const woad_module = b.addModule("woad", .{ + .root_source_file = b.path("src/root.zig"), + .target = target, + .optimize = optimize, + }); + + // Static library using the module + const lib = b.addLibrary(.{ + .name = "woad", + .linkage = .static, + .root_module = woad_module, + }); + b.installArtifact(lib); + + // Unit tests using the module + const lib_unit_tests = b.addTest(.{ + .root_module = woad_module, + }); + const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_lib_unit_tests.step); + + // Example: show_colours + const example = b.addExecutable(.{ + .name = "show_colours", + .root_module = b.createModule(.{ + .root_source_file = b.path("examples/show_colours.zig"), + .target = target, + .optimize = optimize, + }), + }); + example.root_module.addImport("woad", woad_module); + b.installArtifact(example); + + const run_example = b.addRunArtifact(example); + if (b.args) |args| { + run_example.addArgs(args); + } + + const run_example_step = b.step("run-example", "Run the show_colours example"); + run_example_step.dependOn(&run_example.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..39d443d --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,20 @@ +.{ + .authors = .{ + "Matt Wilson ", + }, + .description = "Minimal ANSI terminal colour codes, for Zig", + .fingerprint = 0xa21e34833b201d51, + .name = .woad, + .paths = .{ + "CHANGES.md", + "LICENSE", + "NEWS.md", + "README.md", + "TODO.md", + "build.zig.zon", + "build.zig", + "examples", + "src", + }, + .version = "0.0.1", +} diff --git a/examples/show_colours.zig b/examples/show_colours.zig new file mode 100644 index 0000000..d526cbc --- /dev/null +++ b/examples/show_colours.zig @@ -0,0 +1,42 @@ +const std = @import("std"); +const woad = @import("woad"); + +pub fn main(init: std.process.Init) !void { + var buffer: [4096]u8 = undefined; + var stdout_impl = std.Io.File.stdout().writer(init.io, &buffer); + const stdout = &stdout_impl.interface; + + try stdout.print("woad.Zig version: {s}\n\n", .{woad.VERSION}); + + try stdout.print("Standard foreground colours:\n", .{}); + try stdout.print(" {s}Black{s}\n", .{ woad.FG_BLACK, woad.RESET }); + try stdout.print(" {s}Red{s}\n", .{ woad.FG_RED, woad.RESET }); + try stdout.print(" {s}Green{s}\n", .{ woad.FG_GREEN, woad.RESET }); + try stdout.print(" {s}Yellow{s}\n", .{ woad.FG_YELLOW, woad.RESET }); + try stdout.print(" {s}Blue{s}\n", .{ woad.FG_BLUE, woad.RESET }); + try stdout.print(" {s}Magenta{s}\n", .{ woad.FG_MAGENTA, woad.RESET }); + try stdout.print(" {s}Cyan{s}\n", .{ woad.FG_CYAN, woad.RESET }); + try stdout.print(" {s}White{s}\n\n", .{ woad.FG_WHITE, woad.RESET }); + + try stdout.print("Bright foreground colours:\n", .{}); + try stdout.print(" {s}Bright Black{s}\n", .{ woad.FG_BRIGHT_BLACK, woad.RESET }); + try stdout.print(" {s}Bright Red{s}\n", .{ woad.FG_BRIGHT_RED, woad.RESET }); + try stdout.print(" {s}Bright Green{s}\n", .{ woad.FG_BRIGHT_GREEN, woad.RESET }); + try stdout.print(" {s}Bright Yellow{s}\n", .{ woad.FG_BRIGHT_YELLOW, woad.RESET }); + try stdout.print(" {s}Bright Blue{s}\n", .{ woad.FG_BRIGHT_BLUE, woad.RESET }); + try stdout.print(" {s}Bright Magenta{s}\n", .{ woad.FG_BRIGHT_MAGENTA, woad.RESET }); + try stdout.print(" {s}Bright Cyan{s}\n", .{ woad.FG_BRIGHT_CYAN, woad.RESET }); + try stdout.print(" {s}Bright White{s}\n\n", .{ woad.FG_BRIGHT_WHITE, woad.RESET }); + + try stdout.print("Background colours:\n", .{}); + try stdout.print(" {s} Black {s}\n", .{ woad.BG_BLACK, woad.RESET }); + try stdout.print(" {s} Red {s}\n", .{ woad.BG_RED, woad.RESET }); + try stdout.print(" {s} Green {s}\n", .{ woad.BG_GREEN, woad.RESET }); + try stdout.print(" {s} Yellow {s}\n", .{ woad.BG_YELLOW, woad.RESET }); + try stdout.print(" {s} Blue {s}\n", .{ woad.BG_BLUE, woad.RESET }); + try stdout.print(" {s} Magenta {s}\n", .{ woad.BG_MAGENTA, woad.RESET }); + try stdout.print(" {s} Cyan {s}\n", .{ woad.BG_CYAN, woad.RESET }); + try stdout.print(" {s} White {s}\n", .{ woad.BG_WHITE, woad.RESET }); + + try stdout.flush(); +} diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..0180c04 --- /dev/null +++ b/src/root.zig @@ -0,0 +1,186 @@ +//! Minimal ANSI terminal colour codes, for Zig. +//! +//! **woad** provides the smallest useful set of fixed SGR sequences for +//! library authors. It is not a console or TUI framework. + +/// Package version. +pub const VERSION = "0.0.1"; + +// Reset + +/// Reset all attributes. +pub const RESET = "\x1b[0m"; + +// Foreground (standard) + +/// Foreground black. +pub const FG_BLACK = "\x1b[30m"; +/// Foreground red. +pub const FG_RED = "\x1b[31m"; +/// Foreground green. +pub const FG_GREEN = "\x1b[32m"; +/// Foreground yellow. +pub const FG_YELLOW = "\x1b[33m"; +/// Foreground blue. +pub const FG_BLUE = "\x1b[34m"; +/// Foreground magenta. +pub const FG_MAGENTA = "\x1b[35m"; +/// Foreground cyan. +pub const FG_CYAN = "\x1b[36m"; +/// Foreground white. +pub const FG_WHITE = "\x1b[37m"; + +// Foreground (bright) + +/// Foreground bright black. +pub const FG_BRIGHT_BLACK = "\x1b[90m"; +/// Foreground bright red. +pub const FG_BRIGHT_RED = "\x1b[91m"; +/// Foreground bright green. +pub const FG_BRIGHT_GREEN = "\x1b[92m"; +/// Foreground bright yellow. +pub const FG_BRIGHT_YELLOW = "\x1b[93m"; +/// Foreground bright blue. +pub const FG_BRIGHT_BLUE = "\x1b[94m"; +/// Foreground bright magenta. +pub const FG_BRIGHT_MAGENTA = "\x1b[95m"; +/// Foreground bright cyan. +pub const FG_BRIGHT_CYAN = "\x1b[96m"; +/// Foreground bright white. +pub const FG_BRIGHT_WHITE = "\x1b[97m"; + +// Background (standard) + +/// Background black. +pub const BG_BLACK = "\x1b[40m"; +/// Background red. +pub const BG_RED = "\x1b[41m"; +/// Background green. +pub const BG_GREEN = "\x1b[42m"; +/// Background yellow. +pub const BG_YELLOW = "\x1b[43m"; +/// Background blue. +pub const BG_BLUE = "\x1b[44m"; +/// Background magenta. +pub const BG_MAGENTA = "\x1b[45m"; +/// Background cyan. +pub const BG_CYAN = "\x1b[46m"; +/// Background white. +pub const BG_WHITE = "\x1b[47m"; + +// Background (bright) + +/// Background bright black. +pub const BG_BRIGHT_BLACK = "\x1b[100m"; +/// Background bright red. +pub const BG_BRIGHT_RED = "\x1b[101m"; +/// Background bright green. +pub const BG_BRIGHT_GREEN = "\x1b[102m"; +/// Background bright yellow. +pub const BG_BRIGHT_YELLOW = "\x1b[103m"; +/// Background bright blue. +pub const BG_BRIGHT_BLUE = "\x1b[104m"; +/// Background bright magenta. +pub const BG_BRIGHT_MAGENTA = "\x1b[105m"; +/// Background bright cyan. +pub const BG_BRIGHT_CYAN = "\x1b[106m"; +/// Background bright white. +pub const BG_BRIGHT_WHITE = "\x1b[107m"; + +const std = @import("std"); +const testing = std.testing; + +test "version" { + try testing.expectEqualStrings("0.0.1", VERSION); +} + +test "reset code" { + try testing.expectEqualStrings("\x1b[0m", RESET); +} + +test "foreground standard codes" { + try testing.expectEqualStrings("\x1b[30m", FG_BLACK); + try testing.expectEqualStrings("\x1b[31m", FG_RED); + try testing.expectEqualStrings("\x1b[32m", FG_GREEN); + try testing.expectEqualStrings("\x1b[33m", FG_YELLOW); + try testing.expectEqualStrings("\x1b[34m", FG_BLUE); + try testing.expectEqualStrings("\x1b[35m", FG_MAGENTA); + try testing.expectEqualStrings("\x1b[36m", FG_CYAN); + try testing.expectEqualStrings("\x1b[37m", FG_WHITE); +} + +test "foreground bright codes" { + try testing.expectEqualStrings("\x1b[90m", FG_BRIGHT_BLACK); + try testing.expectEqualStrings("\x1b[91m", FG_BRIGHT_RED); + try testing.expectEqualStrings("\x1b[92m", FG_BRIGHT_GREEN); + try testing.expectEqualStrings("\x1b[93m", FG_BRIGHT_YELLOW); + try testing.expectEqualStrings("\x1b[94m", FG_BRIGHT_BLUE); + try testing.expectEqualStrings("\x1b[95m", FG_BRIGHT_MAGENTA); + try testing.expectEqualStrings("\x1b[96m", FG_BRIGHT_CYAN); + try testing.expectEqualStrings("\x1b[97m", FG_BRIGHT_WHITE); +} + +test "background standard codes" { + try testing.expectEqualStrings("\x1b[40m", BG_BLACK); + try testing.expectEqualStrings("\x1b[41m", BG_RED); + try testing.expectEqualStrings("\x1b[42m", BG_GREEN); + try testing.expectEqualStrings("\x1b[43m", BG_YELLOW); + try testing.expectEqualStrings("\x1b[44m", BG_BLUE); + try testing.expectEqualStrings("\x1b[45m", BG_MAGENTA); + try testing.expectEqualStrings("\x1b[46m", BG_CYAN); + try testing.expectEqualStrings("\x1b[47m", BG_WHITE); +} + +test "background bright codes" { + try testing.expectEqualStrings("\x1b[100m", BG_BRIGHT_BLACK); + try testing.expectEqualStrings("\x1b[101m", BG_BRIGHT_RED); + try testing.expectEqualStrings("\x1b[102m", BG_BRIGHT_GREEN); + try testing.expectEqualStrings("\x1b[103m", BG_BRIGHT_YELLOW); + try testing.expectEqualStrings("\x1b[104m", BG_BRIGHT_BLUE); + try testing.expectEqualStrings("\x1b[105m", BG_BRIGHT_MAGENTA); + try testing.expectEqualStrings("\x1b[106m", BG_BRIGHT_CYAN); + try testing.expectEqualStrings("\x1b[107m", BG_BRIGHT_WHITE); +} + +test "all codes are CSI SGR" { + const codes = [_][]const u8{ + RESET, + FG_BLACK, + FG_RED, + FG_GREEN, + FG_YELLOW, + FG_BLUE, + FG_MAGENTA, + FG_CYAN, + FG_WHITE, + FG_BRIGHT_BLACK, + FG_BRIGHT_RED, + FG_BRIGHT_GREEN, + FG_BRIGHT_YELLOW, + FG_BRIGHT_BLUE, + FG_BRIGHT_MAGENTA, + FG_BRIGHT_CYAN, + FG_BRIGHT_WHITE, + BG_BLACK, + BG_RED, + BG_GREEN, + BG_YELLOW, + BG_BLUE, + BG_MAGENTA, + BG_CYAN, + BG_WHITE, + BG_BRIGHT_BLACK, + BG_BRIGHT_RED, + BG_BRIGHT_GREEN, + BG_BRIGHT_YELLOW, + BG_BRIGHT_BLUE, + BG_BRIGHT_MAGENTA, + BG_BRIGHT_CYAN, + BG_BRIGHT_WHITE, + }; + + for (codes) |code| { + try testing.expect(std.mem.startsWith(u8, code, "\x1b[")); + try testing.expect(std.mem.endsWith(u8, code, "m")); + } +} From d753fc22bb0ca5e62c6a2e3acd0ed80e4772b539 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Fri, 18 Sep 2026 08:24:01 +1000 Subject: [PATCH 2/2] chore(woad.Zig): align boilerplate with Zig gold templates Refresh support files from misc-dev-scripts Zig templates and close family doc gaps after the 0.0.1 landing: - replace .gitattributes, .gitignore, .vimrc, .vscode/settings.json; - add .editorconfig from the Zig template; - add AUTHORS.md and EXAMPLES.md; catalogue show_colours; - update README for Zig 0.16 I/O and Related projects (woad.NET); - align NEWS Details with CHANGES; add TODO.md TOC; - extend build.zig.zon package paths for the new docs. --- .editorconfig | 39 ++++++++++++++++++++++++ .gitattributes | 71 ++++++++++++++++++++++++++++++++++++++++--- .gitignore | 10 ++++-- .vimrc | 20 ++++++------ .vscode/settings.json | 24 +++++++-------- AUTHORS.md | 21 +++++++++++++ EXAMPLES.md | 9 ++++++ NEWS.md | 3 +- README.md | 19 ++++++++++-- TODO.md | 11 +++++-- build.zig.zon | 4 ++- 11 files changed, 195 insertions(+), 36 deletions(-) create mode 100644 .editorconfig create mode 100644 AUTHORS.md create mode 100644 EXAMPLES.md diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..06965af --- /dev/null +++ b/.editorconfig @@ -0,0 +1,39 @@ +root = true + +# Language indent/EOL/charset overlap with .vscode/settings.json. +# Rulers, renderWhitespace, detectIndentation, mergeEditor, and +# language-server settings cannot be expressed here — they stay in +# settings.json. + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +# [json] +[*.json] +indent_size = 2 +indent_style = space + +# [markdown] +[*.md] +indent_size = 2 +indent_style = space + +# [shellscript] +[*.{bash,sh,zsh}] +indent_size = 2 +indent_style = space + +# [yaml] +[*.{yaml,yml}] +indent_size = 2 +indent_style = space + +# [zig] +[*.zig] +indent_size = 4 +indent_style = space diff --git a/.gitattributes b/.gitattributes index c7a1b95..b6d4b9c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,68 @@ -*.zig linguist-language=Zig +# .gitattributes — Zig (GitHub-hosted) +# +# Sources: GitHub Docs (line endings), git-scm gitattributes (no built-in +# zig diff driver), ziglang conventions for artefacts, github-linguist overrides. -*.html linguist-detectable=false -*.sh linguist-detectable=false -*.vimrc linguist-detectable=false +# Default: detect text, normalize to LF in the repository +* text=auto + +# --- Source --- +*.zig text eol=lf +*.zon text eol=lf +build.zig text eol=lf +build.zig.zon text eol=lf + +# --- Scripts --- +*.bash text eol=lf +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf +*.sh text eol=lf +*.zsh text eol=lf + +# --- Docs / meta --- +*.adoc text +*.markdown text diff=markdown +*.md text diff=markdown +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +LICENSE text +NEWS text +README text +TODO text +.gitattributes text +.gitignore text + +# --- Serialisation --- +*.json text +*.toml text +*.xml text +*.yaml text +*.yml text + +# --- Binary --- +*.a binary +*.exe binary +*.o binary +*.obj binary +*.so binary + +# --- Archives / images (common) --- +*.gif binary +*.gz binary +*.ico binary +*.jpeg binary +*.jpg binary +*.png binary +*.tar binary +*.zip binary + +# --- GitHub Linguist --- +# Prefer .gitignore for these; mark if ever committed +**/.zig-cache/** linguist-generated +**/zig-cache/** linguist-generated +**/zig-out/** linguist-generated diff --git a/.gitignore b/.gitignore index 8185211..d14c0b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ +# Synesis Information Systems .gitignore for Zig projects + + # directories (by name) -/scratch/ -/scripts/__pycache__/ /.zig-cache/ +/scratch/ /zig-out/ + # directories (by pattern) @@ -12,9 +15,10 @@ .DS_Store + # files (by pattern) *~ -*.swp +*.sw[pon] *.tmp *.zip diff --git a/.vimrc b/.vimrc index 0f12357..3b044aa 100644 --- a/.vimrc +++ b/.vimrc @@ -40,25 +40,25 @@ autocmd BufWritePre * %s/\s\+$//e augroup sis_c_cxx_zig autocmd! + " [bat] + autocmd FileType bat,dosbatch setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 " [c] / [cpp] autocmd FileType c,cpp setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,64,68,72,76 - " [zig] - autocmd FileType zig setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=76 - " [cmake] autocmd FileType cmake setlocal noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 - " [shellscript] - autocmd FileType sh,bash,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 - - " [bat] - autocmd FileType bat,dosbatch setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + " [json] / [markdown] / [ruby] / [yaml] + autocmd FileType json,markdown,ruby,yaml setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 - " [json] / [markdown] / [yaml] / [ruby] - autocmd FileType json,markdown,yaml,ruby setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 + " [shellscript] + autocmd FileType bash,sh,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 " [toml] autocmd FileType toml setlocal noexpandtab tabstop=2 shiftwidth=2 softtabstop=2 + + " [zig] + autocmd FileType zig setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=76 + augroup END diff --git a/.vscode/settings.json b/.vscode/settings.json index 2abd7ac..50947dc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,20 +1,10 @@ { "[json]": { - "editor.insertSpaces": false, - "editor.tabSize": 2, - }, - "[markdown]": { "editor.insertSpaces": true, "editor.tabSize": 2, }, - "[python]": { - "editor.insertSpaces": true, - "editor.rulers": [ 60, 76 ], - "editor.tabSize": 4, - }, - "[ruby]": { + "[markdown]": { "editor.insertSpaces": true, - "editor.rulers": [ 60, 76 ], "editor.tabSize": 2, }, "[toml]": { @@ -22,11 +12,18 @@ "editor.tabSize": 2, }, "[zig]": { + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit", + }, + "editor.defaultFormatter": "ziglang.vscode-zig", + "editor.formatOnSave": true, "editor.insertSpaces": true, + "editor.suggest.insertMode": "replace", "editor.tabSize": 4, - "editor.formatOnSave": true, - "editor.defaultFormatter": "ziglang.vscode-zig" }, + "cmake.configureOnOpen": false, + "debug.allowBreakpointsEverywhere": true, "editor.detectIndentation": false, "editor.insertSpaces": false, "editor.renderWhitespace": "all", @@ -35,4 +32,5 @@ "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true, "git.mergeEditor": false, + "zig.zls.enabled": "on", } diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..0e727c9 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,21 @@ +# woad.Zig - Authors + + +## Major Contributors + +| Name | GitHub | +| ----------- | --------------------------------- | +| Matt Wilson | [mwsis](https://github.com/mwsis) | + + +## Defect reports, fixes and suggestions (for which we are very grateful) + +| Name | GitHub | +| ------- | ------ | +| \ | | + + +Contributions are welcomed. + + + diff --git a/EXAMPLES.md b/EXAMPLES.md new file mode 100644 index 0000000..c637cdc --- /dev/null +++ b/EXAMPLES.md @@ -0,0 +1,9 @@ +# woad.Zig - Examples + + +| Name | Source | Summary | +| ----------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------- | +| **show_colours** | [examples/show_colours.zig](./examples/show_colours.zig) | Prints standard, bright, and background SGR samples via **woad** codes | + + + diff --git a/NEWS.md b/NEWS.md index 53fc92d..1547b3b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,9 @@ # woad.Zig - News + | Date | News Item | Details | | ------------------- | --------- | ------- | -| 18th September 2026 | [**woad.Zig** 0.0.1](https://github.com/synesissoftware/woad.Zig/releases/tag/0.0.1) | initial version | +| 18th September 2026 | [**woad.Zig** 0.0.1](https://github.com/synesissoftware/woad.Zig/releases/tag/0.0.1) | SGR colour and reset codes | diff --git a/README.md b/README.md index d341386..f870c41 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Minimal ANSI terminal colour codes, for Zig - [Introduction](#introduction) - [Installation](#installation) - [Components](#components) +- [Examples](#examples) - [Project Information](#project-information) - [Where to get help](#where-to-get-help) - [Contribution guidelines](#contribution-guidelines) @@ -68,13 +69,26 @@ exe.root_module.addImport("woad", woad_dep.module("woad")); const std = @import("std"); const woad = @import("woad"); -pub fn main() !void { - const stdout = std.io.getStdOut().writer(); +pub fn main(init: std.process.Init) !void { + var buffer: [256]u8 = undefined; + var stdout_impl = std.Io.File.stdout().writer(init.io, &buffer); + const stdout = &stdout_impl.interface; + try stdout.print("{s}ok{s}\n", .{ woad.FG_GREEN, woad.RESET }); + try stdout.flush(); } ``` +## Examples + +See [EXAMPLES.md](./EXAMPLES.md). Run the sample with: + +```bash +zig build run-example +``` + + ## Project Information @@ -110,6 +124,7 @@ None (currently). * [**woad**](https://github.com/synesissoftware/woad/) * [**woad.Go**](https://github.com/synesissoftware/woad.Go/) +* [**woad.NET**](https://github.com/synesissoftware/woad.NET/) * [**woad.Python**](https://github.com/synesissoftware/woad.Python/) * [**woad.Ruby**](https://github.com/synesissoftware/woad.Ruby/) * [**woad.Rust**](https://github.com/synesissoftware/woad.Rust/) diff --git a/TODO.md b/TODO.md index 373f160..cb43698 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,13 @@ # woad.Zig - TODO +## Table of Contents + +- [Functional improvements](#functional-improvements) +- [Performance improvements](#performance-improvements) +- [Packaging improvements](#packaging-improvements) + + ## Functional improvements * [x] ~~~SGR colour and reset codes~~~ - ✅; @@ -10,12 +17,12 @@ ## Performance improvements -* \ +* \ +* \ diff --git a/build.zig.zon b/build.zig.zon index 39d443d..2e6316c 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,13 +6,15 @@ .fingerprint = 0xa21e34833b201d51, .name = .woad, .paths = .{ + "AUTHORS.md", "CHANGES.md", + "EXAMPLES.md", "LICENSE", "NEWS.md", "README.md", "TODO.md", - "build.zig.zon", "build.zig", + "build.zig.zon", "examples", "src", },