Skip to content

Commit

Permalink
fix(headingAnchor): Rebuild decorationSet in case of replacements
Browse files Browse the repository at this point in the history
When the whole document gets replaced by the same content,
`DecorationSet.map()` returns an empty decorationSet. So only use it for
updates where no decorations get removed.

Signed-off-by: Jonas <jonas@freesources.org>
  • Loading branch information
mejo- committed Jul 25, 2024
1 parent 82e0999 commit ea2e93d
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
4 changes: 4 additions & 0 deletions cypress/e2e/conflict.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ variants.forEach(function({ fixture, mime }) {
})
})

/**
* @param {string} fileName - filename
* @param {string} mime - mimetype
*/
function createConflict(fileName, mime) {
cy.visit('/apps/files')
cy.openFile(fileName)
Expand Down
30 changes: 26 additions & 4 deletions src/plugins/headingAnchor.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default function headingAnchor() {

state: {
init(_, { doc }) {
console.debug('headingAnchor init')
const headings = extractHeadings(doc)
return {
headings,
Expand All @@ -33,9 +34,7 @@ export default function headingAnchor() {
return value
}
const headings = extractHeadings(newState.doc)
const decorations = headingsChanged(headings, value.headings)
? anchorDecorations(newState.doc, headings)
: value.decorations.map(tr.mapping, tr.doc)
const decorations = mapDecorations(value, tr, headings) || anchorDecorations(newState.doc, headings)
return { headings, decorations }
},
},
Expand All @@ -48,11 +47,34 @@ export default function headingAnchor() {
})
}

/**
* Map the previous decorations to current document state.
*
* Return false if headings changed or decorations would get removed.
* The latter prevents lost decorations in case of replacements.
*
* @param {object} value - previous plugin state
* @param {object} tr - current transaction
* @param {Array} headings - array of headings
*
* @return {false|DecorationSet}
*/
function mapDecorations(value, tr, headings) {
if (headingsChanged(headings, value.headings)) {
return false
}
let removedDecorations = false
const decorations = value.decorations.map(tr.mapping, tr.doc, { onRemove: () => { removedDecorations = true } })
return removedDecorations
? false
: decorations
}

/**
* Check if the headings provided are equivalent.
*
* @param {Array} current - array of headings
* @param {Array} other - headings to compare against
* @param {Array} prev - headings to compare against
*
* @return {boolean}
*/
Expand Down

0 comments on commit ea2e93d

Please sign in to comment.