fixed pos.rel cases

This commit is contained in:
Kevin Jahns 2021-11-21 19:53:53 +01:00
parent 40c3be1732
commit 2a33507c00
4 changed files with 65 additions and 9 deletions

View File

@ -55,11 +55,19 @@ export const useSearchMarker = (tr, yarray, index, f) => {
searchMarker.push(fsm) searchMarker.push(fsm)
} }
const diff = fsm.index - index const diff = fsm.index - index
// @todo create fresh marker if diff > index
if (diff > 0) { if (diff > 0) {
fsm.backward(tr, diff) fsm.backward(tr, diff)
} else { } else {
fsm.forward(tr, -diff) fsm.forward(tr, -diff)
} }
// @todo remove this tests
const otherTesting = new ListIterator(yarray)
otherTesting.forward(tr, index)
if (otherTesting.nextItem !== fsm.nextItem || otherTesting.index !== fsm.index || otherTesting.reachedEnd !== fsm.reachedEnd) {
throw new Error('udtirane')
}
const result = f(fsm) const result = f(fsm)
if (fsm.reachedEnd) { if (fsm.reachedEnd) {
fsm.reachedEnd = false fsm.reachedEnd = false
@ -93,7 +101,7 @@ export const useSearchMarker = (tr, yarray, index, f) => {
* @param {Array<ListIterator>} searchMarker * @param {Array<ListIterator>} searchMarker
* @param {number} index * @param {number} index
* @param {number} len If insertion, len is positive. If deletion, len is negative. * @param {number} len If insertion, len is positive. If deletion, len is negative.
* @param {ListIterator} origSearchMarker Do not update this searchmarker because it is the one we used to manipulate. * @param {ListIterator|null} origSearchMarker Do not update this searchmarker because it is the one we used to manipulate. @todo !=null for improved perf in ytext
*/ */
export const updateMarkerChanges = (searchMarker, index, len, origSearchMarker) => { export const updateMarkerChanges = (searchMarker, index, len, origSearchMarker) => {
for (let i = searchMarker.length - 1; i >= 0; i--) { for (let i = searchMarker.length - 1; i >= 0; i--) {

View File

@ -27,6 +27,7 @@ import {
updateMarkerChanges, updateMarkerChanges,
ContentType, ContentType,
useSearchMarker, useSearchMarker,
findIndexCleanStart,
ListIterator, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, ID, Doc, Item, Snapshot, Transaction // eslint-disable-line ListIterator, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, ID, Doc, Item, Snapshot, Transaction // eslint-disable-line
} from '../internals.js' } from '../internals.js'
@ -127,9 +128,27 @@ const findPosition = (transaction, parent, index) => {
const currentAttributes = new Map() const currentAttributes = new Map()
if (parent._searchMarker) { if (parent._searchMarker) {
return useSearchMarker(transaction, parent, index, listIter => { return useSearchMarker(transaction, parent, index, listIter => {
let left, right
if (listIter.rel > 0) {
// must exist because rel > 0
const nextItem = /** @type {Item} */ (listIter.nextItem)
if (listIter.rel === nextItem.length) {
left = nextItem
right = left.right
} else {
const structs = /** @type {Array<Item|GC>} */ (transaction.doc.store.clients.get(nextItem.id.client))
const after = /** @type {Item} */ (structs[findIndexCleanStart(transaction, structs, nextItem.id.clock + listIter.rel)])
listIter.nextItem = after
listIter.rel = 0
left = listIter.left
right = listIter.right
}
} else {
left = listIter.left
right = listIter.right
}
// @todo this should simply split if .rel > 0 // @todo this should simply split if .rel > 0
const pos = new ItemTextListPosition(listIter.left, listIter.right, listIter.index, currentAttributes) return new ItemTextListPosition(left, right, index, currentAttributes)
return findNextPosition(transaction, pos, index - listIter.index + listIter.rel)
}) })
} else { } else {
const pos = new ItemTextListPosition(null, parent._start, 0, currentAttributes) const pos = new ItemTextListPosition(null, parent._start, 0, currentAttributes)
@ -266,7 +285,7 @@ const insertText = (transaction, parent, currPos, text, attributes) => {
const content = text.constructor === String ? new ContentString(/** @type {string} */ (text)) : (text instanceof AbstractType ? new ContentType(text) : new ContentEmbed(text)) const content = text.constructor === String ? new ContentString(/** @type {string} */ (text)) : (text instanceof AbstractType ? new ContentType(text) : new ContentEmbed(text))
let { left, right, index } = currPos let { left, right, index } = currPos
if (parent._searchMarker) { if (parent._searchMarker) {
updateMarkerChanges(transaction, parent._searchMarker, currPos.index, content.getLength()) updateMarkerChanges(parent._searchMarker, currPos.index, content.getLength(), null)
} }
right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, content) right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, content)
right.integrate(transaction, 0) right.integrate(transaction, 0)
@ -471,7 +490,7 @@ const deleteText = (transaction, currPos, length) => {
} }
const parent = /** @type {AbstractType<any>} */ (/** @type {Item} */ (currPos.left || currPos.right).parent) const parent = /** @type {AbstractType<any>} */ (/** @type {Item} */ (currPos.left || currPos.right).parent)
if (parent._searchMarker) { if (parent._searchMarker) {
updateMarkerChanges(transaction, parent._searchMarker, currPos.index, -startLength + length) updateMarkerChanges(parent._searchMarker, currPos.index, -startLength + length, null)
} }
return currPos return currPos
} }

View File

@ -162,13 +162,18 @@ export class ListIterator {
/** /**
* @param {Transaction} tr * @param {Transaction} tr
* @param {number} len * @param {number} len
* @return {ListIterator}
*/ */
backward (tr, len) { backward (tr, len) {
if (this.index - len < 0) { if (this.index - len < 0) {
throw lengthExceeded throw lengthExceeded
} }
let item = this.nextItem && this.nextItem.left
this.index -= len this.index -= len
if (this.rel > len) {
this.rel -= len
return this
}
let item = this.nextItem && this.nextItem.left
if (this.rel) { if (this.rel) {
len -= this.rel len -= this.rel
this.rel = 0 this.rel = 0
@ -177,8 +182,10 @@ export class ListIterator {
if (item.countable && !item.deleted && item.moved === this.currMove) { if (item.countable && !item.deleted && item.moved === this.currMove) {
len -= item.length len -= item.length
if (len < 0) { if (len < 0) {
this.rel = item.length + len this.rel = -len
len = 0 len = 0
}
if (len === 0) {
break break
} }
} else if (item.content.constructor === ContentMove && item.moved === this.currMove) { } else if (item.content.constructor === ContentMove && item.moved === this.currMove) {
@ -201,8 +208,7 @@ export class ListIterator {
} }
item = item.left item = item.left
} }
this.index -= len this.nextItem = item
this.nextItem = item && item.right
return this return this
} }

View File

@ -373,6 +373,29 @@ export const compare = users => {
t.compare(Y.encodeStateVector(users[i]), Y.encodeStateVector(users[i + 1])) t.compare(Y.encodeStateVector(users[i]), Y.encodeStateVector(users[i + 1]))
compareDS(Y.createDeleteSetFromStructStore(users[i].store), Y.createDeleteSetFromStructStore(users[i + 1].store)) compareDS(Y.createDeleteSetFromStructStore(users[i].store), Y.createDeleteSetFromStructStore(users[i + 1].store))
compareStructStores(users[i].store, users[i + 1].store) compareStructStores(users[i].store, users[i + 1].store)
// test list-iterator
{
const user = users[0]
user.transact(tr => {
const type = user.getArray('array')
Y.useSearchMarker(tr, type, type.length, walker => {
for (let i = type.length; i >= 0; i--) {
const otherWalker = new Y.ListIterator(type)
otherWalker.forward(tr, walker.index)
otherWalker.forward(tr, 0)
walker.forward(tr, 0)
t.assert(walker.index === i)
t.assert(walker.left === otherWalker.left)
t.assert(walker.right === otherWalker.right)
t.assert(walker.nextItem === otherWalker.nextItem)
t.assert(walker.reachedEnd === otherWalker.reachedEnd)
if (i > 0) {
walker.backward(tr, 1)
}
}
})
})
}
} }
users.map(u => u.destroy()) users.map(u => u.destroy())
} }