(input: string)
| 1260 | } |
| 1261 | |
| 1262 | export function normalizeSequenceToken(input: string): string | null { |
| 1263 | const parts = input |
| 1264 | .split("+") |
| 1265 | .map((part) => part.trim()) |
| 1266 | .filter(Boolean); |
| 1267 | if (parts.length === 0) return null; |
| 1268 | const rawKey = parts.pop(); |
| 1269 | if (!rawKey) return null; |
| 1270 | let base = normalizeSequenceBaseToken(rawKey); |
| 1271 | if (!base) return null; |
| 1272 | const modifiers = normalizeModifiers( |
| 1273 | parts |
| 1274 | .map((part) => normalizeModifierToken(part)) |
| 1275 | .filter((part): part is NonNullable<typeof part> => !!part) |
| 1276 | .filter((part) => part !== "Mod"), |
| 1277 | ); |
| 1278 | // When a non-Shift modifier (Ctrl/Alt/Meta) is combined with a single |
| 1279 | // ASCII letter, canonicalize to uppercase. Event-produced tokens come |
| 1280 | // out lowercase (e.g. Ctrl+w → `'w'` since Shift isn't held), but the |
| 1281 | // convention in default bindings and user-written keymaps is uppercase |
| 1282 | // (`'Ctrl+W'`). Matching them requires a consistent canonical form. |
| 1283 | if ( |
| 1284 | base.length === 1 && |
| 1285 | /[a-zA-Z]/.test(base) && |
| 1286 | modifiers.some((m) => m === "Ctrl" || m === "Alt" || m === "Meta") |
| 1287 | ) { |
| 1288 | base = base.toUpperCase(); |
| 1289 | } |
| 1290 | return modifiers.length > 0 ? `${modifiers.join("+")}+${base}` : base; |
| 1291 | } |
| 1292 | |
| 1293 | export function normalizeSequenceBinding(input: string): string | null { |
| 1294 | const tokens = input |
no test coverage detected