App-Greple

 view release on metacpan or  search on metacpan

RIPGREP-STUDY.md  view on Meta::CPAN

変換は数学的には整合的に定義できる(オフセットは昇順に届くので O(N) の一回走査で変換可能)。
**位置変換そのものは技術的障害ではない**。障害は次節以降で述べるコスト構造にある。

### 3.2 案 B の実測: JSON 経由のオーバーヘッド

| 処理 | 時間 |
|---|---:|
| `rg --json fox corpus.txt`(96k マッチ、JSON 26MB 出力) | 0.09s |
| ↑を Perl (JSON::PP) でパース | **8.0s** |
| (参考)現行 greple の同検索全体 | 0.82s |

マッチ多数時、JSON のパースだけで現行 greple の 10 倍の時間がかかる(コア モジュール JSON::PP の場合。
JSON::XS を追加依存にすれば数百 ms 程度まで縮むが、それでも byte→char 変換・
ブロック構築を加えると現行との差はほぼ消える)。
マッチ少数時はそもそもスキャンフェーズ(80ms)しか削れない。**どちらのケースでも割に合わない。**

### 3.3 libripgrep(grep crates)

ripgrep は `grep-matcher` / `grep-searcher` / `grep-printer` 等のクレート群に分割されており
([libripgrep PR #1017](https://github.com/BurntSushi/ripgrep/pull/1017))、
ライブラリとして再利用可能。正規表現エンジンは Rust regex(有限オートマトン + SIMD)と
PCRE2(`--pcre2` / `-P`、後読み・後方参照対応)の 2 系統。

- Rust regex は後読み・後方参照・`(?{...})` 非対応。greple ユーザーのパターン資産とは方言差がある。
- PCRE2 モードは Perl にかなり近いが、完全互換ではない。

## 4. 各案の詳細検討

### 案 A: rg をファイルレベルのプリフィルタに使う 【推奨】

**仕組み**: `rg -l pattern dir` で「マッチを含むファイル一覧」だけを rg に高速列挙させ、
greple は該当ファイルのみを従来どおり処理する。位置情報を受け渡さないので
バイト/文字オフセット問題・正規表現方言問題の影響を最小化できる。

```
rg -l --null pattern dir | greple --readlist pattern
```

既存機構がほぼそのまま使える:

- `--readlist`(`script/greple:1200-1201`): STDIN からファイルリストを受け取る
- `find.pm` の `!command` 機構(`find.pm:80`): 任意コマンドでファイルリストを生成
  (`dig.pm` が find の薄いラッパであるのと同じ構図で、`App::Greple::rg` モジュールを書ける)

**実装案**: `App::Greple::rg` モジュールを新設し、`greple -Mrg --rg <dir> pattern` で

1. greple のオプション処理後、検索パターンを取得
2. パターンを rg に渡せるか判定(関数パターン `&func` や Perl 固有機能は不可)
3. 渡せる場合 `rg -lP --sort path` でファイルリスト生成(`-P` で PCRE2 = Perl 方言に接近、
   `--sort` は並列性を殺すので出力順が問題になる場合のみ)
4. 渡せない場合は `rg --files`(ファイル列挙のみ)にフォールバック — それでも
   .gitignore 尊重・バイナリスキップの恩恵はある

**正しさの条件**: プリフィルタは「greple がマッチするファイルの上位集合」を返す必要がある。
注意点と対策:

| 懸念 | 対策 |
|---|---|
| 正規表現方言差(後読み等) | `-P` (PCRE2) を使う。変換不能なら素通しフォールバック |
| 行跨ぎパターン | `rg -U`(マルチライン)を付ける |
| 非 UTF-8 ファイル(--icode) | `rg -E <encoding>` にマッピング。guess 時は素通し |
| `--if` フィルタ対象(zip 等) | rg では判定不能 → 素通し(従来どおり greple が処理) |
| 大文字小文字 (`-i`) | `rg -i` を連動 |
| must/need の複数パターン | 各陽性パターンの OR で `-e` を並べれば上位集合になる |

安全側に倒す(迷ったら素通し)設計なら結果の正しさは保たれ、性能だけが段階的に向上する。

**効果**: マッチが疎な大規模ツリーで支配的な「マッチしないファイルの処理」を rg の速度
(並列走査 + .gitignore/バイナリスキップ)で消せる。実測 3000 ファイルで 5 倍、
実プロジェクトの巨大ツリーでは桁違いになる。greple の主用途(ドキュメント・コード検索)で
最も体感が大きいのはこのケース。

**得失まとめ**: 工数小(モジュール 1 個、コア変更ほぼ不要)。rg はオプショナルな外部依存
(無ければ従来動作)。greple の機能・モジュール互換性への影響ゼロ。
単一巨大ファイル・マッチ多数のケースには効かない(→ 案 E で補完)。

### 案 B: rg --json の位置情報を greple 内部位置に変換する 【非推奨】

ユーザーが以前検討した方式。技術的には §3.1 のとおり「rg のオフセットは変換後 UTF-8 バイト基準」
なので、昇順オフセットを 1 パスで文字位置に変換すれば greple の内部表現に載せること自体は可能。
しかし:

1. **改善上限が小さい**: 削れるのはスキャンフェーズ(26MB あたり ~80ms)のみ。
   マッチ後処理(支配的コスト)は greple 側に残る。
2. **JSON オーバーヘッドが逆効果**: マッチ多数時、JSON::PP でパースに 8 秒(実測)。
   JSON::XS を依存に加えても変換・構築コストで利得はほぼ相殺。
3. **機能制約が多い**: 関数パターン(`&func`)不可、`--inside/--outside` の領域パターンも
   同様に外部化しないと片手落ち、`--if` フィルタとの合成、正規表現方言差、
   マッチ 0 幅・重なり領域のセマンティクス差、等の互換性穴が多数。
4. 表示のためどのみち該当ファイルのデコードと slurp は必要で、I/O 面の節約もない。

**結論**: 実装しても現行比でほぼ速くならず、互換性リスクだけ増える。

### 案 C: Rust ライブラリ (grep crates) を FFI::Platypus で呼ぶ 【非推奨】

**技術的成立性は確認できる**:
[FFI::Platypus::Lang::Rust](https://metacpan.org/pod/FFI::Platypus::Lang::Rust)(0.17, 2023)と
[FFI::Build::File::Cargo](https://metacpan.org/pod/FFI::Build::File::Cargo) により、
CPAN ディストリビューションに Rust クレートを同梱し `cargo` でビルドする仕組みは確立している。
in-process なので JSON オーバーヘッドはなく、byte→char 変換テーブルを Rust 側で構築する等の
自由度も高い。

しかし:

1. **効果は案 B と同じ場所に限定される**: 初期マッチ列挙の高速化のみ。本気で速くするには
   領域代数(Regions.pm)とブロック構築(Grep.pm)ごと Rust に移す必要があり、そうなると
   関数パターンや `--postgrep` 等の Perl コールバックとの往復が発生して設計が複雑化する。
2. **配布コストが跳ね上がる**: インストールに Rust toolchain が必要になる。
   `cpanm App::Greple` で入る手軽さが失われる(Alien 化や事前ビルドバイナリ配布は保守負荷大)。
   オプショナル XS 的な二段構え(あれば使う)は二重実装の保守を意味する。
3. Perl↔Rust 境界での文字列コピー(26MB 級)も無視できない。

**結論**: 「工数大・利得小・配布リスク大」。greple の規模のツールに対して割に合わない。

### 案 D: greple 全体を Rust で書き直す 【greple としては非推奨】

技術的には可能で、性能は本物になる(マッチ後処理も含め 10〜100 倍級)。
問題はユーザー認識のとおり **Perl モジュールエコシステム**にある。

greple の価値の中核は `-Mdig`, `-Msubst`, `-Mmd`, `~/.greplerc`, Getopt::EX の
オプション展開機構であり、これらは「Perl コードが検索パイプラインに直接介入できる」



( run in 1.153 second using v1.01-cache-2.11-cpan-7fcb06a456a )