public
Description: A sample VS2010 extension that hilights the current line in the text editor
Homepage:
Clone URL: git://github.com/tomasr/LineAdornments.git
LineAdornments / LineHighlight.cs
100644 120 lines (108 sloc) 4.473 kb
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
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.Text.Classification;
 
namespace Winterdom.VisualStudio.Extensions.Text {
 
   public class LineHighlight {
      public const string NAME = "LineHighlight";
      public const string CUR_LINE_TAG = "currentLine";
      private IAdornmentLayer layer;
      private IWpfTextView view;
      private IClassificationFormatMap formatMap;
      private IClassificationType formatType;
      private Brush fillBrush;
      private Pen borderPen;
 
      public LineHighlight(
            IWpfTextView view, IClassificationFormatMap formatMap,
            IClassificationType formatType) {
         this.view = view;
         this.formatMap = formatMap;
         this.formatType = formatType;
         layer = view.GetAdornmentLayer(NAME);
 
         view.Caret.PositionChanged += OnCaretPositionChanged;
         view.ViewportWidthChanged += OnViewportWidthChanged;
         view.LayoutChanged += OnLayoutChanged;
         formatMap.ClassificationFormatMappingChanged +=
            OnClassificationFormatMappingChanged;
 
         CreateDrawingObjects();
      }
 
      void OnViewportWidthChanged(object sender, EventArgs e) {
         RedrawAdornments();
      }
      void OnClassificationFormatMappingChanged(object sender, EventArgs e) {
         // the user changed something in Fonts and Colors, so
         // recreate our addornments
         CreateDrawingObjects();
      }
      void OnCaretPositionChanged(object sender, CaretPositionChangedEventArgs e) {
         ITextViewLine newLine = GetLineByPos(e.NewPosition);
         ITextViewLine oldLine = GetLineByPos(e.OldPosition);
         if ( newLine != oldLine ) {
            layer.RemoveAdornmentsByTag(CUR_LINE_TAG);
            this.CreateVisuals(newLine);
         }
      }
      void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e) {
         SnapshotPoint caret = view.Caret.Position.BufferPosition;
         foreach ( var line in e.NewOrReformattedLines ) {
            if ( line.ContainsBufferPosition(caret) ) {
               this.CreateVisuals(line);
               break;
            }
         }
      }
 
      private void CreateDrawingObjects() {
         // this gets the color settings configured by the
         // user in Fonts and Colors (or the default in out
         // classification type).
         TextFormattingRunProperties format =
            formatMap.GetTextProperties(formatType);
 
         fillBrush = format.BackgroundBrush;
         Brush penBrush = format.ForegroundBrush;
         borderPen = new Pen(penBrush, 0.5);
         borderPen.Freeze();
         RedrawAdornments();
      }
      private void RedrawAdornments() {
         layer.RemoveAdornmentsByTag(CUR_LINE_TAG);
         var caret = view.Caret.Position;
         ITextViewLine line = GetLineByPos(caret);
         this.CreateVisuals(line);
      }
      private ITextViewLine GetLineByPos(CaretPosition pos) {
         return view.GetTextViewLineContainingBufferPosition(pos.BufferPosition);
      }
      private void CreateVisuals(ITextViewLine line) {
         IWpfTextViewLineCollection textViewLines = view.TextViewLines;
         if ( textViewLines == null )
            return; // not ready yet.
         SnapshotSpan span = line.SnapshotLine.Extent;
         Rect rc = new Rect(
            new Point(line.Left, line.Top),
            new Point(Math.Max(view.ViewportRight - 2, line.Right), line.Bottom)
         );
 
         Geometry g = new RectangleGeometry(rc, 1.0, 1.0);
         GeometryDrawing drawing = new GeometryDrawing(fillBrush, borderPen, g);
         drawing.Freeze();
         DrawingImage drawingImage = new DrawingImage(drawing);
         drawingImage.Freeze();
 
         Image image = new Image();
         // work around WPF rounding bug
         image.UseLayoutRounding = false;
         image.Source = drawingImage;
         //Align the image with the top of the bounds of the text geometry
         Canvas.SetLeft(image, g.Bounds.Left);
         Canvas.SetTop(image, g.Bounds.Top);
 
         layer.AddAdornment(
            AdornmentPositioningBehavior.TextRelative, span,
            CUR_LINE_TAG, image, null
         );
      }
   }
}