/// <summary> /// This handler gets called whenever there is a visual change in the view. /// Example: edit or a scroll. /// </summary> private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e) { using (Logger.LogBlock(FunctionId.Tagger_AdornmentManager_OnLayoutChanged, CancellationToken.None)) using (_asyncListener.BeginAsyncOperation(GetType() + ".OnLayoutChanged")) { // Make sure we're on the UI thread. Contract.ThrowIfFalse(_textView.VisualElement.Dispatcher.CheckAccess()); var reformattedSpans = e.NewOrReformattedSpans; var viewSnapshot = _textView.TextSnapshot; // No need to remove tags as these spans are reformatted anyways. UpdateSpans_CallOnlyOnUIThread(reformattedSpans, removeOldTags: false); // Compute any spans that had been invalidated but were not affected by layout. List <IMappingSpan> invalidated; lock (_invalidatedSpansLock) { invalidated = _invalidatedSpans; _invalidatedSpans = null; } if (invalidated != null) { var invalidatedAndNormalized = TranslateAndNormalize(invalidated, viewSnapshot); var invalidatedButNotReformatted = NormalizedSnapshotSpanCollection.Difference( invalidatedAndNormalized, e.NewOrReformattedSpans); UpdateSpans_CallOnlyOnUIThread(invalidatedButNotReformatted, removeOldTags: true); } } }
public IEnumerable <ITagSpan <NaturalTextTag> > GetTags(NormalizedSnapshotSpanCollection spans) { NormalizedSnapshotSpanCollection classifiedSpans = new NormalizedSnapshotSpanCollection( spans.SelectMany(span => _aggregator.GetClassificationSpans(span)) .Select(c => c.Span)); NormalizedSnapshotSpanCollection plainSpans = NormalizedSnapshotSpanCollection.Difference(spans, classifiedSpans); foreach (var span in plainSpans) { yield return(new TagSpan <NaturalTextTag>(span, new NaturalTextTag())); } }
private void UpdateReadOnlyRegions(bool removeOnly = false) { AssertIsForeground(); if (!removeOnly && _session.ReplacementText == string.Empty) { return; } using (var readOnlyEdit = _subjectBuffer.CreateReadOnlyRegionEdit()) { foreach (var oldReadOnlyRegion in _readOnlyRegions) { readOnlyEdit.RemoveReadOnlyRegion(oldReadOnlyRegion); } _readOnlyRegions.Clear(); if (!removeOnly) { // We will compute the new read only regions to be all spans that are not currently in an editable span var editableSpans = GetEditableSpansForSnapshot(_subjectBuffer.CurrentSnapshot); var entireBufferSpan = _subjectBuffer.CurrentSnapshot.GetSnapshotSpanCollection(); var newReadOnlySpans = NormalizedSnapshotSpanCollection.Difference(entireBufferSpan, new NormalizedSnapshotSpanCollection(editableSpans)); foreach (var newReadOnlySpan in newReadOnlySpans) { _readOnlyRegions.Add(readOnlyEdit.CreateDynamicReadOnlyRegion(newReadOnlySpan, SpanTrackingMode.EdgeExclusive, EdgeInsertionMode.Allow, _isBufferReadOnly)); } // The spans we added allow typing at the start and end. We'll add extra // zero-width read-only regions at the start and end of the file to fix this, // but only if we don't have an identifier at the start or end that _would_ let // them type there. if (editableSpans.All(s => s.Start > 0)) { _readOnlyRegions.Add(readOnlyEdit.CreateDynamicReadOnlyRegion(new Span(0, 0), SpanTrackingMode.EdgeExclusive, EdgeInsertionMode.Deny, _isBufferReadOnly)); } if (editableSpans.All(s => s.End < _subjectBuffer.CurrentSnapshot.Length)) { _readOnlyRegions.Add(readOnlyEdit.CreateDynamicReadOnlyRegion(new Span(_subjectBuffer.CurrentSnapshot.Length, 0), SpanTrackingMode.EdgeExclusive, EdgeInsertionMode.Deny, _isBufferReadOnly)); } } readOnlyEdit.Apply(); } }
//===================================================================== /// <summary> /// Get natural language spans for the given dirty span /// </summary> /// <param name="dirtySpan">The dirty span for which to get natural language spans</param> /// <returns>A normalized snapshot span collection containing natural language spans</returns> private NormalizedSnapshotSpanCollection GetNaturalLanguageSpansForDirtySpan(SnapshotSpan dirtySpan) { if (_isClosed || dirtySpan.IsEmpty) { return(new NormalizedSnapshotSpanCollection()); } ITextSnapshot snapshot = dirtySpan.Snapshot; var spans = new NormalizedSnapshotSpanCollection( _naturalTextAggregator.GetTags(dirtySpan) .SelectMany(tag => tag.Span.GetSpans(snapshot)) .Select(s => s.Intersection(dirtySpan)) .Where(s => s.HasValue && !s.Value.IsEmpty) .Select(s => s.Value)); // Now, subtract out IUrlTag spans, since we never want to spell check URLs var urlSpans = new NormalizedSnapshotSpanCollection(_urlAggregator.GetTags(spans).SelectMany( tagSpan => tagSpan.Span.GetSpans(snapshot))); return(NormalizedSnapshotSpanCollection.Difference(spans, urlSpans)); }
static NormalizedSnapshotSpanCollection SymmetricDifference(NormalizedSnapshotSpanCollection first, NormalizedSnapshotSpanCollection second) { return(NormalizedSnapshotSpanCollection.Union( NormalizedSnapshotSpanCollection.Difference(first, second), NormalizedSnapshotSpanCollection.Difference(second, first))); }
internal IEnumerable <ICollapsible> InternalGetAllRegions(NormalizedSnapshotSpanCollection spans, bool exposedRegionsOnly, CancellationToken?cancel = null) { EnsureValid(spans); // No collapsibles if disabled if (!isEnabled || spans.Count == 0) { return(new List <Collapsible>()); } ITextSnapshot snapshot = spans[0].Snapshot; IList <Collapsed> currentCollapsed = GetCollapsedRegionsInternal(spans, exposedRegionsOnly); IEnumerable <ICollapsible> newCollapsibles; if (!exposedRegionsOnly || currentCollapsed.Count == 0) { newCollapsibles = CollapsiblesFromTags(this.InternalGetTags(spans, cancel)).Keys; } else { NormalizedSnapshotSpanCollection collapsedRegions = new NormalizedSnapshotSpanCollection(currentCollapsed.Select(c => c.Extent.GetSpan(snapshot))); NormalizedSnapshotSpanCollection exposed = NormalizedSnapshotSpanCollection.Difference(spans, collapsedRegions); // Ensure there is an empty region on each end SnapshotSpan first = spans[0]; SnapshotSpan last = spans[spans.Count - 1]; NormalizedSnapshotSpanCollection ends = new NormalizedSnapshotSpanCollection(new SnapshotSpan[] { new SnapshotSpan(first.Start, 0), new SnapshotSpan(last.End, 0) }); exposed = NormalizedSnapshotSpanCollection.Union(exposed, ends); newCollapsibles = CollapsiblesFromTags(this.InternalGetTags(exposed, cancel)).Keys.Where(c => IsRegionExposed(c, snapshot)); } IEnumerable <ICollapsed> removed; var merged = MergeRegions(currentCollapsed, newCollapsibles, out removed); // NOTE: IF we have misbehaved taggers, it is possible that we'll see invalid // changes here in removed regions that are currently collapsed. We can deal // with this by expanding as needed, but it will cause an event to be sent out, which will // likely be unexpected and cause bugs in our clients. // There are a few ways we can deal with this: // #1: Expand/collapse regions and event foreach (var removedRegion in removed) { Debug.Fail("Removing a region here means a tagger has misbehaved."); if (removedRegion.IsCollapsed) { Expand(removedRegion); } } // Other options: // #2: Return the new regions without doing anything special // #3: Return the current collapsed + uncollapsed added regions return(merged); }