( query: string, candidates: VaultTextSearchCandidate[], limit: number, paths: Required<VaultTextSearchToolPaths> )
| 2236 | } |
| 2237 | |
| 2238 | async function runFzfSearch( |
| 2239 | query: string, |
| 2240 | candidates: VaultTextSearchCandidate[], |
| 2241 | limit: number, |
| 2242 | paths: Required<VaultTextSearchToolPaths> |
| 2243 | ): Promise<VaultTextSearchCandidate[]> { |
| 2244 | const fzf = await searchExecutable('fzf', paths) |
| 2245 | if (!fzf) { |
| 2246 | return rankSearchCandidates(query, candidates, limit).map( |
| 2247 | ({ score: _score, ...candidate }) => candidate |
| 2248 | ) |
| 2249 | } |
| 2250 | return await new Promise((resolve, reject) => { |
| 2251 | const child = spawn( |
| 2252 | fzf, |
| 2253 | ['--filter', query, '--delimiter=\t', '--nth=1,2,5', '--tiebreak=index'], |
| 2254 | { stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true } |
| 2255 | ) |
| 2256 | |
| 2257 | let stdout = '' |
| 2258 | let stderr = '' |
| 2259 | child.stdout.on('data', (chunk) => { |
| 2260 | stdout += chunk.toString() |
| 2261 | }) |
| 2262 | child.stderr.on('data', (chunk) => { |
| 2263 | stderr += chunk.toString() |
| 2264 | }) |
| 2265 | child.on('error', reject) |
| 2266 | child.on('close', (code) => { |
| 2267 | if (code !== 0 && code !== 1) { |
| 2268 | reject(new Error(stderr.trim() || `fzf exited with code ${code ?? 'unknown'}`)) |
| 2269 | return |
| 2270 | } |
| 2271 | const matches = stdout |
| 2272 | .split(/\r?\n/) |
| 2273 | .filter(Boolean) |
| 2274 | .slice(0, limit) |
| 2275 | .map((line) => { |
| 2276 | const [pathValue, title, folderValue, lineNumberValue, lineText] = line.split('\t') |
| 2277 | const folder = folderValue === 'quick' || folderValue === 'archive' ? folderValue : 'inbox' |
| 2278 | return { |
| 2279 | path: pathValue, |
| 2280 | title, |
| 2281 | folder, |
| 2282 | lineNumber: Number(lineNumberValue), |
| 2283 | lineText |
| 2284 | } as VaultTextSearchCandidate |
| 2285 | }) |
| 2286 | if (matches.length > 0) { |
| 2287 | resolve(matches) |
| 2288 | return |
| 2289 | } |
| 2290 | resolve( |
| 2291 | rankSearchCandidates(query, candidates, limit).map( |
| 2292 | ({ score: _score, ...candidate }) => candidate |
| 2293 | ) |
| 2294 | ) |
| 2295 | }) |
no test coverage detected