// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)usingSystem;usingSystem.Globalization;usingSystem.Text;usingSystem.Text.RegularExpressions;usingSystem.Windows;usingSystem.Windows.Media;usingSystem.Xml;usingSystem.Xml.Schema;usingICSharpCode.AvalonEdit.Utils;namespaceICSharpCode.AvalonEdit.Highlighting.Xshd{/// <summary>/// Loads .xshd files, version 1.0./// </summary>sealedclassV1Loader{staticXmlSchemaSetschemaSet;staticXmlSchemaSetSchemaSet{get{if(schemaSet==null){schemaSet=HighlightingLoader.LoadSchemaSet(newXmlTextReader(Resources.OpenStream("ModeV1.xsd")));}returnschemaSet;}}publicstaticXshdSyntaxDefinitionLoadDefinition(XmlReaderreader,boolskipValidation){reader=HighlightingLoader.GetValidatingReader(reader,false,skipValidation?null:SchemaSet);XmlDocumentdocument=newXmlDocument();document.Load(reader);V1Loaderloader=newV1Loader();returnloader.ParseDefinition(document.DocumentElement);}XshdSyntaxDefinitionParseDefinition(XmlElementsyntaxDefinition){XshdSyntaxDefinitiondef=newXshdSyntaxDefinition();def.Name=syntaxDefinition.GetAttributeOrNull("name");if(syntaxDefinition.HasAttribute("extensions")){def.Extensions.AddRange(syntaxDefinition.GetAttribute("extensions").Split(';','|'));}XshdRuleSetmainRuleSetElement=null;foreach(XmlElementelementinsyntaxDefinition.GetElementsByTagName("RuleSet")){XshdRuleSetruleSet=ImportRuleSet(element);def.Elements.Add(ruleSet);if(ruleSet.Name==null)mainRuleSetElement=ruleSet;if(syntaxDefinition["Digits"]!=null){// create digit highlighting ruleconststringoptionalExponent=@"([eE][+-]?[0-9]+)?";conststringfloatingPoint=@"\.[0-9]+";ruleSet.Elements.Add(newXshdRule{ColorReference=GetColorReference(syntaxDefinition["Digits"]),RegexType=XshdRegexType.IgnorePatternWhitespace,Regex=@"\b0[xX][0-9a-fA-F]+"+@"|"+@"(\b\d+("+floatingPoint+")?"+@"|"+floatingPoint+")"+optionalExponent});}}if(syntaxDefinition.HasAttribute("extends")&&mainRuleSetElement!=null){// convert 'extends="HTML"' to '<Import ruleSet="HTML/" />' in main rule set.mainRuleSetElement.Elements.Add(newXshdImport{RuleSetReference=newXshdReference<XshdRuleSet>(syntaxDefinition.GetAttribute("extends"),string.Empty)});}returndef;}staticXshdColorGetColorFromElement(XmlElementelement){if(!element.HasAttribute("bold")&&!element.HasAttribute("italic")&&!element.HasAttribute("color")&&!element.HasAttribute("bgcolor"))returnnull;XshdColorcolor=newXshdColor();if(element.HasAttribute("bold"))color.FontWeight=XmlConvert.ToBoolean(element.GetAttribute("bold"))?FontWeights.Bold:FontWeights.Normal;if(element.HasAttribute("italic"))color.FontStyle=XmlConvert.ToBoolean(element.GetAttribute("italic"))?FontStyles.Italic:FontStyles.Normal;if(element.HasAttribute("color"))color.Foreground=ParseColor(element.GetAttribute("color"));if(element.HasAttribute("bgcolor"))color.Background=ParseColor(element.GetAttribute("bgcolor"));returncolor;}staticXshdReference<XshdColor>GetColorReference(XmlElementelement){XshdColorcolor=GetColorFromElement(element);if(color!=null)returnnewXshdReference<XshdColor>(color);elsereturnnewXshdReference<XshdColor>();}staticHighlightingBrushParseColor(stringc){if(c.StartsWith("#",StringComparison.Ordinal)){inta=255;intoffset=0;if(c.Length>7){offset=2;a=Int32.Parse(c.Substring(1,2),NumberStyles.HexNumber,CultureInfo.InvariantCulture);}intr=Int32.Parse(c.Substring(1+offset,2),NumberStyles.HexNumber,CultureInfo.InvariantCulture);intg=Int32.Parse(c.Substring(3+offset,2),NumberStyles.HexNumber,CultureInfo.InvariantCulture);intb=Int32.Parse(c.Substring(5+offset,2),NumberStyles.HexNumber,CultureInfo.InvariantCulture);returnnewSimpleHighlightingBrush(Color.FromArgb((byte)a,(byte)r,(byte)g,(byte)b));}elseif(c.StartsWith("SystemColors.",StringComparison.Ordinal)){returnV2Loader.GetSystemColorBrush(null,c);}else{returnnewSimpleHighlightingBrush((Color)V2Loader.ColorConverter.ConvertFromInvariantString(c));}}charruleSetEscapeCharacter;XshdRuleSetImportRuleSet(XmlElementelement){XshdRuleSetruleSet=newXshdRuleSet();ruleSet.Name=element.GetAttributeOrNull("name");if(element.HasAttribute("escapecharacter")){ruleSetEscapeCharacter=element.GetAttribute("escapecharacter")[0];}else{ruleSetEscapeCharacter='\0';}if(element.HasAttribute("reference")){ruleSet.Elements.Add(newXshdImport{RuleSetReference=newXshdReference<XshdRuleSet>(element.GetAttribute("reference"),string.Empty)});}ruleSet.IgnoreCase=element.GetBoolAttribute("ignorecase");foreach(XmlElementelinelement.GetElementsByTagName("KeyWords")){XshdKeywordskeywords=newXshdKeywords();keywords.ColorReference=GetColorReference(el);// we have to handle old syntax highlighting definitions that contain// empty keywords or empty keyword groupsforeach(XmlElementnodeinel.GetElementsByTagName("Key")){stringword=node.GetAttribute("word");if(!string.IsNullOrEmpty(word))keywords.Words.Add(word);}if(keywords.Words.Count>0){ruleSet.Elements.Add(keywords);}}foreach(XmlElementelinelement.GetElementsByTagName("Span")){ruleSet.Elements.Add(ImportSpan(el));}foreach(XmlElementelinelement.GetElementsByTagName("MarkPrevious")){ruleSet.Elements.Add(ImportMarkPrevNext(el,false));}foreach(XmlElementelinelement.GetElementsByTagName("MarkFollowing")){ruleSet.Elements.Add(ImportMarkPrevNext(el,true));}returnruleSet;}staticXshdRuleImportMarkPrevNext(XmlElementel,boolmarkFollowing){boolmarkMarker=el.GetBoolAttribute("markmarker")??false;stringwhat=Regex.Escape(el.InnerText);conststringidentifier=@"[\d\w_]+";conststringwhitespace=@"\s*";stringregex;if(markFollowing){if(markMarker){regex=what+whitespace+identifier;}else{regex="(?<=("+what+whitespace+"))"+identifier;}}else{if(markMarker){regex=identifier+whitespace+what;}else{regex=identifier+"(?=("+whitespace+what+"))";}}returnnewXshdRule{ColorReference=GetColorReference(el),Regex=regex,RegexType=XshdRegexType.IgnorePatternWhitespace};}XshdSpanImportSpan(XmlElementelement){XshdSpanspan=newXshdSpan();if(element.HasAttribute("rule")){span.RuleSetReference=newXshdReference<XshdRuleSet>(null,element.GetAttribute("rule"));}charescapeCharacter=ruleSetEscapeCharacter;if(element.HasAttribute("escapecharacter")){escapeCharacter=element.GetAttribute("escapecharacter")[0];}span.Multiline=!(element.GetBoolAttribute("stopateol")??false);span.SpanColorReference=GetColorReference(element);span.BeginRegexType=XshdRegexType.IgnorePatternWhitespace;span.BeginRegex=ImportRegex(element["Begin"].InnerText,element["Begin"].GetBoolAttribute("singleword")??false,element["Begin"].GetBoolAttribute("startofline"));span.BeginColorReference=GetColorReference(element["Begin"]);stringendElementText=string.Empty;if(element["End"]!=null){span.EndRegexType=XshdRegexType.IgnorePatternWhitespace;endElementText=element["End"].InnerText;span.EndRegex=ImportRegex(endElementText,element["End"].GetBoolAttribute("singleword")??false,null);span.EndColorReference=GetColorReference(element["End"]);}if(escapeCharacter!='\0'){XshdRuleSetruleSet=newXshdRuleSet();if(endElementText.Length==1&&endElementText[0]==escapeCharacter){// ""-style escaperuleSet.Elements.Add(newXshdSpan{BeginRegex=Regex.Escape(endElementText+endElementText),EndRegex=""});}else{// \"-style escaperuleSet.Elements.Add(newXshdSpan{BeginRegex=Regex.Escape(escapeCharacter.ToString()),EndRegex="."});}if(span.RuleSetReference.ReferencedElement!=null){ruleSet.Elements.Add(newXshdImport{RuleSetReference=span.RuleSetReference});}span.RuleSetReference=newXshdReference<XshdRuleSet>(ruleSet);}returnspan;}staticstringImportRegex(stringexpr,boolsingleWord,bool?startOfLine){StringBuilderb=newStringBuilder();if(startOfLine!=null){if(startOfLine.Value){b.Append(@"(?<=(^\s*))");}else{b.Append(@"(?<!(^\s*))");}}else{if(singleWord)b.Append(@"\b");}for(inti=0;i<expr.Length;i++){charc=expr[i];if(c=='@'){++i;if(i==expr.Length)thrownewHighlightingDefinitionInvalidException("Unexpected end of @ sequence, use @@ to look for a single @.");switch(expr[i]){case'C':// match whitespace or punctuationb.Append(@"[^\w\d_]");break;case'!':// negative lookahead{StringBuilderwhatmatch=newStringBuilder();++i;while(i<expr.Length&&expr[i]!='@'){whatmatch.Append(expr[i++]);}b.Append("(?!(");b.Append(Regex.Escape(whatmatch.ToString()));b.Append("))");}break;case'-':// negative lookbehind{StringBuilderwhatmatch=newStringBuilder();++i;while(i<expr.Length&&expr[i]!='@'){whatmatch.Append(expr[i++]);}b.Append("(?<!(");b.Append(Regex.Escape(whatmatch.ToString()));b.Append("))");}break;case'@':b.Append("@");break;default:thrownewHighlightingDefinitionInvalidException("Unknown character in @ sequence.");}}else{b.Append(Regex.Escape(c.ToString()));}}if(singleWord)b.Append(@"\b");returnb.ToString();}}}