/// <summary> /// This method 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) { // TODO this is an inefficient call to GetMultiLineComments each time! var multiLineComments = GetMultiLineComments(span); var compiler = new Compiler(); compiler.Options.Add("number", "float"); // Use Cobra's own tokenizer var tokCobra = new VisualCobraTokenizer { TypeProvider = compiler, WillReturnComments = true, WillReturnDirectives = true }; Node.SetCompiler(compiler); tokCobra.StartSource(span.GetText()); var classifications = GetClassificationsFromCobraTokenizer(span, tokCobra); // Add classification spans for indent errors classifications.AddRange(GetIndentErrorSpans(span)); var removeMe = new List<ClassificationSpan>(); var e = classifications.GetEnumerator(); while (e.MoveNext()) { if (e.Current != null) { removeMe.AddRange(from comment in multiLineComments // ReSharper disable PossibleNullReferenceException where comment.Contains(e.Current.Span) // ReSharper restore PossibleNullReferenceException select e.Current); } } foreach (var remove in removeMe) { classifications.Remove(remove); } // Add all comment spans // TODO Many of these will be out of bounds, so they should perhaps be trimmed down first classifications.AddRange(multiLineComments.Select(comment => new ClassificationSpan(new SnapshotSpan(span.Snapshot, comment), _cobraCommentClassificationType))); return classifications; }
/// <summary> /// Gets the classifications from <see cref="VisualCobraTokenizer"/>. /// </summary> /// <param name="span">The span to get classifications from.</param> /// <param name="tokCobra">The tokenizer to use.</param> /// <returns>A list of <see cref="ClassificationSpan"/> objects representing the classifications /// in <paramref name="span"/>.</returns> private static List<ClassificationSpan> GetClassificationsFromCobraTokenizer(SnapshotSpan span, VisualCobraTokenizer tokCobra) { // Tried parallelising, but I'm not sure it's safe in combination with "previous". var classifications = new List<ClassificationSpan>(); IToken previous = null; foreach (var tok in tokCobra.AllTokens()) { if (tok.IsKeyword) { var tokenSpan = new SnapshotSpan(span.Snapshot, new Span(span.Start.Position + tok.CharNum - 1, tok.Length)); // +1 var cs = new ClassificationSpan(tokenSpan, _cobraKeywordClassificationType); classifications.Add(cs); } else { switch (tok.Which) { case "STRING_SINGLE": case "STRING_DOUBLE": case "CHAR": case "CHAR_LIT_SINGLE": AddSpanToClassifications(span, classifications, tok, tok.Length, _cobraStringClassificationType); break; case "ID": // Note "CLASS" is the class keyword, not "a class" if (IsClass(tok)) { AddSpanToClassifications(span, classifications, tok, tok.Length, _cobraClassClassificationType); } break; case "QUESTION": { if (IsClass(previous)) { // add another char to cover the ? on the end of a nillable class AddSpanToClassifications(span, classifications, tok, 1, _cobraClassClassificationType); } break; } case "COMMENT": AddSpanToClassifications(span, classifications, tok, tok.Length, _cobraCommentClassificationType); break; } previous = tok; } } return classifications; }