Hello, what would be the best way for cursor to skip ranges hidden through Decoration.replace
?
Should I use transactionFilter(tr)
that would update tr.selection
if it gets into RangeSet
that stores all Decoration.replace
?
Hello, what would be the best way for cursor to skip ranges hidden through Decoration.replace
?
Should I use transactionFilter(tr)
that would update tr.selection
if it gets into RangeSet
that stores all Decoration.replace
?
Thanks a lot—this is exactly what’s needed!
Out of curiosity, if atomicRanges
are included as core part of View why not to add them as additional parameter of Decoration.replace
or Decoration.mark
?
I made a quick plugin that links View.Plugin.atomicRanges
with state.Facet(EditorView.decorations)
, but think it could be useful for others too.
import { Decoration, ViewPlugin, PluginField, EditorView } from '@codemirror/view'
import { RangeSet, Range } from '@codemirror/rangeset'
/** Decoration that hides the content and skips on selection move */
const rangeHide = Decoration.replace({})
/** Decoration that displays the content but skips on selection move */
const rangeSkip = Decoration.mark({})
/** ViewPlugin that enables the functionality
* to hide a range provide RangeSet with either `rangeHide` or `rangeSkip` to ViewState facet
*/
const atomicRanges = ViewPlugin.define(
(view) => ({ view }),
{
provide: PluginField.atomicRanges.from((val) => {
const decorations = val.view.state.facet(EditorView.decorations)
let ranges = []
for (let iter = RangeSet.iter(decorations); iter.value !== null; iter.next())
if (iter.value === rangeSkip || iter.value === rangeHide)
ranges.push(new Range(iter.from, iter.to, iter.value))
return RangeSet.of(ranges, true)
})
}
)
export { rangeHide, rangeSkip, atomicRanges }
Thank you @ilyakochik - this was very helpful to me.
I’ve been following the boolean toggle widget example but building a replace
decoration instead of a widget
and I want to make them atomic.
How would I apply your Facet in my case?
e.g.
const MyPluginClass = class {
constructor(view){
this.decorations = createsMyReplacementWidgets(update.view)
}
update(update){
if(update.docChanged || update.viewportChanged){
this.decorations = createsMyReplacementWidgets(update.view)
}
}
}
const myExtension = [
ViewPlugin.fromClass(
MyPluginClass,
{
decorations: v => v.decorations
}
)
]
I think this could work:
const MyPluginClass = class {
constructor(view) {
this.decorations = createsMyReplacementWidgets(view)
}
update(update) {
if (update.docChanged || update.viewportChanged) {
this.decorations = createsMyReplacementWidgets(update.view)
}
}
}
const myExtension = [
ViewPlugin.fromClass(
MyPluginClass,
{
decorations: v => v.decorations,
// provide PluginField
provide: PluginField.atomicRanges.from(val => val.decorations)
}
)
]