
# Wyszukiwanie tekstu

Tryb tekstowy Greph wyszukuje bajty wiersz po wierszu w przemierzanym drzewie plików. Jest domyślnym trybem `greph` CLI oraz fasady `Greph::searchText()`. Wyniki są w kanonicznym formacie `file:line:content`, który analizują grep, ripgrep i większość integracji z edytorami.

## Szybkie przykłady

```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
```

## Wzorce

Domyślnie wzorzec jest traktowany jako wyrażenie regularne PCRE2. Za silnikiem stoją funkcje `preg_*` z PHP, więc składnia odpowiada [dokumentacji PCRE](https://www.php.net/manual/en/pcre.pattern.php)PHP.

Wyłącz silnik wyrażeń regularnych za pomocą `-F`, aby traktować wzorzec jako dosłowną sekwencję bajtów. Tryb stałego ciągu to szybka ścieżka: do dopasowywania używa `strpos()` i całkowicie pomija etap kompilacji PCRE2.

`-i` sprawia, że w obu trybach wielkość liter nie ma znaczenia. `-w` dodaje granice całych słów po obu stronach dopasowania.

## Filtrowanie plików

Greph przemierza drzewo plików przed wyszukiwaniem. Ten sam mechanizm przemierzania jest używany w trybie AST i trybie indeksowanym, dlatego wszędzie obowiązują te same flagi filtrowania.

| Flaga | Działanie |
|---|---|
| `--type NAME` | Uwzględnia tylko pliki pasujące do nazwanego aliasu typu (`php`, `js`, `md`, ...) |
| `--type-not NAME` | Wyklucza pliki pasujące do nazwanego aliasu typu |
| `--glob GLOB` | Uwzględnia tylko pliki, których ścieżki pasują do GLOB. Można powtarzać. |
| `--no-ignore` | Ignoruje `.gitignore` lub `.grephignore` |
| `--hidden` | Uwzględnia ukryte pliki |

Mechanizm przemierzania domyślnie respektuje `.gitignore` i `.grephignore`, pomija pliki binarne (wykrywane na podstawie bajtów null w pierwszych 512 bajtach) i ogranicza rozmiar pliku do 10 MiB. Oba limity można skonfigurować za pomocą `WalkOptions`.

Pełną listę wbudowanych aliasów typów znajdziesz w [API / FileTypeFilter](https://greph.inline0.dev/pl/docs/api#grephwalkerfiletypefilter).

## Kontekst, liczniki i tryby tylko dla plików

```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` i `-L` pomijają formatowanie, dzięki czemu nie trzeba wczytywać wszystkich wierszy do pamięci. To odpowiednie tryby dla zapytań „ile” i „gdzie”.

## Skanowanie równoległe

Przekaż `-j N`, aby rozdzielić skanowanie między N procesów roboczych. Greph używa `pcntl_fork()` do utworzenia puli procesów roboczych i przechodzi na wykonanie jednego procesu, gdy `ext-pcntl` jest niedostępne.

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

Fasada ocenia, czy wykonanie równoległe jest warte dodatkowego narzutu, na podstawie liczby plików, trybu i kształtu wzorca. Poniżej progu pozostaje przy jednym procesie. Zobacz [Zaawansowane / Procesy robocze równoległe](https://greph.inline0.dev/pl/docs/advanced/parallel), aby poznać heurystyki.

## Dane wyjściowe JSON

`--json` emituje uporządkowany ładunek danych, który narzędzia dalszego przetwarzania mogą analizować bez pobierania wyników w formacie grep:

```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": []
      }
    ]
  }
]
```

Opakowanie `rg` emituje zamiast tego JSON w formie zdarzeń ripgrep. Użyj go, gdy istniejący odbiorca oczekuje schematu ripgrep.

## Użycie programowe

```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";
    }
}
```

Obiekty wynikowe opisano w [API / Obiekty wynikowe](https://greph.inline0.dev/pl/docs/api#result-objects).

## Jak to działa

Silnik tekstowy ma dwie ścieżki:

- **Ścieżka dosłowna**: gdy ustawiono `-F`, wyszukiwanie wykonuje `strpos()` na buforowanym czytniku o rozmiarze 64 KiB i śledzi znaki nowej linii na potrzeby numeracji wierszy. Nie ma etapu kompilacji wyrażeń regularnych.
- **Ścieżka wyrażeń regularnych**: gdy nie ustawiono `-F`, Greph wyodrębnia dosłowne podciągi ze wzorca za pomocą prostego analizatora w stylu PCRE (`Greph\Text\LiteralExtractor`) i używa ich jako filtra wstępnego `strpos()`. Wiersze, które przejdą filtr wstępny, są następnie dopasowywane do skompilowanego wzorca PCRE2 z włączonym JIT.

Obie ścieżki używają tego samego `BufferedReader` do operacji wejścia i wyjścia. Czytnik odczytuje dane w porcjach po 64 KiB zamiast `fgets()` na wiersz, co znacznie zmniejsza liczbę wywołań systemowych w przypadku dużych plików.

Przy powtarzających się zadaniach [indeksowany tryb tekstowy](https://greph.inline0.dev/pl/docs/indexed/text) zastępuje buforowany czytnik rozgrzanym magazynem trójgramów i wystąpień identyfikatorów, całkowicie pomijając większość plików.
