Skip to content

Commit b5076b0

Browse files
committed
Report column number in stack frame when debugger stops
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
1 parent 0439152 commit b5076b0

File tree

6 files changed

+61
-15
lines changed

6 files changed

+61
-15
lines changed

src/PowerShellEditorServices.Protocol/DebugAdapter/StackFrame.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ public class StackFrame
1515

1616
public int Line { get; set; }
1717

18+
public int? EndLine { get; set; }
19+
1820
public int Column { get; set; }
1921

22+
public int? EndColumn { get; set; }
23+
2024
// /** An identifier for the stack frame. */
2125
//id: number;
2226
///** The name of the stack frame, typically a method name */
@@ -38,8 +42,10 @@ public static StackFrame Create(
3842
{
3943
Id = id,
4044
Name = stackFrame.FunctionName,
41-
Line = stackFrame.LineNumber,
42-
Column = stackFrame.ColumnNumber,
45+
Line = stackFrame.StartLineNumber,
46+
EndLine = stackFrame.EndLineNumber > 0 ? (int?)stackFrame.EndLineNumber : null,
47+
Column = stackFrame.StartColumnNumber,
48+
EndColumn = stackFrame.EndColumnNumber > 0 ? (int?)stackFrame.EndColumnNumber : null,
4349
Source = new Source
4450
{
4551
Path = stackFrame.ScriptPath

src/PowerShellEditorServices.Protocol/DebugAdapter/StoppedEvent.cs

-4
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ public class StoppedEventBody
2828

2929
public Source Source { get; set; }
3030

31-
public int Line { get; set; }
32-
33-
public int Column { get; set; }
34-
3531
/// <summary>
3632
/// Gets or sets additional information such as an error message.
3733
/// </summary>

src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs

-2
Original file line numberDiff line numberDiff line change
@@ -857,8 +857,6 @@ await this.SendEvent(
857857
{
858858
Path = e.ScriptPath,
859859
},
860-
Line = e.LineNumber,
861-
Column = e.ColumnNumber,
862860
ThreadId = 1,
863861
Reason = debuggerStoppedReason
864862
});

src/PowerShellEditorServices/Debugging/DebugService.cs

+24
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Linq;
99
using System.Management.Automation;
1010
using System.Management.Automation.Language;
11+
using System.Reflection;
1112
using System.Text;
1213
using System.Threading.Tasks;
1314
using Microsoft.PowerShell.EditorServices.Debugging;
@@ -41,6 +42,7 @@ public class DebugService
4142
private VariableContainerDetails globalScopeVariables;
4243
private VariableContainerDetails scriptScopeVariables;
4344
private StackFrameDetails[] stackFrameDetails;
45+
private PropertyInfo invocationTypeScriptPositionProperty;
4446

4547
private static int breakpointHitCounter = 0;
4648

@@ -81,6 +83,12 @@ public DebugService(
8183
this.powerShellContext.BreakpointUpdated += this.OnBreakpointUpdated;
8284

8385
this.remoteFileManager = remoteFileManager;
86+
87+
this.invocationTypeScriptPositionProperty =
88+
typeof(InvocationInfo)
89+
.GetProperty(
90+
"ScriptPosition",
91+
BindingFlags.NonPublic | BindingFlags.Instance);
8492
}
8593

8694
#endregion
@@ -1100,6 +1108,22 @@ await this.remoteFileManager.FetchRemoteFile(
11001108
this.powerShellContext.CurrentRunspace);
11011109
}
11021110

1111+
if (this.stackFrameDetails.Length > 0)
1112+
{
1113+
// Augment the top stack frame with details from the stop event
1114+
IScriptExtent scriptExtent =
1115+
this.invocationTypeScriptPositionProperty
1116+
.GetValue(e.InvocationInfo) as IScriptExtent;
1117+
1118+
if (scriptExtent != null)
1119+
{
1120+
this.stackFrameDetails[0].StartLineNumber = scriptExtent.StartLineNumber;
1121+
this.stackFrameDetails[0].EndLineNumber = scriptExtent.EndLineNumber;
1122+
this.stackFrameDetails[0].StartColumnNumber = scriptExtent.StartColumnNumber;
1123+
this.stackFrameDetails[0].EndColumnNumber = scriptExtent.EndColumnNumber;
1124+
}
1125+
}
1126+
11031127
// Notify the host that the debugger is stopped
11041128
this.DebuggerStopped?.Invoke(
11051129
sender,

src/PowerShellEditorServices/Debugging/StackFrameDetails.cs

+15-5
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,25 @@ public class StackFrameDetails
3535
/// </summary>
3636
public string FunctionName { get; private set; }
3737

38+
/// <summary>
39+
/// Gets the start line number of the script where the stack frame occurred.
40+
/// </summary>
41+
public int StartLineNumber { get; internal set; }
42+
3843
/// <summary>
3944
/// Gets the line number of the script where the stack frame occurred.
4045
/// </summary>
41-
public int LineNumber { get; private set; }
46+
public int EndLineNumber { get; internal set; }
47+
48+
/// <summary>
49+
/// Gets the start column number of the line where the stack frame occurred.
50+
/// </summary>
51+
public int StartColumnNumber { get; internal set; }
4252

4353
/// <summary>
44-
/// Gets the column number of the line where the stack frame occurred.
54+
/// Gets the end column number of the line where the stack frame occurred.
4555
/// </summary>
46-
public int ColumnNumber { get; private set; }
56+
public int EndColumnNumber { get; internal set; }
4757

4858
/// <summary>
4959
/// Gets or sets the VariableContainerDetails that contains the auto variables.
@@ -82,8 +92,8 @@ static internal StackFrameDetails Create(
8292
{
8393
ScriptPath = (callStackFrameObject.Properties["ScriptName"].Value as string) ?? NoFileScriptPath,
8494
FunctionName = callStackFrameObject.Properties["FunctionName"].Value as string,
85-
LineNumber = (int)(callStackFrameObject.Properties["ScriptLineNumber"].Value ?? 0),
86-
ColumnNumber = 0, // Column number isn't given in PowerShell stack frames
95+
StartLineNumber = (int)(callStackFrameObject.Properties["ScriptLineNumber"].Value ?? 0),
96+
StartColumnNumber = 0, // Column number isn't given in PowerShell stack frames
8797
AutoVariables = autoVariables,
8898
LocalVariables = localVariables
8999
};

test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs

+14-2
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,25 @@ await this.SendRequest(
8585
// Wait for a couple breakpoints
8686
StoppedEventBody stoppedDetails = await breakEventTask;
8787
Assert.Equal(DebugScriptPath, stoppedDetails.Source.Path);
88-
Assert.Equal(5, stoppedDetails.Line);
88+
89+
var stackTraceResponse =
90+
await this.SendRequest(
91+
StackTraceRequest.Type,
92+
new StackTraceRequestArguments());
93+
94+
Assert.Equal(5, stackTraceResponse.StackFrames[0].Line);
8995

9096
breakEventTask = this.WaitForEvent(StoppedEvent.Type);
9197
await this.SendRequest(ContinueRequest.Type, new object());
9298
stoppedDetails = await breakEventTask;
9399
Assert.Equal(DebugScriptPath, stoppedDetails.Source.Path);
94-
Assert.Equal(7, stoppedDetails.Line);
100+
101+
stackTraceResponse =
102+
await this.SendRequest(
103+
StackTraceRequest.Type,
104+
new StackTraceRequestArguments());
105+
106+
Assert.Equal(7, stackTraceResponse.StackFrames[0].Line);
95107

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

0 commit comments

Comments
 (0)