diff --git a/src/vs/editor/contrib/codeAction/codeActionModel.ts b/src/vs/editor/contrib/codeAction/codeActionModel.ts index 4afe90c451eb3..c3ef8c90f78aa 100644 --- a/src/vs/editor/contrib/codeAction/codeActionModel.ts +++ b/src/vs/editor/contrib/codeAction/codeActionModel.ts @@ -4,10 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { CancelablePromise, createCancelablePromise, TimeoutTimer } from 'vs/base/common/async'; +import { isPromiseCanceledError } from 'vs/base/common/errors'; import { Emitter } from 'vs/base/common/event'; import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; @@ -15,10 +18,8 @@ import { CodeActionProviderRegistry, CodeActionTriggerType } from 'vs/editor/com import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IEditorProgressService, Progress } from 'vs/platform/progress/common/progress'; -import { getCodeActions, CodeActionSet } from './codeAction'; +import { CodeActionSet, getCodeActions } from './codeAction'; import { CodeActionTrigger } from './types'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import { isEqual } from 'vs/base/common/resources'; export const SUPPORTED_CODE_ACTIONS = new RawContextKey('supportedCodeAction', ''); @@ -147,17 +148,38 @@ export namespace CodeActionsState { export class Triggered { readonly type = Type.Triggered; + public readonly actions: Promise; + constructor( public readonly trigger: CodeActionTrigger, public readonly rangeOrSelection: Range | Selection, public readonly position: Position, - public readonly actions: CancelablePromise, - ) { } + private readonly _cancellablePromise: CancelablePromise, + ) { + this.actions = _cancellablePromise.catch((e): CodeActionSet => { + if (isPromiseCanceledError(e)) { + return emptyCodeActionSet; + } + throw e; + }); + } + + public cancel() { + this._cancellablePromise.cancel(); + } } export type State = typeof Empty | Triggered; } +const emptyCodeActionSet: CodeActionSet = { + allActions: [], + validActions: [], + dispose: () => { }, + documentation: [], + hasAutoFix: false +}; + export class CodeActionModel extends Disposable { private readonly _codeActionOracle = this._register(new MutableDisposable()); @@ -167,6 +189,8 @@ export class CodeActionModel extends Disposable { private readonly _onDidChangeState = this._register(new Emitter()); public readonly onDidChangeState = this._onDidChangeState.event; + #isDisposed = false; + constructor( private readonly _editor: ICodeEditor, private readonly _markerService: IMarkerService, @@ -184,11 +208,20 @@ export class CodeActionModel extends Disposable { } dispose(): void { + if (this.#isDisposed) { + return; + } + this.#isDisposed = true; + super.dispose(); this.setState(CodeActionsState.Empty, true); } private _update(): void { + if (this.#isDisposed) { + return; + } + this._codeActionOracle.value = undefined; this.setState(CodeActionsState.Empty); @@ -240,12 +273,12 @@ export class CodeActionModel extends Disposable { // Cancel old request if (this._state.type === CodeActionsState.Type.Triggered) { - this._state.actions.cancel(); + this._state.cancel(); } this._state = newState; - if (!skipNotify) { + if (!skipNotify && !this.#isDisposed) { this._onDidChangeState.fire(newState); } }