Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Event } from '../../../../base/common/event.js';
7
import { URI, UriComponents } from '../../../../base/common/uri.js';
8
import { IChannel } from '../../../../base/parts/ipc/common/ipc.js';
9
import { IExtensionHostDebugService, IOpenExtensionWindowResult } from '../../../../platform/debug/common/extensionHostDebug.js';
10
import { ExtensionHostDebugBroadcastChannel, ExtensionHostDebugChannelClient } from '../../../../platform/debug/common/extensionHostDebugIpc.js';
11
import { IFileService } from '../../../../platform/files/common/files.js';
12
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
13
import { ILogService } from '../../../../platform/log/common/log.js';
14
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
15
import { isFolderToOpen, isWorkspaceToOpen } from '../../../../platform/window/common/window.js';
16
import { IWorkspaceContextService, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, toWorkspaceIdentifier, hasWorkspaceFileExtension } from '../../../../platform/workspace/common/workspace.js';
17
import { IWorkspace, IWorkspaceProvider } from '../../../browser/web.api.js';
18
import { IBrowserWorkbenchEnvironmentService } from '../../../services/environment/browser/environmentService.js';
19
import { IHostService } from '../../../services/host/browser/host.js';
20
import { IRemoteAgentService } from '../../../services/remote/common/remoteAgentService.js';
21
22
class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient implements IExtensionHostDebugService {
23
24
private static readonly LAST_EXTENSION_DEVELOPMENT_WORKSPACE_KEY = 'debug.lastExtensionDevelopmentWorkspace';
25
26
private workspaceProvider: IWorkspaceProvider;
27
28
private readonly storageService: IStorageService;
29
private readonly fileService: IFileService;
30
31
constructor(
32
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
33
@IBrowserWorkbenchEnvironmentService environmentService: IBrowserWorkbenchEnvironmentService,
34
@ILogService logService: ILogService,
35
@IHostService hostService: IHostService,
36
@IWorkspaceContextService contextService: IWorkspaceContextService,
37
@IStorageService storageService: IStorageService,
38
@IFileService fileService: IFileService
39
) {
40
const connection = remoteAgentService.getConnection();
41
let channel: IChannel;
42
if (connection) {
43
channel = connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName);
44
} else {
45
// Extension host debugging not supported in serverless.
46
channel = { call: async () => undefined, listen: () => Event.None } as any;
47
}
48
49
super(channel);
50
51
this.storageService = storageService;
52
this.fileService = fileService;
53
54
if (environmentService.options && environmentService.options.workspaceProvider) {
55
this.workspaceProvider = environmentService.options.workspaceProvider;
56
} else {
57
this.workspaceProvider = { open: async () => true, workspace: undefined, trusted: undefined };
58
logService.warn('Extension Host Debugging not available due to missing workspace provider.');
59
}
60
61
// Reload window on reload request
62
this._register(this.onReload(event => {
63
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
64
hostService.reload();
65
}
66
}));
67
68
// Close window on close request
69
this._register(this.onClose(event => {
70
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
71
hostService.close();
72
}
73
}));
74
75
// Remember workspace as last used for extension development
76
// (unless this is API tests) to restore for a future session
77
if (environmentService.isExtensionDevelopment && !environmentService.extensionTestsLocationURI) {
78
const workspaceId = toWorkspaceIdentifier(contextService.getWorkspace());
79
if (isSingleFolderWorkspaceIdentifier(workspaceId) || isWorkspaceIdentifier(workspaceId)) {
80
const serializedWorkspace = isSingleFolderWorkspaceIdentifier(workspaceId) ? { folderUri: workspaceId.uri.toJSON() } : { workspaceUri: workspaceId.configPath.toJSON() };
81
storageService.store(BrowserExtensionHostDebugService.LAST_EXTENSION_DEVELOPMENT_WORKSPACE_KEY, JSON.stringify(serializedWorkspace), StorageScope.PROFILE, StorageTarget.MACHINE);
82
} else {
83
storageService.remove(BrowserExtensionHostDebugService.LAST_EXTENSION_DEVELOPMENT_WORKSPACE_KEY, StorageScope.PROFILE);
84
}
85
}
86
}
87
88
override async openExtensionDevelopmentHostWindow(args: string[], _debugRenderer: boolean): Promise<IOpenExtensionWindowResult> {
89
90
// Add environment parameters required for debug to work
91
const environment = new Map<string, string>();
92
93
const fileUriArg = this.findArgument('file-uri', args);
94
if (fileUriArg && !hasWorkspaceFileExtension(fileUriArg)) {
95
environment.set('openFile', fileUriArg);
96
}
97
98
const copyArgs = [
99
'extensionDevelopmentPath',
100
'extensionTestsPath',
101
'extensionEnvironment',
102
'debugId',
103
'inspect-brk-extensions',
104
'inspect-extensions',
105
];
106
107
for (const argName of copyArgs) {
108
const value = this.findArgument(argName, args);
109
if (value) {
110
environment.set(argName, value);
111
}
112
}
113
114
// Find out which workspace to open debug window on
115
let debugWorkspace: IWorkspace = undefined;
116
const folderUriArg = this.findArgument('folder-uri', args);
117
if (folderUriArg) {
118
debugWorkspace = { folderUri: URI.parse(folderUriArg) };
119
} else {
120
const fileUriArg = this.findArgument('file-uri', args);
121
if (fileUriArg && hasWorkspaceFileExtension(fileUriArg)) {
122
debugWorkspace = { workspaceUri: URI.parse(fileUriArg) };
123
}
124
}
125
126
const extensionTestsPath = this.findArgument('extensionTestsPath', args);
127
if (!debugWorkspace && !extensionTestsPath) {
128
const lastExtensionDevelopmentWorkspace = this.storageService.get(BrowserExtensionHostDebugService.LAST_EXTENSION_DEVELOPMENT_WORKSPACE_KEY, StorageScope.PROFILE);
129
if (lastExtensionDevelopmentWorkspace) {
130
try {
131
const serializedWorkspace: { workspaceUri?: UriComponents; folderUri?: UriComponents } = JSON.parse(lastExtensionDevelopmentWorkspace);
132
if (serializedWorkspace.workspaceUri) {
133
debugWorkspace = { workspaceUri: URI.revive(serializedWorkspace.workspaceUri) };
134
} else if (serializedWorkspace.folderUri) {
135
debugWorkspace = { folderUri: URI.revive(serializedWorkspace.folderUri) };
136
}
137
} catch (error) {
138
// ignore
139
}
140
}
141
}
142
143
// Validate workspace exists
144
if (debugWorkspace) {
145
const debugWorkspaceResource = isFolderToOpen(debugWorkspace) ? debugWorkspace.folderUri : isWorkspaceToOpen(debugWorkspace) ? debugWorkspace.workspaceUri : undefined;
146
if (debugWorkspaceResource) {
147
const workspaceExists = await this.fileService.exists(debugWorkspaceResource);
148
if (!workspaceExists) {
149
debugWorkspace = undefined;
150
}
151
}
152
}
153
154
// Open debug window as new window. Pass arguments over.
155
const success = await this.workspaceProvider.open(debugWorkspace, {
156
reuse: false, // debugging always requires a new window
157
payload: Array.from(environment.entries()) // mandatory properties to enable debugging
158
});
159
160
return { success };
161
}
162
163
private findArgument(key: string, args: string[]): string | undefined {
164
for (const a of args) {
165
const k = `--${key}=`;
166
if (a.indexOf(k) === 0) {
167
return a.substring(k.length);
168
}
169
}
170
171
return undefined;
172
}
173
}
174
175
registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService, InstantiationType.Delayed);
176
177