Skip to content

Commit 49beee1

Browse files
authored
feat: add runtime table builder and pretty-csv utility (#73)
* feat: add runtime table builder and pretty-csv utility Implements `TableBuilder` for dynamic row management during runtime. Introduces `pretty-csv` binary for rendering text tables from CSV/TSV data. Updates install script and documentation coverage. * feat(pretty-table): add DynTable for dynamic tables Refactor pretty-csv to use the new DynTable module instead of custom rendering logic. Remove duplicate width detection and truncation implementation to leverage library features. Update documentation to reflect changes in pretty-table and add new packages. * fmt * refactor(pretty-table): rename APIs and expand features Rename API types for semantic clarity: - Rename `TableBuilder(N)` to `Table(N).Owned`. - Rename `DynTable` to `RuntimeTable`. Add support for more complex data representations: - Add `transpose` mode and row separators to `Table(N)`. - Add footer support, per-column alignment, and `"{f}"` formatting to `RuntimeTable`. - Expose `--row-separator` and `--right-columns` flags to CLI tools. This enables flexible row representations and precise numerical alignment in reports. * fix(pretty-csv): remove column filtering limit Remove hardcoded 256 column limit in filtering by utilizing dynamic memory allocation. Previously, columns exceeding this threshold were silently truncated. Improve visual truncation accuracy by counting UTF-8 code points instead of bytes for accurate alignment and representation of multi-byte characters.
1 parent d75a726 commit 49beee1

File tree

10 files changed

+1909
-40
lines changed

10 files changed

+1909
-40
lines changed

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### New Programs
6+
- **pretty-csv**: Pretty-print CSV/TSV files as aligned tables
7+
- Auto-fits table width to terminal, truncates with ``
8+
- Three border styles: `ascii`, `box`, `dos`
9+
- Transpose mode (`-t`): show each record as vertical key-value block
10+
- Column selection (`-c 1,3,5`): display only specific columns
11+
- Row separators (`--row-separator`) and right-aligned selected columns (`-r 2,4`)
12+
- Configurable delimiter, padding, and max input size
13+
14+
### Improvements
15+
- **pretty-table**: `Table(N).Owned` runtime row helper with string shorthand and Cell-level control
16+
- `Table(N)` and `Table(N).Owned`: optional transpose mode
17+
- `RuntimeTable`: runtime column count with footer rows, header/footer cell setters, row separators, per-column alignment, `"{f}"` formatting, optional cell truncation, and UTF-8-safe truncation boundaries
18+
- Windows targets skip POSIX terminal-width probing during cross-compilation
19+
- **pretty-csv**: column filtering no longer truncates silently when CSV inputs exceed 256 columns
20+
21+
### Documentation
22+
- Added `gitignore` package docs
23+
- Updated `pretty-table` and `simargs` docs for Zig 0.15 API
24+
325
## v0.4.0 (2026-03-18)
426

527
### New Programs

build.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ fn buildBinaries(
119119
"tcp-proxy",
120120
"timeout",
121121
"cowsay",
122+
"pretty-csv",
122123
"zfetch",
123124
"progress",
124125
}) |name| {

docs/content/install.org

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ Then in your =build.zig=, import the module like this:
5151
#+begin_src zig
5252
const zigcli = b.dependency("zigcli", .{});
5353

54-
// Currently zigcli provide two packages.
54+
// Currently zigcli provides three packages.
5555
exe.root_module.addImport("simargs", zigcli.module("simargs"));
5656
exe.root_module.addImport("pretty-table", zigcli.module("pretty-table"));
57+
exe.root_module.addImport("gitignore", zigcli.module("gitignore"));
5758
#+end_src
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#+TITLE: gitignore
2+
#+DATE: 2026-03-20T08:45:00+0800
3+
#+LASTMOD: 2026-03-20T08:45:00+0800
4+
#+TYPE: docs
5+
#+WEIGHT: 30
6+
#+DESCRIPTION: Pure Zig .gitignore pattern matching — no libc dependency
7+
8+
* Features
9+
- Full [[https://git-scm.com/docs/gitignore][.gitignore spec]] support: =*=, =?=, =[abc]=, =**/=, negation (=!=)
10+
- Recursive =.gitignore= filtering via =GitignoreStack= (per-directory layers)
11+
- Pure Zig implementation — no =libc= =fnmatch= dependency
12+
- Last-match-wins semantics across all layers
13+
14+
* API
15+
16+
** =Gitignore=
17+
Parse a single =.gitignore= file and match paths against it.
18+
19+
#+begin_src zig
20+
const gitignore = @import("gitignore");
21+
22+
var gi = try gitignore.Gitignore.init(allocator, content);
23+
defer gi.deinit();
24+
25+
if (gi.shouldIgnore("build/output.o", false)) {
26+
// path is ignored
27+
}
28+
#+end_src
29+
30+
** =GitignoreStack=
31+
Manage a stack of =.gitignore= layers for recursive directory walks.
32+
Each layer is anchored to its directory, and patterns are evaluated with
33+
correct relative paths.
34+
35+
#+begin_src zig
36+
const gitignore = @import("gitignore");
37+
38+
var stack = gitignore.GitignoreStack.init();
39+
defer stack.deinit(allocator);
40+
41+
// Push a layer when entering a directory.
42+
const pushed = try stack.tryPushDir(dir, rel_dir, allocator);
43+
44+
if (stack.shouldIgnore(rel_path, is_dir)) {
45+
// path is ignored
46+
}
47+
48+
// Pop when leaving the directory.
49+
if (pushed) stack.pop(allocator);
50+
#+end_src
51+
52+
* Used by
53+
- =tree=: Respects =.gitignore= when listing directory trees.
54+
- =loc=: Skips ignored files when counting lines of code.

0 commit comments

Comments
 (0)