diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index 11014299ff5..6df4312e6f6 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -14,9 +14,8 @@ import { import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import severity from 'vs/base/common/severity'; import { AbstractDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; -import * as paths from 'vs/base/common/paths'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/parts/debug/common/debugUtils'; +import { convertToVSCPaths, convertToDAPaths, stringToUri, uriToString } from 'vs/workbench/parts/debug/common/debugUtils'; import { deepClone } from 'vs/base/common/objects'; @@ -215,11 +214,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb public $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage) { - convertToVSCPaths(message, source => { - if (typeof source.path === 'object') { - source.path = uri.revive(source.path).toString(); - } - }); + convertToVSCPaths(message, source => uriToString(source)); this._debugAdapters.get(handle).acceptMessage(message); } @@ -302,13 +297,7 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter { // since we modify Source.paths in the message in place, we need to make a copy of it (see #61129) const msg = deepClone(message); - convertToDAPaths(msg, source => { - if (paths.isAbsolute(source.path)) { - (source).path = uri.file(source.path); - } else { - (source).path = uri.parse(source.path); - } - }); + convertToDAPaths(msg, source => stringToUri(source)); this._proxy.$sendDAMessage(this._handle, msg); } diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 46ee6e9e4aa..6552de5fc9e 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -27,7 +27,7 @@ import { getTerminalLauncher, hasChildprocesses, prepareCommand } from 'vs/workb import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/node/variableResolver'; import { ExtHostConfiguration } from './extHostConfiguration'; -import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/parts/debug/common/debugUtils'; +import { convertToVSCPaths, convertToDAPaths, stringToUri, uriToString } from 'vs/workbench/parts/debug/common/debugUtils'; import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -400,11 +400,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } // DA -> VS Code - convertToVSCPaths(msg, source => { - if (paths.isAbsolute(source.path)) { - (source).path = URI.file(source.path); - } - }); + convertToVSCPaths(msg, source => stringToUri(source)); mythis._debugServiceProxy.$acceptDAMessage(handle, msg); }); @@ -435,11 +431,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { public $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): TPromise { // VS Code -> DA - convertToDAPaths(message, source => { - if (typeof source.path === 'object') { - source.path = URI.revive(source.path).fsPath; - } - }); + convertToDAPaths(message, source => uriToString(source)); const tracker = this._debugAdaptersTrackers.get(handle); if (tracker) { diff --git a/src/vs/workbench/parts/debug/common/debugSource.ts b/src/vs/workbench/parts/debug/common/debugSource.ts index a3a322880c6..992a1526095 100644 --- a/src/vs/workbench/parts/debug/common/debugSource.ts +++ b/src/vs/workbench/parts/debug/common/debugSource.ts @@ -12,6 +12,7 @@ import { DEBUG_SCHEME } from 'vs/workbench/parts/debug/common/debug'; import { IRange } from 'vs/editor/common/core/range'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { Schemas } from 'vs/base/common/network'; +import { isUri } from 'vs/workbench/parts/debug/common/debugUtils'; const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source"); @@ -36,23 +37,29 @@ export class Source { constructor(public raw: DebugProtocol.Source, sessionId: string) { let path: string; - if (!raw) { + if (raw) { + path = this.raw.path || this.raw.name; + this.available = true; + } else { this.raw = { name: UNKNOWN_SOURCE_LABEL }; this.available = false; path = `${DEBUG_SCHEME}:${UNKNOWN_SOURCE_LABEL}`; - } else { - path = this.raw.path || this.raw.name; - this.available = true; } if (this.raw.sourceReference > 0) { this.uri = uri.parse(`${DEBUG_SCHEME}:${encodeURIComponent(path)}?session=${encodeURIComponent(sessionId)}&ref=${this.raw.sourceReference}`); } else { - if (paths.isAbsolute(path)) { - this.uri = uri.file(path); - } else { - // assume that path is a URI + if (isUri(path)) { this.uri = uri.parse(path); + } else { + // assume path + if (paths.isAbsolute_posix(path) || paths.isAbsolute_win32(path)) { + this.uri = uri.file(path); + } else { + // path is relative + // should not happen because relative paths always have a sourceReference > 0 + console.error('cannot handle relative paths without sourceReference'); + } } } } diff --git a/src/vs/workbench/parts/debug/common/debugUtils.ts b/src/vs/workbench/parts/debug/common/debugUtils.ts index f2be8a2b233..24091e11889 100644 --- a/src/vs/workbench/parts/debug/common/debugUtils.ts +++ b/src/vs/workbench/parts/debug/common/debugUtils.ts @@ -5,6 +5,8 @@ import { equalsIgnoreCase } from 'vs/base/common/strings'; import { IConfig } from 'vs/workbench/parts/debug/common/debug'; +import { URI as uri } from 'vs/base/common/uri'; +import { isAbsolute_posix, isAbsolute_win32 } from 'vs/base/common/paths'; const _formatPIIRegexp = /{([^}]+)}/g; @@ -67,6 +69,41 @@ export function getExactExpressionStartAndEnd(lineContent: string, looseStart: n { start: 0, end: 0 }; } +// RFC 2396, Appendix A: https://www.ietf.org/rfc/rfc2396.txt +const _schemePattern = /^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/; + +export function isUri(s: string) { + // heuristics: a valid uri starts with a scheme and + // the scheme has at least 2 characters so that it doesn't look like a drive letter. + return s && s.match(_schemePattern); +} + +export function stringToUri(source: DebugProtocol.Source): void { + if (typeof source.path === 'string') { + if (isUri(source.path)) { + (source).path = uri.parse(source.path); + } else { + // assume path + if (isAbsolute_posix(source.path) || isAbsolute_win32(source.path)) { + (source).path = uri.file(source.path); + } else { + // leave relative path as is + } + } + } +} + +export function uriToString(source: DebugProtocol.Source): void { + if (typeof source.path === 'object') { + const u = uri.revive(source.path); + if (u.scheme === 'file') { + source.path = u.fsPath; + } else { + source.path = u.toString(); + } + } +} + // path hooks helpers export function convertToDAPaths(msg: DebugProtocol.ProtocolMessage, fixSourcePaths: (source: DebugProtocol.Source) => void): void {