proper quick fix if recently edited document (#206490)

* if doc has been recently changed, wait before running code action

* checking needs delay in extension

* removed unused awaits

* removed unused checks

* remove whitespace

* remove needsDelay and adds delay in extension instead

* remove recentlyadded

* remove whitespace

* cleanup from comments

* adds back needs delay

* deal with cancellation state

* remove whitespace and needsDelay again

* clean up

* Update codeActionController.ts

* add review

* added position for extra check
This commit is contained in:
Justin Chen 2024-03-14 16:47:17 -07:00 committed by GitHub
parent d6fc8a0223
commit 7637ca582e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 8 deletions

View File

@ -198,10 +198,10 @@ class SupportedCodeActionProvider {
private readonly client: ITypeScriptServiceClient
) { }
public async getFixableDiagnosticsForContext(context: vscode.CodeActionContext): Promise<DiagnosticsSet> {
public async getFixableDiagnosticsForContext(diagnostics: readonly vscode.Diagnostic[]): Promise<DiagnosticsSet> {
const fixableCodes = await this.fixableDiagnosticCodes;
return DiagnosticsSet.from(
context.diagnostics.filter(diagnostic => typeof diagnostic.code !== 'undefined' && fixableCodes.has(diagnostic.code + '')));
diagnostics.filter(diagnostic => typeof diagnostic.code !== 'undefined' && fixableCodes.has(diagnostic.code + '')));
}
@memoize
@ -214,6 +214,8 @@ class SupportedCodeActionProvider {
class TypeScriptQuickFixProvider implements vscode.CodeActionProvider<VsCodeCodeAction> {
private static readonly _maxCodeActionsPerFile: number = 1000;
public static readonly metadata: vscode.CodeActionProviderMetadata = {
providedCodeActionKinds: [vscode.CodeActionKind.QuickFix]
};
@ -237,7 +239,7 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider<VsCodeCode
public async provideCodeActions(
document: vscode.TextDocument,
_range: vscode.Range,
range: vscode.Range,
context: vscode.CodeActionContext,
token: vscode.CancellationToken
): Promise<VsCodeCodeAction[] | undefined> {
@ -246,12 +248,32 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider<VsCodeCode
return;
}
const fixableDiagnostics = await this.supportedCodeActionProvider.getFixableDiagnosticsForContext(context);
if (!fixableDiagnostics.size || token.isCancellationRequested) {
return;
let diagnostics = context.diagnostics;
if (this.client.bufferSyncSupport.hasPendingDiagnostics(document.uri)) {
// Delay for 500ms when there are pending diagnostics before recomputing up-to-date diagnostics.
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
if (token.isCancellationRequested) {
return;
}
const allDiagnostics: vscode.Diagnostic[] = [];
// Match ranges again after getting new diagnostics
for (const diagnostic of this.diagnosticsManager.getDiagnostics(document.uri)) {
if (range.intersection(diagnostic.range)) {
const newLen = allDiagnostics.push(diagnostic);
if (newLen > TypeScriptQuickFixProvider._maxCodeActionsPerFile) {
break;
}
}
}
diagnostics = allDiagnostics;
}
if (this.client.bufferSyncSupport.hasPendingDiagnostics(document.uri)) {
const fixableDiagnostics = await this.supportedCodeActionProvider.getFixableDiagnosticsForContext(diagnostics);
if (!fixableDiagnostics.size || token.isCancellationRequested) {
return;
}

View File

@ -321,7 +321,20 @@ export class CodeActionModel extends Disposable {
if (trigger.trigger.type === CodeActionTriggerType.Invoke) {
this._progressService?.showWhile(actions, 250);
}
this.setState(new CodeActionsState.Triggered(trigger.trigger, startPosition, actions));
const newState = new CodeActionsState.Triggered(trigger.trigger, startPosition, actions);
let isManualToAutoTransition = false;
if (this._state.type === CodeActionsState.Type.Triggered) {
// Check if the current state is manual and the new state is automatic
isManualToAutoTransition = this._state.trigger.type === CodeActionTriggerType.Invoke &&
newState.type === CodeActionsState.Type.Triggered &&
newState.trigger.type === CodeActionTriggerType.Auto &&
this._state.position !== newState.position;
}
// Do not trigger state if current state is manual and incoming state is automatic
if (!isManualToAutoTransition) {
this.setState(newState);
}
}, undefined);
this._codeActionOracle.value.trigger({ type: CodeActionTriggerType.Auto, triggerAction: CodeActionTriggerSource.Default });
} else {