@@ -19,7 +19,9 @@ import '../models/documents/nodes/block.dart';
19
19
import '../models/documents/nodes/embeddable.dart' ;
20
20
import '../models/documents/nodes/line.dart' ;
21
21
import '../models/documents/nodes/node.dart' ;
22
+ import '../models/documents/nodes/leaf.dart' as leaf;
22
23
import '../models/documents/style.dart' ;
24
+ import '../utils/cast.dart' ;
23
25
import '../utils/delta.dart' ;
24
26
import '../utils/embeds.dart' ;
25
27
import '../utils/platform.dart' ;
@@ -428,6 +430,7 @@ class RawEditorState extends EditorState
428
430
actions: _actions,
429
431
child: Focus (
430
432
focusNode: widget.focusNode,
433
+ onKey: _onKey,
431
434
child: QuillKeyboardListener (
432
435
child: Container (
433
436
constraints: constraints,
@@ -440,6 +443,125 @@ class RawEditorState extends EditorState
440
443
);
441
444
}
442
445
446
+ KeyEventResult _onKey (node, RawKeyEvent event) {
447
+ // Don't handle key if there is a meta key pressed.
448
+ if (event.isAltPressed || event.isControlPressed || event.isMetaPressed) {
449
+ return KeyEventResult .ignored;
450
+ }
451
+
452
+ if (event is ! RawKeyDownEvent ) {
453
+ return KeyEventResult .ignored;
454
+ }
455
+
456
+ // Don't handle key if there is an active selection.
457
+ if (controller.selection.baseOffset != controller.selection.extentOffset) {
458
+ return KeyEventResult .ignored;
459
+ }
460
+
461
+ // Handle indenting blocks when pressing the tab key.
462
+ if (event.logicalKey == LogicalKeyboardKey .tab) {
463
+ return _handleTabKey (event);
464
+ }
465
+
466
+ // Handle inserting lists when space is pressed following
467
+ // a list initiating phrase.
468
+ if (event.logicalKey == LogicalKeyboardKey .space) {
469
+ return _handleSpaceKey (event);
470
+ }
471
+
472
+ return KeyEventResult .ignored;
473
+ }
474
+
475
+ KeyEventResult _handleSpaceKey (RawKeyEvent event) {
476
+ final child =
477
+ controller.document.queryChild (controller.selection.baseOffset);
478
+ if (child.node == null ) {
479
+ return KeyEventResult .ignored;
480
+ }
481
+
482
+ final line = child.node as Line ? ;
483
+ if (line == null ) {
484
+ return KeyEventResult .ignored;
485
+ }
486
+
487
+ final text = castOrNull< leaf.Text > (line.first);
488
+ if (text == null ) {
489
+ return KeyEventResult .ignored;
490
+ }
491
+
492
+ const olKeyPhrase = '1.' ;
493
+ const ulKeyPhrase = '-' ;
494
+
495
+ if (text.value == olKeyPhrase) {
496
+ _updateSelectionForKeyPhrase (olKeyPhrase, Attribute .ol);
497
+ } else if (text.value == ulKeyPhrase) {
498
+ _updateSelectionForKeyPhrase (ulKeyPhrase, Attribute .ul);
499
+ } else {
500
+ return KeyEventResult .ignored;
501
+ }
502
+
503
+ return KeyEventResult .handled;
504
+ }
505
+
506
+ KeyEventResult _handleTabKey (RawKeyEvent event) {
507
+ final child =
508
+ controller.document.queryChild (controller.selection.baseOffset);
509
+
510
+ KeyEventResult insertTabCharacter () {
511
+ controller.replaceText (controller.selection.baseOffset, 0 , '\t ' , null );
512
+ _moveCursor (1 );
513
+ return KeyEventResult .handled;
514
+ }
515
+
516
+ if (child.node == null ) {
517
+ return insertTabCharacter ();
518
+ }
519
+
520
+ final node = child.node! ;
521
+
522
+ final parent = node.parent;
523
+ if (parent == null || parent is ! Block ) {
524
+ return insertTabCharacter ();
525
+ }
526
+
527
+ if (node is ! Line || (node.isNotEmpty && node.first is ! leaf.Text )) {
528
+ return insertTabCharacter ();
529
+ }
530
+
531
+ if (node.isNotEmpty && (node.first as leaf.Text ).value.isNotEmpty) {
532
+ return insertTabCharacter ();
533
+ }
534
+
535
+ final parentBlock = parent;
536
+ if (parentBlock.style.containsKey (Attribute .ol.key) ||
537
+ parentBlock.style.containsKey (Attribute .ul.key) ||
538
+ parentBlock.style.containsKey (Attribute .checked.key)) {
539
+ controller.indentSelection (! event.isShiftPressed);
540
+ return KeyEventResult .handled;
541
+ }
542
+
543
+ return insertTabCharacter ();
544
+ }
545
+
546
+ void _moveCursor (int chars) {
547
+ final selection = controller.selection;
548
+ controller.updateSelection (
549
+ controller.selection.copyWith (
550
+ baseOffset: selection.baseOffset + chars,
551
+ extentOffset: selection.baseOffset + chars),
552
+ ChangeSource .LOCAL );
553
+ }
554
+
555
+ void _updateSelectionForKeyPhrase (String phrase, Attribute attribute) {
556
+ controller
557
+ ..formatSelection (attribute)
558
+ ..replaceText (controller.selection.baseOffset - phrase.length,
559
+ phrase.length, '' , null );
560
+
561
+ // It is unclear why the selection moves forward the edit distance.
562
+ _moveCursor (- 2 );
563
+ }
564
+
443
565
void _handleSelectionChanged (
444
566
TextSelection selection, SelectionChangedCause cause) {
445
567
final oldSelection = controller.selection;
@@ -2076,26 +2198,7 @@ class _IndentSelectionAction extends Action<IndentSelectionIntent> {
2076
2198
2077
2199
@override
2078
2200
void invoke (IndentSelectionIntent intent, [BuildContext ? context]) {
2079
- final indent =
2080
- state.controller.getSelectionStyle ().attributes[Attribute .indent.key];
2081
- if (indent == null ) {
2082
- if (intent.isIncrease) {
2083
- state.controller.formatSelection (Attribute .indentL1);
2084
- }
2085
- return ;
2086
- }
2087
- if (indent.value == 1 && ! intent.isIncrease) {
2088
- state.controller
2089
- .formatSelection (Attribute .clone (Attribute .indentL1, null ));
2090
- return ;
2091
- }
2092
- if (intent.isIncrease) {
2093
- state.controller
2094
- .formatSelection (Attribute .getIndentLevel (indent.value + 1 ));
2095
- return ;
2096
- }
2097
- state.controller
2098
- .formatSelection (Attribute .getIndentLevel (indent.value - 1 ));
2201
+ state.controller.indentSelection (intent.isIncrease);
2099
2202
}
2100
2203
2101
2204
@override
0 commit comments