提交 c82d0462 编写于 作者: R Rob Lourens

Implement when clauses for debugger contributions

Fix #133146
上级 0aebe7b4
......@@ -182,7 +182,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
* setting on lines where breakpoint "run" actions are present.
*/
public getContextMenuActionsAtPosition(lineNumber: number, model: ITextModel) {
if (!this.debugService.getAdapterManager().hasDebuggers()) {
if (!this.debugService.getAdapterManager().hasEnabledDebuggers()) {
return [];
}
......@@ -196,7 +196,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
private registerListeners(): void {
this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => {
if (!this.debugService.getAdapterManager().hasDebuggers()) {
if (!this.debugService.getAdapterManager().hasEnabledDebuggers()) {
return;
}
......@@ -279,7 +279,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
* 2. When users click on line numbers, the breakpoint hint displays immediately, however it doesn't create the breakpoint unless users click on the left gutter. On a touch screen, it's hard to click on that small area.
*/
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
if (!this.debugService.getAdapterManager().hasDebuggers()) {
if (!this.debugService.getAdapterManager().hasEnabledDebuggers()) {
return;
}
......
......@@ -3,36 +3,36 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import * as strings from 'vs/base/common/strings';
import { Emitter, Event } from 'vs/base/common/event';
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import * as strings from 'vs/base/common/strings';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorModel } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IModeService } from 'vs/editor/common/services/modeService';
import * as nls from 'vs/nls';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IDebugConfiguration, IConfig, IDebugAdapterDescriptorFactory, IDebugAdapter, IDebugSession, IAdapterDescriptor, IDebugAdapterFactory, CONTEXT_DEBUGGERS_AVAILABLE, IAdapterManager, INTERNAL_CONSOLE_OPTIONS_SCHEMA } from 'vs/workbench/contrib/debug/common/debug';
import { Debugger } from 'vs/workbench/contrib/debug/common/debugger';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { launchSchema, debuggersExtPoint, breakpointsExtPoint, presentationSchema } from 'vs/workbench/contrib/debug/common/debugSchemas';
import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import Severity from 'vs/base/common/severity';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { CONTEXT_DEBUGGERS_AVAILABLE, IAdapterDescriptor, IAdapterManager, IConfig, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugAdapterFactory, IDebugConfiguration, IDebugSession, INTERNAL_CONSOLE_OPTIONS_SCHEMA } from 'vs/workbench/contrib/debug/common/debug';
import { Debugger } from 'vs/workbench/contrib/debug/common/debugger';
import { breakpointsExtPoint, debuggersExtPoint, launchSchema, presentationSchema } from 'vs/workbench/contrib/debug/common/debugSchemas';
import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry';
import { IEditorModel } from 'vs/editor/common/editorCommon';
import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
export class AdapterManager implements IAdapterManager {
export class AdapterManager extends Disposable implements IAdapterManager {
private debuggers: Debugger[];
private adapterDescriptorFactories: IDebugAdapterDescriptorFactory[];
......@@ -41,6 +41,7 @@ export class AdapterManager implements IAdapterManager {
private readonly _onDidRegisterDebugger = new Emitter<void>();
private readonly _onDidDebuggersExtPointRead = new Emitter<void>();
private breakpointModeIdsSet = new Set<string>();
private debuggerWhenKeys = new Set<string>();
constructor(
@IEditorService private readonly editorService: IEditorService,
......@@ -49,14 +50,20 @@ export class AdapterManager implements IAdapterManager {
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommandService private readonly commandService: ICommandService,
@IExtensionService private readonly extensionService: IExtensionService,
@IContextKeyService contextKeyService: IContextKeyService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IModeService private readonly modeService: IModeService,
@IDialogService private readonly dialogService: IDialogService,
) {
super();
this.adapterDescriptorFactories = [];
this.debuggers = [];
this.registerListeners();
this.debuggersAvailable = CONTEXT_DEBUGGERS_AVAILABLE.bindTo(contextKeyService);
this._register(this.contextKeyService.onDidChangeContext(e => {
if (e.affectsSome(this.debuggerWhenKeys)) {
this.debuggersAvailable.set(this.hasEnabledDebuggers());
}
}));
}
private registerListeners(): void {
......@@ -72,7 +79,9 @@ export class AdapterManager implements IAdapterManager {
if (existing) {
existing.merge(rawAdapter, added.description);
} else {
this.debuggers.push(this.instantiationService.createInstance(Debugger, this, rawAdapter, added.description));
const dbg = this.instantiationService.createInstance(Debugger, this, rawAdapter, added.description);
dbg.when?.keys().forEach(key => this.debuggerWhenKeys.add(key));
this.debuggers.push(dbg);
}
}
});
......@@ -159,7 +168,7 @@ export class AdapterManager implements IAdapterManager {
registerDebugAdapterFactory(debugTypes: string[], debugAdapterLauncher: IDebugAdapterFactory): IDisposable {
debugTypes.forEach(debugType => this.debugAdapterFactories.set(debugType, debugAdapterLauncher));
this.debuggersAvailable.set(this.debugAdapterFactories.size > 0);
this.debuggersAvailable.set(this.hasEnabledDebuggers());
this._onDidRegisterDebugger.fire();
return {
......@@ -169,8 +178,15 @@ export class AdapterManager implements IAdapterManager {
};
}
hasDebuggers(): boolean {
return this.debugAdapterFactories.size > 0;
hasEnabledDebuggers(): boolean {
for (let [type] of this.debugAdapterFactories) {
const dbg = this.getDebugger(type);
if (dbg && this.isDebuggerEnabled(dbg)) {
return true;
}
}
return false;
}
createDebugAdapter(session: IDebugSession): IDebugAdapter | undefined {
......@@ -254,18 +270,24 @@ export class AdapterManager implements IAdapterManager {
return this.breakpointModeIdsSet.has(modeId);
}
isDebuggerEnabled(dbg: Debugger): boolean {
return !dbg.when || this.contextKeyService.contextMatchesRules(dbg.when);
}
getDebugger(type: string): Debugger | undefined {
return this.debuggers.find(dbg => strings.equalsIgnoreCase(dbg.type, type));
}
isDebuggerInterestedInLanguage(language: string): boolean {
return !!this.debuggers.find(a => language && a.languages && a.languages.indexOf(language) >= 0);
return !!this.debuggers
.filter(d => this.isDebuggerEnabled(d))
.find(a => language && a.languages && a.languages.indexOf(language) >= 0);
}
async guessDebugger(gettingConfigurations: boolean, type?: string): Promise<Debugger | undefined> {
if (type) {
const adapter = this.getDebugger(type);
return Promise.resolve(adapter);
return adapter && this.isDebuggerEnabled(adapter) ? adapter : undefined;
}
const activeTextEditorControl = this.editorService.activeTextEditorControl;
......
......@@ -35,7 +35,7 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
protected async _getPicks(filter: string): Promise<(IQuickPickSeparator | IPickerQuickAccessItem)[]> {
const picks: Array<IPickerQuickAccessItem | IQuickPickSeparator> = [];
if (!this.debugService.getAdapterManager().hasDebuggers()) {
if (!this.debugService.getAdapterManager().hasEnabledDebuggers()) {
return [];
}
......
......@@ -166,7 +166,7 @@ export class DebugService implements IDebugService {
this.onStateChange();
}));
this.toDispose.push(Event.any(this.adapterManager.onDidRegisterDebugger, this.configurationManager.onDidSelectConfiguration)(() => {
const debugUxValue = (this.state !== State.Inactive || (this.configurationManager.getAllConfigurations().length > 0 && this.adapterManager.hasDebuggers())) ? 'default' : 'simple';
const debugUxValue = (this.state !== State.Inactive || (this.configurationManager.getAllConfigurations().length > 0 && this.adapterManager.hasEnabledDebuggers())) ? 'default' : 'simple';
this.debugUx.set(debugUxValue);
this.debugStorage.storeDebugUxState(debugUxValue);
}));
......@@ -270,7 +270,7 @@ export class DebugService implements IDebugService {
this.debugState.set(getStateLabel(state));
this.inDebugMode.set(state !== State.Inactive);
// Only show the simple ux if debug is not yet started and if no launch.json exists
const debugUxValue = ((state !== State.Inactive && state !== State.Initializing) || (this.adapterManager.hasDebuggers() && this.configurationManager.selectedConfiguration.name)) ? 'default' : 'simple';
const debugUxValue = ((state !== State.Inactive && state !== State.Initializing) || (this.adapterManager.hasEnabledDebuggers() && this.configurationManager.selectedConfiguration.name)) ? 'default' : 'simple';
this.debugUx.set(debugUxValue);
this.debugStorage.storeDebugUxState(debugUxValue);
});
......@@ -466,7 +466,8 @@ export class DebugService implements IDebugService {
}
resolvedConfig = cfg;
if (!this.adapterManager.getDebugger(resolvedConfig.type) || (configByProviders.request !== 'attach' && configByProviders.request !== 'launch')) {
const dbg = this.adapterManager.getDebugger(resolvedConfig.type);
if (!dbg || (configByProviders.request !== 'attach' && configByProviders.request !== 'launch')) {
let message: string;
if (configByProviders.request !== 'attach' && configByProviders.request !== 'launch') {
message = configByProviders.request ? nls.localize('debugRequestNotSupported', "Attribute '{0}' has an unsupported value '{1}' in the chosen debug configuration.", 'request', configByProviders.request)
......@@ -492,6 +493,12 @@ export class DebugService implements IDebugService {
return false;
}
if (!this.adapterManager.isDebuggerEnabled(dbg)) {
const message = nls.localize('debuggerDisabled', "Configured debug type '{0}' is disabled", dbg.type);
await this.showError(message, []);
return false;
}
const result = await this.doCreateSession(sessionId, launch?.workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options);
if (result && guess && activeEditor && activeEditor.resource) {
// Remeber user choice of environment per active editor to make starting debugging smoother #124770
......
......@@ -680,6 +680,7 @@ export interface IDebuggerContribution extends IPlatformSpecificAdapterContribut
initialConfigurations?: any[];
configurationSnippets?: IJSONSchemaSnippet[];
variables?: { [key: string]: string };
when?: string;
}
export interface IDebugConfigurationProvider {
......@@ -742,7 +743,7 @@ export interface IAdapterManager {
onDidRegisterDebugger: Event<void>;
hasDebuggers(): boolean;
hasEnabledDebuggers(): boolean;
getDebugAdapterDescriptor(session: IDebugSession): Promise<IAdapterDescriptor | undefined>;
getDebuggerLabel(type: string): string | undefined;
isDebuggerInterestedInLanguage(language: string): boolean;
......
......@@ -67,6 +67,11 @@ export const debuggersExtPoint = extensionsRegistry.ExtensionsRegistry.registerE
description: nls.localize('vscode.extension.contributes.debuggers.configurationAttributes', "JSON schema configurations for validating \'launch.json\'."),
type: 'object'
},
when: {
description: nls.localize('vscode.extension.contributes.debuggers.when', "Condition which must be true to enable this type of debugger."),
type: 'string',
default: ''
},
windows: {
description: nls.localize('vscode.extension.contributes.debuggers.windows', "Windows specific settings."),
type: 'object',
......
......@@ -19,6 +19,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import { ITelemetryEndpoint } from 'vs/platform/telemetry/common/telemetry';
import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
export class Debugger implements IDebugger {
......@@ -26,6 +27,8 @@ export class Debugger implements IDebugger {
private mergedExtensionDescriptions: IExtensionDescription[] = [];
private mainExtensionDescription: IExtensionDescription | undefined;
private debuggerWhen: ContextKeyExpression | undefined;
constructor(
private adapterManager: IAdapterManager,
dbgContribution: IDebuggerContribution,
......@@ -38,6 +41,8 @@ export class Debugger implements IDebugger {
) {
this.debuggerContribution = { type: dbgContribution.type };
this.merge(dbgContribution, extensionDescription);
this.debuggerWhen = typeof this.debuggerContribution.when === 'string' ? ContextKeyExpr.deserialize(this.debuggerContribution.when) : undefined;
}
merge(otherDebuggerContribution: IDebuggerContribution, extensionDescription: IExtensionDescription): void {
......@@ -133,6 +138,10 @@ export class Debugger implements IDebugger {
return this.debuggerContribution.languages;
}
get when(): ContextKeyExpression | undefined {
return this.debuggerWhen;
}
hasInitialConfiguration(): boolean {
return !!this.debuggerContribution.initialConfigurations;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册