private void TestParser(string source, StatementListBuilder <StatementType, ParserTokenType> expected) { StringTextProvider textProvider = new StringTextProvider(source); var actual = XmlStatementParser.ParseStatements(new Position(0, 0, 0), textProvider); Assert.True(expected.SequenceEqual(actual, this.statementComparer)); }
/// <summary> /// Scans the given SnapshotSpan for potential matches for this classification. /// </summary> /// <param name="span">The span currently being classified</param> /// <returns>A list of ClassificationSpans that represent spans identified to be of this classification</returns> public IList <ClassificationSpan> GetClassificationSpans(SnapshotSpan span) { List <ClassificationSpan> classifications = new List <ClassificationSpan>(); try { using (ReaderTextProvider textProvider = new ReaderTextProvider(new TextSnapshotToTextReader(span.Snapshot))) { // We parse the whole buffer for statements, not just the current line, // because we need to know if we're on a continuation line. // TODO: Cache the "beginning of logical line" points so that we // don't have to re-parse everything each time? IEnumerable <Statement <StatementType, ParserTokenType> > statements = null; switch (this.language) { case ParserLanguage.Rtype: statements = RtypeStatementParser.ParseStatements(new Position(0, 0, 0), textProvider); break; case ParserLanguage.Xml: statements = XmlStatementParser.ParseStatements(new Position(0, 0, 0), textProvider); break; } int spanStart = span.Start.Position; int spanEnd = span.End.Position; foreach (var statement in statements) { if (statement.Range.End.Offset <= spanStart) { continue; } if (statement.Range.Start.Offset >= spanEnd) { break; } // for a comment statement, we don't have to look at the // individual tokens... if (statement.StatementType == StatementType.Comment) { var classification = this.commentType; // Ensure the returned span doesn't extend past the request! var classifiedSpan = span.Intersection(span.Snapshot.CreateSpanFromSwix(statement.Range)); if (classifiedSpan.HasValue) { classifications.Add(new ClassificationSpan(classifiedSpan.Value, classification)); } } else { foreach (var token in statement.AllTokens) { if (token.Range.End.Offset <= span.Start.Position) { continue; } if (token.Range.Start.Offset >= span.End.Position) { break; } IClassificationType classification = null; switch (token.TokenType) { case ParserTokenType.Unknown: classification = this.delimiterType; break; case ParserTokenType.Whitespace: classification = this.whitespaceType; break; case ParserTokenType.Comment: classification = this.commentType; break; case ParserTokenType.UseKeyword: classification = this.keywordType; break; case ParserTokenType.Object: classification = this.objectType; break; case ParserTokenType.PropertyName: classification = this.propertyType; break; case ParserTokenType.Equals: classification = this.assignmentType; break; case ParserTokenType.PropertyValue: case ParserTokenType.DoubleQuote: case ParserTokenType.SingleQuote: classification = this.valueType; break; case ParserTokenType.NamespacePrefix: classification = this.namespacePrefixType; break; case ParserTokenType.NamespacePrefixDeclaration: // TODO break; case ParserTokenType.NamespaceDeclaration: // TODO break; case ParserTokenType.AttachedPropertyObject: classification = this.attachableObjectType; break; case ParserTokenType.LeftAngle: case ParserTokenType.RightAngle: case ParserTokenType.Colon: case ParserTokenType.Slash: case ParserTokenType.Period: classification = this.delimiterType; break; default: break; } if (classification != null) { // Ensure the returned span doesn't extend past the request! var classifiedSpan = span.Intersection(span.Snapshot.CreateSpanFromSwix(token.Range)); if (classifiedSpan.HasValue) { classifications.Add(new ClassificationSpan(classifiedSpan.Value, classification)); } } } } } } } catch (Exception) { } return(classifications); }