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

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

vslol: fix typo.

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