Features

Understand a function before you read it

What you get

Your agent first sees what a function does, how it is built and who calls it. brief delivers that in one call; read-smart shows the shape of a long function with one line per deep block. The agent then fetches the block it really needs with expand. It does not have to read 200 lines of source for that.

Before and after

The question for serde: What does deserialize_map do in the derive macro, how is it built, and who calls it?

Without greppy

The agent searches for the name, reads the whole function and maps the call site to its function.

$ grep -rnw deserialize_map serde_derive/src
serde_derive/src/de/struct_.rs:97:    let visit_map = Stmts(deserialize_map(
serde_derive/src/de/struct_.rs:115:                    _serde::Deserializer::deserialize_map(__deserializer, self)
serde_derive/src/de/struct_.rs:141:            _serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
serde_derive/src/de/struct_.rs:199:fn deserialize_map(
$ sed -n '199,/^}/p' serde_derive/src/de/struct_.rs
fn deserialize_map(
    struct_path: &TokenStream,
…
}
$ grep -n '^pub.*fn \|^fn ' serde_derive/src/de/struct_.rs
17:pub(super) fn deserialize(
199:fn deserialize_map(
…

Lines 115 and 141 are tokens in the generated code, not calls. The real call sits in deserialize (line 97).

With greppy

$ greppy brief serde_derive/src/de/struct_.rs::deserialize_map
Generates deserialization code for struct fields.

serde_derive/src/de/struct_.rs:199-205
fn deserialize_map(
…
) -> Fragment {
  210  field_i — creates an Ident for a field named after the index
…
  317  expr_is_missing — generates code for missing-field validation
…
}

called by deserialize
expand 986e0689aced6bf4 — the call tree below deserialize_map sketched, 7 functions, 59 lines
$ greppy read-smart serde_derive/src/de/struct_.rs::deserialize_map
serde_derive/src/de/struct_.rs:199-419  deserialize_map
…
    // Match arms to extract a value for a field.
    let value_arms = fields_names
        .iter()
        .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
        … 240-274 Generates deserialization code for a struct field. — greppy expand c53ffb0c7b71d241
…

brief sketches the flow in 19 lines; read-smart shows the 221 lines as 72 lines of shape. Every folded block carries its expand ID: greppy expand c53ffb0c7b71d241 returns exactly lines 240 to 274, again with folded sub-blocks.

without greppy with greppy
Calls 3 2
Output characters 8,419 3,699
Tokens 1,917 1,011

How it works

brief combines the graph, the source and the local model: it prints the function's purpose in one sentence, its signature verbatim, and then one line per call site or branch with the real symbol and its short description. The callers come from the symbol graph. Structs, enums and traits have no flow, so brief shows their whole definition. read-smart keeps a function's outer levels verbatim and folds every deeper block into one line with line range, description and expand ID; --depth N picks the level. The local model writes the descriptions from the source. Large results wait behind an expand ID, and greppy expand ID prints them in one call.

The commands

Command what it does
greppy brief S purpose in one sentence, signature, flow with one line per call or branch, then the callers
greppy read-smart S the definition with folded blocks, one line per block with line range, description and expand ID
greppy expand ID the prepared result of an earlier query, complete in one call

More in the docs