/
WacomTranslationDatabaseHighlighter.cs
144 lines (129 loc) · 4.89 KB
/
WacomTranslationDatabaseHighlighter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows.Media;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
using System.Diagnostics;
namespace WacomTranslationDatabaseHighlighter
{
internal sealed class Components
{
// Map ".utf8" extension to the content-type
[Export]
[FileExtension(".utf8")]
[ContentType("wacom.tdb")]
internal FileExtensionToContentTypeDefinition utf8FileExtensionDefinition = null;
// Metadata about content type
[Export]
[Name("wacom.tdb")]
[BaseDefinition("text")]
internal static ContentTypeDefinition utf8ContentTypeDefinition = null;
}
#region Provider definition
/// <summary>
/// This class causes a classifier to be added to the set of classifiers. Since
/// the content type is set to "text", this classifier applies to all text files
/// </summary>
[Export(typeof(IClassifierProvider))]
[ContentType("wacom.tdb")]
internal class WacomTranslationDatabaseHighlighterProvider : IClassifierProvider
{
/// <summary>
/// Import the classification registry to be used for getting a reference
/// to the custom classification type later.
/// </summary>
[Import]
internal IClassificationTypeRegistryService ClassificationRegistry = null; // Set via MEF
public IClassifier GetClassifier(ITextBuffer buffer)
{
return buffer.Properties.GetOrCreateSingletonProperty<WacomTranslationDatabaseHighlighter>(delegate { return new WacomTranslationDatabaseHighlighter(ClassificationRegistry); });
}
}
#endregion //provider def
#region Classifier
/// <summary>
/// Classifier that classifies all text as an instance of the OrinaryClassifierType
/// </summary>
class WacomTranslationDatabaseHighlighter : IClassifier
{
// Types for key and value
IClassificationType _keyType;
IClassificationType _valType;
IClassificationType _sepType;
IClassificationType _errType;
internal WacomTranslationDatabaseHighlighter(IClassificationTypeRegistryService registry)
{
_keyType = registry.GetClassificationType("wacom.tdb.key");
_valType = registry.GetClassificationType("wacom.tdb.value");
_sepType = registry.GetClassificationType("wacom.tdb.separator");
_errType = registry.GetClassificationType("wacom.tdb.error");
}
/// <summary>
/// This method scans the given SnapshotSpan for potential matches for this classification.
/// In this instance, it classifies everything and returns each span as a new ClassificationSpan.
/// </summary>
/// <param name="trackingSpan">The span currently being classified</param>
/// <returns>A list of ClassificationSpans that represent spans identified to be of this classification</returns>
public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
{
//create a list to hold the results
List<ClassificationSpan> classifications = new List<ClassificationSpan>();
if (span.Snapshot.Length == 0)
return classifications;
int startline = span.Start.GetContainingLine().LineNumber;
int endline = (span.End - 1).GetContainingLine().LineNumber;
for (int i = startline; i <= endline; i++)
{
ITextSnapshotLine line = span.Snapshot.GetLineFromLineNumber(i);
string text = line.GetText();
int linelen = text.Length;
int tabpos = text.IndexOf('\t');
if (tabpos < 0)
{
// No tab, call the entire line an error
classifications.Add(new ClassificationSpan(line.Extent, _errType));
continue;
}
if (tabpos == 0)
{
// Tab at start of line means no key.
classifications.Add(new ClassificationSpan(
new SnapshotSpan(line.Snapshot, new Span(line.Start, 1)),
_errType));
}
if (tabpos > 0)
{
classifications.Add(new ClassificationSpan(
new SnapshotSpan(line.Snapshot, new Span(line.Start, tabpos)),
_keyType));
classifications.Add(new ClassificationSpan(
new SnapshotSpan(line.Snapshot, new Span(line.Start + tabpos, 1)),
_sepType));
classifications.Add(new ClassificationSpan(
new SnapshotSpan(line.Snapshot,
new Span(line.Start + tabpos + 1, linelen - tabpos - 1)),
_valType));
}
int secondtabPosition = text.IndexOf('\t', tabpos + 1);
if (secondtabPosition > 0)
{
// Too many tabs, error starting with the second
classifications.Add(new ClassificationSpan(
new SnapshotSpan(line.Snapshot,
new Span(line.Start + secondtabPosition, linelen - secondtabPosition)),
_errType));
}
}
return classifications;
}
#pragma warning disable 67
// This event gets raised if a non-text change would affect the classification in some way,
// for example typing /* would cause the classification to change in C# without directly
// affecting the span.
public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;
#pragma warning restore 67
}
#endregion //Classifier
}