@@ -258,7 +258,11 @@ class TextDeltasDocumentEditor {
258
258
if (docSelection != null ) {
259
259
// We got a selection from the platform.
260
260
// This could happen in some software keyboards, like GBoard,
261
- // where the user can swipe over the spacebar to change the selection.
261
+ // where the user can swipe over the spacebar to change the selection. This also happens
262
+ // when the app uses the native iOS text selection toolbar and the user presses "Select all".
263
+
264
+ docSelection = _maybeSelectAllOnIos (docSelection);
265
+
262
266
editor.execute ([
263
267
ChangeSelectionRequest (
264
268
docSelection,
@@ -273,6 +277,44 @@ class TextDeltasDocumentEditor {
273
277
_previousImeValue = delta.apply (_previousImeValue);
274
278
}
275
279
280
+ /// Performs a workaround to select all text in the document on iOS when the user presses "Select all".
281
+ ///
282
+ /// On iOS, when the app uses the native text selection toolbar and the user presses "Select all",
283
+ /// Flutter sends us a non-text delta with the selection change. However, since we only send to the IME the text
284
+ /// of the currently selected nodes, the delta reports the node being selected, not the entire
285
+ /// document.
286
+ ///
287
+ /// To workaroud this, whenever iOS reports a selection change that selects an entire node,
288
+ /// we select the entire document instead.
289
+ DocumentSelection _maybeSelectAllOnIos (DocumentSelection documentSelection) {
290
+ if (defaultTargetPlatform != TargetPlatform .iOS) {
291
+ return documentSelection;
292
+ }
293
+
294
+ final extentNode = document.getNodeById (documentSelection.extent.nodeId)! ;
295
+ final isWholeNodeSelected = documentSelection.start.nodeId == documentSelection.end.nodeId &&
296
+ documentSelection.start.nodePosition == extentNode.beginningPosition &&
297
+ documentSelection.end.nodePosition == extentNode.endPosition;
298
+
299
+ if (! isWholeNodeSelected) {
300
+ // The selection is either across multiple nodes or not the entire node.
301
+ // The user didn't press "Select all".
302
+ return documentSelection;
303
+ }
304
+
305
+ // The IME reported a selection that selects an entire node. Select the entire document instead.
306
+ return DocumentSelection (
307
+ base : DocumentPosition (
308
+ nodeId: document.first.id,
309
+ nodePosition: document.first.beginningPosition,
310
+ ),
311
+ extent: DocumentPosition (
312
+ nodeId: document.last.id,
313
+ nodePosition: document.last.endPosition,
314
+ ),
315
+ );
316
+ }
317
+
276
318
void insert (DocumentSelection insertionSelection, String textInserted) {
277
319
editorImeLog.fine ('Inserting "$textInserted " at position "$insertionSelection "' );
278
320
editorImeLog
0 commit comments