scan the document once for all ytexts when cleaning up

Fixes #522 but is a scarier change
This commit is contained in:
Noel Levy 2023-06-12 18:20:06 -07:00
parent 3741f43a11
commit 08801dd406
2 changed files with 33 additions and 40 deletions

View File

@ -862,47 +862,42 @@ export class YText extends AbstractType {
callTypeObservers(this, transaction, event) callTypeObservers(this, transaction, event)
// If a remote change happened, we try to cleanup potential formatting duplicates. // If a remote change happened, we try to cleanup potential formatting duplicates.
if (!transaction.local) { if (!transaction.local) {
transaction._yTexts.push(this) transaction._yTexts.add(this)
} }
} }
/** /**
* @param {Transaction} transaction * @param {Transaction} transaction
*/ */
_cleanup (transaction) { static _cleanup (transaction) {
if (!transaction.local) { const withFormattingItems = new Set()
// check if another formatting item was inserted // check if another formatting item was inserted
let foundFormattingItem = false const doc = transaction.doc
const doc = transaction.doc for (const [client, afterClock] of transaction.afterState.entries()) {
for (const [client, afterClock] of transaction.afterState.entries()) { const clock = transaction.beforeState.get(client) || 0
const clock = transaction.beforeState.get(client) || 0 if (afterClock === clock) {
if (afterClock === clock) { continue
continue
}
iterateStructs(transaction, /** @type {Array<Item|GC>} */ (doc.store.clients.get(client)), clock, afterClock, item => {
if (!item.deleted && /** @type {Item} */ (item).content.constructor === ContentFormat) {
foundFormattingItem = true
}
})
if (foundFormattingItem) {
break
}
} }
if (!foundFormattingItem) { iterateStructs(transaction, /** @type {Array<Item|GC>} */ (doc.store.clients.get(client)), clock, afterClock, item => {
iterateDeletedStructs(transaction, transaction.deleteSet, item => { if (!item.deleted && /** @type {Item} */ (item).content.constructor === ContentFormat && !(item instanceof GC) && transaction._yTexts.has(/** @type YText */ (item.parent))) {
if (item instanceof GC || foundFormattingItem) { withFormattingItems.add(item.parent)
return }
} })
if (item.parent === this && item.content.constructor === ContentFormat) { }
foundFormattingItem = true iterateDeletedStructs(transaction, transaction.deleteSet, item => {
} if (item instanceof GC) {
}) return
} }
transact(doc, (t) => { if (transaction._yTexts.has(/** @type YText */ (item.parent)) && item.content.constructor === ContentFormat) {
if (foundFormattingItem) { withFormattingItems.add(item.parent)
}
})
transact(doc, (t) => {
for (const yText of transaction._yTexts) {
if (withFormattingItems.has(yText)) {
// If a formatting item was inserted, we simply clean the whole type. // If a formatting item was inserted, we simply clean the whole type.
// We need to compute currentAttributes for the current position anyway. // We need to compute currentAttributes for the current position anyway.
cleanupYTextFormatting(this) cleanupYTextFormatting(yText)
} else { } else {
// If no formatting attribute was inserted, we can make due with contextless // If no formatting attribute was inserted, we can make due with contextless
// formatting cleanups. // formatting cleanups.
@ -911,13 +906,13 @@ export class YText extends AbstractType {
if (item instanceof GC) { if (item instanceof GC) {
return return
} }
if (item.parent === this) { if (item.parent === yText) {
cleanupContextlessFormattingGap(t, item) cleanupContextlessFormattingGap(t, item)
} }
}) })
} }
}) }
} })
} }
/** /**

View File

@ -115,9 +115,9 @@ export class Transaction {
*/ */
this.subdocsLoaded = new Set() this.subdocsLoaded = new Set()
/** /**
* @type {Array<YText>} * @type {Set<YText>}
*/ */
this._yTexts = [] this._yTexts = new Set()
} }
} }
@ -299,11 +299,9 @@ const cleanupTransactions = (transactionCleanups, i) => {
fs.push(() => doc.emit('afterTransaction', [transaction, doc])) fs.push(() => doc.emit('afterTransaction', [transaction, doc]))
}) })
callAll(fs, []) callAll(fs, [])
if (transaction._yTexts.length > 0) { if (transaction._yTexts.size > 0) {
transact(doc, () => { transact(doc, () => {
transaction._yTexts.forEach(yText => { YText._cleanup(transaction)
yText._cleanup(transaction)
})
}) })
} }
} finally { } finally {