Skip to content

Commit b93ffdc

Browse files
committed
Add a random decoration test, fix a bug in view updates
1 parent 5eaccf8 commit b93ffdc

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ export class ChangedRange {
385385
let end = ranges[rI + 1]
386386
rI += 2
387387
toB = Math.max(toB, end)
388+
for (let i = dI; i < diff.length && diff[i].fromB <= toB; i++)
389+
off = diff[i].toA - diff[i].toB
388390
toA = Math.max(toA, end + off)
389391
} else if (dI < diff.length && diff[dI].fromB <= toB) {
390392
let next = diff[dI++]

test/webtest-draw-decoration.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,61 @@ describe("EditorView decoration", () => {
185185
ist(marks.every(m => cm.contentDOM.contains(m)))
186186
})
187187

188+
it("properly handles random decorations and changes", () => {
189+
let r = (n: number) => Math.floor(Math.random() * n)
190+
let marks = [Decoration.mark({tagName: "a"}), Decoration.mark({tagName: "b"}), Decoration.mark({tagName: "c"})]
191+
let doc = "abcd efgh ijkl mnopq rstu vwxy z"
192+
let cm = decoEditor(doc, [])
193+
for (let i = 0; i < 50; i++) {
194+
let changes = [], deco: Range<Decoration>[] = []
195+
if (r(5) < 3) {
196+
let from = r(Math.max(0, doc.length - 3))
197+
let to = from + r(Math.min(3, doc.length - from))
198+
let insert = "#".repeat(r(4))
199+
changes.push({from, to, insert})
200+
doc = doc.slice(0, from) + insert + doc.slice(to)
201+
}
202+
for (let j = 0, c = r(marks.length); j < c; j++) {
203+
let from = r(doc.length - 3)
204+
let to = from + 1 + r(doc.length - 1 - from)
205+
if (!deco.some(r => r.from == from && r.to == to))
206+
deco.push(marks[j].range(from, to))
207+
}
208+
deco.sort((a, b) => a.from - b.from || b.to - a.to || (a.value.spec.tagName < b.value.spec.tagName ? -1 : 1))
209+
cm.dispatch({changes, effects: [filterDeco.of(() => false), addDeco.of(deco)]})
210+
let expect = "", pos = 0
211+
for (let j = 0, active: Range<Decoration>[] = [];;) {
212+
let next = j == deco.length ? null : deco[j]
213+
let nextStop = active.reduce((min, mark) => Math.min(min, mark.to), 1e9)
214+
let nextPos = Math.min(nextStop, next ? next.from : doc.length)
215+
if (nextPos > pos) {
216+
expect += doc.slice(pos, nextPos)
217+
pos = nextPos
218+
}
219+
let reopen: Range<Decoration>[] = []
220+
if (nextStop <= pos || next && active.some(a => a.to < next.to)) {
221+
let closeTo = active.findIndex(mark => mark.to == pos || next && mark.to < next.to)
222+
while (active.length > closeTo) {
223+
let close = active.pop()!
224+
expect += `</${close.value.spec.tagName}>`
225+
if (close.to > pos) reopen.unshift(close)
226+
}
227+
}
228+
if (next && next.from == pos) {
229+
j++
230+
expect += `<${next.value.spec.tagName}>`
231+
active.push(next)
232+
}
233+
for (let mark of reopen) {
234+
expect += `<${mark.value.spec.tagName}>`
235+
active.push(mark)
236+
}
237+
if (pos == doc.length) break
238+
}
239+
ist((cm.contentDOM.firstChild as HTMLElement).innerHTML, expect)
240+
}
241+
})
242+
188243
class WordWidget extends WidgetType {
189244
constructor(readonly word: string) { super() }
190245
eq(other: WordWidget) { return this.word.toLowerCase() == other.word.toLowerCase() }

0 commit comments

Comments
 (0)