Files
paseo/packages/app/src/utils/working-directory-suggestions.ts
T
Mohamed Boudra e55dd5a212 fix(search): match complete paths in file and project search
Treat slash-separated fragments as searchable text and use the same full-path fuzzy matcher for daemon results and remembered project paths.
2026-08-19 12:18:23 +02:00

54 lines
1.5 KiB
TypeScript

import { scorePathMatch } from "@getpaseo/protocol/search/text-match";
export interface BuildWorkingDirectorySuggestionsInput {
recommendedPaths: string[];
serverPaths: string[];
query: string;
}
export function buildWorkingDirectorySuggestions(
input: BuildWorkingDirectorySuggestionsInput,
): string[] {
const query = input.query.trim();
const recommended = uniquePaths(input.recommendedPaths);
if (!query) {
return recommended;
}
const matchingRecommended = recommended.filter((path) =>
recommendedPathMatchesQuery(path, query),
);
// Server paths are already ranked by the daemon. Recommended paths use the
// same shared matcher, then keep their existing recommendation order.
return uniquePaths([...matchingRecommended, ...input.serverPaths]);
}
function uniquePaths(paths: string[]): string[] {
const seen = new Set<string>();
const ordered: string[] = [];
for (const path of paths) {
const trimmed = path.trim();
if (!trimmed || seen.has(trimmed)) {
continue;
}
seen.add(trimmed);
ordered.push(trimmed);
}
return ordered;
}
function recommendedPathMatchesQuery(path: string, query: string): boolean {
const candidate = normalizePath(path);
const normalizedQuery = normalizePath(query);
if (["~", "~/"].includes(normalizedQuery)) {
return true;
}
return scorePathMatch(normalizedQuery, candidate) !== null;
}
function normalizePath(value: string): string {
return value.trim().replace(/\\/g, "/").toLowerCase();
}