import type { ReadlineBinding } from "./keymap.js"; type TrieNode = { children: Map; binding?: ReadlineBinding; }; export type TrieResolution = | { kind: "none" } | { kind: "prefix" } | { kind: "exact"; binding: ReadlineBinding } | { kind: "exact-and-prefix"; binding: ReadlineBinding }; function createNode(): TrieNode { return { children: new Map() }; } /** Resolves terminal input against decoded inputrc key sequences. */ export class InputrcKeyTrie { readonly #root = createNode(); static fromEntries( entries: Iterable, ): InputrcKeyTrie { const trie = new InputrcKeyTrie(); for (const [sequence, binding] of entries) trie.add(sequence, binding); return trie; } add(sequence: string, binding: ReadlineBinding): void { if (sequence.length === 0) throw new RangeError("A key trie sequence must not be empty"); let node = this.#root; for (const character of sequence) { let child = node.children.get(character); if (child === undefined) { child = createNode(); node.children.set(character, child); } node = child; } node.binding = binding; } resolve(input: string): TrieResolution { let node = this.#root; for (const character of input) { const child = node.children.get(character); if (child === undefined) return { kind: "none" }; node = child; } if (node.binding === undefined) return node.children.size > 0 ? { kind: "prefix" } : { kind: "none" }; return node.children.size > 0 ? { kind: "exact-and-prefix", binding: node.binding } : { kind: "exact", binding: node.binding }; } }