rename suggestions: cancel rename suggestion providers if user started typing

This commit is contained in:
Ulugbek Abdullaev 2024-03-20 18:42:05 +01:00
parent fab256d903
commit 52f8862304
2 changed files with 21 additions and 9 deletions

View file

@ -229,10 +229,9 @@ class RenameController implements IEditorContribution {
const model = this.editor.getModel(); // @ulugbekna: assumes editor still has a model, otherwise, cts1 should've been cancelled
const renameCandidatesCts = new CancellationTokenSource(cts2.token);
const newSymbolNamesProviders = this._languageFeaturesService.newSymbolNamesProvider.all(model);
const newSymbolNameProvidersResults = newSymbolNamesProviders.map(p => p.provideNewSymbolNames(model, loc.range, renameCandidatesCts.token));
trace(`requested new symbol names from ${newSymbolNamesProviders.length} providers`);
const requestRenameSuggestions = (cts: CancellationToken) => newSymbolNamesProviders.map(p => p.provideNewSymbolNames(model, loc.range, cts));
trace('creating rename input field and awaiting its result');
const supportPreview = this._bulkEditService.hasPreviewHandler() && this._configService.getValue<boolean>(this.editor.getModel().uri, 'editor.rename.enablePreview');
@ -240,8 +239,8 @@ class RenameController implements IEditorContribution {
loc.range,
loc.text,
supportPreview,
newSymbolNameProvidersResults,
renameCandidatesCts
requestRenameSuggestions,
cts2
);
trace('received response from rename input field');

View file

@ -89,7 +89,7 @@ interface IRenameInputField {
where: IRange,
currentName: string,
supportPreview: boolean,
candidates: ProviderResult<NewSymbolName[]>[],
requestRenameSuggestions: (cts: CancellationToken) => ProviderResult<NewSymbolName[]>[],
cts: CancellationTokenSource
): Promise<RenameInputFieldResult | boolean>;
@ -133,6 +133,8 @@ export class RenameWidget implements IRenameInputField, IContentWidget, IDisposa
*/
private _timeBeforeFirstInputFieldEdit: number | undefined;
private _renameCandidateProvidersCts: CancellationTokenSource | undefined;
private readonly _visibleContextKey: IContextKey<boolean>;
private readonly _disposables = new DisposableStore();
@ -200,6 +202,9 @@ export class RenameWidget implements IRenameInputField, IContentWidget, IDisposa
this._isEditingRenameCandidate = true;
}
this._timeBeforeFirstInputFieldEdit ??= this._beforeFirstInputFieldEditSW.elapsed();
if (this._renameCandidateProvidersCts?.token.isCancellationRequested === false) {
this._renameCandidateProvidersCts.cancel();
}
this._renameCandidateListView?.clearFocus();
})
);
@ -356,12 +361,16 @@ export class RenameWidget implements IRenameInputField, IContentWidget, IDisposa
where: IRange,
currentName: string,
supportPreview: boolean,
candidates: ProviderResult<NewSymbolName[]>[],
requestRenameSuggestions: (cts: CancellationToken) => ProviderResult<NewSymbolName[]>[],
cts: CancellationTokenSource
): Promise<RenameInputFieldResult | boolean> {
const { start: selectionStart, end: selectionEnd } = this._getSelection(where, currentName);
this._renameCandidateProvidersCts = new CancellationTokenSource();
const candidates = requestRenameSuggestions(this._renameCandidateProvidersCts.token);
this._updateRenameCandidates(candidates, currentName, cts.token);
this._isEditingRenameCandidate = false;
this._domNode!.classList.toggle('preview', supportPreview);
@ -379,8 +388,12 @@ export class RenameWidget implements IRenameInputField, IContentWidget, IDisposa
const disposeOnDone = new DisposableStore();
disposeOnDone.add(toDisposable(() => cts.dispose(true))); // @ulugbekna: this may result in `this.cancelInput` being called twice, but it should be safe since we set it to undefined after 1st call
this._updateRenameCandidates(candidates, currentName, cts.token);
disposeOnDone.add(toDisposable(() => {
if (this._renameCandidateProvidersCts !== undefined) {
this._renameCandidateProvidersCts.dispose(true);
this._renameCandidateProvidersCts = undefined;
}
}));
const inputResult = new DeferredPromise<RenameInputFieldResult | boolean>();