From 0257f679e9cfc26a8df3f8582914c8bb1fb3a3f3 Mon Sep 17 00:00:00 2001 From: Camille Letavernier Date: Fri, 25 Feb 2022 13:46:11 +0100 Subject: [PATCH 1/2] 10011: Add DebugProtocolSource and DebugProtocolBreakpoint Add "DebugProtocolSource" and "DebugProtocolEndpoint" to the plug-in API, as well as the methods using these interfaces: - DebugSession.getDebugProtocolBreakpoint() - debug.asDebugSourceUri() 10011: Fix asDebugSourceUri - Rename asDebugSourceURI to getDebugSourceUri to avoid name clash - Fix the way the debug source query is built - Add tests 10011: Minor code improvements - Improve test description to be consistent with other tests - Move the SCHEME and SCHEME_PATTERN constants to debug/common for reusability 10011: Rebase on master - Rebase on master and resolve conflicts Contributed on behalf of STMicroelectronics Signed-off-by: Camille Letavernier --- CHANGELOG.md | 1 + packages/debug/src/browser/debug-session.tsx | 11 +++ .../debug/src/browser/model/debug-source.ts | 11 ++- packages/debug/src/common/debug-uri-utils.ts | 24 +++++ .../plugin-ext/src/common/plugin-api-rpc.ts | 1 + .../src/main/browser/debug/debug-main.ts | 9 ++ .../plugin-ext/src/plugin/debug/debug-ext.ts | 38 +++++++- .../debug/plugin-debug-adapter-session.ts | 4 + .../src/plugin/node/debug/debug.spec.ts | 94 +++++++++++++++++++ .../plugin-ext/src/plugin/plugin-context.ts | 3 + packages/plugin-ext/src/plugin/types-impl.ts | 11 ++- packages/plugin/src/theia.d.ts | 33 +++++++ 12 files changed, 225 insertions(+), 15 deletions(-) create mode 100644 packages/debug/src/common/debug-uri-utils.ts create mode 100644 packages/plugin-ext/src/plugin/node/debug/debug.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e823c8293f3d..aae495d0f2434 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - [core] `handleDefault`, `handleElectronDefault` method no longer called in `BrowserMainMenuFactory.registerMenu()`, `DynamicMenuWidget.buildSubMenus()` or `ElectronMainMenuFactory.fillSubmenus()`. Override the respective calling function rather than `handleDefault`. The argument to each of the three methods listed above is now `MenuNode` and not `CompositeMenuNode`, and the methods are truly recursive and called on entire menu tree. `ActionMenuNode.action` removed; access relevant field on `ActionMenuNode.command`, `.when` etc. [#11290](https://github.com/eclipse-theia/theia/pull/11290) - [core] renamed `CommonCommands.NEW_FILE` to `CommonCommands.NEW_UNTITLED_FILE` [#11429](https://github.com/eclipse-theia/theia/pull/11429) - [plugin-ext] `CodeEditorWidgetUtil` moved to `packages/plugin-ext/src/main/browser/menus/vscode-theia-menu-mappings.ts`. `MenusContributionPointHandler` extensively refactored. See PR description for details. [#11290](https://github.com/eclipse-theia/theia/pull/11290) +- [plugin] added support for `DebugProtocolBreakpoint` and `DebugProtocolSource` [#10011](https://github.com/eclipse-theia/theia/issues/10011) - Contributed on behalf of STMicroelectronics ## v1.27.0 - 6/30/2022 diff --git a/packages/debug/src/browser/debug-session.tsx b/packages/debug/src/browser/debug-session.tsx index 846a8694dcacf..86feb898b29bb 100644 --- a/packages/debug/src/browser/debug-session.tsx +++ b/packages/debug/src/browser/debug-session.tsx @@ -541,6 +541,17 @@ export class DebugSession implements CompositeTreeElement { return result; } + getBreakpoint(id: string): DebugBreakpoint | undefined { + for (const breakpoints of this._breakpoints.values()) { + const breakpoint = breakpoints.find(b => b.id === id); + if (breakpoint) { + return breakpoint; + } + + } + return undefined; + } + protected clearBreakpoints(): void { const uris = [...this._breakpoints.keys()]; this._breakpoints.clear(); diff --git a/packages/debug/src/browser/model/debug-source.ts b/packages/debug/src/browser/model/debug-source.ts index fa2010e2d522d..8a80d9f2a073a 100644 --- a/packages/debug/src/browser/model/debug-source.ts +++ b/packages/debug/src/browser/model/debug-source.ts @@ -20,6 +20,7 @@ import URI from '@theia/core/lib/common/uri'; import { DebugProtocol } from 'vscode-debugprotocol/lib/debugProtocol'; import { DebugSession } from '../debug-session'; import { URI as Uri } from '@theia/core/shared/vscode-uri'; +import { DEBUG_SCHEME, SCHEME_PATTERN } from '../../common/debug-uri-utils'; export class DebugSourceData { readonly raw: DebugProtocol.Source; @@ -58,7 +59,7 @@ export class DebugSource extends DebugSourceData { } get inMemory(): boolean { - return this.uri.scheme === DebugSource.SCHEME; + return this.uri.scheme === DEBUG_SCHEME; } get name(): string { @@ -75,16 +76,16 @@ export class DebugSource extends DebugSourceData { return this.labelProvider.getLongName(this.uri); } - static SCHEME = 'debug'; - static SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/; + static SCHEME = DEBUG_SCHEME; + static SCHEME_PATTERN = SCHEME_PATTERN; static toUri(raw: DebugProtocol.Source): URI { if (raw.sourceReference && raw.sourceReference > 0) { - return new URI().withScheme(DebugSource.SCHEME).withPath(raw.name!).withQuery(String(raw.sourceReference)); + return new URI().withScheme(DEBUG_SCHEME).withPath(raw.name!).withQuery(String(raw.sourceReference)); } if (!raw.path) { throw new Error('Unrecognized source type: ' + JSON.stringify(raw)); } - if (raw.path.match(DebugSource.SCHEME_PATTERN)) { + if (raw.path.match(SCHEME_PATTERN)) { return new URI(raw.path); } return new URI(Uri.file(raw.path)); diff --git a/packages/debug/src/common/debug-uri-utils.ts b/packages/debug/src/common/debug-uri-utils.ts new file mode 100644 index 0000000000000..107687cddb5ef --- /dev/null +++ b/packages/debug/src/common/debug-uri-utils.ts @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (C) 2022 STMicroelectronics and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ + +/** + * The URI scheme for debug URIs. + */ +export const DEBUG_SCHEME = 'debug'; +/** + * The pattern for URI schemes. + */ +export const SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/; diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index d7c06e5d304c3..532184f80ec88 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -1750,6 +1750,7 @@ export interface DebugMain { $startDebugging(folder: theia.WorkspaceFolder | undefined, nameOrConfiguration: string | theia.DebugConfiguration, options: theia.DebugSessionOptions): Promise; $stopDebugging(sessionId?: string): Promise; $customRequest(sessionId: string, command: string, args?: any): Promise; + $getDebugProtocolBreakpoint(sessionId: string, breakpointId: string): Promise; } export interface FileSystemExt { diff --git a/packages/plugin-ext/src/main/browser/debug/debug-main.ts b/packages/plugin-ext/src/main/browser/debug/debug-main.ts index e89edb2519ba5..e4a3c93440f4c 100644 --- a/packages/plugin-ext/src/main/browser/debug/debug-main.ts +++ b/packages/plugin-ext/src/main/browser/debug/debug-main.ts @@ -258,6 +258,15 @@ export class DebugMainImpl implements DebugMain, Disposable { } } + async $getDebugProtocolBreakpoint(sessionId: string, breakpointId: string): Promise { + const session = this.sessionManager.getSession(sessionId); + if (session) { + return session.getBreakpoint(breakpointId)?.raw; + } else { + throw new Error(`Debug session '${sessionId}' not found`); + } + } + async $removeBreakpoints(breakpoints: string[]): Promise { const { labelProvider, breakpointsManager, editorManager } = this; const session = this.sessionManager.currentSession; diff --git a/packages/plugin-ext/src/plugin/debug/debug-ext.ts b/packages/plugin-ext/src/plugin/debug/debug-ext.ts index 4c884dbffcd2a..a938b77004e84 100644 --- a/packages/plugin-ext/src/plugin/debug/debug-ext.ts +++ b/packages/plugin-ext/src/plugin/debug/debug-ext.ts @@ -23,13 +23,16 @@ import { PluginPackageDebuggersContribution } from '../../common/plugin-protocol import { RPCProtocol } from '../../common/rpc-protocol'; import { CommandRegistryImpl } from '../command-registry'; import { ConnectionImpl } from '../../common/connection'; -import { Disposable, Breakpoint as BreakpointExt, SourceBreakpoint, FunctionBreakpoint, Location, Range } from '../types-impl'; +import { DEBUG_SCHEME, SCHEME_PATTERN } from '@theia/debug/lib/common/debug-uri-utils'; +import { Disposable, Breakpoint as BreakpointExt, SourceBreakpoint, FunctionBreakpoint, Location, Range, URI as URIImpl } from '../types-impl'; import { PluginDebugAdapterSession } from './plugin-debug-adapter-session'; import { PluginDebugAdapterTracker } from './plugin-debug-adapter-tracker'; import uuid = require('uuid'); import { DebugAdapter } from '@theia/debug/lib/common/debug-model'; import { PluginDebugAdapterCreator } from './plugin-debug-adapter-creator'; import { NodeDebugAdapterCreator } from '../node/debug/plugin-node-debug-adapter-creator'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import TheiaURI from '@theia/core/lib/common/uri'; interface ConfigurationProviderRecord { handle: number; @@ -176,6 +179,29 @@ export class DebugExtImpl implements DebugExt { return this.proxy.$stopDebugging(session?.id); } + asDebugSourceUri(source: theia.DebugProtocolSource, session?: theia.DebugSession): theia.Uri { + const raw = source as DebugProtocol.Source; + const uri = this.getDebugSourceUri(raw, session?.id); + return URIImpl.parse(uri.toString()); + } + + private getDebugSourceUri(raw: DebugProtocol.Source, sessionId?: string): TheiaURI { + if (raw.sourceReference && raw.sourceReference > 0) { + let query = 'ref=' + String(raw.sourceReference); + if (sessionId) { + query += `&session=${sessionId}`; + } + return new TheiaURI().withScheme(DEBUG_SCHEME).withPath(raw.path || '').withQuery(query); + } + if (!raw.path) { + throw new Error('Unrecognized source type: ' + JSON.stringify(raw)); + } + if (raw.path.match(SCHEME_PATTERN)) { + return new TheiaURI(raw.path); + } + return new TheiaURI(URI.file(raw.path)); + } + registerDebugAdapterDescriptorFactory(debugType: string, factory: theia.DebugAdapterDescriptorFactory): Disposable { if (this.descriptorFactories.has(debugType)) { throw new Error(`Descriptor factory for ${debugType} has been already registered`); @@ -279,13 +305,13 @@ export class DebugExtImpl implements DebugExt { this.onDidChangeBreakpointsEmitter.fire({ added: a, removed: r, changed: c }); } - protected toBreakpointExt({ functionName, location, enabled, condition, hitCondition, logMessage }: Breakpoint): BreakpointExt | undefined { + protected toBreakpointExt({ functionName, location, enabled, condition, hitCondition, logMessage, id }: Breakpoint): BreakpointExt | undefined { if (location) { const range = new Range(location.range.startLineNumber, location.range.startColumn, location.range.endLineNumber, location.range.endColumn); - return new SourceBreakpoint(new Location(URI.revive(location.uri), range), enabled, condition, hitCondition, logMessage); + return new SourceBreakpoint(new Location(URI.revive(location.uri), range), enabled, condition, hitCondition, logMessage, id); } if (functionName) { - return new FunctionBreakpoint(functionName!, enabled, condition, hitCondition, logMessage); + return new FunctionBreakpoint(functionName!, enabled, condition, hitCondition, logMessage, id); } return undefined; } @@ -305,7 +331,9 @@ export class DebugExtImpl implements DebugExt { return response.body; } return Promise.reject(new Error(response.message ?? 'custom request failed')); - } + }, + getDebugProtocolBreakpoint: async (breakpoint: Breakpoint) => + this.proxy.$getDebugProtocolBreakpoint(sessionId, breakpoint.id) }; const tracker = await this.createDebugAdapterTracker(theiaSession); diff --git a/packages/plugin-ext/src/plugin/debug/plugin-debug-adapter-session.ts b/packages/plugin-ext/src/plugin/debug/plugin-debug-adapter-session.ts index e1a498183f451..577c82937c74e 100644 --- a/packages/plugin-ext/src/plugin/debug/plugin-debug-adapter-session.ts +++ b/packages/plugin-ext/src/plugin/debug/plugin-debug-adapter-session.ts @@ -61,6 +61,10 @@ export class PluginDebugAdapterSession extends DebugAdapterSessionImpl { return this.theiaSession.customRequest(command, args); } + async getDebugProtocolBreakpoint(breakpoint: theia.Breakpoint): Promise { + return this.theiaSession.getDebugProtocolBreakpoint(breakpoint); + } + protected override onDebugAdapterError(error: Error): void { if (this.tracker.onError) { this.tracker.onError(error); diff --git a/packages/plugin-ext/src/plugin/node/debug/debug.spec.ts b/packages/plugin-ext/src/plugin/node/debug/debug.spec.ts new file mode 100644 index 0000000000000..fba237feb742a --- /dev/null +++ b/packages/plugin-ext/src/plugin/node/debug/debug.spec.ts @@ -0,0 +1,94 @@ +/******************************************************************************** + * Copyright (C) 2022 STMicroelectronics and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +import { DebugSession } from '@theia/plugin'; +import * as chai from 'chai'; +import { ProxyIdentifier, RPCProtocol } from '../../../common/rpc-protocol'; + +import { DebugExtImpl } from '../../debug/debug-ext'; + +const expect = chai.expect; + +describe('Debug API', () => { + + describe('#asDebugSourceURI', () => { + + const mockRPCProtocol: RPCProtocol = { + getProxy(_proxyId: ProxyIdentifier): T { + return {} as T; + }, + set(_id: ProxyIdentifier, instance: R): R { + return instance; + }, + dispose(): void { + // Nothing + } + }; + + const debug = new DebugExtImpl(mockRPCProtocol); + + it('should use sourceReference, path and sessionId', () => { + const source = { + sourceReference: 3, + path: 'test/path' + }; + const session = { id: 'test-session' } as DebugSession; + const uri = debug.asDebugSourceUri(source, session); + expect(uri.toString(true)).to.be.equal('debug:test/path?ref=3&session=test-session'); + }); + + it('should use sourceReference', () => { + const source = { + sourceReference: 5 + }; + const uri = debug.asDebugSourceUri(source); + expect(uri.toString(true)).to.be.equal('debug:?ref=5'); + }); + + it('should use sourceReference and session', () => { + const source = { + sourceReference: 5 + }; + const session = { id: 'test-session' } as DebugSession; + const uri = debug.asDebugSourceUri(source, session); + expect(uri.toString(true)).to.be.equal('debug:?ref=5&session=test-session'); + }); + + it('should use sourceReference and path', () => { + const source = { + sourceReference: 4, + path: 'test/path' + }; + const uri = debug.asDebugSourceUri(source); + expect(uri.toString(true)).to.be.equal('debug:test/path?ref=4'); + }); + + it('should use path', () => { + const source = { + path: 'scheme:/full/path' + }; + const uri = debug.asDebugSourceUri(source); + expect(uri.toString(true)).to.be.equal('scheme:/full/path'); + }); + + it('should use file path', () => { + const source = { + path: '/full/path' + }; + const uri = debug.asDebugSourceUri(source); + expect(uri.toString(true)).to.be.equal('file:///full/path'); + }); + }); +}); diff --git a/packages/plugin-ext/src/plugin/plugin-context.ts b/packages/plugin-ext/src/plugin/plugin-context.ts index e9a8adcd973c9..0ecbc837047fb 100644 --- a/packages/plugin-ext/src/plugin/plugin-context.ts +++ b/packages/plugin-ext/src/plugin/plugin-context.ts @@ -868,6 +868,9 @@ export function createAPIFactory( }, removeBreakpoints(breakpoints: readonly theia.Breakpoint[]): void { debugExt.removeBreakpoints(breakpoints); + }, + asDebugSourceUri(source: theia.DebugProtocolSource, session?: theia.DebugSession): theia.Uri { + return debugExt.asDebugSourceUri(source, session); } }; diff --git a/packages/plugin-ext/src/plugin/types-impl.ts b/packages/plugin-ext/src/plugin/types-impl.ts index afbc66cad604c..5ababe64d05ac 100644 --- a/packages/plugin-ext/src/plugin/types-impl.ts +++ b/packages/plugin-ext/src/plugin/types-impl.ts @@ -2250,11 +2250,12 @@ export class Breakpoint { */ logMessage?: string; - protected constructor(enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string) { + protected constructor(enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, id?: string) { this.enabled = enabled || false; this.condition = condition; this.hitCondition = hitCondition; this.logMessage = logMessage; + this._id = id; } private _id: string | undefined; @@ -2283,8 +2284,8 @@ export class SourceBreakpoint extends Breakpoint { /** * Create a new breakpoint for a source location. */ - constructor(location: Location, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string) { - super(enabled, condition, hitCondition, logMessage); + constructor(location: Location, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, id?: string) { + super(enabled, condition, hitCondition, logMessage, id); this.location = location; } } @@ -2302,8 +2303,8 @@ export class FunctionBreakpoint extends Breakpoint { /** * Create a new function breakpoint. */ - constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string) { - super(enabled, condition, hitCondition, logMessage); + constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, id?: string) { + super(enabled, condition, hitCondition, logMessage, id); this.functionName = functionName; } } diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index bbf8349baf4c0..e7151d334a047 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -9868,6 +9868,20 @@ export module '@theia/plugin' { // Properties: see details [here](https://microsoft.github.io/debug-adapter-protocol/specification#Base_Protocol_ProtocolMessage). } + /** + * A DebugProtocolBreakpoint is an opaque stand-in type for the [Breakpoint](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Breakpoint) type defined in the Debug Adapter Protocol. + */ + export interface DebugProtocolBreakpoint { + // Properties: see details [here](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Breakpoint) + } + + /** + * A DebugProtocolSource is an opaque stand-in type for the [Source](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source) type defined in the Debug Adapter Protocol. + */ + export interface DebugProtocolSource { + // Properties: see details [here](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source) + } + /** * Configuration for a debug session. */ @@ -9927,6 +9941,15 @@ export module '@theia/plugin' { * Send a custom request to the debug adapter. */ customRequest(command: string, args?: any): Thenable; + + /** + * Maps a breakpoint in the editor to the corresponding Debug Adapter Protocol (DAP) breakpoint that + * is managed by the debug adapter of the debug session. If no DAP breakpoint exists (either because + * the editor breakpoint was not yet registered or because the debug adapter is not interested in the + * breakpoint), the value undefined is returned. + * @param breakpoint a Breakpoint in the editor. + */ + getDebugProtocolBreakpoint(breakpoint: Breakpoint): PromiseLike } /** @@ -10402,6 +10425,16 @@ export module '@theia/plugin' { */ export function registerDebugAdapterDescriptorFactory(debugType: string, factory: DebugAdapterDescriptorFactory): Disposable; + /** + * Converts a "Source" descriptor object received via the Debug Adapter Protocol into a Uri that can be used to load its contents. + * If the source descriptor is based on a path, a file Uri is returned. If the source descriptor uses a reference number, a + * specific debug Uri (scheme 'debug') is constructed that requires a corresponding ContentProvider and a running debug session + * If the "Source" descriptor has insufficient information for creating the Uri, an error is thrown. + * @param source An object conforming to the Source type defined in the Debug Adapter Protocol. + * @param session An optional debug session that will be used when the source descriptor uses a reference number to load the contents from an active debug session. + */ + export function asDebugSourceUri(source: DebugProtocolSource, session?: DebugSession): Uri; + /** * Register a {@link DebugConfigurationProvider debug configuration provider} for a specific debug type. * The optional {@link DebugConfigurationProviderTriggerKind triggerKind} can be used to specify when the `provideDebugConfigurations` method of the provider is triggered. From 611ab0ab77f2e26f8da3b0f969ded2eb3085d5b1 Mon Sep 17 00:00:00 2001 From: Camille Letavernier Date: Thu, 21 Jul 2022 11:03:58 +0200 Subject: [PATCH 2/2] 10011: Use VSCode URI instead of Theia URI --- packages/plugin-ext/src/plugin/debug/debug-ext.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/plugin-ext/src/plugin/debug/debug-ext.ts b/packages/plugin-ext/src/plugin/debug/debug-ext.ts index a938b77004e84..9b952167eced4 100644 --- a/packages/plugin-ext/src/plugin/debug/debug-ext.ts +++ b/packages/plugin-ext/src/plugin/debug/debug-ext.ts @@ -32,7 +32,6 @@ import { DebugAdapter } from '@theia/debug/lib/common/debug-model'; import { PluginDebugAdapterCreator } from './plugin-debug-adapter-creator'; import { NodeDebugAdapterCreator } from '../node/debug/plugin-node-debug-adapter-creator'; import { DebugProtocol } from 'vscode-debugprotocol'; -import TheiaURI from '@theia/core/lib/common/uri'; interface ConfigurationProviderRecord { handle: number; @@ -180,26 +179,24 @@ export class DebugExtImpl implements DebugExt { } asDebugSourceUri(source: theia.DebugProtocolSource, session?: theia.DebugSession): theia.Uri { - const raw = source as DebugProtocol.Source; - const uri = this.getDebugSourceUri(raw, session?.id); - return URIImpl.parse(uri.toString()); + return this.getDebugSourceUri(source, session?.id); } - private getDebugSourceUri(raw: DebugProtocol.Source, sessionId?: string): TheiaURI { + private getDebugSourceUri(raw: DebugProtocol.Source, sessionId?: string): theia.Uri { if (raw.sourceReference && raw.sourceReference > 0) { let query = 'ref=' + String(raw.sourceReference); if (sessionId) { query += `&session=${sessionId}`; } - return new TheiaURI().withScheme(DEBUG_SCHEME).withPath(raw.path || '').withQuery(query); + return URIImpl.from({ scheme: DEBUG_SCHEME, path: raw.path ?? '', query }); } if (!raw.path) { throw new Error('Unrecognized source type: ' + JSON.stringify(raw)); } if (raw.path.match(SCHEME_PATTERN)) { - return new TheiaURI(raw.path); + return URIImpl.parse(raw.path); } - return new TheiaURI(URI.file(raw.path)); + return URIImpl.file(raw.path); } registerDebugAdapterDescriptorFactory(debugType: string, factory: theia.DebugAdapterDescriptorFactory): Disposable {