Hi,
I’m trying to implement something like “interactive diff mode”: when user deletes text, I leave the text where it was, but apply red background. This works fine and undo works out of the box, but I’m struggling with redo. I tried to follow inverted effects example, but my invert
function does not receive any transactions with effects.
This is my state effect:
const markDeletion = StateEffect.define<{ from: number, to: number }>({
map: ({ from, to }, change) => ({ from: change.mapPos(from), to: change.mapPos(to) })
});
// and this is inverted version, just in case:
const unmarkDeletion = StateEffect.define<{ from: number, to: number }>({
map: ({ from, to }, change) => ({ from: change.mapPos(from), to: change.mapPos(to) })
})
StateField is:
export const deletions = StateField.define({
create(state) {
return Decoration.none;
},
update(deletions, transaction) {
deletions = deletions.map(transaction.changes);
for (let e of transaction.effects) {
if (e.is(markDeletion)) {
// This applies the Decoration
deletions = deletions.update({ add: [removedText.range(e.value.from, e.value.to)] })
continue
}
}
return deletions
},
provide: f => EditorView.decorations.from(f)
});
And here’s the function I call to apply the effect on delete
UserEffect:
function onDelete(transaction: Transaction) {
const changes = transaction.changes.invert(transaction.startState.doc);
const effects: StateEffect<unknown>[] = [];
changes.iterChangedRanges((fromA, toA, fromB, toB) => {
effects.push(markDeletion.of({ from: fromB, to: toB }));
});
return { changes, effects };
}
I use transaction.changes.invert
to get the deleted text back into the document. Now the below function is my handler for inverted effects and it only console.log
s effect for the first transaction (when the user removes text), never for undo and never (and I guess this is the problem) for redo:
const invert = invertedEffects.of((transaction) => {
const inverted: StateEffect<unknown>[] = [];
transaction.effects
.forEach((effect) => {
console.log(effect);
if (effect.is(markDeletion)) {
inverted.push(unmarkDeletion.of(effect.value));
return;
}
if (effect.is(unmarkDeletion)) {
inverted.push(markDeletion.of(effect.value))
return;
}
});
return inverted
}
Any help is appreciated, as I’m struggling with this problem for few days now. I think that the issue is that I’m reinserting the text, but I’m not sure. Thanks.