Skip to content

Instantly share code, notes, and snippets.

@marcuswestin
Last active September 20, 2021 16:21
Show Gist options
  • Save marcuswestin/f8f5c01094a5e7740f2c3de8a557bd55 to your computer and use it in GitHub Desktop.
Save marcuswestin/f8f5c01094a5e7740f2c3de8a557bd55 to your computer and use it in GitHub Desktop.
Example of content-based code-folding that has a rendering bug
import {EditorState, EditorView, basicSetup} from "@codemirror/basic-setup"
import { foldEffect } from "@codemirror/fold";
import { Line } from "@codemirror/text";
import { Decoration, DecorationSet, PluginValue, ViewPlugin, ViewUpdate, WidgetType } from "@codemirror/view";
let doc = `
Test list 1
- Test item
- Test item
[FOLD] - Test list 2
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test item
- Test list 3
- Test item
`
class DecorateFoldedContentPlugin implements PluginValue {
decorations: DecorationSet
constructor(readonly view: EditorView) {
this.decorations = this.makeDecarationSet()
}
update?(update: ViewUpdate) {
if (update.viewportChanged || update.docChanged) {
this.decorations = this.makeDecarationSet()
}
}
private makeDecarationSet() {
let doc = this.view.state.doc
let lineNumber = 1
let decorations = []
while (lineNumber <= doc.lines) {
let line = doc.line(lineNumber)
if (line.text.startsWith('[FOLD]')) {
let foldRangeStart = line.to
while (lineNumber <= doc.lines) {
line = doc.line(lineNumber)
if (this.isWhitespaceOnly(line)) {
let foldRangeStop = line.to
console.log(foldRangeStart, foldRangeStop)
decorations.push(hideDecoration.range(foldRangeStart, foldRangeStop))
break
}
lineNumber += 1
}
}
lineNumber += 1
}
return Decoration.set(decorations)
}
isWhitespaceOnly(line: Line) {
return line.text.match(/^\w*$/)
}
}
let hideDecoration = Decoration.replace({
widget: new class extends WidgetType {
toDOM(view: EditorView) {
let element = document.createElement('span')
element.textContent = '…'
element.setAttribute('aria-label', state.phrase('folded code'))
element.title = state.phrase('unfold')
element.className = 'cm-foldPlaceholder'
return element
}
}
})
let foldedTreeDecorator = ViewPlugin.fromClass(DecorateFoldedContentPlugin,
{decorations: (instance) => instance.decorations}
)
let state = EditorState.create({doc, extensions: [
foldedTreeDecorator,
basicSetup,
]})
let view = new EditorView({state, parent: document.querySelector("#editor")!})
;(window as any).view = view
view.focus()
// ;(function foldRangeManually() {
// let effects = foldEffect.of({from:60, to:683})
// let tr = state.update({ effects })
// view.dispatch(tr)
// }());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment