mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 18:49:00 +01:00
gracefully handle the case in which a delegate command has been disposed before execution, fixes #3265
This commit is contained in:
@@ -23,6 +23,7 @@ import {ExtHostMessageService} from 'vs/workbench/api/node/extHostMessageService
|
||||
import {ExtHostEditors} from 'vs/workbench/api/node/extHostEditors';
|
||||
import {ExtHostLanguages} from 'vs/workbench/api/node/extHostLanguages';
|
||||
import {ExtHostLanguageFeatures} from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import * as ExtHostTypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import {registerApiCommands} from 'vs/workbench/api/node/extHostApiCommands';
|
||||
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
|
||||
import Modes = require('vs/editor/common/modes');
|
||||
@@ -148,6 +149,10 @@ export class ExtHostAPIImplementation {
|
||||
const extHostStatusBar = new ExtHostStatusBar(this._threadService);
|
||||
const extHostOutputService = new ExtHostOutputService(this._threadService);
|
||||
|
||||
// the converter might create delegate commands to avoid sending args
|
||||
// around all the time
|
||||
ExtHostTypeConverters.Command.initialize(extHostCommands);
|
||||
|
||||
// env namespace
|
||||
let telemetryInfo: ITelemetryInfo;
|
||||
this.env = Object.freeze({
|
||||
|
||||
@@ -87,7 +87,7 @@ class CodeLensAdapter implements modes.ICodeLensSupport {
|
||||
data.symbols.push(<modes.ICodeLensSymbol>{
|
||||
id: String(i),
|
||||
range: TypeConverters.fromRange(lens.range),
|
||||
command: TypeConverters.Command.from(lens.command, { commands: this._commands, disposables: data.disposables })
|
||||
command: TypeConverters.Command.from(lens.command, data.disposables)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -144,7 +144,7 @@ class CodeLensAdapter implements modes.ICodeLensSupport {
|
||||
};
|
||||
}
|
||||
|
||||
symbol.command = TypeConverters.Command.from(command, { commands: this._commands, disposables: cachedData.disposables });
|
||||
symbol.command = TypeConverters.Command.from(command, cachedData.disposables);
|
||||
return symbol;
|
||||
});
|
||||
});
|
||||
@@ -315,7 +315,6 @@ class QuickFixAdapter implements modes.IQuickFixSupport {
|
||||
});
|
||||
|
||||
this._cachedCommands = dispose(this._cachedCommands);
|
||||
const ctx = { commands: this._commands, disposables: this._cachedCommands };
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideCodeActions(doc, ran, { diagnostics: allDiagnostics }, token)).then(commands => {
|
||||
if (!Array.isArray(commands)) {
|
||||
@@ -323,7 +322,7 @@ class QuickFixAdapter implements modes.IQuickFixSupport {
|
||||
}
|
||||
return commands.map((command, i) => {
|
||||
return <modes.IQuickFix> {
|
||||
command: TypeConverters.Command.from(command, ctx),
|
||||
command: TypeConverters.Command.from(command, this._cachedCommands),
|
||||
score: i
|
||||
};
|
||||
});
|
||||
|
||||
@@ -494,10 +494,23 @@ export namespace SignatureHelp {
|
||||
|
||||
export namespace Command {
|
||||
|
||||
const _delegateId = '_internal_delegate_command';
|
||||
const _cache: { [id: string]: vscode.Command } = Object.create(null);
|
||||
let _idPool = 1;
|
||||
|
||||
export function from(command: vscode.Command, context: { commands: ExtHostCommands; disposables: IDisposable[]; }): modes.ICommand {
|
||||
export function initialize(commands: ExtHostCommands) {
|
||||
return commands.registerCommand(_delegateId, (args: [string]) => {
|
||||
const [id] = args;
|
||||
const command = _cache[id];
|
||||
if (!command) {
|
||||
// handle already disposed delegations graceful
|
||||
return;
|
||||
}
|
||||
return commands.executeCommand(command.command, ...command.arguments);
|
||||
});
|
||||
}
|
||||
|
||||
export function from(command: vscode.Command, disposables: IDisposable[]): modes.ICommand {
|
||||
|
||||
if (!command) {
|
||||
return;
|
||||
@@ -510,22 +523,29 @@ export namespace Command {
|
||||
|
||||
if (!isFalsyOrEmpty(command.arguments)) {
|
||||
|
||||
// keep command around
|
||||
const id = `${command.command}-no-args-wrapper-${_idPool++}`;
|
||||
result.id = id;
|
||||
// redirect to delegate command and store actual command
|
||||
const id = `delegate/${_idPool++}/for/${command.command}`;
|
||||
|
||||
result.id = _delegateId;
|
||||
result.arguments = [id];
|
||||
_cache[id] = command;
|
||||
|
||||
const disposable1 = context.commands.registerCommand(id, () => context.commands.executeCommand(command.command, ..._cache[id].arguments));
|
||||
const disposable2 = { dispose() { delete _cache[id]; } };
|
||||
context.disposables.push(disposable1, disposable2);
|
||||
disposables.push({
|
||||
dispose() {
|
||||
delete _cache[id];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function to(command: modes.ICommand): vscode.Command {
|
||||
|
||||
let result = _cache[command.id];
|
||||
let result: vscode.Command;
|
||||
if (command.id === _delegateId) {
|
||||
let [key] = command.arguments;
|
||||
result = _cache[key];
|
||||
}
|
||||
if (!result) {
|
||||
result = {
|
||||
command: command.id,
|
||||
|
||||
Reference in New Issue
Block a user