/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Xshd/V2Loader.cs

http://github.com/icsharpcode/ILSpy · C# · 350 lines · 293 code · 29 blank · 28 comment · 61 complexity · 985ccf87a436414b5455b830a605d864 MD5 · raw file

  1. // Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Diagnostics;
  21. using System.Windows;
  22. using System.Windows.Media;
  23. using System.Xml;
  24. using System.Xml.Schema;
  25. using ICSharpCode.AvalonEdit.Utils;
  26. namespace ICSharpCode.AvalonEdit.Highlighting.Xshd
  27. {
  28. /// <summary>
  29. /// Loads .xshd files, version 2.0.
  30. /// Version 2.0 files are recognized by the namespace.
  31. /// </summary>
  32. static class V2Loader
  33. {
  34. public const string Namespace = "http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008";
  35. static XmlSchemaSet schemaSet;
  36. static XmlSchemaSet SchemaSet {
  37. get {
  38. if (schemaSet == null) {
  39. schemaSet = HighlightingLoader.LoadSchemaSet(new XmlTextReader(
  40. Resources.OpenStream("ModeV2.xsd")));
  41. }
  42. return schemaSet;
  43. }
  44. }
  45. public static XshdSyntaxDefinition LoadDefinition(XmlReader reader, bool skipValidation)
  46. {
  47. reader = HighlightingLoader.GetValidatingReader(reader, true, skipValidation ? null : SchemaSet);
  48. reader.Read();
  49. return ParseDefinition(reader);
  50. }
  51. static XshdSyntaxDefinition ParseDefinition(XmlReader reader)
  52. {
  53. Debug.Assert(reader.LocalName == "SyntaxDefinition");
  54. XshdSyntaxDefinition def = new XshdSyntaxDefinition();
  55. def.Name = reader.GetAttribute("name");
  56. string extensions = reader.GetAttribute("extensions");
  57. if (extensions != null)
  58. def.Extensions.AddRange(extensions.Split(';'));
  59. ParseElements(def.Elements, reader);
  60. Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
  61. Debug.Assert(reader.LocalName == "SyntaxDefinition");
  62. return def;
  63. }
  64. static void ParseElements(ICollection<XshdElement> c, XmlReader reader)
  65. {
  66. if (reader.IsEmptyElement)
  67. return;
  68. while (reader.Read() && reader.NodeType != XmlNodeType.EndElement) {
  69. Debug.Assert(reader.NodeType == XmlNodeType.Element);
  70. if (reader.NamespaceURI != Namespace) {
  71. if (!reader.IsEmptyElement)
  72. reader.Skip();
  73. continue;
  74. }
  75. switch (reader.Name) {
  76. case "RuleSet":
  77. c.Add(ParseRuleSet(reader));
  78. break;
  79. case "Property":
  80. c.Add(ParseProperty(reader));
  81. break;
  82. case "Color":
  83. c.Add(ParseNamedColor(reader));
  84. break;
  85. case "Keywords":
  86. c.Add(ParseKeywords(reader));
  87. break;
  88. case "Span":
  89. c.Add(ParseSpan(reader));
  90. break;
  91. case "Import":
  92. c.Add(ParseImport(reader));
  93. break;
  94. case "Rule":
  95. c.Add(ParseRule(reader));
  96. break;
  97. default:
  98. throw new NotSupportedException("Unknown element " + reader.Name);
  99. }
  100. }
  101. }
  102. static XshdElement ParseProperty(XmlReader reader)
  103. {
  104. XshdProperty property = new XshdProperty();
  105. SetPosition(property, reader);
  106. property.Name = reader.GetAttribute("name");
  107. property.Value = reader.GetAttribute("value");
  108. return property;
  109. }
  110. static XshdRuleSet ParseRuleSet(XmlReader reader)
  111. {
  112. XshdRuleSet ruleSet = new XshdRuleSet();
  113. SetPosition(ruleSet, reader);
  114. ruleSet.Name = reader.GetAttribute("name");
  115. ruleSet.IgnoreCase = reader.GetBoolAttribute("ignoreCase");
  116. CheckElementName(reader, ruleSet.Name);
  117. ParseElements(ruleSet.Elements, reader);
  118. return ruleSet;
  119. }
  120. static XshdRule ParseRule(XmlReader reader)
  121. {
  122. XshdRule rule = new XshdRule();
  123. SetPosition(rule, reader);
  124. rule.ColorReference = ParseColorReference(reader);
  125. if (!reader.IsEmptyElement) {
  126. reader.Read();
  127. if (reader.NodeType == XmlNodeType.Text) {
  128. rule.Regex = reader.ReadContentAsString();
  129. rule.RegexType = XshdRegexType.IgnorePatternWhitespace;
  130. }
  131. }
  132. return rule;
  133. }
  134. static XshdKeywords ParseKeywords(XmlReader reader)
  135. {
  136. XshdKeywords keywords = new XshdKeywords();
  137. SetPosition(keywords, reader);
  138. keywords.ColorReference = ParseColorReference(reader);
  139. reader.Read();
  140. while (reader.NodeType != XmlNodeType.EndElement) {
  141. Debug.Assert(reader.NodeType == XmlNodeType.Element);
  142. keywords.Words.Add(reader.ReadElementString());
  143. }
  144. return keywords;
  145. }
  146. static XshdImport ParseImport(XmlReader reader)
  147. {
  148. XshdImport import = new XshdImport();
  149. SetPosition(import, reader);
  150. import.RuleSetReference = ParseRuleSetReference(reader);
  151. if (!reader.IsEmptyElement)
  152. reader.Skip();
  153. return import;
  154. }
  155. static XshdSpan ParseSpan(XmlReader reader)
  156. {
  157. XshdSpan span = new XshdSpan();
  158. SetPosition(span, reader);
  159. span.BeginRegex = reader.GetAttribute("begin");
  160. span.EndRegex = reader.GetAttribute("end");
  161. span.Multiline = reader.GetBoolAttribute("multiline") ?? false;
  162. span.SpanColorReference = ParseColorReference(reader);
  163. span.RuleSetReference = ParseRuleSetReference(reader);
  164. if (!reader.IsEmptyElement) {
  165. reader.Read();
  166. while (reader.NodeType != XmlNodeType.EndElement) {
  167. Debug.Assert(reader.NodeType == XmlNodeType.Element);
  168. switch (reader.Name) {
  169. case "Begin":
  170. if (span.BeginRegex != null)
  171. throw Error(reader, "Duplicate Begin regex");
  172. span.BeginColorReference = ParseColorReference(reader);
  173. span.BeginRegex = reader.ReadElementString();
  174. span.BeginRegexType = XshdRegexType.IgnorePatternWhitespace;
  175. break;
  176. case "End":
  177. if (span.EndRegex != null)
  178. throw Error(reader, "Duplicate End regex");
  179. span.EndColorReference = ParseColorReference(reader);
  180. span.EndRegex = reader.ReadElementString();
  181. span.EndRegexType = XshdRegexType.IgnorePatternWhitespace;
  182. break;
  183. case "RuleSet":
  184. if (span.RuleSetReference.ReferencedElement != null)
  185. throw Error(reader, "Cannot specify both inline RuleSet and RuleSet reference");
  186. span.RuleSetReference = new XshdReference<XshdRuleSet>(ParseRuleSet(reader));
  187. reader.Read();
  188. break;
  189. default:
  190. throw new NotSupportedException("Unknown element " + reader.Name);
  191. }
  192. }
  193. }
  194. return span;
  195. }
  196. static Exception Error(XmlReader reader, string message)
  197. {
  198. return Error(reader as IXmlLineInfo, message);
  199. }
  200. static Exception Error(IXmlLineInfo lineInfo, string message)
  201. {
  202. if (lineInfo != null)
  203. return new HighlightingDefinitionInvalidException(HighlightingLoader.FormatExceptionMessage(message, lineInfo.LineNumber, lineInfo.LinePosition));
  204. else
  205. return new HighlightingDefinitionInvalidException(message);
  206. }
  207. /// <summary>
  208. /// Sets the element's position to the XmlReader's position.
  209. /// </summary>
  210. static void SetPosition(XshdElement element, XmlReader reader)
  211. {
  212. IXmlLineInfo lineInfo = reader as IXmlLineInfo;
  213. if (lineInfo != null) {
  214. element.LineNumber = lineInfo.LineNumber;
  215. element.ColumnNumber = lineInfo.LinePosition;
  216. }
  217. }
  218. static XshdReference<XshdRuleSet> ParseRuleSetReference(XmlReader reader)
  219. {
  220. string ruleSet = reader.GetAttribute("ruleSet");
  221. if (ruleSet != null) {
  222. // '/' is valid in highlighting definition names, so we need the last occurence
  223. int pos = ruleSet.LastIndexOf('/');
  224. if (pos >= 0) {
  225. return new XshdReference<XshdRuleSet>(ruleSet.Substring(0, pos), ruleSet.Substring(pos + 1));
  226. } else {
  227. return new XshdReference<XshdRuleSet>(null, ruleSet);
  228. }
  229. } else {
  230. return new XshdReference<XshdRuleSet>();
  231. }
  232. }
  233. static void CheckElementName(XmlReader reader, string name)
  234. {
  235. if (name != null) {
  236. if (name.Length == 0)
  237. throw Error(reader, "The empty string is not a valid name.");
  238. if (name.IndexOf('/') >= 0)
  239. throw Error(reader, "Element names must not contain a slash.");
  240. }
  241. }
  242. #region ParseColor
  243. static XshdColor ParseNamedColor(XmlReader reader)
  244. {
  245. XshdColor color = ParseColorAttributes(reader);
  246. // check removed: invisible named colors may be useful now that apps can read highlighting data
  247. //if (color.Foreground == null && color.FontWeight == null && color.FontStyle == null)
  248. // throw Error(reader, "A named color must have at least one element.");
  249. color.Name = reader.GetAttribute("name");
  250. CheckElementName(reader, color.Name);
  251. color.ExampleText = reader.GetAttribute("exampleText");
  252. return color;
  253. }
  254. static XshdReference<XshdColor> ParseColorReference(XmlReader reader)
  255. {
  256. string color = reader.GetAttribute("color");
  257. if (color != null) {
  258. int pos = color.LastIndexOf('/');
  259. if (pos >= 0) {
  260. return new XshdReference<XshdColor>(color.Substring(0, pos), color.Substring(pos + 1));
  261. } else {
  262. return new XshdReference<XshdColor>(null, color);
  263. }
  264. } else {
  265. return new XshdReference<XshdColor>(ParseColorAttributes(reader));
  266. }
  267. }
  268. static XshdColor ParseColorAttributes(XmlReader reader)
  269. {
  270. XshdColor color = new XshdColor();
  271. SetPosition(color, reader);
  272. IXmlLineInfo position = reader as IXmlLineInfo;
  273. color.Foreground = ParseColor(position, reader.GetAttribute("foreground"));
  274. color.Background = ParseColor(position, reader.GetAttribute("background"));
  275. color.FontWeight = ParseFontWeight(reader.GetAttribute("fontWeight"));
  276. color.FontStyle = ParseFontStyle(reader.GetAttribute("fontStyle"));
  277. color.Underline = reader.GetBoolAttribute("underline");
  278. return color;
  279. }
  280. internal readonly static ColorConverter ColorConverter = new ColorConverter();
  281. internal readonly static FontWeightConverter FontWeightConverter = new FontWeightConverter();
  282. internal readonly static FontStyleConverter FontStyleConverter = new FontStyleConverter();
  283. static HighlightingBrush ParseColor(IXmlLineInfo lineInfo, string color)
  284. {
  285. if (string.IsNullOrEmpty(color))
  286. return null;
  287. if (color.StartsWith("SystemColors.", StringComparison.Ordinal))
  288. return GetSystemColorBrush(lineInfo, color);
  289. else
  290. return FixedColorHighlightingBrush((Color?)ColorConverter.ConvertFromInvariantString(color));
  291. }
  292. internal static SystemColorHighlightingBrush GetSystemColorBrush(IXmlLineInfo lineInfo, string name)
  293. {
  294. Debug.Assert(name.StartsWith("SystemColors.", StringComparison.Ordinal));
  295. string shortName = name.Substring(13);
  296. var property = typeof(SystemColors).GetProperty(shortName + "Brush");
  297. if (property == null)
  298. throw Error(lineInfo, "Cannot find '" + name + "'.");
  299. return new SystemColorHighlightingBrush(property);
  300. }
  301. static HighlightingBrush FixedColorHighlightingBrush(Color? color)
  302. {
  303. if (color == null)
  304. return null;
  305. return new SimpleHighlightingBrush(color.Value);
  306. }
  307. static FontWeight? ParseFontWeight(string fontWeight)
  308. {
  309. if (string.IsNullOrEmpty(fontWeight))
  310. return null;
  311. return (FontWeight?)FontWeightConverter.ConvertFromInvariantString(fontWeight);
  312. }
  313. static FontStyle? ParseFontStyle(string fontStyle)
  314. {
  315. if (string.IsNullOrEmpty(fontStyle))
  316. return null;
  317. return (FontStyle?)FontStyleConverter.ConvertFromInvariantString(fontStyle);
  318. }
  319. #endregion
  320. }
  321. }