internal AsyncTagger(IAsyncTaggerSource <TData, TTag> asyncTaggerSource) { _asyncTaggerSource = asyncTaggerSource; _asyncTaggerSource.Changed += OnAsyncTaggerSourceChanged; // If there is an ITextView associated with the IAsyncTaggerSource then we want to // listen to LayoutChanges. If the layout changes while we are getting tags we want // to prioritize the visible lines if (_asyncTaggerSource.TextViewOptional != null) { _asyncTaggerSource.TextViewOptional.LayoutChanged += OnLayoutChanged; } }
protected void Create(params string[] lines) { _textView = CreateTextView(lines); _textBuffer = _textView.TextBuffer; _globalSettings = new GlobalSettings(); _globalSettings.IgnoreCase = true; _globalSettings.HighlightSearch = true; _vimData = Vim.VimData; _asyncTaggerSourceRaw = new HighlightSearchTaggerSource( _textView, _globalSettings, _vimData, Vim.VimHost); _asyncTaggerSource = _asyncTaggerSourceRaw; }
protected void Create(params string[] lines) { _textView = CreateTextView(lines); _textBuffer = _textView.TextBuffer; _globalSettings = Vim.GlobalSettings; _globalSettings.IgnoreCase = true; _globalSettings.HighlightSearch = true; _vimData = Vim.VimData; _asyncTaggerSourceRaw = new HighlightSearchTaggerSource( _textView, _globalSettings, _vimData, Vim.VimHost); _asyncTaggerSource = _asyncTaggerSourceRaw; }
private void Create(params string[] lines) { _textView = CreateTextView(lines); _textBuffer = _textView.TextBuffer; _globalSettings = new GlobalSettings(); _globalSettings.IgnoreCase = true; _globalSettings.HighlightSearch = true; _searchService = VimUtil.CreateSearchService(); _vimData = Vim.VimData; _asyncTaggerSourceRaw = new HighlightSearchTaggerSource( _textView, _globalSettings, VimUtil.CreateTextStructureNavigator(_textBuffer, WordKind.NormalWord), _searchService, _vimData, Vim.VimHost); _asyncTaggerSource = _asyncTaggerSourceRaw; }
private void Create(params string[] lines) { _textView = CreateTextView(lines); _textBuffer = _textView.TextBuffer; _globalSettings = new GlobalSettings(); _globalSettings.IgnoreCase = true; _globalSettings.HighlightSearch = true; _searchService = Vim.SearchService; _vimData = Vim.VimData; _asyncTaggerSourceRaw = new HighlightSearchTaggerSource( _textView, _globalSettings, CreateTextStructureNavigator(_textBuffer, WordKind.NormalWord), _searchService, _vimData, Vim.VimHost); _asyncTaggerSource = _asyncTaggerSourceRaw; }
public static IClassifier CreateClassifierRaw <TData>(IAsyncTaggerSource <TData, IClassificationTag> asyncTaggerSource) { return(new Classifier(CreateTaggerRaw(asyncTaggerSource))); }
/// <summary> /// Create an ITagger implementation for the IAsyncTaggerSource. /// </summary> public static ITagger <TTag> CreateTaggerRaw <TData, TTag>(IAsyncTaggerSource <TData, TTag> asyncTaggerSource) where TTag : ITag { return(new AsyncTagger <TData, TTag>(asyncTaggerSource)); }
private static void GetTagsInBackgroundCore( IAsyncTaggerSource <TData, TTag> asyncTaggerSource, TData data, int chunkCount, Channel channel, NormalizedLineRangeCollection visited, CancellationToken cancellationToken, Action <CompleteReason> onComplete, Action <SnapshotLineRange, ReadOnlyCollection <ITagSpan <TTag> > > onProgress) { CompleteReason completeReason; try { // Keep track of the LineRange values which we've already provided tags for. Don't // duplicate the work var toProcess = new Queue <SnapshotLineRange>(); // *** This value can be wrong *** // This is the version number we expect the Channel to have. It's used // as a hueristic to determine if we should prioritize a value off of the stack or our // local stack. If it's wrong it means we prioritize the wrong value. Not a bug it // just changes the order in which values will appear var versionNumber = channel.CurrentVersion; // Take one value off of the threadedLineRangeStack value. If the value is bigger than // our chunking increment then we will add the value in chunks to the toProcess queue Action popOne = () => { var value = channel.Read(); if (!value.HasValue) { return; } var lineRange = value.Value; if (lineRange.Count <= chunkCount) { toProcess.Enqueue(lineRange); return; } var snapshot = lineRange.Snapshot; var startLineNumber = lineRange.StartLineNumber; while (startLineNumber <= lineRange.LastLineNumber) { var startLine = snapshot.GetLineFromLineNumber(startLineNumber); var localRange = SnapshotLineRange.CreateForLineAndMaxCount(startLine, chunkCount); toProcess.Enqueue(localRange); startLineNumber += chunkCount; } }; // Get the tags for the specified SnapshotLineRange and return the results. No chunking is done here, // the data is just directly processed Action <SnapshotLineRange> getTags = tagLineRange => { var unvisited = visited.GetUnvisited(tagLineRange.LineRange); if (unvisited.HasValue) { var tagList = EmptyTagList; try { tagLineRange = SnapshotLineRange.CreateForLineNumberRange(tagLineRange.Snapshot, unvisited.Value.StartLineNumber, unvisited.Value.LastLineNumber).Value; tagList = asyncTaggerSource.GetTagsInBackground(data, tagLineRange.ExtentIncludingLineBreak, cancellationToken); } catch (Exception e) { // Ignore exceptions that are thrown by IAsyncTaggerSource. If the tagger threw then we consider // the tags to be nothing for this span. // // It's important that we register some value here. If we register nothing then the foreground will // never see this slot as fulfilled and later requests for this span will eventually queue up another // background request EditorUtilsTrace.TraceInfo("AsyncTagger source exception in background processing {0}", e); } visited.Add(tagLineRange.LineRange); onProgress(tagLineRange, tagList); } }; do { versionNumber = channel.CurrentVersion; popOne(); // We've drained both of the sources of input hence we are done if (0 == toProcess.Count) { break; } while (0 != toProcess.Count) { // If at any point the threadLineRangeStack value changes we consider the new values to have // priority over the old ones if (versionNumber != channel.CurrentVersion) { break; } cancellationToken.ThrowIfCancellationRequested(); var lineRange = toProcess.Dequeue(); getTags(lineRange); } } while (!cancellationToken.IsCancellationRequested); completeReason = cancellationToken.IsCancellationRequested ? CompleteReason.Cancelled : CompleteReason.Finished; } catch (OperationCanceledException) { // Don't report cancellation exceptions. These are thrown during cancellation for fast // break from the operation. It's really a control flow mechanism completeReason = CompleteReason.Cancelled; } catch (Exception e) { // Handle cancellation exceptions and everything else. Don't want an errant // exception thrown by the IAsyncTaggerSource to crash the process EditorUtilsTrace.TraceInfo("AsyncTagger Exception in background processing {0}", e); completeReason = CompleteReason.Error; } onComplete(completeReason); }