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.
 
 
 

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