This repository contains hikkoshi, a Zig CLI tool for running commands under profile-specific HOME/XDG environments.
src/– main implementation (main.zig,config.zig,env.zig,root.zig).docs/– design notes and CLI/semantics (docs/design.md).zig-out/and.zig-cache/– build outputs and cache; never edit these by hand.
zig build– build and installhikkoshiintozig-out/bin/hikkoshi.zig build run -- <args>– build and run the CLI, e.g.zig build run -- example nvim.zig build test– run all Zig tests defined in the library and CLI modules.
- Language: Zig, using the standard library and idioms from
std. - Formatting: run
zig fmt src/*.zigbefore committing. - Naming:
PascalCasefor types,snake_casefor functions and variables, constants inALL_CAPSonly when they are process-wide. - Principle: code is for humans first; keep functions small, error messages explicit, and control flow straightforward.
- Prefer small, focused
testblocks near the code they exercise. - Use deterministic inputs; avoid tests that depend on external files or network.
- Ensure
zig build testpasses before opening a pull request.
- Follow a lightweight conventional style, e.g.
feat: add list subcommand,fix: handle missing HOME,chore: update docs. - Each pull request should describe the motivation, main changes, and any user-visible CLI or config behavior differences.
- If you change semantics, update
docs/design.mdand include examples or usage notes.
- When using automated tools or assistants, prefer editing
src/anddocs/and avoid touching build output directories. - Keep dependencies minimal; if you add a new Zig package, update both
build.zigandbuild.zig.zonconsistently.
-
Stdout/Stderr Writer API
- Do not use
std.io.getStdOut()/std.io.getStdErr()here; Zig 0.15.2’s stdlib exposes writers viastd.fs.Filewith an explicit buffer. - Preferred pattern for CLI output:
var buf: [1024]u8 = undefined; var file_writer = std.fs.File.stdout().writer(&buf); const out = &file_writer.interface; defer out.flush() catch {}; try out.print("...", .{});
- Use the same pattern for stderr with
std.fs.File.stderr().
- Do not use
-
ArrayList Usage
std.ArrayList(T)in 0.15.2 is an alias to the managed array list type; it does not have a staticinit(allocator)constructor.- If you really need an
ArrayList, allocate via:var list: std.ArrayList(T) = .empty; // or: var list = try std.ArrayList(T).initCapacity(allocator, n);
- For simple path building, avoid
ArrayList; prefer a small fixed array plusstd.fs.path.join(as insrc/env.zig), to keep code and ownership simpler.
-
Sorting API (
std.sort)- There is no generic
std.sort.sortfunction in Zig 0.15.2; use concrete algorithms such asstd.sort.block/std.sort.heap/std.sort.pdq. - Example for sorting a slice of strings:
std.sort.block([]const u8, names, {}, struct { fn lessThan(_: void, a: []const u8, b: []const u8) bool { return std.mem.lessThan(u8, a, b); } }.lessThan);
- Make sure the slice you pass to
blockis mutable ([][]const u8is fine;[]const []const u8is not).
- There is no generic
-
Interactive stdin (yes/no prompts)
Io.Readerin 0.15.2 does not providereadByte; preferreadSliceShortwith a 1‑byte buffer for simpley/nstyle prompts.- Recommended pattern:
const stdin_file = std.fs.File.stdin(); var stdin_buf: [1024]u8 = undefined; var stdin_reader = stdin_file.reader(&stdin_buf); const stdin = &stdin_reader.interface; var answer_buf: [1]u8 = undefined; const count = stdin.readSliceShort(&answer_buf) catch |err| { if (err == error.EndOfStream) return false; return err; }; if (count == 0) return false; const ch = answer_buf[0]; const yes = (ch == 'y' or ch == 'Y');
- 对交互式 CLI 提示(如“是否创建配置文件?[y/N]”),建议先检测
stdin_file.isTty(),避免在管道或脚本环境中阻塞等待输入。