diff --git a/Extension/package.json b/Extension/package.json index 63375d0043..3d5b8f3734 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -1455,11 +1455,46 @@ "default": false }, "sourceFileMap": { - "type": "object", - "description": "%c_cpp.debuggers.sourceFileMap.description%", - "default": { - "": "" - } + "anyOf": [ + { + "type": "object", + "description": "%c_cpp.debuggers.sourceFileMap.description%", + "default": { + "": "" + } + }, + { + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.description%", + "type": "object", + "default": { + "": { + "editorPath": "", + "useForBreakpoints": true + } + }, + "properties": { + "": { + "type": "object", + "default": { + "editorPath": "", + "useForBreakpoints": true + }, + "properties": { + "editorPath": { + "type": "string", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.editorPath.description%", + "default": "" + }, + "useForBreakpoints": { + "type": "boolean", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.useForBreakpoints.description%", + "default": true + } + } + } + } + } + ] }, "logging": { "description": "%c_cpp.debuggers.logging.description%", @@ -1648,11 +1683,46 @@ "default": false }, "sourceFileMap": { - "type": "object", - "description": "%c_cpp.debuggers.sourceFileMap.description%", - "default": { - "": "" - } + "anyOf": [ + { + "type": "object", + "description": "%c_cpp.debuggers.sourceFileMap.description%", + "default": { + "": "" + } + }, + { + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.description%", + "type": "object", + "default": { + "": { + "editorPath": "", + "useForBreakpoints": true + } + }, + "properties": { + "": { + "type": "object", + "default": { + "editorPath": "", + "useForBreakpoints": true + }, + "properties": { + "editorPath": { + "type": "string", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.editorPath.description%", + "default": "" + }, + "useForBreakpoints": { + "type": "boolean", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.useForBreakpoints.description%", + "default": true + } + } + } + } + } + ] }, "logging": { "description": "%c_cpp.debuggers.logging.description%", diff --git a/Extension/package.nls.json b/Extension/package.nls.json index 0ad5b0051f..120d14ad07 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -227,5 +227,8 @@ "c_cpp.taskDefinitions.args.description": "Additional arguments to pass to the compiler or compilation script", "c_cpp.taskDefinitions.options.description": "Additional command options", "c_cpp.taskDefinitions.options.cwd.description": "The current working directory of the executed program or script. If omitted Code's current workspace root is used.", - "c_cpp.taskDefinitions.detail.description": "Additional details of the task" + "c_cpp.taskDefinitions.detail.description": "Additional details of the task", + "c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.description": "Current and compile-time paths to the same source trees. Files found under the EditorPath are mapped to the CompileTimePath path for breakpoint matching and mapped from CompileTimePath to EditorPath when displaying stacktrace locations.", + "c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.editorPath.description": "The path to the source tree the editor will use.", + "c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.useForBreakpoints.description": "False if this entry is only used for stack frame location mapping. True if this entry should also be used when specifying breakpoint locations." } diff --git a/Extension/src/Debugger/configurationProvider.ts b/Extension/src/Debugger/configurationProvider.ts index 1757cb6ec1..3fc8fa74cc 100644 --- a/Extension/src/Debugger/configurationProvider.ts +++ b/Extension/src/Debugger/configurationProvider.ts @@ -344,24 +344,35 @@ class CppConfigurationProvider implements vscode.DebugConfigurationProvider { let message: string = ""; const sourceFileMapTarget: string = config.sourceFileMap[sourceFileMapSource]; - // TODO: pass config.environment as 'additionalEnvironment' to resolveVariables when it is { key: value } instead of { "key": key, "value": value } - const newSourceFileMapSource: string = util.resolveVariables(sourceFileMapSource, undefined); - const newSourceFileMapTarget: string = util.resolveVariables(sourceFileMapTarget, undefined); - let source: string = sourceFileMapSource; - let target: string = sourceFileMapTarget; + let target: string | object = sourceFileMapTarget; + // TODO: pass config.environment as 'additionalEnvironment' to resolveVariables when it is { key: value } instead of { "key": key, "value": value } + const newSourceFileMapSource: string = util.resolveVariables(sourceFileMapSource, undefined); if (sourceFileMapSource !== newSourceFileMapSource) { message = "\t" + localize("replacing.sourcepath", "Replacing {0} '{1}' with '{2}'.", "sourcePath", sourceFileMapSource, newSourceFileMapSource); delete config.sourceFileMap[sourceFileMapSource]; source = newSourceFileMapSource; } - if (sourceFileMapTarget !== newSourceFileMapTarget) { - // Add a space if source was changed, else just tab the target message. - message += (message ? ' ' : '\t'); - message += localize("replacing.targetpath", "Replacing {0} '{1}' with '{2}'.", "targetPath", sourceFileMapTarget, newSourceFileMapTarget); - target = newSourceFileMapTarget; + if (util.isString(sourceFileMapTarget)) { + const newSourceFileMapTarget: string = util.resolveVariables(sourceFileMapTarget, undefined); + if (sourceFileMapTarget !== newSourceFileMapTarget) { + // Add a space if source was changed, else just tab the target message. + message += (message ? ' ' : '\t'); + message += localize("replacing.targetpath", "Replacing {0} '{1}' with '{2}'.", "targetPath", sourceFileMapTarget, newSourceFileMapTarget); + target = newSourceFileMapTarget; + } + } else if (util.isObject(sourceFileMapTarget)) { + const newSourceFileMapTarget: {"editorPath": string; "useForBreakpoints": boolean } = sourceFileMapTarget; + newSourceFileMapTarget["editorPath"] = util.resolveVariables(sourceFileMapTarget["editorPath"], undefined); + + if (sourceFileMapTarget !== newSourceFileMapTarget) { + // Add a space if source was changed, else just tab the target message. + message += (message ? ' ' : '\t'); + message += localize("replacing.editorPath", "Replacing {0} '{1}' with '{2}'.", "editorPath", sourceFileMapTarget, newSourceFileMapTarget["editorPath"]); + target = newSourceFileMapTarget; + } } if (message) { diff --git a/Extension/src/common.ts b/Extension/src/common.ts index dc8377b837..a957d65461 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -262,6 +262,10 @@ export function isBoolean(input: any): input is boolean { return typeof(input) === "boolean"; } +export function isObject(input: any): input is object { + return typeof(input) === "object"; +} + export function isArray(input: any): input is any[] { return input instanceof Array; } diff --git a/Extension/tools/GenerateOptionsSchema.ts b/Extension/tools/GenerateOptionsSchema.ts index 418f34ad29..1f74be5ea3 100644 --- a/Extension/tools/GenerateOptionsSchema.ts +++ b/Extension/tools/GenerateOptionsSchema.ts @@ -80,6 +80,15 @@ function replaceReferences(definitions: any, objects: any): any { objects[key] = refReplace(definitions, objects[key]); } + // Handle 'anyOf' with references + if (objects[key].hasOwnProperty('anyOf')) { + for (const index in objects[key].anyOf) { + if (objects[key].anyOf[index].hasOwnProperty('$ref')) { + objects[key].anyOf[index] = refReplace(definitions, objects[key].anyOf[index]); + } + } + } + // Recursively replace references if this object has properties. if (objects[key].hasOwnProperty('type') && objects[key].type === 'object' && objects[key].properties !== null) { objects[key].properties = replaceReferences(definitions, objects[key].properties); diff --git a/Extension/tools/OptionsSchema.json b/Extension/tools/OptionsSchema.json index c8f0f07e1d..1cee13b3ef 100644 --- a/Extension/tools/OptionsSchema.json +++ b/Extension/tools/OptionsSchema.json @@ -145,6 +145,37 @@ } } }, + "SourceFileMapEntry": { + "type": "object", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.description%", + "default": { + "": { + "editorPath": "", + "useForBreakpoints": true + } + }, + "properties": { + "": { + "type": "object", + "default": { + "editorPath": "", + "useForBreakpoints": true + }, + "properties": { + "editorPath": { + "type": "string", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.editorPath.description%", + "default": "" + }, + "useForBreakpoints": { + "type": "boolean", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.useForBreakpoints.description%", + "default": true + } + } + } + } + }, "CppdbgLaunchOptions": { "type": "object", "default": {}, @@ -304,11 +335,19 @@ "default": false }, "sourceFileMap": { - "type": "object", - "description": "%c_cpp.debuggers.sourceFileMap.description%", - "default": { - "": "" - } + "anyOf": [ + { + "type": "object", + "description": "%c_cpp.debuggers.sourceFileMap.description%", + "default": { + "": "" + } + }, + { + "$ref": "#/definitions/SourceFileMapEntry", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.description%" + } + ] }, "logging": { "$ref": "#/definitions/Logging", @@ -402,11 +441,19 @@ "default": false }, "sourceFileMap": { - "type": "object", - "description": "%c_cpp.debuggers.sourceFileMap.description%", - "default": { - "": "" - } + "anyOf": [ + { + "type": "object", + "description": "%c_cpp.debuggers.sourceFileMap.description%", + "default": { + "": "" + } + }, + { + "$ref": "#/definitions/SourceFileMapEntry", + "description": "%c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.description%" + } + ] }, "logging": { "$ref": "#/definitions/Logging",