public TagSource( ITextView textViewOpt, ITextBuffer subjectBuffer, AbstractAsynchronousTaggerProvider <TTag> dataSource, IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService) { if (dataSource.SpanTrackingMode == SpanTrackingMode.Custom) { throw new ArgumentException("SpanTrackingMode.Custom not allowed.", "spanTrackingMode"); } _subjectBuffer = subjectBuffer; _textViewOpt = textViewOpt; _dataSource = dataSource; _asyncListener = asyncListener; _notificationService = notificationService; _tagSpanComparer = new TagSpanComparer(_dataSource.TagComparer); DebugRecordInitialStackTrace(); _workQueue = new AsynchronousSerialWorkQueue(asyncListener); this.CachedTagTrees = ImmutableDictionary.Create <ITextBuffer, TagSpanIntervalTree <TTag> >(); _eventSource = CreateEventSource(); Connect(); // Kick off a task to compute the initial set of tags. RecalculateTagsOnChanged(new TaggerEventArgs(TaggerDelay.Short)); }
public TagSource( ITextView textViewOpt, ITextBuffer subjectBuffer, AbstractAsynchronousTaggerProvider <TTag> dataSource, IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService) : base(dataSource.ThreadingContext) { if (dataSource.SpanTrackingMode == SpanTrackingMode.Custom) { throw new ArgumentException("SpanTrackingMode.Custom not allowed.", "spanTrackingMode"); } _subjectBuffer = subjectBuffer; _textViewOpt = textViewOpt; _dataSource = dataSource; _asyncListener = asyncListener; _notificationService = notificationService; _tagSpanComparer = new TagSpanComparer(_dataSource.TagComparer); 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(); }
public TagSource( ITextView textViewOpt, ITextBuffer subjectBuffer, AbstractAsynchronousTaggerProvider <TTag> dataSource, IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService) { if (dataSource.SpanTrackingMode == SpanTrackingMode.Custom) { throw new ArgumentException("SpanTrackingMode.Custom not allowed.", "spanTrackingMode"); } _subjectBuffer = subjectBuffer; _textViewOpt = textViewOpt; _dataSource = dataSource; _asyncListener = asyncListener; _notificationService = notificationService; _tagSpanComparer = new TagSpanComparer(_dataSource.TagComparer); DebugRecordInitialStackTrace(); _workQueue = new AsynchronousSerialWorkQueue(asyncListener); this.CachedTagTrees = ImmutableDictionary.Create <ITextBuffer, TagSpanIntervalTree <TTag> >(); _eventSource = CreateEventSource(); Connect(); // Kick off a task to immediately compute the initial set of tags. This work should // not be cancellable (except if we get completely released), even if more events come // in. That way we can get the initial set of results for the buffer as quickly as // possible, without kicking the work down the road. var initialTagsCancellationToken = _initialComputationCancellationTokenSource.Token; // Note: we always kick this off to the new UI pump instead of computing tags right // on this thread. The reason for that is that we may be getting created at a time // when the view itself is initializing. As such the view is not in a state where // we want code touching it. RegisterNotification( () => RecomputeTagsForeground(cancellationTokenOpt: initialTagsCancellationToken), delay: 0, cancellationToken: initialTagsCancellationToken); }
public TagSource( ITextView textViewOpt, ITextBuffer subjectBuffer, AbstractAsynchronousTaggerProvider <TTag> dataSource, IAsynchronousOperationListener asyncListener) : 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; _highPriTagsChangedQueue = new AsyncBatchingWorkQueue <NormalizedSnapshotSpanCollection>( TaggerDelay.NearImmediate.ComputeTimeDelay(), ProcessTagsChangedAsync, equalityComparer: null, asyncListener, _tagSourceState.Target.DisposalToken); if (_dataSource.AddedTagNotificationDelay == TaggerDelay.NearImmediate) { // if the tagger wants "added tags" to be reported "NearImmediate"ly, then just reuse // the "high pri" queue as that already reports things at that cadence. _normalPriTagsChangedQueue = _highPriTagsChangedQueue; } else { _normalPriTagsChangedQueue = new AsyncBatchingWorkQueue <NormalizedSnapshotSpanCollection>( _dataSource.AddedTagNotificationDelay.ComputeTimeDelay(), ProcessTagsChangedAsync, equalityComparer: null, asyncListener, _tagSourceState.Target.DisposalToken); } DebugRecordInitialStackTrace(); _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. EnqueueWork(initialTags: true); 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(); } }
public TestAccessor(AbstractAsynchronousTaggerProvider <TTag> provider) => _provider = provider;
public TagSource( ITextView?textView, ITextBuffer subjectBuffer, ITextBufferVisibilityTracker?visibilityTracker, AbstractAsynchronousTaggerProvider <TTag> dataSource, IAsynchronousOperationListener asyncListener) { dataSource.ThreadingContext.ThrowIfNotOnUIThread(); if (dataSource.SpanTrackingMode == SpanTrackingMode.Custom) { throw new ArgumentException("SpanTrackingMode.Custom not allowed.", "spanTrackingMode"); } _textView = textView; _subjectBuffer = subjectBuffer; _visibilityTracker = visibilityTracker; _dataSource = dataSource; _asyncListener = asyncListener; _workspaceRegistration = Workspace.GetWorkspaceRegistration(subjectBuffer.AsTextContainer()); // Collapse all booleans added to just a max of two ('true' or 'false') representing if we're being // asked for initial tags or not _eventChangeQueue = new AsyncBatchingWorkQueue <bool>( dataSource.EventChangeDelay.ComputeTimeDelay(), ProcessEventChangeAsync, EqualityComparer <bool> .Default, asyncListener, _disposalTokenSource.Token); _highPriTagsChangedQueue = new AsyncBatchingWorkQueue <NormalizedSnapshotSpanCollection>( TaggerDelay.NearImmediate.ComputeTimeDelay(), ProcessTagsChangedAsync, equalityComparer: null, asyncListener, _disposalTokenSource.Token); if (_dataSource.AddedTagNotificationDelay == TaggerDelay.NearImmediate) { // if the tagger wants "added tags" to be reported "NearImmediate"ly, then just reuse // the "high pri" queue as that already reports things at that cadence. _normalPriTagsChangedQueue = _highPriTagsChangedQueue; } else { _normalPriTagsChangedQueue = new AsyncBatchingWorkQueue <NormalizedSnapshotSpanCollection>( _dataSource.AddedTagNotificationDelay.ComputeTimeDelay(), ProcessTagsChangedAsync, equalityComparer: null, asyncListener, _disposalTokenSource.Token); } DebugRecordInitialStackTrace(); // Create the tagger-specific events that will cause the tagger to refresh. _eventSource = CreateEventSource(); // any time visibility changes, resume tagging on all taggers. Any non-visible taggers will pause // themselves immediately afterwards. _onVisibilityChanged = () => ResumeIfVisible(); // Now hook up this tagger to all interesting events. Connect(); // Now that we're all hooked up to the events we care about, start computing the initial set of tags at // high priority. We want to get the UI to a complete state as soon as possible. EnqueueWork(highPriority: true); return; // Represented as a local function just so we can keep this in sync with Dispose.Disconnect below. void Connect() { _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); // Register to hear about visibility changes so we can pause/resume this tagger. _visibilityTracker?.RegisterForVisibilityChanges(subjectBuffer, _onVisibilityChanged); _eventSource.Changed += OnEventSourceChanged; if (_dataSource.TextChangeBehavior.HasFlag(TaggerTextChangeBehavior.TrackTextChanges)) { _subjectBuffer.Changed += OnSubjectBufferChanged; } if (_dataSource.CaretChangeBehavior.HasFlag(TaggerCaretChangeBehavior.RemoveAllTagsOnCaretMoveOutsideOfTag)) { if (_textView == null) { throw new ArgumentException( nameof(_dataSource.CaretChangeBehavior) + " can only be specified for an " + nameof(IViewTaggerProvider)); } _textView.Caret.PositionChanged += OnCaretPositionChanged; } // Tell the interaction object to start issuing events. _eventSource.Connect(); } }
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(); } }