Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Code Search

Searching across a codebase is one of the most common tasks when navigating unfamiliar code or tracking down all uses of a function, type, or dependency. There are two approaches: text-based search (fast, works everywhere) and structural search (syntax-aware, understands code structure).

ripgrep

ripgrep is a command-line tool for searching code bases using regular expressions. It is very fast, making use of Rust’s powerful regex crate. It understands git repositories and respects .gitignore files, making it particularly suitable for searching software projects.

Note

If you use Visual Studio Code, you are already using ripgrep. VS Code uses ripgrep internally to implement its search functionality.

You can install it with Cargo:

cargo install ripgrep

Running this will install the rg binary, which you can use to search code projects. You can then use it to search for patterns.

$ rg uuid::
database/src/main.rs
8:use uuid::Uuid;

protocol/src/types.rs
10:use uuid::Uuid;

common/src/entities.rs
12:use uuid::Uuid;

ast-grep

ast-grep (command: sg) is a structural search tool. Where ripgrep matches text with regular expressions, ast-grep parses code into an abstract syntax tree (AST) and matches against tree patterns. This makes it syntax-aware: it can distinguish between a function call and a variable name that happens to have the same text, and it ignores whitespace and formatting differences that would break a regex.

You can install it with Cargo:

cargo install ast-grep

ast-grep uses patterns that look like the code you are searching for, with metavariables (prefixed with $) standing in for parts you don’t care about. For example, to find all places where .unwrap() is called on anything:

$ sg -p '$A.unwrap()' -l rust
src/config.rs
15:    let file = std::fs::read_to_string(path).unwrap();

src/main.rs
42:    let port = env::var("PORT").unwrap();

You can also use it for codemod-style replacements. For example, to replace all unwrap() calls with expect():

sg -p '$A.unwrap()' -r '$A.expect("todo: handle error")' -l rust

ast-grep supports Rust and 20+ other languages out of the box through tree-sitter parsers. Beyond one-off searches, it can also be used as a linter by defining custom rules in YAML configuration files, and it has a language server for editor integration.

Reading

Andrew, the author of ripgrep, introduces the tool in this article, explains how it works and compares it to some common similar tools used by developers, showing how it performs better and how it excels at dealing with Unicode, something other tools struggle with.