// Enough hits to look past same-named neighbours (`ChatView.test.tsx`) without// asking for a full listing on a single click.export const WORKSPACE_BASENAME_LOOKUP_LIMIT = 25;// One counter for every caller: they all open the same panel, so the newest// click wins regardless of which one started the lookup.let latestLookupSequence = 0;/** Call the returned predicate when the search settles; false means a later click superseded it. */export function claimWorkspaceBasenameLookup(): () => boolean { latestLookupSequence += 1; const claimed = latestLookupSequence; return () => claimed === latestLookupSequence;}export interface WorkspaceEntryCandidate { readonly path: string; readonly kind: "file" | "directory";}function basenameOfPath(path: string): string { const separatorIndex = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")); return separatorIndex >= 0 ? path.slice(separatorIndex + 1) : path;}export function needsWorkspaceBasenameLookup(relativePath: string): boolean { const trimmed = relativePath.trim(); return trimmed.length > 0 && !trimmed.includes("/") && !trimmed.includes("\\");}export function pickWorkspaceBasenameMatch( basename: string, entries: ReadonlyArray<WorkspaceEntryCandidate>,): string | null { const target = basename.trim(); if (!target) return null; const files = entries.filter((entry) => entry.kind === "file"); const exact = files.find((entry) => basenameOfPath(entry.path) === target); if (exact) return exact.path; // Folded matching covers casing that drifted from disk, but `FOO.ts` against // both `Foo.ts` and `foo.ts` has no right answer, so it resolves to nothing // rather than opening whichever the index ranked first. const folded = target.toLowerCase(); const foldedMatches = files.filter( (entry) => basenameOfPath(entry.path).toLowerCase() === folded, ); return foldedMatches.length === 1 ? (foldedMatches[0]?.path ?? null) : null;}
// Enough hits to look past same-named neighbours (`ChatView.test.tsx`) without
// asking for a full listing on a single click.
export const WORKSPACE_BASENAME_LOOKUP_LIMIT = 25;
// One counter for every caller: they all open the same panel, so the newest
// click wins regardless of which one started the lookup.
let latestLookupSequence = 0;
/** Call the returned predicate when the search settles; false means a later click superseded it. */
export function claimWorkspaceBasenameLookup(): () => boolean {
latestLookupSequence += 1;
const claimed = latestLookupSequence;
return () => claimed === latestLookupSequence;
}
export interface WorkspaceEntryCandidate {
readonly path: string;
readonly kind: "file" | "directory";
}
function basenameOfPath(path: string): string {
const separatorIndex = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
return separatorIndex >= 0 ? path.slice(separatorIndex + 1) : path;
}
export function needsWorkspaceBasenameLookup(relativePath: string): boolean {
const trimmed = relativePath.trim();
return trimmed.length > 0 && !trimmed.includes("/") && !trimmed.includes("\\");
}
export function pickWorkspaceBasenameMatch(
basename: string,
entries: ReadonlyArray<WorkspaceEntryCandidate>,
): string | null {
const target = basename.trim();
if (!target) return null;
const files = entries.filter((entry) => entry.kind === "file");
const exact = files.find((entry) => basenameOfPath(entry.path) === target);
if (exact) return exact.path;
// Folded matching covers casing that drifted from disk, but `FOO.ts` against
// both `Foo.ts` and `foo.ts` has no right answer, so it resolves to nothing
// rather than opening whichever the index ranked first.
const folded = target.toLowerCase();
const foldedMatches = files.filter(
(entry) => basenameOfPath(entry.path).toLowerCase() === folded,
);
return foldedMatches.length === 1 ? (foldedMatches[0]?.path ?? null) : null;
}