diff --git a/ICSharpCode.NRefactory.Xml/AXmlParser.cs b/ICSharpCode.NRefactory.Xml/AXmlParser.cs index dfee11174d..d2c327ef30 100644 --- a/ICSharpCode.NRefactory.Xml/AXmlParser.cs +++ b/ICSharpCode.NRefactory.Xml/AXmlParser.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading; using System.Xml.Linq; using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Utils; @@ -51,12 +52,13 @@ namespace ICSharpCode.NRefactory.Xml /// Parses a document into a flat list of tags. /// /// Parsed tag soup. - public IList ParseTagSoup(ITextSource textSource) + public IList ParseTagSoup(ITextSource textSource, + CancellationToken cancellationToken = default(CancellationToken)) { if (textSource == null) throw new ArgumentNullException("textSource"); var reader = new TagReader(this, textSource, false); - var internalObjects = reader.ReadAllObjects(); + var internalObjects = reader.ReadAllObjects(cancellationToken); return CreatePublic(internalObjects); } @@ -66,16 +68,21 @@ namespace ICSharpCode.NRefactory.Xml /// The parser state from a previous call to ParseIncremental(). Use null for the first call. /// The text source for the new document version. /// Out: the new parser state, pass this to the next ParseIncremental() call. + /// Optional: cancellation token. /// Parsed tag soup. - public IList ParseTagSoupIncremental(IncrementalParserState oldParserState, ITextSource newTextSource, out IncrementalParserState newParserState) + public IList ParseTagSoupIncremental( + IncrementalParserState oldParserState, ITextSource newTextSource, out IncrementalParserState newParserState, + CancellationToken cancellationToken = default(CancellationToken)) { if (newTextSource == null) throw new ArgumentNullException("newTextSource"); - var internalObjects = InternalParseIncremental(oldParserState, newTextSource, out newParserState, false); + var internalObjects = InternalParseIncremental(oldParserState, newTextSource, out newParserState, false, cancellationToken); return CreatePublic(internalObjects); } - List InternalParseIncremental(IncrementalParserState oldParserState, ITextSource newTextSource, out IncrementalParserState newParserState, bool collapseProperlyNestedElements) + List InternalParseIncremental( + IncrementalParserState oldParserState, ITextSource newTextSource, out IncrementalParserState newParserState, + bool collapseProperlyNestedElements, CancellationToken cancellationToken) { var reader = new TagReader(this, newTextSource, collapseProperlyNestedElements); ITextSourceVersion newVersion = newTextSource.Version; @@ -83,9 +90,9 @@ namespace ICSharpCode.NRefactory.Xml List internalObjects; if (reuseMap != null) - internalObjects = reader.ReadAllObjectsIncremental(oldParserState.Objects, reuseMap); + internalObjects = reader.ReadAllObjectsIncremental(oldParserState.Objects, reuseMap, cancellationToken); else - internalObjects = reader.ReadAllObjects(); + internalObjects = reader.ReadAllObjects(cancellationToken); if (newVersion != null) newParserState = new IncrementalParserState(newTextSource.TextLength, newVersion, internalObjects.ToArray()); @@ -98,14 +105,14 @@ namespace ICSharpCode.NRefactory.Xml /// /// Parses a document. /// - public AXmlDocument Parse(ITextSource textSource) + public AXmlDocument Parse(ITextSource textSource, CancellationToken cancellationToken = default(CancellationToken)) { if (textSource == null) throw new ArgumentNullException("textSource"); var reader = new TagReader(this, textSource, true); - var internalObjects = reader.ReadAllObjects(); + var internalObjects = reader.ReadAllObjects(cancellationToken); var heuristic = new TagMatchingHeuristics(textSource); - return new AXmlDocument(null, 0, heuristic.CreateDocument(internalObjects)); + return new AXmlDocument(null, 0, heuristic.CreateDocument(internalObjects, cancellationToken)); } /// @@ -114,14 +121,17 @@ namespace ICSharpCode.NRefactory.Xml /// The parser state from a previous call to ParseIncremental(). Use null for the first call. /// The text source for the new document version. /// Out: the new parser state, pass this to the next ParseIncremental() call. + /// Optional: cancellation token. /// Parsed tag soup. - public AXmlDocument ParseIncremental(IncrementalParserState oldParserState, ITextSource newTextSource, out IncrementalParserState newParserState) + public AXmlDocument ParseIncremental( + IncrementalParserState oldParserState, ITextSource newTextSource, out IncrementalParserState newParserState, + CancellationToken cancellationToken = default(CancellationToken)) { if (newTextSource == null) throw new ArgumentNullException("newTextSource"); - var internalObjects = InternalParseIncremental(oldParserState, newTextSource, out newParserState, true); + var internalObjects = InternalParseIncremental(oldParserState, newTextSource, out newParserState, true, cancellationToken); var heuristic = new TagMatchingHeuristics(newTextSource); - return new AXmlDocument(null, 0, heuristic.CreateDocument(internalObjects)); + return new AXmlDocument(null, 0, heuristic.CreateDocument(internalObjects, cancellationToken)); } } } diff --git a/ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs b/ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs index 2772f44b35..dc997d9907 100644 --- a/ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs +++ b/ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs @@ -20,6 +20,7 @@ using System; using System.Linq; using System.Collections.Generic; using System.Diagnostics; +using System.Threading; using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Utils; @@ -28,6 +29,7 @@ namespace ICSharpCode.NRefactory.Xml class TagMatchingHeuristics { readonly ITextSource textSource; + const int MaxConfigurationCount = 30; public TagMatchingHeuristics(ITextSource textSource) @@ -35,9 +37,9 @@ namespace ICSharpCode.NRefactory.Xml this.textSource = textSource; } - public InternalDocument CreateDocument(List tagSoup) + public InternalDocument CreateDocument(List tagSoup, CancellationToken cancellationToken) { - var stack = InsertPlaceholderTags(tagSoup); + var stack = InsertPlaceholderTags(tagSoup, cancellationToken); InternalDocument doc = new InternalDocument(); var docElements = CreateElements(ref stack); docElements.Reverse(); // reverse due to stack @@ -201,7 +203,7 @@ namespace ICSharpCode.NRefactory.Xml return indentation; } - ImmutableStack InsertPlaceholderTags(List objects) + ImmutableStack InsertPlaceholderTags(List objects, CancellationToken cancellationToken) { // Calculate indentation levels in front of the tags: int[] indentationBeforeTags = new int[objects.Count]; @@ -218,6 +220,7 @@ namespace ICSharpCode.NRefactory.Xml listA.Add(new Configuration(new OpenTagStack(), ImmutableStack.Empty, 0)); for (int i = 0; i < indentationBeforeTags.Length; i++) { + cancellationToken.ThrowIfCancellationRequested(); ProcessObject(objects[i], indentationBeforeTags[i], listA, ref listB); Swap(ref listA, ref listB); } diff --git a/ICSharpCode.NRefactory.Xml/TagReader.cs b/ICSharpCode.NRefactory.Xml/TagReader.cs index e6178de37d..ef6e424c1e 100644 --- a/ICSharpCode.NRefactory.Xml/TagReader.cs +++ b/ICSharpCode.NRefactory.Xml/TagReader.cs @@ -22,6 +22,7 @@ using System.Diagnostics; using System.Globalization; using System.Linq; using System.Text; +using System.Threading; using ICSharpCode.NRefactory.Editor; namespace ICSharpCode.NRefactory.Xml @@ -38,21 +39,23 @@ namespace ICSharpCode.NRefactory.Xml elementNameStack = new Stack(); } - public List ReadAllObjects() + public List ReadAllObjects(CancellationToken cancellationToken) { while (HasMoreData()) { + cancellationToken.ThrowIfCancellationRequested(); ReadObject(); } return objects; } - public List ReadAllObjectsIncremental(InternalObject[] oldObjects, List reuseMap) + public List ReadAllObjectsIncremental(InternalObject[] oldObjects, List reuseMap, CancellationToken cancellationToken) { ObjectIterator oldObjectIterator = new ObjectIterator(oldObjects); int reuseMapIndex = 0; while (reuseMapIndex < reuseMap.Count) { var reuseEntry = reuseMap[reuseMapIndex]; while (this.CurrentLocation < reuseEntry.NewOffset) { + cancellationToken.ThrowIfCancellationRequested(); ReadObject(); } if (this.CurrentLocation >= reuseEntry.NewOffset + reuseEntry.Length) { @@ -80,6 +83,7 @@ namespace ICSharpCode.NRefactory.Xml } } while (HasMoreData()) { + cancellationToken.ThrowIfCancellationRequested(); ReadObject(); } return objects;