Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c42b36f6
Unverified
Commit
c42b36f6
authored
Feb 11, 2022
by
Justin McCandless
Committed by
GitHub
Feb 11, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Windows/Linux keyboard shortcuts at a wordwrap (#96323)
parent
ac708f1c
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1176 additions
and
162 deletions
+1176
-162
default_text_editing_shortcuts.dart
...utter/lib/src/widgets/default_text_editing_shortcuts.dart
+8
-6
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+78
-8
text_editing_intents.dart
packages/flutter/lib/src/widgets/text_editing_intents.dart
+48
-3
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+1042
-145
No files found.
packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart
View file @
c42b36f6
...
...
@@ -317,8 +317,10 @@ class DefaultTextEditingShortcuts extends Shortcuts {
const
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
shift:
true
,
meta:
true
):
const
ExtendSelectionToDocumentBoundaryIntent
(
forward:
false
,
collapseSelection:
false
),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
shift:
true
,
meta:
true
):
const
ExtendSelectionToDocumentBoundaryIntent
(
forward:
true
,
collapseSelection:
false
),
const
SingleActivator
(
LogicalKeyboardKey
.
home
,
shift:
true
):
const
ExtendSelectionToDocumentBoundaryIntent
(
forward:
false
,
collapseSelection:
false
),
const
SingleActivator
(
LogicalKeyboardKey
.
end
,
shift:
true
):
const
ExtendSelectionToDocumentBoundaryIntent
(
forward:
true
,
collapseSelection:
false
),
const
SingleActivator
(
LogicalKeyboardKey
.
home
):
const
ScrollToDocumentBoundaryIntent
(
forward:
false
),
const
SingleActivator
(
LogicalKeyboardKey
.
end
):
const
ScrollToDocumentBoundaryIntent
(
forward:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
home
,
shift:
true
):
const
ExpandSelectionToDocumentBoundaryIntent
(
forward:
false
),
const
SingleActivator
(
LogicalKeyboardKey
.
end
,
shift:
true
):
const
ExpandSelectionToDocumentBoundaryIntent
(
forward:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
keyX
,
meta:
true
):
const
CopySelectionTextIntent
.
cut
(
SelectionChangedCause
.
keyboard
),
const
SingleActivator
(
LogicalKeyboardKey
.
keyC
,
meta:
true
):
CopySelectionTextIntent
.
copy
,
...
...
@@ -349,10 +351,10 @@ class DefaultTextEditingShortcuts extends Shortcuts {
// * Meta + backspace
static
final
Map
<
ShortcutActivator
,
Intent
>
_windowsShortcuts
=
<
ShortcutActivator
,
Intent
>{
...
_commonShortcuts
,
const
SingleActivator
(
LogicalKeyboardKey
.
home
):
const
ExtendSelectionToLineBreakIntent
(
forward:
false
,
collapseSelection:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
end
):
const
ExtendSelectionToLineBreakIntent
(
forward:
true
,
collapseSelection:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
home
,
shift:
true
):
const
ExtendSelectionToLineBreakIntent
(
forward:
false
,
collapseSelection:
false
),
const
SingleActivator
(
LogicalKeyboardKey
.
end
,
shift:
true
):
const
ExtendSelectionToLineBreakIntent
(
forward:
true
,
collapseSelection:
false
),
const
SingleActivator
(
LogicalKeyboardKey
.
home
):
const
ExtendSelectionToLineBreakIntent
(
forward:
false
,
collapseSelection:
true
,
continuesAtWrap:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
end
):
const
ExtendSelectionToLineBreakIntent
(
forward:
true
,
collapseSelection:
true
,
continuesAtWrap:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
home
,
shift:
true
):
const
ExtendSelectionToLineBreakIntent
(
forward:
false
,
collapseSelection:
false
,
continuesAtWrap:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
end
,
shift:
true
):
const
ExtendSelectionToLineBreakIntent
(
forward:
true
,
collapseSelection:
false
,
continuesAtWrap:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
home
,
control:
true
):
const
ExtendSelectionToDocumentBoundaryIntent
(
forward:
false
,
collapseSelection:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
end
,
control:
true
):
const
ExtendSelectionToDocumentBoundaryIntent
(
forward:
true
,
collapseSelection:
true
),
const
SingleActivator
(
LogicalKeyboardKey
.
home
,
shift:
true
,
control:
true
):
const
ExtendSelectionToDocumentBoundaryIntent
(
forward:
false
,
collapseSelection:
false
),
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
c42b36f6
...
...
@@ -3069,7 +3069,18 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
late
final
Action
<
ReplaceTextIntent
>
_replaceTextAction
=
CallbackAction
<
ReplaceTextIntent
>(
onInvoke:
_replaceText
);
// Scrolls either to the beginning or end of the document depending on the
// intent's `forward` parameter.
void
_scrollToDocumentBoundary
(
ScrollToDocumentBoundaryIntent
intent
)
{
if
(
intent
.
forward
)
{
bringIntoView
(
TextPosition
(
offset:
_value
.
text
.
length
));
}
else
{
bringIntoView
(
const
TextPosition
(
offset:
0
));
}
}
void
_updateSelection
(
UpdateSelectionIntent
intent
)
{
bringIntoView
(
intent
.
newSelection
.
extent
);
userUpdateTextEditingValue
(
intent
.
currentTextEditingValue
.
copyWith
(
selection:
intent
.
newSelection
),
intent
.
cause
,
...
...
@@ -3079,28 +3090,38 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
late
final
_UpdateTextSelectionToAdjacentLineAction
<
ExtendSelectionVerticallyToAdjacentLineIntent
>
_adjacentLineAction
=
_UpdateTextSelectionToAdjacentLineAction
<
ExtendSelectionVerticallyToAdjacentLineIntent
>(
this
);
void
_expandSelection
(
ExpandSelectionToLineBreakIntent
intent
)
{
void
_expandSelectionToDocumentBoundary
(
ExpandSelectionToDocumentBoundaryIntent
intent
)
{
final
_TextBoundary
textBoundary
=
_documentBoundary
(
intent
);
_expandSelection
(
intent
.
forward
,
textBoundary
,
true
);
}
void
_expandSelectionToLinebreak
(
ExpandSelectionToLineBreakIntent
intent
)
{
final
_TextBoundary
textBoundary
=
_linebreak
(
intent
);
_expandSelection
(
intent
.
forward
,
textBoundary
);
}
void
_expandSelection
(
bool
forward
,
_TextBoundary
textBoundary
,
[
bool
extentAtIndex
=
false
])
{
final
TextSelection
textBoundarySelection
=
textBoundary
.
textEditingValue
.
selection
;
if
(!
textBoundarySelection
.
isValid
)
{
return
;
}
final
bool
inOrder
=
textBoundarySelection
.
baseOffset
<=
textBoundarySelection
.
extentOffset
;
final
bool
towardsExtent
=
intent
.
forward
==
inOrder
;
final
bool
towardsExtent
=
forward
==
inOrder
;
final
TextPosition
position
=
towardsExtent
?
textBoundarySelection
.
extent
:
textBoundarySelection
.
base
;
final
TextPosition
newExtent
=
intent
.
forward
final
TextPosition
newExtent
=
forward
?
textBoundary
.
getTrailingTextBoundaryAt
(
position
)
:
textBoundary
.
getLeadingTextBoundaryAt
(
position
);
final
TextSelection
newSelection
=
textBoundarySelection
.
expandTo
(
newExtent
,
textBoundarySelection
.
isCollapsed
);
final
TextSelection
newSelection
=
textBoundarySelection
.
expandTo
(
newExtent
,
textBoundarySelection
.
isCollapsed
||
extentAtIndex
);
userUpdateTextEditingValue
(
_value
.
copyWith
(
selection:
newSelection
),
SelectionChangedCause
.
keyboard
,
);
bringIntoView
(
newSelection
.
extent
);
}
late
final
Map
<
Type
,
Action
<
Intent
>>
_actions
=
<
Type
,
Action
<
Intent
>>{
...
...
@@ -3118,10 +3139,12 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
ExtendSelectionByCharacterIntent:
_makeOverridable
(
_UpdateTextSelectionAction
<
ExtendSelectionByCharacterIntent
>(
this
,
false
,
_characterBoundary
,)),
ExtendSelectionToNextWordBoundaryIntent:
_makeOverridable
(
_UpdateTextSelectionAction
<
ExtendSelectionToNextWordBoundaryIntent
>(
this
,
true
,
_nextWordBoundary
)),
ExtendSelectionToLineBreakIntent:
_makeOverridable
(
_UpdateTextSelectionAction
<
ExtendSelectionToLineBreakIntent
>(
this
,
true
,
_linebreak
)),
ExpandSelectionToLineBreakIntent:
_makeOverridable
(
CallbackAction
<
ExpandSelectionToLineBreakIntent
>(
onInvoke:
_expandSelection
)),
ExpandSelectionToLineBreakIntent:
_makeOverridable
(
CallbackAction
<
ExpandSelectionToLineBreakIntent
>(
onInvoke:
_expandSelectionToLinebreak
)),
ExpandSelectionToDocumentBoundaryIntent:
_makeOverridable
(
CallbackAction
<
ExpandSelectionToDocumentBoundaryIntent
>(
onInvoke:
_expandSelectionToDocumentBoundary
)),
ExtendSelectionVerticallyToAdjacentLineIntent:
_makeOverridable
(
_adjacentLineAction
),
ExtendSelectionToDocumentBoundaryIntent:
_makeOverridable
(
_UpdateTextSelectionAction
<
ExtendSelectionToDocumentBoundaryIntent
>(
this
,
true
,
_documentBoundary
)),
ExtendSelectionToNextWordBoundaryOrCaretLocationIntent:
_makeOverridable
(
_ExtendSelectionOrCaretPositionAction
(
this
,
_nextWordBoundary
)),
ScrollToDocumentBoundaryIntent:
_makeOverridable
(
CallbackAction
<
ScrollToDocumentBoundaryIntent
>(
onInvoke:
_scrollToDocumentBoundary
)),
// Copy Paste
SelectAllTextIntent:
_makeOverridable
(
_SelectAllAction
(
this
)),
...
...
@@ -3763,7 +3786,10 @@ class _WordBoundary extends _TextBoundary {
// interpreted as caret locations because [TextPainter.getLineAtOffset] is
// text-affinity-aware.
class
_LineBreak
extends
_TextBoundary
{
const
_LineBreak
(
this
.
textLayout
,
this
.
textEditingValue
);
const
_LineBreak
(
this
.
textLayout
,
this
.
textEditingValue
,
);
final
TextLayoutMetrics
textLayout
;
...
...
@@ -3776,6 +3802,7 @@ class _LineBreak extends _TextBoundary {
offset:
textLayout
.
getLineAtOffset
(
position
).
start
,
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
return
TextPosition
(
...
...
@@ -3945,12 +3972,39 @@ class _DeleteTextAction<T extends DirectionalTextEditingIntent> extends ContextA
}
class
_UpdateTextSelectionAction
<
T
extends
DirectionalCaretMovementIntent
>
extends
ContextAction
<
T
>
{
_UpdateTextSelectionAction
(
this
.
state
,
this
.
ignoreNonCollapsedSelection
,
this
.
getTextBoundariesForIntent
);
_UpdateTextSelectionAction
(
this
.
state
,
this
.
ignoreNonCollapsedSelection
,
this
.
getTextBoundariesForIntent
,
);
final
EditableTextState
state
;
final
bool
ignoreNonCollapsedSelection
;
final
_TextBoundary
Function
(
T
intent
)
getTextBoundariesForIntent
;
static
const
int
NEWLINE_CODE_UNIT
=
10
;
// Returns true iff the given position is at a wordwrap boundary in the
// upstream position.
bool
_isAtWordwrapUpstream
(
TextPosition
position
)
{
final
TextPosition
end
=
TextPosition
(
offset:
state
.
renderEditable
.
getLineAtOffset
(
position
).
end
,
affinity:
TextAffinity
.
upstream
,
);
return
end
==
position
&&
end
.
offset
!=
state
.
textEditingValue
.
text
.
length
&&
state
.
textEditingValue
.
text
.
codeUnitAt
(
position
.
offset
)
!=
NEWLINE_CODE_UNIT
;
}
// Returns true iff the given position at a wordwrap boundary in the
// downstream position.
bool
_isAtWordwrapDownstream
(
TextPosition
position
)
{
final
TextPosition
start
=
TextPosition
(
offset:
state
.
renderEditable
.
getLineAtOffset
(
position
).
start
,
);
return
start
==
position
&&
start
.
offset
!=
0
&&
state
.
textEditingValue
.
text
.
codeUnitAt
(
position
.
offset
-
1
)
!=
NEWLINE_CODE_UNIT
;
}
@override
Object
?
invoke
(
T
intent
,
[
BuildContext
?
context
])
{
final
TextSelection
selection
=
state
.
_value
.
selection
;
...
...
@@ -3986,7 +4040,23 @@ class _UpdateTextSelectionAction<T extends DirectionalCaretMovementIntent> exten
);
}
final
TextPosition
extent
=
textBoundarySelection
.
extent
;
TextPosition
extent
=
textBoundarySelection
.
extent
;
// If continuesAtWrap is true extent and is at the relevant wordwrap, then
// move it just to the other side of the wordwrap.
if
(
intent
.
continuesAtWrap
)
{
if
(
intent
.
forward
&&
_isAtWordwrapUpstream
(
extent
))
{
extent
=
TextPosition
(
offset:
extent
.
offset
,
);
}
else
if
(!
intent
.
forward
&&
_isAtWordwrapDownstream
(
extent
))
{
extent
=
TextPosition
(
offset:
extent
.
offset
,
affinity:
TextAffinity
.
upstream
,
);
}
}
final
TextPosition
newExtent
=
intent
.
forward
?
textBoundary
.
getTrailingTextBoundaryAt
(
extent
)
:
textBoundary
.
getLeadingTextBoundaryAt
(
extent
);
...
...
packages/flutter/lib/src/widgets/text_editing_intents.dart
View file @
c42b36f6
...
...
@@ -20,7 +20,9 @@ class DoNothingAndStopPropagationTextIntent extends Intent {
/// direction of the current caret location.
abstract
class
DirectionalTextEditingIntent
extends
Intent
{
/// Creates a [DirectionalTextEditingIntent].
const
DirectionalTextEditingIntent
(
this
.
forward
);
const
DirectionalTextEditingIntent
(
this
.
forward
,
);
/// Whether the input field, if applicable, should perform the text editing
/// operation from the current caret location towards the end of the document.
...
...
@@ -65,7 +67,10 @@ abstract class DirectionalCaretMovementIntent extends DirectionalTextEditingInte
const
DirectionalCaretMovementIntent
(
bool
forward
,
this
.
collapseSelection
,
[
this
.
collapseAtReversal
=
false
]
[
this
.
collapseAtReversal
=
false
,
this
.
continuesAtWrap
=
false
,
]
)
:
assert
(!
collapseSelection
||
!
collapseAtReversal
),
super
(
forward
);
...
...
@@ -90,6 +95,14 @@ abstract class DirectionalCaretMovementIntent extends DirectionalTextEditingInte
///
/// Cannot be true when collapseSelection is true.
final
bool
collapseAtReversal
;
/// Whether or not to continue to the next line at a wordwrap.
///
/// If true, when an [Intent] to go to the beginning/end of a wordwrapped line
/// is received and the selection is already at the beginning/end of the line,
/// then the selection will be moved to the next/previous line. If false, the
/// selection will remain at the wordwrap.
final
bool
continuesAtWrap
;
}
/// Extends, or moves the current selection from the current
...
...
@@ -132,6 +145,23 @@ class ExtendSelectionToNextWordBoundaryOrCaretLocationIntent extends Directional
})
:
super
(
forward
);
}
/// Expands the current selection to the document boundary in the direction
/// given by [forward].
///
/// Unlike [ExpandSelectionToLineBreakIntent], the extent will be moved, which
/// matches the behavior on MacOS.
///
/// See also:
///
/// [ExtendSelectionToDocumentBoundaryIntent], which is similar but always
/// moves the extent.
class
ExpandSelectionToDocumentBoundaryIntent
extends
DirectionalTextEditingIntent
{
/// Creates an [ExpandSelectionToDocumentBoundaryIntent].
const
ExpandSelectionToDocumentBoundaryIntent
({
required
bool
forward
,
})
:
super
(
forward
);
}
/// Expands the current selection to the closest line break in the direction
/// given by [forward].
///
...
...
@@ -165,8 +195,9 @@ class ExtendSelectionToLineBreakIntent extends DirectionalCaretMovementIntent {
required
bool
forward
,
required
bool
collapseSelection
,
bool
collapseAtReversal
=
false
,
bool
continuesAtWrap
=
false
,
})
:
assert
(!
collapseSelection
||
!
collapseAtReversal
),
super
(
forward
,
collapseSelection
,
collapseAtReversal
);
super
(
forward
,
collapseSelection
,
collapseAtReversal
,
continuesAtWrap
);
}
/// Extends, or moves the current selection from the current
...
...
@@ -182,6 +213,11 @@ class ExtendSelectionVerticallyToAdjacentLineIntent extends DirectionalCaretMove
/// Extends, or moves the current selection from the current
/// [TextSelection.extent] position to the start or the end of the document.
///
/// See also:
///
/// [ExtendSelectionToDocumentBoundaryIntent], which is similar but always
/// increases the size of the selection.
class
ExtendSelectionToDocumentBoundaryIntent
extends
DirectionalCaretMovementIntent
{
/// Creates an [ExtendSelectionToDocumentBoundaryIntent].
const
ExtendSelectionToDocumentBoundaryIntent
({
...
...
@@ -190,6 +226,15 @@ class ExtendSelectionToDocumentBoundaryIntent extends DirectionalCaretMovementIn
})
:
super
(
forward
,
collapseSelection
);
}
/// Scrolls to the beginning or end of the document depending on the [forward]
/// parameter.
class
ScrollToDocumentBoundaryIntent
extends
DirectionalTextEditingIntent
{
/// Creates a [ScrollToDocumentBoundaryIntent].
const
ScrollToDocumentBoundaryIntent
({
required
bool
forward
,
})
:
super
(
forward
);
}
/// An [Intent] to select everything in the field.
class
SelectAllTextIntent
extends
Intent
{
/// Creates an instance of [SelectAllTextIntent].
...
...
packages/flutter/test/widgets/editable_text_test.dart
View file @
c42b36f6
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment