
# Поиск по тексту

Текстовый режим 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. Функции PHP`preg_*` лежат в основе движка, поэтому синтаксис соответствует справочнику по PCRE[PHP](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 / FileTypeFilter](https://greph.inline0.dev/ru/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/ru/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` вместо этого выдаёт ripgrep в виде событий JSON. Используйте её, если существующий потребитель ожидает схему 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/ru/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/ru/docs/indexed/text) заменяет буферизованный читатель прогретым хранилищем триграмм и публикаций идентификаторов, пропуская большую часть файлов целиком.
