Files
paseo/packages/app/src/utils/file-mention-autocomplete.ts
T
Mohamed Boudra 013e53881b fix(app): prevent infinite loop in @-mention scan when @ is at index 0
`findActiveFileMention` walked back through `@` candidates with
`lastIndexOf("@", atIndex - 1)`, but per spec a negative `position`
clamps to 0 — so once `atIndex` hit 0 with an invalid query (e.g. a
trailing space), the loop stepped from 0 back to 0 forever, freezing
the JS thread on every keystroke and forcing a quit.

Refs #596, #425
2026-04-28 19:16:04 +07:00

49 lines
1.3 KiB
TypeScript

export interface FileMentionRange {
start: number;
end: number;
query: string;
}
interface FindActiveFileMentionInput {
text: string;
cursorIndex: number;
}
interface ApplyFileMentionReplacementInput {
text: string;
mention: FileMentionRange;
relativePath: string;
}
const INVALID_MENTION_QUERY_CHARS = /[\s\n\r\t"']/;
export function findActiveFileMention(input: FindActiveFileMentionInput): FileMentionRange | null {
const clampedCursor = Math.max(0, Math.min(input.cursorIndex, input.text.length));
const beforeCursor = input.text.slice(0, clampedCursor);
for (
let atIndex = beforeCursor.lastIndexOf("@");
atIndex >= 0;
atIndex = atIndex === 0 ? -1 : beforeCursor.lastIndexOf("@", atIndex - 1)
) {
const query = beforeCursor.slice(atIndex + 1);
if (INVALID_MENTION_QUERY_CHARS.test(query)) {
continue;
}
return {
start: atIndex,
end: clampedCursor,
query,
};
}
return null;
}
export function applyFileMentionReplacement(input: ApplyFileMentionReplacementInput): string {
const safePath = input.relativePath.replace(/"/g, '\\"');
const before = input.text.slice(0, input.mention.start);
const after = input.text.slice(input.mention.end);
return `${before}"${safePath}"${after}`;
}