@@ -14,6 +14,83 @@ param($query)
1414
1515$list = [System.Collections.Generic.List [PSCustomObject ]]::new()
1616
17+ # === Search index cache (JSON-based, faster than SQLite) ===
18+ $searchCachePath = Join-Path $scoopdir ' search-cache.json'
19+ $searchIndexApps = $null
20+ $searchIndexBins = $null
21+
22+ function init_search_cache {
23+ if (-not (Test-Path $searchCachePath )) { return $false }
24+ try {
25+ $cache = Get-Content $searchCachePath - Raw | ConvertFrom-Json - ErrorAction Stop
26+ $cacheAge = (Get-Date ) - [datetime ]::Parse($cache.timestamp )
27+ if ($cacheAge.TotalHours -ge 24 ) { return $false }
28+ # Cross-check file count for staleness
29+ $currentCount = 0
30+ Get-LocalBucket | ForEach-Object {
31+ $dir = Find-BucketDirectory $_
32+ $currentCount += (Get-ChildItem $dir - Filter ' *.json' - Recurse - ErrorAction SilentlyContinue).Count
33+ }
34+ if ($cache.fileCount -ne $currentCount ) { return $false }
35+ $script :searchIndexApps = @ {}
36+ foreach ($prop in $cache.apps.PSObject.Properties ) {
37+ $script :searchIndexApps [$prop.Name ] = @ { path = $prop.Value.path ; bucket = $prop.Value.bucket }
38+ }
39+ $script :searchIndexBins = @ {}
40+ foreach ($prop in $cache.bins.PSObject.Properties ) {
41+ $script :searchIndexBins [$prop.Name ] = @ ($prop.Value )
42+ }
43+ return $true
44+ } catch { return $false }
45+ }
46+
47+ function build_search_cache {
48+ $allPathsByBucket = @ {}
49+ Get-LocalBucket | ForEach-Object {
50+ $dir = Find-BucketDirectory $_
51+ $paths = @ (Get-ChildItem $dir - Filter ' *.json' - Recurse - ErrorAction SilentlyContinue | ForEach-Object { $_.FullName })
52+ if ($paths.Count -gt 0 ) { $allPathsByBucket [$_ ] = $paths }
53+ }
54+ $totalCount = ($allPathsByBucket.Values | ForEach-Object { $_.Count } | Measure-Object - Sum).Sum
55+ $newApps = @ {}
56+ $newBins = @ {}
57+
58+ foreach ($bucket in $allPathsByBucket.Keys ) {
59+ foreach ($filePath in $allPathsByBucket [$bucket ]) {
60+ $appName = [System.IO.Path ]::GetFileNameWithoutExtension($filePath )
61+ $newApps [$appName ] = @ { path = $filePath ; bucket = $bucket }
62+ try {
63+ $manifest = Get-Content - Path $filePath - Raw | ConvertFrom-Json - ErrorAction Stop
64+ if (-not $manifest.bin ) { continue }
65+ foreach ($binEntry in $manifest.bin ) {
66+ $exe = $null ; $alias = $null
67+ if ($binEntry -is [System.Object []]) {
68+ $exe = $binEntry [0 ]
69+ $alias = if ($binEntry.Count -gt 1 ) { $binEntry [1 ] } else { $null }
70+ } else { $exe = $binEntry }
71+ $exeName = [System.IO.Path ]::GetFileNameWithoutExtension([string ]$exe ).ToLower()
72+ if ($exeName ) {
73+ if (-not $newBins.ContainsKey ($exeName )) { $newBins [$exeName ] = @ () }
74+ if ($appName -notin $newBins [$exeName ]) { $newBins [$exeName ] += $appName }
75+ }
76+ if ($alias ) {
77+ $aliasName = $alias.ToLower ()
78+ if ($aliasName ) {
79+ if (-not $newBins.ContainsKey ($aliasName )) { $newBins [$aliasName ] = @ () }
80+ if ($appName -notin $newBins [$aliasName ]) { $newBins [$aliasName ] += $appName }
81+ }
82+ }
83+ }
84+ } catch { }
85+ }
86+ }
87+ $cacheData = [PSCustomObject ]@ { timestamp = (Get-Date ).ToString(' o' ); fileCount = $totalCount ; apps = [PSCustomObject ]$newApps ; bins = [PSCustomObject ]$newBins }
88+ $cacheData | ConvertTo-Json - Compress - Depth 4 | Set-Content $searchCachePath - Encoding UTF8
89+ $script :searchIndexApps = $newApps
90+ $script :searchIndexBins = $newBins
91+ return $true
92+ }
93+
1794function bin_match ($manifest , $query ) {
1895 if (! $manifest.bin ) { return $false }
1996 $bins = foreach ($bin in $manifest.bin ) {
0 commit comments