refactor(editor): use shared rankVocab in autocomplete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2875993339
commit
ca6a7aa74c
2 changed files with 12 additions and 34 deletions
18
l4d2web/l4d2web/static/vendor/editor.bundle.js
vendored
18
l4d2web/l4d2web/static/vendor/editor.bundle.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,38 +1,16 @@
|
||||||
import { autocompletion } from "@codemirror/autocomplete";
|
import { autocompletion } from "@codemirror/autocomplete";
|
||||||
|
import { rankVocab } from "./vocab-rank.js";
|
||||||
|
|
||||||
const WORD_RE = /[A-Za-z0-9_]{2,}/;
|
const WORD_RE = /[A-Za-z0-9_]{2,}/;
|
||||||
|
|
||||||
function rank(query, label) {
|
|
||||||
const q = query.toLowerCase();
|
|
||||||
const l = label.toLowerCase();
|
|
||||||
if (l === q) return 0;
|
|
||||||
if (l.startsWith(q)) return 1 + l.length; // shorter prefix matches first
|
|
||||||
const i = l.indexOf(q);
|
|
||||||
if (i !== -1) return 10000 + i; // substring matches after all prefix matches
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function vocabCompletions(vocab) {
|
export function vocabCompletions(vocab) {
|
||||||
// vocab: { cvars: [{name, desc?}, …], commands: [{name, desc?}, …] }
|
// vocab: { cvars: [{name, desc?}, …], commands: [{name, desc?}, …] }
|
||||||
const entries = [
|
|
||||||
...vocab.cvars.map(e => ({ ...e, kind: "cvar" })),
|
|
||||||
...vocab.commands.map(e => ({ ...e, kind: "command" })),
|
|
||||||
];
|
|
||||||
|
|
||||||
return (context) => {
|
return (context) => {
|
||||||
const word = context.matchBefore(WORD_RE);
|
const word = context.matchBefore(WORD_RE);
|
||||||
if (!word || (word.from === word.to && !context.explicit)) return null;
|
if (!word || (word.from === word.to && !context.explicit)) return null;
|
||||||
const q = word.text;
|
|
||||||
|
|
||||||
const scored = [];
|
const ranked = rankVocab(word.text, vocab);
|
||||||
for (const e of entries) {
|
const options = ranked.map(e => ({
|
||||||
const r = rank(q, e.name);
|
|
||||||
if (r === -1) continue;
|
|
||||||
scored.push([r, e]);
|
|
||||||
if (scored.length > 200) break; // bound work; we cap to 50 below
|
|
||||||
}
|
|
||||||
scored.sort((a, b) => a[0] - b[0]);
|
|
||||||
const options = scored.slice(0, 50).map(([, e]) => ({
|
|
||||||
label: e.name,
|
label: e.name,
|
||||||
info: e.desc || e.kind,
|
info: e.desc || e.kind,
|
||||||
type: e.kind === "command" ? "function" : "variable",
|
type: e.kind === "command" ? "function" : "variable",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue