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

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Karlaš <david.karlas@microsoft.com>2019-01-22 12:29:18 +0300
committerDavid Karlaš <david.karlas@microsoft.com>2019-01-22 20:55:26 +0300
commit333faaaabe5803030cfe6f8d2476a614b4fd89de (patch)
treedab464727e0eb99292425000b714fa71e8bf02f7 /main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView
parent38a30db559e0e4410f6b6b8c041041e5748c348d (diff)
Initial Debugger support in new editor
Diffstat (limited to 'main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView')
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphFactoryProvider.cs81
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphMouseProcessor.cs583
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphMouseProcessorProvider.cs31
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTag.cs89
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTagger.cs69
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTaggerProvider.cs27
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphFactoryProvider.cs21
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTag.cs9
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTagger.cs12
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTaggerProvider.cs19
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/GlyphCommandType.cs8
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/IActiveGlyphDropHandler.cs8
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/IInteractiveGlyph.cs13
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ImageSourceGlyphFactory.cs32
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphFactoryProvider.cs21
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTag.cs9
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTagger.cs12
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTaggerProvider.cs19
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/DebuggerQuickInfoSource.cs109
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/DebuggerQuickInfoSourceProvider.cs31
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/IDebugInfoProvider.cs29
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/AbstractBreakpointTagger.cs66
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/AbstractCurrentStatementTagger.cs75
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointForegroundTagger.cs17
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointForegroundTaggerProvider.cs32
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointMarkerDefinition.cs21
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTag.cs40
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTagger.cs13
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTaggerProvider.cs21
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ClassificationTypes.cs118
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementForegroundTagger.cs16
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementForegroundTaggerProvider.cs32
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementMarkerDefinition.cs21
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTag.cs16
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTagger.cs12
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTaggerProvider.cs19
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementForegroundTaggerProvider.cs31
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementMarkerDefinition.cs21
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTag.cs16
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTagger.cs12
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTaggerProvider.cs19
41 files changed, 1850 insertions, 0 deletions
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphFactoryProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphFactoryProvider.cs
new file mode 100644
index 0000000000..c5b3b0d856
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphFactoryProvider.cs
@@ -0,0 +1,81 @@
+using System.ComponentModel.Composition;
+using Microsoft.Ide.Editor;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+using Microsoft.VisualStudio.Core.Imaging;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IGlyphFactoryProvider))]
+ [Name (nameof (BreakpointGlyphTag))]
+ [ContentType ("code")]
+ [TagType (typeof (BreakpointGlyphTag))]
+ internal class BreakpointGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory (ICocoaTextView view, ICocoaTextViewMargin margin)
+ {
+ return new ImageSourceGlyphFactory<BreakpointGlyphTag> ("md-breakpoint");
+ }
+ }
+
+ [Export (typeof (IGlyphFactoryProvider))]
+ [Name (nameof (BreakpointDisabledGlyphTag))]
+ [ContentType ("code")]
+ [TagType (typeof (BreakpointDisabledGlyphTag))]
+ internal class BreakpointDisabledGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory (ICocoaTextView view, ICocoaTextViewMargin margin)
+ {
+ return new ImageSourceGlyphFactory<BreakpointDisabledGlyphTag> ("md-breakpoint-disabled");
+ }
+ }
+
+ [Export (typeof (IGlyphFactoryProvider))]
+ [Name (nameof (BreakpointInvalidGlyphTag))]
+ [ContentType ("code")]
+ [TagType (typeof (BreakpointInvalidGlyphTag))]
+ internal class BreakpointInvalidGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory (ICocoaTextView view, ICocoaTextViewMargin margin)
+ {
+ return new ImageSourceGlyphFactory<BreakpointInvalidGlyphTag> ("md-breakpoint-invalid");
+ }
+ }
+
+ [Export (typeof (IGlyphFactoryProvider))]
+ [Name (nameof (TracepointGlyphTag))]
+ [ContentType ("code")]
+ [TagType (typeof (TracepointGlyphTag))]
+ internal class TracepointGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory (ICocoaTextView view, ICocoaTextViewMargin margin)
+ {
+ return new ImageSourceGlyphFactory<TracepointGlyphTag> ("md-gutter-tracepoint");
+ }
+ }
+
+ [Export (typeof (IGlyphFactoryProvider))]
+ [Name (nameof (TracepointDisabledGlyphTag))]
+ [ContentType ("code")]
+ [TagType (typeof (TracepointDisabledGlyphTag))]
+ internal class TracepointDisabledGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory (ICocoaTextView view, ICocoaTextViewMargin margin)
+ {
+ return new ImageSourceGlyphFactory<TracepointDisabledGlyphTag> ("md-gutter-tracepoint-disabled");
+ }
+ }
+
+ [Export (typeof (IGlyphFactoryProvider))]
+ [Name (nameof (TracepointInvalidGlyphTag))]
+ [ContentType ("code")]
+ [TagType (typeof (TracepointInvalidGlyphTag))]
+ internal class TracepointInvalidGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory (ICocoaTextView view, ICocoaTextViewMargin margin)
+ {
+ return new ImageSourceGlyphFactory<TracepointInvalidGlyphTag> ("md-gutter-tracepoint-invalid");
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphMouseProcessor.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphMouseProcessor.cs
new file mode 100644
index 0000000000..07761fb5f1
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphMouseProcessor.cs
@@ -0,0 +1,583 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Threading;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Formatting;
+using Microsoft.VisualStudio.Text.Tagging;
+using AppKit;
+using CoreGraphics;
+using MonoDevelop.Debugger;
+using MonoDevelop.Ide.Gui;
+using MonoDevelop.Ide;
+using MonoDevelop.Ide.Editor;
+
+namespace MonoDevelop.Debugger
+{
+ public class BreakpointGlyphMouseProcessor : CocoaMouseProcessorBase
+ {
+ private readonly ICocoaTextViewHost textViewHost;
+ private ITagAggregator<IGlyphTag> glyphTagAggregator;
+ private readonly ICocoaTextViewMargin glyphMargin;
+ private readonly IViewPrimitives viewPrimitives;
+ private IActiveGlyphDropHandler activeGlyphDropHandler;
+
+ // Tooltip
+ //private readonly Popup popup;
+
+ // Hover members
+ private DispatcherTimer mouseHoverTimer = null;
+ private ITextViewLine lastHoverPosition;
+ private ITextViewLine currentlyHoveringLine;
+
+ // Drag/drop members
+ private CGPoint clickLocation;
+ internal bool LastLeftButtonWasDoubleClick = true; // internal for unit testing
+ private bool dragOccurred = false;
+
+ // Constants for scrolling tolerance (borrowed from \platform\text\dragdrop\DragDropMouseProcessor.cs).
+ private const double VerticalScrollTolerance = 15;
+ private const double HorizontalScrollTolerance = 15;
+
+ // Delay before tooltips display
+ private const int ToolTipDelayMilliseconds = 150;
+
+ public BreakpointGlyphMouseProcessor (
+ ICocoaTextViewHost wpfTextViewHost,
+ ICocoaTextViewMargin margin,
+ ITagAggregator<IGlyphTag> tagAggregator,
+ IViewPrimitives viewPrimitives)
+ {
+ this.textViewHost = wpfTextViewHost;
+ this.glyphMargin = margin;
+ this.glyphTagAggregator = tagAggregator;
+ this.viewPrimitives = viewPrimitives;
+
+ // Setup the UI
+ //TODO:MAC
+ //popup = new Popup();
+ //popup.IsOpen = false;
+ //popup.Visibility = Visibility.Hidden;
+
+ textViewHost.Closed += delegate {
+ glyphTagAggregator.Dispose ();
+ glyphTagAggregator = null;
+ };
+ }
+
+ public override void PreprocessMouseLeftButtonDown (MouseEvent e)
+ {
+ // Record click location.
+ clickLocation = GetMouseLocationInTextView (e);
+
+ // We don't handle double-click, and set the flag so that the mouse
+ // up handler doesn't try to handle it as a click either.
+ LastLeftButtonWasDoubleClick = e.Event.ClickCount == 2;
+
+ if (LastLeftButtonWasDoubleClick) {
+ return;
+ }
+
+ // Starts a drag if applicable.
+ HandleDragStart (clickLocation);
+ }
+
+ public override void PreprocessMouseLeftButtonUp (MouseEvent e)
+ {
+ // Did we successfully drag a glyph?
+ var mouseUpLocation = GetMouseLocationInTextView (e);
+ if (HandleDragEnd (mouseUpLocation)) {
+ e.Handled = true;
+ return;
+ }
+
+ // We don't handle double-click
+ if (LastLeftButtonWasDoubleClick) {
+ return;
+ }
+
+ if (GetTextViewLine (mouseUpLocation.Y) != GetTextViewLine (clickLocation.Y)) {
+ // If the user (probably accidentally) click-dragged to a different line, don't treat it as a click.
+ e.Handled = false;
+ return;
+ }
+
+ // Treat this as a marker click
+ e.Handled = HandleMarkerClick (e);
+ }
+
+ public override void PostprocessMouseRightButtonUp (MouseEvent e)
+ {
+ var mouseUpLocation = GetMouseLocationInTextView (e);
+ var textViewLine = GetTextViewLine (mouseUpLocation.Y);
+ if (!textViewLine.Extent.Contains (textViewHost.TextView.Caret.Position.BufferPosition))
+ textViewHost.TextView.Caret.MoveTo (textViewLine.Start);
+ var view = (ViewContent)textViewHost.TextView.Properties [typeof (ViewContent)];
+ var ctx = view.WorkbenchWindow?.ExtensionContext ?? Mono.Addins.AddinManager.AddinEngine;
+ var cset = IdeApp.CommandService.CreateCommandEntrySet (ctx, "/MonoDevelop/SourceEditor2/IconContextMenu/Editor");
+ var pt = ((NSEvent)e.Event).LocationInWindow;
+ pt = textViewHost.TextView.VisualElement.ConvertPointFromView (pt, null);
+ IdeApp.CommandService.ShowContextMenu (textViewHost.TextView.VisualElement, (int)pt.X, (int)pt.Y, cset, view);
+ }
+
+ public override void PostprocessMouseEnter (MouseEvent e)
+ {
+ EnableToolTips ();
+ }
+
+ public override void PostprocessMouseLeave (MouseEvent e)
+ {
+ DisableToolTips ();
+ }
+
+ public override void PreprocessMouseMove (MouseEvent e)
+ {
+ // If we're dragging a glyph, show proper cursor, scroll the view, etc.
+ var pt = GetMouseLocationInTextView (e);
+ if (HandleDragOver (pt)) {
+ return;
+ }
+
+ ITextViewLine textLine = GetTextViewLine (pt.Y);
+
+ // If we're hovering, make sure we're still hovering over the same line.
+ if (mouseHoverTimer != null) {
+ if (textLine != currentlyHoveringLine) {
+ currentlyHoveringLine = null;
+
+ HideTooltip ();
+ }
+
+ mouseHoverTimer.Start ();
+ }
+
+ // If there's a glyph with a hover mouse cursor, show it.
+ if (textLine != null) {
+ foreach (IInteractiveGlyph textMarkerGlyphTag in GetTextMarkerGlyphTagsStartingOnLine (textLine)) {
+ if (textMarkerGlyphTag.HoverCursor != null) {
+ //TODO:MAC
+ //Mouse.SetCursor(textMarkerGlyphTag.HoverCursor);
+ break;
+ }
+ }
+ }
+ }
+
+ #region Private Drag/Drop Helpers
+
+ // Internal for unit testing.
+ internal void HandleDragStart (CGPoint viewPoint)
+ {
+ Debug.Assert (activeGlyphDropHandler == null);
+ activeGlyphDropHandler = null;
+
+ // Get the ITextViewLine corresponding to the click point.
+ ITextViewLine textLine = GetTextViewLine (viewPoint.Y);
+ if (textLine == null) {
+ return;
+ }
+
+ // Is there a draggable glyph here?
+ IActiveGlyphDropHandler draggableTextMarkerGlyphTag = null;
+ foreach (IInteractiveGlyph textMarkerGlyphTag in GetTextMarkerGlyphTagsStartingOnLine (textLine)) {
+ if (textMarkerGlyphTag.DropHandler != null) {
+ draggableTextMarkerGlyphTag = textMarkerGlyphTag.DropHandler;
+ break;
+ }
+ }
+
+ if (draggableTextMarkerGlyphTag == null) {
+ return;
+ }
+
+ // We have a draggable glyph. Start dragging it!
+ // Store the handler for the glyph being dragged.
+ activeGlyphDropHandler = draggableTextMarkerGlyphTag;
+
+ HideTooltip ();
+
+ dragOccurred = false;
+
+ // Capture mouse events so we catch mouse moves over the entire screen and the mouse up event.
+ // Note: This may trigger an immediate OnMouseMove event, so make sure we do it last.
+ //glyphMargin.VisualElement.CaptureMouse();
+ }
+
+ internal bool HandleDragOver (CGPoint viewPoint)
+ {
+ if (activeGlyphDropHandler == null) {
+ return false; // not dragging
+ }
+
+ if (!dragOccurred) {
+ // if the mouse moved position is less than the system settings for drag start, don't start the
+ // drag operation
+ Vector dragDelta = new Vector (clickLocation.X - viewPoint.X, clickLocation.Y - viewPoint.Y);
+ if (Math.Abs (dragDelta.X) < SystemParameters.MinimumHorizontalDragDistance && Math.Abs (dragDelta.Y) < SystemParameters.MinimumVerticalDragDistance) {
+ return false;
+ }
+
+ // Now that the mouse has moved, this is an actual drag.
+ dragOccurred = true;
+ }
+
+ Tuple<int, int> lineAndColumn = GetLineNumberAndColumn (viewPoint);
+
+ // If this line isn't in the data (surface) buffer, we can't use it
+ if (lineAndColumn.Item1 < 0) {
+ return false;
+ }
+
+ // Query if we can drop here and set mouse cursor appropriately.
+ if (activeGlyphDropHandler.CanDrop (lineAndColumn.Item1, lineAndColumn.Item2)) {
+ // We can drop here. Use "hand" cursor.
+ //TODO:MAC
+ //Mouse.OverrideCursor = Cursors.Hand;
+ } else {
+ // Can't drop here; change mouse cursor.
+ //TODO:MAC
+ //Mouse.OverrideCursor = Cursors.No;
+ }
+
+ // if the view does not have any focus, grab it
+ if (!textViewHost.TextView.HasAggregateFocus) {
+ textViewHost.TextView.VisualElement.BecomeFirstResponder ();
+ }
+
+ // Position the drag/drop caret and ensure it's visible.
+ ITextViewLine textViewLine = GetTextViewLine (viewPoint.Y);
+ viewPrimitives.Caret.AdvancedCaret.MoveTo (textViewLine, viewPoint.X);
+
+ this.EnsureCaretVisibleWithPadding ();
+
+ return true;
+ }
+
+ private void EnsureCaretVisibleWithPadding ()
+ {
+ // ensure caret is visible with a little padding to all sides.
+ ITextViewLine caretLine = viewPrimitives.Caret.AdvancedCaret.ContainingTextViewLine;
+ double padding = Math.Max (0.0, (textViewHost.TextView.ViewportHeight - caretLine.Height) * 0.5);
+
+ // Ensure vertical padding.
+ double topSpace = caretLine.Top - (textViewHost.TextView.ViewportTop + VerticalScrollTolerance);
+ double bottomSpace = (textViewHost.TextView.ViewportBottom - VerticalScrollTolerance) - caretLine.Bottom;
+
+ if ((topSpace < 0.0) != (bottomSpace < 0.0)) {
+ if (topSpace < 0.0) {
+ textViewHost.TextView.DisplayTextLineContainingBufferPosition (caretLine.Start, Math.Min (VerticalScrollTolerance, padding), ViewRelativePosition.Top);
+ } else {
+ textViewHost.TextView.DisplayTextLineContainingBufferPosition (caretLine.Start, Math.Min (VerticalScrollTolerance, padding), ViewRelativePosition.Bottom);
+ }
+ }
+
+ // Ensure horizontal padding
+ double leftSpace = viewPrimitives.Caret.AdvancedCaret.Left - (textViewHost.TextView.ViewportLeft + HorizontalScrollTolerance);
+ double rightSpace = (textViewHost.TextView.ViewportRight - HorizontalScrollTolerance) - viewPrimitives.Caret.AdvancedCaret.Right;
+
+ if ((leftSpace < 0.0) != (rightSpace < 0.0)) {
+ if (leftSpace < 0.0) {
+ textViewHost.TextView.ViewportLeft = viewPrimitives.Caret.AdvancedCaret.Left - Math.Min (HorizontalScrollTolerance, rightSpace);
+ } else {
+ textViewHost.TextView.ViewportLeft = (viewPrimitives.Caret.AdvancedCaret.Right + Math.Min (HorizontalScrollTolerance, leftSpace)) - textViewHost.TextView.ViewportWidth;
+ }
+ }
+ }
+
+ internal bool HandleDragEnd (CGPoint viewPoint)
+ {
+ // Clean up our dragging state.
+ //glyphMargin.VisualElement.ReleaseMouseCapture();
+ //Mouse.OverrideCursor = null;
+
+ IActiveGlyphDropHandler glyphDropHandler = activeGlyphDropHandler;
+ activeGlyphDropHandler = null;
+
+ // Did we actually do a drag?
+ if (!dragOccurred) {
+ return false;
+ }
+
+ dragOccurred = false;
+
+ if (glyphDropHandler != null) {
+ Tuple<int, int> lineAndColumn = GetLineNumberAndColumn (viewPoint);
+
+ // If this line isn't in the data (surface) buffer, we can't use it
+ if (lineAndColumn.Item1 < 0) {
+ return false;
+ }
+
+ // Query if we can drop here.
+ if (glyphDropHandler.CanDrop (lineAndColumn.Item1, lineAndColumn.Item2)) {
+ glyphDropHandler.DropAtLocation (lineAndColumn.Item1, lineAndColumn.Item2);
+ }
+ }
+
+ // Even if we couldn't drop here, we return true to ensure that we don't handle this as a normal click.
+ return true;
+ }
+
+ private bool HandleMarkerClick (MouseEvent e)
+ {
+ // Raise MarkerCommandValues.mcvGlyphSingleClickCommand
+ if (ExecuteMarkerCommand (glyphMargin.VisualElement.ConvertPointFromView (e.Event.LocationInWindow, null),
+ GlyphCommandType.SingleClick)) {
+ return true;
+ }
+
+ // Also, make sure that this point in the margin maps to a line/column in the correct buffer. In
+ // certain projection scenarios, this span may not be in the data buffer.
+ Tuple<int, int> lineCol = GetLineNumberAndColumn (GetMouseLocationInTextView (e));
+ if (lineCol.Item1 < 0) {
+ return false;
+ }
+
+ return ToggleBreakpoint (lineCol.Item1, lineCol.Item2);
+ }
+
+ private bool ToggleBreakpoint (int line, int column)
+ {
+ var buffer = textViewHost.TextView.TextBuffer;
+ var path = buffer.GetFilePathOrNull ();
+ if (path == null)
+ return false;
+ DebuggingService.Breakpoints.Toggle (path, line + 1, column + 1);
+ return true;
+ }
+
+ #endregion
+
+ #region Private Helpers
+
+ private CGPoint GetMouseLocationInTextView (MouseEvent e)
+ {
+ ICocoaTextView textView = textViewHost.TextView;
+ var pt = textView.VisualElement.ConvertPointFromView (e.Event.LocationInWindow, null);
+ pt.Y += (nfloat)textView.ViewportTop;
+ pt.X += (nfloat)textView.ViewportLeft;
+
+ return pt;
+ }
+
+ private ITextViewLine GetTextViewLine (double y)
+ {
+ ICocoaTextView textView = textViewHost.TextView;
+
+ // Establish line for point
+ ITextViewLine textViewLine = textView.TextViewLines.GetTextViewLineContainingYCoordinate (y);
+ if (textViewLine == null) {
+ textViewLine = y <= textView.TextViewLines [0].Top ?
+ textView.TextViewLines.FirstVisibleLine :
+ textView.TextViewLines.LastVisibleLine;
+ }
+
+ return textViewLine;
+ }
+
+ private static SnapshotPoint GetBufferPosition (ITextViewLine textViewLine, double x)
+ {
+ SnapshotPoint? bufferPosition = textViewLine.GetBufferPositionFromXCoordinate (x);
+ if (!bufferPosition.HasValue) {
+ bufferPosition = x < textViewLine.TextLeft ? textViewLine.Start : textViewLine.End;
+ }
+
+ return bufferPosition.Value;
+ }
+
+ private Tuple<int, int> GetLineNumberAndColumn (CGPoint viewPoint)
+ {
+ int line = 0;
+ int col = 0;
+
+ ITextViewLine textViewLine = GetTextViewLine (viewPoint.Y);
+ if (textViewLine != null) {
+ // The line number should be the line number in the data buffer,
+ // which is the text buffer adapter's surface buffer
+ var dataSpans = textViewLine.ExtentAsMappingSpan.GetSpans (textViewHost.TextView.TextViewModel.DataBuffer);
+
+ // If this point doesn't map into the data buffer at all, then return line
+ // number of -1 to indicate failure
+ if (dataSpans.Count == 0) {
+ return Tuple.Create (-1, -1);
+ }
+
+ line = dataSpans [0].Start.GetContainingLine ().LineNumber;
+ }
+
+ // Establish col for point
+ int bufferPosition = GetBufferPosition (textViewLine, viewPoint.X);
+ col = bufferPosition - textViewLine.Start;
+
+ return Tuple.Create (line, col);
+ }
+
+ // Internal for unit testing
+ internal bool ExecuteMarkerCommand (CGPoint pt, GlyphCommandType markerCommand)
+ {
+ bool commandHandled = false;
+
+ pt.Y += (nfloat)textViewHost.TextView.ViewportTop;
+
+ ITextViewLine textLine = textViewHost.TextView.TextViewLines.GetTextViewLineContainingYCoordinate (pt.Y);
+ if (textLine == null) {
+ return commandHandled;
+ }
+
+ // Tags are sorted from low priority to high priority
+ IInteractiveGlyph highestPriorityTag = null;
+ foreach (IInteractiveGlyph textMarkerTag in GetTextMarkerGlyphTagsStartingOnLine (textLine)) {
+ // only consider visible glyph markers.
+ if (textMarkerTag.IsEnabled) {
+ highestPriorityTag = textMarkerTag;
+ }
+ }
+
+ if (highestPriorityTag != null && highestPriorityTag.ExecuteCommand (markerCommand)) {
+ // Only handle the highest priority command
+ commandHandled = true;
+ }
+
+ return commandHandled;
+ }
+
+ private void EnableToolTips ()
+ {
+ if (mouseHoverTimer == null) {
+ mouseHoverTimer = new DispatcherTimer (
+ TimeSpan.FromMilliseconds (ToolTipDelayMilliseconds),
+ DispatcherPriority.Normal,
+ OnHoverTimer,
+ Dispatcher.CurrentDispatcher);
+ }
+
+ mouseHoverTimer.Start ();
+ }
+
+ private void DisableToolTips ()
+ {
+ if (mouseHoverTimer != null) {
+ mouseHoverTimer.Stop ();
+ }
+
+ HideTooltip ();
+ lastHoverPosition = null;
+ }
+
+ private void OnHoverTimer (object sender, EventArgs e)
+ {
+ // It's possible the view was closed before our timer triggered, in which case
+ // _glyphMargin is disposed and we can't touch it.
+ if (textViewHost.IsClosed) {
+ return;
+ }
+
+ if ((NSEvent.CurrentPressedMouseButtons & 1) > 0) {
+ return; // don't show tooltips when button is pressed (e.g. during a drag)
+ }
+ //TODO:MAC, convert mouse location
+ HoverAtPoint (NSEvent.CurrentMouseLocation);
+ }
+
+ // internal for exposure to unit tests
+ internal void HoverAtPoint (CGPoint pt)
+ {
+ // The HoverAtPoint calls get dispatched to the UI thread and you can imagine rare scenarios where
+ // either multiple calls get queued up (and, possibly, execute after the view has lost focus and
+ // the mouse hover has been disabled). Only execute if we still have a running mouse timer.
+ if ((mouseHoverTimer != null) && mouseHoverTimer.IsEnabled && glyphMargin.Enabled && !dragOccurred) {
+ ITextViewLine textLine = textViewHost.TextView.TextViewLines.GetTextViewLineContainingYCoordinate (pt.Y + textViewHost.TextView.ViewportTop);
+ if (textLine != lastHoverPosition) {
+ lastHoverPosition = textLine;
+
+ // Get textmarkers
+ if (textLine != null) {
+ // Tags are returned in lowest to highest priority order
+ // Keep track of highest priority tip text
+ string tipText = null;
+ foreach (IInteractiveGlyph textMarkerGlyphTag in GetTextMarkerGlyphTagsStartingOnLine (textLine)) {
+ tipText = textMarkerGlyphTag.TooltipText;
+ }
+ //TODO:MAC
+ //if (!string.IsNullOrEmpty(tipText))
+ //{
+ // popup.Child = null;
+
+ // TextBlock textBlock = new TextBlock();
+ // textBlock.Text = tipText;
+ // textBlock.Name = "GlyphToolTip";
+
+ // Border border = new Border();
+ // border.Padding = new Thickness(1);
+ // border.BorderThickness = new Thickness(1);
+ // border.Child = textBlock;
+
+ // // set colors of the tooltip to shell's defined colors
+ // textBlock.SetResourceReference(TextBlock.ForegroundProperty, "VsBrush.ScreenTipText");
+ // border.SetResourceReference(Border.BorderBrushProperty, "VsBrush.ScreenTipBorder");
+ // border.SetResourceReference(Border.BackgroundProperty, "VsBrush.ScreenTipBackground");
+
+ // popup.Child = border;
+ // popup.Placement = PlacementMode.Relative;
+ // popup.PlacementTarget = glyphMargin.VisualElement;
+ // popup.HorizontalOffset = 0.0;
+ // popup.VerticalOffset = textLine.Bottom - textViewHost.TextView.ViewportTop;
+ // popup.IsOpen = true;
+ // popup.Visibility = Visibility.Visible;
+
+ // currentlyHoveringLine = textLine;
+ //}
+ }
+ }
+ }
+ }
+
+ private void HideTooltip ()
+ {
+ //TODO:MAC
+ //popup.Child = null;
+ //popup.IsOpen = false;
+ //popup.Visibility = Visibility.Hidden;
+ }
+
+ // helper method to get the text marker tags starting on a line.
+ private IEnumerable<IInteractiveGlyph> GetTextMarkerGlyphTagsStartingOnLine (ITextViewLine textViewLine)
+ {
+ var visualBuffer = textViewHost.TextView.TextViewModel.VisualBuffer;
+ var editBuffer = textViewHost.TextView.TextBuffer;
+
+ // Tags are sorted from low priority to high priority
+ foreach (var mappingTagSpan in glyphTagAggregator.GetTags (textViewLine.ExtentAsMappingSpan)) {
+ // Only take tag spans with a visible start point and that map to something
+ // in the edit buffer, and the markers that *start* on this line
+
+ IInteractiveGlyph textMarkerGlyphTag = mappingTagSpan.Tag as IInteractiveGlyph;
+
+ if (textMarkerGlyphTag == null) {
+ continue;
+ }
+
+ SnapshotPoint? pointInVisualBuffer = mappingTagSpan.Span.Start.GetPoint (
+ visualBuffer,
+ PositionAffinity.Predecessor);
+ SnapshotPoint? pointInEditBuffer = mappingTagSpan.Span.Start.GetPoint (
+ editBuffer,
+ PositionAffinity.Predecessor);
+
+ if (!(pointInVisualBuffer.HasValue && pointInEditBuffer.HasValue)) {
+ continue;
+ }
+
+ if (pointInEditBuffer.Value >= textViewLine.Start &&
+ pointInEditBuffer.Value <= textViewLine.End) {
+ yield return textMarkerGlyphTag;
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphMouseProcessorProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphMouseProcessorProvider.cs
new file mode 100644
index 0000000000..29390386e3
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphMouseProcessorProvider.cs
@@ -0,0 +1,31 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IGlyphMouseProcessorProvider))]
+ [Name ("BreakpointGlyphMouseProcessorProvider")]
+ [Order]
+ [ContentType ("any")]
+ public class BreakpointGlyphMouseProcessorProvider : IGlyphMouseProcessorProvider
+ {
+ [Import]
+ private IViewTagAggregatorFactoryService viewTagAggregatorService = null;
+
+ [Import]
+ private IEditorPrimitivesFactoryService editorPrimitivesFactoryService = null;
+
+ public ICocoaMouseProcessor GetAssociatedMouseProcessor (
+ ICocoaTextViewHost wpfTextViewHost,
+ ICocoaTextViewMargin margin)
+ {
+ return new BreakpointGlyphMouseProcessor (
+ wpfTextViewHost,
+ margin,
+ viewTagAggregatorService.CreateTagAggregator<IGlyphTag> (wpfTextViewHost.TextView),
+ editorPrimitivesFactoryService.GetViewPrimitives (wpfTextViewHost.TextView));
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTag.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTag.cs
new file mode 100644
index 0000000000..a051d11df3
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTag.cs
@@ -0,0 +1,89 @@
+using System.Windows.Input;
+using AppKit;
+using Microsoft.VisualStudio.Text.Editor;
+using Mono.Debugging.Client;
+using MonoDevelop.Debugger;
+using MonoDevelop.Ide.Gui;
+
+namespace MonoDevelop.Debugger
+{
+ class BreakpointGlyphTag : BaseBreakpointGlyphTag
+ {
+ public BreakpointGlyphTag (BreakEvent breakpoint) : base (breakpoint)
+ {
+ }
+ }
+ class BreakpointDisabledGlyphTag : BaseBreakpointGlyphTag
+ {
+ public BreakpointDisabledGlyphTag (BreakEvent breakpoint) : base (breakpoint)
+ {
+ }
+ }
+ class BreakpointInvalidGlyphTag : BaseBreakpointGlyphTag
+ {
+ public BreakpointInvalidGlyphTag (BreakEvent breakpoint) : base (breakpoint)
+ {
+ }
+ }
+ class TracepointGlyphTag : BaseBreakpointGlyphTag
+ {
+ public TracepointGlyphTag (BreakEvent breakpoint) : base (breakpoint)
+ {
+ }
+ }
+ class TracepointDisabledGlyphTag : BaseBreakpointGlyphTag
+ {
+ public TracepointDisabledGlyphTag (BreakEvent breakpoint) : base (breakpoint)
+ {
+ }
+ }
+ class TracepointInvalidGlyphTag : BaseBreakpointGlyphTag
+ {
+ public TracepointInvalidGlyphTag (BreakEvent breakpoint) : base (breakpoint)
+ {
+ }
+ }
+
+ abstract class BaseBreakpointGlyphTag : IGlyphTag, IInteractiveGlyph
+ {
+ private readonly BreakEvent breakpoint;
+
+ public BaseBreakpointGlyphTag (BreakEvent breakpoint)
+ {
+ this.breakpoint = breakpoint;
+ }
+
+ public NSCursor HoverCursor {
+ get {
+ return null;
+ }
+ }
+
+ public IActiveGlyphDropHandler DropHandler {
+ get {
+ return null;
+ }
+ }
+
+ public bool IsEnabled {
+ get {
+ return true;
+ }
+ }
+
+ public bool ExecuteCommand (GlyphCommandType markerCommand)
+ {
+ if (markerCommand == GlyphCommandType.SingleClick) {
+ DebuggingService.Breakpoints.Remove (breakpoint);
+ return true;
+ }
+ return false;
+ }
+
+ public string TooltipText {
+ get {
+ return null;
+ }
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTagger.cs
new file mode 100644
index 0000000000..bab58a6d67
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTagger.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Mono.Debugging.Client;
+using MonoDevelop.Debugger;
+
+namespace MonoDevelop.Debugger
+{
+ internal class BreakpointGlyphTagger : ITagger<BaseBreakpointGlyphTag>
+ {
+ private readonly ITextView textView;
+ private readonly ITextDocumentFactoryService textDocumentFactoryService;
+
+ public BreakpointGlyphTagger (ITextDocumentFactoryService textDocumentFactoryService, ITextView textView)
+ {
+ this.textView = textView;
+ this.textDocumentFactoryService = textDocumentFactoryService;
+ DebuggingService.Breakpoints.Changed += OnBreakpointsChanged;
+ this.textView.Closed += (s, e) => DebuggingService.Breakpoints.Changed -= OnBreakpointsChanged;
+ }
+
+ private void OnBreakpointsChanged (object sender, EventArgs eventArgs)
+ {
+ if (TagsChanged != null) {
+ var snapshot = textView.TextBuffer.CurrentSnapshot;
+ var snapshotSpan = new SnapshotSpan (snapshot, 0, snapshot.Length);
+ var args = new SnapshotSpanEventArgs (snapshotSpan);
+ TagsChanged (this, args);
+ }
+ }
+
+ public IEnumerable<ITagSpan<BaseBreakpointGlyphTag>> GetTags (NormalizedSnapshotSpanCollection spans)
+ {
+ var found = textDocumentFactoryService.TryGetTextDocument (textView.TextBuffer, out var document);
+ if (!found || document.FilePath == null)
+ yield break;
+
+ foreach (var breakpoint in DebuggingService.Breakpoints.GetBreakpointsAtFile (document.FilePath)) {
+ var span = textView.TextBuffer.CurrentSnapshot.GetLineFromLineNumber (breakpoint.Line - 1).Extent;
+ if (spans.IntersectsWith (span)) {
+ bool tracepoint = (breakpoint.HitAction & HitAction.Break) == HitAction.None;
+ if (breakpoint.Enabled) {
+ var status = DebuggingService.GetBreakpointStatus (breakpoint);
+ if (status == BreakEventStatus.Bound || status == BreakEventStatus.Disconnected) {
+ if (tracepoint)
+ yield return new TagSpan<TracepointGlyphTag> (span, new TracepointGlyphTag (breakpoint));
+ else
+ yield return new TagSpan<BreakpointGlyphTag> (span, new BreakpointGlyphTag (breakpoint));
+ } else {
+ if (tracepoint)
+ yield return new TagSpan<TracepointInvalidGlyphTag> (span, new TracepointInvalidGlyphTag (breakpoint));
+ else
+ yield return new TagSpan<BreakpointInvalidGlyphTag> (span, new BreakpointInvalidGlyphTag (breakpoint));
+ }
+ } else {
+ if (tracepoint)
+ yield return new TagSpan<TracepointDisabledGlyphTag> (span, new TracepointDisabledGlyphTag (breakpoint));
+ else
+ yield return new TagSpan<BreakpointDisabledGlyphTag> (span, new BreakpointDisabledGlyphTag (breakpoint));
+ }
+ }
+ }
+ }
+
+ public event System.EventHandler<SnapshotSpanEventArgs> TagsChanged;
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTaggerProvider.cs
new file mode 100644
index 0000000000..4463b5024e
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/BreakpointGlyphTaggerProvider.cs
@@ -0,0 +1,27 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IViewTaggerProvider))]
+ [ContentType ("code")]
+ [TagType (typeof (BreakpointGlyphTag))]
+ [TagType (typeof (BreakpointDisabledGlyphTag))]
+ [TagType (typeof (BreakpointInvalidGlyphTag))]
+ [TagType (typeof (TracepointGlyphTag))]
+ [TagType (typeof (TracepointDisabledGlyphTag))]
+ [TagType (typeof (TracepointInvalidGlyphTag))]
+ internal class BreakpointGlyphTaggerProvider : IViewTaggerProvider
+ {
+ [Import]
+ public ITextDocumentFactoryService TextDocumentFactoryService { get; set; }
+
+ public ITagger<T> CreateTagger<T> (ITextView textView, ITextBuffer buffer) where T : ITag
+ {
+ return new BreakpointGlyphTagger (TextDocumentFactoryService, textView) as ITagger<T>;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphFactoryProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphFactoryProvider.cs
new file mode 100644
index 0000000000..49b9bd0fea
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphFactoryProvider.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.Composition;
+using Microsoft.Ide.Editor;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IGlyphFactoryProvider))]
+ [Name ("CurrentStatementGlyph")]
+ [Order (After = "BreakpointGlyph")]
+ [ContentType ("code")]
+ [TagType (typeof (CurrentStatementGlyphTag))]
+ internal class CurrentStatementGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory (ICocoaTextView view, ICocoaTextViewMargin margin)
+ {
+ return new ImageSourceGlyphFactory<CurrentStatementGlyphTag> ("md-gutter-execution");
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTag.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTag.cs
new file mode 100644
index 0000000000..58d596e087
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTag.cs
@@ -0,0 +1,9 @@
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace MonoDevelop.Debugger
+{
+ internal class CurrentStatementGlyphTag : IGlyphTag
+ {
+ public static readonly CurrentStatementGlyphTag Instance = new CurrentStatementGlyphTag ();
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTagger.cs
new file mode 100644
index 0000000000..9f0874cbea
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTagger.cs
@@ -0,0 +1,12 @@
+using Microsoft.VisualStudio.Text;
+
+namespace MonoDevelop.Debugger
+{
+ internal class CurrentStatementGlyphTagger : AbstractCurrentStatementTagger<CurrentStatementGlyphTag>
+ {
+ public CurrentStatementGlyphTagger (ITextBuffer textBuffer)
+ : base (CurrentStatementGlyphTag.Instance, textBuffer, isGreen: false)
+ {
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTaggerProvider.cs
new file mode 100644
index 0000000000..bfa1425db7
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/CurrentStatementGlyphTaggerProvider.cs
@@ -0,0 +1,19 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IViewTaggerProvider))]
+ [ContentType ("code")]
+ [TagType (typeof (CurrentStatementGlyphTag))]
+ internal class CurrentStatementGlyphTaggerProvider : IViewTaggerProvider
+ {
+ public ITagger<T> CreateTagger<T> (ITextView textView, ITextBuffer buffer) where T : ITag
+ {
+ return new CurrentStatementGlyphTagger (buffer) as ITagger<T>;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/GlyphCommandType.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/GlyphCommandType.cs
new file mode 100644
index 0000000000..6dd9dd8095
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/GlyphCommandType.cs
@@ -0,0 +1,8 @@
+namespace MonoDevelop.Debugger
+{
+ public enum GlyphCommandType
+ {
+ SingleClick,
+ RightClick
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/IActiveGlyphDropHandler.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/IActiveGlyphDropHandler.cs
new file mode 100644
index 0000000000..ddb02bda0e
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/IActiveGlyphDropHandler.cs
@@ -0,0 +1,8 @@
+namespace MonoDevelop.Debugger
+{
+ public interface IActiveGlyphDropHandler
+ {
+ bool CanDrop (int line, int column);
+ void DropAtLocation (int line, int column);
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/IInteractiveGlyph.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/IInteractiveGlyph.cs
new file mode 100644
index 0000000000..fa4a94a435
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/IInteractiveGlyph.cs
@@ -0,0 +1,13 @@
+using AppKit;
+
+namespace MonoDevelop.Debugger
+{
+ public interface IInteractiveGlyph
+ {
+ NSCursor HoverCursor { get; }
+ IActiveGlyphDropHandler DropHandler { get; }
+ bool IsEnabled { get; }
+ bool ExecuteCommand (GlyphCommandType markerCommand);
+ string TooltipText { get; }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ImageSourceGlyphFactory.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ImageSourceGlyphFactory.cs
new file mode 100644
index 0000000000..1465ab11e6
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ImageSourceGlyphFactory.cs
@@ -0,0 +1,32 @@
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Formatting;
+using AppKit;
+using Microsoft.VisualStudio.Core.Imaging;
+using MonoDevelop.Ide;
+
+namespace Microsoft.Ide.Editor
+{
+ public class ImageSourceGlyphFactory<T> : IGlyphFactory
+ where T : IGlyphTag
+ {
+ private readonly string imageSource;
+
+ public ImageSourceGlyphFactory (string imageSource)
+ {
+ this.imageSource = imageSource;
+ }
+
+ public object GenerateGlyph (ICocoaFormattedLine line, IGlyphTag tag)
+ {
+ if (tag == null || !(tag is T) || imageSource == null) {
+ return null;
+ }
+ Xwt.Drawing.Image xwtImage = ImageService.GetIcon (imageSource);
+ var nsImage = (NSImage)Xwt.Toolkit.NativeEngine.GetNativeImage (xwtImage);
+
+ var imageView = NSImageView.FromImage (nsImage);
+ imageView.SetFrameSize (imageView.FittingSize);
+ return imageView;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphFactoryProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphFactoryProvider.cs
new file mode 100644
index 0000000000..e1ede8d823
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphFactoryProvider.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.Composition;
+using Microsoft.Ide.Editor;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IGlyphFactoryProvider))]
+ [Name ("ReturnStatementGlyph")]
+ [Order (After = "CurrentStatementGlyph")]
+ [ContentType ("code")]
+ [TagType (typeof (ReturnStatementGlyphTag))]
+ internal class ReturnStatementGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory (ICocoaTextView view, ICocoaTextViewMargin margin)
+ {
+ return new ImageSourceGlyphFactory<ReturnStatementGlyphTag> ("md-gutter-stack");
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTag.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTag.cs
new file mode 100644
index 0000000000..796d6e6341
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTag.cs
@@ -0,0 +1,9 @@
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace MonoDevelop.Debugger
+{
+ internal class ReturnStatementGlyphTag : IGlyphTag
+ {
+ public static readonly ReturnStatementGlyphTag Instance = new ReturnStatementGlyphTag ();
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTagger.cs
new file mode 100644
index 0000000000..14a8782866
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTagger.cs
@@ -0,0 +1,12 @@
+using Microsoft.VisualStudio.Text;
+
+namespace MonoDevelop.Debugger
+{
+ internal class ReturnStatementGlyphTagger : AbstractCurrentStatementTagger<ReturnStatementGlyphTag>
+ {
+ public ReturnStatementGlyphTagger (ITextBuffer textBuffer)
+ : base (ReturnStatementGlyphTag.Instance, textBuffer, isGreen: true)
+ {
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTaggerProvider.cs
new file mode 100644
index 0000000000..7ce5db1223
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Glyphs/ReturnStatementGlyphTaggerProvider.cs
@@ -0,0 +1,19 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IViewTaggerProvider))]
+ [ContentType ("code")]
+ [TagType (typeof (ReturnStatementGlyphTag))]
+ internal class ReturnStatementGlyphTaggerProvider : IViewTaggerProvider
+ {
+ public ITagger<T> CreateTagger<T> (ITextView textView, ITextBuffer buffer) where T : ITag
+ {
+ return new ReturnStatementGlyphTagger (buffer) as ITagger<T>;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/DebuggerQuickInfoSource.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/DebuggerQuickInfoSource.cs
new file mode 100644
index 0000000000..6a022b56d0
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/DebuggerQuickInfoSource.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.Language.Intellisense;
+using Microsoft.VisualStudio.Text;
+using MonoDevelop.Core;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace MonoDevelop.Debugger.VSTextView.QuickInfo
+{
+ class DebuggerQuickInfoSource : IAsyncQuickInfoSource
+ {
+ readonly DebuggerQuickInfoSourceProvider provider;
+ readonly ITextBuffer textBuffer;
+ DebugValueWindow window;
+
+ public DebuggerQuickInfoSource (DebuggerQuickInfoSourceProvider provider, ITextBuffer textBuffer)
+ {
+ this.provider = provider;
+ this.textBuffer = textBuffer;
+ DebuggingService.CurrentFrameChanged += CurrentFrameChanged;
+ DebuggingService.StoppedEvent += TargetProcessExited;
+ }
+
+ void CurrentFrameChanged (object sender, EventArgs e)
+ {
+ if (window != null) {
+ window.Destroy ();
+ window = null;
+ }
+ }
+
+ void TargetProcessExited (object sender, EventArgs e)
+ {
+ if (window == null)
+ return;
+ var debuggerSession = window.tree.Frame?.DebuggerSession;
+ if (debuggerSession == null || debuggerSession == sender) {
+ window.Destroy ();
+ window = null;
+ }
+ }
+
+ public void Dispose ()
+ {
+ if (window != null)
+ Runtime.RunInMainThread (() => {
+ window?.Destroy ();
+ window = null;
+ }).Ignore ();
+ }
+
+ public async Task<QuickInfoItem> GetQuickInfoItemAsync (IAsyncQuickInfoSession session, CancellationToken cancellationToken)
+ {
+ Task destroyTask = null;
+ if (window != null)
+ destroyTask = Runtime.RunInMainThread (() => {
+ window?.Destroy ();
+ window = null;
+ });
+ if (DebuggingService.CurrentFrame == null)
+ return null;
+ var view = session.TextView;
+
+ var textViewLines = view.TextViewLines;
+ var snapshot = textViewLines.FormattedSpan.Snapshot;
+ var triggerPoint = session.GetTriggerPoint (textBuffer);
+ var point = triggerPoint.GetPoint (snapshot);
+
+ foreach (var debugInfoProvider in provider.debugInfoProviders) {
+ var debugInfo = await debugInfoProvider.Value.GetDebugInfoAsync (point);
+ if (debugInfo == null || debugInfo.Text == null) {
+ continue;
+ }
+
+ var options = DebuggingService.DebuggerSession.EvaluationOptions.Clone ();
+ options.AllowMethodEvaluation = true;
+ options.AllowTargetInvoke = true;
+
+ var val = DebuggingService.CurrentFrame.GetExpressionValue (debugInfo.Text, options);
+
+ if (val == null || val.IsUnknown || val.IsNotSupported)
+ return null;
+
+ if (!view.Properties.TryGetProperty (typeof (Gtk.Widget), out Gtk.Widget gtkParent))
+ return null;
+ provider.textDocumentFactoryService.TryGetTextDocument (textBuffer, out var textDocument);
+
+ // This is a bit hacky, since AsyncQuickInfo is designed to display multiple elements if multiple sources
+ // return value, we don't want that for debugger value hovering, hence we dismiss AsyncQuickInfo
+ // and do our own thing, notice VS does same thing
+ await session.DismissAsync ();
+ if (destroyTask != null)
+ await destroyTask;
+ await provider.joinableTaskContext.Factory.SwitchToMainThreadAsync ();
+ val.Name = debugInfo.Text;
+ window = new DebugValueWindow ((Gtk.Window)gtkParent.Toplevel, textDocument?.FilePath, textBuffer.CurrentSnapshot.GetLineNumberFromPosition (debugInfo.Span.GetStartPoint (textBuffer.CurrentSnapshot)), DebuggingService.CurrentFrame, val, null);
+ Ide.IdeApp.CommandService.RegisterTopWindow (window);
+ var bounds = view.TextViewLines.GetCharacterBounds (point);
+ var cocoaView = ((ICocoaTextView)view);
+ var cgPoint = cocoaView.VisualElement.ConvertPointToView (new CoreGraphics.CGPoint (bounds.Left - view.ViewportLeft, bounds.Top - view.ViewportTop), cocoaView.VisualElement.Superview);
+ cgPoint.Y = cocoaView.VisualElement.Superview.Frame.Height - cgPoint.Y;
+ window.ShowPopup (gtkParent, new Gdk.Rectangle ((int)cgPoint.X, (int)cgPoint.Y, (int)bounds.Width, (int)bounds.Height), Components.PopupPosition.TopLeft);
+ return null;
+ }
+ return null;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/DebuggerQuickInfoSourceProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/DebuggerQuickInfoSourceProvider.cs
new file mode 100644
index 0000000000..4eb135299f
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/DebuggerQuickInfoSourceProvider.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Language.Intellisense;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Threading;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger.VSTextView.QuickInfo
+{
+ [Export (typeof (IAsyncQuickInfoSourceProvider))]
+ [Name ("MonodevelopDebugger")]
+ [Order]
+ [ContentType ("any")]
+ class DebuggerQuickInfoSourceProvider : IAsyncQuickInfoSourceProvider
+ {
+ [ImportMany]
+ internal IEnumerable<Lazy<IDebugInfoProvider>> debugInfoProviders = null;
+
+ [Import]
+ internal ITextDocumentFactoryService textDocumentFactoryService { get; set; }
+
+ [Import]
+ internal JoinableTaskContext joinableTaskContext;
+
+ public IAsyncQuickInfoSource TryCreateQuickInfoSource (ITextBuffer textBuffer)
+ {
+ return new DebuggerQuickInfoSource (this, textBuffer);
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/IDebugInfoProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/IDebugInfoProvider.cs
new file mode 100644
index 0000000000..e9d41b9034
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/IDebugInfoProvider.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.Text;
+
+namespace MonoDevelop.Debugger.VSTextView.QuickInfo
+{
+ public interface IDebugInfoProvider
+ {
+ Task<DataTipInfo> GetDebugInfoAsync (SnapshotPoint snapshotPoint);
+ }
+
+ public class DataTipInfo
+ {
+ public readonly ITrackingSpan Span;
+ public readonly string Text;
+
+ public DataTipInfo (ITrackingSpan span, string text)
+ {
+ this.Span = span;
+ this.Text = text;
+ }
+
+ public bool IsDefault {
+ get { return Span == null && Text == null; }
+ }
+
+ public override string ToString () => $"{Span} {Text}";
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/AbstractBreakpointTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/AbstractBreakpointTagger.cs
new file mode 100644
index 0000000000..a8d09fe388
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/AbstractBreakpointTagger.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Mono.Debugging.Client;
+using MonoDevelop.Debugger;
+using MonoDevelop.Ide;
+
+namespace MonoDevelop.Debugger
+{
+ internal abstract class AbstractBreakpointTagger<T> : ITagger<T> where T : ITag
+ {
+ private readonly ITextView textView;
+ private readonly T tag;
+ private readonly T disabled;
+ private readonly T invalid;
+ private readonly string file;
+
+ public AbstractBreakpointTagger (
+ T tag, T disabled, T invalid, ITextView textView)
+ {
+ this.textView = textView;
+ this.tag = tag;
+ this.disabled = disabled;
+ this.invalid = invalid;
+ file = this.textView.TextBuffer.GetFilePathOrNull ();
+ DebuggingService.Breakpoints.Changed += OnBreakpointsChanged;
+ this.textView.Closed += (s, e) => DebuggingService.Breakpoints.Changed -= OnBreakpointsChanged;
+ }
+
+ private void OnBreakpointsChanged (object sender, EventArgs eventArgs)
+ {
+ if (TagsChanged != null) {
+ var snapshot = textView.TextBuffer.CurrentSnapshot;
+ var snapshotSpan = new SnapshotSpan (snapshot, 0, snapshot.Length);
+ var args = new SnapshotSpanEventArgs (snapshotSpan);
+ TagsChanged (this, args);
+ }
+ }
+
+ public IEnumerable<ITagSpan<T>> GetTags (NormalizedSnapshotSpanCollection spans)
+ {
+ if (file == null)
+ yield break;
+ foreach (var breakpoint in DebuggingService.Breakpoints.GetBreakpointsAtFile (file)) {
+ var snapshot = textView.TextBuffer.CurrentSnapshot;
+ if (snapshot.LineCount <= breakpoint.Line)
+ continue;
+ var span = snapshot.GetLineFromLineNumber (breakpoint.Line - 1).Extent;
+ if (spans.IntersectsWith (span)) {
+ var status = DebuggingService.GetBreakpointStatus (breakpoint);
+ if (breakpoint.Enabled)
+ if (status == BreakEventStatus.Bound || status == BreakEventStatus.Disconnected)
+ yield return new TagSpan<T> (span, tag);
+ else
+ yield return new TagSpan<T> (span, invalid);
+ else
+ yield return new TagSpan<T> (span, disabled);
+ }
+ }
+ }
+
+ public event System.EventHandler<SnapshotSpanEventArgs> TagsChanged;
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/AbstractCurrentStatementTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/AbstractCurrentStatementTagger.cs
new file mode 100644
index 0000000000..e80acf8286
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/AbstractCurrentStatementTagger.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.Ide.Editor;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Tagging;
+using MonoDevelop.Debugger;
+using MonoDevelop.Ide.Editor;
+using MonoDevelop.Ide;
+
+namespace MonoDevelop.Debugger
+{
+ internal class AbstractCurrentStatementTagger<T> : ITagger<T>, IDisposable
+ where T : ITag
+ {
+ private readonly ITextBuffer textBuffer;
+ private readonly T tag;
+ private readonly string filePath;
+ private readonly bool isGreen;
+
+ public AbstractCurrentStatementTagger (T tag, ITextBuffer textBuffer, bool isGreen)
+ {
+ this.textBuffer = textBuffer;
+ this.filePath = textBuffer.GetFilePathOrNull ();
+ this.tag = tag;
+ this.isGreen = isGreen;
+ DebuggingService.CurrentFrameChanged += OnDebuggerCurrentStatementChanged;
+ }
+
+ private void OnDebuggerCurrentStatementChanged (object sender, EventArgs eventArgs)
+ {
+ var handler = TagsChanged;
+ if (handler != null) {
+ var snapshot = textBuffer.CurrentSnapshot;
+ var snapshotSpan = new SnapshotSpan (snapshot, 0, snapshot.Length);
+ var args = new SnapshotSpanEventArgs (snapshotSpan);
+ handler (this, args);
+ }
+ }
+
+ public IEnumerable<ITagSpan<T>> GetTags (NormalizedSnapshotSpanCollection spans)
+ {
+ if (DebuggingService.CurrentCallStack == null)
+ yield break;
+ if (isGreen) {
+ if (DebuggingService.CurrentFrameIndex > 0) {
+ var newTag = CreateTag (DebuggingService.CurrentFrameIndex);
+ if (newTag != null && spans.IntersectsWith (newTag.Span))
+ yield return newTag;
+ }
+ } else {
+ if (DebuggingService.CurrentFrameIndex == 0) {
+ var newTag = CreateTag (0);
+ if (newTag != null && spans.IntersectsWith (newTag.Span))
+ yield return newTag;
+ }
+ }
+ }
+
+ private TagSpan<T> CreateTag (int stackIndex)
+ {
+ var sourceLocation = DebuggingService.CurrentCallStack.GetFrame (stackIndex).SourceLocation;
+ if (sourceLocation.FileName != filePath)
+ return null;
+ var span = textBuffer.CurrentSnapshot.SpanFromMDColumnAndLine (sourceLocation.Line, sourceLocation.Column, sourceLocation.EndLine, sourceLocation.EndColumn);
+ return new TagSpan<T> (span, tag);
+ }
+
+ public void Dispose ()
+ {
+ DebuggingService.CurrentFrameChanged -= OnDebuggerCurrentStatementChanged;
+ }
+
+ public event System.EventHandler<SnapshotSpanEventArgs> TagsChanged;
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointForegroundTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointForegroundTagger.cs
new file mode 100644
index 0000000000..c1cd77c406
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointForegroundTagger.cs
@@ -0,0 +1,17 @@
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+
+namespace MonoDevelop.Debugger
+{
+ internal class BreakpointForegroundTagger : AbstractBreakpointTagger<ClassificationTag>
+ {
+ public BreakpointForegroundTagger (
+ ClassificationTag tag,
+ ClassificationTag disabled,
+ ClassificationTag invalid,
+ ITextView textView)
+ : base (tag, disabled, invalid, textView)
+ {
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointForegroundTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointForegroundTaggerProvider.cs
new file mode 100644
index 0000000000..859eea7658
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointForegroundTaggerProvider.cs
@@ -0,0 +1,32 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IViewTaggerProvider))]
+ [TagType (typeof (IClassificationTag))]
+ [ContentType ("text")]
+ public class BreakpointForegroundTaggerProvider : IViewTaggerProvider
+ {
+ private readonly ClassificationTag tag;
+ private readonly ClassificationTag disabled;
+ private readonly ClassificationTag invalid;
+
+ [ImportingConstructor]
+ public BreakpointForegroundTaggerProvider (IClassificationTypeRegistryService classificationTypeRegistryService)
+ {
+ tag = new ClassificationTag (classificationTypeRegistryService.GetClassificationType (ClassificationTypes.BreakpointForegroundTypeName));
+ disabled = new ClassificationTag (classificationTypeRegistryService.GetClassificationType (ClassificationTypes.BreakpointDisabledForegroundTypeName));
+ invalid = new ClassificationTag (classificationTypeRegistryService.GetClassificationType (ClassificationTypes.BreakpointInvalidForegroundTypeName));
+ }
+
+ public ITagger<T> CreateTagger<T> (ITextView textView, ITextBuffer buffer) where T : ITag
+ {
+ return new BreakpointForegroundTagger (tag, disabled, invalid, textView) as ITagger<T>;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointMarkerDefinition.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointMarkerDefinition.cs
new file mode 100644
index 0000000000..21176ceefb
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointMarkerDefinition.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.Composition;
+using System.Windows.Media;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (EditorFormatDefinition))]
+ [Name (BreakpointTag.TagId)]
+ [UserVisible (true)]
+ [Priority (1)] // necessary to override the standard one from TextMarkerProviderFactory.cs
+ internal class BreakpointMarkerDefinition : MarkerFormatDefinition
+ {
+ public BreakpointMarkerDefinition ()
+ {
+ this.ZOrder = 2;
+ this.Fill = new SolidColorBrush (Color.FromArgb (204, 150, 58, 70));
+ this.Fill.Freeze ();
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTag.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTag.cs
new file mode 100644
index 0000000000..ea29de1367
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTag.cs
@@ -0,0 +1,40 @@
+using Microsoft.VisualStudio.Text.Tagging;
+
+namespace MonoDevelop.Debugger
+{
+ class BreakpointTag : TextMarkerTag
+ {
+ internal const string TagId = "breakpoint";
+
+ public static readonly BreakpointTag Instance = new BreakpointTag ();
+
+ private BreakpointTag ()
+ : base (TagId)
+ {
+ }
+ }
+
+ class BreakpointDisabledTag : TextMarkerTag
+ {
+ internal const string TagId = "breakpoint-disabled";
+
+ public static readonly BreakpointDisabledTag Instance = new BreakpointDisabledTag ();
+
+ private BreakpointDisabledTag ()
+ : base (TagId)
+ {
+ }
+ }
+
+ class BreakpointInvalidTag : TextMarkerTag
+ {
+ internal const string TagId = "breakpoint-invalid";
+
+ public static readonly BreakpointInvalidTag Instance = new BreakpointInvalidTag ();
+
+ private BreakpointInvalidTag ()
+ : base (TagId)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTagger.cs
new file mode 100644
index 0000000000..62b40f8473
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTagger.cs
@@ -0,0 +1,13 @@
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+
+namespace MonoDevelop.Debugger
+{
+ internal class BreakpointTagger : AbstractBreakpointTagger<TextMarkerTag>
+ {
+ public BreakpointTagger (ITextView textView)
+ : base (BreakpointTag.Instance, BreakpointDisabledTag.Instance, BreakpointInvalidTag.Instance, textView)
+ {
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTaggerProvider.cs
new file mode 100644
index 0000000000..410512eb78
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/BreakpointTaggerProvider.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IViewTaggerProvider))]
+ [ContentType ("text")]
+ [TagType (typeof (BreakpointTag))]
+ [TagType (typeof (BreakpointDisabledTag))]
+ [TagType (typeof (BreakpointInvalidTag))]
+ internal class BreakpointTaggerProvider : IViewTaggerProvider
+ {
+ public ITagger<T> CreateTagger<T> (ITextView textView, ITextBuffer buffer) where T : ITag
+ {
+ return new BreakpointTagger (textView) as ITagger<T>;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ClassificationTypes.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ClassificationTypes.cs
new file mode 100644
index 0000000000..84cd73f54e
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ClassificationTypes.cs
@@ -0,0 +1,118 @@
+using System.ComponentModel.Composition;
+using System.Windows.Media;
+using Microsoft.VisualStudio.Language.StandardClassification;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ public class ClassificationTypes
+ {
+ public const string BreakpointForegroundTypeName = "BreakpointForeground";
+ public const string BreakpointDisabledForegroundTypeName = "BreakpointDisabledForeground";
+ public const string BreakpointInvalidForegroundTypeName = "BreakpointInvalidForeground";
+ public const string CurrentStatementForegroundTypeName = "CurrentStatementForeground";
+ public const string ReturnStatementForegroundTypeName = "ReturnStatementForeground";
+
+ [Export]
+ [Name (BreakpointForegroundTypeName)]
+ [BaseDefinition (PredefinedClassificationTypeNames.FormalLanguage)]
+ internal readonly ClassificationTypeDefinition BreakpointForegroundTypeDefinition = null;
+
+ [Export (typeof (EditorFormatDefinition))]
+ [ClassificationType (ClassificationTypeNames = BreakpointForegroundTypeName)]
+ [Name (BreakpointForegroundTypeName + "Format")]
+ [Order (After = LanguagePriority.FormalLanguage, Before = Priority.High)]
+ [UserVisible (true)]
+ private sealed class BreakpointForegroundClassificationFormat
+ : ClassificationFormatDefinition
+ {
+ private BreakpointForegroundClassificationFormat ()
+ {
+ this.DisplayName = BreakpointForegroundTypeName;
+ this.ForegroundColor = Colors.White;
+ }
+ }
+
+
+ [Export]
+ [Name (BreakpointDisabledForegroundTypeName)]
+ [BaseDefinition (PredefinedClassificationTypeNames.FormalLanguage)]
+ internal readonly ClassificationTypeDefinition BreakpointDisabledForegroundTypeDefinition = null;
+
+ [Export (typeof (EditorFormatDefinition))]
+ [ClassificationType (ClassificationTypeNames = BreakpointDisabledForegroundTypeName)]
+ [Name (BreakpointDisabledForegroundTypeName + "Format")]
+ [Order (After = LanguagePriority.FormalLanguage, Before = Priority.High)]
+ [UserVisible (true)]
+ private sealed class BreakpointDisabledForegroundClassificationFormat
+ : ClassificationFormatDefinition
+ {
+ private BreakpointDisabledForegroundClassificationFormat ()
+ {
+ this.DisplayName = BreakpointDisabledForegroundTypeName;
+ this.ForegroundColor = Colors.White;
+ }
+ }
+
+ [Export]
+ [Name (BreakpointInvalidForegroundTypeName)]
+ [BaseDefinition (PredefinedClassificationTypeNames.FormalLanguage)]
+ internal readonly ClassificationTypeDefinition BreakpointInvalidForegroundTypeDefinition = null;
+
+ [Export (typeof (EditorFormatDefinition))]
+ [ClassificationType (ClassificationTypeNames = BreakpointInvalidForegroundTypeName)]
+ [Name (BreakpointInvalidForegroundTypeName + "Format")]
+ [Order (After = LanguagePriority.FormalLanguage, Before = Priority.High)]
+ [UserVisible (true)]
+ private sealed class BreakpointInvalidForegroundClassificationFormat
+ : ClassificationFormatDefinition
+ {
+ private BreakpointInvalidForegroundClassificationFormat ()
+ {
+ this.DisplayName = BreakpointInvalidForegroundTypeName;
+ this.ForegroundColor = Colors.White;
+ }
+ }
+
+ [Export]
+ [Name (CurrentStatementForegroundTypeName)]
+ [BaseDefinition (PredefinedClassificationTypeNames.FormalLanguage)]
+ internal readonly ClassificationTypeDefinition CurrentStatementForegroundTypeDefinition = null;
+
+ [Export (typeof (EditorFormatDefinition))]
+ [ClassificationType (ClassificationTypeNames = CurrentStatementForegroundTypeName)]
+ [Name (CurrentStatementForegroundTypeName + "Format")]
+ [Order (After = LanguagePriority.FormalLanguage, Before = Priority.High)]
+ [UserVisible (true)]
+ private sealed class CurrentStatementForegroundClassificationFormat
+ : ClassificationFormatDefinition
+ {
+ private CurrentStatementForegroundClassificationFormat ()
+ {
+ this.DisplayName = CurrentStatementForegroundTypeName;
+ this.ForegroundColor = Colors.Black;
+ }
+ }
+
+ [Export]
+ [Name (ReturnStatementForegroundTypeName)]
+ [BaseDefinition (PredefinedClassificationTypeNames.FormalLanguage)]
+ internal readonly ClassificationTypeDefinition ReturnStatementForegroundTypeDefinition = null;
+
+ [Export (typeof (EditorFormatDefinition))]
+ [ClassificationType (ClassificationTypeNames = ReturnStatementForegroundTypeName)]
+ [Name (ReturnStatementForegroundTypeName + "Format")]
+ [Order (After = LanguagePriority.FormalLanguage, Before = Priority.High)]
+ [UserVisible (true)]
+ private sealed class ReturnStatementForegroundClassificationFormat
+ : ClassificationFormatDefinition
+ {
+ private ReturnStatementForegroundClassificationFormat ()
+ {
+ this.DisplayName = ReturnStatementForegroundTypeName;
+ this.ForegroundColor = Colors.Black;
+ }
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementForegroundTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementForegroundTagger.cs
new file mode 100644
index 0000000000..124b48f806
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementForegroundTagger.cs
@@ -0,0 +1,16 @@
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Tagging;
+
+namespace MonoDevelop.Debugger
+{
+ internal class CurrentStatementForegroundTagger : AbstractCurrentStatementTagger<ClassificationTag>
+ {
+ public CurrentStatementForegroundTagger (
+ ClassificationTag tag,
+ ITextBuffer textBuffer,
+ bool isGreen)
+ : base (tag, textBuffer, isGreen)
+ {
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementForegroundTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementForegroundTaggerProvider.cs
new file mode 100644
index 0000000000..655582c63d
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementForegroundTaggerProvider.cs
@@ -0,0 +1,32 @@
+using System.ComponentModel.Composition;
+using Microsoft.Ide.Editor;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (ITaggerProvider))]
+ [TagType (typeof (IClassificationTag))]
+ [ContentType ("text")]
+ public class CurrentStatementForegroundTaggerProvider : ITaggerProvider
+ {
+ private readonly IClassificationTypeRegistryService classificationTypeRegistryService;
+ private readonly IClassificationType classificationType;
+ private readonly ClassificationTag tag;
+
+ [ImportingConstructor]
+ public CurrentStatementForegroundTaggerProvider (IClassificationTypeRegistryService classificationTypeRegistryService)
+ {
+ this.classificationTypeRegistryService = classificationTypeRegistryService;
+ this.classificationType = classificationTypeRegistryService.GetClassificationType (ClassificationTypes.CurrentStatementForegroundTypeName);
+ this.tag = new ClassificationTag (classificationType);
+ }
+
+ public ITagger<T> CreateTagger<T> (ITextBuffer buffer) where T : ITag
+ {
+ return new CurrentStatementForegroundTagger (tag, buffer, isGreen: false) as ITagger<T>;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementMarkerDefinition.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementMarkerDefinition.cs
new file mode 100644
index 0000000000..f0adbc69bc
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementMarkerDefinition.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.Composition;
+using System.Windows.Media;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (EditorFormatDefinition))]
+ [Name (CurrentStatementTag.TagId)]
+ [UserVisible (true)]
+ [Priority (1)]
+ internal class CurrentStatementMarkerDefinition : MarkerFormatDefinition
+ {
+ public CurrentStatementMarkerDefinition ()
+ {
+ this.ZOrder = 3;
+ this.Fill = new SolidColorBrush (Color.FromArgb (255, 255, 238, 98));
+ this.Fill.Freeze ();
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTag.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTag.cs
new file mode 100644
index 0000000000..857b89c678
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTag.cs
@@ -0,0 +1,16 @@
+using Microsoft.VisualStudio.Text.Tagging;
+
+namespace MonoDevelop.Debugger
+{
+ internal class CurrentStatementTag : TextMarkerTag
+ {
+ internal const string TagId = "currentstatement";
+
+ public static readonly CurrentStatementTag Instance = new CurrentStatementTag ();
+
+ private CurrentStatementTag ()
+ : base (TagId)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTagger.cs
new file mode 100644
index 0000000000..bab3493fe9
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTagger.cs
@@ -0,0 +1,12 @@
+using Microsoft.VisualStudio.Text;
+
+namespace MonoDevelop.Debugger
+{
+ internal class CurrentStatementTagger : AbstractCurrentStatementTagger<CurrentStatementTag>
+ {
+ public CurrentStatementTagger (ITextBuffer textBuffer)
+ : base (CurrentStatementTag.Instance, textBuffer, isGreen: false)
+ {
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTaggerProvider.cs
new file mode 100644
index 0000000000..ad385fa208
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/CurrentStatementTaggerProvider.cs
@@ -0,0 +1,19 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IViewTaggerProvider))]
+ [ContentType ("text")]
+ [TagType (typeof (CurrentStatementTag))]
+ internal class CurrentStatementTaggerProvider : IViewTaggerProvider
+ {
+ public ITagger<T> CreateTagger<T> (ITextView textView, ITextBuffer buffer) where T : ITag
+ {
+ return new CurrentStatementTagger (buffer) as ITagger<T>;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementForegroundTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementForegroundTaggerProvider.cs
new file mode 100644
index 0000000000..5809d218a2
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementForegroundTaggerProvider.cs
@@ -0,0 +1,31 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (ITaggerProvider))]
+ [TagType (typeof (IClassificationTag))]
+ [ContentType ("text")]
+ public class ReturnStatementForegroundTaggerProvider : ITaggerProvider
+ {
+ private readonly IClassificationTypeRegistryService classificationTypeRegistryService;
+ private readonly IClassificationType classificationType;
+ private readonly ClassificationTag tag;
+
+ [ImportingConstructor]
+ public ReturnStatementForegroundTaggerProvider (IClassificationTypeRegistryService classificationTypeRegistryService)
+ {
+ this.classificationTypeRegistryService = classificationTypeRegistryService;
+ this.classificationType = classificationTypeRegistryService.GetClassificationType (ClassificationTypes.ReturnStatementForegroundTypeName);
+ this.tag = new ClassificationTag (classificationType);
+ }
+
+ public ITagger<T> CreateTagger<T> (ITextBuffer buffer) where T : ITag
+ {
+ return new CurrentStatementForegroundTagger (tag, buffer, isGreen: true) as ITagger<T>;
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementMarkerDefinition.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementMarkerDefinition.cs
new file mode 100644
index 0000000000..f978353661
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementMarkerDefinition.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.Composition;
+using System.Windows.Media;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (EditorFormatDefinition))]
+ [Name (ReturnStatementTag.TagId)]
+ [UserVisible (true)]
+ [Priority (1)]
+ internal class ReturnStatementMarkerDefinition : MarkerFormatDefinition
+ {
+ public ReturnStatementMarkerDefinition ()
+ {
+ this.ZOrder = 4;
+ this.Fill = new SolidColorBrush (Color.FromArgb (255, 180, 228, 180));
+ this.Fill.Freeze ();
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTag.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTag.cs
new file mode 100644
index 0000000000..ca2ac54eb9
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTag.cs
@@ -0,0 +1,16 @@
+using Microsoft.VisualStudio.Text.Tagging;
+
+namespace MonoDevelop.Debugger
+{
+ internal class ReturnStatementTag : TextMarkerTag
+ {
+ internal const string TagId = "returnstatement";
+
+ public static readonly ReturnStatementTag Instance = new ReturnStatementTag ();
+
+ private ReturnStatementTag ()
+ : base (TagId)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTagger.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTagger.cs
new file mode 100644
index 0000000000..f2d1e94149
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTagger.cs
@@ -0,0 +1,12 @@
+using Microsoft.VisualStudio.Text;
+
+namespace MonoDevelop.Debugger
+{
+ internal class ReturnStatementTagger : AbstractCurrentStatementTagger<ReturnStatementTag>
+ {
+ public ReturnStatementTagger (ITextBuffer textBuffer)
+ : base (ReturnStatementTag.Instance, textBuffer, isGreen: true)
+ {
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTaggerProvider.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTaggerProvider.cs
new file mode 100644
index 0000000000..e5ac8feb86
--- /dev/null
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/Tags/ReturnStatementTaggerProvider.cs
@@ -0,0 +1,19 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace MonoDevelop.Debugger
+{
+ [Export (typeof (IViewTaggerProvider))]
+ [ContentType ("text")]
+ [TagType (typeof (ReturnStatementTag))]
+ internal class ReturnStatementTaggerProvider : IViewTaggerProvider
+ {
+ public ITagger<T> CreateTagger<T> (ITextView textView, ITextBuffer buffer) where T : ITag
+ {
+ return new ReturnStatementTagger (buffer) as ITagger<T>;
+ }
+ }
+}