@@ -117,7 +117,9 @@ export class SemanticTokensBuilder {
117117
118118 private _prevLine ! : number ;
119119 private _prevChar ! : number ;
120+ private _dataIsSortedAndDeltaEncoded ! : boolean ;
120121 private _data ! : number [ ] ;
122+ private _dataNonDelta ! : number [ ] ;
121123 private _dataLen ! : number ;
122124
123125 private _prevData : number [ ] | undefined ;
@@ -132,24 +134,35 @@ export class SemanticTokensBuilder {
132134 this . _prevLine = 0 ;
133135 this . _prevChar = 0 ;
134136 this . _data = [ ] ;
137+ this . _dataNonDelta = [ ] ;
135138 this . _dataLen = 0 ;
139+ this . _dataIsSortedAndDeltaEncoded = true ;
136140 }
137141
138142 public push ( line : number , char : number , length : number , tokenType : number , tokenModifiers : number ) : void {
143+ if ( this . _dataIsSortedAndDeltaEncoded && ( line < this . _prevLine || ( line === this . _prevLine && char < this . _prevChar ) ) ) {
144+ // push calls were ordered and are no longer ordered
145+ this . _dataIsSortedAndDeltaEncoded = false ;
146+
147+ this . _dataNonDelta = SemanticTokensBuilder . _deltaDecode ( this . _data ) ;
148+ }
149+
139150 let pushLine = line ;
140151 let pushChar = char ;
141- if ( this . _dataLen > 0 ) {
152+ if ( this . _dataIsSortedAndDeltaEncoded && this . _dataLen > 0 ) {
142153 pushLine -= this . _prevLine ;
143154 if ( pushLine === 0 ) {
144155 pushChar -= this . _prevChar ;
145156 }
146157 }
147158
148- this . _data [ this . _dataLen ++ ] = pushLine ;
149- this . _data [ this . _dataLen ++ ] = pushChar ;
150- this . _data [ this . _dataLen ++ ] = length ;
151- this . _data [ this . _dataLen ++ ] = tokenType ;
152- this . _data [ this . _dataLen ++ ] = tokenModifiers ;
159+ const dataSource = this . _dataIsSortedAndDeltaEncoded ? this . _data : this . _dataNonDelta ;
160+
161+ dataSource [ this . _dataLen ++ ] = pushLine ;
162+ dataSource [ this . _dataLen ++ ] = pushChar ;
163+ dataSource [ this . _dataLen ++ ] = length ;
164+ dataSource [ this . _dataLen ++ ] = tokenType ;
165+ dataSource [ this . _dataLen ++ ] = tokenModifiers ;
153166
154167 this . _prevLine = line ;
155168 this . _prevChar = char ;
@@ -159,18 +172,108 @@ export class SemanticTokensBuilder {
159172 return this . _id . toString ( ) ;
160173 }
161174
175+ private static _deltaDecode ( data : number [ ] ) : number [ ] {
176+ // Remove delta encoding from data
177+ const tokenCount = ( data . length / 5 ) | 0 ;
178+ let prevLine = 0 ;
179+ let prevChar = 0 ;
180+ const result : number [ ] = [ ] ;
181+ for ( let i = 0 ; i < tokenCount ; i ++ ) {
182+ const dstOffset = 5 * i ;
183+ let line = data [ dstOffset ] ;
184+ let char = data [ dstOffset + 1 ] ;
185+
186+ if ( line === 0 ) {
187+ // on the same line as previous token
188+ line = prevLine ;
189+ char += prevChar ;
190+ } else {
191+ // on a different line than previous token
192+ line += prevLine ;
193+ }
194+
195+ const length = data [ dstOffset + 2 ] ;
196+ const tokenType = data [ dstOffset + 3 ] ;
197+ const tokenModifiers = data [ dstOffset + 4 ] ;
198+
199+ result [ dstOffset + 0 ] = line ;
200+ result [ dstOffset + 1 ] = char ;
201+ result [ dstOffset + 2 ] = length ;
202+ result [ dstOffset + 3 ] = tokenType ;
203+ result [ dstOffset + 4 ] = tokenModifiers ;
204+
205+ prevLine = line ;
206+ prevChar = char ;
207+ }
208+
209+ return result ;
210+ }
211+
212+ private static _sortAndDeltaEncode ( data : number [ ] ) : number [ ] {
213+ const pos : number [ ] = [ ] ;
214+ const tokenCount = ( data . length / 5 ) | 0 ;
215+ for ( let i = 0 ; i < tokenCount ; i ++ ) {
216+ pos [ i ] = i ;
217+ }
218+ pos . sort ( ( a , b ) => {
219+ const aLine = data [ 5 * a ] ;
220+ const bLine = data [ 5 * b ] ;
221+ if ( aLine === bLine ) {
222+ const aChar = data [ 5 * a + 1 ] ;
223+ const bChar = data [ 5 * b + 1 ] ;
224+ return aChar - bChar ;
225+ }
226+ return aLine - bLine ;
227+ } ) ;
228+ const result = [ ] ;
229+ let prevLine = 0 ;
230+ let prevChar = 0 ;
231+ for ( let i = 0 ; i < tokenCount ; i ++ ) {
232+ const srcOffset = 5 * pos [ i ] ;
233+ const line = data [ srcOffset + 0 ] ;
234+ const char = data [ srcOffset + 1 ] ;
235+ const length = data [ srcOffset + 2 ] ;
236+ const tokenType = data [ srcOffset + 3 ] ;
237+ const tokenModifiers = data [ srcOffset + 4 ] ;
238+
239+ const pushLine = line - prevLine ;
240+ const pushChar = ( pushLine === 0 ? char - prevChar : char ) ;
241+
242+ const dstOffset = 5 * i ;
243+ result [ dstOffset + 0 ] = pushLine ;
244+ result [ dstOffset + 1 ] = pushChar ;
245+ result [ dstOffset + 2 ] = length ;
246+ result [ dstOffset + 3 ] = tokenType ;
247+ result [ dstOffset + 4 ] = tokenModifiers ;
248+
249+ prevLine = line ;
250+ prevChar = char ;
251+ }
252+
253+ return result ;
254+ }
255+
256+ private getFinalDataDelta ( ) : number [ ] {
257+ if ( this . _dataIsSortedAndDeltaEncoded ) {
258+ return this . _data ;
259+ } else {
260+ return SemanticTokensBuilder . _sortAndDeltaEncode ( this . _dataNonDelta ) ;
261+ }
262+ }
263+
162264 public previousResult ( id : string ) {
163265 if ( this . id === id ) {
164- this . _prevData = this . _data ;
266+ this . _prevData = this . getFinalDataDelta ( ) ;
165267 }
166268 this . initialize ( ) ;
167269 }
168270
169271 public build ( ) : SemanticTokens {
170272 this . _prevData = undefined ;
273+
171274 return {
172275 resultId : this . id ,
173- data : this . _data
276+ data : this . getFinalDataDelta ( )
174277 } ;
175278 }
176279
@@ -182,7 +285,7 @@ export class SemanticTokensBuilder {
182285 if ( this . _prevData !== undefined ) {
183286 return {
184287 resultId : this . id ,
185- edits : ( new SemanticTokensDiff ( this . _prevData , this . _data ) ) . computeDiff ( )
288+ edits : ( new SemanticTokensDiff ( this . _prevData , this . getFinalDataDelta ( ) ) ) . computeDiff ( )
186289 } ;
187290 } else {
188291 return this . build ( ) ;
0 commit comments