-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Closed
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work lista: text inputEntering text in a text field or keyboard related problemsEntering text in a text field or keyboard related problemsengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.10Found to occur in 3.10Found to occur in 3.10found in release: 3.13Found to occur in 3.13Found to occur in 3.13has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onplatform-webWeb applications specificallyWeb applications specificallyr: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer versionteam-webOwned by Web platform teamOwned by Web platform team
Description
Is there an existing issue for this?
- I have searched the existing issues
- I have read the guide to filing a bug
Steps to reproduce
- Clone repository https://github.com/angelosilvestre/super_editor/tree/1219_newline_insertion (branch 1219_newline_insertion)
- Run the example app on web
- Place the caret at the first paragraph
- Press enter
- Type "a"
- Press enter again
Expected results
New line is inserted
Actual results
A crash happens.
Code sample
Code sample
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
super.key,
});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with DeltaTextInputClient {
TextInputConnection? _imeConnection;
final String placeholder = '. ';
TextEditingValue _currentTextEditingValue = const TextEditingValue(
text: 'Press ENTER, then type "a" and press ENTER again',
selection: TextSelection.collapsed(offset: 48),
);
@override
void initState() {
super.initState();
_attachToIme();
}
@override
void dispose() {
_detachFromIme();
super.dispose();
}
@override
void performAction(TextInputAction action) {
if (action == TextInputAction.newline) {
// Here, we would create a new empty paragraph.
// Use a placeholder so we can detect deletions.
final newValue = TextEditingValue(
text: placeholder,
selection: const TextSelection.collapsed(offset: 2),
);
_imeConnection?.setEditingState(newValue);
setState(() {
_currentTextEditingValue = newValue;
});
}
}
@override
void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
// What we think the current value is.
TextEditingValue newValue = _currentTextEditingValue.copyWith();
// What the IME thinks the current value is.
TextEditingValue imeEditingValue = _currentTextEditingValue.copyWith();
for (final delta in textEditingDeltas) {
print('Applying delta: $delta');
// Compute the value that the IME thinks it's the current state.
imeEditingValue = delta.apply(imeEditingValue);
if (delta is TextEditingDeltaInsertion) {
newValue = _applyInsertion(newValue, delta);
} else {
newValue = delta.apply(newValue);
}
}
print('New editing value: $newValue');
if (imeEditingValue != newValue) {
// We diverged from the IME.
//
// Send our value back to the IME.
_imeConnection!.setEditingState(newValue);
}
setState(() {
_currentTextEditingValue = newValue;
});
}
TextEditingValue _applyInsertion(TextEditingValue currentValue, TextEditingDeltaInsertion delta) {
if (delta.textInserted == '\n') {
// The user pressed ENTER.
//
// On web, both performAction and updateEditingValueWithDeltas are called.
//
// As we handle the new line in performAction we ignore it here.
return currentValue;
}
if (delta.oldText == placeholder) {
// The user typed in an empty paragraph.
// The newly inserted text replaces the placeholder.
return TextEditingValue(
text: delta.textInserted,
selection: const TextSelection.collapsed(offset: 1),
);
}
return delta.apply(currentValue);
}
void _attachToIme() {
if (_imeConnection != null && _imeConnection!.attached) {
return;
}
const config = TextInputConfiguration(
enableDeltaModel: true,
inputType: TextInputType.multiline,
inputAction: TextInputAction.newline,
);
_imeConnection = TextInput.attach(this, config);
_imeConnection!.setEditingState(_currentTextEditingValue);
_imeConnection!.show();
}
void _detachFromIme() {
_imeConnection?.close();
_imeConnection = null;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Focus(
autofocus: true,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Text: ${_currentTextEditingValue.text}'),
const SizedBox(height: 30),
Text('Selection: ${_currentTextEditingValue.selection}'),
const SizedBox(height: 30),
Text('Selected text: ${_currentTextEditingValue.selection.textInside(_currentTextEditingValue.text)}'),
],
),
),
),
);
}
@override
void connectionClosed() {}
@override
AutofillScope? get currentAutofillScope => null;
@override
TextEditingValue? get currentTextEditingValue => _currentTextEditingValue;
@override
void didChangeInputControl(TextInputControl? oldControl, TextInputControl? newControl) {}
@override
void insertContent(KeyboardInsertedContent content) {}
@override
void insertTextPlaceholder(Size size) {}
@override
void performPrivateCommand(String action, Map<String, dynamic> data) {}
@override
void performSelector(String selectorName) {}
@override
void removeTextPlaceholder() {}
@override
void showAutocorrectionPromptRect(int start, int end) {}
@override
void showToolbar() {}
@override
void updateEditingValue(TextEditingValue value) {}
@override
void updateFloatingCursor(RawFloatingCursorPoint point) {}
}
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
Launching lib/main.dart on Chrome in debug mode...
This app is linked to the debug service: ws://127.0.0.1:38203/GHhd3P4elAU=/ws
Debug service listening on ws://127.0.0.1:38203/GHhd3P4elAU=/ws
Connecting to VM Service at ws://127.0.0.1:38203/GHhd3P4elAU=/ws
The platformViewRegistry getter is deprecated and will be removed in a future release. Please import it from `dart:ui_web` instead.
Initializing logger: ExampleApp
>received TextInput.setClient: {inputType: {name: TextInputType.multiline, signed: null, decimal: null}, readOnly: false, obscureText: false, autocorrect: true, smartDashesType: 1, smartQuotesType: 1, enableSuggestions: true, enableInteractiveSelection: true, actionLabel: null, inputAction: TextInputAction.newline, textCapitalization: TextCapitalization.sentences, keyboardAppearance: Brightness.light, enableIMEPersonalizedLearning: true, contentCommitMimeTypes: [], enableDeltaModel: true}
>received TextInput.setEditingState: {text: Original text, selectionBase: 13, selectionExtent: 13, composingBase: -1, composingExtent: -1}
>handleChange called
type: selectionchange
newEditingState: {text: Original text, selectionBase: 13, selectionExtent: 13, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState("Original text", base:13, extent:13, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState("Original text", base:13, extent:13, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: true
infered deltaState: {deltas: [{oldText: Original text, deltaText: , deltaStart: -1, deltaEnd: -1, selectionBase: 13, selectionExtent: 13, composingBase: -1, composingExtent: -1}]}
>handleChange called
type: selectionchange
newEditingState: {text: Original text, selectionBase: 13, selectionExtent: 13, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState("Original text", base:13, extent:13, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState("Original text", base:13, extent:13, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: true
infered deltaState: {deltas: [{oldText: Original text, deltaText: , deltaStart: -1, deltaEnd: -1, selectionBase: 13, selectionExtent: 13, composingBase: -1, composingExtent: -1}]}
performAction called: TextInputAction.newline
>received TextInput.setEditingState: {text: >>, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}
>handleChange called
type: input
newEditingState: {text: >>
, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState(">>
", base:3, extent:3, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: false
replacing "Original text" with "
"
originalText: Original text
replacementText:
replacedRange: TextRange(start: 2, end: 2)
isDeltaVerified: false
isMatchWithinOldTextBounds: true
replacing "Original text" with "
"
originalText: Original text
replacementText:
replacedRange: TextRange(start: 2, end: 3)
infered deltaState: {deltas: [{oldText: Original text, deltaText:
, deltaStart: 2, deltaEnd: 2, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}]}
>updateEditingStateWithDeltas called
delta: {deltas: [{oldText: Original text, deltaText:
, deltaStart: 2, deltaEnd: 2, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}]}
>received TextInput.setEditingState: {text: >>, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}
>handleChange called
type: selectionchange
newEditingState: {text: >>, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: true
infered deltaState: {deltas: [{oldText: >>, deltaText: , deltaStart: -1, deltaEnd: -1, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}]}
>handleChange called
type: selectionchange
newEditingState: {text: >>, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: true
infered deltaState: {deltas: [{oldText: >>, deltaText: , deltaStart: -1, deltaEnd: -1, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}]}
>handleChange called
type: selectionchange
newEditingState: {text: >>, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: true
infered deltaState: {deltas: [{oldText: >>, deltaText: , deltaStart: -1, deltaEnd: -1, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}]}
>handleChange called
type: input
newEditingState: {text: >>a, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState(">>a", base:3, extent:3, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: false
replacing ">>" with "a"
originalText: >>
replacementText: a
replacedRange: TextRange(start: 2, end: 2)
isDeltaVerified: true
infered deltaState: {deltas: [{oldText: >>, deltaText: a, deltaStart: 2, deltaEnd: 2, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}]}
>updateEditingStateWithDeltas called
delta: {deltas: [{oldText: >>, deltaText: a, deltaStart: 2, deltaEnd: 2, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}]}
>received TextInput.setEditingState: {text: a, selectionBase: 1, selectionExtent: 1, composingBase: -1, composingExtent: -1}
>handleChange called
type: selectionchange
newEditingState: {text: a, selectionBase: 1, selectionExtent: 1, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState("a", base:1, extent:1, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState("a", base:1, extent:1, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: true
infered deltaState: {deltas: [{oldText: a, deltaText: , deltaStart: -1, deltaEnd: -1, selectionBase: 1, selectionExtent: 1, composingBase: -1, composingExtent: -1}]}
>handleChange called
type: selectionchange
newEditingState: {text: a, selectionBase: 1, selectionExtent: 1, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState("a", base:1, extent:1, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState("a", base:1, extent:1, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: true
infered deltaState: {deltas: [{oldText: a, deltaText: , deltaStart: -1, deltaEnd: -1, selectionBase: 1, selectionExtent: 1, composingBase: -1, composingExtent: -1}]}
performAction called: TextInputAction.newline
>received TextInput.setEditingState: {text: >>, selectionBase: 2, selectionExtent: 2, composingBase: -1, composingExtent: -1}
>handleChange called
type: input
newEditingState: {text: >>
, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState(">>
", base:3, extent:3, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: false
replacing "a" with "
"
originalText: a
replacementText:
replacedRange: TextRange(start: 2, end: 2)
>handleChange called
type: selectionchange
newEditingState: {text: >>
, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState(">>
", base:3, extent:3, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: false
replacing "a" with "
"
originalText: a
replacementText:
replacedRange: TextRange(start: 2, end: 2)
Error: Assertion failed: org-dartlang-sdk:///lib/_engine/engine/text_editing/text_editing.dart:470:10
replacedRange.start <= originalText.length && replacedRange.end <= originalText.length
is not true
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:49 throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 35:3 assertFailed
lib/_engine/engine/text_editing/text_editing.dart 470:89 _replace
lib/_engine/engine/text_editing/text_editing.dart 583:11 inferDeltaState
lib/_engine/engine/text_editing/text_editing.dart 1373:33 handleChange
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 574:37 _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 579:39 dcall
>handleChange called
type: selectionchange
newEditingState: {text: >>
, selectionBase: 3, selectionExtent: 3, composingBase: -1, composingExtent: -1}
infering delta state
lastEditingState: EditingState(">>", base:2, extent:2, composingBase:-1, composingExtent:-1)}
newEditingState: EditingState(">>
", base:3, extent:3, composingBase:-1, composingExtent:-1)}
isTextBeingRemoved: false
isDeltaRangeEmpty: false
replacing "a" with "
"
originalText: a
replacementText:
replacedRange: TextRange(start: 2, end: 2)
Error: Assertion failed: org-dartlang-sdk:///lib/_engine/engine/text_editing/text_editing.dart:470:10
replacedRange.start <= originalText.length && replacedRange.end <= originalText.length
is not true
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:49 throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 35:3 assertFailed
lib/_engine/engine/text_editing/text_editing.dart 470:89 _replace
lib/_engine/engine/text_editing/text_editing.dart 583:11 inferDeltaState
lib/_engine/engine/text_editing/text_editing.dart 1373:33 handleChange
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 574:37 _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 579:39 dcall
Flutter Doctor output
Doctor output
[✓] Flutter (Channel master, 3.13.0-6.0.pre.24, on Ubuntu 22.04.2 LTS 5.15.90.1-microsoft-standard-WSL2,
locale C.UTF-8)
• Flutter version 3.13.0-6.0.pre.24 on channel master at /home/wsl/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision e29f2b98af (2 days ago), 2023-07-19 00:10:17 +0200
• Engine revision 71bbecee30
• Dart version 3.1.0 (build 3.1.0-323.0.dev)
• DevTools version 2.25.0
[✗] Android toolchain - develop for Android devices
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/docs/get-started/install/linux#android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
`flutter config --android-sdk` to update to that location.
[✓] Chrome - develop for the web
• Chrome at google-chrome
[✗] Linux toolchain - develop for Linux desktop
✗ clang++ is required for Linux development.
It is likely available from your distribution (e.g.: apt install clang), or can be downloaded from
https://releases.llvm.org/
✗ CMake is required for Linux development.
It is likely available from your distribution (e.g.: apt install cmake), or can be downloaded from
https://cmake.org/download/
✗ ninja is required for Linux development.
It is likely available from your distribution (e.g.: apt install ninja-build), or can be downloaded
from https://github.com/ninja-build/ninja/releases
• pkg-config version 0.29.2
✗ GTK 3.0 development libraries are required for Linux development.
They are likely available from your distribution (e.g.: apt install libgtk-3-dev)
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/linux#android-setup for detailed instructions).
[✓] Connected device (2 available)
• Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.2 LTS 5.15.90.1-microsoft-standard-WSL2
• Chrome (web) • chrome • web-javascript • Google Chrome 115.0.5790.98
[✓] Network resources
• All expected network resources are available.
! Doctor found issues in 3 categories.Metadata
Metadata
Assignees
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work lista: text inputEntering text in a text field or keyboard related problemsEntering text in a text field or keyboard related problemsengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.10Found to occur in 3.10Found to occur in 3.10found in release: 3.13Found to occur in 3.13Found to occur in 3.13has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onplatform-webWeb applications specificallyWeb applications specificallyr: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer versionteam-webOwned by Web platform teamOwned by Web platform team