Skip to content

Commit d9e6fb5

Browse files
Clean up breakpoint files (#1701)
1 parent 837432b commit d9e6fb5

File tree

4 files changed

+70
-83
lines changed

4 files changed

+70
-83
lines changed

src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs

+42-60
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@ internal class BreakpointService
2323
private readonly DebugStateService _debugStateService;
2424

2525
// TODO: This needs to be managed per nested session
26-
internal readonly Dictionary<string, HashSet<Breakpoint>> BreakpointsPerFile =
27-
new Dictionary<string, HashSet<Breakpoint>>();
26+
internal readonly Dictionary<string, HashSet<Breakpoint>> BreakpointsPerFile = new();
2827

29-
internal readonly HashSet<Breakpoint> CommandBreakpoints =
30-
new HashSet<Breakpoint>();
28+
internal readonly HashSet<Breakpoint> CommandBreakpoints = new();
3129

3230
public BreakpointService(
3331
ILoggerFactory factory,
@@ -51,9 +49,11 @@ public async Task<List<Breakpoint>> GetBreakpointsAsync()
5149
}
5250

5351
// Legacy behavior
54-
PSCommand psCommand = new PSCommand()
55-
.AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint");
56-
IEnumerable<Breakpoint> breakpoints = await _executionService.ExecutePSCommandAsync<Breakpoint>(psCommand, CancellationToken.None).ConfigureAwait(false);
52+
PSCommand psCommand = new PSCommand().AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint");
53+
IEnumerable<Breakpoint> breakpoints = await _executionService
54+
.ExecutePSCommandAsync<Breakpoint>(psCommand, CancellationToken.None)
55+
.ConfigureAwait(false);
56+
5757
return breakpoints.ToList();
5858
}
5959

@@ -73,13 +73,12 @@ public async Task<IEnumerable<BreakpointDetails>> SetBreakpointsAsync(string esc
7373
breakpointDetails.Verified = false;
7474
}
7575
}
76-
7776
return breakpoints;
7877
}
7978

8079
// Legacy behavior
8180
PSCommand psCommand = null;
82-
List<BreakpointDetails> configuredBreakpoints = new List<BreakpointDetails>();
81+
List<BreakpointDetails> configuredBreakpoints = new();
8382
foreach (BreakpointDetails breakpoint in breakpoints)
8483
{
8584
ScriptBlock actionScriptBlock = null;
@@ -106,7 +105,7 @@ public async Task<IEnumerable<BreakpointDetails>> SetBreakpointsAsync(string esc
106105

107106
// On first iteration psCommand will be null, every subsequent
108107
// iteration will need to start a new statement.
109-
if (psCommand == null)
108+
if (psCommand is null)
110109
{
111110
psCommand = new PSCommand();
112111
}
@@ -121,61 +120,61 @@ public async Task<IEnumerable<BreakpointDetails>> SetBreakpointsAsync(string esc
121120
.AddParameter("Line", breakpoint.LineNumber);
122121

123122
// Check if the user has specified the column number for the breakpoint.
124-
if (breakpoint.ColumnNumber.HasValue && breakpoint.ColumnNumber.Value > 0)
123+
if (breakpoint.ColumnNumber > 0)
125124
{
126125
// It bums me out that PowerShell will silently ignore a breakpoint
127126
// where either the line or the column is invalid. I'd rather have an
128127
// error or warning message I could relay back to the client.
129128
psCommand.AddParameter("Column", breakpoint.ColumnNumber.Value);
130129
}
131130

132-
if (actionScriptBlock != null)
131+
if (actionScriptBlock is not null)
133132
{
134133
psCommand.AddParameter("Action", actionScriptBlock);
135134
}
136135
}
137136

138137
// If no PSCommand was created then there are no breakpoints to set.
139-
if (psCommand != null)
138+
if (psCommand is not null)
140139
{
141-
IEnumerable<Breakpoint> setBreakpoints =
142-
await _executionService.ExecutePSCommandAsync<Breakpoint>(psCommand, CancellationToken.None).ConfigureAwait(false);
143-
configuredBreakpoints.AddRange(
144-
setBreakpoints.Select((breakpoint) => BreakpointDetails.Create(breakpoint))
145-
);
140+
IEnumerable<Breakpoint> setBreakpoints = await _executionService
141+
.ExecutePSCommandAsync<Breakpoint>(psCommand, CancellationToken.None)
142+
.ConfigureAwait(false);
143+
configuredBreakpoints.AddRange(setBreakpoints.Select((breakpoint) => BreakpointDetails.Create(breakpoint)));
146144
}
147-
148145
return configuredBreakpoints;
149146
}
150147

151-
public async Task<IEnumerable<CommandBreakpointDetails>> SetCommandBreakpoints(IEnumerable<CommandBreakpointDetails> breakpoints)
148+
public async Task<IEnumerable<CommandBreakpointDetails>> SetCommandBreakpointsAsync(IEnumerable<CommandBreakpointDetails> breakpoints)
152149
{
153150
if (BreakpointApiUtils.SupportsBreakpointApis(_editorServicesHost.CurrentRunspace))
154151
{
155152
foreach (CommandBreakpointDetails commandBreakpointDetails in breakpoints)
156153
{
157154
try
158155
{
159-
BreakpointApiUtils.SetBreakpoint(_editorServicesHost.Runspace.Debugger, commandBreakpointDetails, _debugStateService.RunspaceId);
156+
BreakpointApiUtils.SetBreakpoint(
157+
_editorServicesHost.Runspace.Debugger,
158+
commandBreakpointDetails,
159+
_debugStateService.RunspaceId);
160160
}
161-
catch(InvalidOperationException e)
161+
catch (InvalidOperationException e)
162162
{
163163
commandBreakpointDetails.Message = e.Message;
164164
commandBreakpointDetails.Verified = false;
165165
}
166166
}
167-
168167
return breakpoints;
169168
}
170169

171170
// Legacy behavior
172171
PSCommand psCommand = null;
173-
List<CommandBreakpointDetails> configuredBreakpoints = new List<CommandBreakpointDetails>();
172+
List<CommandBreakpointDetails> configuredBreakpoints = new();
174173
foreach (CommandBreakpointDetails breakpoint in breakpoints)
175174
{
176175
// On first iteration psCommand will be null, every subsequent
177176
// iteration will need to start a new statement.
178-
if (psCommand == null)
177+
if (psCommand is null)
179178
{
180179
psCommand = new PSCommand();
181180
}
@@ -208,20 +207,18 @@ public async Task<IEnumerable<CommandBreakpointDetails>> SetCommandBreakpoints(I
208207
configuredBreakpoints.Add(breakpoint);
209208
continue;
210209
}
211-
212210
psCommand.AddParameter("Action", actionScriptBlock);
213211
}
214212
}
215213

216214
// If no PSCommand was created then there are no breakpoints to set.
217-
if (psCommand != null)
215+
if (psCommand is not null)
218216
{
219-
IEnumerable<Breakpoint> setBreakpoints =
220-
await _executionService.ExecutePSCommandAsync<Breakpoint>(psCommand, CancellationToken.None).ConfigureAwait(false);
221-
configuredBreakpoints.AddRange(
222-
setBreakpoints.Select(CommandBreakpointDetails.Create));
217+
IEnumerable<Breakpoint> setBreakpoints = await _executionService
218+
.ExecutePSCommandAsync<Breakpoint>(psCommand, CancellationToken.None)
219+
.ConfigureAwait(false);
220+
configuredBreakpoints.AddRange(setBreakpoints.Select(CommandBreakpointDetails.Create));
223221
}
224-
225222
return configuredBreakpoints;
226223
}
227224

@@ -238,30 +235,26 @@ public async Task RemoveAllBreakpointsAsync(string scriptPath = null)
238235
_editorServicesHost.Runspace.Debugger,
239236
_debugStateService.RunspaceId))
240237
{
241-
if (scriptPath == null || scriptPath == breakpoint.Script)
238+
if (scriptPath is null || scriptPath == breakpoint.Script)
242239
{
243240
BreakpointApiUtils.RemoveBreakpoint(
244241
_editorServicesHost.Runspace.Debugger,
245242
breakpoint,
246243
_debugStateService.RunspaceId);
247244
}
248245
}
249-
250246
return;
251247
}
252248

253249
// Legacy behavior
254-
255-
PSCommand psCommand = new PSCommand();
256-
psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint");
250+
var psCommand = new PSCommand().AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint");
257251

258252
if (!string.IsNullOrEmpty(scriptPath))
259253
{
260254
psCommand.AddParameter("Script", scriptPath);
261255
}
262256

263257
psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint");
264-
265258
await _executionService.ExecutePSCommandAsync<object>(psCommand, CancellationToken.None).ConfigureAwait(false);
266259
}
267260
catch (Exception e)
@@ -281,37 +274,26 @@ public async Task RemoveBreakpointsAsync(IEnumerable<Breakpoint> breakpoints)
281274
breakpoint,
282275
_debugStateService.RunspaceId);
283276

284-
switch (breakpoint)
277+
_ = breakpoint switch
285278
{
286-
case CommandBreakpoint commandBreakpoint:
287-
CommandBreakpoints.Remove(commandBreakpoint);
288-
break;
289-
case LineBreakpoint lineBreakpoint:
290-
if (BreakpointsPerFile.TryGetValue(lineBreakpoint.Script, out HashSet<Breakpoint> bps))
291-
{
292-
bps.Remove(lineBreakpoint);
293-
}
294-
break;
295-
default:
296-
throw new ArgumentException("Unsupported breakpoint type.");
297-
}
279+
CommandBreakpoint commandBreakpoint => CommandBreakpoints.Remove(commandBreakpoint),
280+
LineBreakpoint lineBreakpoint =>
281+
BreakpointsPerFile.TryGetValue(lineBreakpoint.Script, out HashSet<Breakpoint> bps) && bps.Remove(lineBreakpoint),
282+
_ => throw new NotImplementedException("Other breakpoints not supported yet"),
283+
};
298284
}
299-
300285
return;
301286
}
302287

303288
// Legacy behavior
304-
var breakpointIds = breakpoints.Select(b => b.Id).ToArray();
305-
if(breakpointIds.Length > 0)
289+
var breakpointIds = breakpoints.Select(b => b.Id);
290+
if (breakpointIds.Any())
306291
{
307-
PSCommand psCommand = new PSCommand();
308-
psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint");
309-
psCommand.AddParameter("Id", breakpoints.Select(b => b.Id).ToArray());
310-
292+
PSCommand psCommand = new PSCommand()
293+
.AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint")
294+
.AddParameter("Id", breakpoints.Select(b => b.Id).ToArray());
311295
await _executionService.ExecutePSCommandAsync<object>(psCommand, CancellationToken.None).ConfigureAwait(false);
312296
}
313297
}
314-
315-
316298
}
317299
}

src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public async Task<CommandBreakpointDetails[]> SetCommandBreakpointsAsync(
185185

186186
if (breakpoints.Length > 0)
187187
{
188-
resultBreakpointDetails = (await _breakpointService.SetCommandBreakpoints(breakpoints).ConfigureAwait(false)).ToArray();
188+
resultBreakpointDetails = (await _breakpointService.SetCommandBreakpointsAsync(breakpoints).ConfigureAwait(false)).ToArray();
189189
}
190190

191191
return resultBreakpointDetails ?? Array.Empty<CommandBreakpointDetails>();

src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs

+24-19
Original file line numberDiff line numberDiff line change
@@ -134,17 +134,24 @@ public static Breakpoint SetBreakpoint(Debugger debugger, BreakpointDetailsBase
134134
}
135135
}
136136

137-
switch (breakpoint)
137+
return breakpoint switch
138138
{
139-
case BreakpointDetails lineBreakpoint:
140-
return SetLineBreakpointDelegate(debugger, lineBreakpoint.Source, lineBreakpoint.LineNumber, lineBreakpoint.ColumnNumber ?? 0, actionScriptBlock, runspaceId);
141-
142-
case CommandBreakpointDetails commandBreakpoint:
143-
return SetCommandBreakpointDelegate(debugger, commandBreakpoint.Name, null, null, runspaceId);
144-
145-
default:
146-
throw new NotImplementedException("Other breakpoints not supported yet");
147-
}
139+
BreakpointDetails lineBreakpoint => SetLineBreakpointDelegate(
140+
debugger,
141+
lineBreakpoint.Source,
142+
lineBreakpoint.LineNumber,
143+
lineBreakpoint.ColumnNumber ?? 0,
144+
actionScriptBlock,
145+
runspaceId),
146+
147+
CommandBreakpointDetails commandBreakpoint => SetCommandBreakpointDelegate(debugger,
148+
commandBreakpoint.Name,
149+
null,
150+
null,
151+
runspaceId),
152+
153+
_ => throw new NotImplementedException("Other breakpoints not supported yet"),
154+
};
148155
}
149156

150157
public static List<Breakpoint> GetBreakpoints(Debugger debugger, int? runspaceId = null)
@@ -173,20 +180,20 @@ public static ScriptBlock GetBreakpointActionScriptBlock(string condition, strin
173180

174181
try
175182
{
176-
StringBuilder builder = new StringBuilder(
183+
StringBuilder builder = new(
177184
string.IsNullOrEmpty(logMessage)
178185
? "break"
179186
: $"Microsoft.PowerShell.Utility\\Write-Host \"{logMessage.Replace("\"","`\"")}\"");
180187

181188
// If HitCondition specified, parse and verify it.
182-
if (!(string.IsNullOrWhiteSpace(hitCondition)))
189+
if (!string.IsNullOrWhiteSpace(hitCondition))
183190
{
184191
if (!int.TryParse(hitCondition, out int parsedHitCount))
185192
{
186193
throw new InvalidOperationException("Hit Count was not a valid integer.");
187194
}
188195

189-
if(string.IsNullOrWhiteSpace(condition))
196+
if (string.IsNullOrWhiteSpace(condition))
190197
{
191198
// In the HitCount only case, this is simple as we can just use the HitCount
192199
// property on the breakpoint object which is represented by $_.
@@ -217,8 +224,7 @@ public static ScriptBlock GetBreakpointActionScriptBlock(string condition, strin
217224
// Check for "advanced" condition syntax i.e. if the user has specified
218225
// a "break" or "continue" statement anywhere in their scriptblock,
219226
// pass their scriptblock through to the Action parameter as-is.
220-
if (parsed.Ast.Find(ast =>
221-
(ast is BreakStatementAst || ast is ContinueStatementAst), true) != null)
227+
if (parsed.Ast.Find(ast => ast is BreakStatementAst || ast is ContinueStatementAst, true) is not null)
222228
{
223229
return parsed;
224230
}
@@ -247,10 +253,9 @@ private static bool ValidateBreakpointConditionAst(Ast conditionAst, out string
247253

248254
// We are only inspecting a few simple scenarios in the EndBlock only.
249255
if (conditionAst is ScriptBlockAst scriptBlockAst &&
250-
scriptBlockAst.BeginBlock == null &&
251-
scriptBlockAst.ProcessBlock == null &&
252-
scriptBlockAst.EndBlock != null &&
253-
scriptBlockAst.EndBlock.Statements.Count == 1)
256+
scriptBlockAst.BeginBlock is null &&
257+
scriptBlockAst.ProcessBlock is null &&
258+
scriptBlockAst.EndBlock?.Statements.Count == 1)
254259
{
255260
StatementAst statementAst = scriptBlockAst.EndBlock.Statements[0];
256261
string condition = statementAst.Extent.Text;

src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ internal class BreakpointDetails : BreakpointDetailsBase
3030
public int LineNumber { get; private set; }
3131

3232
/// <summary>
33-
/// Gets the column number at which the breakpoint is set. If null, the default of 1 is used.
33+
/// Gets the column number at which the breakpoint is set.
3434
/// </summary>
3535
public int? ColumnNumber { get; private set; }
3636

@@ -83,9 +83,9 @@ internal static BreakpointDetails Create(
8383
Breakpoint breakpoint,
8484
BreakpointUpdateType updateType = BreakpointUpdateType.Set)
8585
{
86-
Validate.IsNotNull("breakpoint", breakpoint);
86+
Validate.IsNotNull(nameof(breakpoint), breakpoint);
8787

88-
if (!(breakpoint is LineBreakpoint lineBreakpoint))
88+
if (breakpoint is not LineBreakpoint lineBreakpoint)
8989
{
9090
throw new ArgumentException(
9191
"Unexpected breakpoint type: " + breakpoint.GetType().Name);

0 commit comments

Comments
 (0)