public async Task DebuggerAcceptsScriptArgs(string[] args) { // The path is intentionally odd (some escaped chars but not all) because we are testing // the internal path escaping mechanism - it should escape certains chars ([, ] and space) but // it should not escape already escaped chars. ScriptFile debugWithParamsFile = this.workspace.GetFile( @"..\..\..\..\PowerShellEditorServices.Test.Shared\Debugging\Debug` With Params `[Test].ps1"); await this.debugService.SetLineBreakpoints( debugWithParamsFile, new[] { BreakpointDetails.Create("", 3) }); string arguments = string.Join(" ", args); // Execute the script and wait for the breakpoint to be hit Task executeTask = this.powerShellContext.ExecuteScriptWithArgs( debugWithParamsFile.FilePath, arguments); await this.AssertDebuggerStopped(debugWithParamsFile.FilePath); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); var var = variables.FirstOrDefault(v => v.Name == "$Param1"); Assert.NotNull(var); Assert.Equal("\"Foo\"", var.ValueString); Assert.False(var.IsExpandable); var = variables.FirstOrDefault(v => v.Name == "$Param2"); Assert.NotNull(var); Assert.True(var.IsExpandable); var childVars = debugService.GetVariables(var.Id); Assert.Equal(9, childVars.Length); Assert.Equal("\"Bar\"", childVars[0].ValueString); Assert.Equal("\"Baz\"", childVars[1].ValueString); var = variables.FirstOrDefault(v => v.Name == "$Force"); Assert.NotNull(var); Assert.Equal("True", var.ValueString); Assert.True(var.IsExpandable); var = variables.FirstOrDefault(v => v.Name == "$args"); Assert.NotNull(var); Assert.True(var.IsExpandable); childVars = debugService.GetVariables(var.Id); Assert.Equal(8, childVars.Length); Assert.Equal("\"Extra1\"", childVars[0].ValueString); // Abort execution of the script this.powerShellContext.AbortExecution(); }
protected async Task HandleSetBreakpointsRequest( SetBreakpointsRequestArguments setBreakpointsParams, RequestContext <SetBreakpointsResponseBody> requestContext) { ScriptFile scriptFile; // Fix for issue #195 - user can change name of file outside of VSCode in which case // VSCode sends breakpoint requests with the original filename that doesn't exist anymore. try { scriptFile = editorSession.Workspace.GetFile(setBreakpointsParams.Source.Path); } catch (FileNotFoundException) { Logger.Write( LogLevel.Warning, $"Attempted to set breakpoints on a non-existing file: {setBreakpointsParams.Source.Path}"); var srcBreakpoints = setBreakpointsParams.Breakpoints .Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create( srcBkpt, setBreakpointsParams.Source.Path, "Source does not exist, breakpoint not set.")); // Return non-verified breakpoint message. await requestContext.SendResult( new SetBreakpointsResponseBody { Breakpoints = srcBreakpoints.ToArray() }); return; } var breakpointDetails = new BreakpointDetails[setBreakpointsParams.Breakpoints.Length]; for (int i = 0; i < breakpointDetails.Length; i++) { SourceBreakpoint srcBreakpoint = setBreakpointsParams.Breakpoints[i]; breakpointDetails[i] = BreakpointDetails.Create( scriptFile.FilePath, srcBreakpoint.Line, srcBreakpoint.Column, srcBreakpoint.Condition); } BreakpointDetails[] breakpoints = await editorSession.DebugService.SetLineBreakpoints( scriptFile, breakpointDetails); await requestContext.SendResult( new SetBreakpointsResponseBody { Breakpoints = breakpoints .Select(Protocol.DebugAdapter.Breakpoint.Create) .ToArray() }); }
public async Task DebuggerGetsVariables() { await this.debugService.SetLineBreakpointsAsync( this.variableScriptFile, new[] { BreakpointDetails.Create(this.variableScriptFile.FilePath, 14) }).ConfigureAwait(false); // Execute the script and wait for the breakpoint to be hit Task executeTask = this.powerShellContext.ExecuteScriptStringAsync( this.variableScriptFile.FilePath); await this.AssertDebuggerStopped(this.variableScriptFile.FilePath).ConfigureAwait(false); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); // TODO: Add checks for correct value strings as well var strVar = variables.FirstOrDefault(v => v.Name == "$strVar"); Assert.NotNull(strVar); Assert.False(strVar.IsExpandable); var objVar = variables.FirstOrDefault(v => v.Name == "$assocArrVar"); Assert.NotNull(objVar); Assert.True(objVar.IsExpandable); var objChildren = debugService.GetVariables(objVar.Id); Assert.Equal(9, objChildren.Length); var arrVar = variables.FirstOrDefault(v => v.Name == "$arrVar"); Assert.NotNull(arrVar); Assert.True(arrVar.IsExpandable); var arrChildren = debugService.GetVariables(arrVar.Id); Assert.Equal(11, arrChildren.Length); var classVar = variables.FirstOrDefault(v => v.Name == "$classVar"); Assert.NotNull(classVar); Assert.True(classVar.IsExpandable); var classChildren = debugService.GetVariables(classVar.Id); Assert.Equal(2, classChildren.Length); // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask.ConfigureAwait(false); }
public async Task DebuggerStopsOnConditionalBreakpoints() { const int breakpointValue1 = 10; const int breakpointValue2 = 20; BreakpointDetails[] breakpoints = await this.debugService.SetLineBreakpoints( this.debugScriptFile, new[] { BreakpointDetails.Create("", 7, null, $"$i -eq {breakpointValue1} -or $i -eq {breakpointValue2}"), }); await this.AssertStateChange(PowerShellContextState.Ready); Task executeTask = this.powerShellContext.ExecuteScriptWithArgs( this.debugScriptFile.FilePath); // Wait for conditional breakpoint to hit await this.AssertDebuggerStopped(this.debugScriptFile.FilePath, 7); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); // Verify the breakpoint only broke at the condition ie. $i -eq breakpointValue1 var i = variables.FirstOrDefault(v => v.Name == "$i"); Assert.NotNull(i); Assert.False(i.IsExpandable); Assert.Equal($"{breakpointValue1}", i.ValueString); // The conditional breakpoint should not fire again, until the value of // i reaches breakpointValue2. this.debugService.Continue(); await this.AssertDebuggerStopped(this.debugScriptFile.FilePath, 7); stackFrames = debugService.GetStackFrames(); variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); // Verify the breakpoint only broke at the condition ie. $i -eq breakpointValue1 i = variables.FirstOrDefault(v => v.Name == "$i"); Assert.NotNull(i); Assert.False(i.IsExpandable); Assert.Equal($"{breakpointValue2}", i.ValueString); // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask; }
private async void DebugService_BreakpointUpdatedAsync(object sender, BreakpointUpdatedEventArgs e) { string reason = "changed"; if (_setBreakpointInProgress) { // Don't send breakpoint update notifications when setting // breakpoints on behalf of the client. return; } switch (e.UpdateType) { case BreakpointUpdateType.Set: reason = "new"; break; case BreakpointUpdateType.Removed: reason = "removed"; break; } Protocol.DebugAdapter.Breakpoint breakpoint; if (e.Breakpoint is LineBreakpoint) { breakpoint = Protocol.DebugAdapter.Breakpoint.Create(BreakpointDetails.Create(e.Breakpoint)); } else if (e.Breakpoint is CommandBreakpoint) { //breakpoint = Protocol.DebugAdapter.Breakpoint.Create(CommandBreakpointDetails.Create(e.Breakpoint)); Logger.Write(LogLevel.Verbose, "Function breakpoint updated event is not supported yet"); return; } else { Logger.Write(LogLevel.Error, $"Unrecognized breakpoint type {e.Breakpoint.GetType().FullName}"); return; } breakpoint.Verified = e.UpdateType != BreakpointUpdateType.Disabled; await _messageSender.SendEventAsync( BreakpointEvent.Type, new BreakpointEvent { Reason = reason, Breakpoint = breakpoint }); }
private void DebugService_BreakpointUpdated(object sender, BreakpointUpdatedEventArgs e) { string reason = "changed"; if (_debugStateService.IsSetBreakpointInProgress) { // Don't send breakpoint update notifications when setting // breakpoints on behalf of the client. return; } switch (e.UpdateType) { case BreakpointUpdateType.Set: reason = "new"; break; case BreakpointUpdateType.Removed: reason = "removed"; break; } var breakpoint = new OmniSharp.Extensions.DebugAdapter.Protocol.Models.Breakpoint { Verified = e.UpdateType != BreakpointUpdateType.Disabled }; if (e.Breakpoint is LineBreakpoint) { breakpoint = LspDebugUtils.CreateBreakpoint(BreakpointDetails.Create(e.Breakpoint)); } else if (e.Breakpoint is CommandBreakpoint) { _logger.LogTrace("Function breakpoint updated event is not supported yet"); return; } else { _logger.LogError($"Unrecognized breakpoint type {e.Breakpoint.GetType().FullName}"); return; } _debugAdapterServer.SendNotification(EventNames.Breakpoint, new BreakpointEvent { Reason = reason, Breakpoint = breakpoint }); }
public async Task DebuggerVariableHashtableDisplaysCorrectly() { await this.debugService.SetLineBreakpointsAsync( this.variableScriptFile, new[] { BreakpointDetails.Create(this.variableScriptFile.FilePath, 11) }).ConfigureAwait(false); // Execute the script and wait for the breakpoint to be hit Task executeTask = this.powerShellContext.ExecuteScriptStringAsync( this.variableScriptFile.FilePath); await this.AssertDebuggerStopped(this.variableScriptFile.FilePath).ConfigureAwait(false); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); VariableDetailsBase var = variables.FirstOrDefault(v => v.Name == "$assocArrVar"); Assert.NotNull(var); Assert.Equal("[Hashtable: 2]", var.ValueString); Assert.True(var.IsExpandable); VariableDetailsBase[] childVars = debugService.GetVariables(var.Id); Assert.Equal(9, childVars.Length); Assert.Equal("[0]", childVars[0].Name); Assert.Equal("[1]", childVars[1].Name); var childVarStrs = new HashSet <string>(childVars.Select(v => v.ValueString)); var expectedVars = new[] { "[firstChild, \"Child\"]", "[secondChild, 42]" }; foreach (string expectedVar in expectedVars) { Assert.Contains(expectedVar, childVarStrs); } // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask.ConfigureAwait(false); }
public async Task DebuggerFindsParseableButInvalidSimpleBreakpointConditions() { BreakpointDetails[] breakpoints = await this.debugService.SetLineBreakpoints( this.debugScriptFile, new[] { BreakpointDetails.Create("", 5, column: null, condition: "$i == 100"), BreakpointDetails.Create("", 7, column: null, condition: "$i > 100") }); Assert.Equal(2, breakpoints.Length); Assert.Equal(5, breakpoints[0].LineNumber); Assert.False(breakpoints[0].Verified); Assert.Contains("Use '-eq' instead of '=='", breakpoints[0].Message); Assert.Equal(7, breakpoints[1].LineNumber); Assert.False(breakpoints[1].Verified); Assert.NotNull(breakpoints[1].Message); Assert.Contains("Use '-gt' instead of '>'", breakpoints[1].Message); }
public async Task DebuggerProvidesMessageForInvalidConditionalBreakpoint() { BreakpointDetails[] breakpoints = await this.debugService.SetLineBreakpoints( this.debugScriptFile, new[] { BreakpointDetails.Create("", 5), BreakpointDetails.Create("", 10, column: null, condition: "$i -ez 100") }); Assert.Equal(2, breakpoints.Length); Assert.Equal(5, breakpoints[0].LineNumber); Assert.True(breakpoints[0].Verified); Assert.Null(breakpoints[0].Message); Assert.Equal(10, breakpoints[1].LineNumber); Assert.False(breakpoints[1].Verified); Assert.NotNull(breakpoints[1].Message); Assert.Contains("Unexpected token '-ez'", breakpoints[1].Message); }
private void OnBreakpointUpdated(object sender, BreakpointUpdatedEventArgs e) { // Don't send breakpoint update notifications when setting // breakpoints on behalf of the client. if (_debugStateService.IsSetBreakpointInProgress) { return; } if (e.Breakpoint is LineBreakpoint) { OmniSharp.Extensions.DebugAdapter.Protocol.Models.Breakpoint breakpoint = LspDebugUtils.CreateBreakpoint( BreakpointDetails.Create(e.Breakpoint, e.UpdateType) ); string reason = e.UpdateType switch { BreakpointUpdateType.Set => BreakpointEventReason.New, BreakpointUpdateType.Removed => BreakpointEventReason.Removed, BreakpointUpdateType.Enabled => BreakpointEventReason.Changed, BreakpointUpdateType.Disabled => BreakpointEventReason.Changed, _ => "InvalidBreakpointUpdateTypeEnum" }; _debugAdapterServer.SendNotification( EventNames.Breakpoint, new BreakpointEvent { Breakpoint = breakpoint, Reason = reason } ); } else if (e.Breakpoint is CommandBreakpoint) { _logger.LogTrace("Function breakpoint updated event is not supported yet"); } else { _logger.LogError($"Unrecognized breakpoint type {e.Breakpoint.GetType().FullName}"); } }
public async Task DebuggerSetsAndClearsLineBreakpoints() { BreakpointDetails[] breakpoints = await this.debugService.SetLineBreakpointsAsync( this.debugScriptFile, new[] { BreakpointDetails.Create(this.debugScriptFile.FilePath, 5), BreakpointDetails.Create(this.debugScriptFile.FilePath, 10) }).ConfigureAwait(false); var confirmedBreakpoints = await this.GetConfirmedBreakpoints(this.debugScriptFile).ConfigureAwait(false); Assert.Equal(2, confirmedBreakpoints.Count()); Assert.Equal(5, breakpoints[0].LineNumber); Assert.Equal(10, breakpoints[1].LineNumber); breakpoints = await this.debugService.SetLineBreakpointsAsync( this.debugScriptFile, new[] { BreakpointDetails.Create(this.debugScriptFile.FilePath, 2) }).ConfigureAwait(false); confirmedBreakpoints = await this.GetConfirmedBreakpoints(this.debugScriptFile).ConfigureAwait(false); Assert.Single(confirmedBreakpoints); Assert.Equal(2, breakpoints[0].LineNumber); await this.debugService.SetLineBreakpointsAsync( this.debugScriptFile, Array.Empty <BreakpointDetails>()).ConfigureAwait(false); var remainingBreakpoints = await this.GetConfirmedBreakpoints(this.debugScriptFile).ConfigureAwait(false); Assert.Empty(remainingBreakpoints); // Abort debugger this.debugService.Abort(); }
public async Task DebuggerVariablePSCustomObjectDisplaysCorrectly() { await this.debugService.SetLineBreakpointsAsync( this.variableScriptFile, new[] { BreakpointDetails.Create(this.variableScriptFile.FilePath, 18) }).ConfigureAwait(false); // Execute the script and wait for the breakpoint to be hit Task executeTask = this.powerShellContext.ExecuteScriptStringAsync( this.variableScriptFile.FilePath); await this.AssertDebuggerStopped(this.variableScriptFile.FilePath).ConfigureAwait(false); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); var var = variables.FirstOrDefault(v => v.Name == "$psCustomObjVar"); Assert.NotNull(var); Assert.Equal("@{Name=Paul; Age=73}", var.ValueString); Assert.True(var.IsExpandable); var childVars = debugService.GetVariables(var.Id); Assert.Equal(2, childVars.Length); Assert.Equal("Name", childVars[0].Name); Assert.Equal("\"Paul\"", childVars[0].ValueString); Assert.Equal("Age", childVars[1].Name); Assert.Equal("73", childVars[1].ValueString); // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask.ConfigureAwait(false); }
public async Task DebuggerVariablePSObjectDisplaysCorrectly() { await this.debugService.SetLineBreakpointsAsync( this.variableScriptFile, new[] { BreakpointDetails.Create(this.variableScriptFile.FilePath, 17) }).ConfigureAwait(false); // Execute the script and wait for the breakpoint to be hit Task executeTask = this.powerShellContext.ExecuteScriptStringAsync( this.variableScriptFile.FilePath); await this.AssertDebuggerStopped(this.variableScriptFile.FilePath).ConfigureAwait(false); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); var psObjVar = variables.FirstOrDefault(v => v.Name == "$psObjVar"); Assert.NotNull(psObjVar); Assert.True("@{Age=75; Name=John}".Equals(psObjVar.ValueString) || "@{Name=John; Age=75}".Equals(psObjVar.ValueString)); Assert.True(psObjVar.IsExpandable); IDictionary <string, string> childVars = debugService.GetVariables(psObjVar.Id).ToDictionary(v => v.Name, v => v.ValueString); Assert.Equal(2, childVars.Count); Assert.Contains("Age", childVars.Keys); Assert.Contains("Name", childVars.Keys); Assert.Equal("75", childVars["Age"]); Assert.Equal("\"John\"", childVars["Name"]); // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask.ConfigureAwait(false); }
public async Task DebuggerStopsOnLineBreakpoints() { await this.debugService.SetLineBreakpointsAsync( this.debugScriptFile, new[] { BreakpointDetails.Create(this.debugScriptFile.FilePath, 5), BreakpointDetails.Create(this.debugScriptFile.FilePath, 7) }).ConfigureAwait(false); Task executeTask = this.powerShellContext.ExecuteScriptWithArgsAsync( this.debugScriptFile.FilePath); // Wait for a couple breakpoints await this.AssertDebuggerStopped(this.debugScriptFile.FilePath, 5).ConfigureAwait(false); this.debugService.Continue(); await this.AssertDebuggerStopped(this.debugScriptFile.FilePath, 7).ConfigureAwait(false); // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask.ConfigureAwait(false); }
public async Task DebuggerStopsOnConditionalAndHitConditionBreakpoint() { const int hitCount = 5; BreakpointDetails[] breakpoints = await this.debugService.SetLineBreakpoints( this.debugScriptFile, new[] { BreakpointDetails.Create("", 6, null, $"$i % 2 -eq 0", $"{hitCount}"), }); await this.AssertStateChange(PowerShellContextState.Ready); Task executeTask = this.powerShellContext.ExecuteScriptWithArgs( this.debugScriptFile.FilePath); // Wait for conditional breakpoint to hit await this.AssertDebuggerStopped(this.debugScriptFile.FilePath, 6); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); // Verify the breakpoint only broke at the condition ie. $i -eq breakpointValue1 var i = variables.FirstOrDefault(v => v.Name == "$i"); Assert.NotNull(i); Assert.False(i.IsExpandable); // Condition is even numbers ($i starting at 1) should end up on 10 with a hit count of 5. Assert.Equal("10", i.ValueString); // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask; }
public async Task DebuggerSetsAndClearsLineBreakpoints() { BreakpointDetails[] breakpoints = await this.debugService.SetLineBreakpoints( this.debugScriptFile, new[] { BreakpointDetails.Create("", 5), BreakpointDetails.Create("", 10) }); var confirmedBreakpoints = await this.GetConfirmedBreakpoints(this.debugScriptFile); Assert.Equal(2, confirmedBreakpoints.Count()); Assert.Equal(5, breakpoints[0].LineNumber); Assert.Equal(10, breakpoints[1].LineNumber); breakpoints = await this.debugService.SetLineBreakpoints( this.debugScriptFile, new[] { BreakpointDetails.Create("", 2) }); confirmedBreakpoints = await this.GetConfirmedBreakpoints(this.debugScriptFile); Assert.Equal(1, confirmedBreakpoints.Count()); Assert.Equal(2, breakpoints[0].LineNumber); await this.debugService.SetLineBreakpoints( this.debugScriptFile, new[] { BreakpointDetails.Create("", 0) }); var remainingBreakpoints = await this.GetConfirmedBreakpoints(this.debugScriptFile); Assert.False( remainingBreakpoints.Any(), "Breakpoints in the script file were not cleared"); }
protected async Task HandleSetBreakpointsRequest( SetBreakpointsRequestArguments setBreakpointsParams, RequestContext <SetBreakpointsResponseBody> requestContext) { ScriptFile scriptFile = null; // Fix for issue #195 - user can change name of file outside of VSCode in which case // VSCode sends breakpoint requests with the original filename that doesn't exist anymore. try { // When you set a breakpoint in the right pane of a Git diff window on a PS1 file, // the Source.Path comes through as Untitled-X. if (!ScriptFile.IsUntitledPath(setBreakpointsParams.Source.Path)) { scriptFile = editorSession.Workspace.GetFile(setBreakpointsParams.Source.Path); } } catch (Exception e) when( e is FileNotFoundException || e is DirectoryNotFoundException || e is IOException || e is NotSupportedException || e is PathTooLongException || e is SecurityException || e is UnauthorizedAccessException) { Logger.WriteException( $"Failed to set breakpoint on file: {setBreakpointsParams.Source.Path}", e); string message = this.noDebug ? string.Empty : "Source file could not be accessed, breakpoint not set - " + e.Message; var srcBreakpoints = setBreakpointsParams.Breakpoints .Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create( srcBkpt, setBreakpointsParams.Source.Path, message, verified: this.noDebug)); // Return non-verified breakpoint message. await requestContext.SendResult( new SetBreakpointsResponseBody { Breakpoints = srcBreakpoints.ToArray() }); return; } // Verify source file is a PowerShell script file. string fileExtension = Path.GetExtension(scriptFile?.FilePath ?? "")?.ToLower(); if (string.IsNullOrEmpty(fileExtension) || ((fileExtension != ".ps1") && (fileExtension != ".psm1"))) { Logger.Write( LogLevel.Warning, $"Attempted to set breakpoints on a non-PowerShell file: {setBreakpointsParams.Source.Path}"); string message = this.noDebug ? string.Empty : "Source is not a PowerShell script, breakpoint not set."; var srcBreakpoints = setBreakpointsParams.Breakpoints .Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create( srcBkpt, setBreakpointsParams.Source.Path, message, verified: this.noDebug)); // Return non-verified breakpoint message. await requestContext.SendResult( new SetBreakpointsResponseBody { Breakpoints = srcBreakpoints.ToArray() }); return; } // At this point, the source file has been verified as a PowerShell script. var breakpointDetails = new BreakpointDetails[setBreakpointsParams.Breakpoints.Length]; for (int i = 0; i < breakpointDetails.Length; i++) { SourceBreakpoint srcBreakpoint = setBreakpointsParams.Breakpoints[i]; breakpointDetails[i] = BreakpointDetails.Create( scriptFile.FilePath, srcBreakpoint.Line, srcBreakpoint.Column, srcBreakpoint.Condition, srcBreakpoint.HitCondition); } // If this is a "run without debugging (Ctrl+F5)" session ignore requests to set breakpoints. BreakpointDetails[] updatedBreakpointDetails = breakpointDetails; if (!this.noDebug) { this.setBreakpointInProgress = true; try { updatedBreakpointDetails = await editorSession.DebugService.SetLineBreakpoints( scriptFile, breakpointDetails); } catch (Exception e) { // Log whatever the error is Logger.WriteException($"Caught error while setting breakpoints in SetBreakpoints handler for file {scriptFile?.FilePath}", e); } finally { this.setBreakpointInProgress = false; } } await requestContext.SendResult( new SetBreakpointsResponseBody { Breakpoints = updatedBreakpointDetails .Select(Protocol.DebugAdapter.Breakpoint.Create) .ToArray() }); }
public async Task DebuggerSetsVariablesWithConversion() { await this.debugService.SetLineBreakpointsAsync( this.variableScriptFile, new[] { BreakpointDetails.Create(this.variableScriptFile.FilePath, 14) }).ConfigureAwait(false); // Execute the script and wait for the breakpoint to be hit Task executeTask = this.powerShellContext.ExecuteScriptStringAsync( this.variableScriptFile.FilePath); await this.AssertDebuggerStopped(this.variableScriptFile.FilePath).ConfigureAwait(false); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); // Test set of a local string variable (not strongly typed but force conversion) string newStrValue = "\"False\""; string newStrExpr = "$false"; string setStrValue = await debugService.SetVariableAsync(stackFrames[0].LocalVariables.Id, "$strVar2", newStrExpr).ConfigureAwait(false); Assert.Equal(newStrValue, setStrValue); VariableScope[] scopes = this.debugService.GetVariableScopes(0); // Test set of script scope bool variable (strongly typed) VariableScope scriptScope = scopes.FirstOrDefault(s => s.Name == VariableContainerDetails.ScriptScopeName); string newBoolValue = "$true"; string newBoolExpr = "1"; string setBoolValue = await debugService.SetVariableAsync(scriptScope.Id, "$scriptBool", newBoolExpr).ConfigureAwait(false); Assert.Equal(newBoolValue, setBoolValue); // Test set of global scope ActionPreference variable (strongly typed) VariableScope globalScope = scopes.FirstOrDefault(s => s.Name == VariableContainerDetails.GlobalScopeName); string newGlobalValue = "Continue"; string newGlobalExpr = "'Continue'"; string setGlobalValue = await debugService.SetVariableAsync(globalScope.Id, "$VerbosePreference", newGlobalExpr).ConfigureAwait(false); Assert.Equal(newGlobalValue, setGlobalValue); // The above just tests that the debug service returns the correct new value string. // Let's step the debugger and make sure the values got set to the new values. this.debugService.StepOver(); await this.AssertDebuggerStopped(this.variableScriptFile.FilePath).ConfigureAwait(false); stackFrames = debugService.GetStackFrames(); // Test set of a local string variable (not strongly typed but force conversion) variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); var strVar = variables.FirstOrDefault(v => v.Name == "$strVar2"); Assert.Equal(newStrValue, strVar.ValueString); scopes = this.debugService.GetVariableScopes(0); // Test set of script scope bool variable (strongly typed) scriptScope = scopes.FirstOrDefault(s => s.Name == VariableContainerDetails.ScriptScopeName); variables = debugService.GetVariables(scriptScope.Id); var boolVar = variables.FirstOrDefault(v => v.Name == "$scriptBool"); Assert.Equal(newBoolValue, boolVar.ValueString); // Test set of global scope ActionPreference variable (strongly typed) globalScope = scopes.FirstOrDefault(s => s.Name == VariableContainerDetails.GlobalScopeName); variables = debugService.GetVariables(globalScope.Id); var globalVar = variables.FirstOrDefault(v => v.Name == "$VerbosePreference"); Assert.Equal(newGlobalValue, globalVar.ValueString); // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask.ConfigureAwait(false); }
public async Task DebuggerSetsVariablesNoConversion() { await this.debugService.SetLineBreakpointsAsync( this.variableScriptFile, new[] { BreakpointDetails.Create(this.variableScriptFile.FilePath, 14) }).ConfigureAwait(false); // Execute the script and wait for the breakpoint to be hit Task executeTask = this.powerShellContext.ExecuteScriptStringAsync( this.variableScriptFile.FilePath); await this.AssertDebuggerStopped(this.variableScriptFile.FilePath).ConfigureAwait(false); StackFrameDetails[] stackFrames = debugService.GetStackFrames(); VariableDetailsBase[] variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); // Test set of a local string variable (not strongly typed) string newStrValue = "\"Goodbye\""; string setStrValue = await debugService.SetVariableAsync(stackFrames[0].LocalVariables.Id, "$strVar", newStrValue).ConfigureAwait(false); Assert.Equal(newStrValue, setStrValue); VariableScope[] scopes = this.debugService.GetVariableScopes(0); // Test set of script scope int variable (not strongly typed) VariableScope scriptScope = scopes.FirstOrDefault(s => s.Name == VariableContainerDetails.ScriptScopeName); string newIntValue = "49"; string newIntExpr = "7 * 7"; string setIntValue = await debugService.SetVariableAsync(scriptScope.Id, "$scriptInt", newIntExpr).ConfigureAwait(false); Assert.Equal(newIntValue, setIntValue); // Test set of global scope int variable (not strongly typed) VariableScope globalScope = scopes.FirstOrDefault(s => s.Name == VariableContainerDetails.GlobalScopeName); string newGlobalIntValue = "4242"; string setGlobalIntValue = await debugService.SetVariableAsync(globalScope.Id, "$MaximumHistoryCount", newGlobalIntValue).ConfigureAwait(false); Assert.Equal(newGlobalIntValue, setGlobalIntValue); // The above just tests that the debug service returns the correct new value string. // Let's step the debugger and make sure the values got set to the new values. this.debugService.StepOver(); await this.AssertDebuggerStopped(this.variableScriptFile.FilePath).ConfigureAwait(false); stackFrames = debugService.GetStackFrames(); // Test set of a local string variable (not strongly typed) variables = debugService.GetVariables(stackFrames[0].LocalVariables.Id); var strVar = variables.FirstOrDefault(v => v.Name == "$strVar"); Assert.Equal(newStrValue, strVar.ValueString); scopes = this.debugService.GetVariableScopes(0); // Test set of script scope int variable (not strongly typed) scriptScope = scopes.FirstOrDefault(s => s.Name == VariableContainerDetails.ScriptScopeName); variables = debugService.GetVariables(scriptScope.Id); var intVar = variables.FirstOrDefault(v => v.Name == "$scriptInt"); Assert.Equal(newIntValue, intVar.ValueString); // Test set of global scope int variable (not strongly typed) globalScope = scopes.FirstOrDefault(s => s.Name == VariableContainerDetails.GlobalScopeName); variables = debugService.GetVariables(globalScope.Id); var intGlobalVar = variables.FirstOrDefault(v => v.Name == "$MaximumHistoryCount"); Assert.Equal(newGlobalIntValue, intGlobalVar.ValueString); // Abort script execution early and wait for completion this.debugService.Abort(); await executeTask.ConfigureAwait(false); }
public async Task <SetBreakpointsResponse> Handle(SetBreakpointsArguments request, CancellationToken cancellationToken) { if (!_workspaceService.TryGetFile(request.Source.Path, out ScriptFile scriptFile)) { string message = _debugStateService.NoDebug ? string.Empty : "Source file could not be accessed, breakpoint not set."; var srcBreakpoints = request.Breakpoints .Select(srcBkpt => LspDebugUtils.CreateBreakpoint( srcBkpt, request.Source.Path, message, verified: _debugStateService.NoDebug)); // Return non-verified breakpoint message. return(new SetBreakpointsResponse { Breakpoints = new Container <Breakpoint>(srcBreakpoints) }); } // Verify source file is a PowerShell script file. string fileExtension = Path.GetExtension(scriptFile?.FilePath ?? "")?.ToLower(); bool isUntitledPath = ScriptFile.IsUntitledPath(request.Source.Path); if ((!isUntitledPath && fileExtension != ".ps1" && fileExtension != ".psm1") || (!BreakpointApiUtils.SupportsBreakpointApis && isUntitledPath)) { _logger.LogWarning( $"Attempted to set breakpoints on a non-PowerShell file: {request.Source.Path}"); string message = _debugStateService.NoDebug ? string.Empty : "Source is not a PowerShell script, breakpoint not set."; var srcBreakpoints = request.Breakpoints .Select(srcBkpt => LspDebugUtils.CreateBreakpoint( srcBkpt, request.Source.Path, message, verified: _debugStateService.NoDebug)); // Return non-verified breakpoint message. return(new SetBreakpointsResponse { Breakpoints = new Container <Breakpoint>(srcBreakpoints) }); } // At this point, the source file has been verified as a PowerShell script. BreakpointDetails[] breakpointDetails = request.Breakpoints .Select((srcBreakpoint) => BreakpointDetails.Create( scriptFile.FilePath, srcBreakpoint.Line, srcBreakpoint.Column, srcBreakpoint.Condition, srcBreakpoint.HitCondition, srcBreakpoint.LogMessage)) .ToArray(); // If this is a "run without debugging (Ctrl+F5)" session ignore requests to set breakpoints. BreakpointDetails[] updatedBreakpointDetails = breakpointDetails; if (!_debugStateService.NoDebug) { await _debugStateService.WaitForSetBreakpointHandleAsync().ConfigureAwait(false); try { updatedBreakpointDetails = await _debugService.SetLineBreakpointsAsync( scriptFile, breakpointDetails).ConfigureAwait(false); } catch (Exception e) { // Log whatever the error is _logger.LogException($"Caught error while setting breakpoints in SetBreakpoints handler for file {scriptFile?.FilePath}", e); } finally { _debugStateService.ReleaseSetBreakpointHandle(); } } return(new SetBreakpointsResponse { Breakpoints = new Container <Breakpoint>(updatedBreakpointDetails .Select(LspDebugUtils.CreateBreakpoint)) }); }
public async Task <SetBreakpointsResponse> Handle(SetBreakpointsArguments request, CancellationToken cancellationToken) { ScriptFile scriptFile = null; // When you set a breakpoint in the right pane of a Git diff window on a PS1 file, // the Source.Path comes through as Untitled-X. That's why we check for IsUntitledPath. if (!ScriptFile.IsUntitledPath(request.Source.Path) && !_workspaceService.TryGetFile( request.Source.Path, out scriptFile)) { string message = _debugStateService.NoDebug ? string.Empty : "Source file could not be accessed, breakpoint not set."; var srcBreakpoints = request.Breakpoints .Select(srcBkpt => LspDebugUtils.CreateBreakpoint( srcBkpt, request.Source.Path, message, verified: _debugStateService.NoDebug)); // Return non-verified breakpoint message. return(new SetBreakpointsResponse { Breakpoints = new Container <Breakpoint>(srcBreakpoints) }); } // Verify source file is a PowerShell script file. string fileExtension = Path.GetExtension(scriptFile?.FilePath ?? "")?.ToLower(); if (string.IsNullOrEmpty(fileExtension) || ((fileExtension != ".ps1") && (fileExtension != ".psm1"))) { _logger.LogWarning( $"Attempted to set breakpoints on a non-PowerShell file: {request.Source.Path}"); string message = _debugStateService.NoDebug ? string.Empty : "Source is not a PowerShell script, breakpoint not set."; var srcBreakpoints = request.Breakpoints .Select(srcBkpt => LspDebugUtils.CreateBreakpoint( srcBkpt, request.Source.Path, message, verified: _debugStateService.NoDebug)); // Return non-verified breakpoint message. return(new SetBreakpointsResponse { Breakpoints = new Container <Breakpoint>(srcBreakpoints) }); } // At this point, the source file has been verified as a PowerShell script. BreakpointDetails[] breakpointDetails = request.Breakpoints .Select((srcBreakpoint) => BreakpointDetails.Create( scriptFile.FilePath, (int)srcBreakpoint.Line, (int?)srcBreakpoint.Column, srcBreakpoint.Condition, srcBreakpoint.HitCondition)) .ToArray(); // If this is a "run without debugging (Ctrl+F5)" session ignore requests to set breakpoints. BreakpointDetails[] updatedBreakpointDetails = breakpointDetails; if (!_debugStateService.NoDebug) { _debugStateService.SetBreakpointInProgress = true; try { updatedBreakpointDetails = await _debugService.SetLineBreakpointsAsync( scriptFile, breakpointDetails); } catch (Exception e) { // Log whatever the error is _logger.LogException($"Caught error while setting breakpoints in SetBreakpoints handler for file {scriptFile?.FilePath}", e); } finally { _debugStateService.SetBreakpointInProgress = false; } } return(new SetBreakpointsResponse { Breakpoints = new Container <Breakpoint>(updatedBreakpointDetails .Select(LspDebugUtils.CreateBreakpoint)) }); }
protected async Task HandleSetBreakpointsRequest( SetBreakpointsRequestArguments setBreakpointsParams, RequestContext <SetBreakpointsResponseBody> requestContext) { ScriptFile scriptFile = null; // Fix for issue #195 - user can change name of file outside of VSCode in which case // VSCode sends breakpoint requests with the original filename that doesn't exist anymore. try { scriptFile = editorSession.Workspace.GetFile(setBreakpointsParams.Source.Path); } catch (Exception e) when(e is FileNotFoundException || e is DirectoryNotFoundException) { Logger.Write( LogLevel.Warning, $"Attempted to set breakpoints on a non-existing file: {setBreakpointsParams.Source.Path}"); string message = this.noDebug ? string.Empty : "Source does not exist, breakpoint not set."; var srcBreakpoints = setBreakpointsParams.Breakpoints .Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create( srcBkpt, setBreakpointsParams.Source.Path, message, verified: this.noDebug)); // Return non-verified breakpoint message. await requestContext.SendResult( new SetBreakpointsResponseBody { Breakpoints = srcBreakpoints.ToArray() }); return; } var breakpointDetails = new BreakpointDetails[setBreakpointsParams.Breakpoints.Length]; for (int i = 0; i < breakpointDetails.Length; i++) { SourceBreakpoint srcBreakpoint = setBreakpointsParams.Breakpoints[i]; breakpointDetails[i] = BreakpointDetails.Create( scriptFile.FilePath, srcBreakpoint.Line, srcBreakpoint.Column, srcBreakpoint.Condition, srcBreakpoint.HitCondition); } // If this is a "run without debugging (Ctrl+F5)" session ignore requests to set breakpoints. BreakpointDetails[] updatedBreakpointDetails = breakpointDetails; if (!this.noDebug) { this.setBreakpointInProgress = true; try { updatedBreakpointDetails = await editorSession.DebugService.SetLineBreakpoints( scriptFile, breakpointDetails); } catch (Exception e) { // Log whatever the error is Logger.WriteException("Caught error while setting breakpoints in SetBreakpoints handler", e); } finally { this.setBreakpointInProgress = false; } } await requestContext.SendResult( new SetBreakpointsResponseBody { Breakpoints = updatedBreakpointDetails .Select(Protocol.DebugAdapter.Breakpoint.Create) .ToArray() }); }
protected async Task HandleSetBreakpointsRequestAsync( SetBreakpointsRequestArguments setBreakpointsParams, RequestContext <SetBreakpointsResponseBody> requestContext) { ScriptFile scriptFile = null; // When you set a breakpoint in the right pane of a Git diff window on a PS1 file, // the Source.Path comes through as Untitled-X. That's why we check for IsUntitledPath. if (!ScriptFile.IsUntitledPath(setBreakpointsParams.Source.Path) && !_editorSession.Workspace.TryGetFile( setBreakpointsParams.Source.Path, out scriptFile)) { string message = _noDebug ? string.Empty : "Source file could not be accessed, breakpoint not set."; var srcBreakpoints = setBreakpointsParams.Breakpoints .Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create( srcBkpt, setBreakpointsParams.Source.Path, message, verified: _noDebug)); // Return non-verified breakpoint message. await requestContext.SendResultAsync( new SetBreakpointsResponseBody { Breakpoints = srcBreakpoints.ToArray() }); return; } // Verify source file is a PowerShell script file. string fileExtension = Path.GetExtension(scriptFile?.FilePath ?? "")?.ToLower(); if (string.IsNullOrEmpty(fileExtension) || ((fileExtension != ".ps1") && (fileExtension != ".psm1"))) { Logger.Write( LogLevel.Warning, $"Attempted to set breakpoints on a non-PowerShell file: {setBreakpointsParams.Source.Path}"); string message = _noDebug ? string.Empty : "Source is not a PowerShell script, breakpoint not set."; var srcBreakpoints = setBreakpointsParams.Breakpoints .Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create( srcBkpt, setBreakpointsParams.Source.Path, message, verified: _noDebug)); // Return non-verified breakpoint message. await requestContext.SendResultAsync( new SetBreakpointsResponseBody { Breakpoints = srcBreakpoints.ToArray() }); return; } // At this point, the source file has been verified as a PowerShell script. var breakpointDetails = new BreakpointDetails[setBreakpointsParams.Breakpoints.Length]; for (int i = 0; i < breakpointDetails.Length; i++) { SourceBreakpoint srcBreakpoint = setBreakpointsParams.Breakpoints[i]; breakpointDetails[i] = BreakpointDetails.Create( scriptFile.FilePath, srcBreakpoint.Line, srcBreakpoint.Column, srcBreakpoint.Condition, srcBreakpoint.HitCondition); } // If this is a "run without debugging (Ctrl+F5)" session ignore requests to set breakpoints. BreakpointDetails[] updatedBreakpointDetails = breakpointDetails; if (!_noDebug) { _setBreakpointInProgress = true; try { updatedBreakpointDetails = await _editorSession.DebugService.SetLineBreakpointsAsync( scriptFile, breakpointDetails); } catch (Exception e) { // Log whatever the error is Logger.WriteException($"Caught error while setting breakpoints in SetBreakpoints handler for file {scriptFile?.FilePath}", e); } finally { _setBreakpointInProgress = false; } } await requestContext.SendResultAsync( new SetBreakpointsResponseBody { Breakpoints = updatedBreakpointDetails .Select(Protocol.DebugAdapter.Breakpoint.Create) .ToArray() }); }
public async Task <IEnumerable <BreakpointDetails> > SetBreakpointsAsync(string escapedScriptPath, IEnumerable <BreakpointDetails> breakpoints) { if (BreakpointApiUtils.SupportsBreakpointApis) { foreach (BreakpointDetails breakpointDetails in breakpoints) { try { BreakpointApiUtils.SetBreakpoint(_powerShellContextService.CurrentRunspace.Runspace.Debugger, breakpointDetails, _debugStateService.RunspaceId); } catch (InvalidOperationException e) { breakpointDetails.Message = e.Message; breakpointDetails.Verified = false; } } return(breakpoints); } // Legacy behavior PSCommand psCommand = null; List <BreakpointDetails> configuredBreakpoints = new List <BreakpointDetails>(); foreach (BreakpointDetails breakpoint in breakpoints) { ScriptBlock actionScriptBlock = null; // Check if this is a "conditional" line breakpoint. if (!string.IsNullOrWhiteSpace(breakpoint.Condition) || !string.IsNullOrWhiteSpace(breakpoint.HitCondition) || !string.IsNullOrWhiteSpace(breakpoint.LogMessage)) { actionScriptBlock = BreakpointApiUtils.GetBreakpointActionScriptBlock( breakpoint.Condition, breakpoint.HitCondition, breakpoint.LogMessage, out string errorMessage); if (!string.IsNullOrEmpty(errorMessage)) { breakpoint.Verified = false; breakpoint.Message = errorMessage; configuredBreakpoints.Add(breakpoint); continue; } } // On first iteration psCommand will be null, every subsequent // iteration will need to start a new statement. if (psCommand == null) { psCommand = new PSCommand(); } else { psCommand.AddStatement(); } psCommand .AddCommand(@"Microsoft.PowerShell.Utility\Set-PSBreakpoint") .AddParameter("Script", escapedScriptPath) .AddParameter("Line", breakpoint.LineNumber); // Check if the user has specified the column number for the breakpoint. if (breakpoint.ColumnNumber.HasValue && breakpoint.ColumnNumber.Value > 0) { // It bums me out that PowerShell will silently ignore a breakpoint // where either the line or the column is invalid. I'd rather have an // error or warning message I could relay back to the client. psCommand.AddParameter("Column", breakpoint.ColumnNumber.Value); } if (actionScriptBlock != null) { psCommand.AddParameter("Action", actionScriptBlock); } } // If no PSCommand was created then there are no breakpoints to set. if (psCommand != null) { IEnumerable <Breakpoint> setBreakpoints = await _powerShellContextService.ExecuteCommandAsync <Breakpoint>(psCommand).ConfigureAwait(false); configuredBreakpoints.AddRange( setBreakpoints.Select((breakpoint) => BreakpointDetails.Create(breakpoint)) ); } return(configuredBreakpoints); }