diff --git a/src/PowerShellEditorServices.Protocol/DebugAdapter/StackFrame.cs b/src/PowerShellEditorServices.Protocol/DebugAdapter/StackFrame.cs index 910472c86..d9ba5e8c4 100644 --- a/src/PowerShellEditorServices.Protocol/DebugAdapter/StackFrame.cs +++ b/src/PowerShellEditorServices.Protocol/DebugAdapter/StackFrame.cs @@ -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 */ @@ -38,8 +42,10 @@ public static StackFrame Create( { 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 diff --git a/src/PowerShellEditorServices.Protocol/DebugAdapter/StoppedEvent.cs b/src/PowerShellEditorServices.Protocol/DebugAdapter/StoppedEvent.cs index b0850ddb6..8d88a1e5a 100644 --- a/src/PowerShellEditorServices.Protocol/DebugAdapter/StoppedEvent.cs +++ b/src/PowerShellEditorServices.Protocol/DebugAdapter/StoppedEvent.cs @@ -28,10 +28,6 @@ public class StoppedEventBody public Source Source { get; set; } - public int Line { get; set; } - - public int Column { get; set; } - /// /// Gets or sets additional information such as an error message. /// diff --git a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs index 29142a83f..909ea977c 100644 --- a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs +++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs @@ -857,8 +857,6 @@ await this.SendEvent( { Path = e.ScriptPath, }, - Line = e.LineNumber, - Column = e.ColumnNumber, ThreadId = 1, Reason = debuggerStoppedReason }); diff --git a/src/PowerShellEditorServices/Debugging/DebugService.cs b/src/PowerShellEditorServices/Debugging/DebugService.cs index 20ac0f04c..81d042eea 100644 --- a/src/PowerShellEditorServices/Debugging/DebugService.cs +++ b/src/PowerShellEditorServices/Debugging/DebugService.cs @@ -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; @@ -41,6 +42,7 @@ public class DebugService private VariableContainerDetails globalScopeVariables; private VariableContainerDetails scriptScopeVariables; private StackFrameDetails[] stackFrameDetails; + private PropertyInfo invocationTypeScriptPositionProperty; private static int breakpointHitCounter = 0; @@ -81,6 +83,12 @@ public DebugService( this.powerShellContext.BreakpointUpdated += this.OnBreakpointUpdated; this.remoteFileManager = remoteFileManager; + + this.invocationTypeScriptPositionProperty = + typeof(InvocationInfo) + .GetProperty( + "ScriptPosition", + BindingFlags.NonPublic | BindingFlags.Instance); } #endregion @@ -1100,6 +1108,22 @@ await this.remoteFileManager.FetchRemoteFile( 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, diff --git a/src/PowerShellEditorServices/Debugging/StackFrameDetails.cs b/src/PowerShellEditorServices/Debugging/StackFrameDetails.cs index 8b8a07eed..df8ffecd4 100644 --- a/src/PowerShellEditorServices/Debugging/StackFrameDetails.cs +++ b/src/PowerShellEditorServices/Debugging/StackFrameDetails.cs @@ -35,15 +35,25 @@ public class StackFrameDetails /// public string FunctionName { get; private set; } + /// + /// Gets the start line number of the script where the stack frame occurred. + /// + public int StartLineNumber { get; internal set; } + /// /// Gets the line number of the script where the stack frame occurred. /// - public int LineNumber { get; private set; } + public int EndLineNumber { get; internal set; } + + /// + /// Gets the start column number of the line where the stack frame occurred. + /// + public int StartColumnNumber { get; internal set; } /// - /// 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. /// - public int ColumnNumber { get; private set; } + public int EndColumnNumber { get; internal set; } /// /// Gets or sets the VariableContainerDetails that contains the auto variables. @@ -82,8 +92,8 @@ static internal StackFrameDetails Create( { 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 }; diff --git a/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs b/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs index bc2f45504..2d5fc905a 100644 --- a/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs +++ b/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs @@ -85,13 +85,25 @@ await this.SendRequest( // 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());