Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
611f6f93
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
611f6f93
编写于
8月 13, 2020
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
scorer - drop prefix and camelcase scoring and prefer lcs
上级
4398a424
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
59 addition
and
75 deletion
+59
-75
src/vs/base/common/fuzzyScorer.ts
src/vs/base/common/fuzzyScorer.ts
+14
-75
src/vs/base/test/common/fuzzyScorer.test.ts
src/vs/base/test/common/fuzzyScorer.test.ts
+45
-0
未找到文件。
src/vs/base/common/fuzzyScorer.ts
浏览文件 @
611f6f93
...
...
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import
{
compareAnything
}
from
'
vs/base/common/comparers
'
;
import
{
matchesPrefix
,
IMatch
,
matchesCamelCase
,
isUpper
,
fuzzyScore
,
createMatches
as
createFuzzyMatches
,
matchesStrictPrefix
}
from
'
vs/base/common/filters
'
;
import
{
IMatch
,
isUpper
,
fuzzyScore
,
createMatches
as
createFuzzyMatches
}
from
'
vs/base/common/filters
'
;
import
{
sep
}
from
'
vs/base/common/path
'
;
import
{
isWindows
,
isLinux
}
from
'
vs/base/common/platform
'
;
import
{
stripWildcards
,
equalsIgnoreCase
}
from
'
vs/base/common/strings
'
;
...
...
@@ -369,10 +369,7 @@ export interface IItemAccessor<T> {
}
const
PATH_IDENTITY_SCORE
=
1
<<
18
;
const
LABEL_PREFIX_SCORE_MATCHCASE
=
1
<<
17
;
const
LABEL_PREFIX_SCORE_IGNORECASE
=
1
<<
16
;
const
LABEL_CAMELCASE_SCORE
=
1
<<
15
;
const
LABEL_SCORE_THRESHOLD
=
1
<<
14
;
const
LABEL_SCORE_THRESHOLD
=
1
<<
17
;
export
function
scoreItemFuzzy
<
T
>
(
item
:
T
,
query
:
IPreparedQuery
,
fuzzy
:
boolean
,
accessor
:
IItemAccessor
<
T
>
,
cache
:
FuzzyScorerCache
):
IItemScore
{
if
(
!
item
||
!
query
.
normalized
)
{
...
...
@@ -457,21 +454,6 @@ function doScoreItemFuzzySingle(label: string, description: string | undefined,
// Prefer label matches if told so
if
(
preferLabelMatches
)
{
// Treat prefix matches on the label highest
const
prefixLabelMatchIgnoreCase
=
matchesPrefix
(
query
.
normalized
,
label
);
if
(
prefixLabelMatchIgnoreCase
)
{
const
prefixLabelMatchStrictCase
=
matchesStrictPrefix
(
query
.
normalized
,
label
);
return
{
score
:
prefixLabelMatchStrictCase
?
LABEL_PREFIX_SCORE_MATCHCASE
:
LABEL_PREFIX_SCORE_IGNORECASE
,
labelMatch
:
prefixLabelMatchStrictCase
||
prefixLabelMatchIgnoreCase
};
}
// Treat camelcase matches on the label second highest
const
camelcaseLabelMatch
=
matchesCamelCase
(
query
.
normalized
,
label
);
if
(
camelcaseLabelMatch
)
{
return
{
score
:
LABEL_CAMELCASE_SCORE
,
labelMatch
:
camelcaseLabelMatch
};
}
// Prefer scores on the label if any
const
[
labelScore
,
labelPositions
]
=
scoreFuzzy
(
label
,
query
.
normalized
,
query
.
normalizedLowercase
,
fuzzy
);
if
(
labelScore
)
{
return
{
score
:
labelScore
+
LABEL_SCORE_THRESHOLD
,
labelMatch
:
createMatches
(
labelPositions
)
};
...
...
@@ -594,81 +576,39 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
const
scoreA
=
itemScoreA
.
score
;
const
scoreB
=
itemScoreB
.
score
;
// 1.)
prefer identity matches
// 1.)
identity matches have highest score
if
(
scoreA
===
PATH_IDENTITY_SCORE
||
scoreB
===
PATH_IDENTITY_SCORE
)
{
if
(
scoreA
!==
scoreB
)
{
return
scoreA
===
PATH_IDENTITY_SCORE
?
-
1
:
1
;
}
}
// 2.) prefer label prefix matches (match case)
if
(
scoreA
===
LABEL_PREFIX_SCORE_MATCHCASE
||
scoreB
===
LABEL_PREFIX_SCORE_MATCHCASE
)
{
if
(
scoreA
!==
scoreB
)
{
return
scoreA
===
LABEL_PREFIX_SCORE_MATCHCASE
?
-
1
:
1
;
}
const
labelA
=
accessor
.
getItemLabel
(
itemA
)
||
''
;
const
labelB
=
accessor
.
getItemLabel
(
itemB
)
||
''
;
// prefer shorter names when both match on label prefix
if
(
labelA
.
length
!==
labelB
.
length
)
{
return
labelA
.
length
-
labelB
.
length
;
}
}
// 3.) prefer label prefix matches (ignore case)
if
(
scoreA
===
LABEL_PREFIX_SCORE_IGNORECASE
||
scoreB
===
LABEL_PREFIX_SCORE_IGNORECASE
)
{
if
(
scoreA
!==
scoreB
)
{
return
scoreA
===
LABEL_PREFIX_SCORE_IGNORECASE
?
-
1
:
1
;
}
const
labelA
=
accessor
.
getItemLabel
(
itemA
)
||
''
;
const
labelB
=
accessor
.
getItemLabel
(
itemB
)
||
''
;
// prefer shorter names when both match on label prefix
if
(
labelA
.
length
!==
labelB
.
length
)
{
return
labelA
.
length
-
labelB
.
length
;
}
}
// 4.) prefer camelcase matches
if
(
scoreA
===
LABEL_CAMELCASE_SCORE
||
scoreB
===
LABEL_CAMELCASE_SCORE
)
{
// 2.) matches on label are considered higher compared to label+description matches
if
(
scoreA
>
LABEL_SCORE_THRESHOLD
||
scoreB
>
LABEL_SCORE_THRESHOLD
)
{
if
(
scoreA
!==
scoreB
)
{
return
scoreA
===
LABEL_CAMELCASE_SCORE
?
-
1
:
1
;
return
scoreA
>
scoreB
?
-
1
:
1
;
}
const
labelA
=
accessor
.
getItemLabel
(
itemA
)
||
''
;
const
labelB
=
accessor
.
getItemLabel
(
itemB
)
||
''
;
// prefer more compact camel case matches over longer
// prefer more compact matches over longer in label
const
comparedByMatchLength
=
compareByMatchLength
(
itemScoreA
.
labelMatch
,
itemScoreB
.
labelMatch
);
if
(
comparedByMatchLength
!==
0
)
{
return
comparedByMatchLength
;
}
// prefer shorter names when both match on label camelcase
// prefer shorter labels over longer labels
const
labelA
=
accessor
.
getItemLabel
(
itemA
)
||
''
;
const
labelB
=
accessor
.
getItemLabel
(
itemB
)
||
''
;
if
(
labelA
.
length
!==
labelB
.
length
)
{
return
labelA
.
length
-
labelB
.
length
;
}
}
// 5.) prefer label scores
if
(
scoreA
>
LABEL_SCORE_THRESHOLD
||
scoreB
>
LABEL_SCORE_THRESHOLD
)
{
if
(
scoreB
<
LABEL_SCORE_THRESHOLD
)
{
return
-
1
;
}
if
(
scoreA
<
LABEL_SCORE_THRESHOLD
)
{
return
1
;
}
}
// 6.) compare by score
// 3.) compare by score in label+description
if
(
scoreA
!==
scoreB
)
{
return
scoreA
>
scoreB
?
-
1
:
1
;
}
//
7.)
prefer matches in label over non-label matches
//
4.) scores are identical:
prefer matches in label over non-label matches
const
itemAHasLabelMatches
=
Array
.
isArray
(
itemScoreA
.
labelMatch
)
&&
itemScoreA
.
labelMatch
.
length
>
0
;
const
itemBHasLabelMatches
=
Array
.
isArray
(
itemScoreB
.
labelMatch
)
&&
itemScoreB
.
labelMatch
.
length
>
0
;
if
(
itemAHasLabelMatches
&&
!
itemBHasLabelMatches
)
{
...
...
@@ -677,15 +617,14 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
return
1
;
}
//
8.) scores are identical,
prefer more compact matches (label and description)
//
5.) scores are identical:
prefer more compact matches (label and description)
const
itemAMatchDistance
=
computeLabelAndDescriptionMatchDistance
(
itemA
,
itemScoreA
,
accessor
);
const
itemBMatchDistance
=
computeLabelAndDescriptionMatchDistance
(
itemB
,
itemScoreB
,
accessor
);
if
(
itemAMatchDistance
&&
itemBMatchDistance
&&
itemAMatchDistance
!==
itemBMatchDistance
)
{
return
itemBMatchDistance
>
itemAMatchDistance
?
-
1
:
1
;
}
// 9.) at this point, scores are identical and match compactness as well
// for both items so we start to use the fallback compare
// 6.) scores are identical: start to use the fallback compare
return
fallbackCompare
(
itemA
,
itemB
,
query
,
accessor
);
}
...
...
src/vs/base/test/common/fuzzyScorer.test.ts
浏览文件 @
611f6f93
...
...
@@ -925,6 +925,51 @@ suite('Fuzzy Scorer', () => {
assert
.
equal
(
res
[
0
],
resourceB
);
});
test
(
'
compareFilesByScore - prefer shorter match (bug #103052) - foo bar
'
,
function
()
{
const
resourceA
=
URI
.
file
(
'
app/emails/foo.bar.js
'
);
const
resourceB
=
URI
.
file
(
'
app/emails/other-footer.other-bar.js
'
);
for
(
const
query
of
[
'
foo bar
'
,
'
foobar
'
])
{
let
res
=
[
resourceA
,
resourceB
].
sort
((
r1
,
r2
)
=>
compareItemsByScore
(
r1
,
r2
,
query
,
true
,
ResourceAccessor
));
assert
.
equal
(
res
[
0
],
resourceA
);
assert
.
equal
(
res
[
1
],
resourceB
);
res
=
[
resourceB
,
resourceA
].
sort
((
r1
,
r2
)
=>
compareItemsByScore
(
r1
,
r2
,
query
,
true
,
ResourceAccessor
));
assert
.
equal
(
res
[
0
],
resourceA
);
assert
.
equal
(
res
[
1
],
resourceB
);
}
});
test
(
'
compareFilesByScore - prefer shorter match (bug #103052) - payment model
'
,
function
()
{
const
resourceA
=
URI
.
file
(
'
app/components/payment/payment.model.js
'
);
const
resourceB
=
URI
.
file
(
'
app/components/online-payments-history/online-payments-history.model.js
'
);
for
(
const
query
of
[
'
payment model
'
,
'
paymentmodel
'
])
{
let
res
=
[
resourceA
,
resourceB
].
sort
((
r1
,
r2
)
=>
compareItemsByScore
(
r1
,
r2
,
query
,
true
,
ResourceAccessor
));
assert
.
equal
(
res
[
0
],
resourceA
);
assert
.
equal
(
res
[
1
],
resourceB
);
res
=
[
resourceB
,
resourceA
].
sort
((
r1
,
r2
)
=>
compareItemsByScore
(
r1
,
r2
,
query
,
true
,
ResourceAccessor
));
assert
.
equal
(
res
[
0
],
resourceA
);
assert
.
equal
(
res
[
1
],
resourceB
);
}
});
test
(
'
compareFilesByScore - prefer shorter match (bug #103052) - color
'
,
function
()
{
const
resourceA
=
URI
.
file
(
'
app/constants/color.js
'
);
const
resourceB
=
URI
.
file
(
'
app/components/model/input/pick-avatar-color.js
'
);
for
(
const
query
of
[
'
color js
'
,
'
colorjs
'
])
{
let
res
=
[
resourceA
,
resourceB
].
sort
((
r1
,
r2
)
=>
compareItemsByScore
(
r1
,
r2
,
query
,
true
,
ResourceAccessor
));
assert
.
equal
(
res
[
0
],
resourceA
);
assert
.
equal
(
res
[
1
],
resourceB
);
res
=
[
resourceB
,
resourceA
].
sort
((
r1
,
r2
)
=>
compareItemsByScore
(
r1
,
r2
,
query
,
true
,
ResourceAccessor
));
assert
.
equal
(
res
[
0
],
resourceA
);
assert
.
equal
(
res
[
1
],
resourceB
);
}
});
test
(
'
prepareQuery
'
,
()
=>
{
assert
.
equal
(
scorer
.
prepareQuery
(
'
f*a
'
).
normalized
,
'
fa
'
);
assert
.
equal
(
scorer
.
prepareQuery
(
'
model Tester.ts
'
).
original
,
'
model Tester.ts
'
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录