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