Skip to content

Commit ff35f29

Browse files
move to runspaceId
1 parent dfc6fe0 commit ff35f29

File tree

5 files changed

+116
-57
lines changed

5 files changed

+116
-57
lines changed

src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs

+45-9
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,30 @@ internal class BreakpointService
2222
{
2323
private readonly ILogger<BreakpointService> _logger;
2424
private readonly PowerShellContextService _powerShellContextService;
25+
private readonly DebugStateService _debugStateService;
26+
27+
// TODO: This needs to be managed per nested session
28+
internal readonly Dictionary<string, HashSet<Breakpoint>> BreakpointsPerFile =
29+
new Dictionary<string, HashSet<Breakpoint>>();
30+
31+
internal readonly HashSet<Breakpoint> CommandBreakpoints =
32+
new HashSet<Breakpoint>();
2533

2634
public BreakpointService(
2735
ILoggerFactory factory,
28-
PowerShellContextService powerShellContextService)
36+
PowerShellContextService powerShellContextService,
37+
DebugStateService debugStateService)
2938
{
3039
_logger = factory.CreateLogger<BreakpointService>();
3140
_powerShellContextService = powerShellContextService;
41+
_debugStateService = debugStateService;
42+
}
43+
44+
public List<Breakpoint> GetBreakpoints()
45+
{
46+
return BreakpointApiUtils.GetBreakpoints(
47+
_powerShellContextService.CurrentRunspace.Runspace.Debugger,
48+
_debugStateService.RunspaceId);
3249
}
3350

3451
public async Task<IEnumerable<BreakpointDetails>> SetBreakpointsAsync(string escapedScriptPath, IEnumerable<BreakpointDetails> breakpoints)
@@ -39,7 +56,7 @@ public async Task<IEnumerable<BreakpointDetails>> SetBreakpointsAsync(string esc
3956
{
4057
try
4158
{
42-
BreakpointApiUtils.SetBreakpoint(_powerShellContextService.CurrentRunspace.Runspace.Debugger, breakpointDetails);
59+
BreakpointApiUtils.SetBreakpoint(_powerShellContextService.CurrentRunspace.Runspace.Debugger, breakpointDetails, _debugStateService.RunspaceId);
4360

4461
}
4562
catch(InvalidOperationException e)
@@ -129,7 +146,7 @@ public async Task<IEnumerable<CommandBreakpointDetails>> SetCommandBreakpoints(I
129146
{
130147
try
131148
{
132-
BreakpointApiUtils.SetBreakpoint(_powerShellContextService.CurrentRunspace.Runspace.Debugger, commandBreakpointDetails);
149+
BreakpointApiUtils.SetBreakpoint(_powerShellContextService.CurrentRunspace.Runspace.Debugger, commandBreakpointDetails, _debugStateService.RunspaceId);
133150
}
134151
catch(InvalidOperationException e)
135152
{
@@ -195,18 +212,23 @@ public async Task<IEnumerable<CommandBreakpointDetails>> SetCommandBreakpoints(I
195212
/// <summary>
196213
/// Clears all breakpoints in the current session.
197214
/// </summary>
198-
public async Task RemoveAllBreakpointsAsync()
215+
public async Task RemoveAllBreakpointsAsync(string scriptPath = null)
199216
{
200217
try
201218
{
202219
if (VersionUtils.IsPS7OrGreater)
203220
{
204221
foreach (Breakpoint breakpoint in BreakpointApiUtils.GetBreakpoints(
205-
_powerShellContextService.CurrentRunspace.Runspace.Debugger))
206-
{
207-
BreakpointApiUtils.RemoveBreakpoint(
208222
_powerShellContextService.CurrentRunspace.Runspace.Debugger,
209-
breakpoint);
223+
_debugStateService.RunspaceId))
224+
{
225+
if (scriptPath == null || scriptPath == breakpoint.Script)
226+
{
227+
BreakpointApiUtils.RemoveBreakpoint(
228+
_powerShellContextService.CurrentRunspace.Runspace.Debugger,
229+
breakpoint,
230+
_debugStateService.RunspaceId);
231+
}
210232
}
211233

212234
return;
@@ -234,7 +256,21 @@ public async Task RemoveBreakpointsAsync(IEnumerable<Breakpoint> breakpoints)
234256
{
235257
BreakpointApiUtils.RemoveBreakpoint(
236258
_powerShellContextService.CurrentRunspace.Runspace.Debugger,
237-
breakpoint);
259+
breakpoint,
260+
_debugStateService.RunspaceId);
261+
262+
switch (breakpoint)
263+
{
264+
case CommandBreakpoint commandBreakpoint:
265+
CommandBreakpoints.Remove(commandBreakpoint);
266+
break;
267+
case LineBreakpoint lineBreakpoint:
268+
if (BreakpointsPerFile.TryGetValue(lineBreakpoint.Script, out HashSet<Breakpoint> bps))
269+
{
270+
bps.Remove(lineBreakpoint);
271+
}
272+
break;
273+
}
238274
}
239275

240276
return;

src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs

+15-18
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
1919
using Microsoft.PowerShell.EditorServices.Services.PowerShellContext;
2020
using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
21+
using System.Collections.Concurrent;
2122

2223
namespace Microsoft.PowerShell.EditorServices.Services
2324
{
@@ -38,11 +39,6 @@ internal class DebugService
3839
private readonly BreakpointService _breakpointService;
3940
private RemoteFileManagerService remoteFileManager;
4041

41-
// TODO: This needs to be managed per nested session
42-
// TODO: Move to BreakpointService
43-
private readonly Dictionary<string, List<Breakpoint>> breakpointsPerFile =
44-
new Dictionary<string, List<Breakpoint>>();
45-
4642
private int nextVariableId;
4743
private string temporaryScriptListingPath;
4844
private List<VariableDetailsBase> variables;
@@ -192,7 +188,7 @@ public async Task<BreakpointDetails[]> SetLineBreakpointsAsync(
192188
await this.ClearBreakpointsInFileAsync(scriptFile).ConfigureAwait(false);
193189
}
194190

195-
return await _breakpointService.SetBreakpointsAsync(escapedScriptPath, breakpoints).ConfigureAwait(false);
191+
return (await _breakpointService.SetBreakpointsAsync(escapedScriptPath, breakpoints).ConfigureAwait(false)).ToArray();
196192
}
197193

198194
return await dscBreakpoints.SetLineBreakpointsAsync(
@@ -216,7 +212,7 @@ public async Task<CommandBreakpointDetails[]> SetCommandBreakpointsAsync(
216212
if (clearExisting)
217213
{
218214
// Flatten dictionary values into one list and remove them all.
219-
await _breakpointService.RemoveBreakpointsAsync(this.breakpointsPerFile.Values.SelectMany( i => i ).Where( i => i is CommandBreakpoint)).ConfigureAwait(false);
215+
await _breakpointService.RemoveBreakpointsAsync(_breakpointService.GetBreakpoints().Where( i => i is CommandBreakpoint)).ConfigureAwait(false);
220216
}
221217

222218
if (breakpoints.Length > 0)
@@ -672,16 +668,17 @@ public VariableScope[] GetVariableScopes(int stackFrameId)
672668
private async Task ClearBreakpointsInFileAsync(ScriptFile scriptFile)
673669
{
674670
// Get the list of breakpoints for this file
675-
if (this.breakpointsPerFile.TryGetValue(scriptFile.Id, out List<Breakpoint> breakpoints))
676-
{
677-
if (breakpoints.Count > 0)
678-
{
679-
await _breakpointService.RemoveBreakpointsAsync(breakpoints).ConfigureAwait(false);
671+
// if (_breakpointService.BreakpointsPerFile.TryGetValue(scriptFile.Id, out HashSet<Breakpoint> breakpoints))
672+
// {
673+
// if (breakpoints.Count > 0)
674+
// {
675+
await _breakpointService.RemoveBreakpointsAsync(_breakpointService.GetBreakpoints()
676+
.Where(bp => bp is LineBreakpoint lbp && string.Equals(lbp.Script, scriptFile.FilePath))).ConfigureAwait(false);
680677

681678
// Clear the existing breakpoints list for the file
682-
breakpoints.Clear();
683-
}
684-
}
679+
// breakpoints.Clear();
680+
// }
681+
// }
685682
}
686683

687684
private async Task FetchStackFramesAndVariablesAsync(string scriptNameOverride)
@@ -1035,10 +1032,10 @@ private void OnBreakpointUpdated(object sender, BreakpointUpdatedEventArgs e)
10351032
string normalizedScriptName = scriptPath.ToLower();
10361033

10371034
// Get the list of breakpoints for this file
1038-
if (!this.breakpointsPerFile.TryGetValue(normalizedScriptName, out List<Breakpoint> breakpoints))
1035+
if (!_breakpointService.BreakpointsPerFile.TryGetValue(normalizedScriptName, out HashSet<Breakpoint> breakpoints))
10391036
{
1040-
breakpoints = new List<Breakpoint>();
1041-
this.breakpointsPerFile.Add(
1037+
breakpoints = new HashSet<Breakpoint>();
1038+
_breakpointService.BreakpointsPerFile.Add(
10421039
normalizedScriptName,
10431040
breakpoints);
10441041
}

src/PowerShellEditorServices/Services/DebugAdapter/DebugStateService.cs

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ internal class DebugStateService
1919

2020
internal bool IsRemoteAttach { get; set; }
2121

22+
internal int? RunspaceId { get; set; }
23+
2224
internal bool IsAttachSession { get; set; }
2325

2426
internal bool WaitingForAttach { get; set; }

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

+41-27
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ internal static class BreakpointApiUtils
2323

2424
private const string s_psesGlobalVariableNamePrefix = "__psEditorServices_";
2525

26-
private static readonly Lazy<Func<Debugger, string, int, int, ScriptBlock, LineBreakpoint>> s_setLineBreakpointLazy;
26+
private static readonly Lazy<Func<Debugger, string, int, int, ScriptBlock, int?, LineBreakpoint>> s_setLineBreakpointLazy;
2727

28-
private static readonly Lazy<Func<Debugger, string, ScriptBlock, string, CommandBreakpoint>> s_setCommandBreakpointLazy;
28+
private static readonly Lazy<Func<Debugger, string, ScriptBlock, string, int?, CommandBreakpoint>> s_setCommandBreakpointLazy;
2929

30-
private static readonly Lazy<Func<Debugger, List<Breakpoint>>> s_getBreakpointsLazy;
30+
private static readonly Lazy<Func<Debugger, int?, List<Breakpoint>>> s_getBreakpointsLazy;
3131

32-
private static readonly Lazy<Func<Debugger, Breakpoint, bool>> s_removeBreakpointLazy;
32+
private static readonly Lazy<Action<Debugger, IEnumerable<Breakpoint>, int?>> s_setBreakpointsLazy;
33+
34+
private static readonly Lazy<Func<Debugger, Breakpoint, int?, bool>> s_removeBreakpointLazy;
3335

3436
private static int breakpointHitCounter;
3537

@@ -46,42 +48,52 @@ static BreakpointApiUtils()
4648
return;
4749
}
4850

49-
s_setLineBreakpointLazy = new Lazy<Func<Debugger, string, int, int, ScriptBlock, LineBreakpoint>>(() =>
51+
s_setLineBreakpointLazy = new Lazy<Func<Debugger, string, int, int, ScriptBlock, int?, LineBreakpoint>>(() =>
5052
{
5153
MethodInfo setLineBreakpointMethod = typeof(Debugger).GetMethod("SetLineBreakpoint", BindingFlags.Public | BindingFlags.Instance);
5254

53-
return (Func<Debugger, string, int, int, ScriptBlock, LineBreakpoint>)Delegate.CreateDelegate(
54-
typeof(Func<Debugger, string, int, int, ScriptBlock, LineBreakpoint>),
55+
return (Func<Debugger, string, int, int, ScriptBlock, int?, LineBreakpoint>)Delegate.CreateDelegate(
56+
typeof(Func<Debugger, string, int, int, ScriptBlock, int?, LineBreakpoint>),
5557
firstArgument: null,
5658
setLineBreakpointMethod);
5759
});
5860

59-
s_setCommandBreakpointLazy = new Lazy<Func<Debugger, string, ScriptBlock, string, CommandBreakpoint>>(() =>
61+
s_setCommandBreakpointLazy = new Lazy<Func<Debugger, string, ScriptBlock, string, int?, CommandBreakpoint>>(() =>
6062
{
6163
MethodInfo setCommandBreakpointMethod = typeof(Debugger).GetMethod("SetCommandBreakpoint", BindingFlags.Public | BindingFlags.Instance);
6264

63-
return (Func<Debugger, string, ScriptBlock, string, CommandBreakpoint>)Delegate.CreateDelegate(
64-
typeof(Func<Debugger, string, ScriptBlock, string, CommandBreakpoint>),
65+
return (Func<Debugger, string, ScriptBlock, string, int?, CommandBreakpoint>)Delegate.CreateDelegate(
66+
typeof(Func<Debugger, string, ScriptBlock, string, int?, CommandBreakpoint>),
6567
firstArgument: null,
6668
setCommandBreakpointMethod);
6769
});
6870

69-
s_getBreakpointsLazy = new Lazy<Func<Debugger, List<Breakpoint>>>(() =>
71+
s_getBreakpointsLazy = new Lazy<Func<Debugger, int?, List<Breakpoint>>>(() =>
7072
{
7173
MethodInfo removeBreakpointMethod = typeof(Debugger).GetMethod("GetBreakpoints", BindingFlags.Public | BindingFlags.Instance);
7274

73-
return (Func<Debugger, List<Breakpoint>>)Delegate.CreateDelegate(
74-
typeof(Func<Debugger, List<Breakpoint>>),
75+
return (Func<Debugger, int?, List<Breakpoint>>)Delegate.CreateDelegate(
76+
typeof(Func<Debugger, int?, List<Breakpoint>>),
77+
firstArgument: null,
78+
removeBreakpointMethod);
79+
});
80+
81+
s_setBreakpointsLazy = new Lazy<Action<Debugger, IEnumerable<Breakpoint>, int?>>(() =>
82+
{
83+
MethodInfo removeBreakpointMethod = typeof(Debugger).GetMethod("SetBreakpoints", BindingFlags.Public | BindingFlags.Instance);
84+
85+
return (Action<Debugger, IEnumerable<Breakpoint>, int?>)Action.CreateDelegate(
86+
typeof(Action<Debugger, IEnumerable<Breakpoint>, int?>),
7587
firstArgument: null,
7688
removeBreakpointMethod);
7789
});
7890

79-
s_removeBreakpointLazy = new Lazy<Func<Debugger, Breakpoint, bool>>(() =>
91+
s_removeBreakpointLazy = new Lazy<Func<Debugger, Breakpoint, int?, bool>>(() =>
8092
{
8193
MethodInfo removeBreakpointMethod = typeof(Debugger).GetMethod("RemoveBreakpoint", BindingFlags.Public | BindingFlags.Instance);
8294

83-
return (Func<Debugger, Breakpoint, bool>)Delegate.CreateDelegate(
84-
typeof(Func<Debugger, Breakpoint, bool>),
95+
return (Func<Debugger, Breakpoint, int?, bool>)Delegate.CreateDelegate(
96+
typeof(Func<Debugger, Breakpoint, int?, bool>),
8597
firstArgument: null,
8698
removeBreakpointMethod);
8799
});
@@ -91,19 +103,21 @@ static BreakpointApiUtils()
91103

92104
#region Public Static Properties
93105

94-
private static Func<Debugger, string, int, int, ScriptBlock, LineBreakpoint> SetLineBreakpointDelegate => s_setLineBreakpointLazy.Value;
106+
private static Func<Debugger, string, int, int, ScriptBlock, int?, LineBreakpoint> SetLineBreakpointDelegate => s_setLineBreakpointLazy.Value;
107+
108+
private static Func<Debugger, string, ScriptBlock, string, int?, CommandBreakpoint> SetCommandBreakpointDelegate => s_setCommandBreakpointLazy.Value;
95109

96-
private static Func<Debugger, string, ScriptBlock, string, CommandBreakpoint> SetCommandBreakpointDelegate => s_setCommandBreakpointLazy.Value;
110+
private static Func<Debugger, int?, List<Breakpoint>> GetBreakpointsDelegate => s_getBreakpointsLazy.Value;
97111

98-
private static Func<Debugger, List<Breakpoint>> GetBreakpointsDelegate => s_getBreakpointsLazy.Value;
112+
private static Action<Debugger, IEnumerable<Breakpoint>, int?> SetBreakpointsDelegate => s_setBreakpointsLazy.Value;
99113

100-
private static Func<Debugger, Breakpoint, bool> RemoveBreakpointDelegate => s_removeBreakpointLazy.Value;
114+
private static Func<Debugger, Breakpoint, int?, bool> RemoveBreakpointDelegate => s_removeBreakpointLazy.Value;
101115

102116
#endregion
103117

104118
#region Public Static Methods
105119

106-
public static Breakpoint SetBreakpoint(Debugger debugger, BreakpointDetailsBase breakpoint)
120+
public static Breakpoint SetBreakpoint(Debugger debugger, BreakpointDetailsBase breakpoint, int? runspaceId = null)
107121
{
108122
ScriptBlock actionScriptBlock = null;
109123
string logMessage = breakpoint is BreakpointDetails bd ? bd.LogMessage : null;
@@ -118,24 +132,24 @@ public static Breakpoint SetBreakpoint(Debugger debugger, BreakpointDetailsBase
118132
switch (breakpoint)
119133
{
120134
case BreakpointDetails lineBreakpoint:
121-
return SetLineBreakpointDelegate(debugger, lineBreakpoint.Source, lineBreakpoint.LineNumber, lineBreakpoint.ColumnNumber ?? 0, actionScriptBlock);
135+
return SetLineBreakpointDelegate(debugger, lineBreakpoint.Source, lineBreakpoint.LineNumber, lineBreakpoint.ColumnNumber ?? 0, actionScriptBlock, runspaceId);
122136

123137
case CommandBreakpointDetails commandBreakpoint:
124-
return SetCommandBreakpointDelegate(debugger, commandBreakpoint.Name, null, null);
138+
return SetCommandBreakpointDelegate(debugger, commandBreakpoint.Name, null, null, runspaceId);
125139

126140
default:
127141
throw new NotImplementedException("Other breakpoints not supported yet");
128142
}
129143
}
130144

131-
public static List<Breakpoint> GetBreakpoints(Debugger debugger)
145+
public static List<Breakpoint> GetBreakpoints(Debugger debugger, int? runspaceId = null)
132146
{
133-
return GetBreakpointsDelegate(debugger);
147+
return GetBreakpointsDelegate(debugger, runspaceId);
134148
}
135149

136-
public static bool RemoveBreakpoint(Debugger debugger, Breakpoint breakpoint)
150+
public static bool RemoveBreakpoint(Debugger debugger, Breakpoint breakpoint, int? runspaceId = null)
137151
{
138-
return RemoveBreakpointDelegate(debugger, breakpoint);
152+
return RemoveBreakpointDelegate(debugger, breakpoint, runspaceId);
139153
}
140154

141155
public static ScriptBlock GetBreakpointActionScriptBlock(string condition, string hitCondition, string logMessage)

0 commit comments

Comments
 (0)