diff --git a/package.json b/package.json index 79c4e508..d527e97a 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "aiKey": "83dd2c27-6594-41d3-85a9-bdb22070eb42", "preview": true, "engines": { - "vscode": "^1.13.0" + "vscode": "^1.17.0" }, "icon": "images/arduino.png", "license": "SEE LICENSE IN LICENSE.txt", @@ -34,7 +34,6 @@ ], "activationEvents": [ "*", - "onCommand:arduino.debug.startSession", "onCommand:arduino.verify", "onCommand:arduino.upload", "onCommand:arduino.selectSerialPort", @@ -48,7 +47,8 @@ "onCommand:arduino.showBoardManager", "onCommand:arduino.showLibraryManager", "onCommand:arduino.showExamples", - "onCommand:arduino.initialize" + "onCommand:arduino.initialize", + "onDebug" ], "main": "./out/src/extension", "contributes": { @@ -129,7 +129,6 @@ { "type": "arduino", "label": "Arduino", - "startSessionCommand": "arduino.debug.startSession", "enableBreakpointsFor": { "languageIds": [ "c", @@ -145,7 +144,7 @@ "type": "arduino", "request": "launch", "program": "$${{file}}", - "cwd": "$${{workspaceRoot}}", + "cwd": "$${{workspaceFolder}}", "MIMode": "gdb", "targetArchitecture": "arm", "miDebuggerPath": "", @@ -176,42 +175,6 @@ } } ], - "initialConfigurations": [ - { - "name": "Arduino", - "type": "arduino", - "request": "launch", - "program": "${file}", - "cwd": "${workspaceRoot}", - "MIMode": "gdb", - "targetArchitecture": "arm", - "miDebuggerPath": "", - "debugServerPath": "", - "debugServerArgs": "", - "customLaunchSetupCommands": [ - { - "text": "target remote localhost:3333" - }, - { - "text": "file ${file}" - }, - { - "text": "load" - }, - { - "text": "monitor reset halt" - }, - { - "text": "monitor reset init" - } - ], - "stopAtEntry": true, - "serverStarted": "Info\\ :\\ [\\w\\d\\.]*:\\ hardware", - "launchCompleteCommand": "exec-continue", - "filterStderr": true, - "args": [] - } - ], "configurationAttributes": { "launch": { "required": [ @@ -221,7 +184,7 @@ "program": { "type": "string", "description": "Full path to program executable.", - "default": "${workspaceRoot}/arduino.elf" + "default": "${workspaceFolder}/arduino.elf" }, "args": { "type": "array", diff --git a/src/arduinoContext.ts b/src/arduinoContext.ts index 865f2a15..58a3f8a4 100644 --- a/src/arduinoContext.ts +++ b/src/arduinoContext.ts @@ -3,7 +3,6 @@ import { ArduinoApp } from "./arduino/arduino"; import { BoardManager } from "./arduino/boardManager"; -import { DebugConfigurator } from "./debug/configurator"; import { DebuggerManager } from "./debug/debuggerManager"; import { DeviceContext } from "./deviceContext"; @@ -28,26 +27,19 @@ class ArduinoContext { this._boardManager = value; } - public get arduinoConfigurator(): DebugConfigurator { - if (this._arduinoConfigurator === null) { - const debuggerManager = new DebuggerManager( + public get debuggerManager(): DebuggerManager { + if (this._debuggerManager === null) { + this._debuggerManager = new DebuggerManager( DeviceContext.getInstance().extensionPath, this.arduinoApp.settings, this.boardManager); - debuggerManager.initialize(); - this._arduinoConfigurator = new DebugConfigurator( - this.arduinoApp, this.arduinoApp.settings - , this.boardManager, debuggerManager); + this._debuggerManager.initialize(); } - return this._arduinoConfigurator; - } - - public set arduinoConfigurator(value: DebugConfigurator) { - this._arduinoConfigurator = value; + return this._debuggerManager; } private _arduinoApp: ArduinoApp = null; - private _arduinoConfigurator: DebugConfigurator = null; + private _debuggerManager: DebuggerManager = null; private _boardManager: BoardManager = null; } diff --git a/src/debug/configurator.ts b/src/debug/configurationProvider.ts similarity index 59% rename from src/debug/configurator.ts rename to src/debug/configurationProvider.ts index 57da97ba..87cf4277 100644 --- a/src/debug/configurator.ts +++ b/src/debug/configurationProvider.ts @@ -5,62 +5,69 @@ import * as path from "path"; import * as vscode from "vscode"; import { ArduinoApp } from "../arduino/arduino"; -import { IArduinoSettings } from "../arduino/arduinoSettings"; -import { BoardManager } from "../arduino/boardManager"; +import ArduinoActivator from "../arduinoActivator"; +import ArduinoContext from "../arduinoContext"; + import { VscodeSettings } from "../arduino/vscodeSettings"; import * as platform from "../common/platform"; import * as util from "../common/util"; import { DeviceContext } from "../deviceContext"; import * as Logger from "../logger/logger"; -import { DebuggerManager } from "./debuggerManager"; - -/** - * Automatically generate the Arduino board's debug settings. - */ -export class DebugConfigurator { - constructor( - private _arduinoApp: ArduinoApp, - private _arduinoSettings: IArduinoSettings, - private _boardManager: BoardManager, - private _debuggerManager: DebuggerManager, - ) { + +export class ArduinoDebugConfigurationProvider implements vscode.DebugConfigurationProvider { + + constructor() { } + + public provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, token?: vscode.CancellationToken): + vscode.ProviderResult { + return [{ + name: "Arduino", + type: "arduino", + request: "launch", + program: "${file}", + cwd: folder, + MIMode: "gdb", + targetArchitecture: "arm", + miDebuggerPath: "", + debugServerPath: "", + debugServerArgs: "", + customLaunchSetupCommands: [ + { + text: "target remote localhost:3333", + }, + { + text: "file ${file}", + }, + { + text: "load", + }, + { + text: "monitor reset halt", + }, + { + text: "monitor reset init", + }, + ], + stopAtEntry: true, + serverStarted: "Info\\ :\\ [\\w\\d\\.]*:\\ hardware", + launchCompleteCommand: "exec-continue", + filterStderr: true, + args: [], + }]; } - public async run(config) { - // Default settings: - if (!config.request) { - config = { - name: "Arduino", - type: "arduino", - request: "launch", - program: "${file}", - cwd: "${workspaceRoot}", - MIMode: "gdb", - - targetArchitecture: "arm", - customLaunchSetupCommands: [ - { - text: "target remote localhost:3333", - }, - { - text: "file ${file}", - }, - { - text: "load", - }, - { - text: "monitor reset halt", - }, - { - text: "monitor reset init", - }, - ], - stopAtEntry: true, - serverStarted: "Info\\ :\\ [\\w\\d\\.]*:\\ hardware", - launchCompleteCommand: "exec-continue", - filterStderr: true, - args: [], - }; + // Try to add all missing attributes to the debug configuration being launched. + public resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken): + vscode.ProviderResult { + if (config && !config.cwd) { + config.cwd = folder; + } + return this.resolveDebugConfigurationAsync(config); + } + + private async resolveDebugConfigurationAsync(config: vscode.DebugConfiguration) { + if (!ArduinoContext.initialized) { + await ArduinoActivator.activate(); } if (VscodeSettings.getInstance().logLevel === "verbose" && !config.logging) { @@ -71,32 +78,32 @@ export class DebugConfigurator { }; } - if (!this._boardManager.currentBoard) { + if (!ArduinoContext.boardManager.currentBoard) { vscode.window.showErrorMessage("Please select a board."); - return; + return undefined; } if (!this.resolveOpenOcd(config)) { - return; + return undefined; } if (!await this.resolveOpenOcdOptions(config)) { - return; + return undefined; } if (!this.resolveDebuggerPath(config)) { - return; + return undefined; } if (!await this.resolveProgramPath(config)) { - return; + return undefined; } // Use the C++ debugger MIEngine as the real internal debugger config.type = "cppdbg"; - vscode.commands.executeCommand("vscode.startDebug", config); const dc = DeviceContext.getInstance(); Logger.traceUserData("start-cppdbg", { board: dc.board }); + return config; } private async resolveProgramPath(config) { @@ -104,7 +111,7 @@ export class DebugConfigurator { if (!config.program || config.program === "${file}") { // make a unique temp folder because keeping same temp folder will corrupt the build when board is changed - const outputFolder = path.join(dc.output || `.build`, this._boardManager.currentBoard.board); + const outputFolder = path.join(dc.output || `.build`, ArduinoContext.boardManager.currentBoard.board); util.mkdirRecursivelySync(path.join(vscode.workspace.rootPath, outputFolder)); if (!dc.sketch || !util.fileExistsSync(path.join(vscode.workspace.rootPath, dc.sketch))) { await dc.resolveMainSketch(); @@ -122,7 +129,7 @@ export class DebugConfigurator { config.program = path.join(vscode.workspace.rootPath, outputFolder, `${path.basename(dc.sketch)}.elf`); // always compile elf to make sure debug the right elf - if (!await this._arduinoApp.verify(outputFolder)) { + if (!await ArduinoContext.arduinoApp.verify(outputFolder)) { vscode.window.showErrorMessage("Failure to verify the program, please check output for details."); return false; } @@ -145,10 +152,10 @@ export class DebugConfigurator { private resolveDebuggerPath(config) { if (!config.miDebuggerPath) { config.miDebuggerPath = platform.findFile(platform.getExecutableFileName("arm-none-eabi-gdb"), - path.join(this._arduinoSettings.packagePath, "packages", this._boardManager.currentBoard.getPackageName())); + path.join(ArduinoContext.arduinoApp.settings.packagePath, "packages", ArduinoContext.boardManager.currentBoard.getPackageName())); } if (!util.fileExistsSync(config.miDebuggerPath)) { - config.miDebuggerPath = this._debuggerManager.miDebuggerPath; + config.miDebuggerPath = ArduinoContext.debuggerManager.miDebuggerPath; } if (!util.fileExistsSync(config.miDebuggerPath)) { vscode.window.showErrorMessage("Cannot find the debugger path."); @@ -160,11 +167,11 @@ export class DebugConfigurator { private resolveOpenOcd(config) { if (!config.debugServerPath) { config.debugServerPath = platform.findFile(platform.getExecutableFileName("openocd"), - path.join(this._arduinoSettings.packagePath, "packages", - this._boardManager.currentBoard.getPackageName())); + path.join(ArduinoContext.arduinoApp.settings.packagePath, "packages", + ArduinoContext.boardManager.currentBoard.getPackageName())); } if (!util.fileExistsSync(config.debugServerPath)) { - config.debugServerPath = this._debuggerManager.debugServerPath; + config.debugServerPath = ArduinoContext.debuggerManager.debugServerPath; } if (!util.fileExistsSync(config.debugServerPath)) { vscode.window.showErrorMessage("Cannot find the OpenOCD from the launch.json debugServerPath property." + @@ -176,10 +183,9 @@ export class DebugConfigurator { } private async resolveOpenOcdOptions(config) { - if (config.debugServerPath && !config.debugServerArgs) { try { - config.debugServerArgs = await this._debuggerManager.resolveOpenOcdOptions(config); + config.debugServerArgs = await ArduinoContext.debuggerManager.resolveOpenOcdOptions(config); if (!config.debugServerArgs) { return false; } diff --git a/src/extension.ts b/src/extension.ts index 534c5e63..c0df24ee 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,6 +13,7 @@ import { LIBRARY_MANAGER_URI, } from "./common/constants"; import * as util from "./common/util"; +import { ArduinoDebugConfigurationProvider } from "./debug/configurationProvider"; import { DeviceContext } from "./deviceContext"; import { CompletionProvider } from "./langService/completionProvider"; import * as Logger from "./logger/logger"; @@ -24,7 +25,7 @@ const status: any = {}; export async function activate(context: vscode.ExtensionContext) { Logger.configure(context); const activeGuid = Uuid().replace(/-/g, ""); - Logger.traceUserData("start-activate-extension", {correlationId: activeGuid}); + Logger.traceUserData("start-activate-extension", { correlationId: activeGuid }); // Show a warning message if the working file is not under the workspace folder. // People should know the extension might not work appropriately, they should look for the doc to get started. const openEditor = vscode.window.activeTextEditor; @@ -46,7 +47,7 @@ export async function activate(context: vscode.ExtensionContext) { const commandExecution = async (command: string, commandBody: (...args: any[]) => any, args: any, getUserData?: () => any) => { const guid = Uuid().replace(/\-/g, ""); - Logger.traceUserData(`start-command-` + command, {correlationId: guid}); + Logger.traceUserData(`start-command-` + command, { correlationId: guid }); const timer1 = new Logger.Timer(); let telemetryResult; try { @@ -60,7 +61,7 @@ export async function activate(context: vscode.ExtensionContext) { telemetryResult = getUserData(); } } catch (error) { - Logger.traceError("executeCommandError", error, {correlationId: guid, command}); + Logger.traceError("executeCommandError", error, { correlationId: guid, command }); } Logger.traceUserData(`end-command-` + command, { @@ -122,13 +123,13 @@ export async function activate(context: vscode.ExtensionContext) { arduinoManagerProvider.update(LIBRARY_MANAGER_URI); arduinoManagerProvider.update(EXAMPLES_URI); }, () => { - return {board: ArduinoContext.boardManager.currentBoard.name}; + return { board: ArduinoContext.boardManager.currentBoard.name }; }); registerArduinoCommand("arduino.reloadExample", () => { arduinoManagerProvider.update(EXAMPLES_URI); }, () => { - return {board: ArduinoContext.boardManager.currentBoard.name}; + return { board: ArduinoContext.boardManager.currentBoard.name }; }); registerArduinoCommand("arduino.initialize", async () => await deviceContext.initialize()); @@ -143,39 +144,26 @@ export async function activate(context: vscode.ExtensionContext) { delete status.compile; } }, () => { - return {board: ArduinoContext.boardManager.currentBoard.name}; + return { board: ArduinoContext.boardManager.currentBoard.name }; }); registerArduinoCommand("arduino.upload", async () => { - if (!status.compile) { - status.compile = "upload"; - try { - await ArduinoContext.arduinoApp.upload(); - } catch (ex) { - } - delete status.compile; + if (!status.compile) { + status.compile = "upload"; + try { + await ArduinoContext.arduinoApp.upload(); + } catch (ex) { } - }, + delete status.compile; + } + }, () => { - return {board: ArduinoContext.boardManager.currentBoard.name}; + return { board: ArduinoContext.boardManager.currentBoard.name }; }); registerArduinoCommand("arduino.addLibPath", (path) => ArduinoContext.arduinoApp.addLibPath(path)); registerArduinoCommand("arduino.openExample", (path) => ArduinoContext.arduinoApp.openExample(path)); - // Arduino debugger - registerArduinoCommand("arduino.debug.startSession", async (config) => { - if (!status.debug) { - status.debug = "debug"; - try { - await ArduinoContext.arduinoConfigurator.run(config); - } catch (ex) { - } - delete status.debug; - - } - }); - // serial monitor commands const serialMonitor = SerialMonitor.getInstance(); context.subscriptions.push(serialMonitor); @@ -187,6 +175,7 @@ export async function activate(context: vscode.ExtensionContext) { const completionProvider = new CompletionProvider(); context.subscriptions.push(vscode.languages.registerCompletionItemProvider(ARDUINO_MODE, completionProvider, "<", '"', ".")); + context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider("arduino", new ArduinoDebugConfigurationProvider())); UsbDetector.getInstance().initialize(context.extensionPath); UsbDetector.getInstance().startListening(); @@ -203,15 +192,15 @@ export async function activate(context: vscode.ExtensionContext) { SerialMonitor.getInstance().initialize(); } ArduinoContext.boardManager.updateStatusBar(true); - vscode.commands.executeCommand("setContext", "vscode-arduino:showExampleExplorer", true); + vscode.commands.executeCommand("setContext", "vscode-arduino:showExampleExplorer", true); })(); } vscode.window.onDidChangeActiveTextEditor(async () => { const activeEditor = vscode.window.activeTextEditor; if (activeEditor && ((path.basename(activeEditor.document.fileName) === "arduino.json" - && path.basename(path.dirname(activeEditor.document.fileName)) === ".vscode") - || activeEditor.document.fileName.endsWith(".ino") - )) { + && path.basename(path.dirname(activeEditor.document.fileName)) === ".vscode") + || activeEditor.document.fileName.endsWith(".ino") + )) { if (!ArduinoContext.initialized) { await ArduinoActivator.activate(); } @@ -219,10 +208,10 @@ export async function activate(context: vscode.ExtensionContext) { SerialMonitor.getInstance().initialize(); } ArduinoContext.boardManager.updateStatusBar(true); - vscode.commands.executeCommand("setContext", "vscode-arduino:showExampleExplorer", true); + vscode.commands.executeCommand("setContext", "vscode-arduino:showExampleExplorer", true); } }); - Logger.traceUserData("end-activate-extension", {correlationId: activeGuid}); + Logger.traceUserData("end-activate-extension", { correlationId: activeGuid }); } export async function deactivate() { diff --git a/test/extension.test.ts b/test/extension.test.ts index 4953c55a..4708f53e 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -47,7 +47,6 @@ suite("Arduino: Extension Tests", () => { "arduino.sendMessageToSerialPort", "arduino.closeSerialMonitor", "arduino.reloadExample", - "arduino.debug.startSession", "arduino.showExampleExplorer", ];