/// <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>(); // Extend the span to full lines, and tokenize/classify... var firstLine = span.Start.GetContainingLine(); var lastLine = (span.End - 1).GetContainingLine(); // Remove any errors in the span? ////this.RemoveTagSpans(s => span.Contains(s.Span.GetSpan(span.Snapshot))); ////var toRemove = this.errorListProvider.Tasks.OfType<Task>().Where( //// t => firstLine.LineNumber <= t.Line && t.Line <= lastLine.LineNumber).ToList(); ////foreach (var task in toRemove) ////{ //// this.errorListProvider.Tasks.Remove(task); ////} SnapshotTextProvider textProvider = new SnapshotTextProvider(span.Snapshot, span); var statements = StatementParser.ParseStatements( new Position(firstLine.Start.Position, firstLine.LineNumber, 0), textProvider); foreach (var statement in statements) { // If the statement ends before the requested span, ignore it completely. if (statement.AllTokens.Last().Range.End.Offset <= span.Start.Position) { continue; } foreach (var token in statement.AllTokens) { // Skip any tokens entirely before or after the span... if (token.Range.End.Offset <= span.Start.Position) { continue; } else if (token.Range.Start.Offset >= span.End.Position) { break; } IClassificationType classification = null; switch (token.TokenType) { case ParserTokenType.Unknown: break; case ParserTokenType.Whitespace: classification = this.whitespaceType; break; case ParserTokenType.Comment: classification = this.commentType; break; case ParserTokenType.TypeKeyword: classification = this.keywordType; break; case ParserTokenType.MessageTypeDefinition: classification = this.messageTypeDefinitionType; break; case ParserTokenType.MessageTypeRange: classification = this.messageTypeRangeType; break; case ParserTokenType.MessageType: classification = this.messageTypeType; break; case ParserTokenType.MessageName: classification = this.messageNameType; break; case ParserTokenType.LeftBrace: classification = this.replacementDelimiterStart; break; case ParserTokenType.RightBrace: classification = this.replacementDelimiterEnd; break; case ParserTokenType.LeftBracket: case ParserTokenType.RightBracket: case ParserTokenType.Comma: case ParserTokenType.Colon: classification = this.replacementDelimiterType; break; case ParserTokenType.ReplacementName: classification = this.replacementNameType; break; case ParserTokenType.ReplacementType: classification = this.replacementTypeType; break; case ParserTokenType.ReplacementPosition: classification = this.replacementPositionType; break; case ParserTokenType.ReplacementAlignment: classification = this.replacementAlignmentType; break; case ParserTokenType.ReplacementFormat: classification = this.replacementFormatType; break; case ParserTokenType.Value: classification = this.stringType; break; case ParserTokenType.Escape: classification = this.escapeType; break; default: break; } if (classification != null) { SnapshotSpan?intersect = span.Intersection(token.Range.AsSpan()); if (intersect.HasValue) { classifications.Add(new ClassificationSpan(intersect.Value, classification)); } } // If there were any errors, pass those up... ////if (token.Errors != null) ////{ //// foreach (Error error in token.Errors) //// { //// ErrorTag tag = new ErrorTag("syntax error", error.Message); //// this.CreateTagSpan(span.Snapshot.CreateTrackingSpan(token), tag); //// ErrorTask task = new ErrorTask(); //// task.Document = this.filename; //// task.Line = error.Range.Start.Line; //// task.Column = error.Range.Start.Column; //// task.Text = error.Message; //// // inline? //// task.Category = TaskCategory.CodeSense; //// task.ErrorCategory = TaskErrorCategory.Error; //// // Why do we have to do this ourselves? //// if (!string.IsNullOrWhiteSpace(task.Document)) //// { //// IVsUIHierarchy hierarchy; //// uint item; //// IVsWindowFrame frame; //// if (VsShellUtilities.IsDocumentOpen( //// this.provider.ServiceProvider, //// task.Document, //// VSConstants.LOGVIEWID.Any_guid, //// out hierarchy, //// out item, //// out frame)) //// { //// task.HierarchyItem = hierarchy; //// } //// task.Navigate += Task_Navigate; //// } //// this.errorListProvider.Tasks.Add(task); //// } ////} } // If the statement ends at or after the requested span, we're done! if (statement.AllTokens.Last().Range.End.Offset >= span.End.Position) { break; } } return(classifications); }