提交 42f8432c 编写于 作者: I isidor

debug debt: eventing around launch.json updates and error handling

fixes #16615
fixes #16622
上级 932b40df
......@@ -13,7 +13,7 @@ import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
import { SelectActionItem, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IDebugService, IGlobalConfig, NO_CONFIGURATIONS_LABEL, State } from 'vs/workbench/parts/debug/common/debug';
import { IDebugService, NO_CONFIGURATIONS_LABEL } from 'vs/workbench/parts/debug/common/debug';
const $ = dom.$;
......@@ -38,7 +38,9 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem {
private registerListeners(): void {
this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => {
this.updateOptions();
if (e.sourceConfig.launch) {
this.updateOptions();
}
}));
this.toDispose.push(this.selectBox.onDidSelect(configurationName => {
this.debugService.getViewModel().setSelectedConfigurationName(configurationName);
......@@ -85,7 +87,7 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem {
}
public isEnabled(): boolean {
return this.debugService.state !== State.Inactive;
return this.selectBox.enabled;
}
public focus(): void {
......@@ -100,24 +102,22 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem {
this.toDispose = lifecycle.dispose(this.toDispose);
}
private updateOptions(): void {
const config = this.configurationService.getConfiguration<IGlobalConfig>('launch');
if (!config || !config.configurations || config.configurations.length === 0) {
private setEnabled(enabled: boolean): void {
this.selectBox.enabled = enabled;
if (!enabled) {
this.selectBox.setOptions([NO_CONFIGURATIONS_LABEL], 0);
this.selectBox.enabled = false;
} else {
const options = config.configurations.filter(cfg => typeof cfg.name === 'string').map(cfg => cfg.name);
if (config.compounds) {
options.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length)
.map(compound => compound.name));
}
}
}
private updateOptions(): void {
const options = this.debugService.getConfigurationManager().getConfigurationNames();
if (options.length === 0) {
this.setEnabled(false);
} else {
this.setEnabled(true);
const selected = options.indexOf(this.debugService.getViewModel().selectedConfigurationName);
this.selectBox.setOptions(options, selected);
this.selectBox.enabled = true;
}
this.debugService.getViewModel().setSelectedConfigurationName(this.selectBox.getSelected());
}
}
......
......@@ -342,6 +342,12 @@ export interface IConfigurationManager {
*/
getConfiguration(nameOrConfig: string | IConfig): TPromise<IConfig>;
/**
* Returns the names of all configurations and compounds.
* Ignores configurations which are invalid.
*/
getConfigurationNames(): string[];
/**
* Returns a compound with the specified name.
* Returns null if there is no compound with the specified name.
......
......@@ -130,6 +130,15 @@ export class DebugService implements debug.IDebugService {
lifecycleService.onShutdown(this.dispose, this);
this.toDispose.push(this.windowService.onBroadcast(this.onBroadcast, this));
this.toDispose.push(this.configurationService.onDidUpdateConfiguration((event) => {
if (event.sourceConfig.launch) {
const names = this.configurationManager.getConfigurationNames();
if (names.every(name => name !== this.viewModel.selectedConfigurationName)) {
// Current selected configuration no longer exists - take the first configuration instead.
this.viewModel.setSelectedConfigurationName(names.length ? names[0] : undefined);
}
}
}));
}
private onBroadcast(broadcast: IBroadcast): void {
......@@ -566,14 +575,6 @@ export class DebugService implements debug.IDebugService {
}
return this.configurationManager.getConfiguration(configurationOrName).then(configuration => {
if (!configuration) {
return this.configurationManager.openConfigFile(false).then(openend => {
if (openend) {
this.messageService.show(severity.Info, nls.localize('NewLaunchConfig', "Please set up the launch configuration file for your application."));
}
});
}
if (!this.configurationManager.getAdapter(configuration.type)) {
return configuration.type ? TPromise.wrapError(new Error(nls.localize('debugTypeNotSupported', "Configured debug type '{0}' is not supported.", configuration.type)))
: TPromise.wrapError(errors.create(nls.localize('debugTypeMissing', "Missing property 'type' for the chosen launch configuration."),
......@@ -611,6 +612,12 @@ export class DebugService implements debug.IDebugService {
actions: [this.taskService.configureAction(), CloseAction]
});
});
}, err => {
return this.configurationManager.openConfigFile(false).then(openend => {
if (openend) {
this.messageService.show(severity.Info, nls.localize('NewLaunchConfig', "Please set up the launch configuration file for your application. {0}", err.message));
}
});
});
})));
}
......
......@@ -262,45 +262,63 @@ export class ConfigurationManager implements debug.IConfigurationManager {
return config.compounds.filter(compound => compound.name === name).pop();
}
public getConfigurationNames(): string[] {
const config = this.configurationService.getConfiguration<debug.IGlobalConfig>('launch');
if (!config || !config.configurations) {
return [];
} else {
const names = config.configurations.filter(cfg => cfg && typeof cfg.name === 'string').map(cfg => cfg.name);
if (names.length > 0 && config.compounds) {
if (config.compounds) {
names.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length)
.map(compound => compound.name));
}
}
return names;
}
}
public getConfiguration(nameOrConfig: string | debug.IConfig): TPromise<debug.IConfig> {
const config = this.configurationService.getConfiguration<debug.IGlobalConfig>('launch');
let result: debug.IConfig = null;
let result: debug.IConfig;
if (types.isObject(nameOrConfig)) {
result = objects.deepClone(nameOrConfig) as debug.IConfig;
} else {
if (!config || !config.configurations) {
return TPromise.as(null);
if (!nameOrConfig || !config || !config.configurations || !config.configurations.length) {
return TPromise.wrapError(new Error());
}
// if the configuration name is not set yet, take the first launch config (can happen if debug viewlet has not been opened yet).
const filtered = config.configurations.filter(cfg => cfg.name === nameOrConfig);
result = filtered.length === 1 ? filtered[0] : config.configurations[0];
result = objects.deepClone(result);
const filtered = config.configurations.filter(cfg => cfg && cfg.name === nameOrConfig);
if (filtered.length !== 1) {
const message = filtered.length === 0 ? nls.localize('configurationDoesNotExist', "Configuration '{0}' does not exist.", nameOrConfig)
: nls.localize('configuraitonNotUnique', "There are multiple configurations with name '{0}'.", nameOrConfig);
return TPromise.wrapError(new Error(message));
}
result = objects.deepClone(filtered[0]);
}
if (result) {
// Set operating system specific properties #1873
const setOSProperties = (flag: boolean, osConfig: debug.IEnvConfig) => {
if (flag && osConfig) {
Object.keys(osConfig).forEach(key => {
result[key] = osConfig[key];
});
}
};
setOSProperties(isWindows, result.windows);
setOSProperties(isMacintosh, result.osx);
setOSProperties(isLinux, result.linux);
// Set operating system specific properties #1873
const setOSProperties = (flag: boolean, osConfig: debug.IEnvConfig) => {
if (flag && osConfig) {
Object.keys(osConfig).forEach(key => {
result[key] = osConfig[key];
});
}
};
setOSProperties(isWindows, result.windows);
setOSProperties(isMacintosh, result.osx);
setOSProperties(isLinux, result.linux);
// massage configuration attributes - append workspace path to relatvie paths, substitute variables in paths.
Object.keys(result).forEach(key => {
result[key] = this.configurationResolverService.resolveAny(result[key]);
});
// massage configuration attributes - append workspace path to relatvie paths, substitute variables in paths.
Object.keys(result).forEach(key => {
result[key] = this.configurationResolverService.resolveAny(result[key]);
});
const adapter = this.getAdapter(result.type);
return this.configurationResolverService.resolveInteractiveVariables(result, adapter ? adapter.variables : null);
}
return TPromise.as(null);
const adapter = this.getAdapter(result.type);
return this.configurationResolverService.resolveInteractiveVariables(result, adapter ? adapter.variables : null);
}
public openConfigFile(sideBySide: boolean): TPromise<boolean> {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册