diff --git a/src/EditorFeatures/Core/Implementation/BraceMatching/BraceHighlightingViewTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/BraceMatching/BraceHighlightingViewTaggerProvider.cs index a296f2a9b0a1633375a4c09840f1c9369a426c25..0bee923b42d6c032b588e0ee065c35b57c114e75 100644 --- a/src/EditorFeatures/Core/Implementation/BraceMatching/BraceHighlightingViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/BraceMatching/BraceHighlightingViewTaggerProvider.cs @@ -35,13 +35,9 @@ internal class BraceHighlightingViewTaggerProvider : _braceMatcherService = braceMatcherService; } - protected override bool RemoveTagsThatIntersectEdits - { - get - { - return true; - } - } + protected override bool RemoveTagsThatIntersectEdits => true; + + protected override SpanTrackingMode SpanTrackingMode => SpanTrackingMode.EdgeExclusive; protected override IEnumerable> TagSourceOptions { diff --git a/src/EditorFeatures/Core/Implementation/Classification/SemanticClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/Classification/SemanticClassificationTaggerProvider.cs index c004d2b33f14fc8272761eefea7a70eee375bc73..0e908782e52ff3bd7488a4a6402b13d30e7eedd1 100644 --- a/src/EditorFeatures/Core/Implementation/Classification/SemanticClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/Classification/SemanticClassificationTaggerProvider.cs @@ -38,17 +38,13 @@ internal partial class SemanticClassificationTaggerProvider : AbstractAsynchrono _typeMap = typeMap; } - protected override bool RemoveTagsThatIntersectEdits - { - get - { - // We don't want to remove a tag just because it intersected an edit. This can - // cause flashing when a edit touches the edge of a classified symbol without - // changing it. For example, if you have "Console." and you remove the , - // then you don't want to remove the classification for 'Console'. - return false; - } - } + // We don't want to remove a tag just because it intersected an edit. This can + // cause flashing when a edit touches the edge of a classified symbol without + // changing it. For example, if you have "Console." and you remove the , + // then you don't want to remove the classification for 'Console'. + protected override bool RemoveTagsThatIntersectEdits => false; + + protected override SpanTrackingMode SpanTrackingMode => SpanTrackingMode.EdgeExclusive; protected override IEnumerable> TagSourceOptions { @@ -67,6 +63,7 @@ protected override ProducerPopulatedTagSource CreateTagSourc AsyncListener, NotificationService, this.RemoveTagsThatIntersectEdits, + this.SpanTrackingMode, GetRelatedTagSource); } diff --git a/src/EditorFeatures/Core/Implementation/Highlighting/HighlighterViewTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/Highlighting/HighlighterViewTaggerProvider.cs index 46195d1180c5f174701e337c0bcd122e0b0e6a2a..bc8796981b98635c52ef1e89831604c7ad2aced6 100644 --- a/src/EditorFeatures/Core/Implementation/Highlighting/HighlighterViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/Highlighting/HighlighterViewTaggerProvider.cs @@ -35,13 +35,9 @@ internal class HighlighterViewTaggerProvider : _highlighterService = highlighterService; } - protected override bool RemoveTagsThatIntersectEdits - { - get - { - return true; - } - } + protected override bool RemoveTagsThatIntersectEdits => true; + + protected override SpanTrackingMode SpanTrackingMode => SpanTrackingMode.EdgeExclusive; protected override IEnumerable> TagSourceOptions { @@ -73,7 +69,8 @@ protected override ProducerPopulatedTagSource CreateTagSourceCore( CreateEventSource(textViewOpt, subjectBuffer), AsyncListener, NotificationService, - this.RemoveTagsThatIntersectEdits); + this.RemoveTagsThatIntersectEdits, + this.SpanTrackingMode); } } } diff --git a/src/EditorFeatures/Core/Implementation/Highlighting/HighlightingTagSource.cs b/src/EditorFeatures/Core/Implementation/Highlighting/HighlightingTagSource.cs index 66872f593185022c784afaafa030fbfc779afc15..5d6d4df06a769601fffc92833bb59a7b909a0061 100644 --- a/src/EditorFeatures/Core/Implementation/Highlighting/HighlightingTagSource.cs +++ b/src/EditorFeatures/Core/Implementation/Highlighting/HighlightingTagSource.cs @@ -23,13 +23,9 @@ internal sealed class HighlightingTagSource : ViewTagSource ITaggerEventSource eventSource, IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService, - bool removeTagsThatIntersectEdits) : base(textView, - subjectBuffer, - tagProducer, - eventSource, - asyncListener, - notificationService, - removeTagsThatIntersectEdits) + bool removeTagsThatIntersectEdits, + SpanTrackingMode spanTrackingMode) + : base(textView, subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, spanTrackingMode) { } diff --git a/src/EditorFeatures/Core/Implementation/LineSeparators/LineSeparatorTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/LineSeparators/LineSeparatorTaggerProvider.cs index 715d123a9ab3a2b70b9f44900a09e118441226e2..0aa6a855d84877a59b3cf57d041c5e2e5059ff21 100644 --- a/src/EditorFeatures/Core/Implementation/LineSeparators/LineSeparatorTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/LineSeparators/LineSeparatorTaggerProvider.cs @@ -33,13 +33,9 @@ internal partial class LineSeparatorTaggerProvider : { } - protected override bool RemoveTagsThatIntersectEdits - { - get - { - return true; - } - } + protected override bool RemoveTagsThatIntersectEdits => true; + + protected override SpanTrackingMode SpanTrackingMode => SpanTrackingMode.EdgeExclusive; protected override ITaggerEventSource CreateEventSource(ITextView textViewOpt, ITextBuffer subjectBuffer) { diff --git a/src/EditorFeatures/Core/Implementation/Outlining/OutliningTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/Outlining/OutliningTaggerProvider.cs index abaff922c35134286896cc94fef5c98467773650..27e580fbd8d1d44e7f8e5dfa9e8169f98dd211a2 100644 --- a/src/EditorFeatures/Core/Implementation/Outlining/OutliningTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/Outlining/OutliningTaggerProvider.cs @@ -51,13 +51,9 @@ internal partial class OutliningTaggerProvider : _projectionBufferFactoryService = projectionBufferFactoryService; } - protected override bool RemoveTagsThatIntersectEdits - { - get - { - return true; - } - } + protected override bool RemoveTagsThatIntersectEdits => true; + + protected override SpanTrackingMode SpanTrackingMode => SpanTrackingMode.EdgeExclusive; protected override ITaggerEventSource CreateEventSource(ITextView textViewOpt, ITextBuffer subjectBuffer) { diff --git a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingTagSource.cs b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingTagSource.cs index 8d126865fd670152af78a723bfd21914adb1808d..40ba04f616cfc5901a5597ec0f6f8fb22454c49c 100644 --- a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingTagSource.cs +++ b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingTagSource.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -31,11 +30,15 @@ internal partial class ReferenceHighlightingTagSource : ProducerPopulatedTagSour private int _lastUpdateTagsSolutionVersion = VoidVersion; public ReferenceHighlightingTagSource( - ITextView textView, ITextBuffer subjectBuffer, - ITagProducer tagProducer, ITaggerEventSource eventSource, - IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService, - bool removeTagsThatIntersectEdits) : - base(subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, null) + ITextView textView, + ITextBuffer subjectBuffer, + ITagProducer tagProducer, + ITaggerEventSource eventSource, + IAsynchronousOperationListener asyncListener, + IForegroundNotificationService notificationService, + bool removeTagsThatIntersectEdits, + SpanTrackingMode spanTrackingMode) + : base(subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, spanTrackingMode, bufferToRelatedTagSource: null) { _textView = textView; } diff --git a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs index 50c6f310f32c034573acc3c22fae4dd576558c2b..4a455d36759997b46dae24e030676d9467387997 100644 --- a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs @@ -36,13 +36,9 @@ internal partial class ReferenceHighlightingViewTaggerProvider : _semanticChangeNotificationService = semanticChangeNotificationService; } - protected override bool RemoveTagsThatIntersectEdits - { - get - { - return true; - } - } + protected override bool RemoveTagsThatIntersectEdits => true; + + protected override SpanTrackingMode SpanTrackingMode => SpanTrackingMode.EdgeExclusive; protected override IEnumerable> TagSourcePerLanguageOptions { @@ -85,7 +81,8 @@ protected override ProducerPopulatedTagSource : } protected abstract bool RemoveTagsThatIntersectEdits { get; } + protected abstract SpanTrackingMode SpanTrackingMode { get; } + protected abstract ITagProducer CreateTagProducer(); protected abstract ITaggerEventSource CreateEventSource(ITextView textViewOpt, ITextBuffer subjectBuffer); @@ -44,6 +46,7 @@ protected override ProducerPopulatedTagSource CreateTagSourceCore(ITextVie AsyncListener, NotificationService, this.RemoveTagsThatIntersectEdits, + this.SpanTrackingMode, GetRelatedTagSource); } diff --git a/src/EditorFeatures/Core/Shared/Tagging/TagProviders/AbstractAsynchronousViewTaggerProvider.cs b/src/EditorFeatures/Core/Shared/Tagging/TagProviders/AbstractAsynchronousViewTaggerProvider.cs index 83a6c09b2d721b53973555331cdc75979589078d..1d0ccd2852127e2a6a67888001e4e980a93b3aef 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/TagProviders/AbstractAsynchronousViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/TagProviders/AbstractAsynchronousViewTaggerProvider.cs @@ -23,6 +23,8 @@ internal abstract class AbstractAsynchronousViewTaggerProvider : } protected abstract bool RemoveTagsThatIntersectEdits { get; } + protected abstract SpanTrackingMode SpanTrackingMode { get; } + protected abstract ITagProducer CreateTagProducer(); protected abstract ITaggerEventSource CreateEventSource(ITextView textViewOpt, ITextBuffer subjectBuffer); @@ -65,7 +67,8 @@ protected override ProducerPopulatedTagSource CreateTagSourceCore(ITextVie CreateEventSource(textViewOpt, subjectBuffer), AsyncListener, NotificationService, - this.RemoveTagsThatIntersectEdits); + this.RemoveTagsThatIntersectEdits, + this.SpanTrackingMode); } } } diff --git a/src/EditorFeatures/Core/Shared/Tagging/TagSources/BufferTagSource.cs b/src/EditorFeatures/Core/Shared/Tagging/TagSources/BufferTagSource.cs index 53d202ff85b7707f630af6597b48ca7b473f822e..573af62fe9437eec1be786e189fdeec8a270205f 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/TagSources/BufferTagSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/TagSources/BufferTagSource.cs @@ -20,8 +20,9 @@ internal class BufferTagSource : ProducerPopulatedTagSource where TT ITextBuffer subjectBuffer, ITagProducer tagProducer, ITaggerEventSource eventSource, IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService, bool removeTagsThatIntersectEdits, + SpanTrackingMode spanTrackingMode, Func> bufferToRelatedTagSource) : - base(subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, bufferToRelatedTagSource) + base(subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, spanTrackingMode, bufferToRelatedTagSource) { } diff --git a/src/EditorFeatures/Core/Shared/Tagging/TagSources/ProducerPopulatedTagSource.cs b/src/EditorFeatures/Core/Shared/Tagging/TagSources/ProducerPopulatedTagSource.cs index 2bdc6c14455290b56dd248124bfa193b6520f012..588111720dddb8ed72b6a7c69ce9e783d6933572 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/TagSources/ProducerPopulatedTagSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/TagSources/ProducerPopulatedTagSource.cs @@ -56,6 +56,11 @@ internal abstract partial class ProducerPopulatedTagSource : TagSource private readonly bool _removeTagsThatIntersectEdits; + /// + /// The tracking mode we want to use for the tracking spans we create. + /// + private readonly SpanTrackingMode _spanTrackingMode; + private ImmutableDictionary> _cachedTags; private bool _computeTagsSynchronouslyIfNoAsynchronousComputationHasCompleted; @@ -98,11 +103,18 @@ internal abstract partial class ProducerPopulatedTagSource : TagSource> bufferToRelatedTagSource = null) : base(subjectBuffer, notificationService, asyncListener) { + if (spanTrackingMode == SpanTrackingMode.Custom) + { + throw new ArgumentException("SpanTrackingMode.Custom not allowed.", "spanTrackingMode"); + } + _tagProducer = tagProducer; _removeTagsThatIntersectEdits = removeTagsThatIntersectEdits; + _spanTrackingMode = spanTrackingMode; _cachedTags = ImmutableDictionary.Create>(); @@ -270,7 +282,7 @@ private void UpdateCachedTagsForBuffer(ITextSnapshot snapshot, TagSpanIntervalTr TagSpanIntervalTree oldCachedTagsForBuffer = null; if (!oldCachedTags.TryGetValue(snapshot.TextBuffer, out oldCachedTagsForBuffer)) { - oldCachedTagsForBuffer = new TagSpanIntervalTree(snapshot.TextBuffer, SpanTrackingMode.EdgeExclusive); + oldCachedTagsForBuffer = new TagSpanIntervalTree(snapshot.TextBuffer, _spanTrackingMode); } var difference = ComputeDifference(snapshot, oldCachedTagsForBuffer, newTagsForBuffer); @@ -427,14 +439,14 @@ private void CheckSnapshot(ITextSnapshot snapshot) tags = tagsInBuffer; } - map = map.Add(tagsInBuffer.Key, new TagSpanIntervalTree(tagsInBuffer.Key, SpanTrackingMode.EdgeExclusive, tags)); + map = map.Add(tagsInBuffer.Key, new TagSpanIntervalTree(tagsInBuffer.Key, _spanTrackingMode, tags)); } foreach (var kv in tagsToKeepByBuffer) { if (!map.ContainsKey(kv.Key) && kv.Value.Any()) { - map = map.Add(kv.Key, new TagSpanIntervalTree(kv.Key, SpanTrackingMode.EdgeExclusive, kv.Value)); + map = map.Add(kv.Key, new TagSpanIntervalTree(kv.Key, _spanTrackingMode, kv.Value)); } } @@ -453,12 +465,12 @@ private void CheckSnapshot(ITextSnapshot snapshot) foreach (var tagsInBuffer in tagsByBuffer) { var tags = tagsInBuffer.Key == invalidBuffer ? tagsInBuffer.Concat(tagsToKeep) : tagsInBuffer; - map = map.Add(tagsInBuffer.Key, new TagSpanIntervalTree(tagsInBuffer.Key, SpanTrackingMode.EdgeExclusive, tags)); + map = map.Add(tagsInBuffer.Key, new TagSpanIntervalTree(tagsInBuffer.Key, _spanTrackingMode, tags)); } if (!map.ContainsKey(invalidBuffer) && tagsToKeep.Any()) { - map = map.Add(invalidBuffer, new TagSpanIntervalTree(invalidBuffer, SpanTrackingMode.EdgeExclusive, tagsToKeep)); + map = map.Add(invalidBuffer, new TagSpanIntervalTree(invalidBuffer, _spanTrackingMode, tagsToKeep)); } return map; diff --git a/src/EditorFeatures/Core/Shared/Tagging/TagSources/SemanticBufferTagSource.cs b/src/EditorFeatures/Core/Shared/Tagging/TagSources/SemanticBufferTagSource.cs index ae8ac6a95d8dddf83e6907639c67a3971acba684..2c09d739641dadb89b78e56465317dbc7451eac8 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/TagSources/SemanticBufferTagSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/TagSources/SemanticBufferTagSource.cs @@ -22,10 +22,15 @@ internal sealed class SemanticBufferTagSource : ProducerPopulatedTagSource private VersionStamp _lastSemanticVersion; public SemanticBufferTagSource( - ITextBuffer subjectBuffer, ITagProducer tagProducer, ITaggerEventSource eventSource, - IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService, - bool removeTagsThatIntersectEdits, Func> bufferToRelatedTagSource) : - base(subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, bufferToRelatedTagSource) + ITextBuffer subjectBuffer, + ITagProducer tagProducer, + ITaggerEventSource eventSource, + IAsynchronousOperationListener asyncListener, + IForegroundNotificationService notificationService, + bool removeTagsThatIntersectEdits, + SpanTrackingMode spanTrackingMode, + Func> bufferToRelatedTagSource) + : base(subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, spanTrackingMode, bufferToRelatedTagSource) { _lastSemanticVersion = VersionStamp.Default; } diff --git a/src/EditorFeatures/Core/Shared/Tagging/TagSources/ViewTagSource.cs b/src/EditorFeatures/Core/Shared/Tagging/TagSources/ViewTagSource.cs index 322df406b0edfcc49a7c39d6c62e7fd7e027868a..bb97d96f1ad4f4060208ab99294792adb066f262 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/TagSources/ViewTagSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/TagSources/ViewTagSource.cs @@ -22,8 +22,9 @@ internal class ViewTagSource : ProducerPopulatedTagSource where TTag public ViewTagSource( ITextView textView, ITextBuffer subjectBuffer, ITagProducer tagProducer, ITaggerEventSource eventSource, IAsynchronousOperationListener asyncListener, IForegroundNotificationService notificationService, - bool removeTagsThatIntersectEdits) : - base(subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, null) + bool removeTagsThatIntersectEdits, + SpanTrackingMode spanTrackingMode) : + base(subjectBuffer, tagProducer, eventSource, asyncListener, notificationService, removeTagsThatIntersectEdits, spanTrackingMode, bufferToRelatedTagSource: null) { _textView = textView; } diff --git a/src/EditorFeatures/Core/Tagging/AsynchronousTaggerProvider.cs b/src/EditorFeatures/Core/Tagging/AsynchronousTaggerProvider.cs index ea8deabd9b9e3a1035fad6f64d92f0f75d08c0a2..3819f70c57fe93cbd7e1a5779408cf85fb3eb69e 100644 --- a/src/EditorFeatures/Core/Tagging/AsynchronousTaggerProvider.cs +++ b/src/EditorFeatures/Core/Tagging/AsynchronousTaggerProvider.cs @@ -63,13 +63,9 @@ public AsynchronousTaggerProviderImpl(IAsynchronousOperationListener asyncListen _dataSource = dataSource; } - protected override bool RemoveTagsThatIntersectEdits - { - get - { - return _dataSource.RemoveTagsThatIntersectEdits; - } - } + protected override bool RemoveTagsThatIntersectEdits => _dataSource.RemoveTagsThatIntersectEdits; + + protected override SpanTrackingMode SpanTrackingMode => _dataSource.SpanTrackingMode; protected override ITaggerEventSource CreateEventSource(ITextView textViewOpt, ITextBuffer subjectBuffer) { diff --git a/src/EditorFeatures/Core/Tagging/IAsynchronousTaggerDataSource.cs b/src/EditorFeatures/Core/Tagging/IAsynchronousTaggerDataSource.cs index 803f41c69cc18a74745dc44aa76d3483e6964003..6c007f2c472d734699d0af421fa29ab76dfd106a 100644 --- a/src/EditorFeatures/Core/Tagging/IAsynchronousTaggerDataSource.cs +++ b/src/EditorFeatures/Core/Tagging/IAsynchronousTaggerDataSource.cs @@ -28,6 +28,13 @@ internal interface IAsynchronousTaggerDataSource where TTag : ITag /// bool RemoveTagsThatIntersectEdits { get; } + /// + /// The behavior of tags that are created by the async tagger. This will matter for tags + /// created for a previous version of a document that are mapped forward by the async + /// tagging architecture. This value cannot be . + /// + SpanTrackingMode SpanTrackingMode { get; } + /// /// Creates the that notifies the /// that it should recompute tags for the text buffer after an appropriate . diff --git a/src/EditorFeatures/Test/Tagging/AsynchronousTaggerTests.cs b/src/EditorFeatures/Test/Tagging/AsynchronousTaggerTests.cs index 16dd9c47451fad49d6c3fc5e4eed16c7a041177b..33a93b466b19286fa07dada05507c9db6be22e7b 100644 --- a/src/EditorFeatures/Test/Tagging/AsynchronousTaggerTests.cs +++ b/src/EditorFeatures/Test/Tagging/AsynchronousTaggerTests.cs @@ -181,13 +181,9 @@ private sealed class TestTaggerProvider : AbstractAsynchronousBufferTaggerProvid _disableCancellation = disableCancellation; } - protected override bool RemoveTagsThatIntersectEdits - { - get - { - return true; - } - } + protected override bool RemoveTagsThatIntersectEdits => true; + + protected override SpanTrackingMode SpanTrackingMode => SpanTrackingMode.EdgeExclusive; protected override ITaggerEventSource CreateEventSource(ITextView textViewOpt, ITextBuffer subjectBuffer) {