
# Текстовий пошук

Текстовий режим Greph виконує побайтовий пошук у рядках дерева файлів. Це типовий режим `greph` CLI і фасаду `Greph::searchText()`. Вивід використовує канонічний формат `file:line:content`, який розбирають grep, ripgrep і більшість інтеграцій із редакторами.

## Короткі приклади

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

## Візерунки

Типово шаблон трактується як регулярний вираз PCRE2. Функції `preg_*` бібліотеки PHP забезпечують роботу рушія, тож синтаксис відповідає [офіційній довідці PCREPHP](https://www.php.net/manual/en/pcre.pattern.php).

Вимкніть рушій регулярних виразів за допомогою `-F`, щоб трактувати шаблон як буквальну послідовність байтів. Режим фіксованих рядків — найшвидший: для зіставлення він використовує `strpos()` і повністю пропускає етап компіляції PCRE2.

`-i` робить обидва режими нечутливими до регістру. `-w` додає межі цілих слів з обох боків збігу.

## Фільтрування файлів

Greph обходить дерево файлів перед пошуком. Засіб обходу спільний для режимів AST та індексованого пошуку, тому однакові прапорці фільтрування діють скрізь.

| Прапорець | Результат |
|---|---|
| `--type NAME` | Включити лише файли, що відповідають зазначеному псевдоніму типу (`php`, `js`, `md`, ...) |
| `--type-not NAME` | Виключити файли, що відповідають зазначеному псевдоніму типу |
| `--glob GLOB` | Включити лише файли, шляхи яких відповідають GLOB. Прапорець можна повторювати. |
| `--no-ignore` | Не враховувати `.gitignore` або `.grephignore` |
| `--hidden` | Включити приховані файли |

Типово засіб обходу враховує `.gitignore` і `.grephignore`, пропускає двійкові файли (визначає їх за нульовими байтами в перших 512 байтах) і обмежує розмір файлу до 10 MiB. Обидва обмеження можна налаштувати через `WalkOptions`.

Повний список вбудованих псевдонімів типів див. у [API / Фільтрі типів файлів](https://greph.inline0.dev/uk/docs/api#grephwalkerfiletypefilter).

## Контекст, підрахунок і режими лише для файлів

```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` і `-L` обходять форматувальник, щоб не створювати всі рядки в пам'яті. Це доречні режими для запитів «скільки» та «де».

## Паралельне сканування

Передайте `-j N`, щоб розподілити сканування між N робочими процесами. Greph використовує `pcntl_fork()` для пулу робочих процесів і переходить до виконання в одному процесі, якщо `ext-pcntl` недоступний.

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

Фасад визначає, чи варте паралельне виконання додаткових витрат, з огляду на кількість файлів, режим і форму шаблону. Нижче порогового значення він працює в одному процесі. Евристики описано в розділі [Розширені можливості / Паралельні робочі процеси](https://greph.inline0.dev/uk/docs/advanced/parallel).

## Вивід JSON

`--json` виводить структурований набір даних, який наступні інструменти можуть обробити без розбору 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": []
      }
    ]
  }
]
```

Обгортка `rg` виводить об'єкти JSON у формі подій ripgrep. Використовуйте її, якщо наявному споживачу потрібна схема ripgrep.

## Програмне використання

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

Об'єкти результатів описано в розділі [API / Об'єкти результатів](https://greph.inline0.dev/uk/docs/api#result-objects).

## Як це працює

Текстовий рушій має два шляхи:

- **Шлях буквального пошуку**: якщо встановлено `-F`, пошук виконується за допомогою `strpos()` через буферизований зчитувач розміром 64 KiB, який відстежує переноси рядків для нумерації. Компіляції регулярного виразу немає.
- **Шлях пошуку регулярними виразами**: якщо `-F` не встановлено, Greph витягує з шаблону буквальні підрядки за допомогою невеликого аналізатора з формою PCRE (`Greph\Text\LiteralExtractor`) і використовує їх як попередній фільтр `strpos()`. Рядки, що проходять попередній фільтр, потім зіставляються зі скомпільованим шаблоном PCRE2 із увімкненим JIT.

Обидва шляхи використовують для введення-виведення той самий `BufferedReader`. Зчитувач читає блоками по 64 KiB замість `fgets()` для кожного рядка, що різко зменшує кількість системних викликів у великих файлах.

Для повторюваних завдань [індексований текстовий режим](https://greph.inline0.dev/uk/docs/indexed/text) замінює буферизований зчитувач прогрітим сховищем триграм і індексом ідентифікаторів, пропускаючи більшість файлів.
