This commit is contained in:
Andre Weinand 2020-09-10 01:10:23 +02:00
Родитель c2dc113ef3
Коммит 354c0e93c9
16 изменённых файлов: 2821 добавлений и 364 удалений

8
.gitignore поставляемый
Просмотреть файл

@ -1,6 +1,8 @@
.DS_Store
node_modules/
out/
out
dist
node_modules
.vscode-test/
npm-debug.log
mock-debug.txt
*.vsix
.DS_Store

18
.vscode/launch.json поставляемый
Просмотреть файл

@ -5,15 +5,29 @@
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
"--extensionDevelopmentPath=${workspaceFolder}",
"${workspaceFolder}/sampleworkspace"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "npm: watch"
},
{
"name": "Web Extension",
"type": "pwa-extensionHost",
"debugWebWorkerHost": true,
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"${workspaceFolder}/sampleworkspace"
],
"outFiles": [
"${workspaceFolder}/dist/web/**/*.js"
],
"preLaunchTask": "npm: watch-web"
},
{
"name": "Server",
"type": "node",

56
.vscode/tasks.json поставляемый
Просмотреть файл

@ -1,18 +1,40 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "compile-web",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$ts-webpack",
"$tslint-webpack"
]
},
{
"type": "npm",
"script": "watch-web",
"group": "build",
"isBackground": true,
"problemMatcher": [
"$ts-webpack-watch",
"$tslint-webpack-watch"
]
}
]
}

Просмотреть файл

@ -1,8 +1,9 @@
## 0.43.0
* Added context menu action "Show as Hex" to integer variables in Variables view
* Added new run option "namedPipeServer" for debug adapter in extension.ts
* Using new extension API for passing the "noDebug" option to "vscode.debug.startDebugging"
* Add context menu action "Show as Hex" to integer variables in Variables view
* Add new run option "namedPipeServer" for debug adapter in extension.ts
* Use new extension API for passing the "noDebug" option to "vscode.debug.startDebugging"
* Support to run Mock Debug in the browser/web worker
## 0.42.2
* Project hygiene: get rid of all warnings

Просмотреть файл

@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* 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';
//@ts-check
/** @typedef {import('webpack').Configuration} WebpackConfig **/
const path = require('path');
module.exports = /** @type WebpackConfig */ {
context: path.dirname(__dirname),
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
target: 'webworker', // extensions run in a webworker context
entry: {
extension: './src/web/extension.ts',
},
resolve: {
mainFields: ['module', 'main'],
extensions: ['.ts', '.js'], // support ts-files and js-files
alias: {
}
},
module: {
rules: [{
test: /\.ts$/,
exclude: /node_modules/,
use: [{
// configure TypeScript loader:
// * enable sources maps for end-to-end source maps
loader: 'ts-loader',
options: {
compilerOptions: {
'sourceMap': true,
'declaration': false
}
}
}]
}]
},
externals: {
'vscode': 'commonjs vscode', // ignored because it doesn't exist
},
performance: {
hints: false
},
output: {
filename: 'extension.js',
path: path.join(__dirname, '../dist/web'),
libraryTarget: 'commonjs'
},
devtool: 'source-map'
};

Просмотреть файл

@ -1,166 +1,173 @@
{
"name": "mock-debug",
"displayName": "Mock Debug",
"version": "0.42.2",
"publisher": "andreweinand",
"description": "Starter extension for developing debug adapters for VS Code.",
"author": {
"name": "Microsoft Corporation",
"email": "aweinand@microsoft.com"
},
"license": "MIT",
"keywords": [
"multi-root ready"
],
"engines": {
"vscode": "^1.46.0"
},
"icon": "images/mock-debug-icon.png",
"categories": [
"Debuggers"
],
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vscode-mock-debug.git"
},
"bugs": {
"url": "https://github.com/Microsoft/vscode-mock-debug/issues"
},
"scripts": {
"vscode:prepublish": "yarn run compile",
"compile": "tsc -p ./",
"lint": "eslint src --ext ts",
"watch": "tsc -watch -p ./",
"pretest": "yarn run compile && yarn run lint",
"test": "node ./out/test/runTest.js",
"package": "vsce package",
"publish": "vsce publish"
},
"dependencies": {
"await-notify": "1.0.1",
"vscode-debugadapter": "1.41.1"
},
"devDependencies": {
"@types/vscode": "^1.48.0",
"@types/glob": "^7.1.3",
"@types/mocha": "^8.0.0",
"@types/node": "^14.0.27",
"eslint": "^7.6.0",
"@typescript-eslint/eslint-plugin": "^3.8.0",
"@typescript-eslint/parser": "^3.8.0",
"glob": "^7.1.6",
"mocha": "^8.0.1",
"typescript": "^3.8.3",
"vscode-debugadapter-testsupport": "1.41.0",
"vsce": "1.78.0"
},
"main": "./out/extension",
"activationEvents": [
"onDebug",
"onDebugDynamicConfigurations:mock",
"onCommand:extension.mock-debug.getProgramName",
"onCommand:extension.mock-debug.runEditorContents",
"onCommand:extension.mock-debug.debugEditorContents"
],
"contributes": {
"menus": {
"editor/title": [
{
"command": "extension.mock-debug.runEditorContents",
"when": "resourceLangId == markdown",
"group": "1_run@10"
},
{
"command": "extension.mock-debug.debugEditorContents",
"when": "resourceLangId == markdown",
"group": "1_run@20"
}
],
"debug/variables/context": [
{
"command": "extension.mock-debug.showAsHex",
"when": "debugConfigurationType == 'mock' && debugProtocolVariableMenuContext == 'simple'"
}
]
},
"commands": [
{
"command": "extension.mock-debug.debugEditorContents",
"title": "Debug File",
"icon": "$(debug-alt)"
},
{
"command": "extension.mock-debug.runEditorContents",
"title": "Run File",
"icon": "$(play)"
},
{
"command": "extension.mock-debug.showAsHex",
"title": "Show as Hex"
}
],
"breakpoints": [
{
"language": "markdown"
}
],
"debuggers": [
{
"type": "mock",
"label": "Mock Debug",
"program": "./out/debugAdapter.js",
"runtime": "node",
"configurationAttributes": {
"launch": {
"required": [
"program"
],
"properties": {
"program": {
"type": "string",
"description": "Absolute path to a text file.",
"default": "${workspaceFolder}/${command:AskForProgramName}"
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop after launch.",
"default": true
},
"trace": {
"type": "boolean",
"description": "Enable logging of the Debug Adapter Protocol.",
"default": true
}
}
}
},
"initialConfigurations": [
{
"type": "mock",
"request": "launch",
"name": "Ask for file name",
"program": "${workspaceFolder}/${command:AskForProgramName}",
"stopOnEntry": true
}
],
"configurationSnippets": [
{
"label": "Mock Debug: Launch",
"description": "A new configuration for 'debugging' a user selected markdown file.",
"body": {
"type": "mock",
"request": "launch",
"name": "Ask for file name",
"program": "^\"\\${workspaceFolder}/\\${command:AskForProgramName}\"",
"stopOnEntry": true
}
}
],
"variables": {
"AskForProgramName": "extension.mock-debug.getProgramName"
}
}
]
}
"name": "mock-debug",
"displayName": "Mock Debug",
"version": "0.43.0",
"publisher": "andreweinand",
"description": "Starter extension for developing debug adapters for VS Code.",
"author": {
"name": "Microsoft Corporation",
"email": "aweinand@microsoft.com"
},
"license": "MIT",
"keywords": [
"multi-root ready"
],
"engines": {
"vscode": "^1.46.0"
},
"icon": "images/mock-debug-icon.png",
"categories": [
"Debuggers"
],
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vscode-mock-debug.git"
},
"bugs": {
"url": "https://github.com/Microsoft/vscode-mock-debug/issues"
},
"scripts": {
"vscode:prepublish": "yarn run compile",
"compile": "tsc -p ./",
"lint": "eslint src --ext ts",
"watch": "tsc -watch -p ./",
"pretest": "yarn run compile && yarn run lint",
"test": "node ./out/test/runTest.js",
"package": "vsce package",
"publish": "vsce publish",
"compile-web": "webpack --devtool nosources-source-map --config ./build/web-extension.webpack.config.js",
"watch-web": "webpack --watch --devtool nosources-source-map --info-verbosity verbose --config ./build/web-extension.webpack.config.js",
"package-web": "webpack --mode production --watch --config ./build/web-extension.webpack.config.js"
},
"dependencies": {
"await-notify": "1.0.1",
"vscode-debugadapter": "1.42.0-pre.4"
},
"devDependencies": {
"@types/vscode": "^1.48.0",
"@types/glob": "^7.1.3",
"@types/mocha": "^8.0.0",
"@types/node": "^14.0.27",
"eslint": "^7.6.0",
"@typescript-eslint/eslint-plugin": "^3.8.0",
"@typescript-eslint/parser": "^3.8.0",
"glob": "^7.1.6",
"mocha": "^8.0.1",
"typescript": "^3.8.3",
"vscode-debugadapter-testsupport": "1.41.0",
"vsce": "^1.79.5",
"ts-loader": "^8.0.2",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
},
"main": "./out/extension",
"browser": "./dist/web/extension.js",
"activationEvents": [
"onDebug",
"onDebugDynamicConfigurations:mock",
"onCommand:extension.mock-debug.getProgramName",
"onCommand:extension.mock-debug.runEditorContents",
"onCommand:extension.mock-debug.debugEditorContents"
],
"contributes": {
"menus": {
"editor/title": [
{
"command": "extension.mock-debug.runEditorContents",
"when": "resourceLangId == markdown",
"group": "1_run@10"
},
{
"command": "extension.mock-debug.debugEditorContents",
"when": "resourceLangId == markdown",
"group": "1_run@20"
}
],
"debug/variables/context": [
{
"command": "extension.mock-debug.showAsHex",
"when": "debugConfigurationType == 'mock' && debugProtocolVariableMenuContext == 'simple'"
}
]
},
"commands": [
{
"command": "extension.mock-debug.debugEditorContents",
"title": "Debug File",
"icon": "$(debug-alt)"
},
{
"command": "extension.mock-debug.runEditorContents",
"title": "Run File",
"icon": "$(play)"
},
{
"command": "extension.mock-debug.showAsHex",
"title": "Show as Hex"
}
],
"breakpoints": [
{
"language": "markdown"
}
],
"debuggers": [
{
"type": "mock",
"label": "Mock Debug",
"program": "./out/debugAdapter.js",
"runtime": "node",
"configurationAttributes": {
"launch": {
"required": [
"program"
],
"properties": {
"program": {
"type": "string",
"description": "Absolute path to a text file.",
"default": "${workspaceFolder}/${command:AskForProgramName}"
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop after launch.",
"default": true
},
"trace": {
"type": "boolean",
"description": "Enable logging of the Debug Adapter Protocol.",
"default": true
}
}
}
},
"initialConfigurations": [
{
"type": "mock",
"request": "launch",
"name": "Ask for file name",
"program": "${workspaceFolder}/${command:AskForProgramName}",
"stopOnEntry": true
}
],
"configurationSnippets": [
{
"label": "Mock Debug: Launch",
"description": "A new configuration for 'debugging' a user selected markdown file.",
"body": {
"type": "mock",
"request": "launch",
"name": "Ask for file name",
"program": "^\"\\${workspaceFolder}/\\${command:AskForProgramName}\"",
"stopOnEntry": true
}
}
],
"variables": {
"AskForProgramName": "extension.mock-debug.getProgramName"
}
}
]
}
}

16
sampleworkspace/.vscode/launch.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "mock",
"request": "launch",
"name": "Debug test.md",
"program": "${workspaceFolder}/test.md",
"stopOnEntry": true,
"trace": false
}
]
}

3
sampleworkspace/.vscode/settings.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
{
"extensions.webWorker": true
}

38
sampleworkspace/test.md Normal file
Просмотреть файл

@ -0,0 +1,38 @@
# VS Code Mock Debug
Mock Debug allows to "debug" markdown files (like this).
The text of the markdown is considered the "program to debug" and certain keywords trigger specific functionality:
* if debugging stops on a line, the line becomes a stack in the CALL STACK with the words shown as frames.
* variables are synthetic
Please note: breakpoints are only verified in an active debug session.
* if a line is empty or starts with '+' we don't allow to set a breakpoint but move the breakpoint down
* if a line starts with '-' we don't allow to set a breakpoint but move the breakpoint up
* a breakpoint on a line containing the word 'lazy' is not immediately verified, but only after hitting it once
* Fire events if line has a breakpoint or the word 'exception' is found.
* a line with the pattern `log(xxx)` logs `xxx` to the debug console. If "xxx" is `start` or `end`, a "log group" is started or ended.
log(start)
log(arbitrary line of text)
log(start)
log(arbitrary line of text level 2)
log(start)
log(arbitrary line of text level 3)
log(start)
log(arbitrary line of text level 4)
log(start)
log(arbitrary line of text level 5)
log(another line of text level 5)
log(end)
log(another line of text level 4)
log(end)
log(another line of text level 3)
log(end)
log(another line of text level 2)
log(end)
log(another line of text)
log(end)

138
src/activateMockDebug.ts Normal file
Просмотреть файл

@ -0,0 +1,138 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import { WorkspaceFolder, DebugConfiguration, ProviderResult, CancellationToken } from 'vscode';
import { MockDebugSession } from './mockDebug';
import { FileAccessor } from './mockRuntime';
export function activateMockDebug(context: vscode.ExtensionContext, factory?: vscode.DebugAdapterDescriptorFactory) {
context.subscriptions.push(
vscode.commands.registerCommand('extension.mock-debug.runEditorContents', (resource: vscode.Uri) => {
vscode.debug.startDebugging(undefined, {
type: 'mock',
name: 'Run Editor Contents',
request: 'launch',
program: resource.fsPath
}, {
//noDebug: true
});
}),
vscode.commands.registerCommand('extension.mock-debug.debugEditorContents', (resource: vscode.Uri) => {
vscode.debug.startDebugging(undefined, {
type: 'mock',
name: 'Debug Editor Contents',
request: 'launch',
program: resource.fsPath
});
}),
vscode.commands.registerCommand('extension.mock-debug.showAsHex', (variable) => {
vscode.window.showInformationMessage(`${variable.container.name}: ${variable.variable.name}`);
})
);
context.subscriptions.push(vscode.commands.registerCommand('extension.mock-debug.getProgramName', config => {
return vscode.window.showInputBox({
placeHolder: "Please enter the name of a markdown file in the workspace folder",
value: "readme.md"
});
}));
// register a configuration provider for 'mock' debug type
const provider = new MockConfigurationProvider();
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('mock', provider));
// register a dynamic configuration provider for 'mock' debug type
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('mock', {
provideDebugConfigurations(folder: WorkspaceFolder | undefined): ProviderResult<DebugConfiguration[]> {
return [
{
name: "Dynamic Launch",
request: "launch",
type: "node",
program: "${file}"
},
{
name: "Another Dynamic Launch",
request: "launch",
type: "node",
program: "${file}"
},
{
name: "Mock Launch",
request: "launch",
type: "node",
program: "${file}"
}
];
}
}, vscode.DebugConfigurationProviderTriggerKind.Dynamic));
if (!factory) {
factory = new InlineDebugAdapterFactory();
}
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('mock', factory));
if ('dispose' in factory) {
context.subscriptions.push(factory);
}
// override VS Code's default implementation of the debug hover
/*
vscode.languages.registerEvaluatableExpressionProvider('markdown', {
provideEvaluatableExpression(document: vscode.TextDocument, position: vscode.Position): vscode.ProviderResult<vscode.EvaluatableExpression> {
const wordRange = document.getWordRangeAtPosition(position);
return wordRange ? new vscode.EvaluatableExpression(wordRange) : undefined;
}
});
*/
}
class MockConfigurationProvider implements vscode.DebugConfigurationProvider {
/**
* Massage a debug configuration just before a debug session is being launched,
* e.g. add all missing attributes to the debug configuration.
*/
resolveDebugConfiguration(folder: WorkspaceFolder | undefined, config: DebugConfiguration, token?: CancellationToken): ProviderResult<DebugConfiguration> {
// if launch.json is missing or empty
if (!config.type && !config.request && !config.name) {
const editor = vscode.window.activeTextEditor;
if (editor && editor.document.languageId === 'markdown') {
config.type = 'mock';
config.name = 'Launch';
config.request = 'launch';
config.program = '${file}';
config.stopOnEntry = true;
}
}
if (!config.program) {
return vscode.window.showInformationMessage("Cannot find a program to debug").then(_ => {
return undefined; // abort launch
});
}
return config;
}
}
export const workspaceFileAccessor: FileAccessor = {
async readFile(path: string) {
const uri = vscode.Uri.parse(path);
const bytes = await vscode.workspace.fs.readFile(uri);
const contents = Buffer.from(bytes).toString('utf8');
return contents;
}
};
class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory {
createDebugAdapterDescriptor(_session: vscode.DebugSession): ProviderResult<vscode.DebugAdapterDescriptor> {
return new vscode.DebugAdapterInlineImplementation(new MockDebugSession(workspaceFileAccessor));
}
}

Просмотреть файл

@ -2,6 +2,59 @@
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import { MockDebugSession } from './mockDebug';
import { MockDebugSession } from './mockDebug';
MockDebugSession.run(MockDebugSession);
import { readFileSync } from 'fs';
import * as Net from 'net';
import { FileAccessor } from './mockRuntime';
/*
* Since the debug adapter runs as an external process, it has no access to VS Code API.
*/
const fsAccessor: FileAccessor = {
async readFile(path: string): Promise<string> {
const buffer = readFileSync(path);
return buffer.toString();
}
};
/*
* When the debug adapter is run as an external process,
* the helper function DebugSession.run(...) takes care of everything.
*/
// MockDebugSession.run(MockDebugSession);
// ... but the helper is not flexible enough to deal with constructors with parameters.
// So for now we use a modified copy of the helper:
// parse arguments
let port = 0;
const args = process.argv.slice(2);
args.forEach(function (val, index, array) {
const portMatch = /^--server=(\d{4,5})$/.exec(val);
if (portMatch) {
port = parseInt(portMatch[1], 10);
}
});
if (port > 0) {
// start as a server
console.error(`waiting for debug protocol on port ${port}`);
Net.createServer((socket) => {
console.error('>> accepted connection from client');
socket.on('end', () => {
console.error('>> client connection closed\n');
});
const session = new MockDebugSession(fsAccessor);
session.setRunAsServer(true);
session.start(socket, socket);
}).listen(port);
} else {
// start a session
const session = new MockDebugSession(fsAccessor);
process.on('SIGTERM', () => {
session.shutdown();
});
session.start(process.stdin, process.stdout);
}

Просмотреть файл

@ -10,8 +10,9 @@ import { randomBytes } from 'crypto';
import { tmpdir } from 'os';
import { join } from 'path';
import { platform } from 'process';
import { WorkspaceFolder, DebugConfiguration, ProviderResult, CancellationToken } from 'vscode';
import { ProviderResult } from 'vscode';
import { MockDebugSession } from './mockDebug';
import { activateMockDebug, workspaceFileAccessor } from './activateMockDebug';
/*
* The compile time flag 'runMode' controls how the debug adapter is run.
@ -21,141 +22,34 @@ const runMode: 'external' | 'server' | 'namedPipeServer' | 'inline' = 'inline';
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.commands.registerCommand('extension.mock-debug.runEditorContents', (resource: vscode.Uri) => {
vscode.debug.startDebugging(undefined, {
type: 'mock',
name: 'Run Editor Contents',
request: 'launch',
program: resource.fsPath
}, {
//noDebug: true
});
}),
vscode.commands.registerCommand('extension.mock-debug.debugEditorContents', (resource: vscode.Uri) => {
vscode.debug.startDebugging(undefined, {
type: 'mock',
name: 'Debug Editor Contents',
request: 'launch',
program: resource.fsPath
});
}),
vscode.commands.registerCommand('extension.mock-debug.showAsHex', (variable) => {
vscode.window.showInformationMessage(`${variable.container.name}: ${variable.variable.name}`);
})
);
context.subscriptions.push(vscode.commands.registerCommand('extension.mock-debug.getProgramName', config => {
return vscode.window.showInputBox({
placeHolder: "Please enter the name of a markdown file in the workspace folder",
value: "readme.md"
});
}));
// register a configuration provider for 'mock' debug type
const provider = new MockConfigurationProvider();
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('mock', provider));
// register a dynamic configuration provider for 'mock' debug type
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('mock', {
provideDebugConfigurations(folder: WorkspaceFolder | undefined): ProviderResult<DebugConfiguration[]> {
return [
{
name: "Dynamic Launch",
request: "launch",
type: "node",
program: "${file}"
},
{
name: "Another Dynamic Launch",
request: "launch",
type: "node",
program: "${file}"
},
{
name: "Mock Launch",
request: "launch",
type: "node",
program: "${file}"
}
];
}
}, vscode.DebugConfigurationProviderTriggerKind.Dynamic));
// debug adapters can be run in different ways by using a vscode.DebugAdapterDescriptorFactory:
let factory: vscode.DebugAdapterDescriptorFactory;
switch (runMode) {
case 'server':
// run the debug adapter as a server inside the extension and communicate via a socket
factory = new MockDebugAdapterServerDescriptorFactory();
activateMockDebug(context, new MockDebugAdapterServerDescriptorFactory());
break;
case 'namedPipeServer':
// run the debug adapter as a server inside the extension and communicate via a named pipe (Windows) or UNIX domain socket (non-Windows)
factory = new MockDebugAdapterNamedPipeServerDescriptorFactory();
break;
case 'inline':
// run the debug adapter inside the extension and directly talk to it
factory = new InlineDebugAdapterFactory();
activateMockDebug(context, new MockDebugAdapterNamedPipeServerDescriptorFactory());
break;
case 'external': default:
// run the debug adapter as a separate process
factory = new DebugAdapterExecutableFactory();
activateMockDebug(context, new DebugAdapterExecutableFactory());
break;
case 'inline':
// run the debug adapter inside the extension and directly talk to it
activateMockDebug(context);
break;
}
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('mock', factory));
if ('dispose' in factory) {
context.subscriptions.push(factory);
}
// override VS Code's default implementation of the debug hover
/*
vscode.languages.registerEvaluatableExpressionProvider('markdown', {
provideEvaluatableExpression(document: vscode.TextDocument, position: vscode.Position): vscode.ProviderResult<vscode.EvaluatableExpression> {
const wordRange = document.getWordRangeAtPosition(position);
return wordRange ? new vscode.EvaluatableExpression(wordRange) : undefined;
}
});
*/
}
export function deactivate() {
// nothing to do
}
class MockConfigurationProvider implements vscode.DebugConfigurationProvider {
/**
* Massage a debug configuration just before a debug session is being launched,
* e.g. add all missing attributes to the debug configuration.
*/
resolveDebugConfiguration(folder: WorkspaceFolder | undefined, config: DebugConfiguration, token?: CancellationToken): ProviderResult<DebugConfiguration> {
// if launch.json is missing or empty
if (!config.type && !config.request && !config.name) {
const editor = vscode.window.activeTextEditor;
if (editor && editor.document.languageId === 'markdown') {
config.type = 'mock';
config.name = 'Launch';
config.request = 'launch';
config.program = '${file}';
config.stopOnEntry = true;
}
}
if (!config.program) {
return vscode.window.showInformationMessage("Cannot find a program to debug").then(_ => {
return undefined; // abort launch
});
}
return config;
}
}
class DebugAdapterExecutableFactory implements vscode.DebugAdapterDescriptorFactory {
// The following use of a DebugAdapter factory shows how to control what debug adapter executable is used.
@ -192,7 +86,7 @@ class MockDebugAdapterServerDescriptorFactory implements vscode.DebugAdapterDesc
if (!this.server) {
// start listening on a random port
this.server = Net.createServer(socket => {
const session = new MockDebugSession();
const session = new MockDebugSession(workspaceFileAccessor);
session.setRunAsServer(true);
session.start(socket as NodeJS.ReadableStream, socket);
}).listen(0);
@ -221,7 +115,7 @@ class MockDebugAdapterNamedPipeServerDescriptorFactory implements vscode.DebugAd
const pipePath = platform === "win32" ? join('\\\\.\\pipe\\', pipeName) : join(tmpdir(), pipeName);
this.server = Net.createServer(socket => {
const session = new MockDebugSession();
const session = new MockDebugSession(workspaceFileAccessor);
session.setRunAsServer(true);
session.start(<NodeJS.ReadableStream>socket, socket);
}).listen(pipePath);
@ -239,10 +133,3 @@ class MockDebugAdapterNamedPipeServerDescriptorFactory implements vscode.DebugAd
}
}
}
class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory {
createDebugAdapterDescriptor(_session: vscode.DebugSession): ProviderResult<vscode.DebugAdapterDescriptor> {
return new vscode.DebugAdapterInlineImplementation(new MockDebugSession());
}
}

Просмотреть файл

@ -11,7 +11,7 @@ import {
} from 'vscode-debugadapter';
import { DebugProtocol } from 'vscode-debugprotocol';
import { basename } from 'path';
import { MockRuntime, IMockBreakpoint } from './mockRuntime';
import { MockRuntime, IMockBreakpoint, FileAccessor } from './mockRuntime';
import { Subject } from 'await-notify';
function timeout(ms: number) {
@ -59,14 +59,14 @@ export class MockDebugSession extends LoggingDebugSession {
* Creates a new debug adapter that is used for one debug session.
* We configure the default implementation of a debug adapter here.
*/
public constructor() {
public constructor(fileAccessor: FileAccessor) {
super("mock-debug.txt");
// this debugger uses zero-based lines and columns
this.setDebuggerLinesStartAt1(false);
this.setDebuggerColumnsStartAt1(false);
this._runtime = new MockRuntime();
this._runtime = new MockRuntime(fileAccessor);
// setup event handlers
this._runtime.on('stopOnEntry', () => {
@ -171,12 +171,12 @@ export class MockDebugSession extends LoggingDebugSession {
await this._configurationDone.wait(1000);
// start the program in the runtime
this._runtime.start(args.program, !!args.stopOnEntry, !!args.noDebug);
await this._runtime.start(args.program, !!args.stopOnEntry, !!args.noDebug);
this.sendResponse(response);
}
protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
protected async setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): Promise<void> {
const path = args.source.path as string;
const clientLines = args.lines || [];
@ -185,12 +185,13 @@ export class MockDebugSession extends LoggingDebugSession {
this._runtime.clearBreakpoints(path);
// set and verify breakpoint locations
const actualBreakpoints = clientLines.map(l => {
const { verified, line, id } = this._runtime.setBreakPoint(path, this.convertClientLineToDebugger(l));
const actualBreakpoints0 = clientLines.map(async l => {
const { verified, line, id } = await this._runtime.setBreakPoint(path, this.convertClientLineToDebugger(l));
const bp = new Breakpoint(verified, this.convertDebuggerLineToClient(line)) as DebugProtocol.Breakpoint;
bp.id= id;
return bp;
});
const actualBreakpoints = await Promise.all<DebugProtocol.Breakpoint>(actualBreakpoints0);
// send back the actual breakpoint positions
response.body = {
@ -380,7 +381,7 @@ export class MockDebugSession extends LoggingDebugSession {
this.sendResponse(response);
}
protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void {
protected async evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): Promise<void> {
let reply: string | undefined = undefined;
@ -388,7 +389,7 @@ export class MockDebugSession extends LoggingDebugSession {
// 'evaluate' supports to create and delete breakpoints from the 'repl':
const matches = /new +([0-9]+)/.exec(args.expression);
if (matches && matches.length === 2) {
const mbp = this._runtime.setBreakPoint(this._runtime.sourceFile, this.convertClientLineToDebugger(parseInt(matches[1])));
const mbp = await this._runtime.setBreakPoint(this._runtime.sourceFile, this.convertClientLineToDebugger(parseInt(matches[1])));
const bp = new Breakpoint(mbp.verified, this.convertDebuggerLineToClient(mbp.line), undefined, this.createSource(this._runtime.sourceFile)) as DebugProtocol.Breakpoint;
bp.id= mbp.id;
this.sendEvent(new BreakpointEvent('new', bp));

Просмотреть файл

@ -2,9 +2,12 @@
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import { readFileSync } from 'fs';
import { EventEmitter } from 'events';
export interface FileAccessor {
readFile(path: string): Promise<string>;
}
export interface IMockBreakpoint {
id: number;
line: number;
@ -58,21 +61,21 @@ export class MockRuntime extends EventEmitter {
private _noDebug = false;
constructor() {
constructor(private _fileAccessor: FileAccessor) {
super();
}
/**
* Start executing the given program.
*/
public start(program: string, stopOnEntry: boolean, noDebug: boolean) {
public async start(program: string, stopOnEntry: boolean, noDebug: boolean): Promise<void> {
this._noDebug = noDebug;
this.loadSource(program);
await this.loadSource(program);
this._currentLine = -1;
this.verifyBreakpoints(this._sourceFile);
await this.verifyBreakpoints(this._sourceFile);
if (stopOnEntry) {
// we step once
@ -206,7 +209,7 @@ export class MockRuntime extends EventEmitter {
/*
* Set breakpoint in file with given line.
*/
public setBreakPoint(path: string, line: number): IMockBreakpoint {
public async setBreakPoint(path: string, line: number): Promise<IMockBreakpoint> {
const bp: IMockBreakpoint = { verified: false, line, id: this._breakpointId++ };
let bps = this._breakPoints.get(path);
@ -216,7 +219,7 @@ export class MockRuntime extends EventEmitter {
}
bps.push(bp);
this.verifyBreakpoints(path);
await this.verifyBreakpoints(path);
return bp;
}
@ -264,10 +267,11 @@ export class MockRuntime extends EventEmitter {
// private methods
private loadSource(file: string) {
private async loadSource(file: string): Promise<void> {
if (this._sourceFile !== file) {
this._sourceFile = file;
this._sourceLines = readFileSync(this._sourceFile).toString().split('\n');
const contents = await this._fileAccessor.readFile(file);
this._sourceLines = contents.split('\n');
}
}
@ -301,7 +305,7 @@ export class MockRuntime extends EventEmitter {
}
}
private verifyBreakpoints(path: string): void {
private async verifyBreakpoints(path: string): Promise<void> {
if (this._noDebug) {
return;
@ -309,7 +313,7 @@ export class MockRuntime extends EventEmitter {
const bps = this._breakPoints.get(path);
if (bps) {
this.loadSource(path);
await this.loadSource(path);
bps.forEach(bp => {
if (!bp.verified && bp.line < this._sourceLines.length) {
const srcLine = this._sourceLines[bp.line].trim();

14
src/web/extension.ts Normal file
Просмотреть файл

@ -0,0 +1,14 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import * as vscode from 'vscode';
import { activateMockDebug } from '../activateMockDebug';
export function activate(context: vscode.ExtensionContext) {
activateMockDebug(context);
}
export function deactivate() {
// nothing to do
}

2257
yarn.lock

Разница между файлами не показана из-за своего большого размера Загрузить разницу