Skip to content

Commit

Permalink
Report column number in stack frame when debugger stops
Browse files Browse the repository at this point in the history
This change causes the column number of the debugger's currently stopped
position to be passed through with the top stack frame.  This allows VS
Code's debugger UI to show an indicator that points to where the debugger
stopped when stepping through code.

Resolve PowerShell/vscode-powershell#616
  • Loading branch information
daviwil committed Mar 25, 2017
1 parent 0439152 commit b5076b0
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 15 deletions.
10 changes: 8 additions & 2 deletions src/PowerShellEditorServices.Protocol/DebugAdapter/StackFrame.cs
Expand Up @@ -15,8 +15,12 @@ public class StackFrame

public int Line { get; set; }

public int? EndLine { get; set; }

public int Column { get; set; }

public int? EndColumn { get; set; }

// /** An identifier for the stack frame. */
//id: number;
///** The name of the stack frame, typically a method name */
Expand All @@ -38,8 +42,10 @@ public class StackFrame
{
Id = id,
Name = stackFrame.FunctionName,
Line = stackFrame.LineNumber,
Column = stackFrame.ColumnNumber,
Line = stackFrame.StartLineNumber,
EndLine = stackFrame.EndLineNumber > 0 ? (int?)stackFrame.EndLineNumber : null,
Column = stackFrame.StartColumnNumber,
EndColumn = stackFrame.EndColumnNumber > 0 ? (int?)stackFrame.EndColumnNumber : null,
Source = new Source
{
Path = stackFrame.ScriptPath
Expand Down
Expand Up @@ -28,10 +28,6 @@ public class StoppedEventBody

public Source Source { get; set; }

public int Line { get; set; }

public int Column { get; set; }

/// <summary>
/// Gets or sets additional information such as an error message.
/// </summary>
Expand Down
2 changes: 0 additions & 2 deletions src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs
Expand Up @@ -857,8 +857,6 @@ async void DebugService_DebuggerStopped(object sender, DebuggerStoppedEventArgs
{
Path = e.ScriptPath,
},
Line = e.LineNumber,
Column = e.ColumnNumber,
ThreadId = 1,
Reason = debuggerStoppedReason
});
Expand Down
24 changes: 24 additions & 0 deletions src/PowerShellEditorServices/Debugging/DebugService.cs
Expand Up @@ -8,6 +8,7 @@
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Debugging;
Expand Down Expand Up @@ -41,6 +42,7 @@ public class DebugService
private VariableContainerDetails globalScopeVariables;
private VariableContainerDetails scriptScopeVariables;
private StackFrameDetails[] stackFrameDetails;
private PropertyInfo invocationTypeScriptPositionProperty;

private static int breakpointHitCounter = 0;

Expand Down Expand Up @@ -81,6 +83,12 @@ public DebugService(PowerShellContext powerShellContext)
this.powerShellContext.BreakpointUpdated += this.OnBreakpointUpdated;

this.remoteFileManager = remoteFileManager;

this.invocationTypeScriptPositionProperty =
typeof(InvocationInfo)
.GetProperty(
"ScriptPosition",
BindingFlags.NonPublic | BindingFlags.Instance);
}

#endregion
Expand Down Expand Up @@ -1100,6 +1108,22 @@ private async void OnDebuggerStop(object sender, DebuggerStopEventArgs e)
this.powerShellContext.CurrentRunspace);
}

if (this.stackFrameDetails.Length > 0)
{
// Augment the top stack frame with details from the stop event
IScriptExtent scriptExtent =
this.invocationTypeScriptPositionProperty
.GetValue(e.InvocationInfo) as IScriptExtent;

if (scriptExtent != null)
{
this.stackFrameDetails[0].StartLineNumber = scriptExtent.StartLineNumber;
this.stackFrameDetails[0].EndLineNumber = scriptExtent.EndLineNumber;
this.stackFrameDetails[0].StartColumnNumber = scriptExtent.StartColumnNumber;
this.stackFrameDetails[0].EndColumnNumber = scriptExtent.EndColumnNumber;
}
}

// Notify the host that the debugger is stopped
this.DebuggerStopped?.Invoke(
sender,
Expand Down
20 changes: 15 additions & 5 deletions src/PowerShellEditorServices/Debugging/StackFrameDetails.cs
Expand Up @@ -35,15 +35,25 @@ public class StackFrameDetails
/// </summary>
public string FunctionName { get; private set; }

/// <summary>
/// Gets the start line number of the script where the stack frame occurred.
/// </summary>
public int StartLineNumber { get; internal set; }

/// <summary>
/// Gets the line number of the script where the stack frame occurred.
/// </summary>
public int LineNumber { get; private set; }
public int EndLineNumber { get; internal set; }

/// <summary>
/// Gets the start column number of the line where the stack frame occurred.
/// </summary>
public int StartColumnNumber { get; internal set; }

/// <summary>
/// Gets the column number of the line where the stack frame occurred.
/// Gets the end column number of the line where the stack frame occurred.
/// </summary>
public int ColumnNumber { get; private set; }
public int EndColumnNumber { get; internal set; }

/// <summary>
/// Gets or sets the VariableContainerDetails that contains the auto variables.
Expand Down Expand Up @@ -82,8 +92,8 @@ public class StackFrameDetails
{
ScriptPath = (callStackFrameObject.Properties["ScriptName"].Value as string) ?? NoFileScriptPath,
FunctionName = callStackFrameObject.Properties["FunctionName"].Value as string,
LineNumber = (int)(callStackFrameObject.Properties["ScriptLineNumber"].Value ?? 0),
ColumnNumber = 0, // Column number isn't given in PowerShell stack frames
StartLineNumber = (int)(callStackFrameObject.Properties["ScriptLineNumber"].Value ?? 0),
StartColumnNumber = 0, // Column number isn't given in PowerShell stack frames
AutoVariables = autoVariables,
LocalVariables = localVariables
};
Expand Down
16 changes: 14 additions & 2 deletions test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs
Expand Up @@ -85,13 +85,25 @@ public async Task DebugAdapterStopsOnLineBreakpoints()
// Wait for a couple breakpoints
StoppedEventBody stoppedDetails = await breakEventTask;
Assert.Equal(DebugScriptPath, stoppedDetails.Source.Path);
Assert.Equal(5, stoppedDetails.Line);

var stackTraceResponse =
await this.SendRequest(
StackTraceRequest.Type,
new StackTraceRequestArguments());

Assert.Equal(5, stackTraceResponse.StackFrames[0].Line);

breakEventTask = this.WaitForEvent(StoppedEvent.Type);
await this.SendRequest(ContinueRequest.Type, new object());
stoppedDetails = await breakEventTask;
Assert.Equal(DebugScriptPath, stoppedDetails.Source.Path);
Assert.Equal(7, stoppedDetails.Line);

stackTraceResponse =
await this.SendRequest(
StackTraceRequest.Type,
new StackTraceRequestArguments());

Assert.Equal(7, stackTraceResponse.StackFrames[0].Line);

// Abort script execution
await this.SendRequest(DisconnectRequest.Type, new object());
Expand Down

0 comments on commit b5076b0

Please sign in to comment.