@@ -56,6 +56,8 @@ export class LynxWorkspaceService {
56
56
private projectDocChangeSubscription ?: Subscription ;
57
57
private readonly curInsightsByEventUriAndSource = new Map < string , Map < string , LynxInsight [ ] > > ( ) ;
58
58
private curInsightsFlattened : LynxInsight [ ] = [ ] ;
59
+ private onTypeEditsSequence = 0 ;
60
+ private onTypeEditsActiveDelta ?: Delta ;
59
61
60
62
// Emits when workspace is recreated when project settings change
61
63
private rawInsightSourceSubject$ = new BehaviorSubject < Observable < LynxInsight [ ] > | null > ( null ) ;
@@ -174,42 +176,75 @@ export class LynxWorkspaceService {
174
176
if ( curDocUri == null ) {
175
177
return [ ] ;
176
178
}
177
- const ops : Op [ ] = delta . ops ;
178
- let offset : number ;
179
- let text : string ;
180
- if ( ops . length === 1 && typeof ops [ 0 ] . insert === 'string' ) {
181
- offset = 0 ;
182
- text = ops [ 0 ] . insert ;
183
- } else if ( ops . length === 2 && typeof ops [ 0 ] . retain === 'number' && typeof ops [ 1 ] . insert === 'string' ) {
184
- offset = ops [ 0 ] . retain ;
185
- text = ops [ 1 ] . insert ;
186
- } else {
187
- return [ ] ;
188
- }
189
179
190
- const doc : ScriptureDeltaDocument | undefined = await this . documentManager . get ( curDocUri ) ;
191
- if ( doc == null ) {
192
- return [ ] ;
193
- }
194
- const edits : Delta [ ] = [ ] ;
195
- for ( const ch of this . workspace . getOnTypeTriggerCharacters ( ) ) {
196
- let startIndex : number = 0 ;
197
- while ( startIndex < text . length ) {
198
- const chIndex : number = text . indexOf ( ch , startIndex ) ;
199
- if ( chIndex >= 0 ) {
200
- const position = doc . positionAt ( offset + chIndex + 1 ) ;
201
- const chEdits : Op [ ] | undefined = await this . workspace . getOnTypeEdits ( curDocUri , position , ch ) ;
202
-
203
- if ( chEdits != null && chEdits . length > 0 ) {
204
- edits . push ( new Delta ( chEdits ) ) ;
205
- }
206
- startIndex = chIndex + ch . length ;
207
- } else {
180
+ // Increment sequence number for this call
181
+ const currentSequence = ++ this . onTypeEditsSequence ;
182
+ let isAborted = false ;
183
+
184
+ // Compose with any existing active delta
185
+ this . onTypeEditsActiveDelta = this . onTypeEditsActiveDelta ?. compose ( delta ) ?? delta ;
186
+
187
+ try {
188
+ const ops : Op [ ] = this . onTypeEditsActiveDelta . ops ;
189
+ let offset : number = 0 ;
190
+ let text : string = '' ;
191
+
192
+ for ( let i = 0 ; i < ops . length ; i ++ ) {
193
+ if ( typeof ops [ i ] . insert === 'string' ) {
194
+ text = ops [ i ] . insert as string ;
208
195
break ;
196
+ } else if ( typeof ops [ i ] . retain === 'number' ) {
197
+ offset += ops [ i ] . retain as number ;
198
+ continue ;
199
+ } else {
200
+ return [ ] ;
201
+ }
202
+ }
203
+
204
+ const doc : ScriptureDeltaDocument | undefined = await this . documentManager . get ( curDocUri ) ;
205
+
206
+ // 'offset' may be stale here. For example, a blank embed may have been auto-deleted while awaiting the doc.
207
+ // Check if a newer call has superseded this one while we were awaiting the document.
208
+ if ( currentSequence !== this . onTypeEditsSequence ) {
209
+ isAborted = true ;
210
+ return [ ] ; // Abort - a newer call is handling this
211
+ }
212
+
213
+ if ( doc == null ) {
214
+ return [ ] ;
215
+ }
216
+
217
+ const edits : Delta [ ] = [ ] ;
218
+ for ( const ch of this . workspace . getOnTypeTriggerCharacters ( ) ) {
219
+ let startIndex : number = 0 ;
220
+ while ( startIndex < text . length ) {
221
+ const chIndex : number = text . indexOf ( ch , startIndex ) ;
222
+ if ( chIndex >= 0 ) {
223
+ const position = doc . positionAt ( offset + chIndex + 1 ) ;
224
+ const chEdits : Op [ ] | undefined = await this . workspace . getOnTypeEdits ( curDocUri , position , ch ) ;
225
+
226
+ // Check sequence number again after each async operation
227
+ if ( currentSequence !== this . onTypeEditsSequence ) {
228
+ isAborted = true ;
229
+ return [ ] ; // Abort - a newer call is handling this
230
+ }
231
+
232
+ if ( chEdits != null && chEdits . length > 0 ) {
233
+ edits . push ( new Delta ( chEdits ) ) ;
234
+ }
235
+ startIndex = chIndex + ch . length ;
236
+ } else {
237
+ break ;
238
+ }
209
239
}
210
240
}
241
+ return edits ;
242
+ } finally {
243
+ // Clear active delta if this call finished without aborting
244
+ if ( ! isAborted ) {
245
+ this . onTypeEditsActiveDelta = undefined ;
246
+ }
211
247
}
212
- return edits ;
213
248
}
214
249
215
250
/**
0 commit comments