You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

234 lines
7.9 KiB

  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. using System;
  11. using System.Collections.Generic;
  12. using System.ComponentModel.Composition;
  13. using System.Windows.Media;
  14. using System.Text.RegularExpressions;
  15. using Microsoft.VisualStudio.Text;
  16. using Microsoft.VisualStudio.Text.Classification;
  17. using Microsoft.VisualStudio.Text.Formatting;
  18. using Microsoft.VisualStudio.Language.StandardClassification;
  19. using Microsoft.VisualStudio.Utilities;
  20. namespace lol
  21. {
  22. [Export(typeof(IClassifierProvider))]
  23. [ContentType("c/c++")]
  24. [ContentType("csharp")]
  25. [ContentType("lolfx")]
  26. internal class LolClassifierProvider : IClassifierProvider
  27. {
  28. [Import]
  29. internal IClassificationTypeRegistryService m_type_registry = null; /* Set via MEF */
  30. [Import]
  31. internal IClassifierAggregatorService m_aggregator = null;
  32. [Import]
  33. internal IClassificationFormatMapService m_format_map = null;
  34. internal static bool m_inprogress = false;
  35. public IClassifier GetClassifier(ITextBuffer buffer)
  36. {
  37. /* Avoid infinite recursion */
  38. if (m_inprogress)
  39. return null;
  40. LolGenericFormat.SetRegistry(m_type_registry, m_format_map);
  41. try
  42. {
  43. m_inprogress = true;
  44. return buffer.Properties.GetOrCreateSingletonProperty<CppKeywordClassifier>(delegate { return new CppKeywordClassifier(m_type_registry, m_aggregator.GetClassifier(buffer), buffer.ContentType); });
  45. }
  46. finally { m_inprogress = false; }
  47. }
  48. }
  49. class CppKeywordClassifier : IClassifier
  50. {
  51. private IClassifier m_classifier;
  52. private IClassificationType m_customclass_type, m_constant_type;
  53. private Regex m_customclass_regex, m_constant_regex;
  54. internal CppKeywordClassifier(IClassificationTypeRegistryService registry,
  55. IClassifier classifier,
  56. IContentType type)
  57. {
  58. m_classifier = classifier;
  59. /* Regex for types and specifiers */
  60. m_customclass_type = registry.GetClassificationType("LolCustomClass");
  61. string tmp = @"\b(";
  62. tmp += "void|bool|int|unsigned|char|short|long|float|double|ldouble|";
  63. tmp += "class|struct|union|template|const|static|extern|volatile|inline|namespace|";
  64. if (type.IsOfType("lolfx"))
  65. tmp += "attribute|varying|uniform|in|out|";
  66. if (type.IsOfType("csharp"))
  67. tmp += "var|out|ref|string|internal|sealed|public|private|protected|override|";
  68. if (!type.IsOfType("csharp"))
  69. tmp += "(f(16|128)||d|[ui](8|16||64)|r)(vec[234]|mat[234]|quat|cmplx)|";
  70. if (type.IsOfType("c/c++"))
  71. {
  72. tmp += "u?int(8|16|32|64|ptr)_t|";
  73. tmp += "(wchar|size|ssize)_t|";
  74. tmp += "real|half|explicit|typename|typedef|auto|";
  75. }
  76. tmp = tmp.Remove(tmp.Length - 1);
  77. tmp += @")\b";
  78. m_customclass_regex = new Regex(tmp);
  79. /* Regex for constant words */
  80. m_constant_type = registry.GetClassificationType("LolCppConstant");
  81. if (type.IsOfType("csharp"))
  82. m_constant_regex = new Regex(@"\b(null|true|false)\b");
  83. else if (type.IsOfType("c/c++"))
  84. m_constant_regex = new Regex(@"\b(NULL|nullptr|true|false|M_PI)\b");
  85. else if (type.IsOfType("lolfx"))
  86. m_constant_regex = new Regex(@"\b(gl_Position|gl_FragColor)\b");
  87. else
  88. m_constant_regex = new Regex(@"\b(NULL)\b");
  89. }
  90. public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
  91. {
  92. List<ClassificationSpan> ret = new List<ClassificationSpan>();
  93. foreach (ClassificationSpan cs in m_classifier.GetClassificationSpans(span))
  94. {
  95. string cs_class = cs.ClassificationType.Classification.ToLower();
  96. /* Only apply our rules if we found a keyword or an identifier */
  97. if (cs_class == "keyword" || cs_class == "identifier")
  98. {
  99. if (m_customclass_regex.IsMatch(cs.Span.GetText()))
  100. {
  101. ret.Add(new ClassificationSpan(cs.Span, m_customclass_type));
  102. continue;
  103. }
  104. if (m_constant_regex.IsMatch(cs.Span.GetText()))
  105. {
  106. ret.Add(new ClassificationSpan(cs.Span, m_constant_type));
  107. continue;
  108. }
  109. }
  110. ret.Add(cs);
  111. }
  112. return ret;
  113. }
  114. public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;
  115. }
  116. internal class LolGenericFormat : ClassificationFormatDefinition
  117. {
  118. static IClassificationTypeRegistryService m_type_registry;
  119. static IClassificationFormatMapService m_format_map;
  120. public static void SetRegistry(IClassificationTypeRegistryService type_registry,
  121. IClassificationFormatMapService format_map)
  122. {
  123. m_type_registry = type_registry;
  124. m_format_map = format_map;
  125. }
  126. protected void CopyStyleColor(string category)
  127. {
  128. if (m_type_registry == null || m_format_map == null)
  129. return;
  130. var map = m_format_map.GetClassificationFormatMap("Text Editor");
  131. if (map == null)
  132. return;
  133. //string[] foo = { "Comment", "Keyword", "C/C++ User Keywords", "Call Return", "HTML Comment" , "User Types", "User Types (Type parameters)", "User Types (Value types)"};
  134. var type = m_type_registry.GetClassificationType(category);
  135. if (type == null)
  136. return;
  137. var prop = map.GetExplicitTextProperties(type);
  138. if (prop == null)
  139. return;
  140. var c1 = prop.ForegroundBrush as SolidColorBrush;
  141. if (c1 != null && c1.Color != Colors.Transparent)
  142. {
  143. this.ForegroundColor = c1.Color;
  144. this.ForegroundOpacity = 1.0;
  145. }
  146. var c2 = prop.BackgroundBrush as SolidColorBrush;
  147. if (c2 != null && c2.Color != Colors.Transparent)
  148. {
  149. this.BackgroundColor = c2.Color;
  150. this.BackgroundOpacity = 1.0;
  151. }
  152. }
  153. }
  154. internal static class LolClassifierClassificationDefinition
  155. {
  156. [Export(typeof(ClassificationTypeDefinition))]
  157. [Name(LolCppTypeFormat.m_name)]
  158. internal static ClassificationTypeDefinition LolCustomClassType = null;
  159. [Export(typeof(ClassificationTypeDefinition))]
  160. [Name(LolCppConstantFormat.m_name)]
  161. internal static ClassificationTypeDefinition LolCustomConstantType = null;
  162. }
  163. [Export(typeof(EditorFormatDefinition))]
  164. [ClassificationType(ClassificationTypeNames = LolCppTypeFormat.m_name)]
  165. [Name(LolCppTypeFormat.m_name)]
  166. [UserVisible(true)]
  167. [Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
  168. internal sealed class LolCppTypeFormat : LolGenericFormat
  169. {
  170. public const string m_name = "LolCustomClass";
  171. public LolCppTypeFormat()
  172. {
  173. this.DisplayName = "C/C++ Types and Qualifiers";
  174. this.ForegroundColor = Colors.Lime;
  175. this.ForegroundOpacity = 1.0;
  176. this.IsBold = true;
  177. //CopyStyleColor("User Types");
  178. }
  179. }
  180. [Export(typeof(EditorFormatDefinition))]
  181. [ClassificationType(ClassificationTypeNames = LolCppConstantFormat.m_name)]
  182. [Name(LolCppConstantFormat.m_name)]
  183. [UserVisible(true)]
  184. [Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
  185. internal sealed class LolCppConstantFormat : LolGenericFormat
  186. {
  187. public const string m_name = "LolCppConstant";
  188. public LolCppConstantFormat()
  189. {
  190. this.DisplayName = "C/C++ Constants";
  191. this.ForegroundColor = Colors.Magenta;
  192. this.ForegroundOpacity = 1.0;
  193. this.IsBold = true;
  194. //CopyStyleColor("User Types");
  195. }
  196. }
  197. } /* namespace lol */