Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
c5914db4
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c5914db4
编写于
7月 21, 2015
作者:
C
Cyrus Najmabadi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Pull all specialized ReferenceHighlighting behavior into the core tagging infrastructure.
上级
b519d004
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
214 addition
and
308 deletion
+214
-308
src/EditorFeatures/Core/EditorFeatures.csproj
src/EditorFeatures/Core/EditorFeatures.csproj
+0
-1
src/EditorFeatures/Core/Implementation/Diagnostics/AbstractAggregatedDiagnosticsTagSource.cs
...ion/Diagnostics/AbstractAggregatedDiagnosticsTagSource.cs
+1
-1
src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlighterViewTaggerProvider.cs
...tion/KeywordHighlighting/HighlighterViewTaggerProvider.cs
+0
-1
src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingTagSource.cs
...n/ReferenceHighlighting/ReferenceHighlightingTagSource.cs
+0
-175
src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs
...ceHighlighting/ReferenceHighlightingViewTaggerProvider.cs
+30
-42
src/EditorFeatures/Core/Shared/Tagging/TagSources/ProducerPopulatedTagSource.cs
...e/Shared/Tagging/TagSources/ProducerPopulatedTagSource.cs
+102
-36
src/EditorFeatures/Core/Shared/Tagging/TagSources/TagSource.cs
...ditorFeatures/Core/Shared/Tagging/TagSources/TagSource.cs
+0
-36
src/EditorFeatures/Core/Tagging/AsynchronousTaggerContext.cs
src/EditorFeatures/Core/Tagging/AsynchronousTaggerContext.cs
+29
-4
src/EditorFeatures/Core/Tagging/AsynchronousTaggerDataSource.cs
...itorFeatures/Core/Tagging/AsynchronousTaggerDataSource.cs
+7
-1
src/EditorFeatures/Core/Tagging/IAsynchronousTaggerDataSource.cs
...torFeatures/Core/Tagging/IAsynchronousTaggerDataSource.cs
+33
-7
src/EditorFeatures/Core/Tagging/TaggerTextChangeBehavior.cs
src/EditorFeatures/Core/Tagging/TaggerTextChangeBehavior.cs
+12
-4
未找到文件。
src/EditorFeatures/Core/EditorFeatures.csproj
浏览文件 @
c5914db4
...
...
@@ -762,7 +762,6 @@
<Compile
Include=
"Shared\Tagging\Tags\ConflictTagDefinition.cs"
/>
<Compile
Include=
"Shared\Tagging\Tags\PreviewWarningTag.cs"
/>
<Compile
Include=
"Shared\Tagging\Tags\PreviewWarningTagDefinition.cs"
/>
<Compile
Include=
"Implementation\ReferenceHighlighting\ReferenceHighlightingTagSource.cs"
/>
<Compile
Include=
"Shared\Tagging\TagSources\ProducerPopulatedTagSource.cs"
/>
<Compile
Include=
"Shared\Tagging\TagSources\TagSource_ReferenceCounting.cs"
/>
<Compile
Include=
"Shared\Tagging\Utilities\BatchChangeNotifier.cs"
/>
...
...
src/EditorFeatures/Core/Implementation/Diagnostics/AbstractAggregatedDiagnosticsTagSource.cs
浏览文件 @
c5914db4
...
...
@@ -22,7 +22,7 @@ internal abstract partial class AbstractAggregatedDiagnosticsTagSource<TTag> : T
IForegroundNotificationService
notificationService
,
DiagnosticService
service
,
IAsynchronousOperationListener
asyncListener
)
:
base
(
textViewOpt
:
null
,
subjectBuffer
:
subjectBuffer
,
ignoreCaretMovementToExistingTag
:
false
,
notificationService
:
notificationService
,
asyncListener
:
asyncListener
)
:
base
(
subjectBuffer
,
notificationService
,
asyncListener
)
{
_service
=
service
;
_mode
=
GetMode
(
subjectBuffer
);
...
...
src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlighterViewTaggerProvider.cs
浏览文件 @
c5914db4
...
...
@@ -35,7 +35,6 @@ internal class HighlighterViewTaggerProvider : AsynchronousViewTaggerProvider<Hi
// Whenever any text change happens, we want to immediately remove any highlights that
// touch the edit.
public
override
TaggerTextChangeBehavior
TextChangeBehavior
=>
TaggerTextChangeBehavior
.
RemoveTagsThatIntersectEdits
;
public
override
bool
IgnoreCaretMovementToExistingTag
=>
true
;
public
override
IEnumerable
<
Option
<
bool
>>
Options
=>
SpecializedCollections
.
SingletonEnumerable
(
InternalFeatureOnOffOptions
.
KeywordHighlight
);
[
ImportingConstructor
]
...
...
src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingTagSource.cs
已删除
100644 → 0
浏览文件 @
b519d004
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Editor.Shared.Tagging
;
using
Microsoft.CodeAnalysis.Editor.Tagging
;
using
Microsoft.CodeAnalysis.Shared.TestHooks
;
using
Microsoft.CodeAnalysis.Text
;
using
Microsoft.CodeAnalysis.Text.Shared.Extensions
;
using
Microsoft.VisualStudio.Text
;
using
Microsoft.VisualStudio.Text.Editor
;
using
Microsoft.VisualStudio.Text.Tagging
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Editor.Implementation.ReferenceHighlighting
{
using
Context
=
AsynchronousTaggerContext
<
AbstractNavigatableReferenceHighlightingTag
,
object
>;
internal
partial
class
ReferenceHighlightingTagSource
:
ProducerPopulatedTagSource
<
AbstractNavigatableReferenceHighlightingTag
,
object
>
{
private
const
int
VoidVersion
=
-
1
;
// last solution version we used to update tags
// * NOTE * here unfortunately, we only hold onto version without caret position since
// it is not easy to pass through it. for now, we will void the last version whenever
// we see caret changes.
private
int
_lastUpdateTagsSolutionVersion
=
VoidVersion
;
public
ReferenceHighlightingTagSource
(
ITextView
textView
,
ITextBuffer
subjectBuffer
,
ReferenceHighlightingViewTaggerProvider
taggerProvider
,
IAsynchronousOperationListener
asyncListener
,
IForegroundNotificationService
notificationService
)
:
base
(
textView
,
subjectBuffer
,
taggerProvider
,
asyncListener
,
notificationService
)
{
}
protected
override
SnapshotPoint
?
GetCaretPoint
()
{
return
this
.
TextViewOpt
.
Caret
.
Position
.
Point
.
GetPoint
(
b
=>
b
.
ContentType
.
IsOfType
(
ContentTypeNames
.
RoslynContentType
),
PositionAffinity
.
Successor
);
}
protected
override
void
RecalculateTagsOnChangedCore
(
TaggerEventArgs
e
)
{
var
cancellationToken
=
this
.
WorkQueue
.
CancellationToken
;
VoidLastSolutionVersionIfCaretChanged
(
e
);
RegisterNotification
(()
=>
{
this
.
WorkQueue
.
AssertIsForeground
();
var
caret
=
GetCaretPoint
();
if
(!
caret
.
HasValue
)
{
ClearTags
(
cancellationToken
);
return
;
}
var
spansToTag
=
TryGetSpansAndDocumentsToTag
(
e
.
Kind
);
if
(
spansToTag
!=
null
)
{
// we will eagerly remove tags except for semantic change case.
// in semantic change case, we don't actually know whether it will affect highlight we currently
// have, so we will wait until we get new tags before removing them.
if
(
e
.
Kind
!=
PredefinedChangedEventKinds
.
SemanticsChanged
)
{
ClearTags
(
spansToTag
,
cancellationToken
);
}
base
.
RecalculateTagsOnChangedCore
(
e
);
}
},
delay
:
TaggerConstants
.
NearImmediateDelay
,
cancellationToken
:
cancellationToken
);
}
private
void
VoidLastSolutionVersionIfCaretChanged
(
TaggerEventArgs
e
)
{
if
(
e
.
Kind
==
PredefinedChangedEventKinds
.
CaretPositionChanged
)
{
_lastUpdateTagsSolutionVersion
=
VoidVersion
;
}
}
private
void
ClearTags
(
CancellationToken
cancellationToken
)
{
this
.
WorkQueue
.
AssertIsForeground
();
ClearTags
(
spansToTag
:
null
,
cancellationToken
:
cancellationToken
);
}
private
void
ClearTags
(
List
<
DocumentSnapshotSpan
>
spansToTag
,
CancellationToken
cancellationToken
)
{
this
.
WorkQueue
.
AssertIsForeground
();
spansToTag
=
spansToTag
??
GetSpansAndDocumentsToTag
();
// Save to access CachedTagTrees here because we're on the foreground thread.
var
oldTagsTrees
=
this
.
CachedTagTrees
;
this
.
WorkQueue
.
EnqueueBackgroundTask
(
c
=>
this
.
ClearTagsAsync
(
spansToTag
,
oldTagsTrees
,
c
),
"ClearTags"
,
cancellationToken
);
}
private
List
<
DocumentSnapshotSpan
>
TryGetSpansAndDocumentsToTag
(
string
kind
)
{
this
.
WorkQueue
.
AssertIsForeground
();
// TODO: tagger creates so much temporary objects. GetSpansAndDocumentsToTags creates handful of objects per events
// (in this case, on every caret move or text change). at some point of time, we should either re-write tagger framework
// or do some audit to reduce memory allocations.
var
spansToTag
=
GetSpansAndDocumentsToTag
();
if
(
kind
==
PredefinedChangedEventKinds
.
SemanticsChanged
||
kind
==
PredefinedChangedEventKinds
.
TextChanged
)
{
// check whether we already processed highlight for this document
// * this can happen if we are called twice for same document due to two different change events caused by
// same root change (text edit)
var
spanAndTag
=
spansToTag
.
First
(
s
=>
s
.
SnapshotSpan
.
Snapshot
.
TextBuffer
==
this
.
SubjectBuffer
);
var
version
=
spanAndTag
.
SnapshotSpan
.
Snapshot
.
Version
.
ReiteratedVersionNumber
;
var
document
=
spanAndTag
.
Document
;
if
(
version
==
this
.
SubjectBuffer
.
CurrentSnapshot
.
Version
.
ReiteratedVersionNumber
&&
document
!=
null
&&
document
.
Project
.
Solution
.
WorkspaceVersion
==
_lastUpdateTagsSolutionVersion
)
{
return
null
;
}
}
// we are going to update tags, clear last update tags solution version
_lastUpdateTagsSolutionVersion
=
VoidVersion
;
return
spansToTag
;
}
private
Task
ClearTagsAsync
(
List
<
DocumentSnapshotSpan
>
spansToTag
,
ImmutableDictionary
<
ITextBuffer
,
TagSpanIntervalTree
<
AbstractNavigatableReferenceHighlightingTag
>>
oldTagTrees
,
CancellationToken
cancellationToken
)
{
this
.
WorkQueue
.
AssertIsBackground
();
cancellationToken
.
ThrowIfCancellationRequested
();
var
tagSpans
=
SpecializedCollections
.
EmptyEnumerable
<
ITagSpan
<
AbstractNavigatableReferenceHighlightingTag
>>();
var
newTagTrees
=
ConvertToTagTrees
(
oldTagTrees
,
tagSpans
,
spansToTag
);
// here we call base.ProcessNewTags so that we can clear tags without setting last solution version
// clear tags is a special update mechanism where it represents clearing tags not updating tags.
// we don't care about accumulated text change, so give it null
base
.
ProcessNewTagTrees
(
spansToTag
,
oldTagTrees
:
oldTagTrees
,
newTagTrees
:
newTagTrees
,
newState
:
null
,
cancellationToken
:
cancellationToken
);
return
SpecializedTasks
.
EmptyTask
;
}
protected
override
void
ProcessNewTagTrees
(
IEnumerable
<
DocumentSnapshotSpan
>
spansToCompute
,
ImmutableDictionary
<
ITextBuffer
,
TagSpanIntervalTree
<
AbstractNavigatableReferenceHighlightingTag
>>
oldTagTrees
,
ImmutableDictionary
<
ITextBuffer
,
TagSpanIntervalTree
<
AbstractNavigatableReferenceHighlightingTag
>>
newTags
,
object
newState
,
CancellationToken
cancellationToken
)
{
base
.
ProcessNewTagTrees
(
spansToCompute
,
oldTagTrees
,
newTags
,
newState
,
cancellationToken
);
// remember last solution version we updated the tags
var
document
=
spansToCompute
.
First
().
Document
;
if
(
document
!=
null
)
{
_lastUpdateTagsSolutionVersion
=
document
.
Project
.
Solution
.
WorkspaceVersion
;
}
}
}
}
src/EditorFeatures/Core/Implementation/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs
浏览文件 @
c5914db4
...
...
@@ -5,11 +5,9 @@
using
System.Collections.Immutable
;
using
System.ComponentModel.Composition
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Editor.Shared.Options
;
using
Microsoft.CodeAnalysis.Editor.Shared.Tagging
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.Editor.Tagging
;
using
Microsoft.CodeAnalysis.Internal.Log
;
using
Microsoft.CodeAnalysis.Notification
;
...
...
@@ -31,43 +29,24 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.ReferenceHighlighting
[
ContentType
(
ContentTypeNames
.
RoslynContentType
)]
[
TagType
(
typeof
(
AbstractNavigatableReferenceHighlightingTag
))]
[
TextViewRole
(
PredefinedTextViewRoles
.
Interactive
)]
internal
partial
class
ReferenceHighlightingViewTaggerProvider
:
ForegroundThreadAffinitizedObject
,
IViewTaggerProvider
,
IAsynchronousTaggerDataSource
<
AbstractNavigatableReferenceHighlightingTag
,
object
>
internal
partial
class
ReferenceHighlightingViewTaggerProvider
:
AsynchronousViewTaggerProvider
<
AbstractNavigatableReferenceHighlightingTag
,
object
>
{
private
readonly
ISemanticChangeNotificationService
_semanticChangeNotificationService
;
private
readonly
Lazy
<
IViewTaggerProvider
>
_asynchronousTaggerProvider
;
public
TaggerTextChangeBehavior
TextChangeBehavior
=>
TaggerTextChangeBehavior
.
None
;
public
SpanTrackingMode
SpanTrackingMode
=>
SpanTrackingMode
.
EdgeExclusive
;
public
bool
IgnoreCaretMovementToExistingTag
=>
true
;
public
bool
ComputeTagsSynchronouslyIfNoAsynchronousComputationHasCompleted
=>
false
;
public
IEqualityComparer
<
AbstractNavigatableReferenceHighlightingTag
>
TagComparer
=>
null
;
public
IEnumerable
<
Option
<
bool
>>
Options
=>
null
;
public
IEnumerable
<
PerLanguageOption
<
bool
>>
PerLanguageOptions
=>
SpecializedCollections
.
SingletonEnumerable
(
FeatureOnOffOptions
.
ReferenceHighlighting
);
public
override
TaggerCaretChangeBehavior
CaretChangeBehavior
=>
TaggerCaretChangeBehavior
.
RemoveAllTagsOnCaretMoveOutsideOfTag
;
public
override
IEnumerable
<
PerLanguageOption
<
bool
>>
PerLanguageOptions
=>
SpecializedCollections
.
SingletonEnumerable
(
FeatureOnOffOptions
.
ReferenceHighlighting
);
[
ImportingConstructor
]
public
ReferenceHighlightingViewTaggerProvider
(
IForegroundNotificationService
notificationService
,
ISemanticChangeNotificationService
semanticChangeNotificationService
,
[
ImportMany
]
IEnumerable
<
Lazy
<
IAsynchronousOperationListener
,
FeatureMetadata
>>
asyncListeners
)
:
base
(
new
AggregateAsynchronousOperationListener
(
asyncListeners
,
FeatureAttribute
.
ReferenceHighlighting
),
notificationService
)
{
_semanticChangeNotificationService
=
semanticChangeNotificationService
;
_asynchronousTaggerProvider
=
new
Lazy
<
IViewTaggerProvider
>(()
=>
new
AsynchronousViewTaggerProviderWithTagSource
<
AbstractNavigatableReferenceHighlightingTag
,
object
>(
this
,
new
AggregateAsynchronousOperationListener
(
asyncListeners
,
FeatureAttribute
.
ReferenceHighlighting
),
notificationService
,
this
.
CreateTagSource
));
}
public
ITagger
<
T
>
CreateTagger
<
T
>(
ITextView
textView
,
ITextBuffer
buffer
)
where
T
:
ITag
{
return
_asynchronousTaggerProvider
.
Value
.
CreateTagger
<
T
>(
textView
,
buffer
);
}
public
ITaggerEventSource
CreateEventSource
(
ITextView
textView
,
ITextBuffer
subjectBuffer
)
public
override
ITaggerEventSource
CreateEventSource
(
ITextView
textView
,
ITextBuffer
subjectBuffer
)
{
// Note: we don't listen for OnTextChanged. Text changes to this this buffer will get
// reported by OnSemanticChanged.
...
...
@@ -78,22 +57,19 @@ public ITaggerEventSource CreateEventSource(ITextView textView, ITextBuffer subj
TaggerEventSources
.
OnOptionChanged
(
subjectBuffer
,
FeatureOnOffOptions
.
ReferenceHighlighting
,
TaggerDelay
.
NearImmediate
));
}
private
ProducerPopulatedTagSource
<
AbstractNavigatableReferenceHighlightingTag
,
object
>
CreateTagSource
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
,
IAsynchronousOperationListener
asyncListener
,
IForegroundNotificationService
notificationService
)
public
override
SnapshotPoint
?
GetCaretPoint
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
)
{
return
new
ReferenceHighlightingTagSource
(
textViewOpt
,
subjectBuffer
,
this
,
asyncListener
,
notificationService
);
return
textViewOpt
.
Caret
.
Position
.
Point
.
GetPoint
(
b
=>
b
.
ContentType
.
IsOfType
(
ContentTypeNames
.
RoslynContentType
),
PositionAffinity
.
Successor
);
}
public
IEnumerable
<
SnapshotSpan
>
GetSpansToTag
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
)
public
override
IEnumerable
<
SnapshotSpan
>
GetSpansToTag
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
)
{
return
textViewOpt
.
BufferGraph
.
GetTextBuffers
(
b
=>
b
.
ContentType
.
IsOfType
(
ContentTypeNames
.
RoslynContentType
))
.
Select
(
b
=>
b
.
CurrentSnapshot
.
GetFullSpan
())
.
ToList
();
}
public
Task
ProduceTagsAsync
(
Context
context
)
public
override
Task
ProduceTagsAsync
(
Context
context
)
{
// NOTE(cyrusn): Normally we'd limit ourselves to producing tags in the span we were
// asked about. However, we want to produce all tags here so that the user can actually
...
...
@@ -104,21 +80,38 @@ public Task ProduceTagsAsync(Context context)
return
SpecializedTasks
.
EmptyTask
;
}
var
p
osition
=
context
.
CaretPosition
.
Value
;
var
caretP
osition
=
context
.
CaretPosition
.
Value
;
Workspace
workspace
;
if
(!
Workspace
.
TryGetWorkspace
(
p
osition
.
Snapshot
.
AsText
().
Container
,
out
workspace
))
if
(!
Workspace
.
TryGetWorkspace
(
caretP
osition
.
Snapshot
.
AsText
().
Container
,
out
workspace
))
{
return
SpecializedTasks
.
EmptyTask
;
}
var
document
=
context
.
SpansToTag
.
First
(
vt
=>
vt
.
SnapshotSpan
.
Snapshot
==
p
osition
.
Snapshot
).
Document
;
var
document
=
context
.
SpansToTag
.
First
(
vt
=>
vt
.
SnapshotSpan
.
Snapshot
==
caretP
osition
.
Snapshot
).
Document
;
if
(
document
==
null
)
{
return
SpecializedTasks
.
EmptyTask
;
}
return
ProduceTagsAsync
(
context
,
position
,
workspace
,
document
);
// Don't produce tags if the feature is not enabled.
if
(!
workspace
.
Options
.
GetOption
(
FeatureOnOffOptions
.
ReferenceHighlighting
,
document
.
Project
.
Language
))
{
return
SpecializedTasks
.
EmptyTask
;
}
var
existingTags
=
context
.
GetExistingTags
(
new
SnapshotSpan
(
caretPosition
,
0
));
if
(!
existingTags
.
IsEmpty
())
{
// We already have a tag at this position. So the user is moving from one highlight
// tag to another. In this case we don't want to recompute anything. Let our caller
// know that we should preserve all tags.
context
.
SetSpansTagged
(
SpecializedCollections
.
EmptyEnumerable
<
DocumentSnapshotSpan
>());
return
SpecializedTasks
.
EmptyTask
;
}
// Otherwise, we need to go produce all tags.
return
ProduceTagsAsync
(
context
,
caretPosition
,
workspace
,
document
);
}
internal
async
Task
ProduceTagsAsync
(
...
...
@@ -128,11 +121,6 @@ public Task ProduceTagsAsync(Context context)
Document
document
)
{
var
cancellationToken
=
context
.
CancellationToken
;
// Don't produce tags if the feature is not enabled.
if
(!
workspace
.
Options
.
GetOption
(
FeatureOnOffOptions
.
ReferenceHighlighting
,
document
.
Project
.
Language
))
{
return
;
}
var
solution
=
document
.
Project
.
Solution
;
...
...
src/EditorFeatures/Core/Shared/Tagging/TagSources/ProducerPopulatedTagSource.cs
浏览文件 @
c5914db4
...
...
@@ -49,6 +49,8 @@ internal partial class ProducerPopulatedTagSource<TTag, TState> : TagSource<TTag
#
region
Fields
that
can
only
be
accessed
from
the
foreground
thread
private
readonly
ITextView
_textViewOpt
;
/// <summary>
/// Our tagger event source that lets us know when we should call into the tag producer for
/// new tags.
...
...
@@ -74,26 +76,26 @@ internal partial class ProducerPopulatedTagSource<TTag, TState> : TagSource<TTag
IAsynchronousTaggerDataSource
<
TTag
,
TState
>
dataSource
,
IAsynchronousOperationListener
asyncListener
,
IForegroundNotificationService
notificationService
)
:
base
(
textViewOpt
,
subjectBuffer
,
dataSource
.
IgnoreCaretMovementToExistingTag
,
notificationService
,
asyncListener
)
:
base
(
subjectBuffer
,
notificationService
,
asyncListener
)
{
if
(
dataSource
.
SpanTrackingMode
==
SpanTrackingMode
.
Custom
)
{
throw
new
ArgumentException
(
"SpanTrackingMode.Custom not allowed."
,
"spanTrackingMode"
);
}
_textViewOpt
=
textViewOpt
;
_dataSource
=
dataSource
;
_tagSpanComparer
=
new
TagSpanComparer
<
TTag
>(
this
.
TagComparer
);
this
.
CachedTagTrees
=
ImmutableDictionary
.
Create
<
ITextBuffer
,
TagSpanIntervalTree
<
TTag
>>();
this
.
AccumulatedTextChanges
=
null
;
_eventSource
=
dataSource
.
CreateEventSource
(
textViewOpt
,
subjectBuffer
);
AttachEventHandlersAndStart
();
}
private
IEqualityComparer
<
TTag
>
TagComparer
=>
private
IEqualityComparer
<
TTag
>
TagComparer
=>
_dataSource
.
TagComparer
??
EqualityComparer
<
TTag
>.
Default
;
protected
TextChangeRange
?
AccumulatedTextChanges
...
...
@@ -154,6 +156,17 @@ private void AttachEventHandlersAndStart()
this
.
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
();
}
...
...
@@ -167,6 +180,11 @@ protected override void Disconnect()
// Tell the interaction object to stop issuing events.
_eventSource
.
Disconnect
();
if
(
_dataSource
.
CaretChangeBehavior
.
HasFlag
(
TaggerCaretChangeBehavior
.
RemoveAllTagsOnCaretMoveOutsideOfTag
))
{
this
.
_textViewOpt
.
Caret
.
PositionChanged
-=
OnCaretPositionChanged
;
}
if
(
_dataSource
.
TextChangeBehavior
.
HasFlag
(
TaggerTextChangeBehavior
.
TrackTextChanges
))
{
this
.
SubjectBuffer
.
Changed
-=
OnSubjectBufferChanged
;
...
...
@@ -193,13 +211,6 @@ private void OnUIUpdatesResumed(object sender, EventArgs e)
RaiseResumed
();
}
private
void
OnSubjectBufferChanged
(
object
sender
,
TextContentChangedEventArgs
e
)
{
this
.
WorkQueue
.
AssertIsForeground
();
UpdateTagsForTextChange
(
e
);
AccumulateTextChanges
(
e
);
}
private
void
OnChanged
(
object
sender
,
TaggerEventArgs
e
)
{
using
(
var
token
=
this
.
Listener
.
BeginAsyncOperation
(
"OnChanged"
))
...
...
@@ -209,12 +220,60 @@ private void OnChanged(object sender, TaggerEventArgs e)
this
.
WorkQueue
.
CancelCurrentWork
();
// We don't currently have a request issued to re-compute our tags. Issue it for some
// time in the future
// time in the future.
RecalculateTagsOnChanged
(
e
);
}
}
private
void
OnCaretPositionChanged
(
object
sender
,
CaretPositionChangedEventArgs
e
)
{
this
.
AssertIsForeground
();
Debug
.
Assert
(
_dataSource
.
CaretChangeBehavior
.
HasFlag
(
TaggerCaretChangeBehavior
.
RemoveAllTagsOnCaretMoveOutsideOfTag
));
var
caret
=
GetCaretPoint
();
if
(
caret
.
HasValue
)
{
// If it changed position and we're still in a tag, there's nothing more to do
var
currentTags
=
GetTagIntervalTreeForBuffer
(
caret
.
Value
.
Snapshot
.
TextBuffer
);
if
(
currentTags
!=
null
&&
currentTags
.
GetIntersectingSpans
(
new
SnapshotSpan
(
caret
.
Value
,
0
)).
Count
>
0
)
{
// Caret is inside a tag. No need to do anything.
return
;
}
}
RemoveAllTags
();
}
private
void
RemoveAllTags
()
{
this
.
AssertIsForeground
();
var
oldTagTrees
=
this
.
CachedTagTrees
;
this
.
CachedTagTrees
=
ImmutableDictionary
<
ITextBuffer
,
TagSpanIntervalTree
<
TTag
>>.
Empty
;
var
snapshot
=
this
.
SubjectBuffer
.
CurrentSnapshot
;
var
oldTagTree
=
GetTagTree
(
snapshot
,
oldTagTrees
);
var
newTagTree
=
GetTagTree
(
snapshot
,
this
.
CachedTagTrees
);
var
difference
=
ComputeDifference
(
snapshot
,
newTagTree
,
oldTagTree
);
RaiseTagsChanged
(
snapshot
.
TextBuffer
,
difference
);
}
protected
SnapshotPoint
?
GetCaretPoint
()
{
this
.
AssertIsForeground
();
return
_dataSource
.
GetCaretPoint
(
_textViewOpt
,
SubjectBuffer
)
??
_textViewOpt
?.
GetCaretPoint
(
SubjectBuffer
);
}
private
void
OnSubjectBufferChanged
(
object
sender
,
TextContentChangedEventArgs
e
)
{
this
.
WorkQueue
.
AssertIsForeground
();
UpdateTagsForTextChange
(
e
);
AccumulateTextChanges
(
e
);
}
private
void
AccumulateTextChanges
(
TextContentChangedEventArgs
contentChanged
)
{
this
.
WorkQueue
.
AssertIsForeground
();
...
...
@@ -254,12 +313,22 @@ private void UpdateTagsForTextChange(TextContentChangedEventArgs e)
{
this
.
WorkQueue
.
AssertIsForeground
();
if
(
_dataSource
.
TextChangeBehavior
.
HasFlag
(
TaggerTextChangeBehavior
.
RemoveAllTags
))
{
this
.
RemoveAllTags
();
return
;
}
// Don't bother going forward if we're not going adjust any tags based on edits.
if
(
!
_dataSource
.
TextChangeBehavior
.
HasFlag
(
TaggerTextChangeBehavior
.
RemoveTagsThatIntersectEdits
))
if
(
_dataSource
.
TextChangeBehavior
.
HasFlag
(
TaggerTextChangeBehavior
.
RemoveTagsThatIntersectEdits
))
{
RemoveTagsThatIntersectEdit
(
e
);
return
;
}
}
private
void
RemoveTagsThatIntersectEdit
(
TextContentChangedEventArgs
e
)
{
if
(!
e
.
Changes
.
Any
())
{
return
;
...
...
@@ -285,34 +354,30 @@ private void UpdateTagsForTextChange(TextContentChangedEventArgs e)
}
var
allTags
=
treeForBuffer
.
GetSpans
(
e
.
After
).
ToList
();
var
newT
reeForBuffer
=
new
TagSpanIntervalTree
<
TTag
>(
var
newT
agTree
=
new
TagSpanIntervalTree
<
TTag
>(
buffer
,
treeForBuffer
.
SpanTrackingMode
,
allTags
.
Except
(
tagsToRemove
,
_tagSpanComparer
));
UpdateCachedTagsForBuffer
(
e
.
After
,
newTreeForBuffer
);
}
private
void
UpdateCachedTagsForBuffer
(
ITextSnapshot
snapshot
,
TagSpanIntervalTree
<
TTag
>
newTagsForBuffer
)
{
this
.
WorkQueue
.
AssertIsForeground
();
var
oldCachedTagTrees
=
this
.
CachedTagTrees
;
var
snapshot
=
e
.
After
;
this
.
CachedTagTrees
=
oldCachedTagTrees
.
SetItem
(
snapshot
.
TextBuffer
,
newTagsForBuffer
);
var
oldTagTrees
=
this
.
CachedTagTrees
;
this
.
CachedTagTrees
=
oldTagTrees
.
SetItem
(
snapshot
.
TextBuffer
,
newTagTree
);
// Grab our old tags. We might not have any, so in this case we'll just pretend it's
// empty
TagSpanIntervalTree
<
TTag
>
oldCachedTagsForBuffer
=
null
;
if
(!
oldCachedTagTrees
.
TryGetValue
(
snapshot
.
TextBuffer
,
out
oldCachedTagsForBuffer
))
{
oldCachedTagsForBuffer
=
new
TagSpanIntervalTree
<
TTag
>(
snapshot
.
TextBuffer
,
_dataSource
.
SpanTrackingMode
);
}
var
oldTagTree
=
GetTagTree
(
snapshot
,
oldTagTrees
);
var
difference
=
ComputeDifference
(
snapshot
,
oldCachedTagsForBuffer
,
newTagsForBuffer
);
if
(
difference
.
Count
>
0
)
{
RaiseTagsChanged
(
snapshot
.
TextBuffer
,
difference
);
}
var
difference
=
ComputeDifference
(
snapshot
,
newTagTree
,
oldTagTree
);
RaiseTagsChanged
(
snapshot
.
TextBuffer
,
difference
);
}
private
TagSpanIntervalTree
<
TTag
>
GetTagTree
(
ITextSnapshot
snapshot
,
ImmutableDictionary
<
ITextBuffer
,
TagSpanIntervalTree
<
TTag
>>
tagTrees
)
{
TagSpanIntervalTree
<
TTag
>
tagTree
=
null
;
return
tagTrees
.
TryGetValue
(
snapshot
.
TextBuffer
,
out
tagTree
)
?
tagTree
:
new
TagSpanIntervalTree
<
TTag
>(
snapshot
.
TextBuffer
,
_dataSource
.
SpanTrackingMode
);
}
private
bool
TryStealTagsFromRelatedTagSource
(
TextContentChangedEventArgs
e
)
...
...
@@ -406,7 +471,7 @@ protected List<DocumentSnapshotSpan> GetSpansAndDocumentsToTag()
// TODO: Update to tag spans from all related documents.
var
snapshotToDocumentMap
=
new
Dictionary
<
ITextSnapshot
,
Document
>();
var
spansToTag
=
_dataSource
.
GetSpansToTag
(
T
extViewOpt
,
SubjectBuffer
)
??
this
.
GetFullBufferSpan
();
var
spansToTag
=
_dataSource
.
GetSpansToTag
(
_t
extViewOpt
,
SubjectBuffer
)
??
this
.
GetFullBufferSpan
();
var
spansAndDocumentsToTag
=
spansToTag
.
Select
(
span
=>
{
Document
document
=
null
;
...
...
@@ -659,7 +724,8 @@ private IEnumerable<ITagSpan<TTag>> GetNonIntersectingTagSpans(IEnumerable<Snaps
var
newTagSpans
=
SpecializedCollections
.
EmptyEnumerable
<
ITagSpan
<
TTag
>>();
var
context
=
new
AsynchronousTaggerContext
<
TTag
,
TState
>(
oldState
,
spansToTag
,
caretPosition
,
textChangeRange
,
cancellationToken
);
var
context
=
new
AsynchronousTaggerContext
<
TTag
,
TState
>(
oldState
,
spansToTag
,
caretPosition
,
textChangeRange
,
oldTagTrees
,
cancellationToken
);
await
_dataSource
.
ProduceTagsAsync
(
context
).
ConfigureAwait
(
false
);
ProcessContext
(
oldTagTrees
,
context
);
...
...
@@ -669,7 +735,7 @@ private IEnumerable<ITagSpan<TTag>> GetNonIntersectingTagSpans(IEnumerable<Snaps
ImmutableDictionary
<
ITextBuffer
,
TagSpanIntervalTree
<
TTag
>>
oldTagTrees
,
AsynchronousTaggerContext
<
TTag
,
TState
>
context
)
{
var
spansTagged
=
context
.
spansTagged
;
var
spansTagged
=
context
.
_
spansTagged
;
var
newTagTrees
=
ConvertToTagTrees
(
oldTagTrees
,
context
.
tagSpans
,
spansTagged
);
ProcessNewTagTrees
(
spansTagged
,
oldTagTrees
,
newTagTrees
,
context
.
State
,
context
.
CancellationToken
);
...
...
@@ -790,7 +856,7 @@ public override ITagSpanIntervalTree<TTag> GetTagIntervalTreeForBuffer(ITextBuff
// use can cancel out if this takes a long time.
var
context
=
new
AsynchronousTaggerContext
<
TTag
,
TState
>(
this
.
State
,
spansToTag
,
GetCaretPoint
(),
this
.
AccumulatedTextChanges
,
CancellationToken
.
None
);
this
.
State
,
spansToTag
,
GetCaretPoint
(),
this
.
AccumulatedTextChanges
,
oldTagTrees
,
CancellationToken
.
None
);
_dataSource
.
ProduceTagsAsync
(
context
).
Wait
();
var
newTagTrees
=
ProcessContext
(
oldTagTrees
,
context
);
...
...
src/EditorFeatures/Core/Shared/Tagging/TagSources/TagSource.cs
浏览文件 @
c5914db4
...
...
@@ -36,7 +36,6 @@ internal abstract partial class TagSource<TTag> :
/// </summary>
internal
readonly
AsynchronousSerialWorkQueue
WorkQueue
;
protected
readonly
ITextView
TextViewOpt
;
protected
readonly
ITextBuffer
SubjectBuffer
;
/// <summary>
...
...
@@ -48,20 +47,15 @@ internal abstract partial class TagSource<TTag> :
/// foreground notification service
/// </summary>
private
readonly
IForegroundNotificationService
_notificationService
;
private
readonly
bool
_ignoreCaretMovementToExistingTag
;
#
endregion
protected
TagSource
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
,
bool
ignoreCaretMovementToExistingTag
,
IForegroundNotificationService
notificationService
,
IAsynchronousOperationListener
asyncListener
)
{
TextViewOpt
=
textViewOpt
;
this
.
SubjectBuffer
=
subjectBuffer
;
_ignoreCaretMovementToExistingTag
=
ignoreCaretMovementToExistingTag
;
_notificationService
=
notificationService
;
this
.
Listener
=
asyncListener
;
...
...
@@ -94,40 +88,10 @@ public void RegisterNotification(Action action, int delay, CancellationToken can
/// Called by derived types to enqueue tags re-calculation request
/// </summary>
protected
void
RecalculateTagsOnChanged
(
TaggerEventArgs
e
)
{
if
(
_ignoreCaretMovementToExistingTag
&&
e
.
Kind
==
PredefinedChangedEventKinds
.
CaretPositionChanged
)
{
this
.
AssertIsForeground
();
var
caret
=
GetCaretPoint
();
if
(
caret
.
HasValue
)
{
// If it changed position and we're still in a tag, there's nothing more to do
var
currentTags
=
GetTagIntervalTreeForBuffer
(
caret
.
Value
.
Snapshot
.
TextBuffer
);
if
(
currentTags
!=
null
&&
currentTags
.
GetIntersectingSpans
(
new
SnapshotSpan
(
caret
.
Value
,
0
)).
Count
>
0
)
{
return
;
}
}
}
RecalculateTagsOnChangedCore
(
e
);
}
protected
virtual
void
RecalculateTagsOnChangedCore
(
TaggerEventArgs
e
)
{
RegisterNotification
(
RecomputeTagsForeground
,
e
.
Delay
.
ComputeTimeDelayMS
(
this
.
SubjectBuffer
),
this
.
WorkQueue
.
CancellationToken
);
}
/// <summary>
/// Implemented by derived types to return the caret position.
/// </summary>
/// <remarks>Called on the foreground thread.</remarks>
protected
virtual
SnapshotPoint
?
GetCaretPoint
()
{
return
TextViewOpt
?.
GetCaretPoint
(
SubjectBuffer
);
}
protected
virtual
void
Disconnect
()
{
this
.
WorkQueue
.
AssertIsForeground
();
...
...
src/EditorFeatures/Core/Tagging/AsynchronousTaggerContext.cs
浏览文件 @
c5914db4
...
...
@@ -5,14 +5,21 @@
using
System.Text
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Editor.Shared.Tagging
;
using
Microsoft.CodeAnalysis.Text
;
using
Microsoft.VisualStudio.Text
;
using
Microsoft.VisualStudio.Text.Tagging
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Editor.Tagging
{
internal
class
AsynchronousTaggerContext
<
TTag
,
TState
>
where
TTag
:
ITag
{
private
readonly
ImmutableDictionary
<
ITextBuffer
,
TagSpanIntervalTree
<
TTag
>>
_existingTags
;
internal
IEnumerable
<
DocumentSnapshotSpan
>
_spansTagged
;
internal
ImmutableArray
<
ITagSpan
<
TTag
>>.
Builder
tagSpans
=
ImmutableArray
.
CreateBuilder
<
ITagSpan
<
TTag
>>();
public
TState
State
{
get
;
set
;
}
public
IEnumerable
<
DocumentSnapshotSpan
>
SpansToTag
{
get
;
}
public
SnapshotPoint
?
CaretPosition
{
get
;
}
...
...
@@ -25,14 +32,23 @@ internal class AsynchronousTaggerContext<TTag, TState> where TTag : ITag
public
TextChangeRange
?
TextChangeRange
{
get
;
}
public
CancellationToken
CancellationToken
{
get
;
}
internal
IEnumerable
<
DocumentSnapshotSpan
>
spansTagged
;
internal
ImmutableArray
<
ITagSpan
<
TTag
>>.
Builder
tagSpans
=
ImmutableArray
.
CreateBuilder
<
ITagSpan
<
TTag
>>();
// For testing only.
internal
AsynchronousTaggerContext
(
TState
state
,
IEnumerable
<
DocumentSnapshotSpan
>
spansToTag
,
SnapshotPoint
?
caretPosition
,
TextChangeRange
?
textChangeRange
,
CancellationToken
cancellationToken
)
:
this
(
state
,
spansToTag
,
caretPosition
,
textChangeRange
,
null
,
cancellationToken
)
{
}
internal
AsynchronousTaggerContext
(
TState
state
,
IEnumerable
<
DocumentSnapshotSpan
>
spansToTag
,
SnapshotPoint
?
caretPosition
,
TextChangeRange
?
textChangeRange
,
ImmutableDictionary
<
ITextBuffer
,
TagSpanIntervalTree
<
TTag
>>
existingTags
,
CancellationToken
cancellationToken
)
{
this
.
State
=
state
;
...
...
@@ -41,7 +57,8 @@ internal class AsynchronousTaggerContext<TTag, TState> where TTag : ITag
this
.
TextChangeRange
=
textChangeRange
;
this
.
CancellationToken
=
cancellationToken
;
this
.
spansTagged
=
spansToTag
;
_spansTagged
=
spansToTag
;
_existingTags
=
existingTags
;
}
public
void
AddTag
(
ITagSpan
<
TTag
>
tag
)
...
...
@@ -62,7 +79,15 @@ public void SetSpansTagged(IEnumerable<DocumentSnapshotSpan> spansTagged)
throw
new
ArgumentNullException
(
nameof
(
spansTagged
));
}
this
.
spansTagged
=
spansTagged
;
this
.
_spansTagged
=
spansTagged
;
}
public
IEnumerable
<
ITagSpan
<
TTag
>>
GetExistingTags
(
SnapshotSpan
span
)
{
TagSpanIntervalTree
<
TTag
>
tree
;
return
_existingTags
.
TryGetValue
(
span
.
Snapshot
.
TextBuffer
,
out
tree
)
?
tree
.
GetIntersectingSpans
(
span
)
:
SpecializedCollections
.
EmptyEnumerable
<
ITagSpan
<
TTag
>>();
}
}
}
src/EditorFeatures/Core/Tagging/AsynchronousTaggerDataSource.cs
浏览文件 @
c5914db4
...
...
@@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Editor.Tagging
internal
abstract
class
AsynchronousTaggerDataSource
<
TTag
,
TState
>
:
IAsynchronousTaggerDataSource
<
TTag
,
TState
>
where
TTag
:
ITag
{
public
virtual
TaggerTextChangeBehavior
TextChangeBehavior
=>
TaggerTextChangeBehavior
.
None
;
public
virtual
bool
IgnoreCaretMovementToExistingTag
=>
fals
e
;
public
virtual
TaggerCaretChangeBehavior
CaretChangeBehavior
=>
TaggerCaretChangeBehavior
.
Non
e
;
public
virtual
SpanTrackingMode
SpanTrackingMode
=>
SpanTrackingMode
.
EdgeExclusive
;
public
virtual
bool
ComputeTagsSynchronouslyIfNoAsynchronousComputationHasCompleted
=>
false
;
...
...
@@ -29,6 +29,12 @@ internal abstract class AsynchronousTaggerDataSource<TTag, TState> : IAsynchrono
protected
AsynchronousTaggerDataSource
()
{
}
public
virtual
SnapshotPoint
?
GetCaretPoint
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
)
{
// Use 'null' to indicate that the tagger should get the default caret position.
return
null
;
}
public
virtual
IEnumerable
<
SnapshotSpan
>
GetSpansToTag
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
)
{
// Use 'null' to indicate that the tagger should tag the default set of spans.
...
...
src/EditorFeatures/Core/Tagging/IAsynchronousTaggerDataSource.cs
浏览文件 @
c5914db4
...
...
@@ -12,6 +12,23 @@
namespace
Microsoft.CodeAnalysis.Editor.Tagging
{
/// <summary>
/// Flags that affect how the tagger infrastructure responds to caret changes.
/// </summary>
[
Flags
]
internal
enum
TaggerCaretChangeBehavior
{
/// <summary>
/// No special caret change behavior.
/// </summary>
None
=
0
,
/// <summary>
/// If the caret moves outside of a tag, immediately remove all existing tags.
/// </summary>
RemoveAllTagsOnCaretMoveOutsideOfTag
=
1
<<
0
,
}
/// <summary>
/// Data source for the <see cref="AsynchronousTaggerProvider{TTag, TState}"/>. This type tells the
/// <see cref="AsynchronousTaggerProvider{TTag, TState}"/> when tags need to be recomputed, as well
...
...
@@ -31,6 +48,11 @@ internal interface IAsynchronousTaggerDataSource<TTag, TState> where TTag : ITag
/// </summary>
TaggerTextChangeBehavior
TextChangeBehavior
{
get
;
}
/// <summary>
/// The bahavior the tagger will have when changes happen to the caret.
/// </summary>
TaggerCaretChangeBehavior
CaretChangeBehavior
{
get
;
}
/// <summary>
/// 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
...
...
@@ -43,13 +65,6 @@ internal interface IAsynchronousTaggerDataSource<TTag, TState> where TTag : ITag
/// </summary>
bool
ComputeTagsSynchronouslyIfNoAsynchronousComputationHasCompleted
{
get
;
}
/// <summary>
/// <code>true</code> if the tagger infrastructure can avoid recomputing tags when the
/// user's caret moves to an already existing tag. This is useful to avoid work for
/// features like Highlighting if the user is navigating between highlight tags.
/// </summary>
bool
IgnoreCaretMovementToExistingTag
{
get
;
}
/// <summary>
/// Options controlling this tagger. The tagger infrastructure will check this option
/// against the buffer it is associated with to see if it should tag or not.
...
...
@@ -77,6 +92,17 @@ internal interface IAsynchronousTaggerDataSource<TTag, TState> where TTag : ITag
/// </summary>
ITaggerEventSource
CreateEventSource
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
);
/// <summary>
/// Called by the <see cref="AsynchronousTaggerProvider{TTag, TState}"/> infrastructure to
/// determine the caret position. This value will be passed in as the value to
/// <see cref="AsynchronousTaggerContext{TTag, TState}.CaretPosition"/> in the call to
/// <see cref="ProduceTagsAsync"/>.
///
/// Return <code>null</code> to get the default tagger behavior. This will the caret
/// position in the subject buffer this tagger is attached to.
/// </summary>
SnapshotPoint
?
GetCaretPoint
(
ITextView
textViewOpt
,
ITextBuffer
subjectBuffer
);
/// <summary>
/// Called by the <see cref="AsynchronousTaggerProvider{TTag, TState}"/> infrastructure to determine
/// the set of spans that it should asynchronously tag. This will be called in response to
...
...
src/EditorFeatures/Core/Tagging/TaggerTextChangeBehavior.cs
浏览文件 @
c5914db4
...
...
@@ -3,7 +3,7 @@
namespace
Microsoft.CodeAnalysis.Editor.Tagging
{
/// <summary>
///
What the async tagger infrastructure should do in the presence of text edit
s.
///
Flags that affect how the tagger infrastructure responds to text change
s.
/// </summary>
[
Flags
]
internal
enum
TaggerTextChangeBehavior
...
...
@@ -22,12 +22,20 @@ internal enum TaggerTextChangeBehavior
TrackTextChanges
=
1
<<
0
,
/// <summary>
/// The async tagger infrastructure will
not
track text changes to the subject buffer it is
/// The async tagger infrastructure will track text changes to the subject buffer it is
/// attached to. The text changes will be provided to the <see cref="AsynchronousTaggerContext{TTag, TState}"/>
/// that is passed to <see cref="IAsynchronousTaggerDataSource{TTag, TState}.ProduceTagsAsync"/>.
///
/// Tags that intersect the text change range will immediately removed.
/// On any edit, tags that intersect the text change range will immediately removed.
/// </summary>
RemoveTagsThatIntersectEdits
=
TrackTextChanges
|
(
1
<<
1
),
/// <summary>
/// The async tagger infrastructure will track text changes to the subject buffer it is
/// attached to.
///
/// On any edit all tags will we be removed.
/// </summary>
Remove
TagsThatIntersectEdits
=
TrackTextChanges
|
(
1
<<
1
)
Remove
AllTags
=
TrackTextChanges
|
(
1
<<
2
),
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录