Dein Agent sieht, wie der Code zusammenhängt
Was du davon hast
Dein Agent fragt nach Beziehungen statt nach Text. Wer ruft eine Funktion auf, was ruft sie selbst auf, was hängt an einer Änderung: greppy antwortet in einem Aufruf mit Datei, Zeile und dem Namen der Funktion. Der Agent ordnet keine Trefferzeilen mehr von Hand ihren Funktionen zu.
Vorher und nachher
Die Frage an serde: Wer ruft visit_content_map auf?
Ohne greppy
grep liefert Zeilen, keine Aufrufer. Der Agent sucht das Wort und ordnet danach jede Fundstelle der Funktion zu, in der sie steht.
$ grep -rnw visit_content_map --include='*.rs' .
./serde/src/private/de.rs:1103: fn visit_content_map<'de, V, E>(
./serde/src/private/de.rs:1152: Content::Map(v) => visit_content_map(v, visitor),
./serde/src/private/de.rs:1399: Content::Map(v) => visit_content_map(v, visitor),
./serde/src/private/de.rs:1415: Content::Map(v) => visit_content_map(v, visitor),
$ grep -n 'fn \|impl' serde/src/private/de.rs | awk -F: '$1>=1103 && $1<=1415'
1103: fn visit_content_map<'de, V, E>(
1120: impl<'de, E> Deserializer<'de> for ContentDeserializer<'de, E>
1126: fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
1156: fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
…
1394: fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
1404: fn deserialize_struct<V>(
Mit greppy
$ greppy who-calls visit_content_map
serde/src/private/de.rs:1152 ContentDeserializer::deserialize_any
serde/src/private/de.rs:1399 ContentDeserializer::deserialize_map
serde/src/private/de.rs:1415 ContentDeserializer::deserialize_struct
| ohne greppy | mit greppy | |
|---|---|---|
| Aufrufe | 2 | 1 |
| Zeichen Ausgabe | 2.569 | 204 |
| Token | 738 | 45 |
So funktioniert es
Einkompilierte tree-sitter-Parser zerlegen jede Datei in Definitionen. Daraus baut greppy einen typisierten Symbolgraph: Funktionen, Methoden und Typen sind Knoten, Aufrufe, Verwendungen, Typreferenzen und Imports sind Kanten. who-calls folgt den eingehenden Kanten eines Symbols, callees den ausgehenden. impact geht transitiv weiter und zeigt in einem Aufruf alles, was eine Änderung erreicht, path verbindet zwei Symbole über ihre Aufrufstellen. Vor jeder Abfrage gleicht greppy den Index mit dem Arbeitsbaum ab, die Antwort passt also zum aktuellen Stand deiner Dateien. Ist ein Name mehrfach definiert, qualifizierst du ihn mit seiner Datei, zum Beispiel serde_derive/src/de/struct_.rs::deserialize_map.
Die Befehle
| Befehl | was er tut |
|---|---|
greppy who-calls S |
wer S aufruft oder verwendet, mit Datei und Zeile; mehrere Symbole in einem Aufruf |
greppy callees S |
die indizierten Definitionen, die S direkt aufruft, mit ihrem Ort |
greppy impact S |
die transitive Reichweite in einem Aufruf: --direction incoming (Standard) zeigt, was bei einer Änderung bricht, outgoing, was S erreicht |
greppy path --from A --to B |
jede Aufrufkette zwischen zwei Symbolen als ein Baum ihrer Aufrufstellen |
greppy where-am-i |
das Repository auf einen Blick: Aufbau, Sprachen, Einstiegspunkte, Test-Verzeichnisse |
Mehr in der Doku
- Den Graph navigieren: alle Navigationsbefehle, Flags und Ausgabeformate
- So funktioniert greppy: Index, Graph und Embeddings
- Grenzen: was ein statischer Graph nicht sieht