Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
ripgrep をライブラリとして使う
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Linda_pp
November 24, 2021
Technology
770
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ripgrep をライブラリとして使う
Rust LT Online #5 発表資料
https://rust.connpass.com/event/228732/
Linda_pp
November 24, 2021
More Decks by Linda_pp
See All by Linda_pp
actionlint の Linter 設計
rhysd
7
6.6k
port-monolith-to-wasm-for-chrome-extension
rhysd
0
570
Fuzzing Rust Text Editor
rhysd
1
3.1k
Vim compiled to WebAssembly
rhysd
5
2.4k
about-neovim-0.4.0-floating-window
rhysd
3
2.4k
reply.vim
rhysd
0
1.4k
Vim ported to WebAssembly (VimConf 2018)
rhysd
4
3.6k
go-selfupdate-github で ツールを自己アップデートする
rhysd
5
4.7k
小さく始めて育てるコンパイラ
rhysd
13
5.1k
Other Decks in Technology
See All in Technology
研究開発部の紹介 / Sansan R&D Profile
sansan33
PRO
5
25k
2026-09-10 【Snowflake World Tour Tokyo 2026】dbt Core と Snowflake で実現する多層的なデータガバナンス / Multi-Layered Data Governance Powered by dbt Core and Snowflake
civitaspo
0
360
GoCon2026 - Open Source, Open World
sanposhiho
4
3.4k
すぐできる衛星通信対応 あとは山奥に行くだけ
tatetate55
0
110
AI時代に顧客へ最速で価値を 届けるための試行錯誤 〜「AI × マネジメント」領域におけるmentoのケース〜
posterkeisuke
0
110
アプリログインとWeb認証基盤をつなぐ ASWebAuthenticationSession 作法
shimastripe
1
220
日経電子版を支えていく Kasane Design System/fec_fukuoka
nikkei_engineer_recruiting
0
980
Omarchy Quattro の日本語設定周り
simosako
2
150
AIネイティブプロダクトで顧客価値を最大化するプロダクトエンジニアとFDEの協働
righttouch
PRO
0
240
Claude Code本って、 読む必要あるの?
oikon48
2
420
AI時代のAPI品質を支えるガードレール / API Guardrails for API quality in the AI era
yokawasa
1
220
データ界隈LT祭 第1回LT登壇
taromatsui_cccmkhd
0
210
Featured
See All Featured
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
Ruling the World: When Life Gets Gamed
codingconduct
0
330
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.9k
30 Presentation Tips
portentint
PRO
1
390
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
560
Utilizing Notion as your number one productivity tool
mfonobong
4
590
Skip the Path - Find Your Career Trail
mkilby
1
230
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
270
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
42k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
Transcript
ripgrep をライブラリとして使う Twitter: @Linda_pp, GitHub: @rhysd Rust LT Online #5
(2021/11/23)
ripgrep とは 有名な grep 互換のコマンドラインツール.SIMD や マルチスレッドを活用し処理を高速化してい る..gitignore を見てくれたり出力に色を付けてくれ たりなど,ユーザフレンドリーな機能も提供.
pcre2 対応を除いて,すべて Rust で実装されてお り,ライブラリとしても使えるようにうまくモジュール化 されている.
活用例 hgrep (Human-friendly GREP) というツールでファイ ル検索に利用. 検索結果を良い感じにスニペットにまとめて構文ハイ ライトして出力するコマンドラインツール. - リポジトリ:
https://github.com/rhysd/hgrep - 紹介記事: https://rhysd.hatenablog.com/entry/2021/11/2 3/211530
TL;DR https://github.com/rhysd/hgrep/bl ob/main/src/ripgrep.rs ↑ここにすべての実装が入っている grep 出力 パーサ grep 実装 chunk
の 計算処理 Printer Bat Printer Syntect Printer ↓ ここの話 --no-ignore --ignore-case --smart-case --glob GLOB... --glob-case-insensitive --fixed-strings --word-regexp --follow --multiline --multiline-dotall --crlf --mmap --max-count NUM --max-depth NUM --max-filesize NUM+SUFFIX? --line-regexp --invert-match --pcre2 --type TYPE --type-not TYPE --type-list --one-file-system --no-unicode --regex-size-limit --dfa-size-limit
ripgrep のモジュール構造 ripgrep cli core ignore globpath matcher pcre2 regex
memmem memchr printer searcher ripgrep 用 CLI パーサ (grep-cli) 本体(main 関数はここ) ディレクトリを辿ってファイルパスを列挙 **/*.rs のような glob のファイルパス列挙 ファイルに対するマッチ処理 (grep-matcher) pcre2 の Rust binding 有名な regex crate libc の memmem の SIMD 実装 libc の memchr の SIMD 実装 ファイルの検索処理 (grep-searcher) マッチ結果の表示処理 (grep-printer)
ripgrep のモジュール構造 ripgrep cli core ignore globpath matcher pcre2 regex
memmem memchr printer searcher ripgrep 用 CLI パーサ (grep-cli) 本体(main 関数はここ) ディレクトリを辿ってファイルパスを列挙 **/*.rs のような glob のファイルパス列挙 ファイルに対するマッチ処理 (grep-matcher) pcre2 の Rust binding 有名な regex crate libc の memmem の SIMD 実装 libc の memchr の SIMD 実装 ファイルの検索処理 (grep-searcher) マッチ結果の表示処理 (grep-printer)
サンプルコード https://github.com/rhysd/misc/tree/master/rust/chibigrep - ripgrep のうち再帰的にファイルを検索してマッチ結果を 取得する処理部分だけを使う - 特定のテキストを含んだファイルを探してくるユースケー スを想定 -
ignore, grep-matcher, grep-searcher の3つの crate を 使う
ディレクトリの walker を生成 use ignore::{WalkBuilder, WalkState}; // Path を再帰的に辿る walker
を生成.今回は WalkParallel でマルチスレッドでパスを 辿る // スレッドプールは自動で生成される(スレッド数は指定もできるが,デフォルトで良い感じに決 めてくれる) let mut builder = WalkBuilder::new(path); for path in rest { builder.add(path); } builder .hidden(false) // 隠しファイルを検索 .ignore(true) // ignore されたファイルを無視 .parents(true); // 親ディレクトリを辿って .gitignore を探す let walker = builder.build_parallel();
ディレクトリをマルチスレッドで再帰的に辿る let (tx, rx) = mpsc::channel(); // walker.run はマルチスレッドで呼ばれるので値の受け渡しを channel
でやる walker.run(|| { // 初期化関数.ここはスレッドプールのスレッドごとに呼ばれる let tx = tx.clone(); Box::new(move |result| match result { // この内側のコールバックはファイルパスごとに呼ばれる Ok(entry) if entry.file_type().map(|t| t.is_file()).unwrap_or(false) => { // `entry` は `ignore::DirEntry` grep_file(pat, entry.into_path(), &tx); // ファイルの時.ファイル内を検索 ignore::WalkState::Continue // 検索を続ける } Ok(_) => ignore::WalkState::Continue, // ディレクトリの時.検索を続ける Err(err) => { tx.send(Err(format!("{}", err))).unwrap(); ignore::WalkState::Quit // 検索を中止する } }) });
マッチ結果を受け取る Sink を実装 use grep_searcher::{Sink, SinkMatch}; struct SearchSink<'a> { tx:
&'a Sender<Result<Match, MyError>>, path: &'a Path, } // 結果を集めるためのコールバックを Sink で実装.マッチ箇所ごとに `matched` が呼ばれる impl<'a> Sink for SearchSink<'a> { type Error = io::Error; // `SinkMatch` にマッチ情報が入っている fn matched(&mut self, _searcher: &Searcher, mat: &SinkMatch<'_>) -> Result<bool, Self::Error> { let m = Match { path: self.path.to_owned(), lnum: mat.line_number().unwrap_or(0), line: mat.bytes().to_vec(), }; self.tx.send(Ok(m)).unwrap(); // マッチ結果を返す Ok(true) } }
マッチ処理を行う matcher を生成 use grep_regex::RegexMatcherBuilder; let mut builder = RegexMatcherBuilder::new();
builder .case_smart(true) // smart case を有効に .unicode(true); // unicode 対応 // Matcher を生成.今回は regex crate を使った RegexMatcher を使う // これ以外にも pcre2 を使ったものもある let matcher = match builder.build(pat) { Ok(m) => m, Err(err) => { tx.send(Err(format!("{}", err))).unwrap(); return; } };
searcher を生成してファイル内を検索 use grep_searcher::{BinaryDetection, MmapChoice, SearcherBuilder}; // Searcher を生成 let
mut builder = SearcherBuilder::new(); builder .binary_detection(BinaryDetection::quit(0)) // バイナリファイルだと判明したら検索をやめる .line_number(true) .memory_map(unsafe { MmapChoice::auto() }); // mmap を有効にする let mut searcher = builder.build(); // ここでファイルを検索.マッチごとに sink の matched メソッドが呼ばれる let mut sink = SearchSink { tx, path: &path }; if let Err(err) = searcher.search_path(&matcher, &path, &mut sink) { tx.send(Err(format!("{}", err))).unwrap(); }
まとめ • ripgrep は個々の機能ごと複数の crate に分割して実装されている ◦ ファイルパス検索(ignore) ◦ マッチ処理(grep-regex,
grep-matcher) ◦ ファイル検索(grep-searcher) ◦ 結果表示(grep-printer) • 「特定のパターンのテキストを含んだファイルを探してくる」という処理に対してはか なり汎用的・簡単に使うことができ,実行効率も良い(マルチスレッド活用・SIMD に よる検索実装)