Skip to content

Commit ff7f63b

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fix-1278
2 parents af9b719 + ef66f3a commit ff7f63b

File tree

6 files changed

+159
-52
lines changed

6 files changed

+159
-52
lines changed

package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,12 +1668,7 @@
16681668
"number",
16691669
"string"
16701670
],
1671-
"description": "The CSP debug ID to use to identify the target process. If provided, 'processId' and 'stopOnEntry' are ignored."
1672-
},
1673-
"stopOnEntry": {
1674-
"type": "boolean",
1675-
"description": "Automatically stop target after attach. If not specified, target does not stop.",
1676-
"default": false
1671+
"description": "The CSP debug ID to use to identify the target process. If provided, 'processId' is ignored."
16771672
}
16781673
}
16791674
}
@@ -1686,7 +1681,12 @@
16861681
"type": "objectscript",
16871682
"request": "launch",
16881683
"name": "XDebug"
1689-
}
1684+
},
1685+
{
1686+
"type": "objectscript",
1687+
"request": "attach",
1688+
"name": "Attach to running process"
1689+
}
16901690
],
16911691
"configurationSnippets": [
16921692
{

src/commands/project.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,14 @@ export async function deleteProject(node: ProjectNode | undefined): Promise<any>
169169
api = new AtelierAPI(vscode.Uri.parse(`isfs://${serverName}:${namespace}/`));
170170
project = await pickProject(api);
171171
}
172-
if (project === undefined) {
172+
if (project == undefined) {
173173
return;
174174
}
175175

176176
try {
177+
// Ask the user for confirmation
178+
const answer = await vscode.window.showWarningMessage(`Delete project '${project}'?`, { modal: true }, "Yes", "No");
179+
if (answer != "Yes") return;
177180
// Delete the project
178181
await api.actionQuery("DELETE FROM %Studio.Project WHERE Name = ?", [project]);
179182
} catch (error) {
@@ -446,7 +449,7 @@ async function pickAdditions(
446449
if (items.findIndex((pi) => pi.Type == "DIR" && pi.Name == app) == -1) {
447450
return {
448451
label: "$(folder) " + app,
449-
fullName: app,
452+
fullName: i,
450453
buttons: [
451454
{
452455
iconPath: new vscode.ThemeIcon("chevron-right"),
@@ -507,7 +510,7 @@ async function pickAdditions(
507510
if (category == "CLS" || !item.fullName.includes("/")) {
508511
tmpParams = [item.fullName + "/*.cls", sys, gen, project, item.fullName + ".", item.fullName + "."];
509512
} else {
510-
tmpParams = [item.fullName + "/*", sys, gen, project, item.fullName + "/"];
513+
tmpParams = [item.fullName + "/*", sys, gen, project, item.fullName.slice(1) + "/"];
511514
}
512515
if (category == undefined) {
513516
if (item.fullName.includes("/")) {
@@ -714,7 +717,11 @@ export async function modifyProject(
714717

715718
let newAdd: ProjectItem[] = [];
716719
let newRemove: ProjectItem[] = [];
717-
const addResult = addProjectItem(type == "CLS" || type == "PKG" ? pick.slice(0, -4) : pick, type, items);
720+
const addResult = addProjectItem(
721+
type == "CLS" || type == "PKG" ? pick.slice(0, -4) : type == "CSP" || type == "DIR" ? pick.slice(1) : pick,
722+
type,
723+
items
724+
);
718725
newAdd = addResult.add;
719726
newRemove = addResult.remove;
720727

src/debug/debugAdapterFactory.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,41 @@ import { ObjectScriptDebugSession } from "./debugSession";
55
export class ObjectScriptDebugAdapterDescriptorFactory
66
implements vscode.DebugAdapterDescriptorFactory, vscode.Disposable
77
{
8-
private server?: net.Server;
8+
private serverMap = new Map<string, net.Server>();
99

1010
public createDebugAdapterDescriptor(
1111
session: vscode.DebugSession,
1212
executable: vscode.DebugAdapterExecutable | undefined
1313
): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
14-
if (!this.server) {
15-
// start listening on a random port
16-
const debugSession = new ObjectScriptDebugSession();
14+
const debugSession = new ObjectScriptDebugSession();
15+
16+
// pickProcess may have added a suffix to inform us which folder's connection it used
17+
const workspaceFolderIndex = (session.configuration.processId as string)?.split("@")[1];
18+
const workspaceFolderUri = workspaceFolderIndex
19+
? vscode.workspace.workspaceFolders[parseInt(workspaceFolderIndex)]?.uri
20+
: undefined;
21+
debugSession.setupAPI(workspaceFolderUri);
1722

18-
this.server = net
23+
const serverId = debugSession.serverId;
24+
let server = this.serverMap.get(serverId);
25+
if (!server) {
26+
// start listening on a random port
27+
server = net
1928
.createServer((socket) => {
2029
debugSession.setRunAsServer(true);
2130
debugSession.start(socket as NodeJS.ReadableStream, socket);
2231
})
2332
.listen(0);
33+
this.serverMap.set(serverId, server);
2434
}
2535

26-
// make VS Code connect to debug server
27-
const address = this.server.address();
36+
// make VS Code connect to this debug server
37+
const address = server.address();
2838
const port = typeof address !== "string" ? address.port : 9000;
2939
return new vscode.DebugAdapterServer(port);
3040
}
3141

3242
public dispose(): void {
33-
if (this.server) {
34-
this.server.close();
35-
}
43+
this.serverMap.forEach((server) => server.close());
3644
}
3745
}

src/debug/debugSession.ts

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ async function convertClientPathToDebugger(uri: vscode.Uri, namespace: string):
6363
}
6464

6565
export class ObjectScriptDebugSession extends LoggingDebugSession {
66+
/** After setupAPI() has been called this will return the serverId string */
67+
public get serverId(): string | undefined {
68+
return this._api?.serverId;
69+
}
70+
71+
private _api?: AtelierAPI;
72+
73+
private _workspaceFolderUri?: vscode.Uri;
74+
6675
private _statuses = new Map<xdebug.Connection, xdebug.StatusResponse>();
6776

6877
private _connection: xdebug.Connection;
@@ -89,8 +98,6 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
8998

9099
private _workspace: string;
91100

92-
private cookies: string[] = [];
93-
94101
/** If this is a CSPDEBUG session */
95102
private _isCsp = false;
96103

@@ -106,9 +113,6 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
106113
/** If we're stopped at a breakpoint. */
107114
private _break = false;
108115

109-
/** If we should automatically stop target */
110-
private _stopOnEntry: boolean;
111-
112116
/** If this is a `launch` session */
113117
private _isLaunch = false;
114118

@@ -127,6 +131,27 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
127131
} while (!this._debugTargetSet);
128132
}
129133

134+
/** To be called immediately after construction */
135+
public setupAPI(workspaceFolderUri?: vscode.Uri): void {
136+
// Only effective the first time
137+
if (this._api) {
138+
return;
139+
}
140+
141+
this._workspaceFolderUri = workspaceFolderUri;
142+
if (workspaceFolderUri) {
143+
// The uri of the relevant workspace folder was set after construction
144+
this._workspace = undefined;
145+
this._api = new AtelierAPI(workspaceFolderUri);
146+
} else {
147+
// Fall back to old way of deciding where to connect
148+
const file = currentFile();
149+
this._workspace = file?.workspaceFolder;
150+
this._api = new AtelierAPI(file?.uri);
151+
}
152+
return;
153+
}
154+
130155
/** Check if the target is stopped */
131156
private async _isStopped(): Promise<boolean> {
132157
return this._connection
@@ -164,21 +189,16 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
164189
};
165190

166191
try {
167-
const file = currentFile();
168-
this._workspace = file?.workspaceFolder;
169-
170-
const api = new AtelierAPI(file?.uri);
171-
this.cookies = api.cookies;
172-
if (!api.active) {
192+
if (!this._api.active) {
173193
throw new Error("Connection not active");
174194
}
175-
this._namespace = api.ns;
176-
this._url = api.xdebugUrl();
195+
this._namespace = this._api.ns;
196+
this._url = this._api.xdebugUrl();
177197

178198
const socket = new WebSocket(this._url, {
179199
rejectUnauthorized: vscode.workspace.getConfiguration("http").get("proxyStrictSSL"),
180200
headers: {
181-
cookie: this.cookies,
201+
cookie: this._api.cookies,
182202
},
183203
});
184204

@@ -228,7 +248,7 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
228248

229249
protected async launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): Promise<void> {
230250
try {
231-
this._debugTargetSet = this._stopOnEntry = false;
251+
this._debugTargetSet = false;
232252
this._isLaunch = true;
233253
const debugTarget = `${this._namespace}:${args.program}`;
234254
await this._connection.sendFeatureSetCommand("debug_target", debugTarget, true);
@@ -243,8 +263,8 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
243263
protected async attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): Promise<void> {
244264
try {
245265
this._debugTargetSet = this._isLaunch = false;
246-
this._stopOnEntry = args.stopOnEntry;
247-
const debugTarget = args.cspDebugId != undefined ? `CSPDEBUG:${args.cspDebugId}` : `PID:${args.processId}`;
266+
const debugTarget =
267+
args.cspDebugId != undefined ? `CSPDEBUG:${args.cspDebugId}` : `PID:${args.processId.split("@")[0]}`;
248268
await this._connection.sendFeatureSetCommand("debug_target", debugTarget);
249269
if (args.cspDebugId != undefined) {
250270
if (args.isUnitTest) {
@@ -258,7 +278,6 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
258278
await this._connection.sendBreakpointSetCommand(new xdebug.Watchpoint("ok", this._cspWatchpointCondition));
259279
this._isCsp = true;
260280
}
261-
this._stopOnEntry = false;
262281
this.sendResponse(response);
263282
} else {
264283
this._isCsp = false;
@@ -291,11 +310,9 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
291310
args: DebugProtocol.ConfigurationDoneArguments
292311
): Promise<void> {
293312
if (!this._isLaunch && !this._isCsp) {
294-
// The debug agent ignores the first run command for non-CSP attaches,
295-
// so send one right away, regardless of the stopOnEntry value
313+
// The debug agent ignores the first run command
314+
// for non-CSP attaches, so send one right away
296315
await this._connection.sendRunCommand();
297-
}
298-
if (this._stopOnEntry && !this._isLaunch && !this._isCsp) {
299316
// Tell VS Code that we're stopped
300317
this.sendResponse(response);
301318
const event: DebugProtocol.StoppedEvent = new StoppedEvent("entry", this._connection.id);
@@ -597,7 +614,13 @@ export class ObjectScriptDebugSession extends LoggingDebugSession {
597614
stack.stack.map(async (stackFrame: xdebug.StackFrame, index): Promise<StackFrame> => {
598615
const [, namespace, name] = decodeURI(stackFrame.fileUri).match(/^dbgp:\/\/\|([^|]+)\|(.*)$/);
599616
const routine = name;
600-
const fileUri = DocumentContentProvider.getUri(routine, this._workspace, namespace);
617+
const fileUri = DocumentContentProvider.getUri(
618+
routine,
619+
this._workspace,
620+
namespace,
621+
undefined,
622+
this._workspaceFolderUri
623+
);
601624
const source = new Source(routine, fileUri.toString());
602625
let line = stackFrame.line + 1;
603626
const place = `${stackFrame.method}+${stackFrame.methodOffset}`;

0 commit comments

Comments
 (0)