Welcome to mirror list, hosted at ThFree Co, Russian Federation.

BreakpointManager.cs « MonoDevelop.Debugger.VSTextView « MonoDevelop.Debugger « addins « src « main - github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: f3f690e4507b5b7bdc2a15ab2b1de3a437742167 (plain)
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
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 newSpan = breakpoint.TrackingSpan.GetSpan (e.After);
				if (newSpan.IsEmpty) {
					DebuggingService.Breakpoints.Remove (breakpoint.Breakpoint);
					continue;
				}
				var newLineNumber = e.After.GetLineFromPosition (newSpan.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 void OnBreakpointsChanged (object sender, EventArgs eventArgs)
		{
			var snapshot = textBuffer.CurrentSnapshot;
			var newBreakpoints = new Dictionary<Breakpoint, ManagerBreakpoint> ();
			bool 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 newSpan = snapshot.GetLineFromLineNumber (breakpoint.Line - 1).Extent;
				if (breakpoints.TryGetValue (breakpoint, out var existingBreakpoint)) {
					newBreakpoints.Add (breakpoint, existingBreakpoint);
					if (existingBreakpoint.Span != newSpan.Span) {
						// Update if anything was modifed
						needsUpdate = true;
						existingBreakpoint.Span = newSpan.Span;
					}
				} else {
					// Update if anything was added
					needsUpdate = true;
					newBreakpoints.Add (breakpoint, new ManagerBreakpoint () {
						Breakpoint = breakpoint,
						TrackingSpan = snapshot.CreateTrackingSpan (newSpan, SpanTrackingMode.EdgeExclusive),
						Span = newSpan.Span
					});
				}
			}
			// 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;
		}
	}
}