I have created a Visual Code Debugger Extension, and in my extension activate routine, I can tell it was activated when I debug a sample *.xyz file, as it writes out XYZ Debuger Activated to the console. The problem is, my debugger executable named debugger.exe (which is a console application written in C#) does not get executed.
When I close the *.xyz file, my breakpoint in the deactivate extension function gets hit. this leaves me to believe that for the most part, the extension is working somewhat, but not totally.
What am I doing wrong?
Here is my extension.ts file
'use strict';
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import { WorkspaceFolder, DebugConfiguration, ProviderResult, CancellationToken } from 'vscode';
import * as Net from 'net';
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('XYZ-Debugger Activated');
}
// this method is called when your extension is deactivated
export function deactivate() {
console.log('XYZ-Debugger Deactivated');
}
And here is my package.json file:
{
"name": "xyz-debugger",
"displayName": "XYZ Debugger",
"description": "Test Debugger.",
"version": "0.0.1",
"publisher": "Ed_Starkey",
"engines": {
"vscode": "^1.24.0",
"node": "^6.3.0"
},
"categories": [
"Debuggers"
],
"dependencies": {
"vscode-debugprotocol": "^1.20.0",
"vscode-nls": "^2.0.2"
},
"activationEvents": [
"onDebug"
],
"main": "./out/extension",
"contributes": {
"breakpoints": [
{
"language": "xyz"
}
],
"debuggers": [{
"type": "XYZDebug",
"label": "XYZ Debug",
"windows": {
"program": "program": "./out/debugger.exe"
},
"languages": [
{
"id": "xyz",
"extensions": [
".xyz"
],
"aliases": [
"XYZ"
]
}],
"configurationAttributes": {
"launch": {
"required": [
"program"
],
"properties": {
"program": {
"type": "string",
"description": "The program to debug."
}
}
}
},
"initialConfigurations": [
{
"type": "xyz",
"request": "launch",
"name": "Launch Program",
"windows": {
"program": "./out/debugger.exe"
}
}
],
}]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "npm run compile && node ./node_modules/vscode/bin/test"
},
"devDependencies": {
"typescript": "^2.5.3",
"vscode": "^1.1.5",
"#types/node": "^7.0.43",
"vscode-debugadapter-testsupport":"^1.29.0"
}
}
And here is my launch.json:
// A launch configuration that compiles the extension and then opens it inside a new window
{
"version": "0.1.0",
"configurations": [
{
"name": "Launch XYZ Debug",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [ "${workspaceRoot}/out/**/*.js" ],
"preLaunchTask": "npm: watch"
},
{
"name": "Launch Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
"preLaunchTask": "npm: watch"
}
]
}
You're not registering what you want VSCode to do in activate.
Something like this will do what you want:
let factory: XYZDebugAdapterDescriptorFactory
export function activate(context: vscode.ExtensionContext) {
const debugProvider = new XYZDebugConfigProvider();
factory = new XYZDebugAdapterDescriptorFactory();
context.subscriptions.push(
vscode.debug.registerDebugConfigurationProvider(
'xyz', debugProvider
)
);
context.subscriptions.push(
vscode.debug.onDidReceiveDebugSessionCustomEvent(
handleCustomEvent
)
);
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('xyz', factory));
context.subscriptions.push(factory);
}
You'll then need to provide an adaptor for the config. This one will connect to a DAP server on the supplied port or launch xyz.exe
class XYZDebugConfigProvider implements vscode.DebugConfigurationProvider {
resolveDebugConfiguration(folder: WorkspaceFolder | undefined, config: DebugConfiguration, token?: CancellationToken): ProviderResult<DebugConfiguration> {
const editor = vscode.window.activeTextEditor;
const defaultConfig = vscode.extensions
.getExtension("YOUR EXTENSION NAME HERE")
.packageJSON
.contributes
.debuggers[0]
.initialConfigurations[0];
if (!config.request && editor.document.languageId === 'xyz') {
return defaultConfig;
} else if (!config.request) {
// Not trying to debug xyz?
return undefined;
}
config = {
...defaultConfig,
...config
}
config.execArgs = (config.args || [])
.concat(`-l${config.port}`);
return config;
}
}
class ElpsDebugAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory {
private outputchannel: vscode.OutputChannel
constructor() {
this.outputchannel = vscode.window.createOutputChannel(
'XYZ Debug Log'
);
}
createDebugAdapterDescriptor(session: DebugSession, executable: DebugAdapterExecutable | undefined): ProviderResult<DebugAdapterDescriptor> {
if (session.configuration.type !== "xyz") {
return undefined
}
if (session.configuration.request == "launch") {
const args = [...session.configuration.execArgs, session.configuration.program]
this.outputchannel.appendLine(`Starting XYZ with "${session.configuration.executable}" and args "${args.join(" ")}"`)
const debugee = spawn(session.configuration.executable, args)
debugee.stderr.on('data', (data) => {
this.outputchannel.appendLine(data.toString())
})
debugee.stdout.on('data', (data) => {
this.outputchannel.appendLine(data.toString())
})
debugee.on("close", (data) => {
this.outputchannel.appendLine(`Process closed with status ${data}`)
})
debugee.on("error", (data) => {
this.outputchannel.appendLine(`Error from XYZ: ${data.message}:\n${data.stack}`)
})
}
return new vscode.DebugAdapterServer(session.configuration.port)
}
dispose() {}
}
Lastly you'll need to add the rest of the config that you might want to use to your package.json and into launch.json in the debuggee - that part is very well covered in the docs for the example debugger https://code.visualstudio.com/api/extension-guides/debugger-extension
The above is adapted from a ELISP debugger I was writing and is in turn inspired by the excellent Perl 6 support at https://marketplace.visualstudio.com/items?itemName=mortenhenriksen.perl-debug
Related
I created a new configuration in my angular.json and I cannot make VS Code debug.
My VS Code is debugging OK when I use the default configuration.
I created a new configuraton in angular.json as below:
{
...
},
"newProjectRoot": "projects",
"projects": {
"MyProject": {
"projectType": "application",
"schematics": {
...
},
...
"architect": {
"build": {
...,
"configurations": {
"production": {
...
},
"development": {
...
},
"fred": { <================================================
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.fred.ts"
}
]
}
},
"defaultConfiguration": "development"
},
"serve": {
...,
"configurations": {
"production": {
"browserTarget": "fuse:MyProject:production"
},
"development": {
"browserTarget": "fuse:MyProject:development"
},
"fred": { <=====================================================
"browserTarget": "fuse:MyProject:fred"
}
},
"defaultConfiguration": "development"
},
...
}
}
}
}
On package.json I created a new script
"scripts": {
"ng": "ng",
"start": "ng serve --port 8093",
"start-fred": "ng serve --configuration fred --port 8093", <====================
...
}
On my launch.json I added a new config to start that script
{
"version": "0.2.0",
"configurations": [
{
"name": "ng serve Chrome",
...
},
{
"name": "Fred ng serve Chrome",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: start-fred", <=================================
"url": "https://localhost:8093",
"webRoot": "${workspaceFolder}"
},
{
"name": "ng serve Edge",
...
}
]
}
It builds OK and I can navigate the app by manually going to the URL on the browser but I cannot debug. VS Code hangs with no error message and never starts the debug session.
I don't know where else to look. As I said before, I can debug OK when I use the default (development) configuration
How can I pass environment variables to my build task? According to what I've found at many places, this can be specified in the tasks.json. However, I tried without success:
tasks.json:
{
"version": "2.0.0",
"options": {
"env": {
"CXX": "/usr/local/opt/llvm/bin/clang++",
"LDFLAGS": "-L/usr/local/opt/llvm/lib/c++ -Wl,-rpath,/usr/local/opt/llvm/lib/c++ -L/usr/local/opt/libomp/lib",
"CXXFLAGS": "-I/usr/local/opt/libomp/include"
},
"shell": {"executable": "/bin/zsh"}
},
"tasks": [
{
"type": "cppbuild",
"label": "make test",
"command": "gmake",
"args": [
"-f",
"Test.Makefile"
],
"options": {
"cwd": "${workspaceFolder}"
}
}
}
}
Test.Makefile:
$(info $(LDFLAGS))
$(info $(CXXFLAGS))
When I launch this task, the makefile prints no values for the variables. In my usual terminal (where I have exported these variables in my .zshrc) the variables are seen by gmake. What am I doing wrong?
I want to lanuch VS Code with --remote-debugging-port.
I can do this with runTest.ts like below.
This works fine with puppereer.connect().
import { runTests } from '#vscode/test-electron';
async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
// The path to the extension test runner script
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './suite/index');
// Download VS Code, unzip it and run the integration test
await runTests({
extensionDevelopmentPath,
extensionTestsPath,
launchArgs: [
"--remote-debugging-port=9229",
]
});
} catch (err) {
console.error(err);
console.error('Failed to run tests');
process.exit(1);
}
}
main();
But when I try to do same thing with launch.json, it's failed.
When I start debug, this may cause FetchError: Failed to fetch browser webSocket URL from http://127.0.0.1:9229/json/version: request to http://127.0.0.1:9229/json/version failed, reason: connect ECONNREFUSED 127.0.0.1:9229
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension Test",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index",
],
"runtimeArgs": [
"--remote-debugging-port=9229",
],
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "test-compile"
},
]
}
How can I do this with launch.json?
Edit:
I update my launch.json and http://127.0.0.1:9229 is now opened.
{
"args": [
"--remote-debugging-port=9229",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index",
],
"port": "9229",
}
But now, I dont get webSocketDebuggerUrl from result of fetch 127.0.0.1:9229. It only return this json.
{Browser: 'node.js/v14.16.0', Protocol-Version: '1.1'}
Looking at the code they have a specific location of the launchArgs
if runTests works you could try
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension Test",
"type": "extensionHost",
"request": "launch",
"args": [
"--remote-debugging-port=9229",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index",
],
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "test-compile"
},
]
}
I am trying to create a new VS Code theme, but whenever I try to run the debugger vs code shows a warning "You don't have an extension for debugging 'JSON with comments'. Should we find a 'JSON with comments' extension in the marketplace?'
My launch.json file:
{
"version": "0.2.0",
"configurations": [
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"]
}
]
}
My package.json file:
{
"name": "theme",
"displayName": "theme",
"description": "theme",
"version": "0.0.1",
"engines": {
"vscode": "^1.58.0"
},
"categories": [
"Themes"
],
"contributes": {
"themes": [
{
"label": "theme",
"uiTheme": "vs-dark",
"path": "./themes/theme-color-theme.json"
}
]
}
}
I tried finding the JSON with comments debugger in the marketplace, but couldn't find it. Does anyone has any idea what I am doing wrong?
When debugging a theme your "./.vscode/launch.json" should look like this:
// "./.vscode/launch.json"
{
"configurations": [
{
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"name": "Launch Extension",
"request": "launch",
"type": "pwa-extensionHost"
}
]
}
"You only need four (4) settings total, which are displayed in the snippet above. Everything else is unnecessary junk when debugging a theme."
You need to do one more thing:
At the very top of your "./themes/theme-color-theme.json" file add the following lines:
// "./themes/theme-color-theme.json"
{
"name": "Your-themes-name",
"type": "dark",
"$schema": "vscode://schemas/color-theme",
"colors": {
// theme highlighting...
},
}
EDIT:
I unintentionally added "semanticHighlighting": true to the snippet above. That's something that isn't related to this question so I removed it from the example. Semantic Highlight is important, though, and you should read about it before choosing true or false, if you haven't read about it already.
Is it possible to run a command in a variable and pass parameters? Given that this command requires input arguments.
Example:
// in launch.json
{
"program": "${command:somecommand(foo=${someargument})}"
}
Create an input in your launch.json which calls your command, there you can pass your argument. You can then reference the input in your attach/launch config.
// launch.json
{
"version": "0.2.0",
"inputs": [
{
"id": "commandInput",
"type": "command",
"command": "somecommand",
"args": {
"foo": "${someargument}"
}
}
],
"configurations": [
{
"name": "Launch",
"type": "node",
"request": "launch",
"program": "${input:commandInput}"
}
]
}