Is there a reason why you’re using multiple plugins instead of one plugin if there is duplicated logic?
The easy answer here would be to use the setMeta
property to specify which character you want:
const charReplace = new PluginKey("charReplace")
const charReplacePlugin = new Plugin({
key: charReplace,
state: {
init() {
return DecorationSet.empty;
},
apply(tr, set) {
set = set.map(tr.mapping, tr.doc);
const action = tr.getMeta(charReplace);
if (action && action.add) {
const deco = Decoration.widget(action.add.pos - 1, document.createTextNode(action.charToAdd), { id: action.add.id });
DecorationSet.create(tr.doc, [Decoration.widget(tr.selection.from - 1, widget)]);
set = set.add(tr.doc, [deco]);
} else if (action && action.remove) {
set = set.remove(set.find(null, null, (spec) => spec.id == action.remove.id));
}
return set;
},
}
})
tr.setMeta(charReplace, { add: { pos: tr.selection.from }, charToAdd: '⎵'});
The harder answer (that involves more rewriting) is to not use setMeta
at all. It looks like you’re using code from the upload example, but most of that logic is not required for character replacement: setMeta
is used there because uploading is asynchronous, but the decorations you compute are / can be synchronous.
If I had to tackle the problem (which I presume is Rendering Different Characters in Place of Actual Transformation), I would do more of the following:
const charReplace = new PluginKey("charReplace")
const charReplacePlugin = new Plugin({
key: charReplace,
state: {
init(config, state: EditorState) {
// Iterate over `state.doc` using `doc.nodesBetween` to compute widget decorations based on the entire initial document.
let decos = []
state.doc.nodesBetween(0, state.doc.nodeSize, (node, pos) => {
// character replacement logic here e.g. something like
// const deco = Decoration.widget(pos - 1, ...)
// decos.push(deco)
})
return decos.length ? DecorationSet.create(state.doc, decos) : DecorationSet.empty;
},
apply(tr, set) {
set = set.map(tr.mapping, tr.doc);
// Iterate only over parts of the document that `tr` has modified
// For reference, look at https://discuss.prosemirror.net/t/find-new-node-instances-and-track-them/96/7
changedRanges = getChangedRanges(tr)
for (range in changedRanges) {
// Remove previous decorations if they exist in the range using `find` and `remove`
// character replacement logic here
tr.doc.nodesBetween(range.from, range.to, ...)
}
return set;
},
}
})