Prefer final

Declaring variables as final when possible is a good practice
because it helps avoid accidental reassignments and allows the
compiler to do optimizations.
pull/145/head
Till Friebe 4 years ago
parent e4a3c11702
commit bc494bc50f
  1. 5
      analysis_options.yaml
  2. 6
      example/lib/pages/home_page.dart
  3. 4
      example/lib/universal_ui/universal_ui.dart
  4. 6
      lib/models/documents/attribute.dart
  5. 48
      lib/models/documents/document.dart
  6. 12
      lib/models/documents/history.dart
  7. 10
      lib/models/documents/nodes/block.dart
  8. 16
      lib/models/documents/nodes/container.dart
  9. 4
      lib/models/documents/nodes/embed.dart
  10. 37
      lib/models/documents/nodes/leaf.dart
  11. 74
      lib/models/documents/nodes/line.dart
  12. 6
      lib/models/documents/nodes/node.dart
  13. 18
      lib/models/documents/style.dart
  14. 15
      lib/models/quill_delta.dart
  15. 28
      lib/models/rules/delete.dart
  16. 36
      lib/models/rules/format.dart
  17. 96
      lib/models/rules/insert.dart
  18. 2
      lib/models/rules/rule.dart
  19. 4
      lib/utils/color.dart
  20. 24
      lib/utils/diff_delta.dart
  21. 18
      lib/widgets/controller.dart
  22. 16
      lib/widgets/cursor.dart
  23. 10
      lib/widgets/default_styles.dart
  24. 2
      lib/widgets/delegate.dart
  25. 152
      lib/widgets/editor.dart
  26. 6
      lib/widgets/keyboard_listener.dart
  27. 4
      lib/widgets/proxy.dart
  28. 135
      lib/widgets/raw_editor.dart
  29. 102
      lib/widgets/text_block.dart
  30. 85
      lib/widgets/text_line.dart
  31. 49
      lib/widgets/text_selection.dart
  32. 34
      lib/widgets/toolbar.dart

@ -3,7 +3,6 @@ include: package:pedantic/analysis_options.yaml
analyzer: analyzer:
errors: errors:
undefined_prefixed_name: ignore undefined_prefixed_name: ignore
omit_local_variable_types: ignore
unsafe_html: ignore unsafe_html: ignore
linter: linter:
rules: rules:
@ -11,7 +10,11 @@ linter:
- avoid_print - avoid_print
- avoid_redundant_argument_values - avoid_redundant_argument_values
- directives_ordering - directives_ordering
- omit_local_variable_types
- prefer_const_constructors - prefer_const_constructors
- prefer_const_constructors_in_immutables - prefer_const_constructors_in_immutables
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- prefer_relative_imports - prefer_relative_imports
- unnecessary_parenthesis - unnecessary_parenthesis

@ -178,14 +178,14 @@ class _HomePageState extends State<HomePage> {
// You can also upload the picked image to any server (eg : AWS s3 or Firebase) and then return the uploaded image URL // You can also upload the picked image to any server (eg : AWS s3 or Firebase) and then return the uploaded image URL
Future<String> _onImagePickCallback(File file) async { Future<String> _onImagePickCallback(File file) async {
// Copies the picked file from temporary cache to applications directory // Copies the picked file from temporary cache to applications directory
Directory appDocDir = await getApplicationDocumentsDirectory(); final appDocDir = await getApplicationDocumentsDirectory();
File copiedFile = final copiedFile =
await file.copy('${appDocDir.path}/${basename(file.path)}'); await file.copy('${appDocDir.path}/${basename(file.path)}');
return copiedFile.path.toString(); return copiedFile.path.toString();
} }
Widget _buildMenuBar(BuildContext context) { Widget _buildMenuBar(BuildContext context) {
Size size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
final itemStyle = const TextStyle( final itemStyle = const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 18, fontSize: 18,

@ -28,8 +28,8 @@ var ui = UniversalUI();
Widget defaultEmbedBuilderWeb(BuildContext context, leaf.Embed node) { Widget defaultEmbedBuilderWeb(BuildContext context, leaf.Embed node) {
switch (node.value.type) { switch (node.value.type) {
case 'image': case 'image':
String imageUrl = node.value.data; final String imageUrl = node.value.data;
Size size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
UniversalUI().platformViewRegistry.registerViewFactory( UniversalUI().platformViewRegistry.registerViewFactory(
imageUrl, (int viewId) => html.ImageElement()..src = imageUrl); imageUrl, (int viewId) => html.ImageElement()..src = imageUrl);
return Padding( return Padding(

@ -164,8 +164,8 @@ class Attribute<T> {
if (!_registry.containsKey(key)) { if (!_registry.containsKey(key)) {
throw ArgumentError.value(key, 'key "$key" not found.'); throw ArgumentError.value(key, 'key "$key" not found.');
} }
Attribute origin = _registry[key]!; final origin = _registry[key]!;
Attribute attribute = clone(origin, value); final attribute = clone(origin, value);
return attribute; return attribute;
} }
@ -177,7 +177,7 @@ class Attribute<T> {
bool operator ==(Object other) { bool operator ==(Object other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
if (other is! Attribute<T>) return false; if (other is! Attribute<T>) return false;
Attribute<T> typedOther = other; final typedOther = other;
return key == typedOther.key && return key == typedOther.key &&
scope == typedOther.scope && scope == typedOther.scope &&
value == typedOther.value; value == typedOther.value;

@ -56,14 +56,14 @@ class Document {
return Delta(); return Delta();
} }
Delta delta = _rules.apply(RuleType.INSERT, this, index, data: data); final delta = _rules.apply(RuleType.INSERT, this, index, data: data);
compose(delta, ChangeSource.LOCAL); compose(delta, ChangeSource.LOCAL);
return delta; return delta;
} }
Delta delete(int index, int len) { Delta delete(int index, int len) {
assert(index >= 0 && len > 0); assert(index >= 0 && len > 0);
Delta delta = _rules.apply(RuleType.DELETE, this, index, len: len); final delta = _rules.apply(RuleType.DELETE, this, index, len: len);
if (delta.isNotEmpty) { if (delta.isNotEmpty) {
compose(delta, ChangeSource.LOCAL); compose(delta, ChangeSource.LOCAL);
} }
@ -74,18 +74,18 @@ class Document {
assert(index >= 0); assert(index >= 0);
assert(data is String || data is Embeddable); assert(data is String || data is Embeddable);
bool dataIsNotEmpty = (data is String) ? data.isNotEmpty : true; final dataIsNotEmpty = (data is String) ? data.isNotEmpty : true;
assert(dataIsNotEmpty || len > 0); assert(dataIsNotEmpty || len > 0);
Delta delta = Delta(); var delta = Delta();
if (dataIsNotEmpty) { if (dataIsNotEmpty) {
delta = insert(index + len, data); delta = insert(index + len, data);
} }
if (len > 0) { if (len > 0) {
Delta deleteDelta = delete(index, len); final deleteDelta = delete(index, len);
delta = delta.compose(deleteDelta); delta = delta.compose(deleteDelta);
} }
@ -95,9 +95,9 @@ class Document {
Delta format(int index, int len, Attribute? attribute) { Delta format(int index, int len, Attribute? attribute) {
assert(index >= 0 && len >= 0 && attribute != null); assert(index >= 0 && len >= 0 && attribute != null);
Delta delta = Delta(); var delta = Delta();
Delta formatDelta = _rules.apply(RuleType.FORMAT, this, index, final formatDelta = _rules.apply(RuleType.FORMAT, this, index,
len: len, attribute: attribute); len: len, attribute: attribute);
if (formatDelta.isNotEmpty) { if (formatDelta.isNotEmpty) {
compose(formatDelta, ChangeSource.LOCAL); compose(formatDelta, ChangeSource.LOCAL);
@ -108,16 +108,16 @@ class Document {
} }
Style collectStyle(int index, int len) { Style collectStyle(int index, int len) {
ChildQuery res = queryChild(index); final res = queryChild(index);
return (res.node as Line).collectStyle(res.offset, len); return (res.node as Line).collectStyle(res.offset, len);
} }
ChildQuery queryChild(int offset) { ChildQuery queryChild(int offset) {
ChildQuery res = _root.queryChild(offset, true); final res = _root.queryChild(offset, true);
if (res.node is Line) { if (res.node is Line) {
return res; return res;
} }
Block block = res.node as Block; final block = res.node as Block;
return block.queryChild(res.offset, true); return block.queryChild(res.offset, true);
} }
@ -126,11 +126,11 @@ class Document {
delta.trim(); delta.trim();
assert(delta.isNotEmpty); assert(delta.isNotEmpty);
int offset = 0; var offset = 0;
delta = _transform(delta); delta = _transform(delta);
Delta originalDelta = toDelta(); final originalDelta = toDelta();
for (Operation op in delta.toList()) { for (final op in delta.toList()) {
Style? style = final style =
op.attributes != null ? Style.fromJson(op.attributes) : null; op.attributes != null ? Style.fromJson(op.attributes) : null;
if (op.isInsert) { if (op.isInsert) {
@ -172,10 +172,10 @@ class Document {
bool get hasRedo => _history.hasRedo; bool get hasRedo => _history.hasRedo;
static Delta _transform(Delta delta) { static Delta _transform(Delta delta) {
Delta res = Delta(); final res = Delta();
List<Operation> ops = delta.toList(); final ops = delta.toList();
for (int i = 0; i < ops.length; i++) { for (var i = 0; i < ops.length; i++) {
Operation op = ops[i]; final op = ops[i];
res.push(op); res.push(op);
_handleImageInsert(i, ops, op, res); _handleImageInsert(i, ops, op, res);
} }
@ -184,14 +184,14 @@ class Document {
static void _handleImageInsert( static void _handleImageInsert(
int i, List<Operation> ops, Operation op, Delta res) { int i, List<Operation> ops, Operation op, Delta res) {
bool nextOpIsImage = final nextOpIsImage =
i + 1 < ops.length && ops[i + 1].isInsert && ops[i + 1].data is! String; i + 1 < ops.length && ops[i + 1].isInsert && ops[i + 1].data is! String;
if (nextOpIsImage && !(op.data as String).endsWith('\n')) { if (nextOpIsImage && !(op.data as String).endsWith('\n')) {
res.push(Operation.insert('\n')); res.push(Operation.insert('\n'));
} }
// Currently embed is equivalent to image and hence `is! String` // Currently embed is equivalent to image and hence `is! String`
bool opInsertImage = op.isInsert && op.data is! String; final opInsertImage = op.isInsert && op.data is! String;
bool nextOpIsLineBreak = i + 1 < ops.length && final nextOpIsLineBreak = i + 1 < ops.length &&
ops[i + 1].isInsert && ops[i + 1].isInsert &&
ops[i + 1].data is String && ops[i + 1].data is String &&
(ops[i + 1].data as String).startsWith('\n'); (ops[i + 1].data as String).startsWith('\n');
@ -221,7 +221,7 @@ class Document {
void _loadDocument(Delta doc) { void _loadDocument(Delta doc) {
assert((doc.last.data as String).endsWith('\n')); assert((doc.last.data as String).endsWith('\n'));
int offset = 0; var offset = 0;
for (final op in doc.toList()) { for (final op in doc.toList()) {
if (!op.isInsert) { if (!op.isInsert) {
throw ArgumentError.value(doc, throw ArgumentError.value(doc,
@ -247,12 +247,12 @@ class Document {
return false; return false;
} }
final Node node = root.children.first; final node = root.children.first;
if (!node.isLast) { if (!node.isLast) {
return false; return false;
} }
Delta delta = node.toDelta(); final delta = node.toDelta();
return delta.length == 1 && return delta.length == 1 &&
delta.first.data == '\n' && delta.first.data == '\n' &&
delta.first.key == 'insert'; delta.first.key == 'insert';

@ -47,7 +47,7 @@ class History {
void record(Delta change, Delta before) { void record(Delta change, Delta before) {
if (change.isEmpty) return; if (change.isEmpty) return;
stack.redo.clear(); stack.redo.clear();
Delta undoDelta = change.invert(before); var undoDelta = change.invert(before);
final timeStamp = DateTime.now().millisecondsSinceEpoch; final timeStamp = DateTime.now().millisecondsSinceEpoch;
if (lastRecorded + interval > timeStamp && stack.undo.isNotEmpty) { if (lastRecorded + interval > timeStamp && stack.undo.isNotEmpty) {
@ -74,7 +74,7 @@ class History {
} }
void transformStack(List<Delta> stack, Delta delta) { void transformStack(List<Delta> stack, Delta delta) {
for (int i = stack.length - 1; i >= 0; i -= 1) { for (var i = stack.length - 1; i >= 0; i -= 1) {
final oldDelta = stack[i]; final oldDelta = stack[i];
stack[i] = delta.transform(oldDelta, true); stack[i] = delta.transform(oldDelta, true);
delta = oldDelta.transform(delta, false); delta = oldDelta.transform(delta, false);
@ -88,10 +88,10 @@ class History {
if (source.isEmpty) { if (source.isEmpty) {
return const Tuple2(false, 0); return const Tuple2(false, 0);
} }
Delta delta = source.removeLast(); final delta = source.removeLast();
// look for insert or delete // look for insert or delete
int? len = 0; int? len = 0;
List<Operation> ops = delta.toList(); final ops = delta.toList();
for (var i = 0; i < ops.length; i++) { for (var i = 0; i < ops.length; i++) {
if (ops[i].key == Operation.insertKey) { if (ops[i].key == Operation.insertKey) {
len = ops[i].length; len = ops[i].length;
@ -99,8 +99,8 @@ class History {
len = ops[i].length! * -1; len = ops[i].length! * -1;
} }
} }
Delta base = Delta.from(doc.toDelta()); final base = Delta.from(doc.toDelta());
Delta inverseDelta = delta.invert(base); final inverseDelta = delta.invert(base);
dest.add(inverseDelta); dest.add(inverseDelta);
lastRecorded = 0; lastRecorded = 0;
ignoreChange = true; ignoreChange = true;

@ -17,7 +17,7 @@ class Block extends Container<Line?> {
@override @override
void adjust() { void adjust() {
if (isEmpty) { if (isEmpty) {
Node? sibling = previous; final sibling = previous;
unlink(); unlink();
if (sibling != null) { if (sibling != null) {
sibling.adjust(); sibling.adjust();
@ -25,8 +25,8 @@ class Block extends Container<Line?> {
return; return;
} }
Block block = this; var block = this;
Node? prev = block.previous; final prev = block.previous;
// merging it with previous block if style is the same // merging it with previous block if style is the same
if (!block.isFirst && if (!block.isFirst &&
block.previous is Block && block.previous is Block &&
@ -35,7 +35,7 @@ class Block extends Container<Line?> {
block.unlink(); block.unlink();
block = prev as Block; block = prev as Block;
} }
Node? next = block.next; final next = block.next;
// merging it with next block if style is the same // merging it with next block if style is the same
if (!block.isLast && block.next is Block && next!.style == block.style) { if (!block.isLast && block.next is Block && next!.style == block.style) {
(next as Block).moveChildToNewParent(block); (next as Block).moveChildToNewParent(block);
@ -47,7 +47,7 @@ class Block extends Container<Line?> {
String toString() { String toString() {
final block = style.attributes.toString(); final block = style.attributes.toString();
final buffer = StringBuffer('§ {$block}\n'); final buffer = StringBuffer('§ {$block}\n');
for (var child in children) { for (final child in children) {
final tree = child.isLast ? '' : ''; final tree = child.isLast ? '' : '';
buffer.write(' $tree $child'); buffer.write(' $tree $child');
if (!child.isLast) buffer.writeln(); if (!child.isLast) buffer.writeln();

@ -48,9 +48,9 @@ abstract class Container<T extends Node?> extends Node {
return; return;
} }
T? last = newParent!.isEmpty ? null : newParent.last as T?; final last = newParent!.isEmpty ? null : newParent.last as T?;
while (isNotEmpty) { while (isNotEmpty) {
T child = first as T; final child = first as T;
child?.unlink(); child?.unlink();
newParent.add(child); newParent.add(child);
} }
@ -63,8 +63,8 @@ abstract class Container<T extends Node?> extends Node {
return ChildQuery(null, 0); return ChildQuery(null, 0);
} }
for (Node node in children) { for (final node in children) {
int len = node.length; final len = node.length;
if (offset < len || (inclusive && offset == len && (node.isLast))) { if (offset < len || (inclusive && offset == len && (node.isLast))) {
return ChildQuery(node, offset); return ChildQuery(node, offset);
} }
@ -84,14 +84,14 @@ abstract class Container<T extends Node?> extends Node {
assert(index == 0 || (index > 0 && index < length)); assert(index == 0 || (index > 0 && index < length));
if (isNotEmpty) { if (isNotEmpty) {
ChildQuery child = queryChild(index, false); final child = queryChild(index, false);
child.node!.insert(child.offset, data, style); child.node!.insert(child.offset, data, style);
return; return;
} }
// empty // empty
assert(index == 0); assert(index == 0);
T node = defaultChild; final node = defaultChild;
add(node); add(node);
node?.insert(index, data, style); node?.insert(index, data, style);
} }
@ -99,14 +99,14 @@ abstract class Container<T extends Node?> extends Node {
@override @override
void retain(int index, int? length, Style? attributes) { void retain(int index, int? length, Style? attributes) {
assert(isNotEmpty); assert(isNotEmpty);
ChildQuery child = queryChild(index, false); final child = queryChild(index, false);
child.node!.retain(child.offset, length, attributes); child.node!.retain(child.offset, length, attributes);
} }
@override @override
void delete(int index, int? length) { void delete(int index, int? length) {
assert(isNotEmpty); assert(isNotEmpty);
ChildQuery child = queryChild(index, false); final child = queryChild(index, false);
child.node!.delete(child.offset, length); child.node!.delete(child.offset, length);
} }

@ -5,12 +5,12 @@ class Embeddable {
Embeddable(this.type, this.data); Embeddable(this.type, this.data);
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
Map<String, String> m = {type: data}; final m = <String, String>{type: data};
return m; return m;
} }
static Embeddable fromJson(Map<String, dynamic> json) { static Embeddable fromJson(Map<String, dynamic> json) {
Map<String, dynamic> m = Map<String, dynamic>.from(json); final m = Map<String, dynamic>.from(json);
assert(m.length == 1, 'Embeddable map has one key'); assert(m.length == 1, 'Embeddable map has one key');
return BlockEmbed(m.keys.first, m.values.first); return BlockEmbed(m.keys.first, m.values.first);

@ -18,7 +18,7 @@ abstract class Leaf extends Node {
if (data is Embeddable) { if (data is Embeddable) {
return Embed(data); return Embed(data);
} }
String text = data as String; final text = data as String;
assert(text.isNotEmpty); assert(text.isNotEmpty);
return Text(text); return Text(text);
} }
@ -44,14 +44,15 @@ abstract class Leaf extends Node {
@override @override
Delta toDelta() { Delta toDelta() {
var data = _value is Embeddable ? (_value as Embeddable).toJson() : _value; final data =
_value is Embeddable ? (_value as Embeddable).toJson() : _value;
return Delta()..insert(data, style.toJson()); return Delta()..insert(data, style.toJson());
} }
@override @override
void insert(int index, Object data, Style? style) { void insert(int index, Object data, Style? style) {
assert(index >= 0 && index <= length); assert(index >= 0 && index <= length);
Leaf node = Leaf(data); final node = Leaf(data);
if (index < length) { if (index < length) {
splitAt(index)!.insertBefore(node); splitAt(index)!.insertBefore(node);
} else { } else {
@ -66,9 +67,9 @@ abstract class Leaf extends Node {
return; return;
} }
int local = math.min(length - index, len!); final local = math.min(length - index, len!);
int remain = len - local; final remain = len - local;
Leaf node = _isolate(index, local); final node = _isolate(index, local);
if (remain > 0) { if (remain > 0) {
assert(node.next != null); assert(node.next != null);
@ -81,13 +82,13 @@ abstract class Leaf extends Node {
void delete(int index, int? len) { void delete(int index, int? len) {
assert(index < length); assert(index < length);
int local = math.min(length - index, len!); final local = math.min(length - index, len!);
Leaf target = _isolate(index, local); final target = _isolate(index, local);
Leaf? prev = target.previous as Leaf?; final prev = target.previous as Leaf?;
Leaf? next = target.next as Leaf?; final next = target.next as Leaf?;
target.unlink(); target.unlink();
int remain = len - local; final remain = len - local;
if (remain > 0) { if (remain > 0) {
assert(next != null); assert(next != null);
next!.delete(0, remain); next!.delete(0, remain);
@ -104,9 +105,9 @@ abstract class Leaf extends Node {
return; return;
} }
Text node = this as Text; var node = this as Text;
// merging it with previous node if style is the same // merging it with previous node if style is the same
Node? prev = node.previous; final prev = node.previous;
if (!node.isFirst && prev is Text && prev.style == node.style) { if (!node.isFirst && prev is Text && prev.style == node.style) {
prev._value = prev.value + node.value; prev._value = prev.value + node.value;
node.unlink(); node.unlink();
@ -114,7 +115,7 @@ abstract class Leaf extends Node {
} }
// merging it with next node if style is the same // merging it with next node if style is the same
Node? next = node.next; final next = node.next;
if (!node.isLast && next is Text && next.style == node.style) { if (!node.isLast && next is Text && next.style == node.style) {
node._value = node.value + next.value; node._value = node.value + next.value;
next.unlink(); next.unlink();
@ -123,7 +124,7 @@ abstract class Leaf extends Node {
Leaf? cutAt(int index) { Leaf? cutAt(int index) {
assert(index >= 0 && index <= length); assert(index >= 0 && index <= length);
Leaf? cut = splitAt(index); final cut = splitAt(index);
cut?.unlink(); cut?.unlink();
return cut; return cut;
} }
@ -138,9 +139,9 @@ abstract class Leaf extends Node {
} }
assert(this is Text); assert(this is Text);
String text = _value as String; final text = _value as String;
_value = text.substring(0, index); _value = text.substring(0, index);
Leaf split = Leaf(text.substring(index)); final split = Leaf(text.substring(index));
split.applyStyle(style); split.applyStyle(style);
insertAfter(split); insertAfter(split);
return split; return split;
@ -157,7 +158,7 @@ abstract class Leaf extends Node {
Leaf _isolate(int index, int length) { Leaf _isolate(int index, int length) {
assert( assert(
index >= 0 && index < this.length && (index + length <= this.length)); index >= 0 && index < this.length && (index + length <= this.length));
Leaf target = splitAt(index)!; final target = splitAt(index)!;
target.splitAt(length); target.splitAt(length);
return target; return target;
} }

@ -47,7 +47,7 @@ class Line extends Container<Leaf?> {
.fold(Delta(), (dynamic a, b) => a.concat(b)); .fold(Delta(), (dynamic a, b) => a.concat(b));
var attributes = style; var attributes = style;
if (parent is Block) { if (parent is Block) {
Block block = parent as Block; final block = parent as Block;
attributes = attributes.mergeAll(block.style); attributes = attributes.mergeAll(block.style);
} }
delta.insert('\n', attributes.toJson()); delta.insert('\n', attributes.toJson());
@ -71,20 +71,20 @@ class Line extends Container<Leaf?> {
return; return;
} }
String text = data as String; final text = data as String;
int lineBreak = text.indexOf('\n'); final lineBreak = text.indexOf('\n');
if (lineBreak < 0) { if (lineBreak < 0) {
_insert(index, text, style); _insert(index, text, style);
return; return;
} }
String prefix = text.substring(0, lineBreak); final prefix = text.substring(0, lineBreak);
_insert(index, prefix, style); _insert(index, prefix, style);
if (prefix.isNotEmpty) { if (prefix.isNotEmpty) {
index += prefix.length; index += prefix.length;
} }
Line nextLine = _getNextLine(index); final nextLine = _getNextLine(index);
clearStyle(); clearStyle();
@ -95,7 +95,7 @@ class Line extends Container<Leaf?> {
_format(style); _format(style);
// Continue with the remaining // Continue with the remaining
String remain = text.substring(lineBreak + 1); final remain = text.substring(lineBreak + 1);
nextLine.insert(0, remain, style); nextLine.insert(0, remain, style);
} }
@ -104,9 +104,9 @@ class Line extends Container<Leaf?> {
if (style == null) { if (style == null) {
return; return;
} }
int thisLen = length; final thisLen = length;
int local = math.min(thisLen - index, len!); final local = math.min(thisLen - index, len!);
if (index + local == thisLen && local == 1) { if (index + local == thisLen && local == 1) {
assert(style.values.every((attr) => attr.scope == AttributeScope.BLOCK)); assert(style.values.every((attr) => attr.scope == AttributeScope.BLOCK));
@ -117,7 +117,7 @@ class Line extends Container<Leaf?> {
super.retain(index, local, style); super.retain(index, local, style);
} }
int remain = len - local; final remain = len - local;
if (remain > 0) { if (remain > 0) {
assert(nextLine != null); assert(nextLine != null);
nextLine!.retain(0, remain, style); nextLine!.retain(0, remain, style);
@ -126,8 +126,8 @@ class Line extends Container<Leaf?> {
@override @override
void delete(int index, int? len) { void delete(int index, int? len) {
int local = math.min(length - index, len!); final local = math.min(length - index, len!);
bool deleted = index + local == length; final deleted = index + local == length;
if (deleted) { if (deleted) {
clearStyle(); clearStyle();
if (local > 1) { if (local > 1) {
@ -137,7 +137,7 @@ class Line extends Container<Leaf?> {
super.delete(index, local); super.delete(index, local);
} }
int remain = len - local; final remain = len - local;
if (remain > 0) { if (remain > 0) {
assert(nextLine != null); assert(nextLine != null);
nextLine!.delete(0, remain); nextLine!.delete(0, remain);
@ -150,7 +150,7 @@ class Line extends Container<Leaf?> {
} }
if (deleted) { if (deleted) {
Node p = parent!; final Node p = parent!;
unlink(); unlink();
p.adjust(); p.adjust();
} }
@ -162,24 +162,24 @@ class Line extends Container<Leaf?> {
} }
applyStyle(newStyle); applyStyle(newStyle);
Attribute? blockStyle = newStyle.getBlockExceptHeader(); final blockStyle = newStyle.getBlockExceptHeader();
if (blockStyle == null) { if (blockStyle == null) {
return; return;
} }
if (parent is Block) { if (parent is Block) {
Attribute? parentStyle = (parent as Block).style.getBlockExceptHeader(); final parentStyle = (parent as Block).style.getBlockExceptHeader();
if (blockStyle.value == null) { if (blockStyle.value == null) {
_unwrap(); _unwrap();
} else if (blockStyle != parentStyle) { } else if (blockStyle != parentStyle) {
_unwrap(); _unwrap();
Block block = Block(); final block = Block();
block.applyAttribute(blockStyle); block.applyAttribute(blockStyle);
_wrap(block); _wrap(block);
block.adjust(); block.adjust();
} }
} else if (blockStyle.value != null) { } else if (blockStyle.value != null) {
Block block = Block(); final block = Block();
block.applyAttribute(blockStyle); block.applyAttribute(blockStyle);
_wrap(block); _wrap(block);
block.adjust(); block.adjust();
@ -197,7 +197,7 @@ class Line extends Container<Leaf?> {
if (parent is! Block) { if (parent is! Block) {
throw ArgumentError('Invalid parent'); throw ArgumentError('Invalid parent');
} }
Block block = parent as Block; final block = parent as Block;
assert(block.children.contains(this)); assert(block.children.contains(this));
@ -208,10 +208,10 @@ class Line extends Container<Leaf?> {
unlink(); unlink();
block.insertAfter(this); block.insertAfter(this);
} else { } else {
Block before = block.clone() as Block; final before = block.clone() as Block;
block.insertBefore(before); block.insertBefore(before);
Line child = block.first as Line; var child = block.first as Line;
while (child != this) { while (child != this) {
child.unlink(); child.unlink();
before.add(child); before.add(child);
@ -226,20 +226,20 @@ class Line extends Container<Leaf?> {
Line _getNextLine(int index) { Line _getNextLine(int index) {
assert(index == 0 || (index > 0 && index < length)); assert(index == 0 || (index > 0 && index < length));
Line line = clone() as Line; final line = clone() as Line;
insertAfter(line); insertAfter(line);
if (index == length - 1) { if (index == length - 1) {
return line; return line;
} }
ChildQuery query = queryChild(index, false); final query = queryChild(index, false);
while (!query.node!.isLast) { while (!query.node!.isLast) {
Leaf next = last as Leaf; final next = last as Leaf;
next.unlink(); next.unlink();
line.addFirst(next); line.addFirst(next);
} }
Leaf child = query.node as Leaf; final child = query.node as Leaf;
Leaf? cut = child.splitAt(query.offset); final cut = child.splitAt(query.offset);
cut?.unlink(); cut?.unlink();
line.addFirst(cut); line.addFirst(cut);
return line; return line;
@ -256,12 +256,12 @@ class Line extends Container<Leaf?> {
} }
if (isNotEmpty) { if (isNotEmpty) {
ChildQuery result = queryChild(index, true); final result = queryChild(index, true);
result.node!.insert(result.offset, data, style); result.node!.insert(result.offset, data, style);
return; return;
} }
Leaf child = Leaf(data); final child = Leaf(data);
add(child); add(child);
child.format(style); child.format(style);
} }
@ -272,30 +272,30 @@ class Line extends Container<Leaf?> {
} }
Style collectStyle(int offset, int len) { Style collectStyle(int offset, int len) {
int local = math.min(length - offset, len); final local = math.min(length - offset, len);
Style res = Style(); var res = Style();
var excluded = <Attribute>{}; final excluded = <Attribute>{};
void _handle(Style style) { void _handle(Style style) {
if (res.isEmpty) { if (res.isEmpty) {
excluded.addAll(style.values); excluded.addAll(style.values);
} else { } else {
for (Attribute attr in res.values) { for (final attr in res.values) {
if (!style.containsKey(attr.key)) { if (!style.containsKey(attr.key)) {
excluded.add(attr); excluded.add(attr);
} }
} }
} }
Style remain = style.removeAll(excluded); final remain = style.removeAll(excluded);
res = res.removeAll(excluded); res = res.removeAll(excluded);
res = res.mergeAll(remain); res = res.mergeAll(remain);
} }
ChildQuery data = queryChild(offset, true); final data = queryChild(offset, true);
Leaf? node = data.node as Leaf?; var node = data.node as Leaf?;
if (node != null) { if (node != null) {
res = res.mergeAll(node.style); res = res.mergeAll(node.style);
int pos = node.length - data.offset; var pos = node.length - data.offset;
while (!node!.isLast && pos < local) { while (!node!.isLast && pos < local) {
node = node.next as Leaf?; node = node.next as Leaf?;
_handle(node!.style); _handle(node!.style);
@ -305,11 +305,11 @@ class Line extends Container<Leaf?> {
res = res.mergeAll(style); res = res.mergeAll(style);
if (parent is Block) { if (parent is Block) {
Block block = parent as Block; final block = parent as Block;
res = res.mergeAll(block.style); res = res.mergeAll(block.style);
} }
int remain = len - local; final remain = len - local;
if (remain > 0) { if (remain > 0) {
_handle(nextLine!.collectStyle(0, remain)); _handle(nextLine!.collectStyle(0, remain));
} }

@ -32,19 +32,19 @@ abstract class Node extends LinkedListEntry<Node> {
int get length; int get length;
Node clone() { Node clone() {
Node node = newInstance(); final node = newInstance();
node.applyStyle(style); node.applyStyle(style);
return node; return node;
} }
int getOffset() { int getOffset() {
int offset = 0; var offset = 0;
if (list == null || isFirst) { if (list == null || isFirst) {
return offset; return offset;
} }
Node cur = this; var cur = this;
do { do {
cur = cur.previous!; cur = cur.previous!;
offset += cur.length; offset += cur.length;

@ -16,8 +16,8 @@ class Style {
return Style(); return Style();
} }
Map<String, Attribute> result = attributes.map((String key, dynamic value) { final result = attributes.map((String key, dynamic value) {
Attribute attr = Attribute.fromKeyValue(key, value); final attr = Attribute.fromKeyValue(key, value);
return MapEntry<String, Attribute>(key, attr); return MapEntry<String, Attribute>(key, attr);
}); });
return Style.attr(result); return Style.attr(result);
@ -48,7 +48,7 @@ class Style {
bool containsKey(String key) => _attributes.containsKey(key); bool containsKey(String key) => _attributes.containsKey(key);
Attribute? getBlockExceptHeader() { Attribute? getBlockExceptHeader() {
for (Attribute val in values) { for (final val in values) {
if (val.isBlockExceptHeader) { if (val.isBlockExceptHeader) {
return val; return val;
} }
@ -57,7 +57,7 @@ class Style {
} }
Style merge(Attribute attribute) { Style merge(Attribute attribute) {
Map<String, Attribute> merged = Map<String, Attribute>.from(_attributes); final merged = Map<String, Attribute>.from(_attributes);
if (attribute.value == null) { if (attribute.value == null) {
merged.remove(attribute.key); merged.remove(attribute.key);
} else { } else {
@ -67,21 +67,21 @@ class Style {
} }
Style mergeAll(Style other) { Style mergeAll(Style other) {
Style result = Style.attr(_attributes); var result = Style.attr(_attributes);
for (Attribute attribute in other.values) { for (final attribute in other.values) {
result = result.merge(attribute); result = result.merge(attribute);
} }
return result; return result;
} }
Style removeAll(Set<Attribute> attributes) { Style removeAll(Set<Attribute> attributes) {
Map<String, Attribute> merged = Map<String, Attribute>.from(_attributes); final merged = Map<String, Attribute>.from(_attributes);
attributes.map((item) => item.key).forEach(merged.remove); attributes.map((item) => item.key).forEach(merged.remove);
return Style.attr(merged); return Style.attr(merged);
} }
Style put(Attribute attribute) { Style put(Attribute attribute) {
Map<String, Attribute> m = Map<String, Attribute>.from(attributes); final m = Map<String, Attribute>.from(attributes);
m[attribute.key] = attribute; m[attribute.key] = attribute;
return Style.attr(m); return Style.attr(m);
} }
@ -94,7 +94,7 @@ class Style {
if (other is! Style) { if (other is! Style) {
return false; return false;
} }
Style typedOther = other; final typedOther = other;
final eq = const MapEquality<String, Attribute>(); final eq = const MapEquality<String, Attribute>();
return eq.equals(_attributes, typedOther._attributes); return eq.equals(_attributes, typedOther._attributes);
} }

@ -135,7 +135,7 @@ class Operation {
bool operator ==(other) { bool operator ==(other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
if (other is! Operation) return false; if (other is! Operation) return false;
Operation typedOther = other; final typedOther = other;
return key == typedOther.key && return key == typedOther.key &&
length == typedOther.length && length == typedOther.length &&
_valueEquality.equals(data, typedOther.data) && _valueEquality.equals(data, typedOther.data) &&
@ -221,14 +221,14 @@ class Delta {
attr ??= const {}; attr ??= const {};
base ??= const {}; base ??= const {};
var baseInverted = base.keys.fold({}, (dynamic memo, key) { final baseInverted = base.keys.fold({}, (dynamic memo, key) {
if (base![key] != attr![key] && attr.containsKey(key)) { if (base![key] != attr![key] && attr.containsKey(key)) {
memo[key] = base[key]; memo[key] = base[key];
} }
return memo; return memo;
}); });
var inverted = final inverted =
Map<String, dynamic>.from(attr.keys.fold(baseInverted, (memo, key) { Map<String, dynamic>.from(attr.keys.fold(baseInverted, (memo, key) {
if (base![key] != attr![key] && !base.containsKey(key)) { if (base![key] != attr![key] && !base.containsKey(key)) {
memo[key] = null; memo[key] = null;
@ -292,7 +292,7 @@ class Delta {
bool operator ==(dynamic other) { bool operator ==(dynamic other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
if (other is! Delta) return false; if (other is! Delta) return false;
Delta typedOther = other; final typedOther = other;
final comparator = final comparator =
const ListEquality<Operation>(DefaultEquality<Operation>()); const ListEquality<Operation>(DefaultEquality<Operation>());
return comparator.equals(_operations, typedOther._operations); return comparator.equals(_operations, typedOther._operations);
@ -529,7 +529,8 @@ class Delta {
if (op.isDelete) { if (op.isDelete) {
inverted.push(baseOp); inverted.push(baseOp);
} else if (op.isRetain && op.isNotPlain) { } else if (op.isRetain && op.isNotPlain) {
var invertAttr = invertAttributes(op.attributes, baseOp.attributes); final invertAttr =
invertAttributes(op.attributes, baseOp.attributes);
inverted.retain( inverted.retain(
baseOp.length!, invertAttr.isEmpty ? null : invertAttr); baseOp.length!, invertAttr.isEmpty ? null : invertAttr);
} }
@ -548,7 +549,7 @@ class Delta {
Delta slice(int start, [int? end]) { Delta slice(int start, [int? end]) {
final delta = Delta(); final delta = Delta();
var index = 0; var index = 0;
var opIterator = DeltaIterator(this); final opIterator = DeltaIterator(this);
final actualEnd = end ?? double.infinity; final actualEnd = end ?? double.infinity;
@ -661,7 +662,7 @@ class DeltaIterator {
final opIsNotEmpty = final opIsNotEmpty =
opData is String ? opData.isNotEmpty : true; // embeds are never empty opData is String ? opData.isNotEmpty : true; // embeds are never empty
final opLength = opData is String ? opData.length : 1; final opLength = opData is String ? opData.length : 1;
final int opActualLength = opIsNotEmpty ? opLength : actualLength as int; final opActualLength = opIsNotEmpty ? opLength : actualLength as int;
return Operation._(opKey, opActualLength, opData, opAttributes); return Operation._(opKey, opActualLength, opData, opAttributes);
} }
return Operation.retain(length); return Operation.retain(length);

@ -34,31 +34,31 @@ class PreserveLineStyleOnMergeRule extends DeleteRule {
@override @override
Delta? applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int? len, Object? data, Attribute? attribute}) { {int? len, Object? data, Attribute? attribute}) {
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Operation op = itr.next(1); var op = itr.next(1);
if (op.data != '\n') { if (op.data != '\n') {
return null; return null;
} }
bool isNotPlain = op.isNotPlain; final isNotPlain = op.isNotPlain;
Map<String, dynamic>? attrs = op.attributes; final attrs = op.attributes;
itr.skip(len! - 1); itr.skip(len! - 1);
Delta delta = Delta() final delta = Delta()
..retain(index) ..retain(index)
..delete(len); ..delete(len);
while (itr.hasNext) { while (itr.hasNext) {
op = itr.next(); op = itr.next();
String text = op.data is String ? (op.data as String?)! : ''; final text = op.data is String ? (op.data as String?)! : '';
int lineBreak = text.indexOf('\n'); final lineBreak = text.indexOf('\n');
if (lineBreak == -1) { if (lineBreak == -1) {
delta.retain(op.length!); delta.retain(op.length!);
continue; continue;
} }
Map<String, dynamic>? attributes = op.attributes == null var attributes = op.attributes == null
? null ? null
: op.attributes!.map<String, dynamic>((String key, dynamic value) => : op.attributes!.map<String, dynamic>((String key, dynamic value) =>
MapEntry<String, dynamic>(key, null)); MapEntry<String, dynamic>(key, null));
@ -80,15 +80,15 @@ class EnsureEmbedLineRule extends DeleteRule {
@override @override
Delta? applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int? len, Object? data, Attribute? attribute}) { {int? len, Object? data, Attribute? attribute}) {
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
Operation? op = itr.skip(index); var op = itr.skip(index);
int? indexDelta = 0, lengthDelta = 0, remain = len; int? indexDelta = 0, lengthDelta = 0, remain = len;
bool embedFound = op != null && op.data is! String; var embedFound = op != null && op.data is! String;
bool hasLineBreakBefore = final hasLineBreakBefore =
!embedFound && (op == null || (op.data as String).endsWith('\n')); !embedFound && (op == null || (op.data as String).endsWith('\n'));
if (embedFound) { if (embedFound) {
Operation candidate = itr.next(1); var candidate = itr.next(1);
if (remain != null) { if (remain != null) {
remain--; remain--;
if (candidate.data == '\n') { if (candidate.data == '\n') {
@ -107,7 +107,7 @@ class EnsureEmbedLineRule extends DeleteRule {
op = itr.skip(remain!); op = itr.skip(remain!);
if (op != null && if (op != null &&
(op.data is String ? op.data as String? : '')!.endsWith('\n')) { (op.data is String ? op.data as String? : '')!.endsWith('\n')) {
Operation candidate = itr.next(1); final candidate = itr.next(1);
if (candidate.data is! String && !hasLineBreakBefore) { if (candidate.data is! String && !hasLineBreakBefore) {
embedFound = true; embedFound = true;
lengthDelta--; lengthDelta--;

@ -26,21 +26,21 @@ class ResolveLineFormatRule extends FormatRule {
return null; return null;
} }
Delta delta = Delta()..retain(index); var delta = Delta()..retain(index);
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Operation op; Operation op;
for (int cur = 0; cur < len! && itr.hasNext; cur += op.length!) { for (var cur = 0; cur < len! && itr.hasNext; cur += op.length!) {
op = itr.next(len - cur); op = itr.next(len - cur);
if (op.data is! String || !(op.data as String).contains('\n')) { if (op.data is! String || !(op.data as String).contains('\n')) {
delta.retain(op.length!); delta.retain(op.length!);
continue; continue;
} }
String text = op.data as String; final text = op.data as String;
Delta tmp = Delta(); final tmp = Delta();
int offset = 0; var offset = 0;
for (int lineBreak = text.indexOf('\n'); for (var lineBreak = text.indexOf('\n');
lineBreak >= 0; lineBreak >= 0;
lineBreak = text.indexOf('\n', offset)) { lineBreak = text.indexOf('\n', offset)) {
tmp..retain(lineBreak - offset)..retain(1, attribute.toJson()); tmp..retain(lineBreak - offset)..retain(1, attribute.toJson());
@ -52,8 +52,8 @@ class ResolveLineFormatRule extends FormatRule {
while (itr.hasNext) { while (itr.hasNext) {
op = itr.next(); op = itr.next();
String text = op.data is String ? (op.data as String?)! : ''; final text = op.data is String ? (op.data as String?)! : '';
int lineBreak = text.indexOf('\n'); final lineBreak = text.indexOf('\n');
if (lineBreak < 0) { if (lineBreak < 0) {
delta.retain(op.length!); delta.retain(op.length!);
continue; continue;
@ -75,9 +75,9 @@ class FormatLinkAtCaretPositionRule extends FormatRule {
return null; return null;
} }
Delta delta = Delta(); final delta = Delta();
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
Operation? before = itr.skip(index), after = itr.next(); final before = itr.skip(index), after = itr.next();
int? beg = index, retain = 0; int? beg = index, retain = 0;
if (before != null && before.hasAttribute(attribute.key)) { if (before != null && before.hasAttribute(attribute.key)) {
beg -= before.length!; beg -= before.length!;
@ -105,20 +105,20 @@ class ResolveInlineFormatRule extends FormatRule {
return null; return null;
} }
Delta delta = Delta()..retain(index); final delta = Delta()..retain(index);
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Operation op; Operation op;
for (int cur = 0; cur < len! && itr.hasNext; cur += op.length!) { for (var cur = 0; cur < len! && itr.hasNext; cur += op.length!) {
op = itr.next(len - cur); op = itr.next(len - cur);
String text = op.data is String ? (op.data as String?)! : ''; final text = op.data is String ? (op.data as String?)! : '';
int lineBreak = text.indexOf('\n'); var lineBreak = text.indexOf('\n');
if (lineBreak < 0) { if (lineBreak < 0) {
delta.retain(op.length!, attribute.toJson()); delta.retain(op.length!, attribute.toJson());
continue; continue;
} }
int pos = 0; var pos = 0;
while (lineBreak >= 0) { while (lineBreak >= 0) {
delta..retain(lineBreak - pos, attribute.toJson())..retain(1); delta..retain(lineBreak - pos, attribute.toJson())..retain(1);
pos = lineBreak + 1; pos = lineBreak + 1;

@ -29,28 +29,28 @@ class PreserveLineStyleOnSplitRule extends InsertRule {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
Operation? before = itr.skip(index); final before = itr.skip(index);
if (before == null || if (before == null ||
before.data is! String || before.data is! String ||
(before.data as String).endsWith('\n')) { (before.data as String).endsWith('\n')) {
return null; return null;
} }
Operation after = itr.next(); final after = itr.next();
if (after.data is! String || (after.data as String).startsWith('\n')) { if (after.data is! String || (after.data as String).startsWith('\n')) {
return null; return null;
} }
final text = after.data as String; final text = after.data as String;
Delta delta = Delta()..retain(index); final delta = Delta()..retain(index);
if (text.contains('\n')) { if (text.contains('\n')) {
assert(after.isPlain); assert(after.isPlain);
delta.insert('\n'); delta.insert('\n');
return delta; return delta;
} }
Tuple2<Operation?, int?> nextNewLine = _getNextNewLine(itr); final nextNewLine = _getNextNewLine(itr);
Map<String, dynamic>? attributes = nextNewLine.item1?.attributes; final attributes = nextNewLine.item1?.attributes;
return delta..insert('\n', attributes); return delta..insert('\n', attributes);
} }
@ -66,19 +66,19 @@ class PreserveBlockStyleOnInsertRule extends InsertRule {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Tuple2<Operation?, int?> nextNewLine = _getNextNewLine(itr); final nextNewLine = _getNextNewLine(itr);
Style lineStyle = final lineStyle =
Style.fromJson(nextNewLine.item1?.attributes ?? <String, dynamic>{}); Style.fromJson(nextNewLine.item1?.attributes ?? <String, dynamic>{});
Attribute? attribute = lineStyle.getBlockExceptHeader(); final attribute = lineStyle.getBlockExceptHeader();
if (attribute == null) { if (attribute == null) {
return null; return null;
} }
var blockStyle = <String, dynamic>{attribute.key: attribute.value}; final blockStyle = <String, dynamic>{attribute.key: attribute.value};
Map<String, dynamic>? resetStyle; Map<String, dynamic>? resetStyle;
@ -86,10 +86,10 @@ class PreserveBlockStyleOnInsertRule extends InsertRule {
resetStyle = Attribute.header.toJson(); resetStyle = Attribute.header.toJson();
} }
List<String> lines = data.split('\n'); final lines = data.split('\n');
Delta delta = Delta()..retain(index); final delta = Delta()..retain(index);
for (int i = 0; i < lines.length; i++) { for (var i = 0; i < lines.length; i++) {
String line = lines[i]; final line = lines[i];
if (line.isNotEmpty) { if (line.isNotEmpty) {
delta.insert(line); delta.insert(line);
} }
@ -131,10 +131,9 @@ class AutoExitBlockRule extends InsertRule {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
Operation? prev = itr.skip(index), cur = itr.next(); final prev = itr.skip(index), cur = itr.next();
Attribute? blockStyle = final blockStyle = Style.fromJson(cur.attributes).getBlockExceptHeader();
Style.fromJson(cur.attributes).getBlockExceptHeader();
if (cur.isPlain || blockStyle == null) { if (cur.isPlain || blockStyle == null) {
return null; return null;
} }
@ -146,7 +145,7 @@ class AutoExitBlockRule extends InsertRule {
return null; return null;
} }
Tuple2<Operation?, int?> nextNewLine = _getNextNewLine(itr); final nextNewLine = _getNextNewLine(itr);
if (nextNewLine.item1 != null && if (nextNewLine.item1 != null &&
nextNewLine.item1!.attributes != null && nextNewLine.item1!.attributes != null &&
Style.fromJson(nextNewLine.item1!.attributes).getBlockExceptHeader() == Style.fromJson(nextNewLine.item1!.attributes).getBlockExceptHeader() ==
@ -155,7 +154,7 @@ class AutoExitBlockRule extends InsertRule {
} }
final attributes = cur.attributes ?? <String, dynamic>{}; final attributes = cur.attributes ?? <String, dynamic>{};
String k = attributes.keys final k = attributes.keys
.firstWhere((k) => Attribute.blockKeysExceptHeader.contains(k)); .firstWhere((k) => Attribute.blockKeysExceptHeader.contains(k));
attributes[k] = null; attributes[k] = null;
// retain(1) should be '\n', set it with no attribute // retain(1) should be '\n', set it with no attribute
@ -173,9 +172,9 @@ class ResetLineFormatOnNewLineRule extends InsertRule {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Operation cur = itr.next(); final cur = itr.next();
if (cur.data is! String || !(cur.data as String).startsWith('\n')) { if (cur.data is! String || !(cur.data as String).startsWith('\n')) {
return null; return null;
} }
@ -203,12 +202,12 @@ class InsertEmbedsRule extends InsertRule {
return null; return null;
} }
Delta delta = Delta()..retain(index); final delta = Delta()..retain(index);
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
Operation? prev = itr.skip(index), cur = itr.next(); final prev = itr.skip(index), cur = itr.next();
String? textBefore = prev?.data is String ? prev!.data as String? : ''; final textBefore = prev?.data is String ? prev!.data as String? : '';
String textAfter = cur.data is String ? (cur.data as String?)! : ''; final textAfter = cur.data is String ? (cur.data as String?)! : '';
final isNewlineBefore = prev == null || textBefore!.endsWith('\n'); final isNewlineBefore = prev == null || textBefore!.endsWith('\n');
final isNewlineAfter = textAfter.startsWith('\n'); final isNewlineAfter = textAfter.startsWith('\n');
@ -222,7 +221,7 @@ class InsertEmbedsRule extends InsertRule {
lineStyle = cur.attributes; lineStyle = cur.attributes;
} else { } else {
while (itr.hasNext) { while (itr.hasNext) {
Operation op = itr.next(); final op = itr.next();
if ((op.data is String ? op.data as String? : '')!.contains('\n')) { if ((op.data is String ? op.data as String? : '')!.contains('\n')) {
lineStyle = op.attributes; lineStyle = op.attributes;
break; break;
@ -251,17 +250,17 @@ class ForceNewlineForInsertsAroundEmbedRule extends InsertRule {
return null; return null;
} }
String text = data; final text = data;
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
final prev = itr.skip(index); final prev = itr.skip(index);
final cur = itr.next(); final cur = itr.next();
bool cursorBeforeEmbed = cur.data is! String; final cursorBeforeEmbed = cur.data is! String;
bool cursorAfterEmbed = prev != null && prev.data is! String; final cursorAfterEmbed = prev != null && prev.data is! String;
if (!cursorBeforeEmbed && !cursorAfterEmbed) { if (!cursorBeforeEmbed && !cursorAfterEmbed) {
return null; return null;
} }
Delta delta = Delta()..retain(index); final delta = Delta()..retain(index);
if (cursorBeforeEmbed && !text.endsWith('\n')) { if (cursorBeforeEmbed && !text.endsWith('\n')) {
return delta..insert(text)..insert('\n'); return delta..insert(text)..insert('\n');
} }
@ -282,19 +281,19 @@ class AutoFormatLinksRule extends InsertRule {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
Operation? prev = itr.skip(index); final prev = itr.skip(index);
if (prev == null || prev.data is! String) { if (prev == null || prev.data is! String) {
return null; return null;
} }
try { try {
String cand = (prev.data as String).split('\n').last.split(' ').last; final cand = (prev.data as String).split('\n').last.split(' ').last;
Uri link = Uri.parse(cand); final link = Uri.parse(cand);
if (!['https', 'http'].contains(link.scheme)) { if (!['https', 'http'].contains(link.scheme)) {
return null; return null;
} }
Map<String, dynamic> attributes = prev.attributes ?? <String, dynamic>{}; final attributes = prev.attributes ?? <String, dynamic>{};
if (attributes.containsKey(Attribute.link.key)) { if (attributes.containsKey(Attribute.link.key)) {
return null; return null;
@ -321,16 +320,16 @@ class PreserveInlineStylesRule extends InsertRule {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); final itr = DeltaIterator(document);
Operation? prev = itr.skip(index); final prev = itr.skip(index);
if (prev == null || if (prev == null ||
prev.data is! String || prev.data is! String ||
(prev.data as String).contains('\n')) { (prev.data as String).contains('\n')) {
return null; return null;
} }
Map<String, dynamic>? attributes = prev.attributes; final attributes = prev.attributes;
String text = data; final text = data;
if (attributes == null || !attributes.containsKey(Attribute.link.key)) { if (attributes == null || !attributes.containsKey(Attribute.link.key)) {
return Delta() return Delta()
..retain(index) ..retain(index)
@ -338,13 +337,12 @@ class PreserveInlineStylesRule extends InsertRule {
} }
attributes.remove(Attribute.link.key); attributes.remove(Attribute.link.key);
Delta delta = Delta() final delta = Delta()
..retain(index) ..retain(index)
..insert(text, attributes.isEmpty ? null : attributes); ..insert(text, attributes.isEmpty ? null : attributes);
Operation next = itr.next(); final next = itr.next();
Map<String, dynamic> nextAttributes = final nextAttributes = next.attributes ?? const <String, dynamic>{};
next.attributes ?? const <String, dynamic>{};
if (!nextAttributes.containsKey(Attribute.link.key)) { if (!nextAttributes.containsKey(Attribute.link.key)) {
return delta; return delta;
} }
@ -371,9 +369,9 @@ class CatchAllInsertRule extends InsertRule {
Tuple2<Operation?, int?> _getNextNewLine(DeltaIterator iterator) { Tuple2<Operation?, int?> _getNextNewLine(DeltaIterator iterator) {
Operation op; Operation op;
for (int skipped = 0; iterator.hasNext; skipped += op.length!) { for (var skipped = 0; iterator.hasNext; skipped += op.length!) {
op = iterator.next(); op = iterator.next();
int lineBreak = final lineBreak =
(op.data is String ? op.data as String? : '')!.indexOf('\n'); (op.data is String ? op.data as String? : '')!.indexOf('\n');
if (lineBreak >= 0) { if (lineBreak >= 0) {
return Tuple2(op, skipped); return Tuple2(op, skipped);

@ -52,7 +52,7 @@ class Rules {
Delta apply(RuleType ruleType, Document document, int index, Delta apply(RuleType ruleType, Document document, int index,
{int? len, Object? data, Attribute? attribute}) { {int? len, Object? data, Attribute? attribute}) {
final delta = document.toDelta(); final delta = document.toDelta();
for (var rule in _rules) { for (final rule in _rules) {
if (rule.type != ruleType) { if (rule.type != ruleType) {
continue; continue;
} }

@ -118,8 +118,8 @@ Color stringToColor(String? s) {
throw 'Color code not supported'; throw 'Color code not supported';
} }
String hex = s.replaceFirst('#', ''); var hex = s.replaceFirst('#', '');
hex = hex.length == 6 ? 'ff' + hex : hex; hex = hex.length == 6 ? 'ff' + hex : hex;
int val = int.parse(hex, radix: 16); final val = int.parse(hex, radix: 16);
return Color(val); return Color(val);
} }

@ -52,17 +52,17 @@ class Diff {
/* Get diff operation between old text and new text */ /* Get diff operation between old text and new text */
Diff getDiff(String oldText, String newText, int cursorPosition) { Diff getDiff(String oldText, String newText, int cursorPosition) {
int end = oldText.length; var end = oldText.length;
int delta = newText.length - end; final delta = newText.length - end;
for (int limit = math.max(0, cursorPosition - delta); for (final limit = math.max(0, cursorPosition - delta);
end > limit && oldText[end - 1] == newText[end + delta - 1]; end > limit && oldText[end - 1] == newText[end + delta - 1];
end--) {} end--) {}
int start = 0; var start = 0;
for (int startLimit = cursorPosition - math.max(0, delta); for (final startLimit = cursorPosition - math.max(0, delta);
start < startLimit && oldText[start] == newText[start]; start < startLimit && oldText[start] == newText[start];
start++) {} start++) {}
String deleted = (start >= end) ? '' : oldText.substring(start, end); final deleted = (start >= end) ? '' : oldText.substring(start, end);
String inserted = newText.substring(start, end + delta); final inserted = newText.substring(start, end + delta);
return Diff(start, deleted, inserted); return Diff(start, deleted, inserted);
} }
@ -71,13 +71,13 @@ int getPositionDelta(Delta user, Delta actual) {
return 0; return 0;
} }
DeltaIterator userItr = DeltaIterator(user); final userItr = DeltaIterator(user);
DeltaIterator actualItr = DeltaIterator(actual); final actualItr = DeltaIterator(actual);
int diff = 0; var diff = 0;
while (userItr.hasNext || actualItr.hasNext) { while (userItr.hasNext || actualItr.hasNext) {
final length = math.min(userItr.peekLength(), actualItr.peekLength()); final length = math.min(userItr.peekLength(), actualItr.peekLength());
Operation userOperation = userItr.next(length as int); final userOperation = userItr.next(length as int);
Operation actualOperation = actualItr.next(length); final actualOperation = actualItr.next(length);
if (userOperation.length != actualOperation.length) { if (userOperation.length != actualOperation.length) {
throw 'userOp ' + throw 'userOp ' +
userOperation.length.toString() + userOperation.length.toString() +

@ -43,7 +43,7 @@ class QuillController extends ChangeNotifier {
} }
void undo() { void undo() {
Tuple2 tup = document.undo(); final tup = document.undo();
if (tup.item1) { if (tup.item1) {
_handleHistoryChange(tup.item2); _handleHistoryChange(tup.item2);
} }
@ -65,7 +65,7 @@ class QuillController extends ChangeNotifier {
} }
void redo() { void redo() {
Tuple2 tup = document.redo(); final tup = document.redo();
if (tup.item1) { if (tup.item1) {
_handleHistoryChange(tup.item2); _handleHistoryChange(tup.item2);
} }
@ -82,7 +82,7 @@ class QuillController extends ChangeNotifier {
Delta? delta; Delta? delta;
if (len > 0 || data is! String || data.isNotEmpty) { if (len > 0 || data is! String || data.isNotEmpty) {
delta = document.replace(index, len, data); delta = document.replace(index, len, data);
bool shouldRetainDelta = toggledStyle.isNotEmpty && var shouldRetainDelta = toggledStyle.isNotEmpty &&
delta.isNotEmpty && delta.isNotEmpty &&
delta.length <= 2 && delta.length <= 2 &&
delta.last.isInsert; delta.last.isInsert;
@ -98,7 +98,7 @@ class QuillController extends ChangeNotifier {
} }
} }
if (shouldRetainDelta) { if (shouldRetainDelta) {
Delta retainDelta = Delta() final retainDelta = Delta()
..retain(index) ..retain(index)
..retain(data is String ? data.length : 1, toggledStyle.toJson()); ..retain(data is String ? data.length : 1, toggledStyle.toJson());
document.compose(retainDelta, ChangeSource.LOCAL); document.compose(retainDelta, ChangeSource.LOCAL);
@ -110,11 +110,11 @@ class QuillController extends ChangeNotifier {
if (delta == null || delta.isEmpty) { if (delta == null || delta.isEmpty) {
_updateSelection(textSelection, ChangeSource.LOCAL); _updateSelection(textSelection, ChangeSource.LOCAL);
} else { } else {
Delta user = Delta() final user = Delta()
..retain(index) ..retain(index)
..insert(data) ..insert(data)
..delete(len); ..delete(len);
int positionDelta = getPositionDelta(user, delta); final positionDelta = getPositionDelta(user, delta);
_updateSelection( _updateSelection(
textSelection.copyWith( textSelection.copyWith(
baseOffset: textSelection.baseOffset + positionDelta, baseOffset: textSelection.baseOffset + positionDelta,
@ -134,8 +134,8 @@ class QuillController extends ChangeNotifier {
toggledStyle = toggledStyle.put(attribute); toggledStyle = toggledStyle.put(attribute);
} }
Delta change = document.format(index, len, attribute); final change = document.format(index, len, attribute);
TextSelection adjustedSelection = selection.copyWith( final adjustedSelection = selection.copyWith(
baseOffset: change.transformPosition(selection.baseOffset), baseOffset: change.transformPosition(selection.baseOffset),
extentOffset: change.transformPosition(selection.extentOffset)); extentOffset: change.transformPosition(selection.extentOffset));
if (selection != adjustedSelection) { if (selection != adjustedSelection) {
@ -177,7 +177,7 @@ class QuillController extends ChangeNotifier {
void _updateSelection(TextSelection textSelection, ChangeSource source) { void _updateSelection(TextSelection textSelection, ChangeSource source) {
selection = textSelection; selection = textSelection;
int end = document.length - 1; final end = document.length - 1;
selection = selection.copyWith( selection = selection.copyWith(
baseOffset: math.min(selection.baseOffset, end), baseOffset: math.min(selection.baseOffset, end),
extentOffset: math.min(selection.extentOffset, end)); extentOffset: math.min(selection.extentOffset, end));

@ -99,7 +99,7 @@ class CursorCont extends ChangeNotifier {
void _cursorTick(Timer timer) { void _cursorTick(Timer timer) {
_targetCursorVisibility = !_targetCursorVisibility; _targetCursorVisibility = !_targetCursorVisibility;
double targetOpacity = _targetCursorVisibility ? 1.0 : 0.0; final targetOpacity = _targetCursorVisibility ? 1.0 : 0.0;
if (style.opacityAnimates) { if (style.opacityAnimates) {
_blinkOpacityCont.animateTo(targetOpacity, curve: Curves.easeOut); _blinkOpacityCont.animateTo(targetOpacity, curve: Curves.easeOut);
} else { } else {
@ -168,9 +168,9 @@ class CursorPainter {
void paint(Canvas canvas, Offset offset, TextPosition position) { void paint(Canvas canvas, Offset offset, TextPosition position) {
assert(prototype != null); assert(prototype != null);
Offset caretOffset = final caretOffset =
editable!.getOffsetForCaret(position, prototype) + offset; editable!.getOffsetForCaret(position, prototype) + offset;
Rect caretRect = prototype!.shift(caretOffset); var caretRect = prototype!.shift(caretOffset);
if (style.offset != null) { if (style.offset != null) {
caretRect = caretRect.shift(style.offset!); caretRect = caretRect.shift(style.offset!);
} }
@ -179,7 +179,7 @@ class CursorPainter {
caretRect = caretRect.shift(Offset(-caretRect.left, 0.0)); caretRect = caretRect.shift(Offset(-caretRect.left, 0.0));
} }
double? caretHeight = editable!.getFullHeightForCaret(position); final caretHeight = editable!.getFullHeightForCaret(position);
if (caretHeight != null) { if (caretHeight != null) {
switch (defaultTargetPlatform) { switch (defaultTargetPlatform) {
case TargetPlatform.android: case TargetPlatform.android:
@ -207,8 +207,8 @@ class CursorPainter {
} }
} }
Offset caretPosition = editable!.localToGlobal(caretRect.topLeft); final caretPosition = editable!.localToGlobal(caretRect.topLeft);
double pixelMultiple = 1.0 / devicePixelRatio; final pixelMultiple = 1.0 / devicePixelRatio;
caretRect = caretRect.shift(Offset( caretRect = caretRect.shift(Offset(
caretPosition.dx.isFinite caretPosition.dx.isFinite
? (caretPosition.dx / pixelMultiple).round() * pixelMultiple - ? (caretPosition.dx / pixelMultiple).round() * pixelMultiple -
@ -219,13 +219,13 @@ class CursorPainter {
caretPosition.dy caretPosition.dy
: caretPosition.dy)); : caretPosition.dy));
Paint paint = Paint()..color = color; final paint = Paint()..color = color;
if (style.radius == null) { if (style.radius == null) {
canvas.drawRect(caretRect, paint); canvas.drawRect(caretRect, paint);
return; return;
} }
RRect caretRRect = RRect.fromRectAndRadius(caretRect, style.radius!); final caretRRect = RRect.fromRectAndRadius(caretRect, style.radius!);
canvas.drawRRect(caretRRect, paint); canvas.drawRRect(caretRRect, paint);
} }
} }

@ -17,7 +17,7 @@ class QuillStyles extends InheritedWidget {
} }
static DefaultStyles? getStyles(BuildContext context, bool nullOk) { static DefaultStyles? getStyles(BuildContext context, bool nullOk) {
var widget = context.dependOnInheritedWidgetOfExactType<QuillStyles>(); final widget = context.dependOnInheritedWidgetOfExactType<QuillStyles>();
if (widget == null && nullOk) { if (widget == null && nullOk) {
return null; return null;
} }
@ -84,13 +84,13 @@ class DefaultStyles {
this.sizeHuge}); this.sizeHuge});
static DefaultStyles getInstance(BuildContext context) { static DefaultStyles getInstance(BuildContext context) {
ThemeData themeData = Theme.of(context); final themeData = Theme.of(context);
DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context); final defaultTextStyle = DefaultTextStyle.of(context);
TextStyle baseStyle = defaultTextStyle.style.copyWith( final baseStyle = defaultTextStyle.style.copyWith(
fontSize: 16.0, fontSize: 16.0,
height: 1.3, height: 1.3,
); );
Tuple2<double, double> baseSpacing = const Tuple2(6.0, 0); final baseSpacing = const Tuple2<double, double>(6.0, 0);
String fontFamily; String fontFamily;
switch (themeData.platform) { switch (themeData.platform) {
case TargetPlatform.iOS: case TargetPlatform.iOS:

@ -34,7 +34,7 @@ class EditorTextSelectionGestureDetectorBuilder {
void onTapDown(TapDownDetails details) { void onTapDown(TapDownDetails details) {
getRenderEditor()!.handleTapDown(details); getRenderEditor()!.handleTapDown(details);
PointerDeviceKind? kind = details.kind; final kind = details.kind;
shouldShowSelectionToolbar = kind == null || shouldShowSelectionToolbar = kind == null ||
kind == PointerDeviceKind.touch || kind == PointerDeviceKind.touch ||
kind == PointerDeviceKind.stylus; kind == PointerDeviceKind.stylus;

@ -17,7 +17,6 @@ import '../models/documents/nodes/container.dart' as container_node;
import '../models/documents/nodes/embed.dart'; import '../models/documents/nodes/embed.dart';
import '../models/documents/nodes/leaf.dart' as leaf; import '../models/documents/nodes/leaf.dart' as leaf;
import '../models/documents/nodes/line.dart'; import '../models/documents/nodes/line.dart';
import '../models/documents/nodes/node.dart';
import 'box.dart'; import 'box.dart';
import 'controller.dart'; import 'controller.dart';
import 'cursor.dart'; import 'cursor.dart';
@ -100,7 +99,7 @@ Widget _defaultEmbedBuilder(BuildContext context, leaf.Embed node) {
assert(!kIsWeb, 'Please provide EmbedBuilder for Web'); assert(!kIsWeb, 'Please provide EmbedBuilder for Web');
switch (node.value.type) { switch (node.value.type) {
case 'image': case 'image':
String imageUrl = _standardizeImageUrl(node.value.data); final imageUrl = _standardizeImageUrl(node.value.data);
return imageUrl.startsWith('http') return imageUrl.startsWith('http')
? Image.network(imageUrl) ? Image.network(imageUrl)
: isBase64(imageUrl) : isBase64(imageUrl)
@ -188,8 +187,8 @@ class _QuillEditorState extends State<QuillEditor>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
ThemeData theme = Theme.of(context); final theme = Theme.of(context);
TextSelectionThemeData selectionTheme = TextSelectionTheme.of(context); final selectionTheme = TextSelectionTheme.of(context);
TextSelectionControls textSelectionControls; TextSelectionControls textSelectionControls;
bool paintCursorAboveText; bool paintCursorAboveText;
@ -213,7 +212,7 @@ class _QuillEditorState extends State<QuillEditor>
break; break;
case TargetPlatform.iOS: case TargetPlatform.iOS:
case TargetPlatform.macOS: case TargetPlatform.macOS:
CupertinoThemeData cupertinoTheme = CupertinoTheme.of(context); final cupertinoTheme = CupertinoTheme.of(context);
textSelectionControls = cupertinoTextSelectionControls; textSelectionControls = cupertinoTextSelectionControls;
paintCursorAboveText = true; paintCursorAboveText = true;
cursorOpacityAnimates = true; cursorOpacityAnimates = true;
@ -344,16 +343,14 @@ class _QuillEditorSelectionGestureDetectorBuilder
if (_state.widget.controller.document.isEmpty()) { if (_state.widget.controller.document.isEmpty()) {
return false; return false;
} }
TextPosition pos = final pos = getRenderEditor()!.getPositionForOffset(details.globalPosition);
getRenderEditor()!.getPositionForOffset(details.globalPosition); final result =
container_node.ChildQuery result =
getEditor()!.widget.controller.document.queryChild(pos.offset); getEditor()!.widget.controller.document.queryChild(pos.offset);
if (result.node == null) { if (result.node == null) {
return false; return false;
} }
Line line = result.node as Line; final line = result.node as Line;
container_node.ChildQuery segmentResult = final segmentResult = line.queryChild(result.offset, false);
line.queryChild(result.offset, false);
if (segmentResult.node == null) { if (segmentResult.node == null) {
if (line.length == 1) { if (line.length == 1) {
// tapping when no text yet on this line // tapping when no text yet on this line
@ -364,7 +361,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
} }
return false; return false;
} }
leaf.Leaf segment = segmentResult.node as leaf.Leaf; final segment = segmentResult.node as leaf.Leaf;
if (segment.style.containsKey(Attribute.link.key)) { if (segment.style.containsKey(Attribute.link.key)) {
var launchUrl = getEditor()!.widget.onLaunchUrl; var launchUrl = getEditor()!.widget.onLaunchUrl;
launchUrl ??= _launchUrl; launchUrl ??= _launchUrl;
@ -380,9 +377,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
return false; return false;
} }
if (getEditor()!.widget.readOnly && segment.value is BlockEmbed) { if (getEditor()!.widget.readOnly && segment.value is BlockEmbed) {
BlockEmbed blockEmbed = segment.value as BlockEmbed; final blockEmbed = segment.value as BlockEmbed;
if (blockEmbed.type == 'image') { if (blockEmbed.type == 'image') {
final String imageUrl = _standardizeImageUrl(blockEmbed.data); final imageUrl = _standardizeImageUrl(blockEmbed.data);
Navigator.push( Navigator.push(
getEditor()!.context, getEditor()!.context,
MaterialPageRoute( MaterialPageRoute(
@ -413,7 +410,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
return false; return false;
} }
// segmentResult.offset == 0 means tap at the beginning of the TextLine // segmentResult.offset == 0 means tap at the beginning of the TextLine
String? listVal = line.style.attributes[Attribute.list.key]!.value; final String? listVal = line.style.attributes[Attribute.list.key]!.value;
if (listVal == Attribute.unchecked.value) { if (listVal == Attribute.unchecked.value) {
getEditor()! getEditor()!
.widget .widget
@ -438,7 +435,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
void onSingleTapUp(TapUpDetails details) { void onSingleTapUp(TapUpDetails details) {
getEditor()!.hideToolbar(); getEditor()!.hideToolbar();
bool positionSelected = _onTapping(details); final positionSelected = _onTapping(details);
if (delegate.getSelectionEnabled() && !positionSelected) { if (delegate.getSelectionEnabled() && !positionSelected) {
switch (Theme.of(_state.context).platform) { switch (Theme.of(_state.context).platform) {
@ -575,12 +572,12 @@ class RenderEditor extends RenderEditableContainerBox
List<TextSelectionPoint> getEndpointsForSelection( List<TextSelectionPoint> getEndpointsForSelection(
TextSelection textSelection) { TextSelection textSelection) {
if (textSelection.isCollapsed) { if (textSelection.isCollapsed) {
RenderEditableBox child = childAtPosition(textSelection.extent); final child = childAtPosition(textSelection.extent);
TextPosition localPosition = TextPosition( final localPosition = TextPosition(
offset: offset:
textSelection.extentOffset - child.getContainer().getOffset()); textSelection.extentOffset - child.getContainer().getOffset());
Offset localOffset = child.getOffsetForCaret(localPosition); final localOffset = child.getOffsetForCaret(localPosition);
BoxParentData parentData = child.parentData as BoxParentData; final parentData = child.parentData as BoxParentData;
return <TextSelectionPoint>[ return <TextSelectionPoint>[
TextSelectionPoint( TextSelectionPoint(
Offset(0.0, child.preferredLineHeight(localPosition)) + Offset(0.0, child.preferredLineHeight(localPosition)) +
@ -590,7 +587,7 @@ class RenderEditor extends RenderEditableContainerBox
]; ];
} }
Node? baseNode = _container.queryChild(textSelection.start, false).node; final baseNode = _container.queryChild(textSelection.start, false).node;
var baseChild = firstChild; var baseChild = firstChild;
while (baseChild != null) { while (baseChild != null) {
@ -601,15 +598,14 @@ class RenderEditor extends RenderEditableContainerBox
} }
assert(baseChild != null); assert(baseChild != null);
BoxParentData baseParentData = baseChild!.parentData as BoxParentData; final baseParentData = baseChild!.parentData as BoxParentData;
TextSelection baseSelection = final baseSelection =
localSelection(baseChild.getContainer(), textSelection, true); localSelection(baseChild.getContainer(), textSelection, true);
TextSelectionPoint basePoint = var basePoint = baseChild.getBaseEndpointForSelection(baseSelection);
baseChild.getBaseEndpointForSelection(baseSelection);
basePoint = TextSelectionPoint( basePoint = TextSelectionPoint(
basePoint.point + baseParentData.offset, basePoint.direction); basePoint.point + baseParentData.offset, basePoint.direction);
Node? extentNode = _container.queryChild(textSelection.end, false).node; final extentNode = _container.queryChild(textSelection.end, false).node;
RenderEditableBox? extentChild = baseChild; RenderEditableBox? extentChild = baseChild;
while (extentChild != null) { while (extentChild != null) {
if (extentChild.getContainer() == extentNode) { if (extentChild.getContainer() == extentNode) {
@ -619,10 +615,10 @@ class RenderEditor extends RenderEditableContainerBox
} }
assert(extentChild != null); assert(extentChild != null);
BoxParentData extentParentData = extentChild!.parentData as BoxParentData; final extentParentData = extentChild!.parentData as BoxParentData;
TextSelection extentSelection = final extentSelection =
localSelection(extentChild.getContainer(), textSelection, true); localSelection(extentChild.getContainer(), textSelection, true);
TextSelectionPoint extentPoint = var extentPoint =
extentChild.getExtentEndpointForSelection(extentSelection); extentChild.getExtentEndpointForSelection(extentSelection);
extentPoint = TextSelectionPoint( extentPoint = TextSelectionPoint(
extentPoint.point + extentParentData.offset, extentPoint.direction); extentPoint.point + extentParentData.offset, extentPoint.direction);
@ -643,9 +639,9 @@ class RenderEditor extends RenderEditableContainerBox
Offset? to, Offset? to,
SelectionChangedCause cause, SelectionChangedCause cause,
) { ) {
TextPosition firstPosition = getPositionForOffset(from); final firstPosition = getPositionForOffset(from);
TextSelection firstWord = selectWordAtPosition(firstPosition); final firstWord = selectWordAtPosition(firstPosition);
TextSelection lastWord = final lastWord =
to == null ? firstWord : selectWordAtPosition(getPositionForOffset(to)); to == null ? firstWord : selectWordAtPosition(getPositionForOffset(to));
_handleSelectionChange( _handleSelectionChange(
@ -662,7 +658,7 @@ class RenderEditor extends RenderEditableContainerBox
TextSelection nextSelection, TextSelection nextSelection,
SelectionChangedCause cause, SelectionChangedCause cause,
) { ) {
bool focusingEmpty = nextSelection.baseOffset == 0 && final focusingEmpty = nextSelection.baseOffset == 0 &&
nextSelection.extentOffset == 0 && nextSelection.extentOffset == 0 &&
!_hasFocus; !_hasFocus;
if (nextSelection == selection && if (nextSelection == selection &&
@ -676,15 +672,15 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
void selectWordEdge(SelectionChangedCause cause) { void selectWordEdge(SelectionChangedCause cause) {
assert(_lastTapDownPosition != null); assert(_lastTapDownPosition != null);
TextPosition position = getPositionForOffset(_lastTapDownPosition!); final position = getPositionForOffset(_lastTapDownPosition!);
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
int nodeOffset = child.getContainer().getOffset(); final nodeOffset = child.getContainer().getOffset();
TextPosition localPosition = TextPosition( final localPosition = TextPosition(
offset: position.offset - nodeOffset, offset: position.offset - nodeOffset,
affinity: position.affinity, affinity: position.affinity,
); );
TextRange localWord = child.getWordBoundary(localPosition); final localWord = child.getWordBoundary(localPosition);
TextRange word = TextRange( final word = TextRange(
start: localWord.start + nodeOffset, start: localWord.start + nodeOffset,
end: localWord.end + nodeOffset, end: localWord.end + nodeOffset,
); );
@ -708,17 +704,17 @@ class RenderEditor extends RenderEditableContainerBox
Offset? to, Offset? to,
SelectionChangedCause cause, SelectionChangedCause cause,
) { ) {
TextPosition fromPosition = getPositionForOffset(from); final fromPosition = getPositionForOffset(from);
TextPosition? toPosition = to == null ? null : getPositionForOffset(to); final toPosition = to == null ? null : getPositionForOffset(to);
int baseOffset = fromPosition.offset; var baseOffset = fromPosition.offset;
int extentOffset = fromPosition.offset; var extentOffset = fromPosition.offset;
if (toPosition != null) { if (toPosition != null) {
baseOffset = math.min(fromPosition.offset, toPosition.offset); baseOffset = math.min(fromPosition.offset, toPosition.offset);
extentOffset = math.max(fromPosition.offset, toPosition.offset); extentOffset = math.max(fromPosition.offset, toPosition.offset);
} }
TextSelection newSelection = TextSelection( final newSelection = TextSelection(
baseOffset: baseOffset, baseOffset: baseOffset,
extentOffset: extentOffset, extentOffset: extentOffset,
affinity: fromPosition.affinity, affinity: fromPosition.affinity,
@ -738,12 +734,12 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
TextSelection selectWordAtPosition(TextPosition position) { TextSelection selectWordAtPosition(TextPosition position) {
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
int nodeOffset = child.getContainer().getOffset(); final nodeOffset = child.getContainer().getOffset();
TextPosition localPosition = TextPosition( final localPosition = TextPosition(
offset: position.offset - nodeOffset, affinity: position.affinity); offset: position.offset - nodeOffset, affinity: position.affinity);
TextRange localWord = child.getWordBoundary(localPosition); final localWord = child.getWordBoundary(localPosition);
TextRange word = TextRange( final word = TextRange(
start: localWord.start + nodeOffset, start: localWord.start + nodeOffset,
end: localWord.end + nodeOffset, end: localWord.end + nodeOffset,
); );
@ -755,12 +751,12 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
TextSelection selectLineAtPosition(TextPosition position) { TextSelection selectLineAtPosition(TextPosition position) {
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
int nodeOffset = child.getContainer().getOffset(); final nodeOffset = child.getContainer().getOffset();
TextPosition localPosition = TextPosition( final localPosition = TextPosition(
offset: position.offset - nodeOffset, affinity: position.affinity); offset: position.offset - nodeOffset, affinity: position.affinity);
TextRange localLineRange = child.getLineBoundary(localPosition); final localLineRange = child.getLineBoundary(localPosition);
TextRange line = TextRange( final line = TextRange(
start: localLineRange.start + nodeOffset, start: localLineRange.start + nodeOffset,
end: localLineRange.end + nodeOffset, end: localLineRange.end + nodeOffset,
); );
@ -810,19 +806,19 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
double preferredLineHeight(TextPosition position) { double preferredLineHeight(TextPosition position) {
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
return child.preferredLineHeight(TextPosition( return child.preferredLineHeight(TextPosition(
offset: position.offset - child.getContainer().getOffset())); offset: position.offset - child.getContainer().getOffset()));
} }
@override @override
TextPosition getPositionForOffset(Offset offset) { TextPosition getPositionForOffset(Offset offset) {
Offset local = globalToLocal(offset); final local = globalToLocal(offset);
RenderEditableBox child = childAtOffset(local)!; final child = childAtOffset(local)!;
BoxParentData parentData = child.parentData as BoxParentData; final parentData = child.parentData as BoxParentData;
Offset localOffset = local - parentData.offset; final localOffset = local - parentData.offset;
TextPosition localPosition = child.getPositionForOffset(localOffset); final localPosition = child.getPositionForOffset(localOffset);
return TextPosition( return TextPosition(
offset: localPosition.offset + child.getContainer().getOffset(), offset: localPosition.offset + child.getContainer().getOffset(),
affinity: localPosition.affinity, affinity: localPosition.affinity,
@ -836,12 +832,12 @@ class RenderEditor extends RenderEditableContainerBox
/// Returns null if [selection] is already visible. /// Returns null if [selection] is already visible.
double? getOffsetToRevealCursor( double? getOffsetToRevealCursor(
double viewportHeight, double scrollOffset, double offsetInViewport) { double viewportHeight, double scrollOffset, double offsetInViewport) {
List<TextSelectionPoint> endpoints = getEndpointsForSelection(selection); final endpoints = getEndpointsForSelection(selection);
TextSelectionPoint endpoint = endpoints.first; final endpoint = endpoints.first;
RenderEditableBox child = childAtPosition(selection.extent); final child = childAtPosition(selection.extent);
const kMargin = 8.0; const kMargin = 8.0;
double caretTop = endpoint.point.dy - final caretTop = endpoint.point.dy -
child.preferredLineHeight(TextPosition( child.preferredLineHeight(TextPosition(
offset: offset:
selection.extentOffset - child.getContainer().getOffset())) - selection.extentOffset - child.getContainer().getOffset())) -
@ -919,7 +915,7 @@ class RenderEditableContainerBox extends RenderBox
RenderEditableBox childAtPosition(TextPosition position) { RenderEditableBox childAtPosition(TextPosition position) {
assert(firstChild != null); assert(firstChild != null);
Node? targetNode = _container.queryChild(position.offset, false).node; final targetNode = _container.queryChild(position.offset, false).node;
var targetChild = firstChild; var targetChild = firstChild;
while (targetChild != null) { while (targetChild != null) {
@ -951,7 +947,8 @@ class RenderEditableContainerBox extends RenderBox
} }
var child = firstChild; var child = firstChild;
double dx = -offset.dx, dy = _resolvedPadding!.top; final dx = -offset.dx;
var dy = _resolvedPadding!.top;
while (child != null) { while (child != null) {
if (child.size.contains(offset.translate(dx, -dy))) { if (child.size.contains(offset.translate(dx, -dy))) {
return child; return child;
@ -978,15 +975,14 @@ class RenderEditableContainerBox extends RenderBox
_resolvePadding(); _resolvePadding();
assert(_resolvedPadding != null); assert(_resolvedPadding != null);
double mainAxisExtent = _resolvedPadding!.top; var mainAxisExtent = _resolvedPadding!.top;
var child = firstChild; var child = firstChild;
BoxConstraints innerConstraints = final innerConstraints =
BoxConstraints.tightFor(width: constraints.maxWidth) BoxConstraints.tightFor(width: constraints.maxWidth)
.deflate(_resolvedPadding!); .deflate(_resolvedPadding!);
while (child != null) { while (child != null) {
child.layout(innerConstraints, parentUsesSize: true); child.layout(innerConstraints, parentUsesSize: true);
final EditableContainerParentData childParentData = final childParentData = child.parentData as EditableContainerParentData;
child.parentData as EditableContainerParentData;
childParentData.offset = Offset(_resolvedPadding!.left, mainAxisExtent); childParentData.offset = Offset(_resolvedPadding!.left, mainAxisExtent);
mainAxisExtent += child.size.height; mainAxisExtent += child.size.height;
assert(child.parentData == childParentData); assert(child.parentData == childParentData);
@ -999,24 +995,22 @@ class RenderEditableContainerBox extends RenderBox
} }
double _getIntrinsicCrossAxis(double Function(RenderBox child) childSize) { double _getIntrinsicCrossAxis(double Function(RenderBox child) childSize) {
double extent = 0.0; var extent = 0.0;
var child = firstChild; var child = firstChild;
while (child != null) { while (child != null) {
extent = math.max(extent, childSize(child)); extent = math.max(extent, childSize(child));
EditableContainerParentData childParentData = final childParentData = child.parentData as EditableContainerParentData;
child.parentData as EditableContainerParentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
return extent; return extent;
} }
double _getIntrinsicMainAxis(double Function(RenderBox child) childSize) { double _getIntrinsicMainAxis(double Function(RenderBox child) childSize) {
double extent = 0.0; var extent = 0.0;
var child = firstChild; var child = firstChild;
while (child != null) { while (child != null) {
extent += childSize(child); extent += childSize(child);
EditableContainerParentData childParentData = final childParentData = child.parentData as EditableContainerParentData;
child.parentData as EditableContainerParentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
return extent; return extent;
@ -1026,7 +1020,7 @@ class RenderEditableContainerBox extends RenderBox
double computeMinIntrinsicWidth(double height) { double computeMinIntrinsicWidth(double height) {
_resolvePadding(); _resolvePadding();
return _getIntrinsicCrossAxis((RenderBox child) { return _getIntrinsicCrossAxis((RenderBox child) {
double childHeight = math.max( final childHeight = math.max(
0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom);
return child.getMinIntrinsicWidth(childHeight) + return child.getMinIntrinsicWidth(childHeight) +
_resolvedPadding!.left + _resolvedPadding!.left +
@ -1038,7 +1032,7 @@ class RenderEditableContainerBox extends RenderBox
double computeMaxIntrinsicWidth(double height) { double computeMaxIntrinsicWidth(double height) {
_resolvePadding(); _resolvePadding();
return _getIntrinsicCrossAxis((RenderBox child) { return _getIntrinsicCrossAxis((RenderBox child) {
double childHeight = math.max( final childHeight = math.max(
0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom);
return child.getMaxIntrinsicWidth(childHeight) + return child.getMaxIntrinsicWidth(childHeight) +
_resolvedPadding!.left + _resolvedPadding!.left +
@ -1050,7 +1044,7 @@ class RenderEditableContainerBox extends RenderBox
double computeMinIntrinsicHeight(double width) { double computeMinIntrinsicHeight(double width) {
_resolvePadding(); _resolvePadding();
return _getIntrinsicMainAxis((RenderBox child) { return _getIntrinsicMainAxis((RenderBox child) {
double childWidth = math.max( final childWidth = math.max(
0.0, width - _resolvedPadding!.left + _resolvedPadding!.right); 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right);
return child.getMinIntrinsicHeight(childWidth) + return child.getMinIntrinsicHeight(childWidth) +
_resolvedPadding!.top + _resolvedPadding!.top +

@ -71,10 +71,10 @@ class KeyboardListener {
return false; return false;
} }
Set<LogicalKeyboardKey> keysPressed = final keysPressed =
LogicalKeyboardKey.collapseSynonyms(RawKeyboard.instance.keysPressed); LogicalKeyboardKey.collapseSynonyms(RawKeyboard.instance.keysPressed);
LogicalKeyboardKey key = event.logicalKey; final key = event.logicalKey;
bool isMacOS = event.data is RawKeyEventDataMacOs; final isMacOS = event.data is RawKeyEventDataMacOs;
if (!_nonModifierKeys.contains(key) || if (!_nonModifierKeys.contains(key) ||
keysPressed keysPressed
.difference(isMacOS ? _macOsModifierKeys : _modifierKeys) .difference(isMacOS ? _macOsModifierKeys : _modifierKeys)

@ -91,8 +91,8 @@ class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox {
]; ];
} }
double left = selection.extentOffset == 0 ? 0.0 : size.width; final left = selection.extentOffset == 0 ? 0.0 : size.width;
double right = selection.extentOffset == 0 ? 0.0 : size.width; final right = selection.extentOffset == 0 ? 0.0 : size.width;
return <TextBox>[ return <TextBox>[
TextBox.fromLTRBD(left, 0.0, right, size.height, TextDirection.ltr) TextBox.fromLTRBD(left, 0.0, right, size.height, TextDirection.ltr)
]; ];

@ -15,9 +15,7 @@ import '../models/documents/attribute.dart';
import '../models/documents/document.dart'; import '../models/documents/document.dart';
import '../models/documents/nodes/block.dart'; import '../models/documents/nodes/block.dart';
import '../models/documents/nodes/line.dart'; import '../models/documents/nodes/line.dart';
import '../models/documents/nodes/node.dart';
import '../utils/diff_delta.dart'; import '../utils/diff_delta.dart';
import 'box.dart';
import 'controller.dart'; import 'controller.dart';
import 'cursor.dart'; import 'cursor.dart';
import 'default_styles.dart'; import 'default_styles.dart';
@ -140,7 +138,7 @@ class RawEditorState extends EditorState
bool get _hasFocus => widget.focusNode.hasFocus; bool get _hasFocus => widget.focusNode.hasFocus;
TextDirection get _textDirection { TextDirection get _textDirection {
TextDirection result = Directionality.of(context); final result = Directionality.of(context);
return result; return result;
} }
@ -153,13 +151,13 @@ class RawEditorState extends EditorState
if (wordModifier && lineModifier) { if (wordModifier && lineModifier) {
return; return;
} }
TextSelection selection = widget.controller.selection; final selection = widget.controller.selection;
TextSelection newSelection = widget.controller.selection; var newSelection = widget.controller.selection;
String plainText = textEditingValue.text; final plainText = textEditingValue.text;
bool rightKey = key == LogicalKeyboardKey.arrowRight, final rightKey = key == LogicalKeyboardKey.arrowRight,
leftKey = key == LogicalKeyboardKey.arrowLeft, leftKey = key == LogicalKeyboardKey.arrowLeft,
upKey = key == LogicalKeyboardKey.arrowUp, upKey = key == LogicalKeyboardKey.arrowUp,
downKey = key == LogicalKeyboardKey.arrowDown; downKey = key == LogicalKeyboardKey.arrowDown;
@ -184,7 +182,7 @@ class RawEditorState extends EditorState
TextSelection _placeCollapsedSelection(TextSelection selection, TextSelection _placeCollapsedSelection(TextSelection selection,
TextSelection newSelection, bool leftKey, bool rightKey) { TextSelection newSelection, bool leftKey, bool rightKey) {
int newOffset = newSelection.extentOffset; var newOffset = newSelection.extentOffset;
if (!selection.isCollapsed) { if (!selection.isCollapsed) {
if (leftKey) { if (leftKey) {
newOffset = newSelection.baseOffset < newSelection.extentOffset newOffset = newSelection.baseOffset < newSelection.extentOffset
@ -206,34 +204,32 @@ class RawEditorState extends EditorState
TextSelection selection, TextSelection selection,
TextSelection newSelection, TextSelection newSelection,
String plainText) { String plainText) {
TextPosition originPosition = TextPosition( final originPosition = TextPosition(
offset: upKey ? selection.baseOffset : selection.extentOffset); offset: upKey ? selection.baseOffset : selection.extentOffset);
RenderEditableBox child = final child = getRenderEditor()!.childAtPosition(originPosition);
getRenderEditor()!.childAtPosition(originPosition); final localPosition = TextPosition(
TextPosition localPosition = TextPosition(
offset: offset:
originPosition.offset - child.getContainer().getDocumentOffset()); originPosition.offset - child.getContainer().getDocumentOffset());
TextPosition? position = upKey var position = upKey
? child.getPositionAbove(localPosition) ? child.getPositionAbove(localPosition)
: child.getPositionBelow(localPosition); : child.getPositionBelow(localPosition);
if (position == null) { if (position == null) {
var sibling = upKey final sibling = upKey
? getRenderEditor()!.childBefore(child) ? getRenderEditor()!.childBefore(child)
: getRenderEditor()!.childAfter(child); : getRenderEditor()!.childAfter(child);
if (sibling == null) { if (sibling == null) {
position = TextPosition(offset: upKey ? 0 : plainText.length - 1); position = TextPosition(offset: upKey ? 0 : plainText.length - 1);
} else { } else {
Offset finalOffset = Offset( final finalOffset = Offset(
child.getOffsetForCaret(localPosition).dx, child.getOffsetForCaret(localPosition).dx,
sibling sibling
.getOffsetForCaret(TextPosition( .getOffsetForCaret(TextPosition(
offset: upKey ? sibling.getContainer().length - 1 : 0)) offset: upKey ? sibling.getContainer().length - 1 : 0))
.dy); .dy);
TextPosition siblingPosition = final siblingPosition = sibling.getPositionForOffset(finalOffset);
sibling.getPositionForOffset(finalOffset);
position = TextPosition( position = TextPosition(
offset: sibling.getContainer().getDocumentOffset() + offset: sibling.getContainer().getDocumentOffset() +
siblingPosition.offset); siblingPosition.offset);
@ -273,28 +269,28 @@ class RawEditorState extends EditorState
bool shift) { bool shift) {
if (wordModifier) { if (wordModifier) {
if (leftKey) { if (leftKey) {
TextSelection textSelection = getRenderEditor()!.selectWordAtPosition( final textSelection = getRenderEditor()!.selectWordAtPosition(
TextPosition( TextPosition(
offset: _previousCharacter( offset: _previousCharacter(
newSelection.extentOffset, plainText, false))); newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.baseOffset); return newSelection.copyWith(extentOffset: textSelection.baseOffset);
} }
TextSelection textSelection = getRenderEditor()!.selectWordAtPosition( final textSelection = getRenderEditor()!.selectWordAtPosition(
TextPosition( TextPosition(
offset: offset:
_nextCharacter(newSelection.extentOffset, plainText, false))); _nextCharacter(newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.extentOffset); return newSelection.copyWith(extentOffset: textSelection.extentOffset);
} else if (lineModifier) { } else if (lineModifier) {
if (leftKey) { if (leftKey) {
TextSelection textSelection = getRenderEditor()!.selectLineAtPosition( final textSelection = getRenderEditor()!.selectLineAtPosition(
TextPosition( TextPosition(
offset: _previousCharacter( offset: _previousCharacter(
newSelection.extentOffset, plainText, false))); newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.baseOffset); return newSelection.copyWith(extentOffset: textSelection.baseOffset);
} }
int startPoint = newSelection.extentOffset; final startPoint = newSelection.extentOffset;
if (startPoint < plainText.length) { if (startPoint < plainText.length) {
TextSelection textSelection = getRenderEditor()! final textSelection = getRenderEditor()!
.selectLineAtPosition(TextPosition(offset: startPoint)); .selectLineAtPosition(TextPosition(offset: startPoint));
return newSelection.copyWith(extentOffset: textSelection.extentOffset); return newSelection.copyWith(extentOffset: textSelection.extentOffset);
} }
@ -302,9 +298,9 @@ class RawEditorState extends EditorState
} }
if (rightKey && newSelection.extentOffset < plainText.length) { if (rightKey && newSelection.extentOffset < plainText.length) {
int nextExtent = final nextExtent =
_nextCharacter(newSelection.extentOffset, plainText, true); _nextCharacter(newSelection.extentOffset, plainText, true);
int distance = nextExtent - newSelection.extentOffset; final distance = nextExtent - newSelection.extentOffset;
newSelection = newSelection.copyWith(extentOffset: nextExtent); newSelection = newSelection.copyWith(extentOffset: nextExtent);
if (shift) { if (shift) {
_cursorResetLocation += distance; _cursorResetLocation += distance;
@ -313,9 +309,9 @@ class RawEditorState extends EditorState
} }
if (leftKey && newSelection.extentOffset > 0) { if (leftKey && newSelection.extentOffset > 0) {
int previousExtent = final previousExtent =
_previousCharacter(newSelection.extentOffset, plainText, true); _previousCharacter(newSelection.extentOffset, plainText, true);
int distance = newSelection.extentOffset - previousExtent; final distance = newSelection.extentOffset - previousExtent;
newSelection = newSelection.copyWith(extentOffset: previousExtent); newSelection = newSelection.copyWith(extentOffset: previousExtent);
if (shift) { if (shift) {
_cursorResetLocation -= distance; _cursorResetLocation -= distance;
@ -331,8 +327,8 @@ class RawEditorState extends EditorState
return string.length; return string.length;
} }
int count = 0; var count = 0;
Characters remain = string.characters.skipWhile((String currentString) { final remain = string.characters.skipWhile((String currentString) {
if (count <= index) { if (count <= index) {
count += currentString.length; count += currentString.length;
return true; return true;
@ -351,9 +347,9 @@ class RawEditorState extends EditorState
return 0; return 0;
} }
int count = 0; var count = 0;
int? lastNonWhitespace; int? lastNonWhitespace;
for (String currentString in string.characters) { for (final currentString in string.characters) {
if (!includeWhitespace && if (!includeWhitespace &&
!WHITE_SPACE.contains( !WHITE_SPACE.contains(
currentString.characters.first.toString().codeUnitAt(0))) { currentString.characters.first.toString().codeUnitAt(0))) {
@ -411,7 +407,7 @@ class RawEditorState extends EditorState
return; return;
} }
TextEditingValue actualValue = textEditingValue.copyWith( final actualValue = textEditingValue.copyWith(
composing: _lastKnownRemoteTextEditingValue!.composing, composing: _lastKnownRemoteTextEditingValue!.composing,
); );
@ -419,7 +415,7 @@ class RawEditorState extends EditorState
return; return;
} }
bool shouldRemember = final shouldRemember =
textEditingValue.text != _lastKnownRemoteTextEditingValue!.text; textEditingValue.text != _lastKnownRemoteTextEditingValue!.text;
_lastKnownRemoteTextEditingValue = actualValue; _lastKnownRemoteTextEditingValue = actualValue;
_textInputConnection!.setEditingState(actualValue); _textInputConnection!.setEditingState(actualValue);
@ -456,13 +452,12 @@ class RawEditorState extends EditorState
return; return;
} }
TextEditingValue effectiveLastKnownValue = final effectiveLastKnownValue = _lastKnownRemoteTextEditingValue!;
_lastKnownRemoteTextEditingValue!;
_lastKnownRemoteTextEditingValue = value; _lastKnownRemoteTextEditingValue = value;
String oldText = effectiveLastKnownValue.text; final oldText = effectiveLastKnownValue.text;
String text = value.text; final text = value.text;
int cursorPosition = value.selection.extentOffset; final cursorPosition = value.selection.extentOffset;
Diff diff = getDiff(oldText, text, cursorPosition); final diff = getDiff(oldText, text, cursorPosition);
widget.controller.replaceText( widget.controller.replaceText(
diff.start, diff.deleted.length, diff.inserted, value.selection); diff.start, diff.deleted.length, diff.inserted, value.selection);
} }
@ -513,7 +508,7 @@ class RawEditorState extends EditorState
_focusAttachment!.reparent(); _focusAttachment!.reparent();
super.build(context); super.build(context);
Document _doc = widget.controller.document; var _doc = widget.controller.document;
if (_doc.isEmpty() && if (_doc.isEmpty() &&
!widget.focusNode.hasFocus && !widget.focusNode.hasFocus &&
widget.placeholder != null) { widget.placeholder != null) {
@ -540,7 +535,7 @@ class RawEditorState extends EditorState
); );
if (widget.scrollable) { if (widget.scrollable) {
EdgeInsets baselinePadding = final baselinePadding =
EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1); EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1);
child = BaselineProxy( child = BaselineProxy(
textStyle: _styles!.paragraph!.style, textStyle: _styles!.paragraph!.style,
@ -553,7 +548,7 @@ class RawEditorState extends EditorState
); );
} }
BoxConstraints constraints = widget.expands final constraints = widget.expands
? const BoxConstraints.expand() ? const BoxConstraints.expand()
: BoxConstraints( : BoxConstraints(
minHeight: widget.minHeight ?? 0.0, minHeight: widget.minHeight ?? 0.0,
@ -584,15 +579,14 @@ class RawEditorState extends EditorState
List<Widget> _buildChildren(Document doc, BuildContext context) { List<Widget> _buildChildren(Document doc, BuildContext context) {
final result = <Widget>[]; final result = <Widget>[];
Map<int, int> indentLevelCounts = {}; final indentLevelCounts = <int, int>{};
for (Node node in doc.root.children) { for (final node in doc.root.children) {
if (node is Line) { if (node is Line) {
EditableTextLine editableTextLine = final editableTextLine = _getEditableTextLineFromNode(node, context);
_getEditableTextLineFromNode(node, context);
result.add(editableTextLine); result.add(editableTextLine);
} else if (node is Block) { } else if (node is Block) {
Map<String, Attribute> attrs = node.style.attributes; final attrs = node.style.attributes;
EditableTextBlock editableTextBlock = EditableTextBlock( final editableTextBlock = EditableTextBlock(
node, node,
_textDirection, _textDirection,
_getVerticalSpacingForBlock(node, _styles), _getVerticalSpacingForBlock(node, _styles),
@ -617,13 +611,13 @@ class RawEditorState extends EditorState
EditableTextLine _getEditableTextLineFromNode( EditableTextLine _getEditableTextLineFromNode(
Line node, BuildContext context) { Line node, BuildContext context) {
TextLine textLine = TextLine( final textLine = TextLine(
line: node, line: node,
textDirection: _textDirection, textDirection: _textDirection,
embedBuilder: widget.embedBuilder, embedBuilder: widget.embedBuilder,
styles: _styles!, styles: _styles!,
); );
EditableTextLine editableTextLine = EditableTextLine( final editableTextLine = EditableTextLine(
node, node,
null, null,
textLine, textLine,
@ -641,9 +635,9 @@ class RawEditorState extends EditorState
Tuple2<double, double> _getVerticalSpacingForLine( Tuple2<double, double> _getVerticalSpacingForLine(
Line line, DefaultStyles? defaultStyles) { Line line, DefaultStyles? defaultStyles) {
Map<String, Attribute> attrs = line.style.attributes; final attrs = line.style.attributes;
if (attrs.containsKey(Attribute.header.key)) { if (attrs.containsKey(Attribute.header.key)) {
int? level = attrs[Attribute.header.key]!.value; final int? level = attrs[Attribute.header.key]!.value;
switch (level) { switch (level) {
case 1: case 1:
return defaultStyles!.h1!.verticalSpacing; return defaultStyles!.h1!.verticalSpacing;
@ -661,7 +655,7 @@ class RawEditorState extends EditorState
Tuple2<double, double> _getVerticalSpacingForBlock( Tuple2<double, double> _getVerticalSpacingForBlock(
Block node, DefaultStyles? defaultStyles) { Block node, DefaultStyles? defaultStyles) {
Map<String, Attribute> attrs = node.style.attributes; final attrs = node.style.attributes;
if (attrs.containsKey(Attribute.blockQuote.key)) { if (attrs.containsKey(Attribute.blockQuote.key)) {
return defaultStyles!.quote!.verticalSpacing; return defaultStyles!.quote!.verticalSpacing;
} else if (attrs.containsKey(Attribute.codeBlock.key)) { } else if (attrs.containsKey(Attribute.codeBlock.key)) {
@ -720,8 +714,8 @@ class RawEditorState extends EditorState
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
DefaultStyles? parentStyles = QuillStyles.getStyles(context, true); final parentStyles = QuillStyles.getStyles(context, true);
DefaultStyles defaultStyles = DefaultStyles.getInstance(context); final defaultStyles = DefaultStyles.getInstance(context);
_styles = (parentStyles != null) _styles = (parentStyles != null)
? defaultStyles.merge(parentStyles) ? defaultStyles.merge(parentStyles)
: defaultStyles; : defaultStyles;
@ -784,27 +778,26 @@ class RawEditorState extends EditorState
} }
void handleDelete(bool forward) { void handleDelete(bool forward) {
TextSelection selection = widget.controller.selection; final selection = widget.controller.selection;
String plainText = textEditingValue.text; final plainText = textEditingValue.text;
int cursorPosition = selection.start; var cursorPosition = selection.start;
String textBefore = selection.textBefore(plainText); var textBefore = selection.textBefore(plainText);
String textAfter = selection.textAfter(plainText); var textAfter = selection.textAfter(plainText);
if (selection.isCollapsed) { if (selection.isCollapsed) {
if (!forward && textBefore.isNotEmpty) { if (!forward && textBefore.isNotEmpty) {
final int characterBoundary = final characterBoundary =
_previousCharacter(textBefore.length, textBefore, true); _previousCharacter(textBefore.length, textBefore, true);
textBefore = textBefore.substring(0, characterBoundary); textBefore = textBefore.substring(0, characterBoundary);
cursorPosition = characterBoundary; cursorPosition = characterBoundary;
} }
if (forward && textAfter.isNotEmpty && textAfter != '\n') { if (forward && textAfter.isNotEmpty && textAfter != '\n') {
final int deleteCount = _nextCharacter(0, textAfter, true); final deleteCount = _nextCharacter(0, textAfter, true);
textAfter = textAfter.substring(deleteCount); textAfter = textAfter.substring(deleteCount);
} }
} }
TextSelection newSelection = final newSelection = TextSelection.collapsed(offset: cursorPosition);
TextSelection.collapsed(offset: cursorPosition); final newText = textBefore + textAfter;
String newText = textBefore + textAfter; final size = plainText.length - newText.length;
int size = plainText.length - newText.length;
widget.controller.replaceText( widget.controller.replaceText(
cursorPosition, cursorPosition,
size, size,
@ -814,8 +807,8 @@ class RawEditorState extends EditorState
} }
void handleShortcut(InputShortcut? shortcut) async { void handleShortcut(InputShortcut? shortcut) async {
TextSelection selection = widget.controller.selection; final selection = widget.controller.selection;
String plainText = textEditingValue.text; final plainText = textEditingValue.text;
if (shortcut == InputShortcut.COPY) { if (shortcut == InputShortcut.COPY) {
if (!selection.isCollapsed) { if (!selection.isCollapsed) {
await Clipboard.setData( await Clipboard.setData(
@ -844,7 +837,7 @@ class RawEditorState extends EditorState
return; return;
} }
if (shortcut == InputShortcut.PASTE && !widget.readOnly) { if (shortcut == InputShortcut.PASTE && !widget.readOnly) {
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); final data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null) { if (data != null) {
widget.controller.replaceText( widget.controller.replaceText(
selection.start, selection.start,
@ -1074,8 +1067,8 @@ class RawEditorState extends EditorState
value.selection, value.selection,
); );
} else { } else {
final TextEditingValue value = textEditingValue; final value = textEditingValue;
final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); final data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null) { if (data != null) {
final length = final length =
textEditingValue.selection.end - textEditingValue.selection.start; textEditingValue.selection.end - textEditingValue.selection.start;
@ -1095,7 +1088,7 @@ class RawEditorState extends EditorState
} }
Future<bool> __isItCut(TextEditingValue value) async { Future<bool> __isItCut(TextEditingValue value) async {
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); final data = await Clipboard.getData(Clipboard.kTextPlain);
if (data == null) { if (data == null) {
return false; return false;
} }

@ -6,7 +6,6 @@ import 'package:tuple/tuple.dart';
import '../models/documents/attribute.dart'; import '../models/documents/attribute.dart';
import '../models/documents/nodes/block.dart'; import '../models/documents/nodes/block.dart';
import '../models/documents/nodes/line.dart'; import '../models/documents/nodes/line.dart';
import '../models/documents/nodes/node.dart';
import 'box.dart'; import 'box.dart';
import 'cursor.dart'; import 'cursor.dart';
import 'default_styles.dart'; import 'default_styles.dart';
@ -79,7 +78,7 @@ class EditableTextBlock extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context)); assert(debugCheckHasMediaQuery(context));
DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); final defaultStyles = QuillStyles.getStyles(context, false);
return _EditableBlock( return _EditableBlock(
block, block,
textDirection, textDirection,
@ -91,7 +90,7 @@ class EditableTextBlock extends StatelessWidget {
BoxDecoration? _getDecorationForBlock( BoxDecoration? _getDecorationForBlock(
Block node, DefaultStyles? defaultStyles) { Block node, DefaultStyles? defaultStyles) {
Map<String, Attribute> attrs = block.style.attributes; final attrs = block.style.attributes;
if (attrs.containsKey(Attribute.blockQuote.key)) { if (attrs.containsKey(Attribute.blockQuote.key)) {
return defaultStyles!.quote!.decoration; return defaultStyles!.quote!.decoration;
} }
@ -103,13 +102,13 @@ class EditableTextBlock extends StatelessWidget {
List<Widget> _buildChildren( List<Widget> _buildChildren(
BuildContext context, Map<int, int> indentLevelCounts) { BuildContext context, Map<int, int> indentLevelCounts) {
DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); final defaultStyles = QuillStyles.getStyles(context, false);
int count = block.children.length; final count = block.children.length;
var children = <Widget>[]; final children = <Widget>[];
int index = 0; var index = 0;
for (Line line in Iterable.castFrom<dynamic, Line>(block.children)) { for (final line in Iterable.castFrom<dynamic, Line>(block.children)) {
index++; index++;
EditableTextLine editableTextLine = EditableTextLine( final editableTextLine = EditableTextLine(
line, line,
_buildLeading(context, line, index, indentLevelCounts, count), _buildLeading(context, line, index, indentLevelCounts, count),
TextLine( TextLine(
@ -134,8 +133,8 @@ class EditableTextBlock extends StatelessWidget {
Widget? _buildLeading(BuildContext context, Line line, int index, Widget? _buildLeading(BuildContext context, Line line, int index,
Map<int, int> indentLevelCounts, int count) { Map<int, int> indentLevelCounts, int count) {
DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); final defaultStyles = QuillStyles.getStyles(context, false);
Map<String, Attribute> attrs = line.style.attributes; final attrs = line.style.attributes;
if (attrs[Attribute.list.key] == Attribute.ol) { if (attrs[Attribute.list.key] == Attribute.ol) {
return _NumberPoint( return _NumberPoint(
index: index, index: index,
@ -183,10 +182,10 @@ class EditableTextBlock extends StatelessWidget {
} }
double _getIndentWidth() { double _getIndentWidth() {
Map<String, Attribute> attrs = block.style.attributes; final attrs = block.style.attributes;
Attribute? indent = attrs[Attribute.indent.key]; final indent = attrs[Attribute.indent.key];
double extraIndent = 0.0; var extraIndent = 0.0;
if (indent != null && indent.value != null) { if (indent != null && indent.value != null) {
extraIndent = 16.0 * indent.value; extraIndent = 16.0 * indent.value;
} }
@ -200,11 +199,11 @@ class EditableTextBlock extends StatelessWidget {
Tuple2 _getSpacingForLine( Tuple2 _getSpacingForLine(
Line node, int index, int count, DefaultStyles? defaultStyles) { Line node, int index, int count, DefaultStyles? defaultStyles) {
double top = 0.0, bottom = 0.0; var top = 0.0, bottom = 0.0;
Map<String, Attribute> attrs = block.style.attributes; final attrs = block.style.attributes;
if (attrs.containsKey(Attribute.header.key)) { if (attrs.containsKey(Attribute.header.key)) {
int? level = attrs[Attribute.header.key]!.value; final level = attrs[Attribute.header.key]!.value;
switch (level) { switch (level) {
case 1: case 1:
top = defaultStyles!.h1!.verticalSpacing.item1; top = defaultStyles!.h1!.verticalSpacing.item1;
@ -310,8 +309,8 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
@override @override
TextRange getLineBoundary(TextPosition position) { TextRange getLineBoundary(TextPosition position) {
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
TextRange rangeInChild = child.getLineBoundary(TextPosition( final rangeInChild = child.getLineBoundary(TextPosition(
offset: position.offset - child.getContainer().getOffset(), offset: position.offset - child.getContainer().getOffset(),
affinity: position.affinity, affinity: position.affinity,
)); ));
@ -323,7 +322,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
@override @override
Offset getOffsetForCaret(TextPosition position) { Offset getOffsetForCaret(TextPosition position) {
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
return child.getOffsetForCaret(TextPosition( return child.getOffsetForCaret(TextPosition(
offset: position.offset - child.getContainer().getOffset(), offset: position.offset - child.getContainer().getOffset(),
affinity: position.affinity, affinity: position.affinity,
@ -333,9 +332,9 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
@override @override
TextPosition getPositionForOffset(Offset offset) { TextPosition getPositionForOffset(Offset offset) {
RenderEditableBox child = childAtOffset(offset)!; final child = childAtOffset(offset)!;
BoxParentData parentData = child.parentData as BoxParentData; final parentData = child.parentData as BoxParentData;
TextPosition localPosition = final localPosition =
child.getPositionForOffset(offset - parentData.offset); child.getPositionForOffset(offset - parentData.offset);
return TextPosition( return TextPosition(
offset: localPosition.offset + child.getContainer().getOffset(), offset: localPosition.offset + child.getContainer().getOffset(),
@ -345,9 +344,9 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
@override @override
TextRange getWordBoundary(TextPosition position) { TextRange getWordBoundary(TextPosition position) {
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
int nodeOffset = child.getContainer().getOffset(); final nodeOffset = child.getContainer().getOffset();
TextRange childWord = child final childWord = child
.getWordBoundary(TextPosition(offset: position.offset - nodeOffset)); .getWordBoundary(TextPosition(offset: position.offset - nodeOffset));
return TextRange( return TextRange(
start: childWord.start + nodeOffset, start: childWord.start + nodeOffset,
@ -359,25 +358,25 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
TextPosition? getPositionAbove(TextPosition position) { TextPosition? getPositionAbove(TextPosition position) {
assert(position.offset < getContainer().length); assert(position.offset < getContainer().length);
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
TextPosition childLocalPosition = TextPosition( final childLocalPosition = TextPosition(
offset: position.offset - child.getContainer().getOffset()); offset: position.offset - child.getContainer().getOffset());
TextPosition? result = child.getPositionAbove(childLocalPosition); final result = child.getPositionAbove(childLocalPosition);
if (result != null) { if (result != null) {
return TextPosition( return TextPosition(
offset: result.offset + child.getContainer().getOffset()); offset: result.offset + child.getContainer().getOffset());
} }
RenderEditableBox? sibling = childBefore(child); final sibling = childBefore(child);
if (sibling == null) { if (sibling == null) {
return null; return null;
} }
Offset caretOffset = child.getOffsetForCaret(childLocalPosition); final caretOffset = child.getOffsetForCaret(childLocalPosition);
TextPosition testPosition = final testPosition =
TextPosition(offset: sibling.getContainer().length - 1); TextPosition(offset: sibling.getContainer().length - 1);
Offset testOffset = sibling.getOffsetForCaret(testPosition); final testOffset = sibling.getOffsetForCaret(testPosition);
Offset finalOffset = Offset(caretOffset.dx, testOffset.dy); final finalOffset = Offset(caretOffset.dx, testOffset.dy);
return TextPosition( return TextPosition(
offset: sibling.getContainer().getOffset() + offset: sibling.getContainer().getOffset() +
sibling.getPositionForOffset(finalOffset).offset); sibling.getPositionForOffset(finalOffset).offset);
@ -387,24 +386,23 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
TextPosition? getPositionBelow(TextPosition position) { TextPosition? getPositionBelow(TextPosition position) {
assert(position.offset < getContainer().length); assert(position.offset < getContainer().length);
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
TextPosition childLocalPosition = TextPosition( final childLocalPosition = TextPosition(
offset: position.offset - child.getContainer().getOffset()); offset: position.offset - child.getContainer().getOffset());
TextPosition? result = child.getPositionBelow(childLocalPosition); final result = child.getPositionBelow(childLocalPosition);
if (result != null) { if (result != null) {
return TextPosition( return TextPosition(
offset: result.offset + child.getContainer().getOffset()); offset: result.offset + child.getContainer().getOffset());
} }
RenderEditableBox? sibling = childAfter(child); final sibling = childAfter(child);
if (sibling == null) { if (sibling == null) {
return null; return null;
} }
Offset caretOffset = child.getOffsetForCaret(childLocalPosition); final caretOffset = child.getOffsetForCaret(childLocalPosition);
Offset testOffset = final testOffset = sibling.getOffsetForCaret(const TextPosition(offset: 0));
sibling.getOffsetForCaret(const TextPosition(offset: 0)); final finalOffset = Offset(caretOffset.dx, testOffset.dy);
Offset finalOffset = Offset(caretOffset.dx, testOffset.dy);
return TextPosition( return TextPosition(
offset: sibling.getContainer().getOffset() + offset: sibling.getContainer().getOffset() +
sibling.getPositionForOffset(finalOffset).offset); sibling.getPositionForOffset(finalOffset).offset);
@ -412,7 +410,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
@override @override
double preferredLineHeight(TextPosition position) { double preferredLineHeight(TextPosition position) {
RenderEditableBox child = childAtPosition(position); final child = childAtPosition(position);
return child.preferredLineHeight(TextPosition( return child.preferredLineHeight(TextPosition(
offset: position.offset - child.getContainer().getOffset())); offset: position.offset - child.getContainer().getOffset()));
} }
@ -426,7 +424,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
null); null);
} }
Node? baseNode = getContainer().queryChild(selection.start, false).node; final baseNode = getContainer().queryChild(selection.start, false).node;
var baseChild = firstChild; var baseChild = firstChild;
while (baseChild != null) { while (baseChild != null) {
if (baseChild.getContainer() == baseNode) { if (baseChild.getContainer() == baseNode) {
@ -436,7 +434,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
} }
assert(baseChild != null); assert(baseChild != null);
TextSelectionPoint basePoint = baseChild!.getBaseEndpointForSelection( final basePoint = baseChild!.getBaseEndpointForSelection(
localSelection(baseChild.getContainer(), selection, true)); localSelection(baseChild.getContainer(), selection, true));
return TextSelectionPoint( return TextSelectionPoint(
basePoint.point + (baseChild.parentData as BoxParentData).offset, basePoint.point + (baseChild.parentData as BoxParentData).offset,
@ -452,7 +450,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
null); null);
} }
Node? extentNode = getContainer().queryChild(selection.end, false).node; final extentNode = getContainer().queryChild(selection.end, false).node;
var extentChild = firstChild; var extentChild = firstChild;
while (extentChild != null) { while (extentChild != null) {
@ -463,7 +461,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
} }
assert(extentChild != null); assert(extentChild != null);
TextSelectionPoint extentPoint = extentChild!.getExtentEndpointForSelection( final extentPoint = extentChild!.getExtentEndpointForSelection(
localSelection(extentChild.getContainer(), selection, true)); localSelection(extentChild.getContainer(), selection, true));
return TextSelectionPoint( return TextSelectionPoint(
extentPoint.point + (extentChild.parentData as BoxParentData).offset, extentPoint.point + (extentChild.parentData as BoxParentData).offset,
@ -487,11 +485,11 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
void _paintDecoration(PaintingContext context, Offset offset) { void _paintDecoration(PaintingContext context, Offset offset) {
_painter ??= _decoration.createBoxPainter(markNeedsPaint); _painter ??= _decoration.createBoxPainter(markNeedsPaint);
EdgeInsets decorationPadding = resolvedPadding! - _contentPadding; final decorationPadding = resolvedPadding! - _contentPadding;
ImageConfiguration filledConfiguration = final filledConfiguration =
configuration.copyWith(size: decorationPadding.deflateSize(size)); configuration.copyWith(size: decorationPadding.deflateSize(size));
int debugSaveCount = context.canvas.getSaveCount(); final debugSaveCount = context.canvas.getSaveCount();
final decorationOffset = final decorationOffset =
offset.translate(decorationPadding.left, decorationPadding.top); offset.translate(decorationPadding.left, decorationPadding.top);
@ -572,7 +570,7 @@ class _NumberPoint extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String s = index.toString(); var s = index.toString();
int? level = 0; int? level = 0;
if (!attrs.containsKey(Attribute.indent.key) && if (!attrs.containsKey(Attribute.indent.key) &&
!indentLevelCounts.containsKey(1)) { !indentLevelCounts.containsKey(1)) {
@ -595,7 +593,7 @@ class _NumberPoint extends StatelessWidget {
// last visited level is done, going up // last visited level is done, going up
indentLevelCounts.remove(level + 1); indentLevelCounts.remove(level + 1);
} }
int count = (indentLevelCounts[level] ?? 0) + 1; final count = (indentLevelCounts[level] ?? 0) + 1;
indentLevelCounts[level] = count; indentLevelCounts[level] = count;
s = count.toString(); s = count.toString();

@ -11,7 +11,6 @@ import '../models/documents/nodes/leaf.dart' as leaf;
import '../models/documents/nodes/leaf.dart'; import '../models/documents/nodes/leaf.dart';
import '../models/documents/nodes/line.dart'; import '../models/documents/nodes/line.dart';
import '../models/documents/nodes/node.dart'; import '../models/documents/nodes/node.dart';
import '../models/documents/style.dart';
import '../utils/color.dart'; import '../utils/color.dart';
import 'box.dart'; import 'box.dart';
import 'cursor.dart'; import 'cursor.dart';
@ -39,14 +38,14 @@ class TextLine extends StatelessWidget {
assert(debugCheckHasMediaQuery(context)); assert(debugCheckHasMediaQuery(context));
if (line.hasEmbed) { if (line.hasEmbed) {
Embed embed = line.children.single as Embed; final embed = line.children.single as Embed;
return EmbedProxy(embedBuilder(context, embed)); return EmbedProxy(embedBuilder(context, embed));
} }
final textSpan = _buildTextSpan(context); final textSpan = _buildTextSpan(context);
final strutStyle = StrutStyle.fromTextStyle(textSpan.style!); final strutStyle = StrutStyle.fromTextStyle(textSpan.style!);
final textAlign = _getTextAlign(); final textAlign = _getTextAlign();
RichText child = RichText( final child = RichText(
text: textSpan, text: textSpan,
textAlign: textAlign, textAlign: textAlign,
textDirection: textDirection, textDirection: textDirection,
@ -80,20 +79,20 @@ class TextLine extends StatelessWidget {
} }
TextSpan _buildTextSpan(BuildContext context) { TextSpan _buildTextSpan(BuildContext context) {
DefaultStyles defaultStyles = styles; final defaultStyles = styles;
List<TextSpan> children = line.children final children = line.children
.map((node) => _getTextSpanFromNode(defaultStyles, node)) .map((node) => _getTextSpanFromNode(defaultStyles, node))
.toList(growable: false); .toList(growable: false);
TextStyle textStyle = const TextStyle(); var textStyle = const TextStyle();
if (line.style.containsKey(Attribute.placeholder.key)) { if (line.style.containsKey(Attribute.placeholder.key)) {
textStyle = defaultStyles.placeHolder!.style; textStyle = defaultStyles.placeHolder!.style;
return TextSpan(children: children, style: textStyle); return TextSpan(children: children, style: textStyle);
} }
Attribute? header = line.style.attributes[Attribute.header.key]; final header = line.style.attributes[Attribute.header.key];
Map<Attribute, TextStyle> m = { final m = <Attribute, TextStyle>{
Attribute.h1: defaultStyles.h1!.style, Attribute.h1: defaultStyles.h1!.style,
Attribute.h2: defaultStyles.h2!.style, Attribute.h2: defaultStyles.h2!.style,
Attribute.h3: defaultStyles.h3!.style, Attribute.h3: defaultStyles.h3!.style,
@ -101,7 +100,7 @@ class TextLine extends StatelessWidget {
textStyle = textStyle.merge(m[header] ?? defaultStyles.paragraph!.style); textStyle = textStyle.merge(m[header] ?? defaultStyles.paragraph!.style);
Attribute? block = line.style.getBlockExceptHeader(); final block = line.style.getBlockExceptHeader();
TextStyle? toMerge; TextStyle? toMerge;
if (block == Attribute.blockQuote) { if (block == Attribute.blockQuote) {
toMerge = defaultStyles.quote!.style; toMerge = defaultStyles.quote!.style;
@ -117,11 +116,11 @@ class TextLine extends StatelessWidget {
} }
TextSpan _getTextSpanFromNode(DefaultStyles defaultStyles, Node node) { TextSpan _getTextSpanFromNode(DefaultStyles defaultStyles, Node node) {
leaf.Text textNode = node as leaf.Text; final textNode = node as leaf.Text;
Style style = textNode.style; final style = textNode.style;
TextStyle res = const TextStyle(); var res = const TextStyle();
Map<String, TextStyle?> m = { final m = <String, TextStyle?>{
Attribute.bold.key: defaultStyles.bold, Attribute.bold.key: defaultStyles.bold,
Attribute.italic.key: defaultStyles.italic, Attribute.italic.key: defaultStyles.italic,
Attribute.link.key: defaultStyles.link, Attribute.link.key: defaultStyles.link,
@ -134,12 +133,12 @@ class TextLine extends StatelessWidget {
} }
}); });
Attribute? font = textNode.style.attributes[Attribute.font.key]; final font = textNode.style.attributes[Attribute.font.key];
if (font != null && font.value != null) { if (font != null && font.value != null) {
res = res.merge(TextStyle(fontFamily: font.value)); res = res.merge(TextStyle(fontFamily: font.value));
} }
Attribute? size = textNode.style.attributes[Attribute.size.key]; final size = textNode.style.attributes[Attribute.size.key];
if (size != null && size.value != null) { if (size != null && size.value != null) {
switch (size.value) { switch (size.value) {
case 'small': case 'small':
@ -152,7 +151,7 @@ class TextLine extends StatelessWidget {
res = res.merge(defaultStyles.sizeHuge); res = res.merge(defaultStyles.sizeHuge);
break; break;
default: default:
double? fontSize = double.tryParse(size.value); final fontSize = double.tryParse(size.value);
if (fontSize != null) { if (fontSize != null) {
res = res.merge(TextStyle(fontSize: fontSize)); res = res.merge(TextStyle(fontSize: fontSize));
} else { } else {
@ -161,7 +160,7 @@ class TextLine extends StatelessWidget {
} }
} }
Attribute? color = textNode.style.attributes[Attribute.color.key]; final color = textNode.style.attributes[Attribute.color.key];
if (color != null && color.value != null) { if (color != null && color.value != null) {
var textColor = defaultStyles.color; var textColor = defaultStyles.color;
if (color.value is String) { if (color.value is String) {
@ -172,7 +171,7 @@ class TextLine extends StatelessWidget {
} }
} }
Attribute? background = textNode.style.attributes[Attribute.background.key]; final background = textNode.style.attributes[Attribute.background.key];
if (background != null && background.value != null) { if (background != null && background.value != null) {
final backgroundColor = stringToColor(background.value); final backgroundColor = stringToColor(background.value);
res = res.merge(TextStyle(backgroundColor: backgroundColor)); res = res.merge(TextStyle(backgroundColor: backgroundColor));
@ -345,7 +344,7 @@ class RenderEditableTextLine extends RenderEditableBox {
return; return;
} }
bool containsSelection = containsTextSelection(); final containsSelection = containsTextSelection();
if (attached && containsCursor()) { if (attached && containsCursor()) {
cursorCont.removeListener(markNeedsLayout); cursorCont.removeListener(markNeedsLayout);
cursorCont.color.removeListener(markNeedsPaint); cursorCont.color.removeListener(markNeedsPaint);
@ -424,7 +423,7 @@ class RenderEditableTextLine extends RenderEditableBox {
} }
List<TextBox> _getBoxes(TextSelection textSelection) { List<TextBox> _getBoxes(TextSelection textSelection) {
BoxParentData? parentData = _body!.parentData as BoxParentData?; final parentData = _body!.parentData as BoxParentData?;
return _body!.getBoxesForSelection(textSelection).map((box) { return _body!.getBoxesForSelection(textSelection).map((box) {
return TextBox.fromLTRBD( return TextBox.fromLTRBD(
box.left + parentData!.offset.dx, box.left + parentData!.offset.dx,
@ -463,9 +462,9 @@ class RenderEditableTextLine extends RenderEditableBox {
getOffsetForCaret(textSelection.extent), getOffsetForCaret(textSelection.extent),
null); null);
} }
List<TextBox> boxes = _getBoxes(textSelection); final boxes = _getBoxes(textSelection);
assert(boxes.isNotEmpty); assert(boxes.isNotEmpty);
TextBox targetBox = first ? boxes.first : boxes.last; final targetBox = first ? boxes.first : boxes.last;
return TextSelectionPoint( return TextSelectionPoint(
Offset(first ? targetBox.start : targetBox.end, targetBox.bottom), Offset(first ? targetBox.start : targetBox.end, targetBox.bottom),
targetBox.direction); targetBox.direction);
@ -473,10 +472,10 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
TextRange getLineBoundary(TextPosition position) { TextRange getLineBoundary(TextPosition position) {
double lineDy = getOffsetForCaret(position) final lineDy = getOffsetForCaret(position)
.translate(0.0, 0.5 * preferredLineHeight(position)) .translate(0.0, 0.5 * preferredLineHeight(position))
.dy; .dy;
List<TextBox> lineBoxes = final lineBoxes =
_getBoxes(TextSelection(baseOffset: 0, extentOffset: line.length - 1)) _getBoxes(TextSelection(baseOffset: 0, extentOffset: line.length - 1))
.where((element) => element.top < lineDy && element.bottom > lineDy) .where((element) => element.top < lineDy && element.bottom > lineDy)
.toList(growable: false); .toList(growable: false);
@ -504,7 +503,7 @@ class RenderEditableTextLine extends RenderEditableBox {
TextPosition? _getPosition(TextPosition textPosition, double dyScale) { TextPosition? _getPosition(TextPosition textPosition, double dyScale) {
assert(textPosition.offset < line.length); assert(textPosition.offset < line.length);
Offset offset = getOffsetForCaret(textPosition) final offset = getOffsetForCaret(textPosition)
.translate(0, dyScale * preferredLineHeight(textPosition)); .translate(0, dyScale * preferredLineHeight(textPosition));
if (_body!.size if (_body!.size
.contains(offset - (_body!.parentData as BoxParentData).offset)) { .contains(offset - (_body!.parentData as BoxParentData).offset)) {
@ -574,7 +573,7 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
void detach() { void detach() {
super.detach(); super.detach();
for (RenderBox child in _children) { for (final child in _children) {
child.detach(); child.detach();
} }
if (containsCursor()) { if (containsCursor()) {
@ -595,7 +594,7 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
List<DiagnosticsNode> debugDescribeChildren() { List<DiagnosticsNode> debugDescribeChildren() {
var value = <DiagnosticsNode>[]; final value = <DiagnosticsNode>[];
void add(RenderBox? child, String name) { void add(RenderBox? child, String name) {
if (child != null) { if (child != null) {
value.add(child.toDiagnosticsNode(name: name)); value.add(child.toDiagnosticsNode(name: name));
@ -613,12 +612,12 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
double computeMinIntrinsicWidth(double height) { double computeMinIntrinsicWidth(double height) {
_resolvePadding(); _resolvePadding();
double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
int leadingWidth = _leading == null final leadingWidth = _leading == null
? 0 ? 0
: _leading!.getMinIntrinsicWidth(height - verticalPadding) as int; : _leading!.getMinIntrinsicWidth(height - verticalPadding) as int;
int bodyWidth = _body == null final bodyWidth = _body == null
? 0 ? 0
: _body!.getMinIntrinsicWidth(math.max(0.0, height - verticalPadding)) : _body!.getMinIntrinsicWidth(math.max(0.0, height - verticalPadding))
as int; as int;
@ -628,12 +627,12 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
double computeMaxIntrinsicWidth(double height) { double computeMaxIntrinsicWidth(double height) {
_resolvePadding(); _resolvePadding();
double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
int leadingWidth = _leading == null final leadingWidth = _leading == null
? 0 ? 0
: _leading!.getMaxIntrinsicWidth(height - verticalPadding) as int; : _leading!.getMaxIntrinsicWidth(height - verticalPadding) as int;
int bodyWidth = _body == null final bodyWidth = _body == null
? 0 ? 0
: _body!.getMaxIntrinsicWidth(math.max(0.0, height - verticalPadding)) : _body!.getMaxIntrinsicWidth(math.max(0.0, height - verticalPadding))
as int; as int;
@ -643,8 +642,8 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
double computeMinIntrinsicHeight(double width) { double computeMinIntrinsicHeight(double width) {
_resolvePadding(); _resolvePadding();
double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
if (_body != null) { if (_body != null) {
return _body! return _body!
.getMinIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + .getMinIntrinsicHeight(math.max(0.0, width - horizontalPadding)) +
@ -656,8 +655,8 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
double computeMaxIntrinsicHeight(double width) { double computeMaxIntrinsicHeight(double width) {
_resolvePadding(); _resolvePadding();
double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
if (_body != null) { if (_body != null) {
return _body! return _body!
.getMaxIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + .getMaxIntrinsicHeight(math.max(0.0, width - horizontalPadding)) +
@ -849,8 +848,8 @@ class _TextLineElement extends RenderObjectElement {
} }
void _mountChild(Widget? widget, TextLineSlot slot) { void _mountChild(Widget? widget, TextLineSlot slot) {
Element? oldChild = _slotToChildren[slot]; final oldChild = _slotToChildren[slot];
Element? newChild = updateChild(oldChild, widget, slot); final newChild = updateChild(oldChild, widget, slot);
if (oldChild != null) { if (oldChild != null) {
_slotToChildren.remove(slot); _slotToChildren.remove(slot);
} }
@ -873,8 +872,8 @@ class _TextLineElement extends RenderObjectElement {
} }
void _updateChild(Widget? widget, TextLineSlot slot) { void _updateChild(Widget? widget, TextLineSlot slot) {
Element? oldChild = _slotToChildren[slot]; final oldChild = _slotToChildren[slot];
Element? newChild = updateChild(oldChild, widget, slot); final newChild = updateChild(oldChild, widget, slot);
if (oldChild != null) { if (oldChild != null) {
_slotToChildren.remove(slot); _slotToChildren.remove(slot);
} }

@ -12,10 +12,10 @@ import '../models/documents/nodes/node.dart';
import 'editor.dart'; import 'editor.dart';
TextSelection localSelection(Node node, TextSelection selection, fromParent) { TextSelection localSelection(Node node, TextSelection selection, fromParent) {
int base = fromParent ? node.getOffset() : node.getDocumentOffset(); final base = fromParent ? node.getOffset() : node.getDocumentOffset();
assert(base <= selection.end && selection.start <= base + node.length - 1); assert(base <= selection.end && selection.start <= base + node.length - 1);
int offset = fromParent ? node.getOffset() : node.getDocumentOffset(); final offset = fromParent ? node.getOffset() : node.getDocumentOffset();
return selection.copyWith( return selection.copyWith(
baseOffset: math.max(selection.start - offset, 0), baseOffset: math.max(selection.start - offset, 0),
extentOffset: math.min(selection.end - offset, node.length - 1)); extentOffset: math.min(selection.end - offset, node.length - 1));
@ -55,7 +55,7 @@ class EditorTextSelectionOverlay {
this.dragStartBehavior, this.dragStartBehavior,
this.onSelectionHandleTapped, this.onSelectionHandleTapped,
this.clipboardStatus) { this.clipboardStatus) {
OverlayState overlay = Overlay.of(context, rootOverlay: true)!; final overlay = Overlay.of(context, rootOverlay: true)!;
_toolbarController = AnimationController( _toolbarController = AnimationController(
duration: const Duration(milliseconds: 150), vsync: overlay); duration: const Duration(milliseconds: 150), vsync: overlay);
@ -161,26 +161,25 @@ class EditorTextSelectionOverlay {
} }
Widget _buildToolbar(BuildContext context) { Widget _buildToolbar(BuildContext context) {
List<TextSelectionPoint> endpoints = final endpoints = renderObject!.getEndpointsForSelection(_selection);
renderObject!.getEndpointsForSelection(_selection);
Rect editingRegion = Rect.fromPoints( final editingRegion = Rect.fromPoints(
renderObject!.localToGlobal(Offset.zero), renderObject!.localToGlobal(Offset.zero),
renderObject!.localToGlobal(renderObject!.size.bottomRight(Offset.zero)), renderObject!.localToGlobal(renderObject!.size.bottomRight(Offset.zero)),
); );
double baseLineHeight = renderObject!.preferredLineHeight(_selection.base); final baseLineHeight = renderObject!.preferredLineHeight(_selection.base);
double extentLineHeight = final extentLineHeight =
renderObject!.preferredLineHeight(_selection.extent); renderObject!.preferredLineHeight(_selection.extent);
double smallestLineHeight = math.min(baseLineHeight, extentLineHeight); final smallestLineHeight = math.min(baseLineHeight, extentLineHeight);
bool isMultiline = endpoints.last.point.dy - endpoints.first.point.dy > final isMultiline = endpoints.last.point.dy - endpoints.first.point.dy >
smallestLineHeight / 2; smallestLineHeight / 2;
double midX = isMultiline final midX = isMultiline
? editingRegion.width / 2 ? editingRegion.width / 2
: (endpoints.first.point.dx + endpoints.last.point.dx) / 2; : (endpoints.first.point.dx + endpoints.last.point.dx) / 2;
Offset midpoint = Offset( final midpoint = Offset(
midX, midX,
endpoints[0].point.dy - baseLineHeight, endpoints[0].point.dy - baseLineHeight,
); );
@ -326,14 +325,14 @@ class _TextSelectionHandleOverlayState
void _handleDragStart(DragStartDetails details) {} void _handleDragStart(DragStartDetails details) {}
void _handleDragUpdate(DragUpdateDetails details) { void _handleDragUpdate(DragUpdateDetails details) {
TextPosition position = final position =
widget.renderObject!.getPositionForOffset(details.globalPosition); widget.renderObject!.getPositionForOffset(details.globalPosition);
if (widget.selection.isCollapsed) { if (widget.selection.isCollapsed) {
widget.onSelectionHandleChanged(TextSelection.fromPosition(position)); widget.onSelectionHandleChanged(TextSelection.fromPosition(position));
return; return;
} }
bool isNormalized = final isNormalized =
widget.selection.extentOffset >= widget.selection.baseOffset; widget.selection.extentOffset >= widget.selection.baseOffset;
TextSelection? newSelection; TextSelection? newSelection;
switch (widget.position) { switch (widget.position) {
@ -389,27 +388,26 @@ class _TextSelectionHandleOverlayState
break; break;
} }
TextPosition textPosition = final textPosition = widget.position == _TextSelectionHandlePosition.START
widget.position == _TextSelectionHandlePosition.START ? widget.selection.base
? widget.selection.base : widget.selection.extent;
: widget.selection.extent; final lineHeight = widget.renderObject!.preferredLineHeight(textPosition);
double lineHeight = widget.renderObject!.preferredLineHeight(textPosition); final handleAnchor =
Offset handleAnchor =
widget.selectionControls.getHandleAnchor(type!, lineHeight); widget.selectionControls.getHandleAnchor(type!, lineHeight);
Size handleSize = widget.selectionControls.getHandleSize(lineHeight); final handleSize = widget.selectionControls.getHandleSize(lineHeight);
Rect handleRect = Rect.fromLTWH( final handleRect = Rect.fromLTWH(
-handleAnchor.dx, -handleAnchor.dx,
-handleAnchor.dy, -handleAnchor.dy,
handleSize.width, handleSize.width,
handleSize.height, handleSize.height,
); );
Rect interactiveRect = handleRect.expandToInclude( final interactiveRect = handleRect.expandToInclude(
Rect.fromCircle( Rect.fromCircle(
center: handleRect.center, radius: kMinInteractiveDimension / 2), center: handleRect.center, radius: kMinInteractiveDimension / 2),
); );
RelativeRect padding = RelativeRect.fromLTRB( final padding = RelativeRect.fromLTRB(
math.max((interactiveRect.width - handleRect.width) / 2, 0), math.max((interactiveRect.width - handleRect.width) / 2, 0),
math.max((interactiveRect.height - handleRect.height) / 2, 0), math.max((interactiveRect.height - handleRect.height) / 2, 0),
math.max((interactiveRect.width - handleRect.width) / 2, 0), math.max((interactiveRect.width - handleRect.width) / 2, 0),
@ -656,8 +654,7 @@ class _EditorTextSelectionGestureDetectorState
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Map<Type, GestureRecognizerFactory> gestures = final gestures = <Type, GestureRecognizerFactory>{};
<Type, GestureRecognizerFactory>{};
gestures[TapGestureRecognizer] = gestures[TapGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>( GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(

@ -215,7 +215,7 @@ class _ToggleStyleButtonState extends State<ToggleStyleButton> {
bool _getIsToggled(Map<String, Attribute> attrs) { bool _getIsToggled(Map<String, Attribute> attrs) {
if (widget.attribute.key == Attribute.list.key) { if (widget.attribute.key == Attribute.list.key) {
Attribute? attribute = attrs[widget.attribute.key]; final attribute = attrs[widget.attribute.key];
if (attribute == null) { if (attribute == null) {
return false; return false;
} }
@ -299,7 +299,7 @@ class _ToggleCheckListButtonState extends State<ToggleCheckListButton> {
bool _getIsToggled(Map<String, Attribute> attrs) { bool _getIsToggled(Map<String, Attribute> attrs) {
if (widget.attribute.key == Attribute.list.key) { if (widget.attribute.key == Attribute.list.key) {
Attribute? attribute = attrs[widget.attribute.key]; final attribute = attrs[widget.attribute.key];
if (attribute == null) { if (attribute == null) {
return false; return false;
} }
@ -430,20 +430,20 @@ class _SelectHeaderStyleButtonState extends State<SelectHeaderStyleButton> {
Widget _selectHeadingStyleButtonBuilder(BuildContext context, Attribute? value, Widget _selectHeadingStyleButtonBuilder(BuildContext context, Attribute? value,
ValueChanged<Attribute?> onSelected) { ValueChanged<Attribute?> onSelected) {
final Map<Attribute, String> _valueToText = { final _valueToText = <Attribute, String>{
Attribute.header: 'N', Attribute.header: 'N',
Attribute.h1: 'H1', Attribute.h1: 'H1',
Attribute.h2: 'H2', Attribute.h2: 'H2',
Attribute.h3: 'H3', Attribute.h3: 'H3',
}; };
List<Attribute> _valueAttribute = [ final _valueAttribute = <Attribute>[
Attribute.header, Attribute.header,
Attribute.h1, Attribute.h1,
Attribute.h2, Attribute.h2,
Attribute.h3 Attribute.h3
]; ];
List<String> _valueString = ['N', 'H1', 'H2', 'H3']; final _valueString = <String>['N', 'H1', 'H2', 'H3'];
final theme = Theme.of(context); final theme = Theme.of(context);
final style = TextStyle( final style = TextStyle(
@ -520,10 +520,10 @@ class _ImageButtonState extends State<ImageButton> {
final FileType _pickingType = FileType.any; final FileType _pickingType = FileType.any;
Future<String?> _pickImage(ImageSource source) async { Future<String?> _pickImage(ImageSource source) async {
final PickedFile? pickedFile = await _picker.getImage(source: source); final pickedFile = await _picker.getImage(source: source);
if (pickedFile == null) return null; if (pickedFile == null) return null;
final File file = File(pickedFile.path); final file = File(pickedFile.path);
return widget.onImagePickCallback!(file); return widget.onImagePickCallback!(file);
} }
@ -536,11 +536,11 @@ class _ImageButtonState extends State<ImageButton> {
: null, : null,
)) ))
?.files; ?.files;
var _fileName = final _fileName =
_paths != null ? _paths!.map((e) => e.name).toString() : '...'; _paths != null ? _paths!.map((e) => e.name).toString() : '...';
if (_paths != null) { if (_paths != null) {
File file = File(_fileName); final file = File(_fileName);
// We simply return the absolute path to selected file. // We simply return the absolute path to selected file.
return widget.onImagePickCallback!(file); return widget.onImagePickCallback!(file);
} else { } else {
@ -550,7 +550,7 @@ class _ImageButtonState extends State<ImageButton> {
} }
Future<String> _pickImageDesktop() async { Future<String> _pickImageDesktop() async {
var filePath = await FilesystemPicker.open( final filePath = await FilesystemPicker.open(
context: context, context: context,
rootDirectory: await getApplicationDocumentsDirectory(), rootDirectory: await getApplicationDocumentsDirectory(),
fsType: FilesystemType.file, fsType: FilesystemType.file,
@ -558,7 +558,7 @@ class _ImageButtonState extends State<ImageButton> {
); );
if (filePath != null && filePath.isEmpty) return ''; if (filePath != null && filePath.isEmpty) return '';
final File file = File(filePath!); final file = File(filePath!);
return widget.onImagePickCallback!(file); return widget.onImagePickCallback!(file);
} }
@ -683,19 +683,19 @@ class _ColorButtonState extends State<ColorButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
Color? iconColor = _isToggledColor && !widget.background && !_isWhite final iconColor = _isToggledColor && !widget.background && !_isWhite
? stringToColor(_selectionStyle.attributes['color']!.value) ? stringToColor(_selectionStyle.attributes['color']!.value)
: theme.iconTheme.color; : theme.iconTheme.color;
var iconColorBackground = final iconColorBackground =
_isToggledBackground && widget.background && !_isWhitebackground _isToggledBackground && widget.background && !_isWhitebackground
? stringToColor(_selectionStyle.attributes['background']!.value) ? stringToColor(_selectionStyle.attributes['background']!.value)
: theme.iconTheme.color; : theme.iconTheme.color;
Color fillColor = _isToggledColor && !widget.background && _isWhite final fillColor = _isToggledColor && !widget.background && _isWhite
? stringToColor('#ffffff') ? stringToColor('#ffffff')
: theme.canvasColor; : theme.canvasColor;
Color fillColorBackground = final fillColorBackground =
_isToggledBackground && widget.background && _isWhitebackground _isToggledBackground && widget.background && _isWhitebackground
? stringToColor('#ffffff') ? stringToColor('#ffffff')
: theme.canvasColor; : theme.canvasColor;
@ -713,7 +713,7 @@ class _ColorButtonState extends State<ColorButton> {
} }
void _changeColor(Color color) { void _changeColor(Color color) {
String hex = color.value.toRadixString(16); var hex = color.value.toRadixString(16);
if (hex.startsWith('ff')) { if (hex.startsWith('ff')) {
hex = hex.substring(2); hex = hex.substring(2);
} }
@ -894,7 +894,7 @@ class _ClearFormatButtonState extends State<ClearFormatButton> {
icon: Icon(widget.icon, size: iconSize, color: iconColor), icon: Icon(widget.icon, size: iconSize, color: iconColor),
fillColor: fillColor, fillColor: fillColor,
onPressed: () { onPressed: () {
for (Attribute k for (final k
in widget.controller.getSelectionStyle().attributes.values) { in widget.controller.getSelectionStyle().attributes.values) {
widget.controller.formatSelection(Attribute.clone(k, null)); widget.controller.formatSelection(Attribute.clone(k, null));
} }

Loading…
Cancel
Save