Skip to content

Commit 67a7211

Browse files
committed
1 parent 8ee5443 commit 67a7211

File tree

2 files changed

+61
-42
lines changed

2 files changed

+61
-42
lines changed

src/vs/base/common/observableImpl/utils.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -198,34 +198,34 @@ class FromEventObservableSignal extends BaseObservable<void> {
198198
}
199199
}
200200

201-
export function observableSignal(
201+
export function observableSignal<TDelta = void>(
202202
debugName: string
203-
): IObservableSignal {
204-
return new ObservableSignal(debugName);
203+
): IObservableSignal<TDelta> {
204+
return new ObservableSignal<TDelta>(debugName);
205205
}
206206

207-
export interface IObservableSignal extends IObservable<void> {
208-
trigger(tx: ITransaction | undefined): void;
207+
export interface IObservableSignal<TChange> extends IObservable<void, TChange> {
208+
trigger(tx: ITransaction | undefined, change: TChange): void;
209209
}
210210

211-
class ObservableSignal extends BaseObservable<void> implements IObservableSignal {
211+
class ObservableSignal<TChange> extends BaseObservable<void, TChange> implements IObservableSignal<TChange> {
212212
constructor(
213213
public readonly debugName: string
214214
) {
215215
super();
216216
}
217217

218-
public trigger(tx: ITransaction | undefined): void {
218+
public trigger(tx: ITransaction | undefined, change: TChange): void {
219219
if (!tx) {
220220
transaction(tx => {
221-
this.trigger(tx);
221+
this.trigger(tx, change);
222222
}, () => `Trigger signal ${this.debugName}`);
223223
return;
224224
}
225225

226226
for (const o of this.observers) {
227227
tx.updateObserver(o, this);
228-
o.handleChange(this, undefined);
228+
o.handleChange(this, change);
229229
}
230230
}
231231

src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { mapFind } from 'vs/base/common/arrays';
77
import { BugIndicatingError, onUnexpectedExternalError } from 'vs/base/common/errors';
88
import { Disposable } from 'vs/base/common/lifecycle';
9-
import { IObservable, IReader, ITransaction, autorun, autorunHandleChanges, derived, observableSignal, observableValue, transaction } from 'vs/base/common/observable';
9+
import { IObservable, ITransaction, autorun, autorunHandleChanges, derived, observableSignal, observableValue, transaction } from 'vs/base/common/observable';
1010
import { isDefined } from 'vs/base/common/types';
1111
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
1212
import { EditOperation } from 'vs/editor/common/core/editOperation';
@@ -34,13 +34,16 @@ export enum VersionIdChangeReason {
3434
export class InlineCompletionsModel extends Disposable {
3535
private readonly _source = this._register(this._instantiationService.createInstance(InlineCompletionsSource, this.textModel, this.textModelVersionId, this._debounceValue));
3636
private readonly _isActive = observableValue('isActive', false);
37+
private readonly _forceUpdate = observableSignal<InlineCompletionTriggerKind>('forceUpdate');
3738

3839
private _isAcceptingPartially = false;
3940
public get isAcceptingPartially() { return this._isAcceptingPartially; }
4041

4142
private _isNavigatingCurrentInlineCompletion = false;
4243
public get isNavigatingCurrentInlineCompletion() { return this._isNavigatingCurrentInlineCompletion; }
4344

45+
private _updatePromise: Promise<unknown> | undefined; // TODO make this a computed
46+
4447
constructor(
4548
public readonly textModel: ITextModel,
4649
public readonly selectedSuggestItem: IObservable<SuggestItemInfo | undefined>,
@@ -57,24 +60,58 @@ export class InlineCompletionsModel extends Disposable {
5760
) {
5861
super();
5962

60-
let preserveCurrentCompletion = false;
6163
const preserveCurrentCompletionReasons = new Set([
6264
VersionIdChangeReason.Redo,
6365
VersionIdChangeReason.Undo,
6466
VersionIdChangeReason.AcceptWord,
6567
]);
68+
69+
// TODO implement ChangeHandler concept
70+
let preserveCurrentCompletion = false;
71+
let inlineCompletionTriggerKind = InlineCompletionTriggerKind.Automatic;
72+
6673
this._register(autorunHandleChanges('update', {
67-
handleChange: ctx => {
74+
handleChange: (ctx) => {
6875
if (ctx.didChange(this.textModelVersionId) && preserveCurrentCompletionReasons.has(ctx.change)) {
6976
preserveCurrentCompletion = true;
77+
} else if (ctx.didChange(this._forceUpdate)) {
78+
inlineCompletionTriggerKind = ctx.change;
7079
}
7180
return true;
7281
}
73-
}, (reader) => {
82+
}, reader => {
83+
this._forceUpdate.read(reader);
7484
if ((this._enabled.read(reader) && this.selectedSuggestItem.read(reader)) || this._isActive.read(reader)) {
75-
this._update(reader, InlineCompletionTriggerKind.Automatic, preserveCurrentCompletion);
85+
const shouldPreserveCurrentCompletion = preserveCurrentCompletion || (this.selectedInlineCompletion.get()?.inlineCompletion.source.inlineCompletions.enableForwardStability ?? false);
86+
87+
const suggestItem = this.selectedSuggestItem.read(reader);
88+
const cursorPosition = this.cursorPosition.read(reader);
89+
this.textModelVersionId.read(reader);
90+
91+
const suggestWidgetInlineCompletions = this._source.suggestWidgetInlineCompletions.get();
92+
if (suggestWidgetInlineCompletions && !suggestItem) {
93+
const inlineCompletions = this._source.inlineCompletions.get();
94+
if (inlineCompletions && suggestWidgetInlineCompletions.request.versionId > inlineCompletions.request.versionId) {
95+
this._source.inlineCompletions.set(suggestWidgetInlineCompletions.clone(), undefined);
96+
}
97+
this._source.clearSuggestWidgetInlineCompletions();
98+
}
99+
100+
this._updatePromise = this._source.update(
101+
cursorPosition,
102+
{
103+
triggerKind: inlineCompletionTriggerKind,
104+
selectedSuggestionInfo: suggestItem?.toSelectedSuggestionInfo()
105+
},
106+
shouldPreserveCurrentCompletion ? this.selectedInlineCompletion.get() : undefined
107+
);
108+
} else {
109+
this._updatePromise = undefined;
76110
}
111+
112+
// Reset local state
77113
preserveCurrentCompletion = false;
114+
inlineCompletionTriggerKind = InlineCompletionTriggerKind.Automatic;
78115
}));
79116

80117
let lastItem: InlineCompletionWithUpdatedRange | undefined = undefined;
@@ -92,31 +129,17 @@ export class InlineCompletionsModel extends Disposable {
92129
}));
93130
}
94131

95-
private async _update(reader: IReader | undefined, triggerKind: InlineCompletionTriggerKind, preserveCurrentCompletion: boolean = false): Promise<void> {
96-
preserveCurrentCompletion = preserveCurrentCompletion || (this.selectedInlineCompletion.get()?.inlineCompletion.source.inlineCompletions.enableForwardStability ?? false);
97-
98-
const suggestItem = this.selectedSuggestItem.read(reader);
99-
const cursorPosition = this.cursorPosition.read(reader);
100-
this.textModelVersionId.read(reader);
101-
102-
const suggestWidgetInlineCompletions = this._source.suggestWidgetInlineCompletions.get();
103-
if (suggestWidgetInlineCompletions && !suggestItem) {
104-
const inlineCompletions = this._source.inlineCompletions.get();
105-
if (inlineCompletions && suggestWidgetInlineCompletions.request.versionId > inlineCompletions.request.versionId) {
106-
this._source.inlineCompletions.set(suggestWidgetInlineCompletions.clone(), undefined);
107-
}
108-
this._source.clearSuggestWidgetInlineCompletions();
109-
}
110-
111-
await this._source.update(
112-
cursorPosition,
113-
{ triggerKind, selectedSuggestionInfo: suggestItem?.toSelectedSuggestionInfo() },
114-
preserveCurrentCompletion ? this.selectedInlineCompletion.get() : undefined
115-
);
132+
public async trigger(tx?: ITransaction): Promise<void> {
133+
this._isActive.set(true, tx);
134+
await this._updatePromise;
116135
}
117136

118-
public trigger(tx?: ITransaction): void {
119-
this._isActive.set(true, tx);
137+
public async triggerExplicitly(): Promise<void> {
138+
transaction(tx => {
139+
this._isActive.set(true, tx);
140+
this._forceUpdate.trigger(tx, InlineCompletionTriggerKind.Explicit);
141+
});
142+
await this._updatePromise;
120143
}
121144

122145
public stop(tx?: ITransaction): void {
@@ -170,7 +193,7 @@ export class InlineCompletionsModel extends Disposable {
170193
}
171194
});
172195

173-
public readonly ghostTextAndCompletion = derived('ghostText', (reader) => {
196+
public readonly ghostTextAndCompletion = derived('ghostTextAndCompletion', (reader) => {
174197
const model = this.textModel;
175198

176199
const suggestItem = this.selectedSuggestItem.read(reader);
@@ -222,10 +245,6 @@ export class InlineCompletionsModel extends Disposable {
222245
return v.ghostText;
223246
});
224247

225-
public async triggerExplicitly(): Promise<void> {
226-
await this._update(undefined, InlineCompletionTriggerKind.Explicit);
227-
}
228-
229248
private async deltaIndex(delta: 1 | -1): Promise<void> {
230249
await this.triggerExplicitly();
231250

0 commit comments

Comments
 (0)