Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
96e66888
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,发现更多精彩内容 >>
提交
96e66888
编写于
9月 04, 2019
作者:
G
Gen Lu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Sort completion list by pattern matching results
上级
8cf35ae6
变更
8
显示空白变更内容
内联
并排
Showing
8 changed file
with
143 addition
and
70 deletion
+143
-70
src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterResult.cs
...plementation/IntelliSense/AsyncCompletion/FilterResult.cs
+4
-1
src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs
...mplementation/IntelliSense/AsyncCompletion/ItemManager.cs
+67
-45
src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs
...IntelliSense/Completion/Controller.Session_FilterModel.cs
+4
-5
src/EditorFeatures/Text/Shared/Extensions/TextSpanExtensions.cs
...itorFeatures/Text/Shared/Extensions/TextSpanExtensions.cs
+8
-1
src/Features/Core/Portable/Completion/CommonCompletionService.cs
...tures/Core/Portable/Completion/CommonCompletionService.cs
+7
-0
src/Features/Core/Portable/Completion/CompletionHelper.cs
src/Features/Core/Portable/Completion/CompletionHelper.cs
+13
-9
src/Features/Core/Portable/Completion/CompletionItem.cs
src/Features/Core/Portable/Completion/CompletionItem.cs
+10
-2
src/Features/Core/Portable/Completion/CompletionService.cs
src/Features/Core/Portable/Completion/CompletionService.cs
+30
-7
未找到文件。
src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterResult.cs
浏览文件 @
96e66888
...
...
@@ -3,6 +3,7 @@
using
System
;
using
Microsoft.CodeAnalysis.Completion
;
using
Microsoft.CodeAnalysis.PatternMatching
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion
...
...
@@ -12,12 +13,14 @@ internal struct FilterResult : IComparable<FilterResult>
public
readonly
CompletionItem
CompletionItem
;
public
readonly
bool
MatchedFilterText
;
public
readonly
string
FilterText
;
public
readonly
PatternMatch
?
PatternMatch
;
public
FilterResult
(
CompletionItem
completionItem
,
string
filterText
,
bool
matchedFilterText
)
public
FilterResult
(
CompletionItem
completionItem
,
string
filterText
,
bool
matchedFilterText
,
PatternMatch
?
patternMatch
)
{
CompletionItem
=
completionItem
;
MatchedFilterText
=
matchedFilterText
;
FilterText
=
filterText
;
PatternMatch
=
patternMatch
;
}
public
int
CompareTo
(
FilterResult
other
)
...
...
src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs
浏览文件 @
96e66888
...
...
@@ -9,6 +9,8 @@
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Completion
;
using
Microsoft.CodeAnalysis.PatternMatching
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.Text
;
using
Microsoft.CodeAnalysis.Text.Shared.Extensions
;
...
...
@@ -174,9 +176,9 @@ internal ItemManager(RecentItemsManager recentItemsManager)
displayTextSuffix
:
item
.
Suffix
);
}
if
(
MatchesFilterText
(
completionHelper
,
roslynItem
,
filterText
,
initialRoslynTriggerKind
,
filterReason
,
_recentItemsManager
.
RecentItems
))
if
(
MatchesFilterText
(
completionHelper
,
roslynItem
,
filterText
,
initialRoslynTriggerKind
,
filterReason
,
_recentItemsManager
.
RecentItems
,
out
var
patternMatch
))
{
initialListOfItemsToBeIncluded
.
Add
(
new
ExtendedFilterResult
(
item
,
new
FilterResult
(
roslynItem
,
filterText
,
matchedFilterText
:
true
)));
initialListOfItemsToBeIncluded
.
Add
(
new
ExtendedFilterResult
(
item
,
new
FilterResult
(
roslynItem
,
filterText
,
matchedFilterText
:
true
,
patternMatch
)));
}
else
{
...
...
@@ -193,7 +195,7 @@ internal ItemManager(RecentItemsManager recentItemsManager)
initialRoslynTriggerKind
==
CompletionTriggerKind
.
Invoke
||
filterText
.
Length
<=
1
)
{
initialListOfItemsToBeIncluded
.
Add
(
new
ExtendedFilterResult
(
item
,
new
FilterResult
(
roslynItem
,
filterText
,
matchedFilterText
:
false
)));
initialListOfItemsToBeIncluded
.
Add
(
new
ExtendedFilterResult
(
item
,
new
FilterResult
(
roslynItem
,
filterText
,
matchedFilterText
:
false
,
patternMatch
)));
}
}
}
...
...
@@ -214,30 +216,33 @@ internal ItemManager(RecentItemsManager recentItemsManager)
return
HandleAllItemsFilteredOut
(
reason
,
data
.
SelectedFilters
,
completionRules
);
}
// todo: Add comment
var
itemsToBeIncludedSortedByMatch
=
initialListOfItemsToBeIncluded
.
OrderBy
(
result
=>
result
.
FilterResult
.
PatternMatch
).
ToImmutableArray
();
var
options
=
document
?.
Project
.
Solution
.
Options
;
var
highlightMatchingPortions
=
options
?.
GetOption
(
CompletionOptions
.
HighlightMatchingPortionsOfCompletionListItems
,
document
.
Project
.
Language
)
??
true
;
var
showCompletionItemFilters
=
options
?.
GetOption
(
CompletionOptions
.
ShowCompletionItemFilters
,
document
.
Project
.
Language
)
??
true
;
var
updatedFilters
=
showCompletionItemFilters
?
GetUpdatedFilters
(
i
nitialListOfItemsToBeIncluded
,
data
.
SelectedFilters
)
?
GetUpdatedFilters
(
i
temsToBeIncludedSortedByMatch
,
data
.
SelectedFilters
)
:
ImmutableArray
<
CompletionFilterWithState
>.
Empty
;
var
highlightedList
=
GetHighlightedList
(
i
nitialListOfItemsToBeIncluded
,
filterText
,
completionHelper
,
highlightMatchingPortions
).
ToImmutableArray
(
);
var
highlightedList
=
GetHighlightedList
(
i
temsToBeIncludedSortedByMatch
,
filterText
,
completionHelper
,
highlightMatchingPortions
);
// If this was deletion, then we control the entire behavior of deletion ourselves.
if
(
initialRoslynTriggerKind
==
CompletionTriggerKind
.
Deletion
)
{
return
HandleDeletionTrigger
(
data
.
Trigger
.
Reason
,
i
nitialListOfItemsToBeIncluded
,
filterText
,
updatedFilters
,
highlightedList
);
return
HandleDeletionTrigger
(
data
.
Trigger
.
Reason
,
i
temsToBeIncludedSortedByMatch
,
filterText
,
updatedFilters
,
highlightedList
);
}
Func
<
ImmutableArray
<
RoslynCompletionItem
>,
string
,
ImmutableArray
<
RoslynCompletionItem
>>
filterMethod
;
Func
<
ImmutableArray
<
(
RoslynCompletionItem
,
PatternMatch
?)
>,
string
,
ImmutableArray
<
RoslynCompletionItem
>>
filterMethod
;
if
(
completionService
==
null
)
{
filterMethod
=
(
items
,
text
)
=>
CompletionService
.
FilterItems
(
completionHelper
,
items
,
text
);
filterMethod
=
(
items
WithPatternMatches
,
text
)
=>
CompletionService
.
FilterItems
(
completionHelper
,
itemsWithPatternMatches
);
}
else
{
filterMethod
=
(
items
,
text
)
=>
completionService
.
FilterItems
(
document
,
item
s
,
text
);
filterMethod
=
(
items
WithPatternMatches
,
text
)
=>
completionService
.
FilterItems
(
document
,
itemsWithPatternMatche
s
,
text
);
}
return
HandleNormalFiltering
(
...
...
@@ -247,7 +252,7 @@ internal ItemManager(RecentItemsManager recentItemsManager)
initialRoslynTriggerKind
,
filterReason
,
data
.
Trigger
.
Character
,
i
nitialListOfItemsToBeIncluded
,
i
temsToBeIncludedSortedByMatch
,
highlightedList
,
completionHelper
,
hasSuggestedItemOptions
);
...
...
@@ -284,6 +289,35 @@ static bool ShouldBeFilteredOutOfExpandedCompletionList(VSCompletionItem item, I
// 2. or, all associated expanders are unselected, therefore should be excluded
return
associatedWithUnselectedExpander
;
}
static
ImmutableArray
<
CompletionItemWithHighlight
>
GetHighlightedList
(
ImmutableArray
<
ExtendedFilterResult
>
filterResults
,
string
filterText
,
CompletionHelper
completionHelper
,
bool
highlightMatchingPortions
)
{
if
(!
highlightMatchingPortions
)
{
return
filterResults
.
SelectAsArray
(
r
=>
new
CompletionItemWithHighlight
(
r
.
VSCompletionItem
,
ImmutableArray
<
Span
>.
Empty
));
}
var
highlightedItems
=
ArrayBuilder
<
CompletionItemWithHighlight
>.
GetInstance
(
filterResults
.
Length
);
foreach
(
var
extendedResult
in
filterResults
)
{
// The PatternMatch in FilterResult is calculated based on Roslyn item's FilterText,
// which can be used to calculate highlighted span for VSCompletion item's DisplayText w/o doing the matching again.
// However, if the PatternMatch is null or the Roslyn item's FilterText is different from its DisplayText,
// we need to do the match against the display text of the VS item directly to get the highlighted spans.
var
filterResult
=
extendedResult
.
FilterResult
;
var
highlightedSpans
=
filterResult
.
PatternMatch
.
HasValue
&&
!
filterResult
.
CompletionItem
.
HasDifferentFilterText
?
filterResult
.
PatternMatch
.
Value
.
MatchedSpans
.
SelectAsArray
(
s
=>
s
.
ToSpan
(
filterResult
.
CompletionItem
.
DisplayTextPrefix
?.
Length
??
0
))
:
completionHelper
.
GetHighlightedSpans
(
extendedResult
.
VSCompletionItem
.
DisplayText
,
filterText
,
CultureInfo
.
CurrentCulture
).
SelectAsArray
(
s
=>
s
.
ToSpan
());
highlightedItems
.
Add
(
new
CompletionItemWithHighlight
(
extendedResult
.
VSCompletionItem
,
highlightedSpans
));
}
return
highlightedItems
.
ToImmutableAndFree
();
}
}
private
static
bool
IsAfterDot
(
ITextSnapshot
snapshot
,
ITrackingSpan
applicableToSpan
)
...
...
@@ -293,13 +327,13 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT
}
private
FilteredCompletionModel
HandleNormalFiltering
(
Func
<
ImmutableArray
<
RoslynCompletionItem
>,
string
,
ImmutableArray
<
RoslynCompletionItem
>>
filterMethod
,
Func
<
ImmutableArray
<
(
RoslynCompletionItem
,
PatternMatch
?)
>,
string
,
ImmutableArray
<
RoslynCompletionItem
>>
filterMethod
,
string
filterText
,
ImmutableArray
<
CompletionFilterWithState
>
filters
,
CompletionTriggerKind
initialRoslynTriggerKind
,
CompletionFilterReason
filterReason
,
char
typeChar
,
List
<
ExtendedFilterResult
>
itemsInList
,
ImmutableArray
<
ExtendedFilterResult
>
itemsInList
,
ImmutableArray
<
CompletionItemWithHighlight
>
highlightedList
,
CompletionHelper
completionHelper
,
bool
hasSuggestedItemOptions
)
...
...
@@ -309,8 +343,7 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT
// Ask the language to determine which of the *matched* items it wants to select.
var
matchingItems
=
itemsInList
.
Where
(
r
=>
r
.
FilterResult
.
MatchedFilterText
)
.
Select
(
t
=>
t
.
FilterResult
.
CompletionItem
)
.
AsImmutable
();
.
SelectAsArray
(
t
=>
(
t
.
FilterResult
.
CompletionItem
,
t
.
FilterResult
.
PatternMatch
));
var
chosenItems
=
filterMethod
(
matchingItems
,
filterText
);
...
...
@@ -331,7 +364,7 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT
if
(
bestItem
!=
null
)
{
selectedItemIndex
=
itemsInList
.
IndexOf
(
i
=>
Equals
(
i
.
FilterResult
.
CompletionItem
,
bestItem
));
var
deduplicatedListCount
=
matchingItems
.
Where
(
r
=>
!
r
.
IsPreferredItem
()).
Count
();
var
deduplicatedListCount
=
matchingItems
.
Where
(
r
=>
!
r
.
CompletionItem
.
IsPreferredItem
()).
Count
();
if
(
selectedItemIndex
>
-
1
&&
deduplicatedListCount
==
1
&&
filterText
.
Length
>
0
)
...
...
@@ -376,12 +409,12 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT
private
FilteredCompletionModel
HandleDeletionTrigger
(
CompletionTriggerReason
filterTriggerKind
,
List
<
ExtendedFilterResult
>
filterResults
,
ImmutableArray
<
ExtendedFilterResult
>
filterResults
,
string
filterText
,
ImmutableArray
<
CompletionFilterWithState
>
filters
,
ImmutableArray
<
CompletionItemWithHighlight
>
highlightedList
)
{
var
matchingItems
=
filterResults
.
Where
(
r
=>
r
.
FilterResult
.
MatchedFilterText
).
AsImmutable
(
);
var
matchingItems
=
filterResults
.
Where
AsArray
(
r
=>
r
.
FilterResult
.
MatchedFilterText
);
if
(
filterTriggerKind
==
CompletionTriggerReason
.
Insertion
&&
!
matchingItems
.
Any
())
{
...
...
@@ -479,26 +512,8 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT
filters
,
selection
,
centerSelection
:
true
,
uniqueItem
:
default
);
}
private
static
IEnumerable
<
CompletionItemWithHighlight
>
GetHighlightedList
(
IEnumerable
<
ExtendedFilterResult
>
filterResults
,
string
filterText
,
CompletionHelper
completionHelper
,
bool
highlightMatchingPortions
)
{
var
highlightedList
=
new
List
<
CompletionItemWithHighlight
>();
foreach
(
var
item
in
filterResults
)
{
var
highlightedSpans
=
highlightMatchingPortions
?
completionHelper
.
GetHighlightedSpans
(
item
.
VSCompletionItem
.
DisplayText
,
filterText
,
CultureInfo
.
CurrentCulture
)
:
ImmutableArray
<
TextSpan
>.
Empty
;
highlightedList
.
Add
(
new
CompletionItemWithHighlight
(
item
.
VSCompletionItem
,
highlightedSpans
.
Select
(
s
=>
s
.
ToSpan
()).
ToImmutableArray
()));
}
return
highlightedList
;
}
private
static
ImmutableArray
<
CompletionFilterWithState
>
GetUpdatedFilters
(
List
<
ExtendedFilterResult
>
filteredList
,
ImmutableArray
<
ExtendedFilterResult
>
filteredList
,
ImmutableArray
<
CompletionFilterWithState
>
filters
)
{
// See which filters might be enabled based on the typed code
...
...
@@ -571,10 +586,20 @@ internal static bool IsBetterDeletionMatch(FilterResult result1, FilterResult re
=>
result1
.
CompareTo
(
result2
)
>
0
;
internal
static
bool
MatchesFilterText
(
CompletionHelper
helper
,
RoslynCompletionItem
item
,
string
filterText
,
CompletionTriggerKind
initialTriggerKind
,
CompletionFilterReason
filterReason
,
ImmutableArray
<
string
>
recentItems
)
CompletionHelper
helper
,
RoslynCompletionItem
item
,
string
filterText
,
CompletionTriggerKind
initialTriggerKind
,
CompletionFilterReason
filterReason
,
ImmutableArray
<
string
>
recentItems
,
out
PatternMatch
?
patternMatch
)
{
// Get the match of the given completion item for the pattern provided so far.
// A completion item is checked against the pattern by see if it's
// CompletionItem.FilterText matches the item. That way, the pattern it checked
// against terms like "IList" and not IList<>
patternMatch
=
helper
.
GetMatch
(
item
.
FilterText
,
filterText
,
includeMatchSpans
:
true
,
CultureInfo
.
CurrentCulture
);
// For the deletion we bake in the core logic for how matching should work.
// This way deletion feels the same across all languages that opt into deletion
// as a completion trigger.
...
...
@@ -603,11 +628,8 @@ internal static bool IsBetterDeletionMatch(FilterResult result1, FilterResult re
}
}
// Checks if the given completion item matches the pattern provided so far.
// A completion item is checked against the pattern by see if it's
// CompletionItem.FilterText matches the item. That way, the pattern it checked
// against terms like "IList" and not IList<>
return
helper
.
MatchesPattern
(
item
.
FilterText
,
filterText
,
CultureInfo
.
CurrentCulture
);
// Otherwise, the item matches filter text if a pattern match is returned.
return
patternMatch
!=
null
;
}
internal
static
bool
IsHardSelection
(
...
...
@@ -644,7 +666,7 @@ internal static bool IsBetterDeletionMatch(FilterResult result1, FilterResult re
// If the user moved the caret left after they started typing, the 'best' match may not match at all
// against the full text span that this item would be replacing.
if
(!
ItemManager
.
MatchesFilterText
(
completionHelper
,
bestFilterMatch
,
fullFilterText
,
initialTriggerKind
,
filterReason
,
recentItems
))
if
(!
ItemManager
.
MatchesFilterText
(
completionHelper
,
bestFilterMatch
,
fullFilterText
,
initialTriggerKind
,
filterReason
,
recentItems
,
out
_
))
{
return
false
;
}
...
...
src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs
浏览文件 @
96e66888
...
...
@@ -140,12 +140,12 @@ internal partial class Session
}
// Check if the item matches the filter text typed so far.
var
matchesFilterText
=
ItemManager
.
MatchesFilterText
(
helper
,
currentItem
,
filterText
,
model
.
Trigger
.
Kind
,
filterReason
,
recentItems
);
var
matchesFilterText
=
ItemManager
.
MatchesFilterText
(
helper
,
currentItem
,
filterText
,
model
.
Trigger
.
Kind
,
filterReason
,
recentItems
,
out
var
patternMatch
);
if
(
matchesFilterText
)
{
filterResults
.
Add
(
new
FilterResult
(
currentItem
,
filterText
,
matchedFilterText
:
true
));
currentItem
,
filterText
,
matchedFilterText
:
true
,
patternMatch
));
}
else
{
...
...
@@ -167,7 +167,7 @@ internal partial class Session
if
(
shouldKeepItem
)
{
filterResults
.
Add
(
new
FilterResult
(
currentItem
,
filterText
,
matchedFilterText
:
false
));
currentItem
,
filterText
,
matchedFilterText
:
false
,
patternMatch
));
}
}
}
...
...
@@ -250,8 +250,7 @@ private bool IsAfterDot(Model model)
}
var
matchingCompletionItems
=
filterResults
.
Where
(
r
=>
r
.
MatchedFilterText
)
.
Select
(
t
=>
t
.
CompletionItem
)
.
AsImmutable
();
.
SelectAsArray
(
t
=>
(
t
.
CompletionItem
,
t
.
PatternMatch
));
var
chosenItems
=
service
.
FilterItems
(
document
,
matchingCompletionItems
,
filterText
);
...
...
src/EditorFeatures/Text/Shared/Extensions/TextSpanExtensions.cs
浏览文件 @
96e66888
...
...
@@ -2,7 +2,6 @@
using
System.Diagnostics
;
using
Microsoft.VisualStudio.Text
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Text.Shared.Extensions
{
...
...
@@ -16,6 +15,14 @@ public static Span ToSpan(this TextSpan textSpan)
return
new
Span
(
textSpan
.
Start
,
textSpan
.
Length
);
}
/// <summary>
/// Convert a <see cref="TextSpan"/> instance to a <see cref="TextSpan"/> with additional offset.
/// </summary>
public
static
Span
ToSpan
(
this
TextSpan
textSpan
,
int
offset
)
{
return
new
Span
(
textSpan
.
Start
+
offset
,
textSpan
.
Length
);
}
/// <summary>
/// Convert a <see cref="TextSpan"/> to a <see cref="SnapshotSpan"/> on the given <see cref="ITextSnapshot"/> instance
/// </summary>
...
...
src/Features/Core/Portable/Completion/CommonCompletionService.cs
浏览文件 @
96e66888
...
...
@@ -4,6 +4,7 @@
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.PatternMatching
;
using
Microsoft.CodeAnalysis.Tags
;
namespace
Microsoft.CodeAnalysis.Completion
...
...
@@ -55,5 +56,11 @@ protected static bool IsSnippetItem(CompletionItem item)
{
return
item
.
Tags
.
Contains
(
WellKnownTags
.
Snippet
);
}
internal
override
ImmutableArray
<
CompletionItem
>
FilterItems
(
Document
document
,
ImmutableArray
<(
CompletionItem
,
PatternMatch
?)>
itemsWithPatternMatch
,
string
filterText
)
{
var
helper
=
CompletionHelper
.
GetHelper
(
document
);
return
CompletionService
.
FilterItems
(
helper
,
itemsWithPatternMatch
);
}
}
}
src/Features/Core/Portable/Completion/CompletionHelper.cs
浏览文件 @
96e66888
...
...
@@ -43,14 +43,13 @@ public static CompletionHelper GetHelper(Document document)
/// results, or false if it should not be.
/// </summary>
public
bool
MatchesPattern
(
string
text
,
string
pattern
,
CultureInfo
culture
)
=>
GetMatch
(
text
,
pattern
,
culture
)
!=
null
;
=>
GetMatch
(
text
,
pattern
,
includeMatchSpans
:
false
,
culture
)
!=
null
;
private
PatternMatch
?
GetMatch
(
string
text
,
string
pattern
,
CultureInfo
culture
)
=>
GetMatch
(
text
,
pattern
,
includeMatchSpans
:
false
,
culture
:
culture
);
private
PatternMatch
?
GetMatch
(
string
completionItemText
,
string
pattern
,
bool
includeMatchSpans
,
CultureInfo
culture
)
public
PatternMatch
?
GetMatch
(
string
completionItemText
,
string
pattern
,
bool
includeMatchSpans
,
CultureInfo
culture
)
{
// If the item has a dot in it (i.e. for something like enum completion), then attempt
// to match what the user wrote against the last portion of the name. That way if they
...
...
@@ -136,9 +135,14 @@ private PatternMatcher GetPatternMatcher(string pattern, CultureInfo culture, bo
/// </summary>
public
int
CompareItems
(
CompletionItem
item1
,
CompletionItem
item2
,
string
pattern
,
CultureInfo
culture
)
{
var
match1
=
GetMatch
(
item1
.
FilterText
,
pattern
,
culture
);
var
match2
=
GetMatch
(
item2
.
FilterText
,
pattern
,
culture
);
var
match1
=
GetMatch
(
item1
.
FilterText
,
pattern
,
includeMatchSpans
:
false
,
culture
);
var
match2
=
GetMatch
(
item2
.
FilterText
,
pattern
,
includeMatchSpans
:
false
,
culture
);
return
CompareItems
(
item1
,
match1
,
item2
,
match2
);
}
public
int
CompareItems
(
CompletionItem
item1
,
PatternMatch
?
match1
,
CompletionItem
item2
,
PatternMatch
?
match2
)
{
if
(
match1
!=
null
&&
match2
!=
null
)
{
var
result
=
CompareMatches
(
match1
.
Value
,
match2
.
Value
,
item1
,
item2
);
...
...
src/Features/Core/Portable/Completion/CompletionItem.cs
浏览文件 @
96e66888
...
...
@@ -14,6 +14,8 @@ namespace Microsoft.CodeAnalysis.Completion
[
DebuggerDisplay
(
"{DisplayText}"
)]
public
sealed
class
CompletionItem
:
IComparable
<
CompletionItem
>
{
private
readonly
string
_filterText
;
/// <summary>
/// The text that is displayed to the user.
/// </summary>
...
...
@@ -37,7 +39,9 @@ public sealed class CompletionItem : IComparable<CompletionItem>
/// The text used to determine if the item matches the filter and is show in the list.
/// This is often the same as <see cref="DisplayText"/> but may be different in certain circumstances.
/// </summary>
public
string
FilterText
{
get
;
}
public
string
FilterText
=>
_filterText
??
DisplayText
;
internal
bool
HasDifferentFilterText
=>
_filterText
!=
null
;
/// <summary>
/// The text used to determine the order that the item appears in the list.
...
...
@@ -107,13 +111,17 @@ public sealed class CompletionItem : IComparable<CompletionItem>
DisplayText
=
displayText
??
""
;
DisplayTextPrefix
=
displayTextPrefix
??
""
;
DisplayTextSuffix
=
displayTextSuffix
??
""
;
FilterText
=
filterText
??
DisplayText
;
SortText
=
sortText
??
DisplayText
;
InlineDescription
=
inlineDescription
??
""
;
Span
=
span
;
Properties
=
properties
??
ImmutableDictionary
<
string
,
string
>.
Empty
;
Tags
=
tags
.
NullToEmpty
();
Rules
=
rules
??
CompletionItemRules
.
Default
;
if
(!
DisplayText
.
Equals
(
filterText
,
StringComparison
.
Ordinal
))
{
_filterText
=
filterText
;
}
}
// binary back compat overload
...
...
src/Features/Core/Portable/Completion/CompletionService.cs
浏览文件 @
96e66888
...
...
@@ -2,11 +2,13 @@
using
System
;
using
System.Collections.Immutable
;
using
System.Diagnostics
;
using
System.Globalization
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.PatternMatching
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.Text
;
...
...
@@ -175,41 +177,62 @@ public virtual TextSpan GetDefaultCompletionListSpan(SourceText text, int caretP
return
FilterItems
(
helper
,
items
,
filterText
);
}
internal
virtual
ImmutableArray
<
CompletionItem
>
FilterItems
(
Document
document
,
ImmutableArray
<(
CompletionItem
,
PatternMatch
?)>
itemsWithPatternMatch
,
string
filterText
)
{
// Default implementation just drops the pattern matches and
// calls the public overload of FilterItems for compatibility.
return
FilterItems
(
document
,
itemsWithPatternMatch
.
SelectAsArray
(
item
=>
item
.
Item1
),
filterText
);
}
internal
static
ImmutableArray
<
CompletionItem
>
FilterItems
(
CompletionHelper
completionHelper
,
ImmutableArray
<
CompletionItem
>
items
,
string
filterText
)
{
var
bestItems
=
ArrayBuilder
<
CompletionItem
>.
GetInstance
();
foreach
(
var
item
in
items
)
var
itemsWithPatternMatch
=
items
.
SelectAsArray
(
item
=>
(
item
,
completionHelper
.
GetMatch
(
item
.
FilterText
,
filterText
,
includeMatchSpans
:
false
,
CultureInfo
.
CurrentCulture
)));
return
FilterItems
(
completionHelper
,
itemsWithPatternMatch
);
}
internal
static
ImmutableArray
<
CompletionItem
>
FilterItems
(
CompletionHelper
completionHelper
,
ImmutableArray
<(
CompletionItem
item
,
PatternMatch
?
match
)>
itemsWithPatternMatch
)
{
var
bestItems
=
ArrayBuilder
<(
CompletionItem
,
PatternMatch
?)>.
GetInstance
();
foreach
(
var
pair
in
itemsWithPatternMatch
)
{
if
(
bestItems
.
Count
==
0
)
{
// We've found no good items yet. So this is the best item currently.
bestItems
.
Add
(
item
);
bestItems
.
Add
(
pair
);
}
else
{
var
comparison
=
completionHelper
.
CompareItems
(
item
,
bestItems
.
First
(),
filterText
,
CultureInfo
.
CurrentCulture
);
var
(
bestItem
,
bestItemMatch
)
=
bestItems
.
First
();
var
comparison
=
completionHelper
.
CompareItems
(
pair
.
item
,
pair
.
match
,
bestItem
,
bestItemMatch
);
if
(
comparison
<
0
)
{
// This item is strictly better than the best items we've found so far.
bestItems
.
Clear
();
bestItems
.
Add
(
item
);
bestItems
.
Add
(
pair
);
}
else
if
(
comparison
==
0
)
{
// This item is as good as the items we've been collecting. We'll return
// it and let the controller decide what to do. (For example, it will
// pick the one that has the best MRU index).
bestItems
.
Add
(
item
);
bestItems
.
Add
(
pair
);
}
// otherwise, this item is strictly worse than the ones we've been collecting.
// We can just ignore it.
}
}
return
bestItems
.
ToImmutableAndFree
();
return
bestItems
.
ToImmutableAndFree
()
.
SelectAsArray
(
itemWithPatternMatch
=>
itemWithPatternMatch
.
Item1
)
;
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录