public Tagger( IThreadingContext threadingContext, IAsynchronousOperationListener listener, IForegroundNotificationService notificationService, TagSource tagSource, ITextBuffer subjectBuffer) { Contract.ThrowIfNull(subjectBuffer); _subjectBuffer = subjectBuffer; _cancellationTokenSource = new CancellationTokenSource(); _batchChangeNotifier = new BatchChangeNotifier( threadingContext, subjectBuffer, listener, notificationService, NotifyEditorNow, _cancellationTokenSource.Token); _tagSource = tagSource; _tagSource.OnTaggerAdded(this); _tagSource.TagsChangedForBuffer += OnTagsChangedForBuffer; _tagSource.Paused += OnPaused; _tagSource.Resumed += OnResumed; // There is a many-to-one relationship between Taggers and TagSources. i.e. one // tag-source can be used by many Taggers. As such, we may be a tagger that is // wrapping a tag-source that has already produced tags and had sent out the // notifications about those tags. // // However, we still want to notify the code consuming us that we have tags to // display. That way, tags can display as soon as possible when someone creates // a new tagger for a view/buffer. // // Note: we have to do this in the future instead of right now because we haven't // even been returned to the caller for them to hook up to change notifications // from us. notificationService.RegisterNotification( () => { if (this.TagsChanged == null) { // don't bother reporting tags if no one is listening. return; } var tags = _tagSource.TryGetTagIntervalTreeForBuffer(_subjectBuffer); if (tags != null) { var collection = new NormalizedSnapshotSpanCollection( tags.GetSpans(_subjectBuffer.CurrentSnapshot).Select(ts => ts.Span)); this.NotifyEditorNow(collection); } }, listener.BeginAsyncOperation(GetType().FullName + ".ctor-ReportInitialTags"), _cancellationTokenSource.Token); }
public Tagger( IAsynchronousOperationListener listener, IForegroundNotificationService notificationService, TagSource tagSource, ITextBuffer subjectBuffer) { Contract.ThrowIfNull(subjectBuffer); _subjectBuffer = subjectBuffer; _batchChangeNotifier = new BatchChangeNotifier(subjectBuffer, listener, notificationService, ReportChangedSpan); _tagSource = tagSource; _tagSource.OnTaggerAdded(this); _tagSource.TagsChangedForBuffer += OnTagsChangedForBuffer; _tagSource.Paused += OnPaused; _tagSource.Resumed += OnResumed; }
public TagSource( ITextView textViewOpt, ITextBuffer subjectBuffer, AbstractAsynchronousTaggerProvider <TTag> dataSource, IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService) : base(dataSource.ThreadingContext) { this.AssertIsForeground(); if (dataSource.SpanTrackingMode == SpanTrackingMode.Custom) { throw new ArgumentException("SpanTrackingMode.Custom not allowed.", "spanTrackingMode"); } _subjectBuffer = subjectBuffer; _textViewOpt = textViewOpt; _dataSource = dataSource; _asyncListener = asyncListener; _notificationService = notificationService; _batchChangeTokenSource = new CancellationTokenSource(); _batchChangeNotifier = new BatchChangeNotifier( dataSource.ThreadingContext, subjectBuffer, asyncListener, notificationService, NotifyEditorNow, _batchChangeTokenSource.Token); DebugRecordInitialStackTrace(); _workQueue = new AsynchronousSerialWorkQueue(ThreadingContext, asyncListener); this.CachedTagTrees = ImmutableDictionary.Create <ITextBuffer, TagSpanIntervalTree <TTag> >(); _eventSource = CreateEventSource(); Connect(); // Start computing the initial set of tags immediately. We want to get the UI // to a complete state as soon as possible. ComputeInitialTags(); return; void Connect() { this.AssertIsForeground(); _eventSource.Changed += OnEventSourceChanged; if (_dataSource.TextChangeBehavior.HasFlag(TaggerTextChangeBehavior.TrackTextChanges)) { _subjectBuffer.Changed += OnSubjectBufferChanged; } if (_dataSource.CaretChangeBehavior.HasFlag(TaggerCaretChangeBehavior.RemoveAllTagsOnCaretMoveOutsideOfTag)) { if (_textViewOpt == null) { throw new ArgumentException( nameof(_dataSource.CaretChangeBehavior) + " can only be specified for an " + nameof(IViewTaggerProvider)); } _textViewOpt.Caret.PositionChanged += OnCaretPositionChanged; } // Tell the interaction object to start issuing events. _eventSource.Connect(); } }