Suchen
Die Suchbefehle von greppy ordnen sich nach einer Frage: Was weißt du über den Code, den du suchst?
| Du kennst | Befehl |
|---|---|
| was er tut, nicht seinen Namen | greppy search "WAS ER TUT" |
| seinen Namen oder einen Teil davon | greppy search-symbol NAME |
| wörtlichen Text, einen Config-Key, eine Meldung | greppy search-pattern REGEX |
| eine Mischung, und du willst eine Rangliste | greppy plus QUERY |
Alle vier nutzen die Exit-Codes von grep: 0 bei einem Treffer, 1 bei keinem. Die Beispiele laufen auf serde 1.0.229.
search: nach Bedeutung
greppy search "convert a field name to snake case"
greppy search collect errors and report them at the end --kind method
greppy search "collect errors and report them at the end" --path serde_derive/ --code
search bettet deine Beschreibung mit EmbeddingGemma ein und gibt die nächstliegenden Definitionen als Rangliste zurück. Jede Zeile nennt Ort, Namen und einen kurzen Zweck-Hinweis. Alles nach dem Verb wird zu einer Anfrage zusammengefügt, Anführungszeichen sind also optional. Die Rangliste hat acht Treffer, auch mit --all.
$ greppy search "convert a field name to snake case"
serde_derive/src/internals/case.rs:82 RenameRule::apply_to_field — converts a string field into a case variant
serde_derive/src/internals/case.rs:174 rename_fields — tests that case field renames apply to their original values test
serde_derive/src/internals/case.rs:57 RenameRule::apply_to_variant — converts a variant string to its canonical form
serde_derive/src/internals/case.rs:140 rename_variants — tests that apply_to_variant returns the expected name, type, and case for each variant test
serde_derive/src/internals/case.rs:9 RenameRule
serde_derive/src/internals/attr.rs:133 unraw — wraps an Ident into a new Ident with a trimmed string
serde_derive/src/internals/case.rs:45 RenameRule::from_str — looks up a named rule in RENAME_RULES
test_suite/tests/test_identifier.rs:160 newtype_fallthrough — tests that a newtype enum falls through to its token test
Die Anfrage nennt weder apply_to_field noch RenameRule. Der erste Treffer ist trotzdem die Methode, die eine Umbenennungsregel auf einen Feldnamen anwendet. --kind grenzt die Art der Definition ein:
$ greppy search collect errors and report them at the end --kind method
serde_derive/src/internals/ctxt.rs:62 Ctxt::drop — panics if errors are present and the thread is not panicking
serde_derive/src/internals/ctxt.rs:46 Ctxt::check — combines any pending errors into a single error
…
serde_derive/src/internals/ctxt.rs:41 Ctxt::syn_error — records a syn::Error into the errors collection
…
--json liefert zu jedem Treffer zusätzlich Signatur und Score, zum Beispiel "signature": "pub fn apply_to_field(self, field: &str) -> String" und "score": 0.5393914580345154.
Nimm die Treffer als Antwortkandidaten. Wähle den besten und antworte aus Symbol, Ort und Hinweis, die schon da sind, statt die Frage in eine weitere semantische Suche umzuformulieren. Meldet search keinen Treffer, ist ein search-pattern auf einen konkreten Begriff aus der Frage der nächste Schritt.
search findet auch Code, den der Graph nicht erreicht, etwa ein Reflection-Ziel oder einen generierten Handler, solange du beschreiben kannst, was er tut.
Während die Embeddings entstehen
Die Embeddings baut greppy nach dem Graphen im Hintergrund. Die erste semantische Abfrage in einem neuen Repository wartet, bis die einmaligen Embeddings veröffentlicht sind, und zeigt ihren Fortschritt auf stderr. Dann antwortet sie mit Exit-Code 0, ohne Teiltreffer.
$ greppy search "compress the ledger records"
semantic-search: semantic index building — 0/600 spans, ETA ~1m 15s (backend metal)
…
mod_05.py:300 compress_ledger_5_27 — compresses a list of items into a flat list of values
…
Die ausgelassenen stderr-Zeilen melden je Phase den Stand, etwa embedding: 256/600 spans; phase ETA about 20s, dazu PID, Worker-Zahl und den Befehl greppy --root DIR index status --json für Details.
Skripte warten, bis greppy index status --json mit 0 endet und sowohl "healthy": true als auch "embedding_complete": true meldet. Solange ein Build läuft, endet der Befehl mit 75.
search-symbol: nach Namen
greppy search-symbol rename
greppy search-symbol Rename --kind enum
search-symbol gibt die Definitionen zurück, deren Name NAME enthält, standardmäßig die ersten 20. Jede Zeile nennt die Art der Definition:
$ greppy search-symbol rename
test_suite/tests/ui/rename:1 serde.test_suite.tests.ui.rename folder test
serde_derive/src/internals/attr.rs:1386 get_renames function
serde_derive/src/internals/case.rs:174 rename_fields function test
serde_derive/src/internals/attr.rs:925 Variant::rename_by_rules method
…
$ greppy search-symbol Rename --kind enum
serde_derive/src/internals/case.rs:9 RenameRule enum
test_suite/tests/test_annotations.rs:614 RenameEnum enum test
test_suite/tests/test_annotations.rs:630 RenameEnumSerializeDeserialize enum test
Ein Fehlgriff endet mit 1 und bietet trotzdem die beste Stufe naher Treffer an, unter einer Überschrift wie similar names: oder closest by meaning:. Die Kaskade probiert Varianten in Groß- und Kleinschreibung und mit Unterstrichen, Editierdistanz, Wortüberlappung und zuletzt die Bedeutung:
$ greppy search-symbol apply_to_snake_case
status: no_matches
scope: indexed definitions in the repository
message: no definition named `apply_to_snake_case`
next: search source text: greppy search-pattern apply_to_snake_case --fixed
next: refresh definitions after source changes: greppy index .
similar names:
serde_derive/src/internals/case.rs:23 RenameRule::SnakeCase enum variant
serde_derive/src/internals/case.rs:82 RenameRule::apply_to_field method
serde_derive/src/internals/case.rs:57 RenameRule::apply_to_variant method
serde_derive/src/internals/case.rs:26 RenameRule::ScreamingSnakeCase enum variant
Vor einem Navigationsbefehl brauchst du search-symbol nicht: who-calls, impact, callees, brief und path nehmen den Namen direkt an.
search-pattern: nach Text
greppy search-pattern 'TODO|FIXME'
greppy search-pattern 'deny_unknown_fields' --fixed
greppy search-pattern 'deny_unknown_fields' --fixed --path serde_derive/ --all
search-pattern findet jede Stelle, auf die der reguläre Ausdruck passt, auch in Kommentaren, Strings und Konfiguration, und nennt die Definition, in der jeder Treffer liegt. --fixed nimmt das Muster als wörtlichen Text.
$ greppy search-pattern 'TODO|FIXME'
serde_core/src/private/mod.rs:5
serde_derive/src/de/enum_externally.rs:63 serde_derive/src/de/enum_externally.rs::Function::deserialize
serde_derive/src/de/enum_untagged.rs:32 serde_derive/src/de/enum_untagged.rs::Function::deserialize
…
serde_derive/src/de/struct_.rs:296 serde_derive/src/de/struct_.rs::Function::deserialize_map
serde_derive/src/de/struct_.rs:592 serde_derive/src/de/struct_.rs::Function::deserialize_map_in_place
Ein Muster mit vielen Treffern druckt die Anzahl und eine Stichprobe von fünf Zeilen. --all druckt jeden Treffer, --code jede getroffene Zeile wörtlich. --kind ordnet einen Texttreffer der Definition zu, in der er liegt.
$ greppy search-pattern 'deny_unknown_fields' --fixed
— 41 matches in 11 files; showing 5
serde_derive/src/internals/symbol.rs:13 serde_derive/src/internals/symbol.rs::Variable::DENY_UNKNOWN_FIELDS
test_suite/tests/regression/issue2792.rs:6
test_suite/tests/test_de.rs:107
test_suite/tests/test_de_error.rs:31
test_suite/tests/test_de_error.rs:39
Verfehlt ein Muster, das wie ein regulärer Ausdruck aussieht, wegen --fixed, nennt greppy das Flag und den passenden nächsten Befehl, Exit-Code 1:
$ greppy search-pattern 'deny_unknown_fields\b' --fixed
status: no_matches
scope: live Greppy-discovered source files in the repository
message: no matches
next: search excluded source directly: greppy rg -n -F 'deny_unknown_fields\b' .
reason: --fixed took the pattern literally, and it reads as a regular expression
next: search it as a regular expression: greppy search-pattern 'deny_unknown_fields\b'
next: search definition names: greppy search-symbol 'deny_unknown_fields\b'
Eine Zeile innerhalb einer Definition trägt einen qualifizierten Locator, den greppy read annimmt. Die umschließende Definition liest du damit direkt:
$ greppy read serde_derive/src/internals/attr.rs::Container::deny_unknown_fields
serde_derive/src/internals/attr.rs:563-565 Container::deny_unknown_fields
pub fn deny_unknown_fields(&self) -> bool {
self.deny_unknown_fields
}
plus: verschmolzene Rangliste
greppy plus "rename all fields" --k 5 --explain
plus kombiniert wörtliche und Volltext-Signale, Symbolnamen, unscharfe Bedeutung und Graph-Nachbarn zu einer Rangliste grep-artiger Zeilen datei:zeile:snippet. Das ist Suchausgabe, keine generierte Antwort. --k N setzt die Zahl der Treffer (Standard 10), --explain hängt an jede Zeile Score, Signale und Symbol an, --code druckt unter Treffern mit Symbol die umschließende Quelltext-Spanne:
$ greppy plus "rename all fields" --k 5 --explain
serde_derive/src/internals/symbol.rs:27:pub const RENAME_ALL_FIELDS: Symbol = Symbol("rename_all_fields"); # score=1.000 signals=fuzzy,fuzzy-token,symbol symbol=serde_derive/src/internals/symbol.rs::Variable::RENAME_ALL_FIELDS
test_suite/tests/test_macros.rs:782:fn test_rename_all_fields() { # score=0.936 signals=fuzzy,fuzzy-token,kind=code,symbol,vector symbol=test_suite/tests/test_macros.rs::Function::test_rename_all_fields
serde_derive/src/internals/attr.rs:555:pub fn rename_all_fields_rules(&self) -> RenameAllRules { # score=0.934 signals=fuzzy,fuzzy-token,kind=code,symbol,vector symbol=serde_derive/src/internals/attr.rs::Container::rename_all_fields_rules
serde_derive/src/internals/case.rs:174:fn rename_fields() { # score=0.873 signals=fuzzy,fuzzy-token,kind=code,vector symbol=serde_derive/src/internals/case.rs::Function::rename_fields
serde_derive/src/internals/attr.rs:940:pub fn rename_all_rules(&self) -> RenameAllRules { # score=0.872 signals=fuzzy,fuzzy-token,kind=code,vector symbol=serde_derive/src/internals/attr.rs::Variant::rename_all_rules
Eine Anfrage aus einem Wort überspringt das semantische Signal und rankt über die exakten Signale. greppy sagt das auf stderr:
$ greppy plus deny_unknown_fields --k 3 --explain
grep: skipped EmbeddingGemma for literal/exact query; using exact signals only
serde_core/src/de/impls.rs:2124:// #[serde(deny_unknown_fields)] # score=1.000 signals=text symbol=-
serde_core/src/de/impls.rs:2418:// #[serde(deny_unknown_fields)] # score=1.000 signals=text symbol=-
serde_core/src/de/impls.rs:2598:// #[serde(deny_unknown_fields)] # score=1.000 signals=text symbol=-
plus nimmt --k, --explain, --code und --json an. --kind, --path und --all gehören zu den anderen drei Suchbefehlen.
Gemeinsame Flags
Diese Flags gelten für search, search-symbol und search-pattern:
| Flag | Wirkung |
|---|---|
--kind K |
Ergebnisse einer Art: function, method, class, struct, enum oder trait. Einen anderen Wert ignoriert greppy mit einem Hinweis auf die gültigen Werte |
--path P |
Ergebnisse unterhalb dieser Datei oder dieses Verzeichnisses; wiederholbar |
--code |
druckt zusätzlich den Quelltext an jedem Ergebnis |
--all |
jedes Ergebnis statt der ersten; search bleibt bei acht Treffern |
--json |
dieselbe Antwort als Daten, mit exakten Zählern |
expand
Manche Ergebnisse bieten ein vorbereitetes Belegpaket an, etwa die letzte Zeile eines brief:
expand be76477a311cb85b — the call tree below expand_derive_deserialize sketched, 100 functions, 1186 lines
greppy expand ID druckt es in einem Aufruf, statt dass du jede Stelle datei:zeile einzeln öffnest. Mit --json steht das Angebot im Feld expand.
$ greppy expand be76477a311cb85b
serde_derive/src/de.rs:84
fn precondition(cx: &Ctxt, cont: &Container) {
85 precondition_sized
86 precondition_no_de_lifetime
}
serde_derive/src/de.rs:145
fn new(cont: &Container) -> Self {
147 this_type
148 this_value
149 borrowed_lifetimes
150 build_generics
}
…
Weiter zu read
greppy search-symbol apply_to_field --json | greppy read -
$ greppy search-symbol apply_to_field --json | greppy read -
serde_derive/src/internals/case.rs:81-109 RenameRule::apply_to_field
/// Apply a renaming rule to a struct field, returning the version expected in the source.
pub fn apply_to_field(self, field: &str) -> String {
match self {
None | LowerCase | SnakeCase => field.to_owned(),
UpperCase => field.to_ascii_uppercase(),
…
KebabCase => field.replace('_', "-"),
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
}
}