/// <summary> /// Adds classification spans to the given collection. /// Scans a contiguous sub-<paramref name="span"/> of a larger code span which starts at <paramref name="codeStartLine"/>. /// </summary> private void AddClassifications(Tokenizer tokenizer, List <ClassificationSpan> classifications, SnapshotSpan span, int codeStartLine, int codeStartLineOffset) { Debug.Assert(span.Length > 0); var snapshot = span.Snapshot; int firstLine = snapshot.GetLineNumberFromPosition(span.Start); int lastLine = snapshot.GetLineNumberFromPosition(span.End - 1); Contract.Assert(codeStartLineOffset >= 0); Contract.Assert(firstLine >= codeStartLine); _tokenCache.EnsureCapacity(snapshot.LineCount); // find the closest line preceding firstLine for which we know categorizer state, stop at the codeStartLine: LineTokenization lineTokenization; int currentLine = _tokenCache.IndexOfPreviousTokenization(firstLine, codeStartLine, out lineTokenization) + 1; object state = lineTokenization.State; while (currentLine <= lastLine) { if (!_tokenCache.TryGetTokenization(currentLine, out lineTokenization)) { lineTokenization = TokenizeLine(tokenizer, snapshot, state, currentLine, (currentLine == codeStartLine) ? codeStartLineOffset : 0); _tokenCache[currentLine] = lineTokenization; } state = lineTokenization.State; classifications.AddRange( from token in lineTokenization.Tokens let classification = ClassifyToken(span, token, currentLine) where classification != null select classification ); currentLine++; } }
/// <summary> /// Adds classification spans to the given collection. /// Scans a contiguous sub-<paramref name="span"/> of a larger code span which starts at <paramref name="codeStartLine"/>. /// </summary> private void AddClassifications(Tokenizer tokenizer, List <ClassificationSpan> classifications, SnapshotSpan span) { Debug.Assert(span.Length > 0); var snapshot = span.Snapshot; int firstLine = snapshot.GetLineNumberFromPosition(span.Start); int lastLine = snapshot.GetLineNumberFromPosition(span.End - 1); Contract.Assert(firstLine >= 0); _tokenCache.EnsureCapacity(snapshot.LineCount); // find the closest line preceding firstLine for which we know categorizer state, stop at the codeStartLine: LineTokenization lineTokenization; int currentLine = _tokenCache.IndexOfPreviousTokenization(firstLine, 0, out lineTokenization) + 1; object state = lineTokenization.State; while (currentLine <= lastLine) { if (!_tokenCache.TryGetTokenization(currentLine, out lineTokenization)) { lineTokenization = TokenizeLine(tokenizer, snapshot, state, currentLine); _tokenCache[currentLine] = lineTokenization; } state = lineTokenization.State; for (int i = 0; i < lineTokenization.Tokens.Length; i++) { var token = lineTokenization.Tokens[i]; if (token.Category == TokenCategory.IncompleteMultiLineStringLiteral) { // we need to walk backwards to find the start of this multi-line string... TokenInfo startToken = token; int validPrevLine; int length = startToken.SourceSpan.Length; if (i == 0) { length += GetLeadingMultiLineStrings(tokenizer, snapshot, firstLine, currentLine, out validPrevLine, ref startToken); } else { validPrevLine = currentLine; } if (i == lineTokenization.Tokens.Length - 1) { length += GetTrailingMultiLineStrings(tokenizer, snapshot, currentLine, state); } var multiStrSpan = new Span(SnapshotSpanToSpan(snapshot, startToken, validPrevLine).Start, length); classifications.Add( new ClassificationSpan( new SnapshotSpan(snapshot, multiStrSpan), _provider.StringLiteral ) ); } else { var classification = ClassifyToken(span, token, currentLine); if (classification != null) { classifications.Add(classification); } } } currentLine++; } }