Quelltext lesen
greppy liest nach Symbol oder nach Pfad. Ein Symbol-Read liefert die exakten Quelltext-Bytes der Definition. Ein Datei-Read liefert Zeilenbereiche, Seiten oder bei einer langen Quelldatei ihre Gliederung. Jeder Read druckt auf Wunsch ein Handle, das genau die gedruckte Spanne für einen späteren Edit festhält.
| Befehl | Liefert |
|---|---|
greppy read S [S …] |
den Quelltext jeder Definition, Byte für Byte |
greppy read-smart S [S …] |
den Quelltext, verschachtelte Blöcke zu einzeiligen Beschreibungen gefaltet |
greppy read-file PATH [PATH …] |
Dateiinhalt: einen Zeilenbereich, alles oder Seiten zu 400 Zeilen; eine lange indexierte Quelldatei ohne Bereich zeigt ihre Gliederung |
Die Beispiele laufen auf serde 1.0.229.
read
greppy read RenameRule::apply_to_variant
greppy read Ctxt::new Ctxt::check
greppy read deserialize_body --head 6 # die ersten 6 Zeilen
greppy read deserialize_body --tail 4 # die letzten 4 Zeilen
greppy read RenameRule::or --handle # zusätzlich ein Edit-Handle
read druckt jede Definition als Quelltext-Bytes, mit der Kopfzeile datei:start-ende name. Dazu gehören die Dokumentation und die Attribute, die der Parser an die Definition hängt, etwa Rust-Kommentare /// und Attribute #[…] oder Python-Dekoratoren:
$ greppy read Ctxt::new Ctxt::check
serde_derive/src/internals/ctxt.rs:19-26 Ctxt::new
/// Create a new context object.
///
/// This object contains no errors, but will still trigger a panic if it is not `check`ed.
pub fn new() -> Self {
Ctxt {
errors: RefCell::new(Some(Vec::new())),
}
}
serde_derive/src/internals/ctxt.rs:45-58 Ctxt::check
/// Consume this object, producing a formatted error string if there are errors.
pub fn check(self) -> syn::Result<()> {
let mut errors = self.errors.borrow_mut().take().unwrap().into_iter();
…
Err(combined)
}
$ greppy read deserialize_in_place_body
serde_derive/src/de.rs:377-380 deserialize_in_place_body
#[cfg(not(feature = "deserialize_in_place"))]
fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option<Stmts> {
None
}
Einfache //-Kommentare über einer Funktion gehören nicht zur Definition, in Rust wie in Go. Über build_generics in serde_derive/src/ser.rs stehen zwei solche Zeilen, greppy read serde_derive/src/ser.rs::build_generics beginnt bei Zeile 135 mit der Signatur.
--head und --tail schneiden jede Definition zu, die Kopfzeile nennt den gedruckten Bereich:
$ greppy read deserialize_body --tail 4
serde_derive/src/de.rs:327-330 deserialize_body
Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"),
}
}
}
Einen mehrfach definierten Namen qualifizierst du mit seiner Datei. Die Mehrdeutigkeit nennt dir für jede Definition den passenden Befehl und endet mit Exit-Code 1:
$ greppy read from_ast
`from_ast` is 4 definitions
serde_derive/src/internals/ast.rs:62 serde_derive/src/internals/ast.rs::Container::from_ast — greppy read serde_derive/src/internals/ast.rs::Container::from_ast
serde_derive/src/internals/attr.rs:237 serde_derive/src/internals/attr.rs::Container::from_ast — greppy read serde_derive/src/internals/attr.rs::Container::from_ast
serde_derive/src/internals/attr.rs:748 serde_derive/src/internals/attr.rs::Variant::from_ast — greppy read serde_derive/src/internals/attr.rs::Variant::from_ast
serde_derive/src/internals/attr.rs:1015 serde_derive/src/internals/attr.rs::Field::from_ast — greppy read serde_derive/src/internals/attr.rs::Field::from_ast
--path wählt ebenfalls unter gleichnamigen Definitionen: greppy read from_ast --path serde_derive/src/internals/ast.rs liest Container::from_ast aus ast.rs.
read nimmt Symbole, keine Zeilenbereiche. Bekommt es einen Dateipfad, druckt es die Definitionen der Datei mit ihren qualifizierten Namen und die nächsten Befehle, nicht den Dateitext:
$ greppy read serde_derive/src/internals/ctxt.rs
`serde_derive/src/internals/ctxt.rs` is a file — read a symbol:
serde_derive/src/internals/ctxt.rs:12 serde_derive/src/internals/ctxt.rs::Class::Ctxt class
serde_derive/src/internals/ctxt.rs:22 serde_derive/src/internals/ctxt.rs::Ctxt::new method
serde_derive/src/internals/ctxt.rs:31 serde_derive/src/internals/ctxt.rs::Ctxt::error_spanned_by method
serde_derive/src/internals/ctxt.rs:41 serde_derive/src/internals/ctxt.rs::Ctxt::syn_error method
serde_derive/src/internals/ctxt.rs:46 serde_derive/src/internals/ctxt.rs::Ctxt::check method
serde_derive/src/internals/ctxt.rs:62 serde_derive/src/internals/ctxt.rs::Ctxt::drop method
read one: greppy read serde_derive/src/internals/ctxt.rs::Class::Ctxt · lines: greppy read-file serde_derive/src/internals/ctxt.rs --lines A:B
read-smart
greppy read-smart RenameRule::apply_to_variant
greppy read-smart RenameRule::apply_to_variant --depth 2
read-smart lässt Blöcke oberhalb der angegebenen Strukturtiefe roh und faltet die Blöcke auf dieser Tiefe zu einzeiligen Beschreibungen. Die Standardtiefe ist 1. Jede gefaltete Zeile nennt ihren Zeilenbereich und eine expand-ID für den verborgenen Block. So siehst du die Form einer langen Funktion, bevor du den Teil liest, den du brauchst:
$ greppy read-smart RenameRule::apply_to_variant
serde_derive/src/internals/case.rs:56-79 RenameRule::apply_to_variant
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
pub fn apply_to_variant(self, variant: &str) -> String {
… 58-78 Converts a variant into its canonical form. — greppy expand 55fb8674dc2a501a
}
$ greppy read-smart RenameRule::apply_to_variant --depth 2
serde_derive/src/internals/case.rs:56-79 RenameRule::apply_to_variant
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
pub fn apply_to_variant(self, variant: &str) -> String {
match self {
None | PascalCase => variant.to_owned(),
LowerCase => variant.to_ascii_lowercase(),
UpperCase => variant.to_ascii_uppercase(),
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
… 63-72 Builds a snake case string from variant characters. — greppy expand 78207fd6ca1ef576
…
expand öffnet einen gefalteten Block wieder gefaltet, Ebene für Ebene:
$ greppy expand 78207fd6ca1ef576
SnakeCase => {
let mut snake = String::new();
… 65-70 Converts a character sequence into lowercase snake case using variant characters. — greppy expand 63c6b28b84f5e000
snake
}
read-file
greppy read-file serde_derive/src/internals/case.rs --lines 112:118 # inklusiv, ab 1 gezählt
greppy read-file serde_derive/src/internals/case.rs --all # jede Zeile
greppy read-file serde_derive/src/internals/case.rs # siehe unten
Für Pfade nimmst du read-file. Mit --lines oder --all druckt es genau diesen Text:
$ greppy read-file serde_derive/src/internals/case.rs --lines 112:118
serde_derive/src/internals/case.rs:112-118
pub fn or(self, rule_b: Self) -> Self {
match self {
None => rule_b,
_ => self,
}
}
}
Gibst du weder --lines noch --all an, gelten diese Regeln:
- Eine Datei mit bis zu 60 Zeilen erscheint ganz.
serde_derive/src/de/unit.rshat 52 Zeilen und kommt alsserde_derive/src/de/unit.rs:1-52. - Eine längere indexierte Quelldatei zeigt ihre Gliederung, dieselbe Definitionsliste mit den nächsten Befehlen wie
greppy read PATH.--outlinefordert sie ausdrücklich an. - Jede andere Datei erscheint in Seiten zu 400 Zeilen. Eine gekürzte Seite endet mit der Fortsetzung, für eine Datei mit 551 Zeilen etwa
151 more lines — greppy expand cb724cce764197c4 continues at 401.
$ greppy read-file serde_derive/src/internals/case.rs
Source outline for `serde_derive/src/internals/case.rs` — fingerprint-verified indexed definitions:
serde_derive/src/internals/case.rs:9 serde_derive/src/internals/case.rs::Enum::RenameRule enum
serde_derive/src/internals/case.rs:45 serde_derive/src/internals/case.rs::RenameRule::from_str method
serde_derive/src/internals/case.rs:57 serde_derive/src/internals/case.rs::RenameRule::apply_to_variant method
serde_derive/src/internals/case.rs:82 serde_derive/src/internals/case.rs::RenameRule::apply_to_field method
serde_derive/src/internals/case.rs:112 serde_derive/src/internals/case.rs::RenameRule::or method
serde_derive/src/internals/case.rs:120 serde_derive/src/internals/case.rs::Class::ParseError class
serde_derive/src/internals/case.rs:125 serde_derive/src/internals/case.rs::ParseError::fmt method
serde_derive/src/internals/case.rs:140 serde_derive/src/internals/case.rs::Function::rename_variants function
serde_derive/src/internals/case.rs:174 serde_derive/src/internals/case.rs::Function::rename_fields function
read one: greppy read serde_derive/src/internals/case.rs::Enum::RenameRule · lines: greppy read-file serde_derive/src/internals/case.rs --lines A:B
Pfade dürfen relativ zum Repository oder absolut sein. Ein relativer Weg mit ../ bleibt im Repository eingeschlossen und endet außerhalb mit no such file. Ein ausdrücklich absoluter Pfad außerhalb, etwa ein heruntergeladenes Build-Artefakt, funktioniert.
Exakte Reads mit --lines und --all brauchen den Graph-Store nicht. Sie laufen also auch, während ein Repository indexiert wird.
Handles
--handle an read, read-smart oder read-file druckt zur gedruckten Spanne ein Handle. Ein Handle hält Datei, Byte-Bereich und Inhalts-Hashes fest. Es benennt genau die gedruckte Spanne: Bei gekürzter Ausgabe deckt es den gezeigten Teil ab.
$ greppy read RenameRule::or --handle
serde_derive/src/internals/case.rs:111-117 RenameRule::or
/// Returns the `RenameRule` if it is not `None`, `rule_b` otherwise.
pub fn or(self, rule_b: Self) -> Self {
match self {
None => rule_b,
_ => self,
}
}
handle: geh2:AgpflQfNuU6DcfwlKqLlHpwi1QVrm02DIQ
Gefalteter Quelltext ist keine exakte Spanne. Für ihn druckt read-smart --handle statt eines Handles den Weg zu einem:
$ greppy read-smart RenameRule::or --handle
serde_derive/src/internals/case.rs:111-117 RenameRule::or
/// Returns the `RenameRule` if it is not `None`, `rule_b` otherwise.
pub fn or(self, rule_b: Self) -> Self {
… 113-116 Returns rule_b when self is None, otherwise self. — greppy expand 9eafa1d9fda51840
}
note: no edit handle for folded source; request greppy read SYMBOL --handle or read-file PATH --lines A:B --handle
Das Handle gibst du an replace-span, statt den Code noch einmal zu suchen:
greppy read RenameRule::or --handle
greppy replace-span H < or_if.rs
replace-span schreibt nichts, wenn sich die Datei seit dem Druck des Handles geändert hat. Ein Beispiel mit Quittung steht unter Transaktional editieren.
Aus einer Abfrage weiterlesen
Jeder Befehl nimmt seine Eingabe auch aus der Pipe, Such- und Navigationsergebnisse gehen direkt in einen Read:
greppy search-symbol apply_to_field --json | greppy read -
greppy callees visit_content_map --json | greppy read -
$ greppy callees visit_content_map --json | greppy read -
serde/src/private/de.rs:1608-1615 MapDeserializer::new
fn new(content: Vec<(Content<'de>, Content<'de>)>) -> Self {
MapDeserializer {
iter: content.into_iter(),
value: None,
count: 0,
error: PhantomData,
}
}
Ausgabe-Flags
| Flag | Wirkung |
|---|---|
--handle |
druckt zu jeder gedruckten Spanne ein Edit-Handle |
--path P |
Ergebnisse unterhalb dieser Datei oder dieses Verzeichnisses; wiederholbar. Bei read wählt es auch unter gleichnamigen Definitionen |
--max-bytes N |
ein hartes Budget für die gedruckte Nutzlast |
--root DIR |
liest aus einem anderen Repository |
Ein Budget kürzt den Inhalt vor den Status- und Fortsetzungszeilen. Die Antwort sagt, wie es weitergeht:
$ greppy read RenameRule::apply_to_variant --max-bytes 300
truncated: true
total: 25
offset: 0
try: greppy read RenameRule::apply_to_variant --max-bytes 300 --offset 2
serde_derive/src/internals/case.rs:56-79 RenameRule::apply_to_variant
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
Frische
Reads liefern die aktuellen Bytes, nie eine veraltete Spanne. Passen die indexierten Spannen nicht mehr zur Datei, frischt greppy den Graphen auf oder bricht sicher ab und sagt, wann du es erneut versuchst. Während der Graph aufgefrischt wird, meldet read einen vorübergehenden Fehler, statt aktuelle Bytes mit einer alten Spanne zu paaren.