Explorer Filter
A VS Code extension (TypeScript + bun) that hides files from the Explorer.
Everything is configured from VS Code's native Settings UI — toggle preset
bundles, add custom globs, and let it follow your .gitignore. It applies the
result to the built-in files.exclude setting, touching only the keys it adds,
so any exclude rules you wrote yourself are preserved.
Features
- Preset bundles for the usual noise — dotfiles,
node_modules, build
output, logs, VCS, Python, IDE files — each toggled from Settings.
.gitignore aware — automatically hides ignored directories (files
optional).
- One-click toggle in the Explorer toolbar hides or shows everything at once,
keeping your selection while it is off.
- Exemptions keep AI agent / config dirs (
.claude, .codex, …) visible
even with the Dotfiles bundle on.
- Non-destructive — only ever touches the
files.exclude keys it added.
Requirements
- bun (package manager + bundler)
- VS Code
^1.90.0
git on PATH (optional — improves .gitignore accuracy; see below)
Getting started
bun install # install dev dependencies
bun run compile # bundle src/ -> dist/extension.js
Press F5 to launch the Extension Development Host. The extension
activates on startup and applies the filter immediately — all bundles are on by
default, and .gitignore directories are hidden too.
The Explorer toolbar shows a single filter button that toggles the filter on
and off:
- when the filter is on, the button is a filled funnel (
$(filter-filled)) —
click it to show the filtered items;
- when the filter is off, it is an outline funnel (
$(filter)) — click it to
hide them again.
The status bar item on the right does the same thing. The toggle state is
remembered per workspace.
Configuring what gets filtered
There is no settings button in the toolbar — what gets hidden is configured
entirely from VS Code's Settings UI. Open Settings and search for
Explorer Filter (the command Explorer Filter: Open Settings is a shortcut).
Preset bundles (all on by default)
| Setting |
Hides |
explorerFilter.bundles.dotfiles |
**/.* |
explorerFilter.bundles.node |
node_modules, .npm, .yarn, .pnp.* |
explorerFilter.bundles.osJunk |
.DS_Store, Thumbs.db, desktop.ini |
explorerFilter.bundles.buildOutput |
dist, build, out, .next, .nuxt, .svelte-kit, .turbo |
explorerFilter.bundles.logs |
*.log, logs |
explorerFilter.bundles.vcs |
.git, .svn, .hg |
explorerFilter.bundles.python |
__pycache__, *.pyc, .venv, .mypy_cache, ... |
explorerFilter.bundles.ide |
.idea, .vscode-test, *.iml |
Bundle patterns live in src/presets.ts. To add a bundle, add
an entry there and a matching boolean under contributes.configuration in
package.json (VS Code requires static settings metadata).
.gitignore integration
| Setting |
Default |
Description |
explorerFilter.useGitignore |
true |
Hide entries listed in .gitignore. |
explorerFilter.gitignoreIncludeFiles |
false |
Also hide ignored files (default hides directories only). |
By default only ignored directories are hidden (e.g. dist/, node_modules/);
ignored files stay visible until you turn on gitignoreIncludeFiles.
How the directory/file split is decided:
- With
git (preferred): the extension runs
git ls-files -o -i --exclude-standard --directory -z per workspace folder.
This honors the full ignore ruleset (nested .gitignore, negations, the global
excludes file) and marks directories with a trailing slash, so the split is
exact.
- Without
git (not a repo / git missing): it falls back to a best-effort
parse of the root .gitignore.
The filter re-applies automatically when settings change, when a .gitignore
changes, or when workspace folders change. Use Explorer Filter: Reapply Filter
to force a refresh.
Exemptions (keep things visible)
files.exclude has no "except" rule, so the Dotfiles bundle can't use a
single **/.* and then carve out exceptions. Instead, when Dotfiles is on, the
extension lists the dotfiles actually present at each workspace root and emits a
**/<name> rule for each — skipping any name in explorerFilter.exclusions.
Those names are never added to files.exclude, so they stay visible.
Default exemptions (AI agent / important config dirs): .claude, .codex,
.cursor, .github, .vscode. The exemption list also acts as a safety net for
the other sources (custom patterns, .gitignore): a pattern whose final segment
is an exempt name is dropped.
Because this enumerates the workspace root, a brand-new dotfile/agent dir added
after activation may need Explorer Filter: Reapply Filter (or a settings
change) to be picked up. With no workspace open, Dotfiles falls back to the
broad **/.* rule and exemptions can't apply.
Other settings
| Setting |
Default |
Description |
explorerFilter.exclusions |
[".claude", ".codex", ".cursor", ".github", ".vscode"] |
Names that are never hidden (see above). |
explorerFilter.customPatterns |
[] |
Extra glob patterns to hide, e.g. **/*.tmp. |
explorerFilter.target |
workspace |
Write files.exclude to workspace or global settings. |
Commands
| Command |
Title |
explorer-filter.toggle |
Explorer Filter: Toggle Filter |
explorer-filter.enable |
Explorer Filter: Hide Filtered Items |
explorer-filter.disable |
Explorer Filter: Show Filtered Items |
explorer-filter.refresh |
Explorer Filter: Reapply Filter |
explorer-filter.openSettings |
Explorer Filter: Open Settings |
Scripts
| Script |
What it does |
bun run compile |
Bundle once to dist/ (with source maps). |
bun run watch |
Rebuild on change. |
bun run check-types |
Type-check with tsc --noEmit. |
bun run bundle |
Minified production bundle (used by vscode:prepublish). |
bun run package |
Build a .vsix via @vscode/vsce. |
Note: VS Code extensions run on Node.js, not the bun runtime. Here bun is
the package manager and the bundler (bun build); the extension uses only the
vscode and Node APIs.
Project layout
explorer-filter/
├─ .vscode/ # launch + build tasks for F5 debugging
├─ src/
│ ├─ extension.ts # activate/deactivate + commands
│ ├─ presets.ts # preset filter bundles (edit me)
│ ├─ filterState.ts # settings -> files.exclude reconciliation
│ └─ gitignore.ts # .gitignore -> exclude globs (git + fallback)
├─ package.json # manifest + settings + scripts
├─ tsconfig.json
└─ .vscodeignore # what NOT to ship in the .vsix
How it works
files.exclude is a map of glob -> boolean. On every change the extension
resolves the active patterns (enabled bundles + custom patterns + .gitignore),
records the keys it owns in workspaceState, and rewrites files.exclude —
removing only its previously-owned keys first. That keeps your own exclude rules
intact while the managed slice stays in sync with your settings.
License
MIT