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

Last change on this file since 2131 was 2131, checked in by sam, 7 years ago

vslol: support Microsoft's int8, int16 etc. extensions.

File size: 10.6 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        "__(int(8|16|32|64)|ptr(32|64)|m(64|128|128d|128i))",
82    };
83
84    /* ldouble real half
85       "(f(16|128)||d|[ui](8|16||64)|r)(vec[234]|mat[234]|quat|cmplx)";
86     */
87
88    private static string[] m_csharp_types =
89    {
90        "var|string",
91        "out|ref|internal|sealed|public|private|protected|override"
92    };
93
94    private static string[] m_lolfx_types =
95    {
96        "attribute|varying|uniform|in|out",
97        "int|uint",
98        "(|[dui])(vec|mat)[234]"
99    };
100
101    private static string[] m_all_constants =
102    {
103        "true|false"
104    };
105
106    private static string[] m_cpp_constants =
107    {
108        "NULL|nullptr",
109        "EXIT_SUCCESS|EXIT_FAILURE",
110        "M_(E|LOG(2|10)E|LN2|LN10|PI|PI_2|PI_4|1_PI|2_PI|2_SQRTPI|SQRT(2|1_2))",
111        "SIG(HUP|INT|QUIT|ILL|TRAP|ABRT|FPE|KILL|USR1|SEGV|USR2|PIPE|ALRM)",
112        "SIG(TERM|CHLD|CONT|STOP|TSTP|TTIN|TTOU)"
113    };
114
115    private static string[] m_csharp_constants =
116    {
117        "null",
118    };
119
120    private static string[] m_lolfx_constants =
121    {
122        "gl_Position|gl_FragColor",
123    };
124
125    private static string[] m_all_normal =
126    {
127    };
128
129    private static string[] m_cpp_normal =
130    {
131        "interface|delegate|event|finally",
132        "gcnew|generic|initonly|property|sealed",
133    };
134
135    internal CppKeywordClassifier(IClassificationTypeRegistryService registry,
136                                  IClassifier classifier,
137                                  IContentType type)
138    {
139        m_classifier = classifier;
140
141        m_types_type = registry.GetClassificationType("LolAnyType");
142        m_normal_type = registry.GetClassificationType("LolAnyIdentifier");
143        m_constant_type = registry.GetClassificationType("LolAnyConstant");
144
145        List<string> types_list = m_all_types.ToList();
146        List<string> constants_list = m_all_constants.ToList();
147        List<string> normals_list = m_all_normal.ToList();
148
149        if (type.IsOfType("c/c++"))
150        {
151            types_list = types_list.Concat(m_cpp_types).ToList();
152            constants_list = constants_list.Concat(m_cpp_constants).ToList();
153            normals_list = normals_list.Concat(m_cpp_normal).ToList();
154        }
155
156        if (type.IsOfType("csharp"))
157        {
158            types_list = types_list.Concat(m_csharp_types).ToList();
159            constants_list = constants_list.Concat(m_csharp_constants).ToList();
160        }
161
162        if (type.IsOfType("lolfx"))
163        {
164            types_list = types_list.Concat(m_lolfx_types).ToList();
165            constants_list = constants_list.Concat(m_lolfx_constants).ToList();
166        }
167
168        m_types_regex =
169            new Regex("^(" + String.Join("|", types_list.ToArray()) + ")$");
170        m_constant_regex =
171            new Regex("^(" + String.Join("|", constants_list.ToArray()) + ")$");
172        m_normal_regex =
173            new Regex("^(" + String.Join("|", normals_list.ToArray()) + ")$");
174    }
175
176    public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
177    {
178        List<ClassificationSpan> ret = new List<ClassificationSpan>();
179
180        foreach (ClassificationSpan cs in m_classifier.GetClassificationSpans(span))
181        {
182            string cs_class = cs.ClassificationType.Classification.ToLower();
183
184            /* Only apply our rules if we found a keyword or an identifier */
185            if (cs_class == "keyword" || cs_class == "identifier")
186            {
187                if (m_types_regex.IsMatch(cs.Span.GetText()))
188                {
189                    ret.Add(new ClassificationSpan(cs.Span, m_types_type));
190                    continue;
191                }
192
193                if (m_constant_regex.IsMatch(cs.Span.GetText()))
194                {
195                    ret.Add(new ClassificationSpan(cs.Span, m_constant_type));
196                    continue;
197                }
198
199                if (m_normal_regex.IsMatch(cs.Span.GetText()))
200                {
201                    ret.Add(new ClassificationSpan(cs.Span, m_normal_type));
202                    continue;
203                }
204            }
205
206            ret.Add(cs);
207        }
208
209        return ret;
210    }
211
212    public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;
213}
214
215internal class LolGenericFormat : ClassificationFormatDefinition
216{
217    static IClassificationTypeRegistryService m_type_registry;
218    static IClassificationFormatMapService m_format_map;
219
220    public static void SetRegistry(IClassificationTypeRegistryService type_registry,
221                                   IClassificationFormatMapService format_map)
222    {
223        m_type_registry = type_registry;
224        m_format_map = format_map;
225    }
226
227    protected void CopyStyleColor(string category)
228    {
229        if (m_type_registry == null || m_format_map == null)
230            return;
231
232        var map = m_format_map.GetClassificationFormatMap("Text Editor");
233        if (map == null)
234            return;
235
236        //string[] foo = { "Comment", "Keyword", "C/C++ User Keywords", "Call Return", "HTML Comment" , "User Types", "User Types (Type parameters)", "User Types (Value types)"};
237
238        var type = m_type_registry.GetClassificationType(category);
239        if (type == null)
240            return;
241
242        var prop = map.GetExplicitTextProperties(type);
243        if (prop == null)
244            return;
245
246        var c1 = prop.ForegroundBrush as SolidColorBrush;
247        if (c1 != null && c1.Color != Colors.Transparent)
248        {
249            this.ForegroundColor = c1.Color;
250            this.ForegroundOpacity = 1.0;
251        }
252        var c2 = prop.BackgroundBrush as SolidColorBrush;
253        if (c2 != null && c2.Color != Colors.Transparent)
254        {
255            this.BackgroundColor = c2.Color;
256            this.BackgroundOpacity = 1.0;
257        }
258    }
259}
260
261internal static class LolClassifierClassificationDefinition
262{
263    [Export(typeof(ClassificationTypeDefinition))]
264    [Name(LolCppTypeFormat.m_name)]
265    internal static ClassificationTypeDefinition LolCustomClassType = null;
266
267    [Export(typeof(ClassificationTypeDefinition))]
268    [Name(LolCppConstantFormat.m_name)]
269    internal static ClassificationTypeDefinition LolCustomConstantType = null;
270
271    [Export(typeof(ClassificationTypeDefinition))]
272    [Name(LolCppIdentifierFormat.m_name)]
273    internal static ClassificationTypeDefinition LolCustomIdentifierType = null;
274}
275
276[Export(typeof(EditorFormatDefinition))]
277[ClassificationType(ClassificationTypeNames = LolCppTypeFormat.m_name)]
278[Name(LolCppTypeFormat.m_name)]
279[UserVisible(true)]
280[Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
281internal sealed class LolCppTypeFormat : LolGenericFormat
282{
283    public const string m_name = "LolAnyType";
284    public LolCppTypeFormat()
285    {
286        this.DisplayName = "C/C++ Types and Qualifiers (VsLol)";
287        this.ForegroundColor = Colors.Lime;
288        this.ForegroundOpacity = 1.0;
289        this.IsBold = true;
290        //CopyStyleColor("User Types");
291    }
292}
293
294[Export(typeof(EditorFormatDefinition))]
295[ClassificationType(ClassificationTypeNames = LolCppConstantFormat.m_name)]
296[Name(LolCppConstantFormat.m_name)]
297[UserVisible(true)]
298[Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
299internal sealed class LolCppConstantFormat : LolGenericFormat
300{
301    public const string m_name = "LolAnyConstant";
302    public LolCppConstantFormat()
303    {
304        this.DisplayName = "C/C++ Constants (VsLol)";
305        this.ForegroundColor = Colors.Magenta;
306        this.ForegroundOpacity = 1.0;
307        this.IsBold = true;
308        //CopyStyleColor("User Types");
309    }
310}
311
312[Export(typeof(EditorFormatDefinition))]
313[ClassificationType(ClassificationTypeNames = LolCppIdentifierFormat.m_name)]
314[Name(LolCppIdentifierFormat.m_name)]
315[UserVisible(true)]
316[Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
317internal sealed class LolCppIdentifierFormat : LolGenericFormat
318{
319    public const string m_name = "LolAnyIdentifier";
320    public LolCppIdentifierFormat()
321    {
322        this.DisplayName = "C/C++ Identifiers (VsLol)";
323        this.ForegroundColor = Colors.Silver;
324        this.ForegroundOpacity = 1.0;
325        this.IsBold = false;
326        CopyStyleColor(PredefinedClassificationTypeNames.Identifier);
327    }
328}
329
330} /* namespace lol */
Note: See TracBrowser for help on using the repository browser.