import { INLINE_TERMINAL_CONTEXT_PLACEHOLDER, type TerminalContextDraft, } from "./lib/terminalContext"; export type ComposerPromptSegment = | { type: "text"; text: string; } | { type: "mention"; path: string; } | { type: "terminal-context"; context: TerminalContextDraft | null; }; const MENTION_TOKEN_REGEX = /(^|\s)@([^\s@]+)(?=\s)/g; function pushTextSegment(segments: ComposerPromptSegment[], text: string): void { if (!text) return; const last = segments[segments.length - 1]; if (last && last.type === "text") { last.text += text; return; } segments.push({ type: "text", text }); } function splitPromptTextIntoComposerSegments(text: string): ComposerPromptSegment[] { const segments: ComposerPromptSegment[] = []; if (!text) { return segments; } let cursor = 0; for (const match of text.matchAll(MENTION_TOKEN_REGEX)) { const fullMatch = match[0]; const prefix = match[1] ?? ""; const path = match[2] ?? ""; const matchIndex = match.index ?? 0; const mentionStart = matchIndex + prefix.length; const mentionEnd = mentionStart + fullMatch.length - prefix.length; if (mentionStart > cursor) { pushTextSegment(segments, text.slice(cursor, mentionStart)); } if (path.length > 0) { segments.push({ type: "mention", path }); } else { pushTextSegment(segments, text.slice(mentionStart, mentionEnd)); } cursor = mentionEnd; } if (cursor < text.length) { pushTextSegment(segments, text.slice(cursor)); } return segments; } export function splitPromptIntoComposerSegments( prompt: string, terminalContexts: ReadonlyArray = [], ): ComposerPromptSegment[] { if (!prompt) { return []; } const segments: ComposerPromptSegment[] = []; let textCursor = 0; let terminalContextIndex = 0; for (let index = 0; index < prompt.length; index += 1) { if (prompt[index] !== INLINE_TERMINAL_CONTEXT_PLACEHOLDER) { continue; } if (index > textCursor) { segments.push(...splitPromptTextIntoComposerSegments(prompt.slice(textCursor, index))); } segments.push({ type: "terminal-context", context: terminalContexts[terminalContextIndex] ?? null, }); terminalContextIndex += 1; textCursor = index + 1; } if (textCursor < prompt.length) { segments.push(...splitPromptTextIntoComposerSegments(prompt.slice(textCursor))); } return segments; }