// `#N` and `@user` in text the user is typing (spec §6.2): what is being // completed at the cursor, and which reference a position sits on. No // vscode imports, so it is tested with plain Node. /** A reference being typed: `#12` (issue or proposal) or `@an` (a user). */ export type Typing = { kind: "number"; prefix: string; start: number } | { kind: "user"; prefix: string; start: number }; /** * What the text before the cursor is in the middle of typing, if anything. * A reference starts a word: after the line start, whitespace or an * opening bracket, so `a#1` and `mail@host` are not references. */ export function typingAt(before: string): Typing | undefined { const n = /(^|[\s([{])#(\d*)$/.exec(before); if (n) { return { kind: "number", prefix: n[2], start: before.length - n[2].length - 1 }; } const u = /(^|[\s([{])@([A-Za-z0-9][A-Za-z0-9_-]*|)$/.exec(before); if (u) { return { kind: "user", prefix: u[2], start: before.length - u[2].length - 1 }; } return undefined; } /** The `#N` reference covering `column` of `line`, with its span. */ export function numberAt(line: string, column: number): { number: number; start: number; end: number } | undefined { const re = /(^|[\s([{])#(\d+)\b/g; for (let m = re.exec(line); m; m = re.exec(line)) { const start = m.index + m[1].length; const end = start + 1 + m[2].length; if (column >= start && column <= end) { return { number: Number(m[2]), start, end }; } } return undefined; } /** A repository root named by an SCM input box's URI query (`rootUri=file:///…`). */ export function rootFromScmQuery(query: string): string | undefined { const raw = new URLSearchParams(query).get("rootUri"); if (!raw) { return undefined; } try { return decodeURIComponent(new URL(raw).pathname); } catch { return undefined; } }