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.
 
 
 

350 lines
11 KiB

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