From c49a964f5690487948773fa37c612694c378166f Mon Sep 17 00:00:00 2001 From: Dan Mace Date: Sun, 20 Mar 2016 00:09:04 -0400 Subject: [PATCH 1/5] Make HoverProvider tolerate missing locations GoHoverProvider was throwing a TypeError trying to read a property from null definition locations. It may be more appropriate to try and prevent the hover provider from entering its handler function if definitionLocation finds no match, but rejecting the Promise didn't see to do the trick. This patch makes the HoverProvider call a no-op when no definition is found.. --- src/goExtraInfo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goExtraInfo.ts b/src/goExtraInfo.ts index 47cbe03ce..6d016adea 100644 --- a/src/goExtraInfo.ts +++ b/src/goExtraInfo.ts @@ -11,6 +11,7 @@ import { definitionLocation } from './goDeclaration'; export class GoHoverProvider implements HoverProvider { public provideHover(document: TextDocument, position: Position, token: CancellationToken): Thenable { return definitionLocation(document, position).then(definitionInfo => { + if (definitionInfo == null) return; let lines = definitionInfo.lines; lines = lines.map(line => { if (line.indexOf('\t') === 0) { From d69146e5a5b0a7245537e4bf62adedc270597c69 Mon Sep 17 00:00:00 2001 From: Dan Mace Date: Sun, 20 Mar 2016 11:47:57 -0400 Subject: [PATCH 2/5] Fix exception in GoDefinitionProvider GoDefinitionProvider shouldn't try to work with a null value returned from definitionLocation. Doing so raises an exception any time godef is invoked on a location which correctly returns no match. --- src/goDeclaration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goDeclaration.ts b/src/goDeclaration.ts index c421c4855..9dbbe5ed1 100644 --- a/src/goDeclaration.ts +++ b/src/goDeclaration.ts @@ -83,6 +83,7 @@ export class GoDefinitionProvider implements vscode.DefinitionProvider { public provideDefinition(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable { return definitionLocation(document, position).then(definitionInfo => { + if (definitionInfo == null) return null; let definitionResource = vscode.Uri.file(definitionInfo.file); let pos = new vscode.Position(definitionInfo.line, definitionInfo.col); return new vscode.Location(definitionResource, pos); From e1747d306ce7595b815d33c875165144a2d8a475 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Sun, 20 Mar 2016 19:49:19 +0100 Subject: [PATCH 3/5] Migrate mis-use of setExceptionBreakPointsRequest to configurationDoneRequest --- src/debugAdapter/goDebug.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/debugAdapter/goDebug.ts b/src/debugAdapter/goDebug.ts index 05c0e83c5..642b0f859 100644 --- a/src/debugAdapter/goDebug.ts +++ b/src/debugAdapter/goDebug.ts @@ -272,6 +272,8 @@ class GoDebugSession extends DebugSession { protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { log('InitializeRequest'); + // This debug adapter implements the configurationDoneRequest. + response.body.supportsConfigurationDoneRequest = true; this.sendResponse(response); log('InitializeResponse'); this.sendEvent(new InitializedEvent()); @@ -311,15 +313,11 @@ class GoDebugSession extends DebugSession { log('DisconnectResponse'); } - protected setExceptionBreakPointsRequest(response: DebugProtocol.SetExceptionBreakpointsResponse, args: DebugProtocol.SetExceptionBreakpointsArguments): void { - log('ExceptionBreakPointsRequest'); - // Wow - this is subtle - it appears that this event will always get - // sent during intiail breakpoint initialization even if there are not - // user breakpoints - so we use this as the indicator to signal - // that breakpoints have been set and we can continue + protected configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.ConfigurationDoneArguments): void { + log('ConfigurationDoneRequest'); this.signalInitialBreakpointsSet(); this.sendResponse(response); - log('ExceptionBreakPointsResponse'); + log('ConfigurationDoneRequest'); } protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void { From 38b3cf01a5cb37c035fc4901ef29ac304517d703 Mon Sep 17 00:00:00 2001 From: Luke Hoban Date: Mon, 21 Mar 2016 12:09:37 -0700 Subject: [PATCH 4/5] Fix TypeScript dev dependency version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 67351db47..9a3988e4c 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "devDependencies": { "fs-extra": "^0.26.0", "tslint": "^3.3.0", - "typescript": "^1.6.2", + "typescript": "1.8.7", "vscode": "^0.10.7" }, "engines": { From de754a38b22a75a0bc2fe07167c1dc6f7933f782 Mon Sep 17 00:00:00 2001 From: Luke Hoban Date: Mon, 21 Mar 2016 13:54:15 -0700 Subject: [PATCH 5/5] Support for `pause` --- .vscode/settings.json | 3 ++- src/debugAdapter/goDebug.ts | 46 +++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bbdabee6e..022f3ba71 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,6 @@ "**/bower_components": true, "out/": true }, - "editor.insertSpaces": false + "editor.insertSpaces": false, + "typescript.tsdk": "./node_modules/typescript/lib" } \ No newline at end of file diff --git a/src/debugAdapter/goDebug.ts b/src/debugAdapter/goDebug.ts index 642b0f859..e0f2c043a 100644 --- a/src/debugAdapter/goDebug.ts +++ b/src/debugAdapter/goDebug.ts @@ -139,6 +139,11 @@ function log(msg?: any, ...args) { console.warn(msg, ...args); } } +function logError(msg?: any, ...args) { + if (DEBUG) { + console.error(msg, ...args); + } +} class Delve { debugProcess: ChildProcess; @@ -216,7 +221,7 @@ class Delve { }); this.debugProcess.on('close', function(code) { // TODO: Report `dlv` crash to user. - console.error('Process exiting with code: ' + code); + logError('Process exiting with code: ' + code); }); this.debugProcess.on('error', function(err) { reject(err); @@ -334,7 +339,10 @@ class GoDebugSession extends DebugSession { log('All cleared'); return Promise.all(args.lines.map(line => { log('Creating on: ' + file + ':' + line); - return this.delve.callPromise('CreateBreakpoint', [{ file, line }]).catch(err => null); + return this.delve.callPromise('CreateBreakpoint', [{ file, line }]).catch(err => { + log('Error on CreateBreakpoint'); + return null; + }); })); }).then(newBreakpoints => { log('All set:' + JSON.stringify(newBreakpoints)); @@ -353,7 +361,7 @@ class GoDebugSession extends DebugSession { log('SetBreakPointsResponse'); }, err => { this.sendErrorResponse(response, 2002, 'Failed to set breakpoint: "{e}"', { e: err.toString() }); - console.error(err); + logError(err); }); } @@ -361,7 +369,7 @@ class GoDebugSession extends DebugSession { log('ThreadsRequest'); this.delve.call('ListGoroutines', [], (err, goroutines) => { if (err) { - console.error('Failed to get threads.'); + logError('Failed to get threads.'); return this.sendErrorResponse(response, 2003, 'Unable to display threads: "{e}"', { e: err.toString() }); } log(goroutines); @@ -382,7 +390,7 @@ class GoDebugSession extends DebugSession { log('StackTraceRequest'); this.delve.call('StacktraceGoroutine', [{ id: args.threadId, depth: args.levels }], (err, locations) => { if (err) { - console.error('Failed to produce stack trace!'); + logError('Failed to produce stack trace!'); return this.sendErrorResponse(response, 2004, 'Unable to produce stack trace: "{e}"', { e: err.toString() }); } log(locations); @@ -408,13 +416,13 @@ class GoDebugSession extends DebugSession { log('ScopesRequest'); this.delve.call('ListLocalVars', [{ goroutineID: this.debugState.currentGoroutine.id, frame: args.frameId }], (err, locals) => { if (err) { - console.error('Failed to list local variables.'); + logError('Failed to list local variables.'); return this.sendErrorResponse(response, 2005, 'Unable to list locals: "{e}"', { e: err.toString() }); } log(locals); this.delve.call('ListFunctionArgs', [{ goroutineID: this.debugState.currentGoroutine.id, frame: args.frameId }], (err, args) => { if (err) { - console.error('Failed to list function args.'); + logError('Failed to list function args.'); return this.sendErrorResponse(response, 2006, 'Unable to list args: "{e}"', { e: err.toString() }); } log(args); @@ -519,7 +527,7 @@ class GoDebugSession extends DebugSession { // [TODO] Can we avoid doing this? https://github.com/Microsoft/vscode/issues/40#issuecomment-161999881 this.delve.call('ListGoroutines', [], (err, goroutines) => { if (err) { - console.error('Failed to get threads.'); + logError('Failed to get threads.'); } // Assume we need to stop all the threads we saw before... let needsToBeStopped = new Set(); @@ -549,7 +557,7 @@ class GoDebugSession extends DebugSession { log('ContinueRequest'); this.delve.call('Command', [{ name: 'continue' }], (err, state) => { if (err) { - console.error('Failed to continue.'); + logError('Failed to continue.'); } log(state); this.debugState = state; @@ -563,7 +571,7 @@ class GoDebugSession extends DebugSession { log('NextRequest'); this.delve.call('Command', [{ name: 'next' }], (err, state) => { if (err) { - console.error('Failed to next.'); + logError('Failed to next.'); } log(state); this.debugState = state; @@ -577,7 +585,7 @@ class GoDebugSession extends DebugSession { log('StepInRequest'); this.delve.call('Command', [{ name: 'step' }], (err, state) => { if (err) { - console.error('Failed to step.'); + logError('Failed to step.'); } log(state); this.debugState = state; @@ -588,13 +596,21 @@ class GoDebugSession extends DebugSession { } protected stepOutRequest(response: DebugProtocol.StepOutResponse): void { - console.error('Not yet implemented: stepOutRequest'); + logError('Not yet implemented: stepOutRequest'); this.sendErrorResponse(response, 2000, 'Step out is not yet supported'); } protected pauseRequest(response: DebugProtocol.PauseResponse): void { - console.error('Not yet implemented: pauseRequest'); - this.sendErrorResponse(response, 2000, 'Pause is not yet supported'); + log('PauseRequest'); + this.delve.call('Command', [{ name: 'halt' }], (err, state) => { + if (err) { + logError('Failed to halt.'); + return this.sendErrorResponse(response, 2010, 'Unable to halt execution: "{e}"', { e: err.toString() }); + } + log(state); + this.sendResponse(response); + log('PauseResponse'); + }); } protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void { @@ -608,7 +624,7 @@ class GoDebugSession extends DebugSession { }; this.delve.call('EvalSymbol', [evalSymbolArgs], (err, variable) => { if (err) { - console.error('Failed to eval expression: ', JSON.stringify(evalSymbolArgs, null, ' ')); + logError('Failed to eval expression: ', JSON.stringify(evalSymbolArgs, null, ' ')); return this.sendErrorResponse(response, 2009, 'Unable to eval expression: "{e}"', { e: err.toString() }); } response.body = this.convertDebugVariableToProtocolVariable(variable, 0);