public
Description: A sample VS2010 extension that renders C# some keywords in a different color.
Homepage:
Clone URL: git://github.com/tomasr/KeywordClassifier.git
KeywordClassifier / KeywordTagger.cs
100644 110 lines (98 sloc) 4.413 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
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Utilities;
 
namespace Winterdom.VisualStudio.Extensions.Text {
 
   static class Constants {
      public const String CLASSIF_NAME = "FlowControl";
      public const String LINQ_CLASSIF_NAME = "LinqOperator";
      public const String VISIBILITY_CLASSIF_NAME = "VisibilityKeyword";
   }
 
[Export(typeof(IViewTaggerProvider))]
[ContentType(CSharp.ContentType)]
[ContentType(Cpp.ContentType)]
[TagType(typeof(ClassificationTag))]
   public class KeywordTaggerProvider : IViewTaggerProvider {
[Import]
      internal IClassificationTypeRegistryService ClassificationRegistry = null;
[Import]
      internal IBufferTagAggregatorFactoryService Aggregator = null;
 
      public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag {
         return new KeywordTagger(
            ClassificationRegistry,
            Aggregator.CreateTagAggregator<ClassificationTag>(buffer)
         ) as ITagger<T>;
      }
   }
 
   class KeywordTagger : ITagger<ClassificationTag> {
      private ClassificationTag keywordClassification;
      private ClassificationTag linqClassification;
      private ClassificationTag visClassification;
      private ITagAggregator<ClassificationTag> aggregator;
      private static readonly IList<ClassificationSpan> EmptyList =
         new List<ClassificationSpan>();
 
#pragma warning disable 67
      public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
#pragma warning restore 67
 
      internal KeywordTagger(
            IClassificationTypeRegistryService registry,
            ITagAggregator<ClassificationTag> aggregator) {
         keywordClassification =
            new ClassificationTag(registry.GetClassificationType(Constants.CLASSIF_NAME));
         linqClassification =
            new ClassificationTag(registry.GetClassificationType(Constants.LINQ_CLASSIF_NAME));
         visClassification =
            new ClassificationTag(registry.GetClassificationType(Constants.VISIBILITY_CLASSIF_NAME));
         this.aggregator = aggregator;
      }
 
      public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
         if ( spans.Count == 0 ) {
            yield break;
         }
         ITextSnapshot snapshot = spans[0].Snapshot;
         ILanguageKeywords keywords =
            GetKeywordsByContentType(snapshot.TextBuffer.ContentType);
         if ( keywords == null ) {
            yield break;
         }
 
         // find spans that the language service has already classified as keywords ...
         var mappedSpans =
            from tagSpan in aggregator.GetTags(spans)
            let name = tagSpan.Tag.ClassificationType.Classification.ToLower()
            where name.Contains("keyword")
            select tagSpan.Span;
         var classifiedSpans =
            from mappedSpan in mappedSpans
            let cs = mappedSpan.GetSpans(snapshot)
            where cs.Count > 0
            select cs[0];
 
         // ... and from those, ones that match our keywords
         foreach ( var cs in classifiedSpans ) {
            String text = cs.GetText();
            if ( keywords.ControlFlow.Contains(text) ) {
               yield return new TagSpan<ClassificationTag>(cs, keywordClassification);
            } else if ( keywords.Visibility.Contains(text) ) {
               yield return new TagSpan<ClassificationTag>(cs, visClassification);
            } else if ( keywords.Linq.Contains(text) ) {
               yield return new TagSpan<ClassificationTag>(cs, linqClassification);
            }
         }
      }
 
      private ILanguageKeywords GetKeywordsByContentType(IContentType contentType) {
         if ( contentType.IsOfType(CSharp.ContentType) ) {
            return new CSharp();
         } else if ( contentType.IsOfType(Cpp.ContentType) ) {
            return new Cpp();
         }
         // VS is calling us for the "CSharp Signature Help" content-type
         // which we didn't ask for. Argh!!!
         // throw new InvalidOperationException("Running into an unsupported editor");
         return null;
      }
   }
}