Fast full-window file and content search for VS Code, powered by FFF. The workspace index lives in memory and is built at startup; results open in a normal editor tab with a preview beside them.
Measured on a 7,700-file, 155 MB workspace: the index takes 57 ms to build, and a keystroke costs 14-34 ms whether the query matches 268 lines or 792,022. Results stream in behind the first page, so the counter climbs while you keep typing and nothing is ever cut off.
Since 0.1.8, FFF replaces the fzf terminal picker: no fzf, no ripgrep, no terminal
integration, and the settings those needed are gone.
Requirements
| VS Code | 1.90 or newer |
| Platform | Linux x64 with glibc, including WSL2. The VSIX bundles only that native build, so macOS, native Windows, arm64 and musl are not supported. |
| Workspace | A folder must be open; the first workspace folder is the search root. Restricted Mode is fine - Sonar only reads and displays files. Virtual workspaces are not, since FFF indexes a real directory. |
| Anything else | Nothing. No fzf, no rg, no bat, no Node install. |
Under WSL, install into the WSL window rather than the Windows one, and keep the workspace off
/mnt/c - indexing and file watching there are slow and miss changes.
Previews are syntax-highlighted by a bundled copy of highlight.js, themed to follow VS Code's light or dark mode. Nothing to install and no subprocess per keystroke.
Commands
| Command | Keybinding |
|---|---|
| Search file | ctrl+shift+j |
| Search within files | ctrl+shift+u |
| Search within current file | - |
| Search within open files | - |
| Resume last search | - |
Type to filter, Up and Down to move, Enter to open; moving updates the preview. File search is typo-tolerant fuzzy matching, content search is literal text rather than a regex, and a selection in the editor seeds the query. The two single-file commands read unsaved editor content, so results match what is on screen.
The counter reads 5/8 for a file search - files kept, files indexed - and 1681 · 5/8 for a
content search: hits first, then the files the // filter and its groups kept. Content search also
skips binaries and files over 10 MB, which no filter controls and the counter does not subtract.
Query syntax
Search file and Search within files split the query at //: left is the pattern, right is a
space-separated file filter.
| Token | Matches |
|---|---|
.c or c |
*.c |
.{c,h} |
*.c and *.h |
!py |
everything except *.py |
*.c, !*_test.c |
used as the glob it is |
src/**, !vendor/ |
path globs; a bare dir/ matches at any depth |
@web |
excludes every entry of the web group (see Settings) |
todo // .c "todo" in C files
handler // py !*_test.py "handler" in Python, skipping tests
config // *.json !dist/ JSON outside dist/
// .py every .py file (Search file only)
todo // @web "todo" outside the "web" group's directories
Filters do not apply to the two single-file commands, which say so if you type one. A filter matching
no file returns nothing rather than quietly widening the search, and a malformed token - empty, a
stray second //, or a negated !@group - is an error. .gitignore is honored, except for the
directories listed in searchIgnoredDirectories (see Settings).
Settings
| Setting | Effect |
|---|---|
fif-sonar.general.excludeDirectoryGroups |
Named sets of directories and globs, expanded by @group in a query. |
fif-sonar.general.searchIgnoredDirectories |
Directories searched even though .gitignore excludes them, relative to the workspace root, e.g. ["dist", "node_modules/@types"]. Each is indexed separately; one that does not exist is skipped. |
fif-sonar.findFiles.defaultGroups |
Groups applied to every Search file run without typing @group. |
Groups live in settings.json:
"fif-sonar.general.excludeDirectoryGroups": {
"web": ["dist", "coverage", "*.min.js"],
"generated": ["build", "target", "*.pb.go"]
},
"fif-sonar.findFiles.defaultGroups": ["generated"]
A directory name is excluded at any depth (dist becomes !**/dist/**) and an entry with * or ?
is used as the glob it is (*.min.js becomes !*.min.js). So todo // @web searches for "todo"
outside dist/, coverage/ and every minified file, and because generated is a default group,
every Search file run skips it without the query saying so. Defaults apply to Search file only.