280 lines
8.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;
  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_types_type, m_constant_type;
  53. private Regex m_types_regex, m_constant_regex;
  54. private static const string[] m_all_types =
  55. {
  56. "auto|void|bool|int|unsigned|char|short|long|float|double";
  57. "class|struct|union|template|namespace|typename|typedef",
  58. "const|static|extern|volatile|inline|explicit"
  59. };
  60. private static const string[] m_cpp_types =
  61. {
  62. "u?int(8|16|32|64|ptr)_t",
  63. "(wchar|size|ssize)_t",
  64. "va_list",
  65. };
  66. /* ldouble real half
  67. "(f(16|128)||d|[ui](8|16||64)|r)(vec[234]|mat[234]|quat|cmplx)";
  68. */
  69. private static const string[] m_csharp_types =
  70. {
  71. "var|string",
  72. "out|ref|internal|sealed|public|private|protected|override"
  73. };
  74. private static const string[] m_lolfx_types =
  75. {
  76. "attribute|varying|uniform|in|out",
  77. "int|uint",
  78. "(|[dui])(vec|mat)[234]"
  79. };
  80. private static const string[] m_all_constants =
  81. {
  82. "true|false"
  83. };
  84. private static const string[] m_cpp_constants =
  85. {
  86. "NULL|nullptr",
  87. "EXIT_SUCCESS|EXIT_FAILURE",
  88. "M_(E|LOG(2|10)E|LN2|LN10|PI|PI_2|PI_4|1_PI|2_PI|2_SQRTPI|SQRT(2|1_2))",
  89. "SIG(HUP|INT|QUIT|ILL|TRAP|ABRT|FPE|KILL|USR1|SEGV|USR2|PIPE|ALRM)",
  90. "SIG(TERM|CHLD|CONT|STOP|TSTP|TTIN|TTOU)"
  91. };
  92. private static const string[] m_csharp_constants =
  93. {
  94. "null",
  95. };
  96. private static const string[] m_lolfx_constants =
  97. {
  98. "gl_Position|gl_FragColor",
  99. };
  100. internal CppKeywordClassifier(IClassificationTypeRegistryService registry,
  101. IClassifier classifier,
  102. IContentType type)
  103. {
  104. m_classifier = classifier;
  105. /* Regex for types and specifiers */
  106. m_types_type = registry.GetClassificationType("LolAnyType");
  107. List<string> types_list = m_all_types.ToList();
  108. if (type.IsOfType("c/c++"))
  109. types_list = types_list.Concat(m_cpp_types).ToList();
  110. if (type.IsOfType("csharp"))
  111. types_list = types_list.Concat(m_csharp_types).ToList();
  112. if (type.IsOfType("lolfx"))
  113. types_list = types_list.Concat(m_lolfx_types).ToList();
  114. m_types_regex =
  115. new Regex(@"\b(" + String.Join("|", types_list.ToArray()) + @")\b");
  116. /* Regex for constant words */
  117. m_constant_type = registry.GetClassificationType("LolAnyConstant");
  118. List<string> constants_list = m_all_constants.ToList();
  119. if (type.IsOfType("c/c++"))
  120. constants_list = constants_list.Concat(m_cpp_constants).ToList();
  121. if (type.IsOfType("csharp"))
  122. constants_list = constants_list.Concat(m_csharp_constants).ToList();
  123. if (type.IsOfType("lolfx"))
  124. constants_list = constants_list.Concat(m_lolfx_constants).ToList();
  125. m_constant_regex =
  126. new Regex(@"\b(" + String.Join("|", constants_list.ToArray()) + @")\b");
  127. }
  128. public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
  129. {
  130. List<ClassificationSpan> ret = new List<ClassificationSpan>();
  131. foreach (ClassificationSpan cs in m_classifier.GetClassificationSpans(span))
  132. {
  133. string cs_class = cs.ClassificationType.Classification.ToLower();
  134. /* Only apply our rules if we found a keyword or an identifier */
  135. if (cs_class == "keyword" || cs_class == "identifier")
  136. {
  137. if (m_types_regex.IsMatch(cs.Span.GetText()))
  138. {
  139. ret.Add(new ClassificationSpan(cs.Span, m_types_type));
  140. continue;
  141. }
  142. if (m_constant_regex.IsMatch(cs.Span.GetText()))
  143. {
  144. ret.Add(new ClassificationSpan(cs.Span, m_constant_type));
  145. continue;
  146. }
  147. }
  148. ret.Add(cs);
  149. }
  150. return ret;
  151. }
  152. public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;
  153. }
  154. internal class LolGenericFormat : ClassificationFormatDefinition
  155. {
  156. static IClassificationTypeRegistryService m_type_registry;
  157. static IClassificationFormatMapService m_format_map;
  158. public static void SetRegistry(IClassificationTypeRegistryService type_registry,
  159. IClassificationFormatMapService format_map)
  160. {
  161. m_type_registry = type_registry;
  162. m_format_map = format_map;
  163. }
  164. protected void CopyStyleColor(string category)
  165. {
  166. if (m_type_registry == null || m_format_map == null)
  167. return;
  168. var map = m_format_map.GetClassificationFormatMap("Text Editor");
  169. if (map == null)
  170. return;
  171. //string[] foo = { "Comment", "Keyword", "C/C++ User Keywords", "Call Return", "HTML Comment" , "User Types", "User Types (Type parameters)", "User Types (Value types)"};
  172. var type = m_type_registry.GetClassificationType(category);
  173. if (type == null)
  174. return;
  175. var prop = map.GetExplicitTextProperties(type);
  176. if (prop == null)
  177. return;
  178. var c1 = prop.ForegroundBrush as SolidColorBrush;
  179. if (c1 != null && c1.Color != Colors.Transparent)
  180. {
  181. this.ForegroundColor = c1.Color;
  182. this.ForegroundOpacity = 1.0;
  183. }
  184. var c2 = prop.BackgroundBrush as SolidColorBrush;
  185. if (c2 != null && c2.Color != Colors.Transparent)
  186. {
  187. this.BackgroundColor = c2.Color;
  188. this.BackgroundOpacity = 1.0;
  189. }
  190. }
  191. }
  192. internal static class LolClassifierClassificationDefinition
  193. {
  194. [Export(typeof(ClassificationTypeDefinition))]
  195. [Name(LolCppTypeFormat.m_name)]
  196. internal static ClassificationTypeDefinition LolCustomClassType = null;
  197. [Export(typeof(ClassificationTypeDefinition))]
  198. [Name(LolCppConstantFormat.m_name)]
  199. internal static ClassificationTypeDefinition LolCustomConstantType = null;
  200. }
  201. [Export(typeof(EditorFormatDefinition))]
  202. [ClassificationType(ClassificationTypeNames = LolCppTypeFormat.m_name)]
  203. [Name(LolCppTypeFormat.m_name)]
  204. [UserVisible(true)]
  205. [Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
  206. internal sealed class LolCppTypeFormat : LolGenericFormat
  207. {
  208. public const string m_name = "LolAnyType";
  209. public LolCppTypeFormat()
  210. {
  211. this.DisplayName = "C/C++ Types and Qualifiers";
  212. this.ForegroundColor = Colors.Lime;
  213. this.ForegroundOpacity = 1.0;
  214. this.IsBold = true;
  215. //CopyStyleColor("User Types");
  216. }
  217. }
  218. [Export(typeof(EditorFormatDefinition))]
  219. [ClassificationType(ClassificationTypeNames = LolCppConstantFormat.m_name)]
  220. [Name(LolCppConstantFormat.m_name)]
  221. [UserVisible(true)]
  222. [Order(After = Priority.Default)] /* Override the Visual Studio classifiers */
  223. internal sealed class LolCppConstantFormat : LolGenericFormat
  224. {
  225. public const string m_name = "LolAnyConstant";
  226. public LolCppConstantFormat()
  227. {
  228. this.DisplayName = "C/C++ Constants";
  229. this.ForegroundColor = Colors.Magenta;
  230. this.ForegroundOpacity = 1.0;
  231. this.IsBold = true;
  232. //CopyStyleColor("User Types");
  233. }
  234. }
  235. } /* namespace lol */