Skip to content

Commit

Permalink
Improve creation of launch.json JSON scheme
Browse files Browse the repository at this point in the history
  • Loading branch information
isidorn committed May 5, 2021
1 parent dbb9eb4 commit 04a3fb2
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 75 deletions.
45 changes: 41 additions & 4 deletions src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ 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 { IJSONSchema } from 'vs/base/common/jsonSchema';
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
import { ITextModel } from 'vs/editor/common/model';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
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 } from 'vs/workbench/contrib/debug/common/debug';
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 } from 'vs/workbench/contrib/debug/common/debugSchemas';
import { launchSchema, debuggersExtPoint, breakpointsExtPoint, presentationSchema } from 'vs/workbench/contrib/debug/common/debugSchemas';
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';
Expand All @@ -27,6 +27,7 @@ import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/plat
import { IModeService } from 'vs/editor/common/services/modeService';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import Severity from 'vs/base/common/severity';
import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry';

const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
export class AdapterManager implements IAdapterManager {
Expand Down Expand Up @@ -91,10 +92,46 @@ export class AdapterManager implements IAdapterManager {

// update the schema to include all attributes, snippets and types from extensions.
const items = (<IJSONSchema>launchSchema.properties!['configurations'].items);
const taskSchema = TaskDefinitionRegistry.getJsonSchema();
const definitions: IJSONSchemaMap = {
'common': {
properties: {
'name': {
type: 'string',
description: nls.localize('debugName', "Name of configuration; appears in the launch configuration dropdown menu."),
default: 'Launch'
},
'debugServer': {
type: 'number',
description: nls.localize('debugServer', "For debug extension development only: if a port is specified VS Code tries to connect to a debug adapter running in server mode"),
default: 4711
},
'preLaunchTask': {
anyOf: [taskSchema, {
type: ['string']
}],
default: '',
defaultSnippets: [{ body: { task: '', type: '' } }],
description: nls.localize('debugPrelaunchTask', "Task to run before debug session starts.")
},
'postDebugTask': {
anyOf: [taskSchema, {
type: ['string'],
}],
default: '',
defaultSnippets: [{ body: { task: '', type: '' } }],
description: nls.localize('debugPostDebugTask', "Task to run after debug session ends.")
},
'presentation': presentationSchema,
'internalConsoleOptions': INTERNAL_CONSOLE_OPTIONS_SCHEMA,
}
}
};
launchSchema.definitions = definitions;
items.oneOf = [];
items.defaultSnippets = [];
this.debuggers.forEach(adapter => {
const schemaAttributes = adapter.getSchemaAttributes();
const schemaAttributes = adapter.getSchemaAttributes(definitions);
if (schemaAttributes && items.oneOf) {
items.oneOf.push(...schemaAttributes);
}
Expand Down
91 changes: 34 additions & 57 deletions src/vs/workbench/contrib/debug/common/debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,18 @@
*--------------------------------------------------------------------------------------------*/

import * as nls from 'vs/nls';
import * as objects from 'vs/base/common/objects';
import { isObject } from 'vs/base/common/types';
import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema';
import { IJSONSchema, IJSONSchemaMap, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IConfig, IDebuggerContribution, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IDebugAdapter, IDebugger, IDebugSession, IAdapterManager, IDebugService } from 'vs/workbench/contrib/debug/common/debug';
import { IConfig, IDebuggerContribution, IDebugAdapter, IDebugger, IDebugSession, IAdapterManager, IDebugService } from 'vs/workbench/contrib/debug/common/debug';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import * as ConfigurationResolverUtils from 'vs/workbench/services/configurationResolver/common/configurationResolverUtils';
import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry';
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { isDebuggerMainContribution } from 'vs/workbench/contrib/debug/common/debugUtils';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { presentationSchema } from 'vs/workbench/contrib/debug/common/debugSchemas';
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';
Expand Down Expand Up @@ -194,15 +191,15 @@ export class Debugger implements IDebugger {
};
}

getSchemaAttributes(): IJSONSchema[] | null {
getSchemaAttributes(definitions: IJSONSchemaMap): IJSONSchema[] | null {

if (!this.debuggerContribution.configurationAttributes) {
return null;
}

// fill in the default configuration attributes shared by all adapters.
const taskSchema = TaskDefinitionRegistry.getJsonSchema();
return Object.keys(this.debuggerContribution.configurationAttributes).map(request => {
const definitionId = `${this.type}:${request}`;
const attributes: IJSONSchema = this.debuggerContribution.configurationAttributes[request];
const defaultRequired = ['name', 'type', 'request'];
attributes.required = attributes.required && attributes.required.length ? defaultRequired.concat(attributes.required) : defaultRequired;
Expand All @@ -219,64 +216,44 @@ export class Debugger implements IDebugger {
errorMessage: nls.localize('debugTypeNotRecognised', "The debug type is not recognized. Make sure that you have a corresponding debug extension installed and that it is enabled."),
patternErrorMessage: nls.localize('node2NotSupported', "\"node2\" is no longer supported, use \"node\" instead and set the \"protocol\" attribute to \"inspector\".")
};
properties['name'] = {
type: 'string',
description: nls.localize('debugName', "Name of configuration; appears in the launch configuration dropdown menu."),
default: 'Launch'
};
properties['request'] = {
enum: [request],
description: nls.localize('debugRequest', "Request type of configuration. Can be \"launch\" or \"attach\"."),
};
properties['debugServer'] = {
type: 'number',
description: nls.localize('debugServer', "For debug extension development only: if a port is specified VS Code tries to connect to a debug adapter running in server mode"),
default: 4711
};
properties['preLaunchTask'] = {
anyOf: [taskSchema, {
type: ['string']
}],
default: '',
defaultSnippets: [{ body: { task: '', type: '' } }],
description: nls.localize('debugPrelaunchTask', "Task to run before debug session starts.")
};
properties['postDebugTask'] = {
anyOf: [taskSchema, {
type: ['string'],
}],
default: '',
defaultSnippets: [{ body: { task: '', type: '' } }],
description: nls.localize('debugPostDebugTask', "Task to run after debug session ends.")
};
properties['presentation'] = presentationSchema;
properties['internalConsoleOptions'] = INTERNAL_CONSOLE_OPTIONS_SCHEMA;
// Clear out windows, linux and osx fields to not have cycles inside the properties object
delete properties['windows'];
delete properties['osx'];
delete properties['linux'];

const osProperties = objects.deepClone(properties);
properties['windows'] = {
type: 'object',
description: nls.localize('debugWindowsConfiguration', "Windows specific launch configuration attributes."),
properties: osProperties
};
properties['osx'] = {
type: 'object',
description: nls.localize('debugOSXConfiguration', "OS X specific launch configuration attributes."),
properties: osProperties
};
properties['linux'] = {
type: 'object',
description: nls.localize('debugLinuxConfiguration', "Linux specific launch configuration attributes."),
properties: osProperties
};
for (const prop in definitions['common'].properties) {
properties[prop] = {
$ref: `#/definitions/common/properties/${prop}`
};
}
definitions[definitionId] = attributes;

Object.keys(properties).forEach(name => {
// Use schema allOf property to get independent error reporting #21113
ConfigurationResolverUtils.applyDeprecatedVariableMessage(properties[name]);
});
return attributes;

const result = {
allOf: [{
$ref: `#/definitions/${definitionId}`
}, {
properties: {
windows: {
$ref: `#/definitions/${definitionId}`,
description: nls.localize('debugWindowsConfiguration', "Windows specific launch configuration attributes.")
},
osx: {
$ref: `#/definitions/${definitionId}`,
description: nls.localize('debugOSXConfiguration', "OS X specific launch configuration attributes.")
},
linux: {
$ref: `#/definitions/${definitionId}`,
description: nls.localize('debugLinuxConfiguration', "Linux specific launch configuration attributes.")
}
}
}]
};

return result;
});
}
}
14 changes: 0 additions & 14 deletions src/vs/workbench/contrib/debug/test/node/debugger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,20 +149,6 @@ suite('Debug - Debugger', () => {
assert.deepStrictEqual(ae!.args, debuggerContribution.args);
});

test('schema attributes', () => {
const schemaAttribute = _debugger.getSchemaAttributes()![0];
assert.notDeepStrictEqual(schemaAttribute, debuggerContribution.configurationAttributes);
Object.keys(debuggerContribution.configurationAttributes.launch).forEach(key => {
assert.deepStrictEqual((<any>schemaAttribute)[key], (<any>debuggerContribution.configurationAttributes.launch)[key]);
});

assert.strictEqual(schemaAttribute['additionalProperties'], false);
assert.strictEqual(!!schemaAttribute['properties']!['request'], true);
assert.strictEqual(!!schemaAttribute['properties']!['name'], true);
assert.strictEqual(!!schemaAttribute['properties']!['type'], true);
assert.strictEqual(!!schemaAttribute['properties']!['preLaunchTask'], true);
});

test('merge platform specific attributes', () => {
const ae = ExecutableDebugAdapter.platformAdapterExecutable([extensionDescriptor1, extensionDescriptor2], 'mock')!;
assert.strictEqual(ae.command, platform.isLinux ? 'linuxRuntime' : (platform.isMacintosh ? 'osxRuntime' : 'winRuntime'));
Expand Down

0 comments on commit 04a3fb2

Please sign in to comment.