@@ -74,7 +74,7 @@ export class HeightOracle {
7474}
7575
7676// This object is used by `updateHeight` to make DOM measurements
77- // arrive at the right nides . The `heights` array is a sequence of
77+ // arrive at the right nodes . The `heights` array is a sequence of
7878// block heights, starting from position `from`.
7979export class MeasuredHeights {
8080 public index = 0
@@ -98,7 +98,7 @@ export class BlockInfo {
9898 readonly height : number ,
9999 /// @internal Weird packed field that holds an array of children
100100 /// for composite blocks, a decoration for block widgets, and a
101- /// number indicating the amount of widget-create line breaks for
101+ /// number indicating the amount of widget-created line breaks for
102102 /// text blocks.
103103 readonly _content : readonly BlockInfo [ ] | PointDecoration | number
104104 ) { }
@@ -200,7 +200,7 @@ export abstract class HeightMap {
200200 return me . updateHeight ( oracle , 0 )
201201 }
202202
203- static empty ( ) : HeightMap { return new HeightMapText ( 0 , 0 ) }
203+ static empty ( ) : HeightMap { return new HeightMapText ( 0 , 0 , 0 ) }
204204
205205 // nodes uses null values to indicate the position of line breaks.
206206 // There are never line breaks at the start or end of the array, or
@@ -251,24 +251,45 @@ function replace(old: HeightMap, val: HeightMap) {
251251
252252HeightMap . prototype . size = 1
253253
254+ const SpaceDeco = Decoration . replace ( { } ) as PointDecoration
255+
254256class HeightMapBlock extends HeightMap {
257+ spaceAbove = 0
258+
255259 constructor ( length : number , height : number , readonly deco : PointDecoration | null ) { super ( length , height ) }
256260
257- blockAt ( _height : number , _oracle : HeightOracle , top : number , offset : number ) {
258- return new BlockInfo ( offset , this . length , top , this . height , this . deco || 0 )
261+ mainBlock ( top : number , offset : number ) {
262+ return new BlockInfo ( offset , this . length , top + this . spaceAbove , this . height - this . spaceAbove , this . deco || 0 )
263+ }
264+
265+ blockAt ( height : number , _oracle : HeightOracle , top : number , offset : number ) {
266+ return this . spaceAbove && height < top + this . spaceAbove ? new BlockInfo ( offset , 0 , top , this . spaceAbove , SpaceDeco )
267+ : this . mainBlock ( top , offset )
259268 }
260269
261270 lineAt ( _value : number , _type : QueryType , oracle : HeightOracle , top : number , offset : number ) {
262- return this . blockAt ( 0 , oracle , top , offset )
271+ let main = this . mainBlock ( top , offset )
272+ return this . spaceAbove ? this . blockAt ( 0 , oracle , top , offset ) . join ( main ) : main
263273 }
264274
265275 forEachLine ( from : number , to : number , oracle : HeightOracle , top : number , offset : number , f : ( line : BlockInfo ) => void ) {
266- if ( from <= offset + this . length && to >= offset ) f ( this . blockAt ( 0 , oracle , top , offset ) )
276+ if ( from <= offset + this . length && to >= offset ) f ( this . lineAt ( 0 , QueryType . ByPos , oracle , top , offset ) )
277+ }
278+
279+ setMeasuredHeight ( measured : MeasuredHeights ) {
280+ let next = measured . heights [ measured . index ++ ]
281+ if ( next < 0 ) {
282+ this . spaceAbove = - next
283+ next = measured . heights [ measured . index ++ ]
284+ } else {
285+ this . spaceAbove = 0
286+ }
287+ this . setHeight ( next )
267288 }
268289
269290 updateHeight ( oracle : HeightOracle , offset : number = 0 , _force : boolean = false , measured ?: MeasuredHeights ) {
270291 if ( measured && measured . from <= offset && measured . more )
271- this . setHeight ( measured . heights [ measured . index ++ ] )
292+ this . setMeasuredHeight ( measured )
272293 this . outdated = false
273294 return this
274295 }
@@ -281,17 +302,20 @@ class HeightMapText extends HeightMapBlock {
281302 public widgetHeight = 0 // Maximum inline widget height
282303 public breaks = 0 // Number of widget-introduced line breaks on the line
283304
284- constructor ( length : number , height : number ) { super ( length , height , null ) }
305+ constructor ( length : number , height : number , above : number ) {
306+ super ( length , height , null )
307+ this . spaceAbove = above
308+ }
285309
286- blockAt ( _height : number , _oracle : HeightOracle , top : number , offset : number ) {
287- return new BlockInfo ( offset , this . length , top , this . height , this . breaks )
310+ mainBlock ( top : number , offset : number ) {
311+ return new BlockInfo ( offset , this . length , top + this . spaceAbove , this . height - this . spaceAbove , this . breaks )
288312 }
289313
290314 replace ( _from : number , _to : number , nodes : ( HeightMap | null ) [ ] ) : HeightMap {
291315 let node = nodes [ 0 ]
292316 if ( nodes . length == 1 && ( node instanceof HeightMapText || node instanceof HeightMapGap && ( node . flags & Flag . SingleLine ) ) &&
293317 Math . abs ( this . length - node . length ) < 10 ) {
294- if ( node instanceof HeightMapGap ) node = new HeightMapText ( node . length , this . height )
318+ if ( node instanceof HeightMapGap ) node = new HeightMapText ( node . length , this . height , this . spaceAbove )
295319 else node . height = this . height
296320 if ( ! this . outdated ) node . outdated = false
297321 return node
@@ -301,11 +325,13 @@ class HeightMapText extends HeightMapBlock {
301325 }
302326
303327 updateHeight ( oracle : HeightOracle , offset : number = 0 , force : boolean = false , measured ?: MeasuredHeights ) {
304- if ( measured && measured . from <= offset && measured . more )
305- this . setHeight ( measured . heights [ measured . index ++ ] )
306- else if ( force || this . outdated )
328+ if ( measured && measured . from <= offset && measured . more ) {
329+ this . setMeasuredHeight ( measured )
330+ } else if ( force || this . outdated ) {
331+ this . spaceAbove = 0
307332 this . setHeight ( Math . max ( this . widgetHeight , oracle . heightForLine ( this . length - this . collapsed ) ) +
308333 this . breaks * oracle . lineHeight )
334+ }
309335 this . outdated = false
310336 return this
311337 }
@@ -415,10 +441,14 @@ class HeightMapGap extends HeightMap {
415441 while ( pos <= end && measured . more ) {
416442 let len = oracle . doc . lineAt ( pos ) . length
417443 if ( nodes . length ) nodes . push ( null )
418- let height = measured . heights [ measured . index ++ ]
444+ let height = measured . heights [ measured . index ++ ] , above = 0
445+ if ( height < 0 ) {
446+ above = - height
447+ height = measured . heights [ measured . index ++ ]
448+ }
419449 if ( singleHeight == - 1 ) singleHeight = height
420450 else if ( Math . abs ( height - singleHeight ) >= Epsilon ) singleHeight = - 2
421- let line = new HeightMapText ( len , height )
451+ let line = new HeightMapText ( len , height , above )
422452 line . outdated = false
423453 nodes . push ( line )
424454 pos += len + 1
@@ -582,7 +612,7 @@ class NodeBuilder implements SpanIterator<Decoration> {
582612 if ( last instanceof HeightMapText )
583613 last . length += end - this . pos
584614 else if ( end > this . pos || ! this . isCovered )
585- this . nodes . push ( new HeightMapText ( end - this . pos , - 1 ) )
615+ this . nodes . push ( new HeightMapText ( end - this . pos , - 1 , 0 ) )
586616 this . writtenTo = end
587617 if ( to > end ) {
588618 this . nodes . push ( null )
@@ -621,7 +651,7 @@ class NodeBuilder implements SpanIterator<Decoration> {
621651 this . nodes . push ( null )
622652 }
623653 if ( this . pos > from )
624- this . nodes . push ( new HeightMapText ( this . pos - from , - 1 ) )
654+ this . nodes . push ( new HeightMapText ( this . pos - from , - 1 , 0 ) )
625655 this . writtenTo = this . pos
626656 }
627657
@@ -635,7 +665,7 @@ class NodeBuilder implements SpanIterator<Decoration> {
635665 this . enterLine ( )
636666 let last = this . nodes . length ? this . nodes [ this . nodes . length - 1 ] : null
637667 if ( last instanceof HeightMapText ) return last
638- let line = new HeightMapText ( 0 , - 1 )
668+ let line = new HeightMapText ( 0 , - 1 , 0 )
639669 this . nodes . push ( line )
640670 return line
641671 }
@@ -661,7 +691,7 @@ class NodeBuilder implements SpanIterator<Decoration> {
661691 finish ( from : number ) {
662692 let last = this . nodes . length == 0 ? null : this . nodes [ this . nodes . length - 1 ]
663693 if ( this . lineStart > - 1 && ! ( last instanceof HeightMapText ) && ! this . isCovered )
664- this . nodes . push ( new HeightMapText ( 0 , - 1 ) )
694+ this . nodes . push ( new HeightMapText ( 0 , - 1 , 0 ) )
665695 else if ( this . writtenTo < this . pos || last == null )
666696 this . nodes . push ( this . blankContent ( this . writtenTo , this . pos ) )
667697 let pos = from
0 commit comments