It would seem that when using Decoration.replace, we have no control over the side of the rendered widget. However, I’m running into a situation where being able to set a value here manually helps:
I have the following text Text1Text2, where Text1 and Text2 are both replaced with widgets (using Decoration.replace). Now I’d like to insert a widget (using Decoration.widget) between the two as follows:
["Text1" = Widget1][Widget2]["Text2" = Widget3].
(Note that Widget2 and Widget3 both start at position 5, but Widget3’s “side” parameter can’t be changed)
Now when I’m building these widgets using a RangeSetBuilder, I get an error because it thinks the ordering should be: ["Text1" = widget 1]["Text 2" = widget 2][Widget]
Is there anything currently in the API that allows setting the side for a replacement widget?
The inclusive options control the side. Replace widgets that are inclusive on a given side will cover any regular widgets at that position, whereas non-inclusive replacements won’t.
Hmm I’m using Decoration.replace({}) which should set inclusive to false according to the docs:
Whether this range covers the positions on its sides. This influences whether new content becomes part of the range and whether the cursor can be drawn on its sides. Defaults to false.
There was some rather funky logic in the way block widgets were assigned sides. I am not entirely sure anymore what problem I was trying to solve with that, but in this case it seems problematic—it made it impossible to do what you are trying to do here, by always making the widget move into adjacent replace decoration ranges. This patch simplifies this, and should make this issue go away.
I think the inclusive replace widget is covering the other widget. Does inclusive: false help? Thought that would also have the effect of making the text positions at the ends visible I guess. What kind of feature are you implementing?
I found out that the API allows developers to manually set the startSide and endSide values after the Decoration has been created, using which I’ve set my widget to 1e8 * 5 which helped it show up.
Using inclusive: false does make it work as well, but the side effect is that an empty cm-line is shown as the replacement does not cover the whole line anymore.
What kind of feature are you implementing?
Well… kinda crazy but I’m attempting to build something like Typora and HyperMD using cm6. It’s really close to mostly working but I’m still experiencing a lot of bugs with respect to janky selection (like when Decorations are added/removed) and some trouble with IMEs creating duplicate text.
I’m using a combination of a ViewPlugin for inline replacements (to hide markdown formatting symbols such as **) and inline widgets (for example, to render markdown images, or to add the little icon
for external links). Here’s what it looks like:
I’m also using a StateField for block level replacements and widgets that sometimes span more than one line.
Do those widgets replace full lines? I can’t really read a screencast like that and figure out what’s going on, sorry, too much moving parts.
From the second gif, the last 2 widgets replaces full lines. I’m trying to add another widget that’s persistently at the end of the document (like a footer). It seems to disappear when the previous widget just happens to replace exactly to the end of the document.
Hm, yeah, this is still pretty awkward. It’s hard to set up straightforward rules for how overlapping/adjacent decorations interact that work in all situations. I will look into this some other time, don’t have time for it now.
This patch further refines decoration ordering, and I think it should cover both the use cases described in this thread and not break any reasonable use of decorations. Please let me know how it works for you if you’ve had a chance to test it.
One thing I’m observing with the new patch is that whole-line block replacements no longer replaces the line element. It is now showing an empty cm-line for the first line of the block.
Creating a decoration like Decoration.replace({widget: someWidget, block: true}).range(lineStart, lineEnd) does replace the entire line with a widget for me. What are you doing?
I’ve done some additional testing since this and it seems that this is actually caused by a Decoration.line in conjunction with a whole-line block replacement widget.