( blocks: KeybindingBlock[], )
| 334 | * Only checks user bindings (not default + user merged). |
| 335 | */ |
| 336 | export function checkDuplicates( |
| 337 | blocks: KeybindingBlock[], |
| 338 | ): KeybindingWarning[] { |
| 339 | const warnings: KeybindingWarning[] = [] |
| 340 | const seenByContext = new Map<string, Map<string, string>>() |
| 341 | |
| 342 | for (const block of blocks) { |
| 343 | const contextMap = |
| 344 | seenByContext.get(block.context) ?? new Map<string, string>() |
| 345 | seenByContext.set(block.context, contextMap) |
| 346 | |
| 347 | for (const [key, action] of Object.entries(block.bindings)) { |
| 348 | const normalizedKey = normalizeKeyForComparison(key) |
| 349 | const existingAction = contextMap.get(normalizedKey) |
| 350 | |
| 351 | if (existingAction && existingAction !== action) { |
| 352 | warnings.push({ |
| 353 | type: 'duplicate', |
| 354 | severity: 'warning', |
| 355 | message: `Duplicate binding "${key}" in ${block.context} context`, |
| 356 | key, |
| 357 | context: block.context, |
| 358 | action: action ?? 'null (unbind)', |
| 359 | suggestion: `Previously bound to "${existingAction}". Only the last binding will be used.`, |
| 360 | }) |
| 361 | } |
| 362 | |
| 363 | contextMap.set(normalizedKey, action ?? 'null') |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | return warnings |
| 368 | } |
| 369 | |
| 370 | /** |
| 371 | * Check for reserved shortcuts that may not work. |
no test coverage detected