diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs index 1718c3168..d978b67e5 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs @@ -23,11 +23,9 @@ internal class BreakpointService private readonly DebugStateService _debugStateService; // TODO: This needs to be managed per nested session - internal readonly Dictionary> BreakpointsPerFile = - new Dictionary>(); + internal readonly Dictionary> BreakpointsPerFile = new(); - internal readonly HashSet CommandBreakpoints = - new HashSet(); + internal readonly HashSet CommandBreakpoints = new(); public BreakpointService( ILoggerFactory factory, @@ -51,9 +49,11 @@ public async Task> GetBreakpointsAsync() } // Legacy behavior - PSCommand psCommand = new PSCommand() - .AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); - IEnumerable breakpoints = await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); + PSCommand psCommand = new PSCommand().AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); + IEnumerable breakpoints = await _executionService + .ExecutePSCommandAsync(psCommand, CancellationToken.None) + .ConfigureAwait(false); + return breakpoints.ToList(); } @@ -73,13 +73,12 @@ public async Task> SetBreakpointsAsync(string esc breakpointDetails.Verified = false; } } - return breakpoints; } // Legacy behavior PSCommand psCommand = null; - List configuredBreakpoints = new List(); + List configuredBreakpoints = new(); foreach (BreakpointDetails breakpoint in breakpoints) { ScriptBlock actionScriptBlock = null; @@ -106,7 +105,7 @@ public async Task> SetBreakpointsAsync(string esc // On first iteration psCommand will be null, every subsequent // iteration will need to start a new statement. - if (psCommand == null) + if (psCommand is null) { psCommand = new PSCommand(); } @@ -121,7 +120,7 @@ public async Task> SetBreakpointsAsync(string esc .AddParameter("Line", breakpoint.LineNumber); // Check if the user has specified the column number for the breakpoint. - if (breakpoint.ColumnNumber.HasValue && breakpoint.ColumnNumber.Value > 0) + if (breakpoint.ColumnNumber > 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 @@ -129,26 +128,24 @@ public async Task> SetBreakpointsAsync(string esc psCommand.AddParameter("Column", breakpoint.ColumnNumber.Value); } - if (actionScriptBlock != null) + if (actionScriptBlock is not null) { psCommand.AddParameter("Action", actionScriptBlock); } } // If no PSCommand was created then there are no breakpoints to set. - if (psCommand != null) + if (psCommand is not null) { - IEnumerable setBreakpoints = - await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); - configuredBreakpoints.AddRange( - setBreakpoints.Select((breakpoint) => BreakpointDetails.Create(breakpoint)) - ); + IEnumerable setBreakpoints = await _executionService + .ExecutePSCommandAsync(psCommand, CancellationToken.None) + .ConfigureAwait(false); + configuredBreakpoints.AddRange(setBreakpoints.Select((breakpoint) => BreakpointDetails.Create(breakpoint))); } - return configuredBreakpoints; } - public async Task> SetCommandBreakpoints(IEnumerable breakpoints) + public async Task> SetCommandBreakpointsAsync(IEnumerable breakpoints) { if (BreakpointApiUtils.SupportsBreakpointApis(_editorServicesHost.CurrentRunspace)) { @@ -156,26 +153,28 @@ public async Task> SetCommandBreakpoints(I { try { - BreakpointApiUtils.SetBreakpoint(_editorServicesHost.Runspace.Debugger, commandBreakpointDetails, _debugStateService.RunspaceId); + BreakpointApiUtils.SetBreakpoint( + _editorServicesHost.Runspace.Debugger, + commandBreakpointDetails, + _debugStateService.RunspaceId); } - catch(InvalidOperationException e) + catch (InvalidOperationException e) { commandBreakpointDetails.Message = e.Message; commandBreakpointDetails.Verified = false; } } - return breakpoints; } // Legacy behavior PSCommand psCommand = null; - List configuredBreakpoints = new List(); + List configuredBreakpoints = new(); foreach (CommandBreakpointDetails breakpoint in breakpoints) { // On first iteration psCommand will be null, every subsequent // iteration will need to start a new statement. - if (psCommand == null) + if (psCommand is null) { psCommand = new PSCommand(); } @@ -208,20 +207,18 @@ public async Task> SetCommandBreakpoints(I configuredBreakpoints.Add(breakpoint); continue; } - psCommand.AddParameter("Action", actionScriptBlock); } } // If no PSCommand was created then there are no breakpoints to set. - if (psCommand != null) + if (psCommand is not null) { - IEnumerable setBreakpoints = - await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); - configuredBreakpoints.AddRange( - setBreakpoints.Select(CommandBreakpointDetails.Create)); + IEnumerable setBreakpoints = await _executionService + .ExecutePSCommandAsync(psCommand, CancellationToken.None) + .ConfigureAwait(false); + configuredBreakpoints.AddRange(setBreakpoints.Select(CommandBreakpointDetails.Create)); } - return configuredBreakpoints; } @@ -238,7 +235,7 @@ public async Task RemoveAllBreakpointsAsync(string scriptPath = null) _editorServicesHost.Runspace.Debugger, _debugStateService.RunspaceId)) { - if (scriptPath == null || scriptPath == breakpoint.Script) + if (scriptPath is null || scriptPath == breakpoint.Script) { BreakpointApiUtils.RemoveBreakpoint( _editorServicesHost.Runspace.Debugger, @@ -246,14 +243,11 @@ public async Task RemoveAllBreakpointsAsync(string scriptPath = null) _debugStateService.RunspaceId); } } - return; } // Legacy behavior - - PSCommand psCommand = new PSCommand(); - psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); + var psCommand = new PSCommand().AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); if (!string.IsNullOrEmpty(scriptPath)) { @@ -261,7 +255,6 @@ public async Task RemoveAllBreakpointsAsync(string scriptPath = null) } psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint"); - await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); } catch (Exception e) @@ -281,37 +274,26 @@ public async Task RemoveBreakpointsAsync(IEnumerable breakpoints) breakpoint, _debugStateService.RunspaceId); - switch (breakpoint) + _ = breakpoint switch { - case CommandBreakpoint commandBreakpoint: - CommandBreakpoints.Remove(commandBreakpoint); - break; - case LineBreakpoint lineBreakpoint: - if (BreakpointsPerFile.TryGetValue(lineBreakpoint.Script, out HashSet bps)) - { - bps.Remove(lineBreakpoint); - } - break; - default: - throw new ArgumentException("Unsupported breakpoint type."); - } + CommandBreakpoint commandBreakpoint => CommandBreakpoints.Remove(commandBreakpoint), + LineBreakpoint lineBreakpoint => + BreakpointsPerFile.TryGetValue(lineBreakpoint.Script, out HashSet bps) && bps.Remove(lineBreakpoint), + _ => throw new NotImplementedException("Other breakpoints not supported yet"), + }; } - return; } // Legacy behavior - var breakpointIds = breakpoints.Select(b => b.Id).ToArray(); - if(breakpointIds.Length > 0) + var breakpointIds = breakpoints.Select(b => b.Id); + if (breakpointIds.Any()) { - PSCommand psCommand = new PSCommand(); - psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint"); - psCommand.AddParameter("Id", breakpoints.Select(b => b.Id).ToArray()); - + PSCommand psCommand = new PSCommand() + .AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint") + .AddParameter("Id", breakpoints.Select(b => b.Id).ToArray()); await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); } } - - } } diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs index 383ecf4fa..680f81be6 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs @@ -185,7 +185,7 @@ public async Task SetCommandBreakpointsAsync( if (breakpoints.Length > 0) { - resultBreakpointDetails = (await _breakpointService.SetCommandBreakpoints(breakpoints).ConfigureAwait(false)).ToArray(); + resultBreakpointDetails = (await _breakpointService.SetCommandBreakpointsAsync(breakpoints).ConfigureAwait(false)).ToArray(); } return resultBreakpointDetails ?? Array.Empty(); diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs index 82eacfe73..f05a96358 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs @@ -134,17 +134,24 @@ public static Breakpoint SetBreakpoint(Debugger debugger, BreakpointDetailsBase } } - switch (breakpoint) + return breakpoint switch { - case BreakpointDetails lineBreakpoint: - return SetLineBreakpointDelegate(debugger, lineBreakpoint.Source, lineBreakpoint.LineNumber, lineBreakpoint.ColumnNumber ?? 0, actionScriptBlock, runspaceId); - - case CommandBreakpointDetails commandBreakpoint: - return SetCommandBreakpointDelegate(debugger, commandBreakpoint.Name, null, null, runspaceId); - - default: - throw new NotImplementedException("Other breakpoints not supported yet"); - } + BreakpointDetails lineBreakpoint => SetLineBreakpointDelegate( + debugger, + lineBreakpoint.Source, + lineBreakpoint.LineNumber, + lineBreakpoint.ColumnNumber ?? 0, + actionScriptBlock, + runspaceId), + + CommandBreakpointDetails commandBreakpoint => SetCommandBreakpointDelegate(debugger, + commandBreakpoint.Name, + null, + null, + runspaceId), + + _ => throw new NotImplementedException("Other breakpoints not supported yet"), + }; } public static List GetBreakpoints(Debugger debugger, int? runspaceId = null) @@ -173,20 +180,20 @@ public static ScriptBlock GetBreakpointActionScriptBlock(string condition, strin try { - StringBuilder builder = new StringBuilder( + StringBuilder builder = new( string.IsNullOrEmpty(logMessage) ? "break" : $"Microsoft.PowerShell.Utility\\Write-Host \"{logMessage.Replace("\"","`\"")}\""); // If HitCondition specified, parse and verify it. - if (!(string.IsNullOrWhiteSpace(hitCondition))) + if (!string.IsNullOrWhiteSpace(hitCondition)) { if (!int.TryParse(hitCondition, out int parsedHitCount)) { throw new InvalidOperationException("Hit Count was not a valid integer."); } - if(string.IsNullOrWhiteSpace(condition)) + if (string.IsNullOrWhiteSpace(condition)) { // In the HitCount only case, this is simple as we can just use the HitCount // property on the breakpoint object which is represented by $_. @@ -217,8 +224,7 @@ public static ScriptBlock GetBreakpointActionScriptBlock(string condition, strin // Check for "advanced" condition syntax i.e. if the user has specified // a "break" or "continue" statement anywhere in their scriptblock, // pass their scriptblock through to the Action parameter as-is. - if (parsed.Ast.Find(ast => - (ast is BreakStatementAst || ast is ContinueStatementAst), true) != null) + if (parsed.Ast.Find(ast => ast is BreakStatementAst || ast is ContinueStatementAst, true) is not null) { return parsed; } @@ -247,10 +253,9 @@ private static bool ValidateBreakpointConditionAst(Ast conditionAst, out string // We are only inspecting a few simple scenarios in the EndBlock only. if (conditionAst is ScriptBlockAst scriptBlockAst && - scriptBlockAst.BeginBlock == null && - scriptBlockAst.ProcessBlock == null && - scriptBlockAst.EndBlock != null && - scriptBlockAst.EndBlock.Statements.Count == 1) + scriptBlockAst.BeginBlock is null && + scriptBlockAst.ProcessBlock is null && + scriptBlockAst.EndBlock?.Statements.Count == 1) { StatementAst statementAst = scriptBlockAst.EndBlock.Statements[0]; string condition = statementAst.Extent.Text; diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs index f1c4c7bbe..4147babb1 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs @@ -30,7 +30,7 @@ internal class BreakpointDetails : BreakpointDetailsBase public int LineNumber { get; private set; } /// - /// Gets the column number at which the breakpoint is set. If null, the default of 1 is used. + /// Gets the column number at which the breakpoint is set. /// public int? ColumnNumber { get; private set; } @@ -83,9 +83,9 @@ internal static BreakpointDetails Create( Breakpoint breakpoint, BreakpointUpdateType updateType = BreakpointUpdateType.Set) { - Validate.IsNotNull("breakpoint", breakpoint); + Validate.IsNotNull(nameof(breakpoint), breakpoint); - if (!(breakpoint is LineBreakpoint lineBreakpoint)) + if (breakpoint is not LineBreakpoint lineBreakpoint) { throw new ArgumentException( "Unexpected breakpoint type: " + breakpoint.GetType().Name);