Archived
1
0

Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'

This commit is contained in:
Joe Previte
2020-12-15 15:52:33 -07:00
4649 changed files with 1311795 additions and 0 deletions

View File

@ -0,0 +1,16 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Server Ready Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
]
}
]
}

View File

@ -0,0 +1,6 @@
src/**
tsconfig.json
out/**
extension.webpack.config.js
yarn.lock
.vscode

View File

@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
const withDefaults = require('../shared.webpack.config');
module.exports = withDefaults({
context: __dirname,
entry: {
extension: './src/extension.ts',
},
resolve: {
mainFields: ['module', 'main']
}
});

View File

@ -0,0 +1,111 @@
{
"name": "debug-server-ready",
"displayName": "%displayName%",
"description": "%description%",
"version": "1.0.0",
"publisher": "vscode",
"engines": {
"vscode": "^1.32.0"
},
"activationEvents": [
"onDebugResolve"
],
"enableProposedApi": true,
"main": "./out/extension",
"scripts": {
"compile": "gulp compile-extension:debug-server-ready",
"watch": "gulp watch-extension:debug-server-ready"
},
"contributes": {
"debuggers": [
{
"type": "*",
"configurationAttributes": {
"launch": {
"properties": {
"serverReadyAction": {
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"markdownDescription": "%debug.server.ready.serverReadyAction.description%",
"default": {
"action": "openExternally"
},
"properties": {
"action": {
"type": "string",
"enum": [
"openExternally"
],
"enumDescriptions": [
"%debug.server.ready.action.openExternally.description%",
"%debug.server.ready.action.debugWithChrome.description%"
],
"markdownDescription": "%debug.server.ready.action.description%",
"default": "openExternally"
},
"pattern": {
"type": "string",
"markdownDescription": "%debug.server.ready.pattern.description%",
"default": "listening on port ([0-9]+)"
},
"uriFormat": {
"type": "string",
"markdownDescription": "%debug.server.ready.uriFormat.description%",
"default": "http://localhost:%s"
}
}
},
{
"type": "object",
"additionalProperties": false,
"markdownDescription": "%debug.server.ready.serverReadyAction.description%",
"default": {
"action": "openExternally"
},
"properties": {
"action": {
"type": "string",
"enum": [
"debugWithChrome"
],
"enumDescriptions": [
"%debug.server.ready.action.openExternally.description%",
"%debug.server.ready.action.debugWithChrome.description%"
],
"markdownDescription": "%debug.server.ready.action.description%",
"default": "openExternally"
},
"pattern": {
"type": "string",
"markdownDescription": "%debug.server.ready.pattern.description%",
"default": "listening on port ([0-9]+)"
},
"uriFormat": {
"type": "string",
"markdownDescription": "%debug.server.ready.uriFormat.description%",
"default": "http://localhost:%s"
},
"webRoot": {
"type": "string",
"markdownDescription": "%debug.server.ready.webRoot.description%",
"default": "${workspaceFolder}"
}
}
}
]
}
}
}
}
}
]
},
"dependencies": {
"vscode-nls": "^4.0.0"
},
"devDependencies": {
"@types/node": "^12.11.7"
}
}

View File

@ -0,0 +1,12 @@
{
"displayName": "Server Ready Action",
"description": "Open URI in browser if server under debugging is ready.",
"debug.server.ready.serverReadyAction.description": "Act upon a URI when a server program under debugging is ready (indicated by sending output of the form 'listening on port 3000' or 'Now listening on: https://localhost:5001' to the debug console.)",
"debug.server.ready.action.description": "What to do with the URI when the server is ready.",
"debug.server.ready.action.openExternally.description": "Open URI externally with the default application.",
"debug.server.ready.action.debugWithChrome.description": "Start debugging with the 'Debugger for Chrome'.",
"debug.server.ready.pattern.description": "Server is ready if this pattern appears on the debug console. The first capture group must include a URI or a port number.",
"debug.server.ready.uriFormat.description": "A format string used when constructing the URI from a port number. The first '%s' is substituted with the port number.",
"debug.server.ready.webRoot.description": "Value passed to the debug configuration for the 'Debugger for Chrome'."
}

View File

@ -0,0 +1,235 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as util from 'util';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
const PATTERN = 'listening on.* (https?://\\S+|[0-9]+)'; // matches "listening on port 3000" or "Now listening on: https://localhost:5001"
const URI_PORT_FORMAT = 'http://localhost:%s';
const URI_FORMAT = '%s';
const WEB_ROOT = '${workspaceFolder}';
interface ServerReadyAction {
pattern: string;
action?: 'openExternally' | 'debugWithChrome';
uriFormat?: string;
webRoot?: string;
}
class ServerReadyDetector extends vscode.Disposable {
private static detectors = new Map<vscode.DebugSession, ServerReadyDetector>();
private static terminalDataListener: vscode.Disposable | undefined;
private hasFired = false;
private shellPid?: number;
private regexp: RegExp;
private disposables: vscode.Disposable[] = [];
static start(session: vscode.DebugSession): ServerReadyDetector | undefined {
if (session.configuration.serverReadyAction) {
let detector = ServerReadyDetector.detectors.get(session);
if (!detector) {
detector = new ServerReadyDetector(session);
ServerReadyDetector.detectors.set(session, detector);
}
return detector;
}
return undefined;
}
static stop(session: vscode.DebugSession): void {
let detector = ServerReadyDetector.detectors.get(session);
if (detector) {
ServerReadyDetector.detectors.delete(session);
detector.dispose();
}
}
static rememberShellPid(session: vscode.DebugSession, pid: number) {
let detector = ServerReadyDetector.detectors.get(session);
if (detector) {
detector.shellPid = pid;
}
}
static async startListeningTerminalData() {
if (!this.terminalDataListener) {
this.terminalDataListener = vscode.window.onDidWriteTerminalData(async e => {
// first find the detector with a matching pid
const pid = await e.terminal.processId;
for (let [, detector] of this.detectors) {
if (detector.shellPid === pid) {
detector.detectPattern(e.data);
return;
}
}
// if none found, try all detectors until one matches
for (let [, detector] of this.detectors) {
if (detector.detectPattern(e.data)) {
return;
}
}
});
}
}
private constructor(private session: vscode.DebugSession) {
super(() => this.internalDispose());
this.regexp = new RegExp(session.configuration.serverReadyAction.pattern || PATTERN, 'i');
}
private internalDispose() {
this.disposables.forEach(d => d.dispose());
this.disposables = [];
}
detectPattern(s: string): boolean {
if (!this.hasFired) {
const matches = this.regexp.exec(s);
if (matches && matches.length >= 1) {
this.openExternalWithString(this.session, matches.length > 1 ? matches[1] : '');
this.hasFired = true;
this.internalDispose();
return true;
}
}
return false;
}
private openExternalWithString(session: vscode.DebugSession, captureString: string) {
const args: ServerReadyAction = session.configuration.serverReadyAction;
let uri;
if (captureString === '') {
// nothing captured by reg exp -> use the uriFormat as the target uri without substitution
// verify that format does not contain '%s'
const format = args.uriFormat || '';
if (format.indexOf('%s') >= 0) {
const errMsg = localize('server.ready.nocapture.error', "Format uri ('{0}') uses a substitution placeholder but pattern did not capture anything.", format);
vscode.window.showErrorMessage(errMsg, { modal: true }).then(_ => undefined);
return;
}
uri = format;
} else {
// if no uriFormat is specified guess the appropriate format based on the captureString
const format = args.uriFormat || (/^[0-9]+$/.test(captureString) ? URI_PORT_FORMAT : URI_FORMAT);
// verify that format only contains a single '%s'
const s = format.split('%s');
if (s.length !== 2) {
const errMsg = localize('server.ready.placeholder.error', "Format uri ('{0}') must contain exactly one substitution placeholder.", format);
vscode.window.showErrorMessage(errMsg, { modal: true }).then(_ => undefined);
return;
}
uri = util.format(format, captureString);
}
this.openExternalWithUri(session, uri);
}
private openExternalWithUri(session: vscode.DebugSession, uri: string) {
const args: ServerReadyAction = session.configuration.serverReadyAction;
switch (args.action || 'openExternally') {
case 'openExternally':
vscode.env.openExternal(vscode.Uri.parse(uri));
break;
case 'debugWithChrome':
vscode.debug.startDebugging(session.workspaceFolder, {
type: 'pwa-chrome',
name: 'Chrome Debug',
request: 'launch',
url: uri,
webRoot: args.webRoot || WEB_ROOT
});
break;
default:
// not supported
break;
}
}
}
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.debug.onDidChangeActiveDebugSession(session => {
if (session && session.configuration.serverReadyAction) {
const detector = ServerReadyDetector.start(session);
if (detector) {
ServerReadyDetector.startListeningTerminalData();
}
}
}));
context.subscriptions.push(vscode.debug.onDidTerminateDebugSession(session => {
ServerReadyDetector.stop(session);
}));
const trackers = new Set<string>();
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('*', {
resolveDebugConfigurationWithSubstitutedVariables(_folder: vscode.WorkspaceFolder | undefined, debugConfiguration: vscode.DebugConfiguration) {
if (debugConfiguration.type && debugConfiguration.serverReadyAction) {
if (!trackers.has(debugConfiguration.type)) {
trackers.add(debugConfiguration.type);
startTrackerForType(context, debugConfiguration.type);
}
}
return debugConfiguration;
}
}));
}
function startTrackerForType(context: vscode.ExtensionContext, type: string) {
// scan debug console output for a PORT message
context.subscriptions.push(vscode.debug.registerDebugAdapterTrackerFactory(type, {
createDebugAdapterTracker(session: vscode.DebugSession) {
const detector = ServerReadyDetector.start(session);
if (detector) {
let runInTerminalRequestSeq: number | undefined;
return {
onDidSendMessage: m => {
if (m.type === 'event' && m.event === 'output' && m.body) {
switch (m.body.category) {
case 'console':
case 'stderr':
case 'stdout':
if (m.body.output) {
detector.detectPattern(m.body.output);
}
break;
default:
break;
}
}
if (m.type === 'request' && m.command === 'runInTerminal' && m.arguments) {
if (m.arguments.kind === 'integrated') {
runInTerminalRequestSeq = m.seq; // remember this to find matching response
}
}
},
onWillReceiveMessage: m => {
if (runInTerminalRequestSeq && m.type === 'response' && m.command === 'runInTerminal' && m.body && runInTerminalRequestSeq === m.request_seq) {
runInTerminalRequestSeq = undefined;
ServerReadyDetector.rememberShellPid(session, m.body.shellProcessId);
}
}
};
}
return undefined;
}
}));
}

View File

@ -0,0 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
/// <reference types='@types/node'/>

View File

@ -0,0 +1,10 @@
{
"extends": "../shared.tsconfig.json",
"compilerOptions": {
"outDir": "./out",
"downlevelIteration": true
},
"include": [
"src/**/*"
]
}

View File

@ -0,0 +1,13 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/node@^12.11.7":
version "12.11.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a"
integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==
vscode-nls@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002"
integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw==