Composing multiple DecorationSets

Is there a convenient way to compose multiple RangeSets? I’m working on a collaborative editor built on top of the new collab module (thanks!). In order to show other user’s selections, I’ve built a plugin that decorates the most recent editor selection for each connected user. Since many users might be sitting around viewing, it’d be nice not to blow away the decorations for their selections whenever any user makes a change.

If possible, I’d like to keep a separate decoration set per user. As far as I know though, I need to merge them all down to a single set in order to provide them, and I couldn’t find a particularly clean way to do that. This is the best I’ve got so far:

    let decorations = []
    for(let user_id in users) {
        let decos = users[user_id];
        if(decos) {
            if(!updated.has(user_id)) users[user_id] = decos = decos.map(txn.changes);
            let iter = decos.iter();
            while(iter.value) {
                decorations.push(iter.value.range(iter.from, iter.to));
                iter.next();
            }
        }
    }
    return {decorations: Decoration.set(decorations, true), users};

Alternatively, if this doesn’t seem like a good approach, what would you recommend?

State-level decorations can be provided in bulk with computeN, something like…

let userSelections = StateField.define<readonly DecorationSet[]>({
  ... create and update functions that maintains the array of sets
  provide: f => EditorView.decorations.computeN(s => s.field(f))
})

You could also create a view plugin providing multiple decoration sets by providing an array of plugin field providers for PluginField.decorations via the provide option in the plugin spec, but that only works if the number of sets is known in advance.

1 Like

computeN is exactly what I didn’t know I needed, thank you!