Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Highlighting/Xshd/V1Loader.cs @ 17507

Last change on this file since 17507 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 11.7 KB
Line 
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.Globalization;
21using System.Text;
22using System.Text.RegularExpressions;
23using System.Windows;
24using System.Windows.Media;
25using System.Xml;
26using System.Xml.Schema;
27
28using ICSharpCode.AvalonEdit.Utils;
29
30namespace ICSharpCode.AvalonEdit.Highlighting.Xshd
31{
32  /// <summary>
33  /// Loads .xshd files, version 1.0.
34  /// </summary>
35  sealed class V1Loader
36  {
37    static XmlSchemaSet schemaSet;
38   
39    static XmlSchemaSet SchemaSet {
40      get {
41        if (schemaSet == null) {
42          schemaSet = HighlightingLoader.LoadSchemaSet(new XmlTextReader(
43            Resources.OpenStream("ModeV1.xsd")));
44        }
45        return schemaSet;
46      }
47    }
48   
49    public static XshdSyntaxDefinition LoadDefinition(XmlReader reader, bool skipValidation)
50    {
51      reader = HighlightingLoader.GetValidatingReader(reader, false, skipValidation ? null : SchemaSet);
52      XmlDocument document = new XmlDocument();
53      document.Load(reader);
54      V1Loader loader = new V1Loader();
55      return loader.ParseDefinition(document.DocumentElement);
56    }
57   
58    XshdSyntaxDefinition ParseDefinition(XmlElement syntaxDefinition)
59    {
60      XshdSyntaxDefinition def = new XshdSyntaxDefinition();
61      def.Name = syntaxDefinition.GetAttributeOrNull("name");
62      if (syntaxDefinition.HasAttribute("extensions")) {
63        def.Extensions.AddRange(syntaxDefinition.GetAttribute("extensions").Split(';', '|'));
64      }
65     
66      XshdRuleSet mainRuleSetElement = null;
67      foreach (XmlElement element in syntaxDefinition.GetElementsByTagName("RuleSet")) {
68        XshdRuleSet ruleSet = ImportRuleSet(element);
69        def.Elements.Add(ruleSet);
70        if (ruleSet.Name == null)
71          mainRuleSetElement = ruleSet;
72       
73        if (syntaxDefinition["Digits"] != null) {
74          // create digit highlighting rule
75         
76          const string optionalExponent = @"([eE][+-]?[0-9]+)?";
77          const string floatingPoint = @"\.[0-9]+";
78          ruleSet.Elements.Add(
79            new XshdRule {
80              ColorReference = GetColorReference(syntaxDefinition["Digits"]),
81              RegexType = XshdRegexType.IgnorePatternWhitespace,
82              Regex = @"\b0[xX][0-9a-fA-F]+"
83                + @"|"
84                + @"(\b\d+(" + floatingPoint + ")?"
85                + @"|" + floatingPoint + ")"
86                + optionalExponent
87            });
88        }
89      }
90     
91      if (syntaxDefinition.HasAttribute("extends") && mainRuleSetElement != null) {
92        // convert 'extends="HTML"' to '<Import ruleSet="HTML/" />' in main rule set.
93        mainRuleSetElement.Elements.Add(
94          new XshdImport { RuleSetReference = new XshdReference<XshdRuleSet>(
95            syntaxDefinition.GetAttribute("extends"), string.Empty
96          ) });
97      }
98      return def;
99    }
100   
101    static XshdColor GetColorFromElement(XmlElement element)
102    {
103      if (!element.HasAttribute("bold") && !element.HasAttribute("italic") && !element.HasAttribute("color") && !element.HasAttribute("bgcolor"))
104        return null;
105      XshdColor color = new XshdColor();
106      if (element.HasAttribute("bold"))
107        color.FontWeight = XmlConvert.ToBoolean(element.GetAttribute("bold")) ? FontWeights.Bold : FontWeights.Normal;
108      if (element.HasAttribute("italic"))
109        color.FontStyle = XmlConvert.ToBoolean(element.GetAttribute("italic")) ? FontStyles.Italic : FontStyles.Normal;
110      if (element.HasAttribute("color"))
111        color.Foreground = ParseColor(element.GetAttribute("color"));
112      if (element.HasAttribute("bgcolor"))
113        color.Background = ParseColor(element.GetAttribute("bgcolor"));
114      return color;
115    }
116   
117    static XshdReference<XshdColor> GetColorReference(XmlElement element)
118    {
119      XshdColor color = GetColorFromElement(element);
120      if (color != null)
121        return new XshdReference<XshdColor>(color);
122      else
123        return new XshdReference<XshdColor>();
124    }
125   
126    static HighlightingBrush ParseColor(string c)
127    {
128      if (c.StartsWith("#", StringComparison.Ordinal)) {
129        int a = 255;
130        int offset = 0;
131        if (c.Length > 7) {
132          offset = 2;
133          a = Int32.Parse(c.Substring(1,2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
134        }
135       
136        int r = Int32.Parse(c.Substring(1 + offset,2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
137        int g = Int32.Parse(c.Substring(3 + offset,2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
138        int b = Int32.Parse(c.Substring(5 + offset,2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
139        return new SimpleHighlightingBrush(Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b));
140      } else if (c.StartsWith("SystemColors.", StringComparison.Ordinal)) {
141        return V2Loader.GetSystemColorBrush(null, c);
142      } else {
143        return new SimpleHighlightingBrush((Color)V2Loader.ColorConverter.ConvertFromInvariantString(c));
144      }
145    }
146   
147    char ruleSetEscapeCharacter;
148   
149    XshdRuleSet ImportRuleSet(XmlElement element)
150    {
151      XshdRuleSet ruleSet = new XshdRuleSet();
152      ruleSet.Name = element.GetAttributeOrNull("name");
153     
154      if (element.HasAttribute("escapecharacter")) {
155        ruleSetEscapeCharacter = element.GetAttribute("escapecharacter")[0];
156      } else {
157        ruleSetEscapeCharacter = '\0';
158      }
159     
160      if (element.HasAttribute("reference")) {
161        ruleSet.Elements.Add(
162          new XshdImport { RuleSetReference = new XshdReference<XshdRuleSet>(
163            element.GetAttribute("reference"), string.Empty
164          ) });
165      }
166      ruleSet.IgnoreCase = element.GetBoolAttribute("ignorecase");
167     
168      foreach (XmlElement el in element.GetElementsByTagName("KeyWords")) {
169        XshdKeywords keywords = new XshdKeywords();
170        keywords.ColorReference = GetColorReference(el);
171        // we have to handle old syntax highlighting definitions that contain
172        // empty keywords or empty keyword groups
173        foreach (XmlElement node in el.GetElementsByTagName("Key")) {
174          string word = node.GetAttribute("word");
175          if (!string.IsNullOrEmpty(word))
176            keywords.Words.Add(word);
177        }
178        if (keywords.Words.Count > 0) {
179          ruleSet.Elements.Add(keywords);
180        }
181      }
182     
183      foreach (XmlElement el in element.GetElementsByTagName("Span")) {
184        ruleSet.Elements.Add(ImportSpan(el));
185      }
186     
187      foreach (XmlElement el in element.GetElementsByTagName("MarkPrevious")) {
188        ruleSet.Elements.Add(ImportMarkPrevNext(el, false));
189      }
190      foreach (XmlElement el in element.GetElementsByTagName("MarkFollowing")) {
191        ruleSet.Elements.Add(ImportMarkPrevNext(el, true));
192      }
193     
194      return ruleSet;
195    }
196   
197    static XshdRule ImportMarkPrevNext(XmlElement el, bool markFollowing)
198    {
199      bool markMarker = el.GetBoolAttribute("markmarker") ?? false;
200      string what = Regex.Escape(el.InnerText);
201      const string identifier = @"[\d\w_]+";
202      const string whitespace = @"\s*";
203     
204      string regex;
205      if (markFollowing) {
206        if (markMarker) {
207          regex = what + whitespace + identifier;
208        } else {
209          regex = "(?<=(" + what + whitespace + "))" + identifier;
210        }
211      } else {
212        if (markMarker) {
213          regex = identifier + whitespace + what;
214        } else {
215          regex = identifier + "(?=(" + whitespace + what + "))";
216        }
217      }
218      return new XshdRule {
219        ColorReference = GetColorReference(el),
220        Regex = regex,
221        RegexType = XshdRegexType.IgnorePatternWhitespace
222      };
223    }
224   
225    XshdSpan ImportSpan(XmlElement element)
226    {
227      XshdSpan span = new XshdSpan();
228      if (element.HasAttribute("rule")) {
229        span.RuleSetReference = new XshdReference<XshdRuleSet>(null, element.GetAttribute("rule"));
230      }
231      char escapeCharacter = ruleSetEscapeCharacter;
232      if (element.HasAttribute("escapecharacter")) {
233        escapeCharacter = element.GetAttribute("escapecharacter")[0];
234      }
235      span.Multiline = !(element.GetBoolAttribute("stopateol") ?? false);
236     
237      span.SpanColorReference = GetColorReference(element);
238     
239      span.BeginRegexType = XshdRegexType.IgnorePatternWhitespace;
240      span.BeginRegex = ImportRegex(element["Begin"].InnerText,
241                                    element["Begin"].GetBoolAttribute("singleword") ?? false,
242                                    element["Begin"].GetBoolAttribute("startofline"));
243      span.BeginColorReference = GetColorReference(element["Begin"]);
244     
245      string endElementText = string.Empty;
246      if (element["End"] != null) {
247        span.EndRegexType = XshdRegexType.IgnorePatternWhitespace;
248        endElementText = element["End"].InnerText;
249        span.EndRegex = ImportRegex(endElementText,
250                                    element["End"].GetBoolAttribute("singleword") ?? false,
251                                    null);
252        span.EndColorReference = GetColorReference(element["End"]);
253      }
254     
255      if (escapeCharacter != '\0') {
256        XshdRuleSet ruleSet = new XshdRuleSet();
257        if (endElementText.Length == 1 && endElementText[0] == escapeCharacter) {
258          // ""-style escape
259          ruleSet.Elements.Add(new XshdSpan {
260                                BeginRegex = Regex.Escape(endElementText + endElementText),
261                                EndRegex = ""
262                               });
263        } else {
264          // \"-style escape
265          ruleSet.Elements.Add(new XshdSpan {
266                                BeginRegex = Regex.Escape(escapeCharacter.ToString()),
267                                EndRegex = "."
268                               });
269        }
270        if (span.RuleSetReference.ReferencedElement != null) {
271          ruleSet.Elements.Add(new XshdImport { RuleSetReference = span.RuleSetReference });
272        }
273        span.RuleSetReference = new XshdReference<XshdRuleSet>(ruleSet);
274      }
275      return span;
276    }
277   
278    static string ImportRegex(string expr, bool singleWord, bool? startOfLine)
279    {
280      StringBuilder b = new StringBuilder();
281      if (startOfLine != null) {
282        if (startOfLine.Value) {
283          b.Append(@"(?<=(^\s*))");
284        } else {
285          b.Append(@"(?<!(^\s*))");
286        }
287      } else {
288        if (singleWord)
289          b.Append(@"\b");
290      }
291      for (int i = 0; i < expr.Length; i++) {
292        char c = expr[i];
293        if (c == '@') {
294          ++i;
295          if (i == expr.Length)
296            throw new HighlightingDefinitionInvalidException("Unexpected end of @ sequence, use @@ to look for a single @.");
297          switch (expr[i]) {
298            case 'C': // match whitespace or punctuation
299              b.Append(@"[^\w\d_]");
300              break;
301            case '!': // negative lookahead
302              {
303                StringBuilder whatmatch = new StringBuilder();
304                ++i;
305                while (i < expr.Length && expr[i] != '@') {
306                  whatmatch.Append(expr[i++]);
307                }
308                b.Append("(?!(");
309                b.Append(Regex.Escape(whatmatch.ToString()));
310                b.Append("))");
311              }
312              break;
313            case '-': // negative lookbehind
314              {
315                StringBuilder whatmatch = new StringBuilder();
316                ++i;
317                while (i < expr.Length && expr[i] != '@') {
318                  whatmatch.Append(expr[i++]);
319                }
320                b.Append("(?<!(");
321                b.Append(Regex.Escape(whatmatch.ToString()));
322                b.Append("))");
323              }
324              break;
325            case '@':
326              b.Append("@");
327              break;
328            default:
329              throw new HighlightingDefinitionInvalidException("Unknown character in @ sequence.");
330          }
331        } else {
332          b.Append(Regex.Escape(c.ToString()));
333        }
334      }
335      if (singleWord)
336        b.Append(@"\b");
337      return b.ToString();
338    }
339  }
340}
Note: See TracBrowser for help on using the repository browser.