Node.length, Node.offset caching added

pull/1964/head
Alspb 9 months ago
parent 13c549c304
commit 0abc4487ad
  1. 22
      lib/src/models/documents/nodes/container.dart
  2. 35
      lib/src/models/documents/nodes/leaf.dart
  3. 9
      lib/src/models/documents/nodes/line.dart
  4. 36
      lib/src/models/documents/nodes/node.dart

@ -47,11 +47,14 @@ abstract base class QuillContainer<T extends Node?> extends Node {
/// Always returns fresh instance.
T get defaultChild;
int? _length;
/// Adds [node] to the end of this container children list.
void add(T node) {
assert(node?.parent == null);
node?.parent = this;
_children.add(node as Node);
clearLengthCache();
}
/// Adds [node] to the beginning of this container children list.
@ -59,6 +62,7 @@ abstract base class QuillContainer<T extends Node?> extends Node {
assert(node?.parent == null);
node?.parent = this;
_children.addFirst(node as Node);
clearLengthCache();
}
/// Removes [node] from this container.
@ -66,6 +70,7 @@ abstract base class QuillContainer<T extends Node?> extends Node {
assert(node?.parent == this);
node?.parent = null;
_children.remove(node as Node);
clearLengthCache();
}
/// Moves children of this node to [newParent].
@ -118,11 +123,20 @@ abstract base class QuillContainer<T extends Node?> extends Node {
.map((e) => e.toPlainText(embedBuilders, unknownEmbedBuilder))
.join();
/// Content length of this node's children.
///
/// To get number of children in this node use [childCount].
@override
int get length => _children.fold(0, (cur, node) => cur + node.length);
int get length {
_length ??= _children.fold(0, (cur, node) => (cur ?? 0) + node.length);
return _length!;
}
@override
void clearLengthCache() {
_length = null;
clearOffsetCache();
if (parent != null) {
parent!.clearLengthCache();
}
}
@override
void insert(int index, Object data, Style? style) {

@ -24,18 +24,39 @@ abstract base class Leaf extends Node {
/// Contents of this node, either a String if this is a [QuillText] or an
/// [Embed] if this is an [BlockEmbed].
Object get value => _value;
set value(Object v) {
_value = v;
_length = null;
clearOffsetCache();
}
Object _value;
@override
Line? get parent => super.parent as Line?;
int? _length;
@override
int get length {
if (_length != null) {
return _length!;
}
if (_value is String) {
return (_value as String).length;
_length = (_value as String).length;
} else {
// return 1 for embedded object
_length = 1;
}
return _length!;
}
@override
void clearLengthCache() {
if (parent != null) {
parent!.clearLengthCache();
}
// return 1 for embedded object
return 1;
}
@override
@ -47,6 +68,7 @@ abstract base class Leaf extends Node {
@override
void insert(int index, Object data, Style? style) {
final length = this.length;
assert(index >= 0 && index <= length);
final node = Leaf(data);
if (index < length) {
@ -75,6 +97,7 @@ abstract base class Leaf extends Node {
@override
void delete(int index, int? len) {
final length = this.length;
assert(index < length);
final local = math.min(length - index, len!);
@ -117,7 +140,7 @@ abstract base class Leaf extends Node {
// Merging it with previous node if style is the same.
final prev = node.previous;
if (!node.isFirst && prev is QuillText && prev.style == node.style) {
prev._value = prev.value + node.value;
prev.value = prev.value + node.value;
node.unlink();
node = prev;
}
@ -125,7 +148,7 @@ abstract base class Leaf extends Node {
// Merging it with next node if style is the same.
final next = node.next;
if (!node.isLast && next is QuillText && next.style == node.style) {
node._value = node.value + next.value;
node.value = node.value + next.value;
next.unlink();
}
}
@ -152,7 +175,7 @@ abstract base class Leaf extends Node {
assert(this is QuillText);
final text = _value as String;
_value = text.substring(0, index);
value = text.substring(0, index);
final split = Leaf(text.substring(index))..applyStyle(style);
insertAfter(split);
return split;

@ -127,11 +127,11 @@ base class Line extends QuillContainer<Leaf?> {
if (style == null) {
return;
}
final thisLength = length;
final length = this.length;
final local = math.min(thisLength - index, len!);
final local = math.min(length - index, len!);
// If index is at newline character then this is a line/block style update.
final isLineFormat = (index + local == thisLength) && local == 1;
final isLineFormat = (index + local == length) && local == 1;
if (isLineFormat) {
assert(
@ -145,7 +145,7 @@ base class Line extends QuillContainer<Leaf?> {
assert(style.values.every((attr) =>
attr.scope == AttributeScope.inline ||
attr.scope == AttributeScope.ignore));
assert(index + local != thisLength);
assert(index + local != length);
super.retain(index, local, style);
}
@ -158,6 +158,7 @@ base class Line extends QuillContainer<Leaf?> {
@override
void delete(int index, int? len) {
final length = this.length;
final local = math.min(length - index, len!);
final isLFDeleted = index + local == length; // Line feed
if (isLFDeleted) {

@ -47,24 +47,41 @@ abstract base class Node extends LinkedListEntry<Node> {
/// Length of this node in characters.
int get length;
void clearLengthCache();
Node clone() => newInstance()..applyStyle(style);
int? _offset;
/// Offset in characters of this node relative to [parent] node.
///
/// To get offset of this node in the document see [documentOffset].
int get offset {
var offset = 0;
if (_offset != null) {
return _offset!;
}
if (list == null || isFirst) {
return offset;
return 0;
}
var offset = 0;
for (final node in list!) {
if (node == this) {
break;
}
offset += node.length;
}
var cur = this;
do {
cur = cur.previous!;
offset += cur.length;
} while (!cur.isFirst);
return offset;
_offset = offset;
return _offset!;
}
void clearOffsetCache() {
_offset = null;
final next = this.next;
if (next != null) {
next.clearOffsetCache();
}
}
/// Offset in characters of this node in the document.
@ -100,6 +117,7 @@ abstract base class Node extends LinkedListEntry<Node> {
assert(entry.parent == null && parent != null);
entry.parent = parent;
super.insertBefore(entry);
clearLengthCache();
}
@override
@ -107,11 +125,13 @@ abstract base class Node extends LinkedListEntry<Node> {
assert(entry.parent == null && parent != null);
entry.parent = parent;
super.insertAfter(entry);
clearLengthCache();
}
@override
void unlink() {
assert(parent != null);
clearLengthCache();
parent = null;
super.unlink();
}

Loading…
Cancel
Save