Search all files in a project with Skink (grep, replace)
Press Alt+S (or Ctrl+Shift+F, or run :grep TEXT) to search every file in the project. Results stream into a tab, grouped by file, and Enter on a result jumps there.
To replace the matches in every file, run :greprep WITH. The changes open in a preview first.
Project search uses the same engine as ripgrep, built in. You do not need rg installed.
Search every file
Section titled “Search every file”| Key | Typed command | Does |
|---|---|---|
| Alt+S or Ctrl+Shift+F | :grep [TEXT] (:search, :rg) |
Search the project |
:stopsearch |
Stop a search that is still running |
In the search prompt, the same toggles as the find bar apply:
| Key | Toggles |
|---|---|
| Alt+R | Regex |
| Alt+C | Case-sensitive |
| Alt+W | Whole word |
What gets searched
Section titled “What gets searched”- Every file under the project root, plus any roots you added with
:addroot DIR. .gitignoreand.ignoreare honoured, so build output andnode_modulesstay out.- The search stops at 5000 matches. Narrow the query if you hit that.
Working with the results
Section titled “Working with the results”Results are a normal tab, so you can keep them open while you work. After following one, come back with Alt+U (jump back, or :back).
Replace in every file
Section titled “Replace in every file”After a search, run:
:greprep NEW_TEXTSkink replaces the last search’s matches in every file through the refactor preview: a list of files and hunks with checkboxes and a side-by-side diff.
| Key in the preview | Does |
|---|---|
| ↑ / ↓ | Move |
| Space | Check or uncheck |
| a / n | Check all / none |
| Enter | Apply the checked changes (one undo step per file) |
| Esc | Cancel |
In regex mode the replacement can use $1 for capture groups.
The changed files stay unsaved, so you can look once more before saving.
Structural search with :sgrep
Section titled “Structural search with :sgrep”:sgrep searches code by its shape rather than its text, using ast-grep patterns. It looks in files of the current file’s language. It also works as :structural.
In a pattern, $NAME matches one syntax node and $$$NAME matches any number of them. Whitespace and comments do not matter.
| Command | Finds |
|---|---|
:sgrep foo($A, $$$REST) |
Every call to foo with at least one argument |
:sgrep $X.unwrap() |
Every .unwrap() call (Rust) |
:sgrep console.log($$$) |
Every console.log (JS/TS) |
Structural rewrite with :srep
Section titled “Structural rewrite with :srep”:srep rewrites every structural match, through the same preview:
:srep foo($A, $B) => bar($B, $A)That turns foo(x, y + 1) into bar(y + 1, x) everywhere, whatever the spacing or line breaks.
After an :sgrep, :greprep WITH does the same rewrite with the pattern you searched for. See Refactoring for more refactors that use the preview.
Related searches
Section titled “Related searches”- Search only the current file: Find and replace.
- Find a file by name: Alt+P or
:recent(quick open). A/in the query matches path segments in order, sos/c/gradefindssrc/color/grade.rs. - Find a symbol: Alt+W (
:allsymbols) searches symbols in the whole project, Ctrl+R (:outline) in this file.