protected virtual void ForceRetagLines(TaggerState taggerState, int startLine, int endLine) { taggerState._firstDirtyLine = Math.Min(taggerState._firstDirtyLine ?? startLine, startLine); taggerState._lastDirtyLine = Math.Max(taggerState._lastDirtyLine ?? endLine, endLine); ITextSnapshot snapshot = _textBuffer.CurrentSnapshot; int start = snapshot.GetLineFromLineNumber(startLine).Start; int end = snapshot.GetLineFromLineNumber(endLine).EndIncludingLineBreak; var e = new SnapshotSpanEventArgs(new SnapshotSpan(_textBuffer.CurrentSnapshot, Span.FromBounds(start, end))); OnTagsChanged(e); }
protected virtual TState AdjustParseSpan(TaggerState taggerState, ref SnapshotSpan span) { int start = span.Start.Position; int endPosition = span.End.Position; ITextSnapshotLine firstDirtyLine = null; if (taggerState._firstDirtyLine.HasValue) { firstDirtyLine = span.Snapshot.GetLineFromLineNumber(taggerState._firstDirtyLine.Value); start = Math.Min(start, firstDirtyLine.Start.Position); } bool haveState = false; TState state = default(TState); int startLine = span.Snapshot.GetLineNumberFromPosition(start); while (startLine > 0) { LineStateInfo lineState = taggerState._lineStates[startLine - 1]; if (!lineState.MultilineToken) { haveState = true; state = lineState.EndLineState; break; } startLine--; } if (startLine == 0) { haveState = true; state = GetStartState(); } start = span.Snapshot.GetLineFromLineNumber(startLine).Start; int length = endPosition - start; span = new SnapshotSpan(span.Snapshot, start, length); Contract.Assert(haveState); return(state); }
protected virtual void SetLineState(TaggerState taggerState, int line, LineStateInfo state) { Contract.Requires(state.IsDirty || !taggerState._firstDirtyLine.HasValue || line <= taggerState._firstDirtyLine); using (_lock.WriteLock()) { taggerState._lineStates[line] = state; if (!state.IsDirty && taggerState._firstDirtyLine == line) { taggerState._firstDirtyLine++; } if (!state.IsDirty && taggerState._lastDirtyLine == line) { taggerState._firstDirtyLine = null; taggerState._lastDirtyLine = null; } } }
public AntlrTaggerBase(ITextBuffer textBuffer, IEqualityComparer <TState> stateComparer, ClassifierOptions options) { Contract.Requires <ArgumentNullException>(textBuffer != null, "textBuffer"); Contract.Requires <ArgumentNullException>(stateComparer != null, "stateComparer"); _textBuffer = textBuffer; _stateComparer = stateComparer; _options = options; ITextSnapshot currentSnapshot = textBuffer.CurrentSnapshot; TaggerState taggerState = new TaggerState(currentSnapshot); _lineStatesCache.Add(currentSnapshot, taggerState); if ((options & ClassifierOptions.ManualUpdate) == 0) { SubscribeEvents(); } ForceRetagLines(taggerState, 0, currentSnapshot.LineCount - 1); }
public AntlrTaggerBase([NotNull] ITextBuffer textBuffer, [NotNull] IEqualityComparer <TState> stateComparer, ClassifierOptions options) { Requires.NotNull(textBuffer, nameof(textBuffer)); Requires.NotNull(stateComparer, nameof(stateComparer)); _textBuffer = textBuffer; _stateComparer = stateComparer; _options = options; ITextSnapshot currentSnapshot = textBuffer.CurrentSnapshot; TaggerState taggerState = new TaggerState(currentSnapshot); _lineStatesCache.Add(currentSnapshot, taggerState); if ((options & ClassifierOptions.ManualUpdate) == 0) { SubscribeEvents(); } ForceRetagLines(taggerState, 0, currentSnapshot.LineCount - 1); }
protected virtual void HandleTextBufferChangedLowPriority(object sender, TextContentChangedEventArgs e) { if (_failedTimeout) { if (!_timeoutReported) { IServiceProvider serviceProvider = null; string message = null; string title = null; OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL; OLEMSGBUTTON button = OLEMSGBUTTON.OLEMSGBUTTON_OK; OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; if (serviceProvider != null) { _timeoutReported = true; VsShellUtilities.ShowMessageBox(serviceProvider, message, title, icon, button, defaultButton); } } return; } if (e.After == _textBuffer.CurrentSnapshot) { TaggerState taggerState = _lineStatesCache.GetValue(e.After, CreateTaggerState); if (taggerState._firstChangedLine.HasValue && taggerState._lastChangedLine.HasValue) { int startLine = taggerState._firstChangedLine.Value; int endLine = Math.Min(taggerState._lastChangedLine.Value, e.After.LineCount - 1); taggerState._firstChangedLine = null; taggerState._lastChangedLine = null; ForceRetagLines(taggerState, startLine, endLine); } } }
public virtual IEnumerable <ITagSpan <TTag> > GetTags(NormalizedSnapshotSpanCollection spans) { Contract.Ensures(Contract.Result <IEnumerable <ITagSpan <TTag> > >() != null); if (spans.Count == 0) { return(Enumerable.Empty <ITagSpan <TTag> >()); } List <ITagSpan <TTag> > tagSpans = new List <ITagSpan <TTag> >(); if (_failedTimeout) { return(tagSpans); } bool spanExtended = false; int extendMultilineSpanToLine = 0; SnapshotSpan span = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End); SnapshotSpan extendedSpan = span; ITextSnapshot snapshot = span.Snapshot; TaggerState taggerState = _lineStatesCache.GetValue(snapshot, CreateTaggerState); using (_lock.UpgradableReadLock(TimeSpan.FromMilliseconds(250))) { Span requestedSpan = span; TState startState = AdjustParseSpan(taggerState, ref span); ICharStream input = CreateInputStream(span); ITokenSourceWithState <TState> lexer = CreateLexer(input, span.Start.GetContainingLine().LineNumber + 1, startState); lexer.TokenFactory = new SnapshotTokenFactory(snapshot, GetEffectiveTokenSource(lexer)); IToken previousToken = null; bool previousTokenEndsLine = false; /* this is held outside the loop because only tokens which end at the end of a line * impact its value. */ bool lineStateChanged = false; while (true) { IToken token = lexer.NextToken(); // The latter is true for EOF token with span.End at the end of the document bool inBounds = token.StartIndex < span.End.Position || token.StopIndex < span.End.Position; int startLineCurrent; if (token.Type == IntStreamConstants.Eof) { startLineCurrent = span.Snapshot.LineCount - 1; } else { startLineCurrent = token.Line - 1; } // endLinePrevious is the line number the previous token ended on int endLinePrevious; if (previousToken != null) { Contract.Assert(previousToken.StopIndex >= previousToken.StartIndex, "previousToken can't be EOF"); endLinePrevious = span.Snapshot.GetLineNumberFromPosition(previousToken.StopIndex); } else { endLinePrevious = span.Snapshot.GetLineNumberFromPosition(span.Start) - 1; } if (startLineCurrent > endLinePrevious + 1 || (startLineCurrent == endLinePrevious + 1 && !previousTokenEndsLine)) { int firstMultilineLine = endLinePrevious; if (previousToken == null || previousTokenEndsLine) { firstMultilineLine++; } for (int i = firstMultilineLine; i < startLineCurrent; i++) { if (!taggerState._lineStates[i].MultilineToken || lineStateChanged) { extendMultilineSpanToLine = i + 1; } SetLineState(taggerState, i, LineStateInfo.Multiline); } } if (IsMultilineToken(span.Snapshot, lexer, token)) { int startLine = span.Snapshot.GetLineNumberFromPosition(token.StartIndex); int stopLine = span.Snapshot.GetLineNumberFromPosition(Math.Max(token.StartIndex, token.StopIndex)); for (int i = startLine; i < stopLine; i++) { if (!taggerState._lineStates[i].MultilineToken) { extendMultilineSpanToLine = i + 1; } SetLineState(taggerState, i, LineStateInfo.Multiline); } } bool tokenEndsLine = TokenEndsAtEndOfLine(span.Snapshot, lexer, token); if (tokenEndsLine) { TState stateAtEndOfLine = lexer.GetCurrentState(); int line = span.Snapshot.GetLineNumberFromPosition(Math.Max(token.StartIndex, token.StopIndex)); lineStateChanged = taggerState._lineStates[line].MultilineToken || !_stateComparer.Equals(taggerState._lineStates[line].EndLineState, stateAtEndOfLine); // even if the state didn't change, we call SetLineState to make sure the _first/_lastChangedLine values get updated. SetLineState(taggerState, line, new LineStateInfo(stateAtEndOfLine)); if (lineStateChanged) { if (line < span.Snapshot.LineCount - 1) { /* update the span's end position or the line state change won't be reflected * in the editor */ int endPosition = span.Snapshot.GetLineFromLineNumber(line + 1).EndIncludingLineBreak; if (endPosition > extendedSpan.End) { spanExtended = true; extendedSpan = new SnapshotSpan(extendedSpan.Snapshot, Span.FromBounds(extendedSpan.Start, endPosition)); } } } } if (token.Type == IntStreamConstants.Eof) { break; } if (token.StartIndex >= span.End.Position) { break; } previousToken = token; previousTokenEndsLine = tokenEndsLine; if (token.StopIndex < requestedSpan.Start) { continue; } var tokenTagSpans = GetTagSpansForToken(token, span.Snapshot); if (tokenTagSpans != null) { tagSpans.AddRange(tokenTagSpans); } if (!inBounds) { break; } } } if (extendMultilineSpanToLine > 0) { int endPosition = extendMultilineSpanToLine < span.Snapshot.LineCount ? span.Snapshot.GetLineFromLineNumber(extendMultilineSpanToLine).EndIncludingLineBreak : span.Snapshot.Length; if (endPosition > extendedSpan.End) { spanExtended = true; extendedSpan = new SnapshotSpan(extendedSpan.Snapshot, Span.FromBounds(extendedSpan.Start, endPosition)); } } if (spanExtended) { /* Subtract 1 from each of these because the spans include the line break on their last * line, forcing it to appear as the first position on the following line. */ int firstLine = extendedSpan.Snapshot.GetLineNumberFromPosition(span.End); int lastLine = extendedSpan.Snapshot.GetLineNumberFromPosition(extendedSpan.End) - 1; // when considering the last line of a document, span and extendedSpan may end on the same line ForceRetagLines(taggerState, firstLine, Math.Max(firstLine, lastLine)); } return(tagSpans); }
protected virtual void HandleTextBufferChangedHighPriority(object sender, TextContentChangedEventArgs e) { try { using (_lock.WriteLock(TimeSpan.FromSeconds(1))) { TaggerState beforeState = _lineStatesCache.GetValue(e.Before, CreateTaggerState); TaggerState afterState = _lineStatesCache.GetValue(e.After, CreateTaggerState); afterState._firstChangedLine = beforeState._firstChangedLine; afterState._lastChangedLine = beforeState._lastChangedLine; afterState._firstDirtyLine = beforeState._firstDirtyLine; afterState._lastDirtyLine = beforeState._lastDirtyLine; List <LineStateInfo> lineStates = new List <LineStateInfo>(beforeState._lineStates); foreach (ITextChange change in e.Changes) { int lineNumberFromPosition = e.After.GetLineNumberFromPosition(change.NewPosition); int num2 = e.After.GetLineNumberFromPosition(change.NewEnd); if (change.LineCountDelta < 0) { lineStates.RemoveRange(lineNumberFromPosition, Math.Abs(change.LineCountDelta)); } else if (change.LineCountDelta > 0) { TState endLineState = lineStates[lineNumberFromPosition].EndLineState; LineStateInfo element = new LineStateInfo(endLineState); lineStates.InsertRange(lineNumberFromPosition, Enumerable.Repeat(element, change.LineCountDelta)); } if (afterState._lastDirtyLine > lineNumberFromPosition) { afterState._lastDirtyLine += change.LineCountDelta; } if (afterState._lastChangedLine > lineNumberFromPosition) { afterState._lastChangedLine += change.LineCountDelta; } for (int i = lineNumberFromPosition; i <= num2; i++) { TState num5 = lineStates[i].EndLineState; LineStateInfo info2 = new LineStateInfo(num5, true); lineStates[i] = info2; } afterState._firstChangedLine = Math.Min(afterState._firstChangedLine ?? lineNumberFromPosition, lineNumberFromPosition); afterState._lastChangedLine = Math.Max(afterState._lastChangedLine ?? num2, num2); } Contract.Assert(lineStates.Count == afterState._lineStates.Length); lineStates.CopyTo(afterState._lineStates); } } catch (TimeoutException) { _failedTimeout = true; UnsubscribeEvents(); } }