keymap: support bare-modifier double-tap chords; double-Shift → quick-open (T-341)
The chord matcher couldn't represent a bare or double-tapped modifier: KeyChord.parse required a base key, so `shift shift` failed, and JetBrains "Search Everywhere" (double-Shift) was unbindable. Design decision: search-everywhere aliases clide's existing quick-open finder (not a new overlay) — bound across all four presets per the user. Changes: - KeyChord: a bare modifier name (`shift`, `ctrl`, `cmd`, …) parses as a modifier-free chord on that modifier's logical key, so parseSequence( 'shift shift') yields a two-chord double-tap. Adds KeyChord.bareModifier and modifierForLogicalKey. - ModifierTapTracker: headless, clock-injected double-tap detector. A bare modifier never forms a single chord; an intervening key breaks the gesture. - app.dart global handler feeds bare-modifier KeyDowns to the tracker and, on a double-tap, resolves the 2-chord sequence via the new KeymapService.resolveSequence. The existing single-chord path is untouched (zero behavioural risk to normal keys). - Presets: default/vim/vscode/jetbrains add `shift shift` → quickOpen.open. jetbrains header updated (the gesture is now expressible). Tests: bare-modifier parse/equality/round-trip; tracker window/reset/ different-modifier/consume; each shipped preset resolves double-Shift to QuickOpenIntent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ library;
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:clide/kernel/src/keymap/intents.dart';
|
||||
import 'package:clide/kernel/src/keymap/key_chord.dart';
|
||||
import 'package:clide/kernel/src/keymap/keymap.dart';
|
||||
import 'package:flutter/widgets.dart' show NextFocusIntent, PreviousFocusIntent;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@@ -49,4 +50,16 @@ void main() {
|
||||
expect(layer.bindings.any((b) => b.intent is NextFocusIntent), isTrue);
|
||||
expect(layer.bindings.any((b) => b.intent is PreviousFocusIntent), isTrue);
|
||||
});
|
||||
|
||||
// Every shipped preset aliases the double-Shift "Search Everywhere"
|
||||
// gesture to quick-open (T-341).
|
||||
final doubleShift = [KeyChord.bareModifier(KeyModifier.shift), KeyChord.bareModifier(KeyModifier.shift)];
|
||||
for (final file in presets) {
|
||||
final name = file.uri.pathSegments.last;
|
||||
test('$name resolves `shift shift` (double-tap) to quick-open', () {
|
||||
final km = Keymap([KeymapLayer.fromYaml(file.readAsStringSync())]);
|
||||
final m = km.match(doubleShift, const {});
|
||||
expect(m.exact, isA<QuickOpenIntent>(), reason: '$name should bind double-Shift to quickOpen.open');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user