-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Iterator peek next #26
base: master
Are you sure you want to change the base?
Conversation
int _docIndex = 0; // index in the current document | ||
|
||
// Makes an independent copy of this iterator | ||
DeltaIterator clone() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clone and resetTo are needed to be able to store a position or go back in time.
50bfece
to
03f7c8b
Compare
_docIndex = it._docIndex; | ||
} | ||
|
||
static Operation end() => Operation.retain(maxLength); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this just be null or Operation.retain(-1) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or anything that Operation can express as invalid
final opActualLength = opIsNotEmpty ? opLength : actualLength; | ||
return Operation._(opKey, opActualLength, opData, opAttributes); | ||
if (_index >= delta.length) { | ||
return end(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it used to return Operation.retain(length) which sound like a hack to me.
can we return null or Operation.retain(-1). I mean anything invalid... (I understand null is probably very inpractical)
Zefyr/Notus needs very little adjustment after this changes. (4 lines needs to be changed) (and they become more understandable)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this idea! I'm thinking we can use Operation.insert with a special data
value, e.g. create constant and use it:
class _EOF {
const _EOF();
}
const _eof = _EOF();
// Then in the iterator
return Operation.insert('insert', 1, _eof);
Can also add Operation.isEof
to allow easy checking for this.
That said, I'd prefer for this change to be a separate PR, if you don't mind. There is already a lot of new changes here which makes it hard to review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks this looks impressive!
It took me a while to digest everything here but I have a couple of concerns about the new APIs introduced by this change (specifically rewind is something I'd prefer to avoid).
I also believe we can achieve similar results with a bit simpler solution. It'd only require one additional method on the iterator - peek
, which is similar to peekLength
but returns the actual operation instead of just length. E.g.:
Operation peek() {
if (_index < delta.length) {
final op = delta._operations[_index];
if (_offset == 0) return op;
return Operation._(op.key, op.length, op.data, op.attributes);
}
return Operation.retain(maxLength);
}
Next we can implement both skipToLineAtIndex
and skipToEndOfLine
using existing methods of the iterator. One important change is that I suggest tweak the return type of these functions.
A semi-pseudo code of both of these is below:
/// Skips [length] characters in source delta and returns contents of the last
/// line up until [length].
/// The returned list of operations can be used to compose the text prefix pretty easily
///
/// Only makes sense to use on a document delta (containing only insert operations).
List<Operation> skipToLineAt(DeltaIterator iter, int length) {
assert(length > 0);
final prefix = <Operation>[];
var skipped = 0;
while (skipped < length && iter.hasNext) {
final opLength = iter.peekLength();
final skip = math.min(length - skipped, opLength);
final op = iter.next(skip);
if (op.data is! String) {
prefix.add(op);
} else {
var text = op.data as String;
var pos = text.lastIndexOf('\n');
if (pos == -1) {
prefix.add(op);
} else {
prefix.clear();
prefix.add(Operation.insert(text.substring(pos + 1), op.attributes));
}
}
skipped += op.length;
}
return prefix;
}
/// Skips to the end of current line and returns all skipped operations
/// including operation containing the newline character.
/// The returned list of operations can be used to find the total skipped length
///
/// Only makes sense to use on a document delta (containing only insert operations).
List<Operation> skipToEndOfLine(DeltaIterator iter) {
assert(iter.hasNext);
final result = <Operation>[];
while (iter.hasNext) {
final op = iter.peek();
if (op.data is! String) {
result.add(op);
iter.next();
continue;
}
final text = op.data as String;
final pos = text.indexOf('\n');
if (pos == -1) {
result.add(op);
iter.next();
continue;
}
result.add(iter.next(pos + 1));
}
return result;
}
I still think that these two functions better to keep in Zefyr as these have a narrower use and only make sense for document deltas (only insert ops).
Sorry for dragging you into a different direction here, hope it makes sense. WDYT?
_DeltaIteratorState( | ||
{required this.index, required this.offset, required this.docIndex}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to be used anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left over from implementing peekNext 😅
final opActualLength = opIsNotEmpty ? opLength : actualLength; | ||
return Operation._(opKey, opActualLength, opData, opAttributes); | ||
if (_index >= delta.length) { | ||
return end(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this idea! I'm thinking we can use Operation.insert with a special data
value, e.g. create constant and use it:
class _EOF {
const _EOF();
}
const _eof = _EOF();
// Then in the iterator
return Operation.insert('insert', 1, _eof);
Can also add Operation.isEof
to allow easy checking for this.
That said, I'd prefer for this change to be a separate PR, if you don't mind. There is already a lot of new changes here which makes it hard to review.
I can move the extension in Notus. No issue. I believe they should just exist somewhere cause they are a pain in the ass to write. I did implement peek before but it makes the code that uses it hard to grok. And peek now is:
Also I believe skipToBeginningOfLineBeforeIndex would be more optimised if we skip to index and then look backward. Otherwise we look for \n on every single line from start of doc. |
For EOF I like the idea too. Will implement in a future PR. |
acd5047
to
b8c13d5
Compare
@@ -652,19 +656,17 @@ class Delta { | |||
|
|||
/// Returns slice of this delta from [start] index (inclusive) to [end] | |||
/// (exclusive). | |||
Delta slice(int start, [int? end]) { | |||
Delta slice(int start, [int end = DeltaIterator.maxLength]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just simplification of the code. no logic changes
Codecov Report
@@ Coverage Diff @@
## master #26 +/- ##
===========================================
- Coverage 93.56% 83.08% -10.49%
===========================================
Files 1 1
Lines 342 396 +54
===========================================
+ Hits 320 329 +9
- Misses 22 67 +45
Continue to review full report at Codecov.
|
b8c13d5
to
97b9fbc
Compare
Please review. Some changes may be better done in another way.
This PR is needed to support Markdown auto formatting rules in Notus.