PageRenderTime 34ms CodeModel.GetById 16ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 1ms

/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
 19using System;
 20using System.Collections.Generic;
 21using System.Diagnostics;
 22using System.Windows;
 23using System.Windows.Media;
 24using System.Xml;
 25using System.Xml.Schema;
 26
 27using ICSharpCode.AvalonEdit.Utils;
 28
 29namespace ICSharpCode.AvalonEdit.Highlighting.Xshd
 30{
 31	/// <summary>
 32	/// Loads .xshd files, version 2.0.
 33	/// Version 2.0 files are recognized by the namespace.
 34	/// </summary>
 35	static class V2Loader
 36	{
 37		public const string Namespace = "http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008";
 38		
 39		static XmlSchemaSet schemaSet;
 40		
 41		static XmlSchemaSet SchemaSet {
 42			get {
 43				if (schemaSet == null) {
 44					schemaSet = HighlightingLoader.LoadSchemaSet(new XmlTextReader(
 45						Resources.OpenStream("ModeV2.xsd")));
 46				}
 47				return schemaSet;
 48			}
 49		}
 50		
 51		public static XshdSyntaxDefinition LoadDefinition(XmlReader reader, bool skipValidation)
 52		{
 53			reader = HighlightingLoader.GetValidatingReader(reader, true, skipValidation ? null : SchemaSet);
 54			reader.Read();
 55			return ParseDefinition(reader);
 56		}
 57		
 58		static XshdSyntaxDefinition ParseDefinition(XmlReader reader)
 59		{
 60			Debug.Assert(reader.LocalName == "SyntaxDefinition");
 61			XshdSyntaxDefinition def = new XshdSyntaxDefinition();
 62			def.Name = reader.GetAttribute("name");
 63			string extensions = reader.GetAttribute("extensions");
 64			if (extensions != null)
 65				def.Extensions.AddRange(extensions.Split(';'));
 66			ParseElements(def.Elements, reader);
 67			Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
 68			Debug.Assert(reader.LocalName == "SyntaxDefinition");
 69			return def;
 70		}
 71		
 72		static void ParseElements(ICollection<XshdElement> c, XmlReader reader)
 73		{
 74			if (reader.IsEmptyElement)
 75				return;
 76			while (reader.Read() && reader.NodeType != XmlNodeType.EndElement) {
 77				Debug.Assert(reader.NodeType == XmlNodeType.Element);
 78				if (reader.NamespaceURI != Namespace) {
 79					if (!reader.IsEmptyElement)
 80						reader.Skip();
 81					continue;
 82				}
 83				switch (reader.Name) {
 84					case "RuleSet":
 85						c.Add(ParseRuleSet(reader));
 86						break;
 87					case "Property":
 88						c.Add(ParseProperty(reader));
 89						break;
 90					case "Color":
 91						c.Add(ParseNamedColor(reader));
 92						break;
 93					case "Keywords":
 94						c.Add(ParseKeywords(reader));
 95						break;
 96					case "Span":
 97						c.Add(ParseSpan(reader));
 98						break;
 99					case "Import":
100						c.Add(ParseImport(reader));
101						break;
102					case "Rule":
103						c.Add(ParseRule(reader));
104						break;
105					default:
106						throw new NotSupportedException("Unknown element " + reader.Name);
107				}
108			}
109		}
110		
111		static XshdElement ParseProperty(XmlReader reader)
112		{
113			XshdProperty property = new XshdProperty();
114			SetPosition(property, reader);
115			property.Name = reader.GetAttribute("name");
116			property.Value = reader.GetAttribute("value");
117			return property;
118		}
119		
120		static XshdRuleSet ParseRuleSet(XmlReader reader)
121		{
122			XshdRuleSet ruleSet = new XshdRuleSet();
123			SetPosition(ruleSet, reader);
124			ruleSet.Name = reader.GetAttribute("name");
125			ruleSet.IgnoreCase = reader.GetBoolAttribute("ignoreCase");
126			
127			CheckElementName(reader, ruleSet.Name);
128			ParseElements(ruleSet.Elements, reader);
129			return ruleSet;
130		}
131		
132		static XshdRule ParseRule(XmlReader reader)
133		{
134			XshdRule rule = new XshdRule();
135			SetPosition(rule, reader);
136			rule.ColorReference = ParseColorReference(reader);
137			if (!reader.IsEmptyElement) {
138				reader.Read();
139				if (reader.NodeType == XmlNodeType.Text) {
140					rule.Regex = reader.ReadContentAsString();
141					rule.RegexType = XshdRegexType.IgnorePatternWhitespace;
142				}
143			}
144			return rule;
145		}
146		
147		static XshdKeywords ParseKeywords(XmlReader reader)
148		{
149			XshdKeywords keywords = new XshdKeywords();
150			SetPosition(keywords, reader);
151			keywords.ColorReference = ParseColorReference(reader);
152			reader.Read();
153			while (reader.NodeType != XmlNodeType.EndElement) {
154				Debug.Assert(reader.NodeType == XmlNodeType.Element);
155				keywords.Words.Add(reader.ReadElementString());
156			}
157			return keywords;
158		}
159		
160		static XshdImport ParseImport(XmlReader reader)
161		{
162			XshdImport import = new XshdImport();
163			SetPosition(import, reader);
164			import.RuleSetReference = ParseRuleSetReference(reader);
165			if (!reader.IsEmptyElement)
166				reader.Skip();
167			return import;
168		}
169		
170		static XshdSpan ParseSpan(XmlReader reader)
171		{
172			XshdSpan span = new XshdSpan();
173			SetPosition(span, reader);
174			span.BeginRegex = reader.GetAttribute("begin");
175			span.EndRegex = reader.GetAttribute("end");
176			span.Multiline = reader.GetBoolAttribute("multiline") ?? false;
177			span.SpanColorReference = ParseColorReference(reader);
178			span.RuleSetReference = ParseRuleSetReference(reader);
179			if (!reader.IsEmptyElement) {
180				reader.Read();
181				while (reader.NodeType != XmlNodeType.EndElement) {
182					Debug.Assert(reader.NodeType == XmlNodeType.Element);
183					switch (reader.Name) {
184						case "Begin":
185							if (span.BeginRegex != null)
186								throw Error(reader, "Duplicate Begin regex");
187							span.BeginColorReference = ParseColorReference(reader);
188							span.BeginRegex = reader.ReadElementString();
189							span.BeginRegexType = XshdRegexType.IgnorePatternWhitespace;
190							break;
191						case "End":
192							if (span.EndRegex != null)
193								throw Error(reader, "Duplicate End regex");
194							span.EndColorReference = ParseColorReference(reader);
195							span.EndRegex = reader.ReadElementString();
196							span.EndRegexType = XshdRegexType.IgnorePatternWhitespace;
197							break;
198						case "RuleSet":
199							if (span.RuleSetReference.ReferencedElement != null)
200								throw Error(reader, "Cannot specify both inline RuleSet and RuleSet reference");
201							span.RuleSetReference = new XshdReference<XshdRuleSet>(ParseRuleSet(reader));
202							reader.Read();
203							break;
204						default:
205							throw new NotSupportedException("Unknown element " + reader.Name);
206					}
207				}
208			}
209			return span;
210		}
211		
212		static Exception Error(XmlReader reader, string message)
213		{
214			return Error(reader as IXmlLineInfo, message);
215		}
216		
217		static Exception Error(IXmlLineInfo lineInfo, string message)
218		{
219			if (lineInfo != null)
220				return new HighlightingDefinitionInvalidException(HighlightingLoader.FormatExceptionMessage(message, lineInfo.LineNumber, lineInfo.LinePosition));
221			else
222				return new HighlightingDefinitionInvalidException(message);
223		}
224		
225		/// <summary>
226		/// Sets the element's position to the XmlReader's position.
227		/// </summary>
228		static void SetPosition(XshdElement element, XmlReader reader)
229		{
230			IXmlLineInfo lineInfo = reader as IXmlLineInfo;
231			if (lineInfo != null) {
232				element.LineNumber = lineInfo.LineNumber;
233				element.ColumnNumber = lineInfo.LinePosition;
234			}
235		}
236		
237		static XshdReference<XshdRuleSet> ParseRuleSetReference(XmlReader reader)
238		{
239			string ruleSet = reader.GetAttribute("ruleSet");
240			if (ruleSet != null) {
241				// '/' is valid in highlighting definition names, so we need the last occurence
242				int pos = ruleSet.LastIndexOf('/');
243				if (pos >= 0) {
244					return new XshdReference<XshdRuleSet>(ruleSet.Substring(0, pos), ruleSet.Substring(pos + 1));
245				} else {
246					return new XshdReference<XshdRuleSet>(null, ruleSet);
247				}
248			} else {
249				return new XshdReference<XshdRuleSet>();
250			}
251		}
252		
253		static void CheckElementName(XmlReader reader, string name)
254		{
255			if (name != null) {
256				if (name.Length == 0)
257					throw Error(reader, "The empty string is not a valid name.");
258				if (name.IndexOf('/') >= 0)
259					throw Error(reader, "Element names must not contain a slash.");
260			}
261		}
262		
263		#region ParseColor
264		static XshdColor ParseNamedColor(XmlReader reader)
265		{
266			XshdColor color = ParseColorAttributes(reader);
267			// check removed: invisible named colors may be useful now that apps can read highlighting data
268			//if (color.Foreground == null && color.FontWeight == null && color.FontStyle == null)
269			//	throw Error(reader, "A named color must have at least one element.");
270			color.Name = reader.GetAttribute("name");
271			CheckElementName(reader, color.Name);
272			color.ExampleText = reader.GetAttribute("exampleText");
273			return color;
274		}
275		
276		static XshdReference<XshdColor> ParseColorReference(XmlReader reader)
277		{
278			string color = reader.GetAttribute("color");
279			if (color != null) {
280				int pos = color.LastIndexOf('/');
281				if (pos >= 0) {
282					return new XshdReference<XshdColor>(color.Substring(0, pos), color.Substring(pos + 1));
283				} else {
284					return new XshdReference<XshdColor>(null, color);
285				}
286			} else {
287				return new XshdReference<XshdColor>(ParseColorAttributes(reader));
288			}
289		}
290		
291		static XshdColor ParseColorAttributes(XmlReader reader)
292		{
293			XshdColor color = new XshdColor();
294			SetPosition(color, reader);
295			IXmlLineInfo position = reader as IXmlLineInfo;
296			color.Foreground = ParseColor(position, reader.GetAttribute("foreground"));
297			color.Background = ParseColor(position, reader.GetAttribute("background"));
298			color.FontWeight = ParseFontWeight(reader.GetAttribute("fontWeight"));
299			color.FontStyle = ParseFontStyle(reader.GetAttribute("fontStyle"));
300			color.Underline = reader.GetBoolAttribute("underline");
301			return color;
302		}
303		
304		internal readonly static ColorConverter ColorConverter = new ColorConverter();
305		internal readonly static FontWeightConverter FontWeightConverter = new FontWeightConverter();
306		internal readonly static FontStyleConverter FontStyleConverter = new FontStyleConverter();
307		
308		static HighlightingBrush ParseColor(IXmlLineInfo lineInfo, string color)
309		{
310			if (string.IsNullOrEmpty(color))
311				return null;
312			if (color.StartsWith("SystemColors.", StringComparison.Ordinal))
313				return GetSystemColorBrush(lineInfo, color);
314			else
315				return FixedColorHighlightingBrush((Color?)ColorConverter.ConvertFromInvariantString(color));
316		}
317		
318		internal static SystemColorHighlightingBrush GetSystemColorBrush(IXmlLineInfo lineInfo, string name)
319		{
320			Debug.Assert(name.StartsWith("SystemColors.", StringComparison.Ordinal));
321			string shortName = name.Substring(13);
322			var property = typeof(SystemColors).GetProperty(shortName + "Brush");
323			if (property == null)
324				throw Error(lineInfo, "Cannot find '" + name + "'.");
325			return new SystemColorHighlightingBrush(property);
326		}
327		
328		static HighlightingBrush FixedColorHighlightingBrush(Color? color)
329		{
330			if (color == null)
331				return null;
332			return new SimpleHighlightingBrush(color.Value);
333		}
334		
335		static FontWeight? ParseFontWeight(string fontWeight)
336		{
337			if (string.IsNullOrEmpty(fontWeight))
338				return null;
339			return (FontWeight?)FontWeightConverter.ConvertFromInvariantString(fontWeight);
340		}
341		
342		static FontStyle? ParseFontStyle(string fontStyle)
343		{
344			if (string.IsNullOrEmpty(fontStyle))
345				return null;
346			return (FontStyle?)FontStyleConverter.ConvertFromInvariantString(fontStyle);
347		}
348		#endregion
349	}
350}