Include Item.redone
in binary encoding
This commit is contained in:
parent
384ec4db78
commit
1cfc865045
@ -93,6 +93,7 @@ export const splitItem = (transaction, leftItem, diff) => {
|
||||
leftItem.rightOrigin,
|
||||
leftItem.parent,
|
||||
leftItem.parentSub,
|
||||
leftItem.redone !== null ? createID(leftItem.redone.client, leftItem.redone.clock + diff) : null,
|
||||
leftItem.content.splice(diff)
|
||||
)
|
||||
if (leftItem.deleted) {
|
||||
@ -101,9 +102,6 @@ export const splitItem = (transaction, leftItem, diff) => {
|
||||
if (leftItem.keep) {
|
||||
rightItem.keep = true
|
||||
}
|
||||
if (leftItem.redone !== null) {
|
||||
rightItem.redone = createID(leftItem.redone.client, leftItem.redone.clock + diff)
|
||||
}
|
||||
// update left (do not set leftItem.rightOrigin as it will lead to problems when syncing)
|
||||
leftItem.right = rightItem
|
||||
// update right
|
||||
@ -232,6 +230,7 @@ export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemo
|
||||
right, right && right.id,
|
||||
parentType,
|
||||
item.parentSub,
|
||||
null,
|
||||
item.content.copy()
|
||||
)
|
||||
item.redone = nextId
|
||||
@ -252,9 +251,10 @@ export class Item extends AbstractStruct {
|
||||
* @param {ID | null} rightOrigin
|
||||
* @param {AbstractType<any>|ID|null} parent Is a type if integrated, is null if it is possible to copy parent from left or right, is ID before integration to search for it.
|
||||
* @param {string | null} parentSub
|
||||
* @param {ID | null} redone
|
||||
* @param {AbstractContent} content
|
||||
*/
|
||||
constructor (id, left, origin, right, rightOrigin, parent, parentSub, content) {
|
||||
constructor (id, left, origin, right, rightOrigin, parent, parentSub, redone, content) {
|
||||
super(id, content.getLength())
|
||||
/**
|
||||
* The item that was originally to the left of this item.
|
||||
@ -293,7 +293,7 @@ export class Item extends AbstractStruct {
|
||||
* this operation.
|
||||
* @type {ID | null}
|
||||
*/
|
||||
this.redone = null
|
||||
this.redone = redone
|
||||
/**
|
||||
* @type {AbstractContent}
|
||||
*/
|
||||
@ -653,10 +653,11 @@ export class Item extends AbstractStruct {
|
||||
const origin = offset > 0 ? createID(this.id.client, this.id.clock + offset - 1) : this.origin
|
||||
const rightOrigin = this.rightOrigin
|
||||
const parentSub = this.parentSub
|
||||
const info = (this.content.getRef() & binary.BITS5) |
|
||||
const info = (this.content.getRef() & binary.BITS4) |
|
||||
(origin === null ? 0 : binary.BIT8) | // origin is defined
|
||||
(rightOrigin === null ? 0 : binary.BIT7) | // right origin is defined
|
||||
(parentSub === null ? 0 : binary.BIT6) // parentSub is non-null
|
||||
(parentSub === null ? 0 : binary.BIT6) | // parentSub is non-null
|
||||
(this.redone === null ? 0 : binary.BIT5) // redone is defined
|
||||
encoder.writeInfo(info)
|
||||
if (origin !== null) {
|
||||
encoder.writeLeftID(origin)
|
||||
@ -691,6 +692,9 @@ export class Item extends AbstractStruct {
|
||||
encoder.writeString(parentSub)
|
||||
}
|
||||
}
|
||||
if (this.redone !== null) {
|
||||
encoder.writeRedone(this.redone)
|
||||
}
|
||||
this.content.write(encoder, offset)
|
||||
}
|
||||
}
|
||||
@ -699,7 +703,7 @@ export class Item extends AbstractStruct {
|
||||
* @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
|
||||
* @param {number} info
|
||||
*/
|
||||
export const readItemContent = (decoder, info) => contentRefs[info & binary.BITS5](decoder)
|
||||
export const readItemContent = (decoder, info) => contentRefs[info & binary.BITS4](decoder)
|
||||
|
||||
/**
|
||||
* A lookup map for reading Item content.
|
||||
|
@ -643,7 +643,7 @@ export const typeListInsertGenericsAfter = (transaction, parent, referenceItem,
|
||||
let jsonContent = []
|
||||
const packJsonContent = () => {
|
||||
if (jsonContent.length > 0) {
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentAny(jsonContent))
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, null, new ContentAny(jsonContent))
|
||||
left.integrate(transaction, 0)
|
||||
jsonContent = []
|
||||
}
|
||||
@ -665,16 +665,16 @@ export const typeListInsertGenericsAfter = (transaction, parent, referenceItem,
|
||||
switch (c.constructor) {
|
||||
case Uint8Array:
|
||||
case ArrayBuffer:
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentBinary(new Uint8Array(/** @type {Uint8Array} */ (c))))
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, null, new ContentBinary(new Uint8Array(/** @type {Uint8Array} */ (c))))
|
||||
left.integrate(transaction, 0)
|
||||
break
|
||||
case Doc:
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentDoc(/** @type {Doc} */ (c)))
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, null, new ContentDoc(/** @type {Doc} */ (c)))
|
||||
left.integrate(transaction, 0)
|
||||
break
|
||||
default:
|
||||
if (c instanceof AbstractType) {
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentType(c))
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, null, new ContentType(c))
|
||||
left.integrate(transaction, 0)
|
||||
} else {
|
||||
throw new Error('Unexpected content type in insert operation')
|
||||
@ -862,7 +862,7 @@ export const typeMapSet = (transaction, parent, key, value) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, null, null, parent, key, content).integrate(transaction, 0)
|
||||
new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, null, null, parent, key, null, content).integrate(transaction, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,7 +166,7 @@ const insertNegatedAttributes = (transaction, parent, currPos, negatedAttributes
|
||||
negatedAttributes.forEach((val, key) => {
|
||||
const left = currPos.left
|
||||
const right = currPos.right
|
||||
const nextFormat = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val))
|
||||
const nextFormat = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, null, new ContentFormat(key, val))
|
||||
nextFormat.integrate(transaction, 0)
|
||||
currPos.right = nextFormat
|
||||
currPos.forward()
|
||||
@ -232,7 +232,7 @@ const insertAttributes = (transaction, parent, currPos, attributes) => {
|
||||
// save negated attribute (set null if currentVal undefined)
|
||||
negatedAttributes.set(key, currentVal)
|
||||
const { left, right } = currPos
|
||||
currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentFormat(key, val))
|
||||
currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, null, new ContentFormat(key, val))
|
||||
currPos.right.integrate(transaction, 0)
|
||||
currPos.forward()
|
||||
}
|
||||
@ -266,7 +266,7 @@ const insertText = (transaction, parent, currPos, text, attributes) => {
|
||||
if (parent._searchMarker) {
|
||||
updateMarkerChanges(parent._searchMarker, currPos.index, content.getLength())
|
||||
}
|
||||
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, null, content)
|
||||
right.integrate(transaction, 0)
|
||||
currPos.right = right
|
||||
currPos.index = index
|
||||
@ -342,7 +342,7 @@ const formatText = (transaction, parent, currPos, length, attributes) => {
|
||||
for (; length > 0; length--) {
|
||||
newlines += '\n'
|
||||
}
|
||||
currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), currPos.left, currPos.left && currPos.left.lastId, currPos.right, currPos.right && currPos.right.id, parent, null, new ContentString(newlines))
|
||||
currPos.right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), currPos.left, currPos.left && currPos.left.lastId, currPos.right, currPos.right && currPos.right.id, parent, null, null, new ContentString(newlines))
|
||||
currPos.right.integrate(transaction, 0)
|
||||
currPos.forward()
|
||||
}
|
||||
|
@ -46,6 +46,13 @@ export class UpdateDecoderV1 extends DSDecoderV1 {
|
||||
return createID(decoding.readVarUint(this.restDecoder), decoding.readVarUint(this.restDecoder))
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {ID}
|
||||
*/
|
||||
readRedone () {
|
||||
return createID(decoding.readVarUint(this.restDecoder), decoding.readVarUint(this.restDecoder))
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the next client id.
|
||||
* Use this in favor of readID whenever possible to reduce the number of objects created.
|
||||
@ -174,6 +181,7 @@ export class UpdateDecoderV2 extends DSDecoderV2 {
|
||||
this.clientDecoder = new decoding.UintOptRleDecoder(decoding.readVarUint8Array(decoder))
|
||||
this.leftClockDecoder = new decoding.IntDiffOptRleDecoder(decoding.readVarUint8Array(decoder))
|
||||
this.rightClockDecoder = new decoding.IntDiffOptRleDecoder(decoding.readVarUint8Array(decoder))
|
||||
this.redoneClockDecoder = new decoding.IntDiffOptRleDecoder(decoding.readVarUint8Array(decoder))
|
||||
this.infoDecoder = new decoding.RleDecoder(decoding.readVarUint8Array(decoder), decoding.readUint8)
|
||||
this.stringDecoder = new decoding.StringDecoder(decoding.readVarUint8Array(decoder))
|
||||
this.parentInfoDecoder = new decoding.RleDecoder(decoding.readVarUint8Array(decoder), decoding.readUint8)
|
||||
@ -195,6 +203,13 @@ export class UpdateDecoderV2 extends DSDecoderV2 {
|
||||
return new ID(this.clientDecoder.read(), this.rightClockDecoder.read())
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {ID}
|
||||
*/
|
||||
readRedone () {
|
||||
return new ID(this.clientDecoder.read(), this.redoneClockDecoder.read())
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the next client id.
|
||||
* Use this in favor of readID whenever possible to reduce the number of objects created.
|
||||
|
@ -50,6 +50,14 @@ export class UpdateEncoderV1 extends DSEncoderV1 {
|
||||
encoding.writeVarUint(this.restEncoder, id.clock)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ID} id
|
||||
*/
|
||||
writeRedone (id) {
|
||||
encoding.writeVarUint(this.restEncoder, id.client)
|
||||
encoding.writeVarUint(this.restEncoder, id.clock)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use writeClient and writeClock instead of writeID if possible.
|
||||
* @param {number} client
|
||||
@ -177,6 +185,7 @@ export class UpdateEncoderV2 extends DSEncoderV2 {
|
||||
this.clientEncoder = new encoding.UintOptRleEncoder()
|
||||
this.leftClockEncoder = new encoding.IntDiffOptRleEncoder()
|
||||
this.rightClockEncoder = new encoding.IntDiffOptRleEncoder()
|
||||
this.redoneClockEncoder = new encoding.IntDiffOptRleEncoder()
|
||||
this.infoEncoder = new encoding.RleEncoder(encoding.writeUint8)
|
||||
this.stringEncoder = new encoding.StringEncoder()
|
||||
this.parentInfoEncoder = new encoding.RleEncoder(encoding.writeUint8)
|
||||
@ -191,6 +200,7 @@ export class UpdateEncoderV2 extends DSEncoderV2 {
|
||||
encoding.writeVarUint8Array(encoder, this.clientEncoder.toUint8Array())
|
||||
encoding.writeVarUint8Array(encoder, this.leftClockEncoder.toUint8Array())
|
||||
encoding.writeVarUint8Array(encoder, this.rightClockEncoder.toUint8Array())
|
||||
encoding.writeVarUint8Array(encoder, this.redoneClockEncoder.toUint8Array())
|
||||
encoding.writeVarUint8Array(encoder, encoding.toUint8Array(this.infoEncoder))
|
||||
encoding.writeVarUint8Array(encoder, this.stringEncoder.toUint8Array())
|
||||
encoding.writeVarUint8Array(encoder, encoding.toUint8Array(this.parentInfoEncoder))
|
||||
@ -217,6 +227,14 @@ export class UpdateEncoderV2 extends DSEncoderV2 {
|
||||
this.rightClockEncoder.write(id.clock)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ID} id
|
||||
*/
|
||||
writeRedone (id) {
|
||||
this.clientEncoder.write(id.client)
|
||||
this.redoneClockEncoder.write(id.clock)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} client
|
||||
*/
|
||||
|
@ -127,7 +127,7 @@ export const readClientsStructRefs = (decoder, doc) => {
|
||||
clientRefs.set(client, { i: 0, refs })
|
||||
for (let i = 0; i < numberOfStructs; i++) {
|
||||
const info = decoder.readInfo()
|
||||
switch (binary.BITS5 & info) {
|
||||
switch (binary.BITS4 & info) {
|
||||
case 0: { // GC
|
||||
const len = decoder.readLen()
|
||||
refs[i] = new GC(createID(client, clock), len)
|
||||
@ -160,6 +160,7 @@ export const readClientsStructRefs = (decoder, doc) => {
|
||||
(info & binary.BIT7) === binary.BIT7 ? decoder.readRightID() : null, // right origin
|
||||
cantCopyParentInfo ? (decoder.readParentInfo() ? doc.get(decoder.readString()) : decoder.readLeftID()) : null, // parent
|
||||
cantCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub
|
||||
(info & binary.BIT5) === binary.BIT5 ? decoder.readRedone() : null, // redone
|
||||
readItemContent(decoder, info) // item content
|
||||
)
|
||||
/* A non-optimized implementation of the above algorithm:
|
||||
@ -184,6 +185,7 @@ export const readClientsStructRefs = (decoder, doc) => {
|
||||
rightOrigin, // right origin
|
||||
cantCopyParentInfo && !hasParentYKey ? decoder.readLeftID() : (parentYKey !== null ? doc.get(parentYKey) : null), // parent
|
||||
cantCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub
|
||||
(info & binary.BIT5) === binary.BIT5 ? decoder.readRedone() : null, // redone
|
||||
readItemContent(decoder, info) // item content
|
||||
)
|
||||
*/
|
||||
|
@ -53,7 +53,7 @@ function * lazyStructReaderGenerator (decoder) {
|
||||
const len = decoding.readVarUint(decoder.restDecoder)
|
||||
yield new Skip(createID(client, clock), len)
|
||||
clock += len
|
||||
} else if ((binary.BITS5 & info) !== 0) {
|
||||
} else if ((binary.BITS4 & info) !== 0) {
|
||||
const cantCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0
|
||||
// If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
|
||||
// and we read the next string as parentYKey.
|
||||
@ -68,6 +68,7 @@ function * lazyStructReaderGenerator (decoder) {
|
||||
// @ts-ignore Force writing a string here.
|
||||
cantCopyParentInfo ? (decoder.readParentInfo() ? decoder.readString() : decoder.readLeftID()) : null, // parent
|
||||
cantCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub
|
||||
(info & binary.BIT5) === binary.BIT5 ? decoder.readRedone() : null, // redone
|
||||
readItemContent(decoder, info) // item content
|
||||
)
|
||||
yield struct
|
||||
@ -316,6 +317,7 @@ const sliceStruct = (left, diff) => {
|
||||
leftItem.rightOrigin,
|
||||
leftItem.parent,
|
||||
leftItem.parentSub,
|
||||
null,
|
||||
leftItem.content.splice(diff)
|
||||
)
|
||||
}
|
||||
|
@ -120,6 +120,6 @@ export const testRelativePositionWithUndo = tc => {
|
||||
t.assert(Y.createAbsolutePositionFromRelativePosition(rpos, ydoc, false)?.index === 6)
|
||||
const ydocClone = new Y.Doc()
|
||||
Y.applyUpdate(ydocClone, Y.encodeStateAsUpdate(ydoc))
|
||||
t.assert(Y.createAbsolutePositionFromRelativePosition(rpos, ydocClone)?.index === 6)
|
||||
t.assert(Y.createAbsolutePositionFromRelativePosition(rpos, ydocClone)?.index === 1)
|
||||
t.assert(Y.createAbsolutePositionFromRelativePosition(rpos, ydocClone, false)?.index === 6)
|
||||
}
|
||||
|
@ -2079,7 +2079,7 @@ export const testBestCase = _tc => {
|
||||
/**
|
||||
* @type {Y.Item}
|
||||
*/
|
||||
const n = new Y.Item(Y.createID(0, 0), null, null, null, null, null, null, c)
|
||||
const n = new Y.Item(Y.createID(0, 0), null, null, null, null, null, null, null, c)
|
||||
// items.push(n)
|
||||
items[i] = n
|
||||
n.right = prevItem
|
||||
|
Loading…
x
Reference in New Issue
Block a user