1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.Text;
using Mono.Debugging.Client;
using MonoDevelop.Core;
using System.Linq;
namespace MonoDevelop.Debugger
{
class BreakpointManager
{
private ITextBuffer textBuffer;
private readonly ITextDocument textDocument;
public BreakpointManager (ITextBuffer textBuffer)
{
this.textBuffer = textBuffer;
if (textBuffer.Properties.TryGetProperty (typeof (ITextDocument), out textDocument) && textDocument.FilePath != null) {
textDocument.FileActionOccurred += TextDocument_FileActionOccurred;
} else {
LoggingService.LogWarning ("Failed to get filename of textbuffer, breakpoints integration will not work.");
return;
}
textBuffer.Changed += TextBuffer_Changed;
DebuggingService.Breakpoints.Changed += OnBreakpointsChanged;
DebuggingService.Breakpoints.BreakpointStatusChanged += OnBreakpointsChanged;
DebuggingService.Breakpoints.BreakpointModified += OnBreakpointsChanged;
OnBreakpointsChanged (null, null);
}
private void TextDocument_FileActionOccurred (object sender, TextDocumentFileActionEventArgs e)
{
if (e.FileActionType == FileActionTypes.DocumentRenamed)
OnBreakpointsChanged (null, null);
}
void TextBuffer_Changed (object sender, TextContentChangedEventArgs e)
{
foreach (var breakpoint in breakpoints.Values) {
var span = breakpoint.TrackingSpan.GetSpan (e.After);
if (span.IsEmpty || string.IsNullOrWhiteSpace (span.GetText ())) {
DebuggingService.Breakpoints.Remove (breakpoint.Breakpoint);
continue;
}
var newLineNumber = e.After.GetLineFromPosition (span.Start).LineNumber + 1;
if (breakpoint.Breakpoint.Line != newLineNumber)
DebuggingService.Breakpoints.UpdateBreakpointLine (breakpoint.Breakpoint, newLineNumber);
}
}
class ManagerBreakpoint
{
public Breakpoint Breakpoint { get; set; }
public ITrackingSpan TrackingSpan { get; set; }
public Span Span { get; set; }
}
private Dictionary<Breakpoint, ManagerBreakpoint> breakpoints = new Dictionary<Breakpoint, ManagerBreakpoint> ();
private async void OnBreakpointsChanged (object sender, EventArgs eventArgs)
{
var newBreakpoints = new Dictionary<Breakpoint, ManagerBreakpoint> ();
var snapshot = textBuffer.CurrentSnapshot;
var needsUpdate = false;
foreach (var breakpoint in DebuggingService.Breakpoints.GetBreakpointsAtFile (textDocument.FilePath)) {
if (breakpoint.Line > snapshot.LineCount)
continue;
if (eventArgs is BreakpointEventArgs breakpointEventArgs && breakpointEventArgs.Breakpoint == breakpoint)
needsUpdate = true;
var line = snapshot.GetLineFromLineNumber (breakpoint.Line - 1);
var position = line.Start.Position + breakpoint.Column;
var span = await DebuggingService.GetBreakpointSpanAsync (textDocument, position);
if (breakpoints.TryGetValue (breakpoint, out var existingBreakpoint)) {
newBreakpoints.Add (breakpoint, existingBreakpoint);
if (existingBreakpoint.Span != span) {
// Update if anything was modified
existingBreakpoint.Span = span;
needsUpdate = true;
}
} else {
// Update if anything was added
newBreakpoints.Add (breakpoint, new ManagerBreakpoint {
Breakpoint = breakpoint,
TrackingSpan = snapshot.CreateTrackingSpan (span, SpanTrackingMode.EdgeExclusive),
Span = span
});
needsUpdate = true;
}
}
// Update if anything was removed
if (needsUpdate || breakpoints.Keys.Except (newBreakpoints.Keys).Any ())
needsUpdate = true;
breakpoints = newBreakpoints;
if (needsUpdate)
BreakpointsChanged?.Invoke (this, new SnapshotSpanEventArgs (new SnapshotSpan (snapshot, 0, snapshot.Length)));
}
public event EventHandler<SnapshotSpanEventArgs> BreakpointsChanged;
public void Dispose ()
{
BreakpointsChanged = null;
textBuffer.Changed -= TextBuffer_Changed;
DebuggingService.Breakpoints.Changed -= OnBreakpointsChanged;
DebuggingService.Breakpoints.BreakpointStatusChanged -= OnBreakpointsChanged;
DebuggingService.Breakpoints.BreakpointModified -= OnBreakpointsChanged;
if (textDocument != null)
textDocument.FileActionOccurred -= TextDocument_FileActionOccurred;
}
public IEnumerable<BreakpointSpan> GetBreakpoints (ITextSnapshot snapshot)
{
foreach (var item in breakpoints.Values) {
yield return new BreakpointSpan (item.Breakpoint, item.TrackingSpan.GetSpan (snapshot));
}
}
}
class BreakpointSpan
{
public Breakpoint Breakpoint { get; }
public SnapshotSpan Span { get; }
public BreakpointSpan (Breakpoint breakpoint, SnapshotSpan span)
{
Breakpoint = breakpoint;
Span = span;
}
}
}
|