Skip to content

Commit 04a030c

Browse files
committed
Merge pull request #30 from PowerShell/daviwil/debug-improvements
Improve debugging support
2 parents 746c6fa + d392fce commit 04a030c

File tree

9 files changed

+92
-41
lines changed

9 files changed

+92
-41
lines changed

src/PowerShellEditorServices.Host/MessageLoop.cs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -183,22 +183,17 @@ await this.messageWriter.WriteMessage(
183183
}, null);
184184
}
185185

186-
void PowerShellSession_OutputWritten(object sender, OutputWrittenEventArgs e)
186+
async void PowerShellSession_OutputWritten(object sender, OutputWrittenEventArgs e)
187187
{
188-
// TODO: change this to use the OutputEvent!
189-
190-
//await this.messageWriter.WriteMessage(
191-
// new ReplWriteOutputEvent
192-
// {
193-
// Body = new ReplWriteOutputEventBody
194-
// {
195-
// LineContents = e.OutputText,
196-
// LineType = e.OutputType,
197-
// IncludeNewLine = e.IncludeNewLine,
198-
// ForegroundColor = e.ForegroundColor,
199-
// BackgroundColor = e.BackgroundColor
200-
// }
201-
// });
188+
await this.messageWriter.WriteMessage(
189+
new OutputEvent
190+
{
191+
Body = new OutputEventBody
192+
{
193+
Output = e.OutputText + (e.IncludeNewLine ? "\r\n" : string.Empty),
194+
Category = (e.OutputType == OutputType.Error) ? "stderr" : "stdout"
195+
}
196+
});
202197
}
203198

204199
#endregion
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using Microsoft.PowerShell.EditorServices.Transport.Stdio.Message;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Text;
11+
using System.Threading.Tasks;
12+
13+
namespace Microsoft.PowerShell.EditorServices.Transport.Stdio.Event
14+
{
15+
[MessageTypeName("output")]
16+
public class OutputEvent : EventBase<OutputEventBody>
17+
{
18+
}
19+
20+
public class OutputEventBody
21+
{
22+
public string Category { get; set; }
23+
24+
public string Output { get; set; }
25+
}
26+
}
27+

src/PowerShellEditorServices.Transport.Stdio/PowerShellEditorServices.Transport.Stdio.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
<Compile Include="Event\EventBase.cs" />
6565
<Compile Include="Event\ExitedEvent.cs" />
6666
<Compile Include="Event\InitializedEvent.cs" />
67+
<Compile Include="Event\OutputEvent.cs" />
6768
<Compile Include="Event\ReplPromptChoiceEvent.cs">
6869
<SubType>Code</SubType>
6970
</Compile>

src/PowerShellEditorServices.Transport.Stdio/Request/EvaluateRequest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public override async Task ProcessMessage(
1818
MessageWriter messageWriter)
1919
{
2020
VariableDetails result =
21-
editorSession.DebugService.EvaluateExpression(
21+
await editorSession.DebugService.EvaluateExpression(
2222
this.Arguments.Expression,
2323
this.Arguments.FrameId);
2424

src/PowerShellEditorServices/Debugging/DebugService.cs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,18 +193,17 @@ public VariableDetails[] GetVariables(int variableReferenceId)
193193
}
194194

195195
/// <summary>
196-
/// Evaluates an expression in the context of the stopped
197-
/// debugger. For now, this just does simple evaluation of
198-
/// a variable in the session. In the future it will execute
199-
/// commands in the PowerShellSession.
196+
/// Evaluates a variable expression in the context of the stopped
197+
/// debugger. This method decomposes the variable expression to
198+
/// walk the cached variable data for the specified stack frame.
200199
/// </summary>
201-
/// <param name="expressionString">The expression string to execute.</param>
202-
/// <param name="stackFrameId">The ID of the stack frame in which the expression should be executed.</param>
200+
/// <param name="variableExpression">The variable expression string to evaluate.</param>
201+
/// <param name="stackFrameId">The ID of the stack frame in which the expression should be evaluated.</param>
203202
/// <returns>A VariableDetails object containing the result.</returns>
204-
public VariableDetails EvaluateExpression(string expressionString, int stackFrameId)
203+
public VariableDetails GetVariableFromExpression(string variableExpression, int stackFrameId)
205204
{
206205
// Break up the variable path
207-
string[] variablePathParts = expressionString.Split('.');
206+
string[] variablePathParts = variableExpression.Split('.');
208207

209208
VariableDetails resolvedVariable = null;
210209
IEnumerable<VariableDetails> variableList = this.currentVariables;
@@ -222,10 +221,10 @@ public VariableDetails EvaluateExpression(string expressionString, int stackFram
222221
v =>
223222
string.Equals(
224223
v.Name,
225-
expressionString,
224+
variableExpression,
226225
StringComparison.InvariantCultureIgnoreCase));
227226

228-
if (resolvedVariable != null &&
227+
if (resolvedVariable != null &&
229228
resolvedVariable.IsExpandable)
230229
{
231230
// Continue by searching in this variable's children
@@ -236,6 +235,29 @@ public VariableDetails EvaluateExpression(string expressionString, int stackFram
236235
return resolvedVariable;
237236
}
238237

238+
/// <summary>
239+
/// Evaluates an expression in the context of the stopped
240+
/// debugger. This method will execute the specified expression
241+
/// PowerShellSession.
242+
/// </summary>
243+
/// <param name="expressionString">The expression string to execute.</param>
244+
/// <param name="stackFrameId">The ID of the stack frame in which the expression should be executed.</param>
245+
/// <returns>A VariableDetails object containing the result.</returns>
246+
public async Task<VariableDetails> EvaluateExpression(string expressionString, int stackFrameId)
247+
{
248+
var results =
249+
await this.powerShellSession.ExecuteScriptString(
250+
expressionString);
251+
252+
// Since this method should only be getting invoked in the debugger,
253+
// we can assume that Out-String will be getting used to format results
254+
// of command executions into string output.
255+
256+
return new VariableDetails(
257+
expressionString,
258+
string.Join(Environment.NewLine, results));
259+
}
260+
239261
/// <summary>
240262
/// Gets the list of stack frames at the point where the
241263
/// debugger sf stopped.

src/PowerShellEditorServices/Debugging/VariableDetails.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public class VariableDetails
2020
{
2121
#region Fields
2222

23+
/// <summary>
24+
/// Provides a constant for the dollar sign variable prefix string.
25+
/// </summary>
26+
public const string DollarPrefix = "$";
27+
2328
/// <summary>
2429
/// Provides a constant for the variable ID of the local variable scope.
2530
/// </summary>
@@ -79,7 +84,7 @@ public class VariableDetails
7984
/// The PSVariable instance from which variable details will be obtained.
8085
/// </param>
8186
public VariableDetails(PSVariable psVariable)
82-
: this(psVariable.Name, psVariable.Value)
87+
: this(DollarPrefix + psVariable.Name, psVariable.Value)
8388
{
8489
}
8590

@@ -105,8 +110,8 @@ public VariableDetails(string name, object value)
105110
{
106111
this.valueObject = value;
107112

108-
this.IsExpandable = GetIsExpandable(value);
109113
this.Name = name;
114+
this.IsExpandable = GetIsExpandable(value);
110115
this.ValueString =
111116
this.IsExpandable == false ?
112117
GetValueString(value) :

src/PowerShellEditorServices/Session/PowerShellSession.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,12 +310,12 @@ public Task ExecuteCommand(PSCommand psCommand)
310310
/// </summary>
311311
/// <param name="scriptString">The script string to execute.</param>
312312
/// <returns>A Task that can be awaited for the script completion.</returns>
313-
public async Task ExecuteScriptString(string scriptString)
313+
public async Task<IEnumerable<object>> ExecuteScriptString(string scriptString)
314314
{
315315
PSCommand psCommand = new PSCommand();
316316
psCommand.AddScript(scriptString);
317317

318-
await this.ExecuteCommand<object>(psCommand, true);
318+
return await this.ExecuteCommand<object>(psCommand, true);
319319
}
320320

321321
/// <summary>
@@ -328,7 +328,7 @@ public async Task ExecuteScriptAtPath(string scriptPath)
328328
PSCommand command = new PSCommand();
329329
command.AddCommand(scriptPath);
330330

331-
await this.ExecuteCommand<object>(command);
331+
await this.ExecuteCommand<object>(command, true);
332332
}
333333

334334
/// <summary>

test/PowerShellEditorServices.Test.Host/ScenarioTests.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,20 +371,21 @@ await this.MessageWriter.WriteMessage(
371371
Assert.Equal(sigHelp.Body.ArgumentCount, 1);
372372
}
373373

374-
[Fact(Skip = "Console output events are disabled until we migrate to the updated debug protocol.")]
374+
[Fact]
375375
public async Task ServiceExecutesReplCommandAndReceivesOutput()
376376
{
377377
await this.MessageWriter.WriteMessage(
378-
new ReplExecuteRequest
378+
new EvaluateRequest
379379
{
380-
Arguments = new ReplExecuteArgs
380+
Arguments = new EvaluateRequestArguments
381381
{
382-
CommandString = "1 + 2"
382+
Expression = "1 + 2"
383383
}
384384
});
385385

386-
ReplWriteOutputEvent replWriteLineEvent = this.WaitForMessage<ReplWriteOutputEvent>();
387-
Assert.Equal("3", replWriteLineEvent.Body.LineContents);
386+
OutputEvent outputEvent = this.WaitForMessage<OutputEvent>();
387+
Assert.Equal("3\r\n", outputEvent.Body.Output);
388+
Assert.Equal("stdout", outputEvent.Body.Category);
388389
}
389390

390391
[Fact(Skip = "Choice prompt functionality is currently in transition to a new model.")]

test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,25 +177,25 @@ await this.debugService.SetBreakpoints(
177177

178178
// TODO: Add checks for correct value strings as well
179179

180-
var strVar = variables.FirstOrDefault(v => v.Name == "strVar");
180+
var strVar = variables.FirstOrDefault(v => v.Name == "$strVar");
181181
Assert.NotNull(strVar);
182182
Assert.False(strVar.IsExpandable);
183183

184-
var objVar = variables.FirstOrDefault(v => v.Name == "objVar");
184+
var objVar = variables.FirstOrDefault(v => v.Name == "$objVar");
185185
Assert.NotNull(objVar);
186186
Assert.True(objVar.IsExpandable);
187187

188188
var objChildren = debugService.GetVariables(objVar.Id);
189189
Assert.Equal(2, objChildren.Length);
190190

191-
var arrVar = variables.FirstOrDefault(v => v.Name == "arrVar");
191+
var arrVar = variables.FirstOrDefault(v => v.Name == "$arrVar");
192192
Assert.NotNull(arrVar);
193193
Assert.True(arrVar.IsExpandable);
194194

195195
var arrChildren = debugService.GetVariables(arrVar.Id);
196196
Assert.Equal(4, arrChildren.Length);
197197

198-
var classVar = variables.FirstOrDefault(v => v.Name == "classVar");
198+
var classVar = variables.FirstOrDefault(v => v.Name == "$classVar");
199199
Assert.NotNull(classVar);
200200
Assert.True(classVar.IsExpandable);
201201

0 commit comments

Comments
 (0)