
# Textsuche

Der Textmodus von Greph durchsucht einen durchsuchten Dateibaum zeilenweise nach Bytes. Er ist der Standardmodus der `greph`-CLI und der `Greph::searchText()`-Fassade. Die Ausgabe verwendet das kanonische Format `file:line:content`, das grep, ripgrep und die meisten Editorintegrationen verarbeiten können.

## Schnellbeispiele

```bash
# Regex search across the current directory
./vendor/bin/greph "function\s+\w+"

# Fixed-string search across src/
./vendor/bin/greph -F "function" src

# Case-insensitive whole-word search
./vendor/bin/greph -F -i -w "function" src

# Two lines of context around each match
./vendor/bin/greph -F -C 2 "TODO" src

# Stop after the first three matches per file
./vendor/bin/greph -F -m 3 "TODO" src

# Files that contain the pattern
./vendor/bin/greph -F -l "TODO" src

# Files that do not contain the pattern
./vendor/bin/greph -F -L "TODO" src

# Count matches per file
./vendor/bin/greph -F -c "TODO" src

# Inverted match
./vendor/bin/greph -F -v "TODO" src/notes.txt
```

## Muster

Standardmäßig wird das Muster als regulärer PCRE2-Ausdruck behandelt. Die Funktionen `preg_*` von PHP bilden die Grundlage der Engine, daher entspricht die Syntax der [PHP PCRE-Referenz](https://www.php.net/manual/en/pcre.pattern.php).

Deaktiviere die Regex-Engine mit `-F`, um das Muster als literale Bytefolge zu behandeln. Der Modus für feste Zeichenfolgen ist der schnelle Pfad: Er verwendet `strpos()` für den Abgleich und überspringt den PCRE2-Kompilierschritt vollständig.

`-i` macht beide Modi unabhängig von Groß- und Kleinschreibung. `-w` fügt auf beiden Seiten des Treffers Wortgrenzen hinzu.

## Dateien filtern

Greph durchläuft den Dateibaum vor der Suche. Der Datei-Scanner wird mit dem AST-Modus und dem Indexmodus geteilt, daher gelten dieselben Filteroptionen überall.

| Option | Wirkung |
|---|---|
| `--type NAME` | Nur Dateien einschließen, die dem benannten Typalias entsprechen (`php`, `js`, `md`, ...) |
| `--type-not NAME` | Dateien ausschließen, die dem benannten Typalias entsprechen |
| `--glob GLOB` | Nur Dateien einschließen, deren Pfade auf GLOB passen. Wiederholbar. |
| `--no-ignore` | `.gitignore` oder `.grephignore` nicht beachten |
| `--hidden` | Versteckte Dateien einschließen |

Der Datei-Scanner beachtet standardmäßig `.gitignore` und `.grephignore`, überspringt Binärdateien (erkannt anhand von Nullbytes in den ersten 512 Bytes) und begrenzt die Dateigröße auf 10 MiB. Beide Grenzwerte lassen sich über `WalkOptions` konfigurieren.

Eine vollständige Liste der integrierten Typaliasse findest du unter [API / FileTypeFilter](https://greph.inline0.dev/de/docs/api#grephwalkerfiletypefilter).

## Kontext, Trefferzahlen und reine Dateimodi

```bash
# Two lines before and after each match
./vendor/bin/greph -F -C 2 "needle" src

# Two lines after, no lines before
./vendor/bin/greph -F -A 2 "needle" src

# Two lines before, no lines after
./vendor/bin/greph -F -B 2 "needle" src

# Count matches per file
./vendor/bin/greph -F -c "needle" src

# List matching files only
./vendor/bin/greph -F -l "needle" src

# List non-matching files only
./vendor/bin/greph -F -L "needle" src
```

`-c`, `-l` und `-L` umgehen den Formatierer direkt und vermeiden so, jede Zeile im Speicher abzulegen. Sie eignen sich für Abfragen wie „wie viele“ und „wo“.

## Parallele Scans

Übergib `-j N`, um den Scan auf N Worker zu verteilen. Greph verwendet `pcntl_fork()` für den Worker-Pool und greift auf die Ausführung in einem einzelnen Prozess zurück, wenn `ext-pcntl` nicht verfügbar ist.

```bash
./vendor/bin/greph -F -j 8 "function" src
```

Die Fassade berechnet anhand der Dateianzahl, des Modus und der Musterform, ob sich parallele Ausführung lohnt. Unterhalb des Schwellenwerts bleibt sie bei einem einzelnen Prozess. Die Heuristiken findest du unter [Advanced / Parallel Workers](https://greph.inline0.dev/de/docs/advanced/parallel).

## JSON-Ausgabe

`--json` gibt eine strukturierte Nutzlast aus, die nachgelagerte Werkzeuge ohne Auslesen des Bildschirmausgabeformats von grep verarbeiten können:

```bash
./vendor/bin/greph --json -F "function" src
```

```json
[
  {
    "file": "src/Greph.php",
    "matches": [
      {
        "line": 31,
        "column": 1,
        "content": "final class Greph",
        "matched_text": "function",
        "captures": []
      }
    ]
  }
]
```

Der Wrapper `rg` gibt stattdessen Ereignisse im Format von ripgrep als JSON aus. Verwende ihn, wenn ein vorhandener Verbraucher das ripgrep-Schema erwartet.

## Programmatische Verwendung

```php
use Greph\Greph;
use Greph\Text\TextSearchOptions;

$results = Greph::searchText(
    'function',
    'src',
    new TextSearchOptions(
        fixedString: true,
        caseInsensitive: true,
        beforeContext: 1,
        afterContext: 1,
        jobs: 4,
    ),
);

foreach ($results as $file) {
    foreach ($file->matches as $match) {
        echo "{$file->file}:{$match->line}:{$match->content}\n";
    }
}
```

Die Ergebnisobjekte sind unter [API / Result objects](https://greph.inline0.dev/de/docs/api#result-objects) dokumentiert.

## So funktioniert es

Die Text-Engine hat zwei Pfade:

- **Literaler Pfad**: Wenn `-F` gesetzt ist, durchsucht `strpos()` einen 64-KiB-gepufferten Reader und erfasst Zeilenumbrüche zur Zeilennummerierung. Es gibt keinen Schritt zum Kompilieren eines regulären Ausdrucks.
- **Regex-Pfad**: Wenn `-F` nicht gesetzt ist, extrahiert Greph mit einem kleinen PCRE-ähnlichen Analysator (`Greph\Text\LiteralExtractor`) literale Teilzeichenfolgen aus dem Muster und verwendet sie als `strpos()`-Vorfilter. Zeilen, die den Vorfilter passieren, werden anschließend mit dem kompilierten PCRE2-Muster und aktiviertem JIT abgeglichen.

Beide Pfade verwenden dasselbe `BufferedReader` für die Ein-/Ausgabe. Der Reader liest Daten in 64-KiB-Blöcken statt `fgets()` pro Zeile, wodurch die Anzahl der Systemaufrufe bei großen Dateien deutlich sinkt.

Bei wiederholten Arbeitslasten ersetzt der [indexierte Textmodus](https://greph.inline0.dev/de/docs/indexed/text) den gepufferten Reader durch einen aufgewärmten Trigramm- und Bezeichner-Posting-Speicher und überspringt die meisten Dateien vollständig.
