My Visual Code Debug Extension, doesn't execute my debugger

Viewed 1105

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"
        }
    ]
}
1 Answers

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