Skip to main content

gier: grep with code-block hierarchy awareness; chier is its companion for whole-file hierarchy queries.

Project description

gier — grep with code block hierarchy awareness

gier is grep with code block hierarchy awareness. chier is its small companion.

gier is a KISS command-line tool that tells you which code block a piece of code lives in — the enclosing function, class, and control flow — instead of just a bare line like plain grep. It grew out of watching coding agents (and people) poke around with grep and wish they could see the surrounding block hierarchy at a glance; the hope is simply that your friendly coding agent finds it useful. chier is the companion you reach for when you want the whole-file hierarchy or a direct "what encloses line N?" query.

Install

uv tool install gier

This installs both gier and chier onto your uv tool path, so you can run them directly (no uv run needed):

gier "def " "src/**/*.py"
chier -c 47 file.py

If you prefer pip: pip install gier.

The block-path syntax

This is the little language both tools speak, so it is worth knowing by heart. A block is written as:

<level>/<decl>{<start_line>,<start_col>~<end_line>,<end_col>}
  • / divides the level from the declaration.
  • <level> — 0-based nesting depth. 0 is the top level (outermost).
  • <decl> — the declaration: the keyword, plus the name for def/class/function definitions, with parameters and their brackets stripped. Examples: def abcd, class Foo, if, for, while, void foo, fn main, int main, (arrow), object:Foo, const o=.
  • {} wrap the coordinates.
  • <start_line>,<start_col> — the first character of the declaration (1-based line and column).
  • ~ separates start from end.
  • <end_line>,<end_col> — the last character of the block's last line (for curly-brace languages, that is the closing }).

When several blocks are reported together, they are joined by a relative marker that describes the relationship to the previous block:

marker meaning
> next block is a child (one level deeper)
` `
< next block is higher; the count of < is the number of levels ascended

Example (Python)

0/def abcd{21,1~61,20}>1/if{46,5~48,16}|1/for{52,5~59,18}<0/if{63,1~69,13}

Read left to right: top-level def abcd (line 21) has an if child (line 46) and a sibling for (line 52); then we ascend back to the top level for another if (line 63). The whole description is exactly one line — one tidy record per file, or per match — which is what makes it easy for an agent to parse.

gier — Grep code HIERarchy

gier [-iHh] [-M N] [-N N] PATTERN FILE [.. [FILE]]

For each FILE (expanded with Python's glob, so **/*.py works) every line matching the compiled PATTERN yields a finding:

  • inside a block → the enclosing block's hierarchy plus its source, exactly like a chier -c query;
  • outside any block (docstring, import, top-level statement) → a classic grep line path:line:code.

Options:

  • -i / --ignore-case — case-insensitive (re.IGNORECASE; re.MULTILINE is always set).
  • -H / --with-filename — always prefix path:.
  • -h / --no-filename — never prefix (overrides -H and the auto rule).
  • -N N / --min-block-length N (default 5) and -M N / --max-block-length N (default 20) — filter the code block; -M defaults to 20 so big blocks stay compact for agents.
  • --help — show usage.

The file name is printed (as path:) when -H is given, or automatically when the globs resolve to more than one file. Findings are separated by a -- line (only between findings, never after the last). Exit status: 0 match, 1 none, 2 error.

chier — Code HIERarchy

chier PATH [PATH ...]
chier (-p|-c) LINE PATH
  • -p LINE / --path-query LINE — print the chain of nested blocks enclosing LINE (root first, >-separated).
  • -c LINE / --code-query LINE — like -p, plus the block's source.
  • -N N / --min-block-length N (default 5) — blocks shorter than N lines merge into their parent, so you get the enclosing scope, not a one-liner.
  • -M N / --max-block-length N (default 99999) — blocks longer than N lines collapse to a single LINE:CODE line.
  • --exclude-fp-objects — by default a { after = : , [ return is treated as a block (capturing closures that look like object literals); pass this to revert to the stricter heuristic.
  • --help — show usage.

Library use

from gier import analyze

description = analyze(open("file.c").read(), path="file.c")

How it works

  • Python — the ast module turns each compound statement into a block; else/finally headers are recovered by scanning the source.
  • Curly-brace languages — a tiny tokenizer (skipping strings, comments, preprocessor lines) feeds a block matcher that pairs each declaration-{ with its closing }.

True to KISS, this is a deliberately simple heuristic: good recall on ordinary function / method / class / control-flow hierarchy, small readable code, and no pretense of being a full parser.

Tests

The suite in tests/ exercises both the library helpers and the CLI using real-world files from test-repos/ (a cloned repo is skipped when absent):

uv run python -m unittest discover -s tests -t . -v

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gier-0.0.1.tar.gz (16.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gier-0.0.1-py3-none-any.whl (20.1 kB view details)

Uploaded Python 3

File details

Details for the file gier-0.0.1.tar.gz.

File metadata

  • Download URL: gier-0.0.1.tar.gz
  • Upload date:
  • Size: 16.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gier-0.0.1.tar.gz
Algorithm Hash digest
SHA256 66103107d93501a4ac405bbbf422731caafab686b7fa9a276ed92e3ea5dedfa0
MD5 2997ea632f1034b1d9f76b1cc76e81a8
BLAKE2b-256 75890e32bdcfa45d28674c43423b9d307d85731850a767b2d408297fb14672bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for gier-0.0.1.tar.gz:

Publisher: publish.yml on jejay/gier

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gier-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: gier-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 20.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gier-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6faecc83bb31bb643f1ec96ded832af3bb0bbb2be77db50b230e25fd54beefcc
MD5 0fd2f10703202c8c0d7198819b4e78db
BLAKE2b-256 15e3f678e8c5045f0d06935bd4d6b8e628e403b1415f82d90ec2ad0a63d4c651

See more details on using hashes here.

Provenance

The following attestation bundles were made for gier-0.0.1-py3-none-any.whl:

Publisher: publish.yml on jejay/gier

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page