start revive
This commit is contained in:
131
tests/keybind-matcher.test.ts
Normal file
131
tests/keybind-matcher.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { parseStroke, parseBindingSpec } from "../src/context/KeybindContext";
|
||||
|
||||
const cfg = {
|
||||
"move-down": parseBindingSpec(["j", "down"]),
|
||||
"move-up": parseBindingSpec(["k", "up"]),
|
||||
"goto-top": parseBindingSpec([["g", "g"]]),
|
||||
"goto-bottom": parseBindingSpec(["G"]),
|
||||
"toggle-select": parseBindingSpec(["space"]),
|
||||
"swipe-prev": parseBindingSpec(["h", "left"]),
|
||||
"audio-toggle": parseBindingSpec(["P"]),
|
||||
"audio-seek-forward": parseBindingSpec(["shift-."]),
|
||||
"audio-seek-backward": parseBindingSpec(["shift-,"]),
|
||||
sort: parseBindingSpec([","]),
|
||||
quit: parseBindingSpec(["q"]),
|
||||
command: parseBindingSpec([":"]),
|
||||
"tab-next": parseBindingSpec(["]"]),
|
||||
} as Record<string, ReturnType<typeof parseBindingSpec>>;
|
||||
|
||||
function eq(a: any, b: any) {
|
||||
return (
|
||||
a.key === b.key &&
|
||||
!!a.ctrl === !!b.ctrl &&
|
||||
!!a.shift === !!b.shift &&
|
||||
!!a.meta === !!b.meta
|
||||
);
|
||||
}
|
||||
function classify(candidate: any[]) {
|
||||
const exact: string[] = [];
|
||||
const prefix: string[] = [];
|
||||
for (const name of Object.keys(cfg)) {
|
||||
for (const seq of cfg[name]) {
|
||||
if (seq.length < candidate.length) continue;
|
||||
let p = true;
|
||||
for (let i = 0; i < candidate.length; i++)
|
||||
if (!eq(seq[i], candidate[i])) {
|
||||
p = false;
|
||||
break;
|
||||
}
|
||||
if (!p) continue;
|
||||
if (seq.length === candidate.length) exact.push(name);
|
||||
else prefix.push(name);
|
||||
}
|
||||
}
|
||||
return { exact, prefix };
|
||||
}
|
||||
function longest(names: string[]) {
|
||||
let best = names[0],
|
||||
bl = 0;
|
||||
for (const n of names)
|
||||
for (const s of cfg[n])
|
||||
if (s.length > bl) {
|
||||
bl = s.length;
|
||||
best = n;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
function sim(strokes: any[]) {
|
||||
let pending: any[] = [];
|
||||
let fired: string | null = null;
|
||||
for (const st of strokes) {
|
||||
const cand = [...pending, st];
|
||||
const { exact, prefix } = classify(cand);
|
||||
if (prefix.length > 0) {
|
||||
pending = cand;
|
||||
continue;
|
||||
}
|
||||
if (exact.length === 0) {
|
||||
const fresh = classify([st]);
|
||||
if (fresh.prefix.length > 0) {
|
||||
pending = [st];
|
||||
continue;
|
||||
}
|
||||
if (fresh.exact.length > 0) fired = longest(fresh.exact);
|
||||
else fired = null;
|
||||
} else fired = longest(exact);
|
||||
pending = [];
|
||||
}
|
||||
return fired;
|
||||
}
|
||||
const E = (k: string, o: any = {}) => ({ key: k, ...o });
|
||||
|
||||
let pass = 0,
|
||||
fail = 0;
|
||||
function check(label: string, got: string | null, want: string | null) {
|
||||
const ok = got === want;
|
||||
if (ok) pass++;
|
||||
else fail++;
|
||||
console.log(
|
||||
`${ok ? "PASS" : "FAIL"} ${label} => ${got}${ok ? "" : ` (want ${want})`}`,
|
||||
);
|
||||
}
|
||||
|
||||
check("j -> move-down", sim([E("j")]), "move-down");
|
||||
check("down -> move-down", sim([E("down")]), "move-down");
|
||||
check("gg -> goto-top", sim([E("g"), E("g")]), "goto-top");
|
||||
check("G -> goto-bottom", sim([E("g", { shift: true })]), "goto-bottom");
|
||||
check("space -> toggle-select", sim([E("space")]), "toggle-select");
|
||||
check("q -> quit", sim([E("q")]), "quit");
|
||||
check(": -> command", sim([E(":")]), "command");
|
||||
check("] -> tab-next", sim([E("]")]), "tab-next");
|
||||
check(
|
||||
"shift+p -> audio-toggle",
|
||||
sim([E("p", { shift: true })]),
|
||||
"audio-toggle",
|
||||
);
|
||||
check("plain p -> null", sim([E("p")]), null);
|
||||
check(
|
||||
"shift+, -> audio-seek-backward",
|
||||
sim([E(",", { shift: true })]),
|
||||
"audio-seek-backward",
|
||||
);
|
||||
check(", -> sort", sim([E(",")]), "sort");
|
||||
check(
|
||||
"shift+. -> audio-seek-forward",
|
||||
sim([E(".", { shift: true })]),
|
||||
"audio-seek-forward",
|
||||
);
|
||||
check(
|
||||
"g then j -> move-down (timeout-ish fallthrough)",
|
||||
sim([E("g"), E("j")]),
|
||||
"move-down",
|
||||
);
|
||||
|
||||
console.log(
|
||||
parseStroke("ctrl-d"),
|
||||
parseStroke("G"),
|
||||
parseStroke(">"),
|
||||
parseStroke("shift-return"),
|
||||
);
|
||||
console.log(`\n${pass} passed, ${fail} failed`);
|
||||
if (fail > 0) process.exit(1);
|
||||
Reference in New Issue
Block a user