@@ -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