/** * @file promptTokens — splits a prompt into plain text, `/command` and * `@path` tokens, so the prompt box and a sent message colour them the same * way. A token starts a word (the line start or after whitespace), like the * prompt box's autocomplete, so `a/b`, `me@x.io` and `/home/x` stay text. * @author Nguyễn Ngọc Trí Vĩ */ export type PromptToken = { kind: "text" | "slash" | "mention"; text: string }; /** A token's colours, shared by the prompt box and a sent message; `@path` * takes the chat's path-link violet. */ export const TOKEN_TONE = { slash: "bg-accent/15 text-accent", mention: "bg-violet-500/15 text-violet-700 dark:text-violet-300", } as const; // `/name` (plugin skills are `plugin:name`) ending the word; `@path` minus a // trailing full stop or comma, which is prose. const TOKEN_RE = /(?<=^|\s)(?:\/[\w:.-]+(?=\s|$)|@[^\s]*[^\s.,;:!?)])/g; export function promptTokens(text: string): PromptToken[] { const out: PromptToken[] = []; let at = 0; for (const m of text.matchAll(TOKEN_RE)) { if (m.index > at) out.push({ kind: "text", text: text.slice(at, m.index) }); out.push({ kind: m[0][0] === "/" ? "slash" : "mention", text: m[0] }); at = m.index + m[0].length; } if (at < text.length) out.push({ kind: "text", text: text.slice(at) }); return out; }