Skip to content

Commit e0968d4

Browse files
committed
Make sure tiles are entered to find reusable widgets during redraw
FIX: Fix an issue where replaced widgets alone on a line weren't reused and didn't get their `updateDOM` method called. Closes codemirror/dev#1646
1 parent db7c7c4 commit e0968d4

File tree

3 files changed

+26
-10
lines changed

3 files changed

+26
-10
lines changed

src/buildtile.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Tile, CompositeTile, DocTile, LineTile, MarkTile, BlockWrapperTile,
2-
WidgetTile, WidgetBufferTile, TextTile, TileFlag, TilePointer} from "./tile"
2+
WidgetTile, WidgetBufferTile, TextTile, TileFlag, TilePointer, TileWalker} from "./tile"
33
import {ChangedRange} from "./extension"
44
import {Attrs, getAttrs, combineAttrs} from "./attributes"
55
import {DecorationSet, MarkDecoration, PointDecoration, LineDecoration, WidgetType,
@@ -357,6 +357,7 @@ export class TileUpdate {
357357
openWidget = false
358358
openMarks = 0
359359
cache: TileCache
360+
reuseWalker: TileWalker
360361

361362
constructor(
362363
readonly view: EditorView,
@@ -370,6 +371,15 @@ export class TileUpdate {
370371
this.builder = new TileBuilder(this.cache, new DocTile(view, view.contentDOM), RangeSet.iter(blockWrappers))
371372
this.cache.reused.set(old, Reused.DOM)
372373
this.old = new TilePointer(old)
374+
this.reuseWalker = {
375+
skip: (tile, from, to) => {
376+
this.cache.add(tile)
377+
if (tile.isComposite()) return false
378+
},
379+
enter: tile => this.cache.add(tile),
380+
leave: () => {},
381+
break: () => {}
382+
}
373383
}
374384

375385
run(changes: readonly ChangedRange[], composition: Composition | null) {
@@ -538,14 +548,13 @@ export class TileUpdate {
538548
}
539549

540550
forward(from: number, to: number) {
541-
this.old.advance(to - from, 1, {
542-
skip: (tile, from, to) => {
543-
if (tile.isText() || to == tile.length) this.cache.add(tile)
544-
},
545-
enter: tile => this.cache.add(tile),
546-
leave: () => {},
547-
break: () => {}
548-
})
551+
if (to - from <= 10) {
552+
this.old.advance(to - from, 1, this.reuseWalker)
553+
} else {
554+
this.old.advance(5, -1, this.reuseWalker)
555+
this.old.advance(to - from - 10, -1)
556+
this.old.advance(5, 1, this.reuseWalker)
557+
}
549558
}
550559

551560
getCompositionContext(text: Text) {

src/tile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ export class TilePointer {
568568
get root() { return (this.parents.length ? this.parents[0].tile : this.tile) as DocTile }
569569
}
570570

571-
interface TileWalker {
571+
export interface TileWalker {
572572
enter(tile: CompositeTile): void
573573
leave(tile: CompositeTile): void
574574
skip(tile: Tile, from: number, to: number): boolean | void

test/webtest-draw-decoration.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,13 @@ describe("EditorView decoration", () => {
361361
ist(nodes.every(n => cm.contentDOM.contains(n)))
362362
})
363363

364+
it("reuses widgets on empty lines", () => {
365+
let cm = decoEditor("a\n\nb", [w(2, new WordWidget("x"))])
366+
let dom = cm.contentDOM.querySelector("strong")
367+
cm.dispatch({effects: [filterDeco.of(() => false), addDeco.of([w(2, new WordWidget("x"))])]})
368+
ist(cm.contentDOM.querySelector("strong"), dom)
369+
})
370+
364371
it("can update widgets in an empty document", () => {
365372
let cm = decoEditor("", [w(0, new WordWidget("A"))])
366373
cm.dispatch({effects: addDeco.of([w(0, new WordWidget("B"))])})

0 commit comments

Comments
 (0)