Skip to content

Commit 6887af2

Browse files
committed
prevent blank embed removal from invalidating offset
1 parent 7b8371e commit 6887af2

File tree

1 file changed

+66
-31
lines changed

1 file changed

+66
-31
lines changed

src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-workspace.service.ts

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export class LynxWorkspaceService {
5656
private projectDocChangeSubscription?: Subscription;
5757
private readonly curInsightsByEventUriAndSource = new Map<string, Map<string, LynxInsight[]>>();
5858
private curInsightsFlattened: LynxInsight[] = [];
59+
private onTypeEditsSequence = 0;
60+
private onTypeEditsActiveDelta?: Delta;
5961

6062
// Emits when workspace is recreated when project settings change
6163
private rawInsightSourceSubject$ = new BehaviorSubject<Observable<LynxInsight[]> | null>(null);
@@ -174,42 +176,75 @@ export class LynxWorkspaceService {
174176
if (curDocUri == null) {
175177
return [];
176178
}
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-
}
189179

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;
208195
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+
}
209239
}
210240
}
241+
return edits;
242+
} finally {
243+
// Clear active delta if this call finished without aborting
244+
if (!isAborted) {
245+
this.onTypeEditsActiveDelta = undefined;
246+
}
211247
}
212-
return edits;
213248
}
214249

215250
/**

0 commit comments

Comments
 (0)