a simple pretty printer for arbitrary data structures in Zig⚡️
designed to inspect deeply-nested and recursive tree structures.
latest (zip) (tar) tested on 0.14.0-dev.1511+54b668f8a
0.13.0
compatible (zip) (tar) (branch)
previous (list)
simplified version of src/demo.zig
:
// main.zig
const std = @import("std");
const pretty = @import("pretty.zig");
const alloc = std.heap.page_allocator;
pub fn main() !void {
const array = [3]u8{ 4, 5, 6 };
// method 1: print with default options
try pretty.print(alloc, array, .{});
// method 2: customize your print
try pretty.print(alloc, array, .{
.array_show_item_idx = false,
.inline_mode = true,
});
// method 3: don't print, get a string!
var out = try pretty.dump(alloc, array, .{});
defer alloc.free(out);
std.debug.print("{s}..\n", .{out[0..5]});
}
output:
$ zig run main.zig
[3]u8
[0]: 4
[1]: 5
[2]: 6
[3]u8{ 4, 5, 6 }
[3]u8..
there are three ways to use pretty:
git clone https://github.com/timfayz/pretty
,cd pretty
andzig build run
, or- download latest version of
pretty.zig
and@import
it directly inside your project, or - use zig build system and
build.zig.zon
(highly undocumented):
$ cd your_project
$ ls
src/
build.zig # should be present (otherwise use `zig init` to generate it)
build.zig.zon # optional (otherwise will be generated by the next command)
$ zig fetch --save https://github.com/timfayz/pretty/archive/refs/heads/main.tar.gz
$ cat build.zig.zon
..
.pretty = .{
.url = "https://github.com/timfayz/pretty/archive/refs/heads/main.tar.gz",
.hash = "..long_hash..",
},
..
edit build.zig
:
// find this:
const exe = b.addExecutable(.{
.name = "your_app",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
// add the following:
const pretty = b.dependency("pretty", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("pretty", pretty.module("pretty"));
..
done, build or run your project:
$ zig build # or zig build run
pretty offers four main functions:
pretty.print
– print formatted string to stdout.pretty.printInline
– print formatted string with.inline_mode
switched on.pretty.dump
– generate formatted string and return it as[]u8
slice.pretty.dumpList
– generate formatted string and return it asstd.ArrayList
interface.
pretty output can be customized with the following options (default values in the option code):
- activate single line printing mode:
inline_mode: bool = false
- limit the printing depth (0 does not limit):
max_depth: u8 = 10
- specify depths to include or exclude from the output:
filter_depths: Filter(usize) = .{ .exclude = &.{} }
- indentation size for multi-line printing mode:
tab_size: u8 = 2
- add extra empty line at the end of print (to stack up multiple prints):
print_extra_empty_line: bool = false
- indicate empty output with a message (otherwise empty output length is 0):
indicate_empty_output: bool = true
- specify a custom format string (eg.
pre{s}post
) to surround the resulting output:
fmt: []const u8 = ""
- show type tags (ie.
std.builtin.TypeId
, such as.Union
,.Int
):
show_type_tags: bool = false
- show type names:
show_type_names: bool = true
- limit the length of type names (0 does not limit):
type_name_max_len: usize = 60
- specify depth of folding parentheses in type names (0 does not fold):
type_name_fold_parens: usize = 1
- refine depth of folding parentheses in function signatures (0 does not fold):
type_name_fold_parens_fn: usize = 2
- refine depth of folding parentheses for special case
@TypeOf(..)
(0 does not fold):
type_name_fold_parens_type_of: usize = 2
- show values:
show_vals: bool = true
- show empty values:
show_empty_vals: bool = true
- follow pointers instead of printing their address:
ptr_deref: bool = true
- reduce duplicating depths when dereferencing pointers:
ptr_skip_dup_unfold: bool = true
- treat
[*:sentinel]T
as array (except[*:0]u8
, see.ptr_many_u8z_is_str
instead:
ptr_many_with_sentinel_is_array: bool = true
- reduce duplicating depths when unfolding optional types:
optional_skip_dup_unfold: bool = true
- show struct fields:
struct_show_field_names: bool = true
- treat empty structs as having
(empty)
value:
struct_show_empty: bool = true
- inline primitive type values to save vertical space:
struct_inline_prim_types: bool = true
- limit the number of fields in the output (0 does not limit):
struct_max_len: usize = 15
- specify field names to include or exclude from the output:
filter_field_names: Filter([]const u8) = .{ .exclude = &.{} }
- specify field type tags to include or exclude from the output:
filter_field_type_tags: Filter(std.builtin.TypeId) = .{ .exclude = &.{} }
- specify field types to include or exclude from the output:
filter_field_types: Filter(type) = .{ .exclude = &.{} }
- limit the number of items in the output (0 does not limit):
array_max_len: usize = 20
- show item indices:
array_show_item_idx: bool = true
- inline primitive types to save vertical space:
array_inline_prim_types: bool = true
- show primitive types' type information (name and tag):
array_show_prim_type_info: bool = false
- specify type tags to treat as primitives:
prim_type_tags: Filter(std.builtin.TypeId) = .{ .include = &.{
.Int,
.ComptimeInt,
.Float,
.ComptimeFloat,
.Void,
.Bool,
} }
- specify concrete types to treat as primitives:
prim_types: Filter(type) = .{ .include = &.{} }
- print u21 as a 'c'odepoint literal:
u21_is_codepoint = true
- limit the length of strings (0 does not limit):
str_max_len: usize = 80
- treat
[]u8
as"string"
:
slice_u8_is_str: bool = true
- treat
[:0]u8
as"string"
:
slice_u8z_is_str: bool = true
- treat
[n]u8
as"string"
:
array_u8_is_str: bool = false
- treat
[n:0]u8
as"string"
:
array_u8z_is_str: bool = true
- treat
[*:0]u8
as"string"
:
ptr_many_u8z_is_str: bool = true
derived from src/tests.zig
:
const value: struct {
field1: bool = true,
field2: u8 = 42,
field3: f32 = 1.1,
} = .{};
try pretty.printInline(alloc, value, .{});
file.main__struct_1472{ .field1: bool = true, .field2: u8 = 42, .field3: f32 = 1.1e0 }
try pretty.print(alloc, value, .{});
file.main__struct_1652
.field1: bool => true
.field2: u8 => 42
.field3: f32 => 1.1e0
use filter_*
options to "query" or cut off unnecessary output:
try pretty.print(alloc, value, .{
.filter_depths = .{ .exclude = &.{ 0, 2 } },
});
.field1: bool
.field2: u8
.field3: f32
try pretty.print(alloc, value, .{
.filter_depths = .{ .include = &.{2} },
});
true
42
1.1e0
try pretty.print(alloc, value, .{
.filter_depths = .{ .exclude = &.{0} },
.filter_field_names = .{ .include = &.{"field2"} },
});
.field2: u8 => 42
please feel free to:
- open an issue and describe the change you'd like to see.
- fork the repository and submit your pull request.
all codebase are belong to MIT.