source: trunk/tools/vslol/CppKeywordClassifier.cs @ 2128

Last change on this file since 2128 was 2128, checked in by sam, 8 years ago

vslol: new feature: disable syntax highlighting for Microsoft "extensions"
that aren't exactly extensions and perfectly valid C++ identifiers.

File size: 10.5 KB
Line 
1//
2// Lol Engine - VsLol add-in for Visual Studio
3//
4// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://www.wtfpl.net/ for more details.
9//
10
11using System;
12using System.Linq;
13using System.Collections.Generic;
14using System.ComponentModel.Composition;
15using System.Windows.Media;
16using System.Text.RegularExpressions;
17
18using Microsoft.VisualStudio.Text;
19using Microsoft.VisualStudio.Text.Classification;
20using Microsoft.VisualStudio.Text.Formatting;
21using Microsoft.VisualStudio.Language.StandardClassification;
22using Microsoft.VisualStudio.Utilities;
23
24namespace lol
25{
26
27[Export(typeof(IClassifierProvider))]
28[ContentType("c/c++")]
29[ContentType("csharp")]
30[ContentType("lolfx")]
31internal class LolClassifierProvider : IClassifierProvider
32{
33    [Import]
34    internal IClassificationTypeRegistryService m_type_registry = null;
35    [Import]
36    internal IClassifierAggregatorService m_aggregator = null;
37    [Import]
38    internal IClassificationFormatMapService m_format_map = null;
39
40    internal static bool m_inprogress = false;
41
42    public IClassifier GetClassifier(ITextBuffer buffer)
43    {
44        /* Avoid infinite recursion */
45        if (m_inprogress)
46            return null;
47
48        LolGenericFormat.SetRegistry(m_type_registry, m_format_map);
49
50        try
51        {
52            m_inprogress = true;
53            return buffer.Properties.GetOrCreateSingletonProperty<CppKeywordClassifier>(delegate { return new CppKeywordClassifier(m_type_registry, m_aggregator.GetClassifier(buffer), buffer.ContentType); });
54        }
55        finally { m_inprogress = false; }
56    }
57}
58
59class CppKeywordClassifier : IClassifier
60{
61    private IClassifier m_classifier;
62
63    private IClassificationType m_types_type, m_constant_type, m_normal_type;
64    private Regex m_types_regex, m_constant_regex, m_normal_regex;
65
66    private static string[] m_all_types =
67    {
68        "void|bool|int|signed|unsigned|char|short|long|float|double",
69        "class|struct|union|template|namespace|typename|typedef",
70        "inline|restrict|export|explicit|mutable",
71        "static|register|auto|volatile|extern|const"
72    };
73
74    private static string[] m_cpp_types =
75    {
76        "u?int(8|16|32|64|ptr|max)_t",
77        "u?int_(least|fast)(8|16|32|64)_t",
78        "(wchar|char16|char32|size|ssize|off|ptrdiff)_t",
79        "(sig_atomic|fpos|clock|time|div|ldiv)_t",
80        "va_list|jmp_buf|FILE|DIR",
81    };
82
83    /* ldouble real half
84       "(f(16|128)||d|[ui](8|16||64)|r)(vec[234]|mat[234]|quat|cmplx)";
85     */
86
87    private static string[] m_csharp_types =
88    {
89        "var|string",
90        "out|ref|internal|sealed|public|private|protected|override"
91    };
92
93    private static string[] m_lolfx_types =
94    {
95        "attribute|varying|uniform|in|out",
96        "int|uint",
97        "(|[dui])(vec|mat)[234]"
98    };
99
100    private static string[] m_all_constants =
101    {
102        "true|false"
103    };
104
105    private static string[] m_cpp_constants =
106    {
107        "NULL|nullptr",
108        "EXIT_SUCCESS|EXIT_FAILURE",
109        "M_(E|LOG(2|10)E|LN2|LN10|PI|PI_2|PI_4|1_PI|2_PI|2_SQRTPI|SQRT(2|1_2))",
110        "SIG(HUP|INT|QUIT|ILL|TRAP|ABRT|FPE|KILL|USR1|SEGV|USR2|PIPE|ALRM)",
111        "SIG(TERM|CHLD|CONT|STOP|TSTP|TTIN|TTOU)"
112    };
113
114    private static string[] m_csharp_constants =
115    {
116        "null",
117    };
118
119    private static string[] m_lolfx_constants =
120    {
121        "gl_Position|gl_FragColor",
122    };
123
124    private static string[] m_all_normal =
125    {
126    };
127
128    private static string[] m_cpp_normal =
129    {
130        "interface|delegate|event|finally",
131        "gcnew|generic|initonly|property|sealed",
132    };
133
134    internal CppKeywordClassifier(IClassificationTypeRegistryService registry,
135                                  IClassifier classifier,
136                                  IContentType type)
137    {
138        m_classifier = classifier;
139
140        m_types_type = registry.GetClassificationType("LolAnyType");
141        m_normal_type = registry.GetClassificationType("LolAnyIdentifier");
142        m_constant_type = registry.GetClassificationType("LolAnyConstant");
143
144        List<string> types_list = m_all_types.ToList();
145        List<string> constants_list = m_all_constants.ToList();
146        List<string> normals_list = m_all_normal.ToList();
147
148        if (type.IsOfType("c/c++"))
149        {
150            types_list = types_list.Concat(m_cpp_types).ToList();
151            constants_list = constants_list.Concat(m_cpp_constants).ToList();
152            normals_list = normals_list.Concat(m_cpp_normal).ToList();
153        }
154
155        if (type.IsOfType("csharp"))
156        {
157            types_list = types_list.Concat(m_csharp_types).ToList();
158            constants_list = constants_list.Concat(m_csharp_constants).ToList();
159        }
160
161        if (type.IsOfType("lolfx"))
162        {
163            types_list = types_list.Concat(m_lolfx_types).ToList();
164            constants_list = constants_list.Concat(m_lolfx_constants).ToList();
165        }
166
167        m_types_regex =
168            new Regex("^(" + String.Join("|", types_list.ToArray()) + ")$");
169        m_constant_regex =
170            new Regex("^(" + String.Join("|", constants_list.ToArray()) + ")$");
171        m_normal_regex =
172            new Regex("^(" + String.Join("|", normals_list.ToArray()) + ")$");
173    }
174
175    public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
176    {
177        List<ClassificationSpan> ret = new List<ClassificationSpan>();
178
179        foreach (ClassificationSpan cs in m_classifier.GetClassificationSpans(span))
180        {
181            string cs_class = cs.ClassificationType.Classification.ToLower();
182
183            /* Only apply our rules if we found a keyword or an identifier */
184            if (cs_class == "keyword" || cs_class == "identifier")
185            {
186                if (m_types_regex.IsMatch(cs.Span.GetText()))
187                {
188                    ret.Add(new ClassificationSpan(cs.Span, m_types_type));
189                    continue;
190                }
191
192                if (m_constant_regex.IsMatch(cs.Span.GetText()))
193                {
194                    ret.Add(new ClassificationSpan(cs.Span, m_constant_type));
195                    continue;
196                }
197
198                if (m_normal_regex.IsMatch(cs.Span.GetText()))
199                {
200                    ret.Add(new ClassificationSpan(cs.Span, m_normal_type));
201                    continue;
202                }
203            }
204
205            ret.Add(cs);
206        }
207
208        return ret;
209    }
210
211    public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;
212}
213
214internal class LolGenericFormat : ClassificationFormatDefinition
215{
216    static IClassificationTypeRegistryService m_type_registry;
217    static IClassificationFormatMapService m_format_map;
218
219    public static void SetRegistry(IClassificationTypeRegistryService type_registry,
220                                   IClassificationFormatMapService format_map)
221    {
222        m_type_registry = type_registry;
223        m_format_map = format_map;
224    }
225
226    protected void CopyStyleColor(string category)
227    {
228        if (m_type_registry == null || m_format_map == null)
229            return;
230
231        var map = m_format_map.GetClassificationFormatMap("Text Editor");
232        if (map == null)
233            return;
234
235        //string[] foo = { "Comment", "Keyword", "C/C++ User Keywords", "Call Return", "HTML Comment" , "User Types", "User Types (Type parameters)", "User Types (Value types)"};
236
237        var type = m_type_registry.GetClassificationType(category);
238        if (type == null)
239            return;
240
241        var prop = map.GetExplicitTextProperties(type);
242        if (prop == null)
243            return;
244
245        var c1 = prop.ForegroundBrush as SolidColorBrush;
246        if (c1 != null && c1.Color != Colors.Transparent)
247        {
248            this.ForegroundColor = c1.Color;
249            this.ForegroundOpacity = 1.0;
250        }
251        var c2 = prop.BackgroundBrush as SolidColorBrush;
252        if (c2 != null && c2.Color != Colors.Transparent)
253        {
254            this.BackgroundColor = c2.Color;
255            this.BackgroundOpacity = 1.0;
256        }
257    }
258}
259
260internal static class LolClassifierClassificationDefinition
261{
262    [Export(typeof(ClassificationTypeDefinition))]
263    [Name(LolCppTypeFormat.m_name)]
264    internal static ClassificationTypeDefinition LolCustomClassType = null;
265
266    [Export(typeof(ClassificationTypeDefinition))]
267    [Name(LolCppConstantFormat.m_name)]
268    internal static ClassificationTypeDefinition LolCustomConstantType = null;
269
270    [Export(typeof(ClassificationTypeDefinition))]
271    [Name(LolCppIdentifierFormat.m_name)]
272    internal static ClassificationTypeDefinition LolCustomIdentifierType = null;
273}
274
275[Export(typeof(EditorFormatDefinition))]
276[ClassificationType(ClassificationTypeNames = LolCppTypeFormat.m_name)]
277[Name(LolCppTypeFormat.m_name)]
278[UserVisible(true)]
279[Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
280internal sealed class LolCppTypeFormat : LolGenericFormat
281{
282    public const string m_name = "LolAnyType";
283    public LolCppTypeFormat()
284    {
285        this.DisplayName = "C/C++ Types and Qualifiers (VsLol)";
286        this.ForegroundColor = Colors.Lime;
287        this.ForegroundOpacity = 1.0;
288        this.IsBold = true;
289        //CopyStyleColor("User Types");
290    }
291}
292
293[Export(typeof(EditorFormatDefinition))]
294[ClassificationType(ClassificationTypeNames = LolCppConstantFormat.m_name)]
295[Name(LolCppConstantFormat.m_name)]
296[UserVisible(true)]
297[Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
298internal sealed class LolCppConstantFormat : LolGenericFormat
299{
300    public const string m_name = "LolAnyConstant";
301    public LolCppConstantFormat()
302    {
303        this.DisplayName = "C/C++ Constants (VsLol)";
304        this.ForegroundColor = Colors.Magenta;
305        this.ForegroundOpacity = 1.0;
306        this.IsBold = true;
307        //CopyStyleColor("User Types");
308    }
309}
310
311[Export(typeof(EditorFormatDefinition))]
312[ClassificationType(ClassificationTypeNames = LolCppIdentifierFormat.m_name)]
313[Name(LolCppIdentifierFormat.m_name)]
314[UserVisible(true)]
315[Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
316internal sealed class LolCppIdentifierFormat : LolGenericFormat
317{
318    public const string m_name = "LolAnyIdentifier";
319    public LolCppIdentifierFormat()
320    {
321        this.DisplayName = "C/C++ Identifiers (VsLol)";
322        this.ForegroundColor = Colors.Silver;
323        this.ForegroundOpacity = 1.0;
324        this.IsBold = false;
325        CopyStyleColor(PredefinedClassificationTypeNames.Identifier);
326    }
327}
328
329} /* namespace lol */
Note: See TracBrowser for help on using the repository browser.