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);
            }
Beispiel #2
0
            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;
            }
Beispiel #3
0
            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();
                }
            }