77 lines
1.6 KiB
TypeScript
77 lines
1.6 KiB
TypeScript
import { isDeepEqual } from "remeda"
|
|
|
|
export namespace Keybind {
|
|
export type Info = {
|
|
ctrl: boolean
|
|
meta: boolean
|
|
shift: boolean
|
|
leader: boolean
|
|
name: string
|
|
}
|
|
|
|
export function match(a: Info, b: Info): boolean {
|
|
return isDeepEqual(a, b)
|
|
}
|
|
|
|
export function toString(info: Info): string {
|
|
const parts: string[] = []
|
|
|
|
if (info.ctrl) parts.push("ctrl")
|
|
if (info.meta) parts.push("alt")
|
|
if (info.shift) parts.push("shift")
|
|
if (info.name) {
|
|
if (info.name === "delete") parts.push("del")
|
|
else parts.push(info.name)
|
|
}
|
|
|
|
let result = parts.join("+")
|
|
|
|
if (info.leader) {
|
|
result = result ? `<leader> ${result}` : `<leader>`
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
export function parse(key: string): Info[] {
|
|
if (key === "none") return []
|
|
|
|
return key.split(",").map((combo) => {
|
|
// Handle <leader> syntax by replacing with leader+
|
|
const normalized = combo.replace(/<leader>/g, "leader+")
|
|
const parts = normalized.toLowerCase().split("+")
|
|
const info: Info = {
|
|
ctrl: false,
|
|
meta: false,
|
|
shift: false,
|
|
leader: false,
|
|
name: "",
|
|
}
|
|
|
|
for (const part of parts) {
|
|
switch (part) {
|
|
case "ctrl":
|
|
info.ctrl = true
|
|
break
|
|
case "alt":
|
|
case "meta":
|
|
case "option":
|
|
info.meta = true
|
|
break
|
|
case "shift":
|
|
info.shift = true
|
|
break
|
|
case "leader":
|
|
info.leader = true
|
|
break
|
|
default:
|
|
info.name = part
|
|
break
|
|
}
|
|
}
|
|
|
|
return info
|
|
})
|
|
}
|
|
}
|