Skip to content

Commit 55d7206

Browse files
committed
support integrated terminal in serverReady feature
1 parent 485b2c9 commit 55d7206

2 files changed

Lines changed: 127 additions & 60 deletions

File tree

extensions/debug-server-ready/src/extension.ts

Lines changed: 126 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import * as vscode from 'vscode';
77
//import * as nls from 'vscode-nls';
88
import * as util from 'util';
99

10-
const trackers = new Set<string>();
1110

1211
const PATTERN = 'listening on.* (https?://\\S+|[0-9]+)'; // matches "listening on port 3000" or "Now listening on: https://localhost:5001"
1312
const URI_FORMAT = 'http://localhost:%s';
@@ -20,78 +19,145 @@ interface ServerReadyAction {
2019
webRoot?: string;
2120
}
2221

23-
export function activate(context: vscode.ExtensionContext) {
22+
class ServerReadyDetector extends vscode.Disposable {
23+
static detectors = new Map<vscode.DebugSession, ServerReadyDetector>();
2424

25-
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('*', {
26-
resolveDebugConfiguration(_folder: vscode.WorkspaceFolder | undefined, debugConfiguration: vscode.DebugConfiguration) {
27-
const args: ServerReadyAction = debugConfiguration.serverReadyAction;
28-
if (debugConfiguration.type && args) {
29-
startTrackerForType(context, debugConfiguration.type);
25+
private hasFired = false;
26+
private regexp: RegExp;
27+
private disposables: vscode.Disposable[] = [];
28+
29+
static start(session: vscode.DebugSession): ServerReadyDetector | undefined {
30+
if (session.configuration.serverReadyAction) {
31+
let detector = ServerReadyDetector.detectors.get(session);
32+
if (!detector) {
33+
detector = new ServerReadyDetector(session);
34+
ServerReadyDetector.detectors.set(session, detector);
3035
}
31-
return debugConfiguration;
36+
return detector;
3237
}
33-
}));
34-
}
38+
return undefined;
39+
}
3540

36-
function startTrackerForType(context: vscode.ExtensionContext, type: string) {
41+
static stop(session: vscode.DebugSession): void {
42+
let detector = ServerReadyDetector.detectors.get(session);
43+
if (detector) {
44+
ServerReadyDetector.detectors.delete(session);
45+
detector.dispose();
46+
}
47+
}
48+
49+
private constructor(private session: vscode.DebugSession) {
50+
super(() => this.internalDispose());
51+
52+
this.regexp = new RegExp(session.configuration.serverReadyAction.pattern || PATTERN);
53+
}
54+
55+
private internalDispose() {
56+
this.disposables.forEach(d => d.dispose());
57+
this.disposables = [];
58+
}
3759

38-
if (!trackers.has(type)) {
39-
trackers.add(type);
60+
trackTerminals() {
61+
// TODO: listen only on the Terminal associated with the debug session
62+
vscode.window.terminals.forEach(terminal => {
63+
this.disposables.push(terminal.onDidWriteData(s => {
64+
this.detectPattern(s);
65+
}));
66+
});
67+
}
4068

41-
// scan debug console output for a PORT message
42-
context.subscriptions.push(vscode.debug.registerDebugAdapterTrackerFactory(type, {
43-
createDebugAdapterTracker(session: vscode.DebugSession) {
69+
detectPattern(s: string): void {
70+
71+
if (!this.hasFired) {
72+
const result = this.regexp.exec(s);
73+
if (result && result.length === 2) {
74+
this.openExternalWithString(this.session, result[1]);
75+
this.hasFired = true;
76+
this.internalDispose();
77+
}
78+
}
79+
}
80+
81+
private openExternalWithString(session: vscode.DebugSession, portOrUriString: string) {
82+
83+
if (portOrUriString) {
84+
if (/^[0-9]+$/.test(portOrUriString)) {
4485
const args: ServerReadyAction = session.configuration.serverReadyAction;
45-
if (args) {
46-
const regexp = new RegExp(args.pattern || PATTERN);
47-
let hasFired = false;
48-
return {
49-
onDidSendMessage: m => {
50-
if (!hasFired && m.type === 'event' && m.event === 'output' && m.body.output) {
51-
const result = regexp.exec(m.body.output);
52-
if (result && result.length === 2) {
53-
openExternalWithString(session, result[1]);
54-
hasFired = true;
55-
}
56-
}
57-
}
58-
};
59-
}
60-
return undefined;
86+
portOrUriString = util.format(args.uriFormat || URI_FORMAT, portOrUriString);
6187
}
62-
}));
88+
this.openExternalWithUri(session, portOrUriString);
89+
}
6390
}
64-
}
6591

66-
function openExternalWithString(session: vscode.DebugSession, portOrUriString: string) {
92+
private openExternalWithUri(session: vscode.DebugSession, uri: string) {
6793

68-
if (portOrUriString) {
69-
if (/^[0-9]+$/.test(portOrUriString)) {
70-
const args: ServerReadyAction = session.configuration.serverReadyAction;
71-
portOrUriString = util.format(args.uriFormat || URI_FORMAT, portOrUriString);
94+
const args: ServerReadyAction = session.configuration.serverReadyAction;
95+
switch (args.action || 'openExternally') {
96+
case 'openExternally':
97+
vscode.env.openExternal(vscode.Uri.parse(uri));
98+
break;
99+
case 'debugWithChrome':
100+
vscode.debug.startDebugging(session.workspaceFolder, {
101+
type: 'chrome',
102+
name: 'Chrome Debug',
103+
request: 'launch',
104+
url: uri,
105+
webRoot: args.webRoot || WEB_ROOT
106+
});
107+
break;
108+
default:
109+
// not supported
110+
break;
72111
}
73-
openExternalWithUri(session, portOrUriString);
74112
}
75113
}
76114

77-
function openExternalWithUri(session: vscode.DebugSession, uri: string) {
78-
79-
const args: ServerReadyAction = session.configuration.serverReadyAction;
80-
switch (args.action || 'openExternally') {
81-
case 'openExternally':
82-
vscode.env.openExternal(vscode.Uri.parse(uri));
83-
break;
84-
case 'debugWithChrome':
85-
vscode.debug.startDebugging(session.workspaceFolder, {
86-
type: 'chrome',
87-
name: 'Chrome Debug',
88-
request: 'launch',
89-
url: uri,
90-
webRoot: args.webRoot || WEB_ROOT
91-
});
92-
break;
93-
default:
94-
// not supported
95-
break;
96-
}
115+
export function activate(context: vscode.ExtensionContext) {
116+
117+
context.subscriptions.push(vscode.debug.onDidChangeActiveDebugSession(session => {
118+
if (session && session.configuration.serverReadyAction) {
119+
const detector = ServerReadyDetector.start(session);
120+
if (detector) {
121+
detector.trackTerminals();
122+
}
123+
}
124+
}));
125+
126+
context.subscriptions.push(vscode.debug.onDidTerminateDebugSession(session => {
127+
ServerReadyDetector.stop(session);
128+
}));
129+
130+
const trackers = new Set<string>();
131+
132+
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('*', {
133+
resolveDebugConfiguration(_folder: vscode.WorkspaceFolder | undefined, debugConfiguration: vscode.DebugConfiguration) {
134+
if (debugConfiguration.type && debugConfiguration.serverReadyAction) {
135+
if (!trackers.has(debugConfiguration.type)) {
136+
trackers.add(debugConfiguration.type);
137+
startTrackerForType(context, debugConfiguration.type);
138+
}
139+
}
140+
return debugConfiguration;
141+
}
142+
}));
143+
}
144+
145+
function startTrackerForType(context: vscode.ExtensionContext, type: string) {
146+
147+
// scan debug console output for a PORT message
148+
context.subscriptions.push(vscode.debug.registerDebugAdapterTrackerFactory(type, {
149+
createDebugAdapterTracker(session: vscode.DebugSession) {
150+
const detector = ServerReadyDetector.start(session);
151+
if (detector) {
152+
return {
153+
onDidSendMessage: m => {
154+
if (m.type === 'event' && m.event === 'output' && m.body.output) {
155+
detector.detectPattern(m.body.output);
156+
}
157+
}
158+
};
159+
}
160+
return undefined;
161+
}
162+
}));
97163
}

extensions/debug-server-ready/src/typings/ref.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
/// <reference path='../../../../src/vs/vscode.d.ts'/>
7+
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
78
/// <reference types='@types/node'/>

0 commit comments

Comments
 (0)