{{ . | printf "%#v" }}
- Go 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Two small idiomatic tweaks: - Fold every AST type into one type ( ... ) block instead of the half-grouped, half-loose spelling. - Split main into run() int + os.Exit(run()) so defer works. The new bufio.NewWriter(os.Stdout) + defer out.Flush() needed this; os.Exit skips deferred calls and would have silently swallowed the last record. Also switches record output from fmt.Println(buf.String()) to buf.WriteTo(out) on the buffered writer \u2014 one syscall for the whole run instead of one per record. |
||
| docs | ||
| .gitignore | ||
| AGENTS.md | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| main_test.go | ||
| man.go | ||
| README.md | ||
gq — format Go %#v output like jq formats JSON
gq reads Go's Go-syntax value printing (as produced by
fmt.Printf("%#v", ...) or Go templates using printf "%#v") and prints
either a human-readable indented tree or JSON.
Licensed under Apache-2.0. See LICENSE.
Install
go install go.schlittermann.de/heiko/gq@latest
Usage
gq [--json] [--types] [--indent STR] [FILE...]
One input line = one top-level Go value. Reads stdin when no FILE is given.
Examples
Human-readable, jq-style:
podman image ls --format '{{. | printf "%#v" }}' | gq
JSON, pipe into jq:
podman image ls --format '{{. | printf "%#v" }}' | gq --json | jq '.Names'
Show Go types alongside values:
podman image ls --format '{{. | printf "%#v" }}' | gq --types
What it understands
Go %#v |
Meaning | JSON output |
|---|---|---|
main.T{F:v, ...} |
struct | object (field order) |
[]T{a, b, c} |
slice / array | array |
map[K]V{k:v, ...} |
map | object (source order) |
&main.T{...} |
pointer | inner value |
<nil> |
nil interface | null |
(*T)(nil) |
nil pointer | null |
[]T(nil), map[K]V(nil) |
nil slice/map | null |
"quoted" / `raw` |
string | JSON string |
42, 0x2a, 0b101 |
int | decimal integer |
3.14, 1e-3 |
float | JSON number |
'A' |
rune | integer code point |
true / false |
bool | true / false |
Anything that survives as raw Go source (custom GoString() methods like
time.Date(...), function values like (func())(0x1234), channels, etc.)
is preserved verbatim as a scalar in pretty mode, and emitted as a JSON
string in --json mode.
Why %#v and not %+v
%#v quotes strings, uses , as separator, and is (with one small
preprocessing step for <nil>) valid Go source. That means we hand
parsing off to go/parser, which is exact — no lookahead heuristics for
scalar boundaries. Strings containing spaces, colons, or braces are
handled correctly.
Limitations
- Extremely large truncated
%#voutput (some tools cap it) fails to parse;gqprints the parse error to stderr and moves on to the next line. - Byte slices come through as integer arrays in JSON. If you want
base64, pipe through
jqand do it there. - Fields with
GoStringerimplementations that don't return valid Go source stay as raw scalars.