mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Fixes flickering (#252310)
This commit is contained in:
committed by
GitHub
parent
21e7d58551
commit
848883ca9c
@@ -376,16 +376,18 @@ class InlineCompletionsState extends Disposable {
|
||||
return new InlineCompletionsState(newInlineCompletions, this.request);
|
||||
}
|
||||
|
||||
public createStateWithAppliedResults(updatedSuggestions: InlineSuggestionItem[], request: UpdateRequest, textModel: ITextModel, cursorPosition: Position, itemIdToPreserve: InlineSuggestionIdentity | undefined): InlineCompletionsState {
|
||||
let updatedItems: InlineSuggestionItem[] = [];
|
||||
|
||||
public createStateWithAppliedResults(updatedSuggestions: InlineSuggestionItem[], request: UpdateRequest, textModel: ITextModel, cursorPosition: Position, itemIdToPreserveAtTop: InlineSuggestionIdentity | undefined): InlineCompletionsState {
|
||||
let itemToPreserve: InlineSuggestionItem | undefined = undefined;
|
||||
if (itemIdToPreserve) {
|
||||
const preserveCandidate = this._findById(itemIdToPreserve);
|
||||
if (preserveCandidate) {
|
||||
const updatedSuggestionsHasItemToPreserve = updatedSuggestions.some(i => i.hash === preserveCandidate.hash);
|
||||
if (!updatedSuggestionsHasItemToPreserve && preserveCandidate.canBeReused(textModel, request.position)) {
|
||||
itemToPreserve = preserveCandidate;
|
||||
if (itemIdToPreserveAtTop) {
|
||||
const itemToPreserveCandidate = this._findById(itemIdToPreserveAtTop);
|
||||
if (itemToPreserveCandidate && itemToPreserveCandidate.canBeReused(textModel, request.position)) {
|
||||
itemToPreserve = itemToPreserveCandidate;
|
||||
|
||||
const updatedItemToPreserve = updatedSuggestions.find(i => i.hash === itemToPreserveCandidate.hash);
|
||||
if (updatedItemToPreserve) {
|
||||
updatedSuggestions = moveToFront(updatedItemToPreserve, updatedSuggestions);
|
||||
} else {
|
||||
updatedSuggestions = [itemToPreserveCandidate, ...updatedSuggestions];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,22 +398,20 @@ class InlineCompletionsState extends Disposable {
|
||||
// Otherwise: prefer inline completion if there is a visible one
|
||||
: updatedSuggestions.some(i => !i.isInlineEdit && i.isVisible(textModel, cursorPosition));
|
||||
|
||||
const updatedItems: InlineSuggestionItem[] = [];
|
||||
for (const i of updatedSuggestions) {
|
||||
const oldItem = this._findByHash(i.hash);
|
||||
if (oldItem) {
|
||||
updatedItems.push(i.withIdentity(oldItem.identity));
|
||||
let item;
|
||||
if (oldItem && oldItem !== i) {
|
||||
item = i.withIdentity(oldItem.identity);
|
||||
oldItem.setEndOfLifeReason({ kind: InlineCompletionEndOfLifeReasonKind.Ignored, userTypingDisagreed: false, supersededBy: i.getSourceCompletion() });
|
||||
} else {
|
||||
updatedItems.push(i);
|
||||
item = i;
|
||||
}
|
||||
if (preferInlineCompletions !== item.isInlineEdit) {
|
||||
updatedItems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemToPreserve) {
|
||||
updatedItems.unshift(itemToPreserve);
|
||||
}
|
||||
|
||||
updatedItems = preferInlineCompletions ? updatedItems.filter(i => !i.isInlineEdit) : updatedItems.filter(i => i.isInlineEdit);
|
||||
|
||||
return new InlineCompletionsState(updatedItems, request);
|
||||
}
|
||||
|
||||
@@ -419,3 +419,11 @@ class InlineCompletionsState extends Disposable {
|
||||
return new InlineCompletionsState(this.inlineCompletions, this.request);
|
||||
}
|
||||
}
|
||||
|
||||
function moveToFront<T>(item: T, items: T[]): T[] {
|
||||
const index = items.indexOf(item);
|
||||
if (index > -1) {
|
||||
return [item, ...items.slice(0, index), ...items.slice(index + 1)];
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -420,6 +420,48 @@ suite('Inline Completions', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('Push item to preserve to front', async function () {
|
||||
const provider = new MockInlineCompletionsProvider(true);
|
||||
await withAsyncTestCodeEditorAndInlineCompletionsModel('',
|
||||
{ fakeClock: true, provider },
|
||||
async ({ editor, editorViewModel, model, context }) => {
|
||||
provider.setReturnValue({ insertText: 'foobar', range: new Range(1, 1, 1, 4) });
|
||||
context.keyboardType('foo');
|
||||
await timeout(1000);
|
||||
|
||||
assert.deepStrictEqual(provider.getAndClearCallHistory(), ([
|
||||
{
|
||||
position: "(1,4)",
|
||||
triggerKind: 0,
|
||||
text: "foo"
|
||||
}
|
||||
]));
|
||||
assert.deepStrictEqual(context.getAndClearViewStates(),
|
||||
([
|
||||
"",
|
||||
"foo[bar]"
|
||||
])
|
||||
);
|
||||
|
||||
provider.setReturnValues([{ insertText: 'foobar1', range: new Range(1, 1, 1, 4) }, { insertText: 'foobar', range: new Range(1, 1, 1, 4) }]);
|
||||
|
||||
await model.triggerExplicitly();
|
||||
await timeout(1000);
|
||||
|
||||
assert.deepStrictEqual(provider.getAndClearCallHistory(), ([
|
||||
{
|
||||
position: "(1,4)",
|
||||
triggerKind: 1,
|
||||
text: "foo"
|
||||
}
|
||||
]));
|
||||
assert.deepStrictEqual(context.getAndClearViewStates(),
|
||||
([])
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('No race conditions', async function () {
|
||||
|
||||
@@ -32,6 +32,10 @@ export class MockInlineCompletionsProvider implements InlineCompletionsProvider
|
||||
private callHistory = new Array<unknown>();
|
||||
private calledTwiceIn50Ms = false;
|
||||
|
||||
constructor(
|
||||
public readonly enableForwardStability = false,
|
||||
) { }
|
||||
|
||||
public setReturnValue(value: InlineCompletion | undefined, delayMs: number = 0): void {
|
||||
this.returnValue = value ? [value] : [];
|
||||
this.delayMs = delayMs;
|
||||
@@ -56,7 +60,7 @@ export class MockInlineCompletionsProvider implements InlineCompletionsProvider
|
||||
|
||||
private lastTimeMs: number | undefined = undefined;
|
||||
|
||||
async provideInlineCompletions(model: ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken) {
|
||||
async provideInlineCompletions(model: ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): Promise<InlineCompletions> {
|
||||
const currentTimeMs = new Date().getTime();
|
||||
if (this.lastTimeMs && currentTimeMs - this.lastTimeMs < 50) {
|
||||
this.calledTwiceIn50Ms = true;
|
||||
@@ -81,7 +85,7 @@ export class MockInlineCompletionsProvider implements InlineCompletionsProvider
|
||||
await timeout(this.delayMs);
|
||||
}
|
||||
|
||||
return { items: result };
|
||||
return { items: result, enableForwardStability: this.enableForwardStability };
|
||||
}
|
||||
disposeInlineCompletions() { }
|
||||
handleItemDidShow() { }
|
||||
|
||||
Reference in New Issue
Block a user