| 1 | import { |
| 2 | KeybindingRule as KeybindingRuleSchema, |
| 3 | type KeybindingCommand, |
| 4 | type KeybindingRule, |
| 5 | type ResolvedKeybindingsConfig, |
| 6 | } from "@t3tools/contracts"; |
| 7 | import * as Schema from "effect/Schema"; |
| 8 | |
| 9 | export const PROJECT_SCRIPT_KEYBINDING_INVALID_MESSAGE = "Invalid keybinding."; |
| 10 | |
| 11 | const decodeKeybindingRule = Schema.decodeUnknownOption(KeybindingRuleSchema); |
| 12 | |
| 13 | function normalizeProjectScriptKeybindingInput( |
| 14 | keybinding: string | null | undefined, |
| 15 | ): string | null { |
| 16 | const trimmed = keybinding?.trim() ?? ""; |
| 17 | return trimmed.length > 0 ? trimmed : null; |
| 18 | } |
| 19 | |
| 20 | export function decodeProjectScriptKeybindingRule(input: { |
| 21 | keybinding: string | null | undefined; |
| 22 | command: KeybindingCommand | null; |
| 23 | }): KeybindingRule | null { |
| 24 | const normalizedKey = normalizeProjectScriptKeybindingInput(input.keybinding); |
| 25 | if (!normalizedKey) return null; |
| 26 | |
| 27 | if (input.command === null) { |
| 28 | throw new Error(PROJECT_SCRIPT_KEYBINDING_INVALID_MESSAGE); |
| 29 | } |
| 30 | |
| 31 | const decoded = decodeKeybindingRule({ |
| 32 | key: normalizedKey, |
| 33 | command: input.command, |
| 34 | }); |
| 35 | if (decoded._tag === "None") { |
| 36 | throw new Error(PROJECT_SCRIPT_KEYBINDING_INVALID_MESSAGE); |
| 37 | } |
| 38 | return decoded.value; |
| 39 | } |
| 40 | |
| 41 | export function keybindingValueForCommand( |
| 42 | keybindings: ResolvedKeybindingsConfig, |
| 43 | command: KeybindingCommand | null, |
| 44 | ): string | null { |
| 45 | if (command === null) return null; |
| 46 | for (let index = keybindings.length - 1; index >= 0; index -= 1) { |
| 47 | const binding = keybindings[index]; |
| 48 | if (!binding || binding.command !== command) continue; |
| 49 | |
| 50 | const parts: string[] = []; |
| 51 | if (binding.shortcut.modKey) parts.push("mod"); |
| 52 | if (binding.shortcut.ctrlKey) parts.push("ctrl"); |
| 53 | if (binding.shortcut.metaKey) parts.push("meta"); |
| 54 | if (binding.shortcut.altKey) parts.push("alt"); |
| 55 | if (binding.shortcut.shiftKey) parts.push("shift"); |
| 56 | const keyToken = |
| 57 | binding.shortcut.key === " " |
| 58 | ? "space" |
| 59 | : binding.shortcut.key === "escape" |
| 60 | ? "esc" |
| 61 | : binding.shortcut.key; |
| 62 | parts.push(keyToken); |
| 63 | return parts.join("+"); |
| 64 | } |
| 65 | return null; |
| 66 | } |