Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Highlighting/HighlightingManager.cs @ 11700

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

#2077: created branch and added first version

File size: 10.1 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.Collections.Generic;
21using System.Collections.ObjectModel;
22using System.Diagnostics;
23using System.IO;
24using System.Xml;
25using ICSharpCode.AvalonEdit.Utils;
26
27namespace ICSharpCode.AvalonEdit.Highlighting
28{
29  /// <summary>
30  /// Manages a list of syntax highlighting definitions.
31  /// </summary>
32  /// <remarks>
33  /// All memers on this class (including instance members) are thread-safe.
34  /// </remarks>
35  public class HighlightingManager : IHighlightingDefinitionReferenceResolver
36  {
37    sealed class DelayLoadedHighlightingDefinition : IHighlightingDefinition
38    {
39      readonly object lockObj = new object();
40      readonly string name;
41      Func<IHighlightingDefinition> lazyLoadingFunction;
42      IHighlightingDefinition definition;
43      Exception storedException;
44     
45      public DelayLoadedHighlightingDefinition(string name, Func<IHighlightingDefinition> lazyLoadingFunction)
46      {
47        this.name = name;
48        this.lazyLoadingFunction = lazyLoadingFunction;
49      }
50     
51      public string Name {
52        get {
53          if (name != null)
54            return name;
55          else
56            return GetDefinition().Name;
57        }
58      }
59     
60      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
61                                                       Justification = "The exception will be rethrown")]
62      IHighlightingDefinition GetDefinition()
63      {
64        Func<IHighlightingDefinition> func;
65        lock (lockObj) {
66          if (this.definition != null)
67            return this.definition;
68          func = this.lazyLoadingFunction;
69        }
70        Exception exception = null;
71        IHighlightingDefinition def = null;
72        try {
73          using (var busyLock = BusyManager.Enter(this)) {
74            if (!busyLock.Success)
75              throw new InvalidOperationException("Tried to create delay-loaded highlighting definition recursively. Make sure the are no cyclic references between the highlighting definitions.");
76            def = func();
77          }
78          if (def == null)
79            throw new InvalidOperationException("Function for delay-loading highlighting definition returned null");
80        } catch (Exception ex) {
81          exception = ex;
82        }
83        lock (lockObj) {
84          this.lazyLoadingFunction = null;
85          if (this.definition == null && this.storedException == null) {
86            this.definition = def;
87            this.storedException = exception;
88          }
89          if (this.storedException != null)
90            throw new HighlightingDefinitionInvalidException("Error delay-loading highlighting definition", this.storedException);
91          return this.definition;
92        }
93      }
94     
95      public HighlightingRuleSet MainRuleSet {
96        get {
97          return GetDefinition().MainRuleSet;
98        }
99      }
100     
101      public HighlightingRuleSet GetNamedRuleSet(string name)
102      {
103        return GetDefinition().GetNamedRuleSet(name);
104      }
105     
106      public HighlightingColor GetNamedColor(string name)
107      {
108        return GetDefinition().GetNamedColor(name);
109      }
110     
111      public IEnumerable<HighlightingColor> NamedHighlightingColors {
112        get {
113          return GetDefinition().NamedHighlightingColors;
114        }
115      }
116     
117      public override string ToString()
118      {
119        return this.Name;
120      }
121     
122      public IDictionary<string, string> Properties {
123        get {
124          return GetDefinition().Properties;
125        }
126      }
127    }
128   
129    readonly object lockObj = new object();
130    Dictionary<string, IHighlightingDefinition> highlightingsByName = new Dictionary<string, IHighlightingDefinition>();
131    Dictionary<string, IHighlightingDefinition> highlightingsByExtension = new Dictionary<string, IHighlightingDefinition>(StringComparer.OrdinalIgnoreCase);
132    List<IHighlightingDefinition> allHighlightings = new List<IHighlightingDefinition>();
133   
134    /// <summary>
135    /// Gets a highlighting definition by name.
136    /// Returns null if the definition is not found.
137    /// </summary>
138    public IHighlightingDefinition GetDefinition(string name)
139    {
140      lock (lockObj) {
141        IHighlightingDefinition rh;
142        if (highlightingsByName.TryGetValue(name, out rh))
143          return rh;
144        else
145          return null;
146      }
147    }
148   
149    /// <summary>
150    /// Gets a copy of all highlightings.
151    /// </summary>
152    public ReadOnlyCollection<IHighlightingDefinition> HighlightingDefinitions {
153      get {
154        lock (lockObj) {
155          return Array.AsReadOnly(allHighlightings.ToArray());
156        }
157      }
158    }
159   
160    /// <summary>
161    /// Gets a highlighting definition by extension.
162    /// Returns null if the definition is not found.
163    /// </summary>
164    public IHighlightingDefinition GetDefinitionByExtension(string extension)
165    {
166      lock (lockObj) {
167        IHighlightingDefinition rh;
168        if (highlightingsByExtension.TryGetValue(extension, out rh))
169          return rh;
170        else
171          return null;
172      }
173    }
174   
175    /// <summary>
176    /// Registers a highlighting definition.
177    /// </summary>
178    /// <param name="name">The name to register the definition with.</param>
179    /// <param name="extensions">The file extensions to register the definition for.</param>
180    /// <param name="highlighting">The highlighting definition.</param>
181    public void RegisterHighlighting(string name, string[] extensions, IHighlightingDefinition highlighting)
182    {
183      if (highlighting == null)
184        throw new ArgumentNullException("highlighting");
185     
186      lock (lockObj) {
187        allHighlightings.Add(highlighting);
188        if (name != null) {
189          highlightingsByName[name] = highlighting;
190        }
191        if (extensions != null) {
192          foreach (string ext in extensions) {
193            highlightingsByExtension[ext] = highlighting;
194          }
195        }
196      }
197    }
198   
199    /// <summary>
200    /// Registers a highlighting definition.
201    /// </summary>
202    /// <param name="name">The name to register the definition with.</param>
203    /// <param name="extensions">The file extensions to register the definition for.</param>
204    /// <param name="lazyLoadedHighlighting">A function that loads the highlighting definition.</param>
205    public void RegisterHighlighting(string name, string[] extensions, Func<IHighlightingDefinition> lazyLoadedHighlighting)
206    {
207      if (lazyLoadedHighlighting == null)
208        throw new ArgumentNullException("lazyLoadedHighlighting");
209      RegisterHighlighting(name, extensions, new DelayLoadedHighlightingDefinition(name, lazyLoadedHighlighting));
210    }
211   
212    /// <summary>
213    /// Gets the default HighlightingManager instance.
214    /// The default HighlightingManager comes with built-in highlightings.
215    /// </summary>
216    public static HighlightingManager Instance {
217      get {
218        return DefaultHighlightingManager.Instance;
219      }
220    }
221   
222    internal sealed class DefaultHighlightingManager : HighlightingManager
223    {
224      public new static readonly DefaultHighlightingManager Instance = new DefaultHighlightingManager();
225     
226      public DefaultHighlightingManager()
227      {
228        Resources.RegisterBuiltInHighlightings(this);
229      }
230     
231      // Registering a built-in highlighting
232      internal void RegisterHighlighting(string name, string[] extensions, string resourceName)
233      {
234        try {
235          #if DEBUG
236          // don't use lazy-loading in debug builds, show errors immediately
237          Xshd.XshdSyntaxDefinition xshd;
238          using (Stream s = Resources.OpenStream(resourceName)) {
239            using (XmlTextReader reader = new XmlTextReader(s)) {
240              xshd = Xshd.HighlightingLoader.LoadXshd(reader, false);
241            }
242          }
243          Debug.Assert(name == xshd.Name);
244          if (extensions != null)
245            Debug.Assert(System.Linq.Enumerable.SequenceEqual(extensions, xshd.Extensions));
246          else
247            Debug.Assert(xshd.Extensions.Count == 0);
248         
249          // round-trip xshd:
250//          string resourceFileName = Path.Combine(Path.GetTempPath(), resourceName);
251//          using (XmlTextWriter writer = new XmlTextWriter(resourceFileName, System.Text.Encoding.UTF8)) {
252//            writer.Formatting = Formatting.Indented;
253//            new Xshd.SaveXshdVisitor(writer).WriteDefinition(xshd);
254//          }
255//          using (FileStream fs = File.Create(resourceFileName + ".bin")) {
256//            new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter().Serialize(fs, xshd);
257//          }
258//          using (FileStream fs = File.Create(resourceFileName + ".compiled")) {
259//            new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter().Serialize(fs, Xshd.HighlightingLoader.Load(xshd, this));
260//          }
261         
262          RegisterHighlighting(name, extensions, Xshd.HighlightingLoader.Load(xshd, this));
263          #else
264          RegisterHighlighting(name, extensions, LoadHighlighting(resourceName));
265          #endif
266        } catch (HighlightingDefinitionInvalidException ex) {
267          throw new InvalidOperationException("The built-in highlighting '" + name + "' is invalid.", ex);
268        }
269      }
270     
271      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
272                                                       Justification = "LoadHighlighting is used only in release builds")]
273      Func<IHighlightingDefinition> LoadHighlighting(string resourceName)
274      {
275        Func<IHighlightingDefinition> func = delegate {
276          Xshd.XshdSyntaxDefinition xshd;
277          using (Stream s = Resources.OpenStream(resourceName)) {
278            using (XmlTextReader reader = new XmlTextReader(s)) {
279              // in release builds, skip validating the built-in highlightings
280              xshd = Xshd.HighlightingLoader.LoadXshd(reader, true);
281            }
282          }
283          return Xshd.HighlightingLoader.Load(xshd, this);
284        };
285        return func;
286      }
287    }
288  }
289}
Note: See TracBrowser for help on using the repository browser.