Skip to content

Commit 21d32ef

Browse files
committed
Search: Add system folder exclusion toggle
- Toggle button in scope row, on by default, excludes common junk directories from results - Granular exclusion list: package managers (`node_modules`, `.cargo`, `.m2`), VCS (`.git`), build output (`dist`, `target`), caches (`Caches`, `GPUCache`, `ShaderCache`), macOS system (`Logs`, `Cookies`, `.Trash`, `.Spotlight-V100`), IDE caches (`workspaceStorage`, `DerivedData`) - Intentionally does NOT exclude `Library` or `Application Support` — those contain user data like email attachments (`~/Library/Mail/`) and iCloud files - Merges with user-specified scope excludes without duplicates
1 parent fb796e7 commit 21d32ef

2 files changed

Lines changed: 63 additions & 0 deletions

File tree

apps/desktop/src/lib/search/SearchDialog.svelte

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@
7070
setCaseSensitive,
7171
getScope,
7272
setScope,
73+
getExcludeSystemDirs,
74+
setExcludeSystemDirs,
75+
systemDirNames,
7376
buildSearchQuery,
7477
resetSearchState,
7578
type SizeFilter,
@@ -151,6 +154,7 @@
151154
const patternType = $derived(getPatternType())
152155
const caseSensitive = $derived(getCaseSensitive())
153156
const scope = $derived(getScope())
157+
const excludeSystemDirs = $derived(getExcludeSystemDirs())
154158
const scanning = $derived(isScanning())
155159
const entriesScanned = $derived(getEntriesScanned())
156160
@@ -254,6 +258,15 @@
254258
if (parsed.includePaths.length > 0) query.includePaths = parsed.includePaths
255259
if (parsed.excludePatterns.length > 0) query.excludeDirNames = parsed.excludePatterns
256260
}
261+
262+
// Merge system dir exclusions (avoid duplicates with user-specified excludes)
263+
if (getExcludeSystemDirs()) {
264+
const existing = new Set(query.excludeDirNames ?? [])
265+
const toAdd = systemDirNames.filter((d) => !existing.has(d))
266+
if (toAdd.length > 0) {
267+
query.excludeDirNames = [...(query.excludeDirNames ?? []), ...toAdd]
268+
}
269+
}
257270
const result = await searchFiles(query)
258271
setResults(result.entries)
259272
setTotalCount(result.totalCount)
@@ -421,6 +434,11 @@
421434
scheduleSearch()
422435
}
423436
437+
function toggleExcludeSystemDirs(): void {
438+
setExcludeSystemDirs(!getExcludeSystemDirs())
439+
scheduleSearch()
440+
}
441+
424442
function handleSizeFilterChange(e: Event): void {
425443
setSizeFilter((e.target as HTMLSelectElement).value as SizeFilter)
426444
scheduleSearch()
@@ -780,6 +798,23 @@
780798
i
781799
</button>
782800
</div>
801+
<button
802+
class="pattern-type-toggle"
803+
class:active={excludeSystemDirs}
804+
onclick={toggleExcludeSystemDirs}
805+
disabled={inputsDisabled}
806+
use:tooltip={{
807+
html:
808+
'<div style="max-width:320px">' +
809+
'<div style="font-weight:600;margin-bottom:4px">Exclude system and build folders</div>' +
810+
'<div style="color:var(--color-text-secondary)">node_modules, .git, Caches, Logs, and ' +
811+
String(systemDirNames.length - 4) + ' more</div>' +
812+
'</div>',
813+
}}
814+
aria-label={excludeSystemDirs ? 'System folders excluded' : 'System folders included'}
815+
>
816+
Filter
817+
</button>
783818
<button
784819
class="pattern-type-toggle"
785820
onclick={() => {

apps/desktop/src/lib/search/search-state.svelte.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,27 @@ let aiPrompt = $state('')
4545
// Scope (folder filter)
4646
let scope = $state('')
4747

48+
// System/build directory exclusion toggle (on by default)
49+
let excludeSystemDirs = $state(true)
50+
51+
/** Common system, build, and cache directory names to exclude from search results. */
52+
export const systemDirNames = [
53+
// Package managers & build tools
54+
'node_modules', '.pnpm-store', '.npm', '.yarn', '.cargo', '.m2', '.gradle',
55+
// VCS
56+
'.git', '.svn', '.hg',
57+
// Python
58+
'__pycache__', '.venv', 'venv', '.tox',
59+
// JS/TS build output
60+
'build', 'dist', '.next', '.nuxt', '.cache', '.parcel-cache', 'target',
61+
// macOS system & caches (granular — not Library or Application Support, those contain user data like Mail)
62+
'Caches', 'CacheStorage', 'Cache', 'GPUCache', 'ScriptCache', 'GrShaderCache', 'ShaderCache',
63+
'Logs', 'Cookies', 'WebKit', 'Saved Application State', '.Trash',
64+
'.Spotlight-V100', '.fseventsd', '.DocumentRevisions-V100',
65+
// IDE workspace caches
66+
'workspaceStorage', 'DerivedData',
67+
]
68+
4869
// Getters
4970
export function getIsIndexReady(): boolean {
5071
return isIndexReady
@@ -109,6 +130,9 @@ export function getCaseSensitive(): boolean {
109130
export function getScope(): string {
110131
return scope
111132
}
133+
export function getExcludeSystemDirs(): boolean {
134+
return excludeSystemDirs
135+
}
112136

113137
// Setters
114138
export function setIsIndexReady(value: boolean): void {
@@ -174,6 +198,9 @@ export function setCaseSensitive(value: boolean): void {
174198
export function setScope(value: string): void {
175199
scope = value
176200
}
201+
export function setExcludeSystemDirs(value: boolean): void {
202+
excludeSystemDirs = value
203+
}
177204

178205
/** Converts size input + unit to bytes. Returns undefined if empty or invalid. */
179206
export function parseSizeToBytes(value: string, unit: SizeUnit): number | undefined {
@@ -264,5 +291,6 @@ export function resetSearchState(): void {
264291
aiStatus = ''
265292
aiPrompt = ''
266293
scope = ''
294+
excludeSystemDirs = true
267295
isSearching = false
268296
}

0 commit comments

Comments
 (0)