resolveKeyWithChordState method

ChordResolveResult resolveKeyWithChordState(
  1. ParsedKeystroke keystroke,
  2. List<KeybindingContext> activeContexts
)

Resolve a keystroke with chord state support. Handles multi-keystroke chord bindings like "ctrl+k ctrl+s".

Implementation

ChordResolveResult resolveKeyWithChordState(
  ParsedKeystroke keystroke,
  List<KeybindingContext> activeContexts,
) {
  // Cancel chord on escape.
  if (keystroke.key == 'escape' && _pendingChord != null) {
    _pendingChord = null;
    return const ChordCancelledResult();
  }

  // Build the full chord sequence to test.
  final testChord = _pendingChord != null
      ? [..._pendingChord!, keystroke]
      : [keystroke];

  // Filter bindings by active contexts.
  final ctxSet = activeContexts.toSet();
  final contextBindings = _bindings
      .where((b) => ctxSet.contains(b.context))
      .toList();

  // Check if this could be a prefix for longer chords. Track null-overrides
  // to avoid entering chord-wait for bindings that have been unbound.
  final chordWinners = <String, String?>{};
  for (final binding in contextBindings) {
    if (binding.chord.length > testChord.length &&
        chordPrefixMatches(testChord, binding)) {
      chordWinners[chordToString(binding.chord)] = binding.action;
    }
  }
  var hasLongerChords = false;
  for (final action in chordWinners.values) {
    if (action != null) {
      hasLongerChords = true;
      break;
    }
  }

  // If this keystroke could start a longer chord, prefer that.
  if (hasLongerChords) {
    _pendingChord = testChord;
    return ChordStartedResult(testChord);
  }

  // Check for exact matches (last one wins).
  ParsedBinding? exactMatch;
  for (final binding in contextBindings) {
    if (chordExactlyMatches(testChord, binding)) {
      exactMatch = binding;
    }
  }

  if (exactMatch != null) {
    _pendingChord = null;
    if (exactMatch.action == null) return const ChordUnboundResult();
    return ChordMatchResult(exactMatch.action!);
  }

  // No match and no potential longer chords.
  if (_pendingChord != null) {
    _pendingChord = null;
    return const ChordCancelledResult();
  }

  return const ChordNoMatchResult();
}