// Pure, dependency-free ranking of a vocabulary against a query string. // Used by both the CodeMirror editor (via autocomplete.js) and the // runtime console (via the vocab-rank bundle exposed on window). // // Score (lower = better): // exact match → 0 // prefix match → 1 + label.length (shorter prefix matches win) // substring match → 10000 + indexOf (earlier substring beats later) // no match → -1 (excluded) function score(query, label) { if (label === query) return 0; if (label.startsWith(query)) return 1 + label.length; const i = label.indexOf(query); if (i !== -1) return 10000 + i; return -1; } export function rankVocab(query, vocab, { limit = 50 } = {}) { if (!query) return []; const q = query.toLowerCase(); const entries = [ ...vocab.cvars.map(e => ({ ...e, kind: "cvar" })), ...vocab.commands.map(e => ({ ...e, kind: "command" })), ]; const scored = []; for (const e of entries) { const s = score(q, e.name.toLowerCase()); if (s === -1) continue; scored.push([s, e]); if (scored.length > limit * 4) break; } scored.sort((a, b) => a[0] - b[0]); return scored.slice(0, limit).map(([, e]) => e); }