source dump of claude code
at main 203 lines 5.0 kB view raw
1import type { 2 Chord, 3 KeybindingBlock, 4 ParsedBinding, 5 ParsedKeystroke, 6} from './types.js' 7 8/** 9 * Parse a keystroke string like "ctrl+shift+k" into a ParsedKeystroke. 10 * Supports various modifier aliases (ctrl/control, alt/opt/option/meta, 11 * cmd/command/super/win). 12 */ 13export function parseKeystroke(input: string): ParsedKeystroke { 14 const parts = input.split('+') 15 const keystroke: ParsedKeystroke = { 16 key: '', 17 ctrl: false, 18 alt: false, 19 shift: false, 20 meta: false, 21 super: false, 22 } 23 for (const part of parts) { 24 const lower = part.toLowerCase() 25 switch (lower) { 26 case 'ctrl': 27 case 'control': 28 keystroke.ctrl = true 29 break 30 case 'alt': 31 case 'opt': 32 case 'option': 33 keystroke.alt = true 34 break 35 case 'shift': 36 keystroke.shift = true 37 break 38 case 'meta': 39 keystroke.meta = true 40 break 41 case 'cmd': 42 case 'command': 43 case 'super': 44 case 'win': 45 keystroke.super = true 46 break 47 case 'esc': 48 keystroke.key = 'escape' 49 break 50 case 'return': 51 keystroke.key = 'enter' 52 break 53 case 'space': 54 keystroke.key = ' ' 55 break 56 case '↑': 57 keystroke.key = 'up' 58 break 59 case '↓': 60 keystroke.key = 'down' 61 break 62 case '←': 63 keystroke.key = 'left' 64 break 65 case '→': 66 keystroke.key = 'right' 67 break 68 default: 69 keystroke.key = lower 70 break 71 } 72 } 73 74 return keystroke 75} 76 77/** 78 * Parse a chord string like "ctrl+k ctrl+s" into an array of ParsedKeystrokes. 79 */ 80export function parseChord(input: string): Chord { 81 // A lone space character IS the space key binding, not a separator 82 if (input === ' ') return [parseKeystroke('space')] 83 return input.trim().split(/\s+/).map(parseKeystroke) 84} 85 86/** 87 * Convert a ParsedKeystroke to its canonical string representation for display. 88 */ 89export function keystrokeToString(ks: ParsedKeystroke): string { 90 const parts: string[] = [] 91 if (ks.ctrl) parts.push('ctrl') 92 if (ks.alt) parts.push('alt') 93 if (ks.shift) parts.push('shift') 94 if (ks.meta) parts.push('meta') 95 if (ks.super) parts.push('cmd') 96 // Use readable names for display 97 const displayKey = keyToDisplayName(ks.key) 98 parts.push(displayKey) 99 return parts.join('+') 100} 101 102/** 103 * Map internal key names to human-readable display names. 104 */ 105function keyToDisplayName(key: string): string { 106 switch (key) { 107 case 'escape': 108 return 'Esc' 109 case ' ': 110 return 'Space' 111 case 'tab': 112 return 'tab' 113 case 'enter': 114 return 'Enter' 115 case 'backspace': 116 return 'Backspace' 117 case 'delete': 118 return 'Delete' 119 case 'up': 120 return '↑' 121 case 'down': 122 return '↓' 123 case 'left': 124 return '←' 125 case 'right': 126 return '→' 127 case 'pageup': 128 return 'PageUp' 129 case 'pagedown': 130 return 'PageDown' 131 case 'home': 132 return 'Home' 133 case 'end': 134 return 'End' 135 default: 136 return key 137 } 138} 139 140/** 141 * Convert a Chord to its canonical string representation for display. 142 */ 143export function chordToString(chord: Chord): string { 144 return chord.map(keystrokeToString).join(' ') 145} 146 147/** 148 * Display platform type - a subset of Platform that we care about for display. 149 * WSL and unknown are treated as linux for display purposes. 150 */ 151type DisplayPlatform = 'macos' | 'windows' | 'linux' | 'wsl' | 'unknown' 152 153/** 154 * Convert a ParsedKeystroke to a platform-appropriate display string. 155 * Uses "opt" for alt on macOS, "alt" elsewhere. 156 */ 157export function keystrokeToDisplayString( 158 ks: ParsedKeystroke, 159 platform: DisplayPlatform = 'linux', 160): string { 161 const parts: string[] = [] 162 if (ks.ctrl) parts.push('ctrl') 163 // Alt/meta are equivalent in terminals, show platform-appropriate name 164 if (ks.alt || ks.meta) { 165 // Only macOS uses "opt", all other platforms use "alt" 166 parts.push(platform === 'macos' ? 'opt' : 'alt') 167 } 168 if (ks.shift) parts.push('shift') 169 if (ks.super) { 170 parts.push(platform === 'macos' ? 'cmd' : 'super') 171 } 172 // Use readable names for display 173 const displayKey = keyToDisplayName(ks.key) 174 parts.push(displayKey) 175 return parts.join('+') 176} 177 178/** 179 * Convert a Chord to a platform-appropriate display string. 180 */ 181export function chordToDisplayString( 182 chord: Chord, 183 platform: DisplayPlatform = 'linux', 184): string { 185 return chord.map(ks => keystrokeToDisplayString(ks, platform)).join(' ') 186} 187 188/** 189 * Parse keybinding blocks (from JSON config) into a flat list of ParsedBindings. 190 */ 191export function parseBindings(blocks: KeybindingBlock[]): ParsedBinding[] { 192 const bindings: ParsedBinding[] = [] 193 for (const block of blocks) { 194 for (const [key, action] of Object.entries(block.bindings)) { 195 bindings.push({ 196 chord: parseChord(key), 197 action, 198 context: block.context, 199 }) 200 } 201 } 202 return bindings 203}