@@ -1583,7 +1583,7 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM
1583
1583
switch (granularity) {
1584
1584
case TextGranularity .character:
1585
1585
final String text = range.textInside (fullText);
1586
- newPosition = _beyondTextBoundary (targetedEdge, forward, CharacterBoundary (text));
1586
+ newPosition = _moveBeyondTextBoundaryAtDirection (targetedEdge, forward, CharacterBoundary (text));
1587
1587
result = SelectionResult .end;
1588
1588
break ;
1589
1589
case TextGranularity .word:
@@ -1592,16 +1592,16 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM
1592
1592
return (forward ? offset >= text.length : offset == 0 )
1593
1593
|| ! TextLayoutMetrics .isWhitespace (text.codeUnitAt (forward ? offset - 1 : offset));
1594
1594
});
1595
- newPosition = _beyondTextBoundary (targetedEdge, forward, textBoundary);
1595
+ newPosition = _moveBeyondTextBoundaryAtDirection (targetedEdge, forward, textBoundary);
1596
1596
result = SelectionResult .end;
1597
1597
break ;
1598
1598
case TextGranularity .line:
1599
- newPosition = _toTextBoundary (targetedEdge, forward, LineBoundary (this ));
1599
+ newPosition = _moveToTextBoundaryAtDirection (targetedEdge, forward, LineBoundary (this ));
1600
1600
result = SelectionResult .end;
1601
1601
break ;
1602
1602
case TextGranularity .document:
1603
1603
final String text = range.textInside (fullText);
1604
- newPosition = _beyondTextBoundary (targetedEdge, forward, DocumentBoundary (text));
1604
+ newPosition = _moveBeyondTextBoundaryAtDirection (targetedEdge, forward, DocumentBoundary (text));
1605
1605
if (forward && newPosition.offset == range.end) {
1606
1606
result = SelectionResult .next;
1607
1607
} else if (! forward && newPosition.offset == range.start) {
@@ -1620,26 +1620,37 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM
1620
1620
return result;
1621
1621
}
1622
1622
1623
- TextPosition _beyondTextBoundary (TextPosition extent, bool forward, TextBoundary textBoundary) {
1623
+ // Move **beyond** the local boundary of the given type (unless range.start or
1624
+ // range.end is reached). Used for most TextGranularity types except for
1625
+ // TextGranularity.line, to ensure the selection movement doesn't get stuck at
1626
+ // a local fixed point.
1627
+ TextPosition _moveBeyondTextBoundaryAtDirection (TextPosition end, bool forward, TextBoundary textBoundary) {
1624
1628
final int newOffset = forward
1625
- ? textBoundary.getTrailingTextBoundaryAt (extent .offset) ?? range.end
1626
- : textBoundary.getLeadingTextBoundaryAt (extent .offset - 1 ) ?? range.start;
1629
+ ? textBoundary.getTrailingTextBoundaryAt (end .offset) ?? range.end
1630
+ : textBoundary.getLeadingTextBoundaryAt (end .offset - 1 ) ?? range.start;
1627
1631
return TextPosition (offset: newOffset);
1628
1632
}
1629
1633
1630
- TextPosition _toTextBoundary (TextPosition extent, bool forward, TextBoundary textBoundary) {
1631
- assert (extent.offset >= 0 );
1634
+ // Move **to** the local boundary of the given type. Typically used for line
1635
+ // boundaries, such that performing "move to line start" more than once never
1636
+ // moves the selection to the previous line.
1637
+ TextPosition _moveToTextBoundaryAtDirection (TextPosition end, bool forward, TextBoundary textBoundary) {
1638
+ assert (end.offset >= 0 );
1632
1639
final int caretOffset;
1633
- switch (extent .affinity) {
1640
+ switch (end .affinity) {
1634
1641
case TextAffinity .upstream:
1635
- if (extent .offset < 1 && ! forward) {
1636
- assert (extent .offset == 0 );
1642
+ if (end .offset < 1 && ! forward) {
1643
+ assert (end .offset == 0 );
1637
1644
return const TextPosition (offset: 0 );
1638
1645
}
1639
- caretOffset = math.max (0 , extent.offset - 1 );
1646
+ final CharacterBoundary characterBoundary = CharacterBoundary (fullText);
1647
+ caretOffset = math.max (
1648
+ 0 ,
1649
+ characterBoundary.getLeadingTextBoundaryAt (range.start + end.offset) ?? range.start,
1650
+ ) - 1 ;
1640
1651
break ;
1641
1652
case TextAffinity .downstream:
1642
- caretOffset = extent .offset;
1653
+ caretOffset = end .offset;
1643
1654
break ;
1644
1655
}
1645
1656
final int offset = forward
0 commit comments