Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
c1c90f8e
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c1c90f8e
编写于
3月 27, 2020
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
quick access - allow to match on multiple inputs (fix #30404)
上级
fb11f140
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
248 addition
and
64 deletion
+248
-64
src/vs/base/common/fuzzyScorer.ts
src/vs/base/common/fuzzyScorer.ts
+83
-11
src/vs/base/test/common/fuzzyScorer.test.ts
src/vs/base/test/common/fuzzyScorer.test.ts
+70
-3
src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts
src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts
+18
-11
src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts
...b/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts
+2
-1
src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts
...s/workbench/contrib/search/browser/anythingQuickAccess.ts
+50
-20
src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts
...vs/workbench/contrib/search/browser/symbolsQuickAccess.ts
+23
-16
src/vs/workbench/services/search/node/fileSearch.ts
src/vs/workbench/services/search/node/fileSearch.ts
+1
-1
src/vs/workbench/services/search/node/rawSearchService.ts
src/vs/workbench/services/search/node/rawSearchService.ts
+1
-1
未找到文件。
src/vs/base/common/fuzzyScorer.ts
浏览文件 @
c1c90f8e
...
...
@@ -9,6 +9,7 @@ import { sep } from 'vs/base/common/path';
import
{
isWindows
,
isLinux
}
from
'
vs/base/common/platform
'
;
import
{
stripWildcards
,
equalsIgnoreCase
}
from
'
vs/base/common/strings
'
;
import
{
CharCode
}
from
'
vs/base/common/charCode
'
;
import
{
distinctES6
}
from
'
vs/base/common/arrays
'
;
export
type
Score
=
[
number
/* score */
,
number
[]
/* match positions */
];
export
type
ScorerCache
=
{
[
key
:
string
]:
IItemScore
};
...
...
@@ -19,7 +20,40 @@ const NO_SCORE: Score = [NO_MATCH, []];
// const DEBUG = false;
// const DEBUG_MATRIX = false;
export
function
score
(
target
:
string
,
query
:
string
,
queryLower
:
string
,
fuzzy
:
boolean
):
Score
{
export
function
score
(
target
:
string
,
query
:
IPreparedQuery
,
fuzzy
:
boolean
):
Score
{
if
(
query
.
values
&&
query
.
values
.
length
>
1
)
{
return
scoreMultiple
(
target
,
query
.
values
,
fuzzy
);
}
return
scoreSingle
(
target
,
query
.
value
,
query
.
valueLowercase
,
fuzzy
);
}
function
scoreMultiple
(
target
:
string
,
query
:
IPreparedQueryPiece
[],
fuzzy
:
boolean
):
Score
{
let
totalScore
=
NO_MATCH
;
const
totalPositions
:
number
[]
=
[];
for
(
const
{
value
,
valueLowercase
}
of
query
)
{
const
[
scoreValue
,
positions
]
=
scoreSingle
(
target
,
value
,
valueLowercase
,
fuzzy
);
if
(
scoreValue
===
NO_MATCH
)
{
// if a single query value does not match, return with
// no score entirely, we require all queries to match
return
NO_SCORE
;
}
totalScore
+=
scoreValue
;
totalPositions
.
push
(...
positions
);
}
if
(
totalScore
===
NO_MATCH
)
{
return
NO_SCORE
;
}
// if we have a score, ensure that the positions are
// sorted in ascending order and distinct
return
[
totalScore
,
distinctES6
(
totalPositions
).
sort
((
a
,
b
)
=>
a
-
b
)];
}
function
scoreSingle
(
target
:
string
,
query
:
string
,
queryLower
:
string
,
fuzzy
:
boolean
):
Score
{
if
(
!
target
||
!
query
)
{
return
NO_SCORE
;
// return early if target or query are undefined
}
...
...
@@ -303,21 +337,62 @@ const LABEL_PREFIX_SCORE = 1 << 17;
const
LABEL_CAMELCASE_SCORE
=
1
<<
16
;
const
LABEL_SCORE_THRESHOLD
=
1
<<
15
;
export
interface
IPreparedQuery
{
export
interface
IPreparedQuery
Piece
{
original
:
string
;
originalLowercase
:
string
;
value
:
string
;
lowercase
:
string
;
valueLowercase
:
string
;
}
export
interface
IPreparedQuery
extends
IPreparedQueryPiece
{
// Split by spaces
values
:
IPreparedQueryPiece
[]
|
undefined
;
containsPathSeparator
:
boolean
;
}
/**
* Helper function to prepare a search value for scoring by removing unwanted characters.
* Helper function to prepare a search value for scoring by removing unwanted characters
* and allowing to score on multiple pieces separated by whitespace character.
*/
const
MULTIPL_QUERY_VALUES_SEPARATOR
=
'
'
;
export
function
prepareQuery
(
original
:
string
):
IPreparedQuery
{
if
(
!
original
)
{
if
(
typeof
original
!==
'
string
'
)
{
original
=
''
;
}
const
originalLowercase
=
original
.
toLowerCase
();
const
value
=
prepareQueryValue
(
original
);
const
valueLowercase
=
value
.
toLowerCase
();
const
containsPathSeparator
=
value
.
indexOf
(
sep
)
>=
0
;
let
values
:
IPreparedQueryPiece
[]
|
undefined
=
undefined
;
const
originalSplit
=
original
.
split
(
MULTIPL_QUERY_VALUES_SEPARATOR
);
if
(
originalSplit
.
length
>
1
)
{
for
(
const
originalPiece
of
originalSplit
)
{
const
valuePiece
=
prepareQueryValue
(
originalPiece
);
if
(
valuePiece
)
{
if
(
!
values
)
{
values
=
[];
}
values
.
push
({
original
:
originalPiece
,
originalLowercase
:
originalPiece
.
toLowerCase
(),
value
:
valuePiece
,
valueLowercase
:
valuePiece
.
toLowerCase
()
});
}
}
}
return
{
original
,
originalLowercase
,
value
,
valueLowercase
,
values
,
containsPathSeparator
};
}
function
prepareQueryValue
(
original
:
string
):
string
{
let
value
=
stripWildcards
(
original
).
replace
(
/
\s
/g
,
''
);
// get rid of all wildcards and whitespace
if
(
isWindows
)
{
value
=
value
.
replace
(
/
\/
/g
,
sep
);
// Help Windows users to search for paths when using slash
...
...
@@ -325,10 +400,7 @@ export function prepareQuery(original: string): IPreparedQuery {
value
=
value
.
replace
(
/
\\
/g
,
sep
);
// Help macOS/Linux users to search for paths when using backslash
}
const
lowercase
=
value
.
toLowerCase
();
const
containsPathSeparator
=
value
.
indexOf
(
sep
)
>=
0
;
return
{
original
,
value
,
lowercase
,
containsPathSeparator
};
return
value
;
}
export
function
scoreItem
<
T
>
(
item
:
T
,
query
:
IPreparedQuery
,
fuzzy
:
boolean
,
accessor
:
IItemAccessor
<
T
>
,
cache
:
ScorerCache
):
IItemScore
{
...
...
@@ -404,7 +476,7 @@ function doScoreItem(label: string, description: string | undefined, path: strin
}
// 4.) prefer scores on the label if any
const
[
labelScore
,
labelPositions
]
=
score
(
label
,
query
.
value
,
query
.
lowercase
,
fuzzy
);
const
[
labelScore
,
labelPositions
]
=
score
(
label
,
query
,
fuzzy
);
if
(
labelScore
)
{
return
{
score
:
labelScore
+
LABEL_SCORE_THRESHOLD
,
labelMatch
:
createMatches
(
labelPositions
)
};
}
...
...
@@ -420,7 +492,7 @@ function doScoreItem(label: string, description: string | undefined, path: strin
const
descriptionPrefixLength
=
descriptionPrefix
.
length
;
const
descriptionAndLabel
=
`
${
descriptionPrefix
}${
label
}
`
;
const
[
labelDescriptionScore
,
labelDescriptionPositions
]
=
score
(
descriptionAndLabel
,
query
.
value
,
query
.
lowercase
,
fuzzy
);
const
[
labelDescriptionScore
,
labelDescriptionPositions
]
=
score
(
descriptionAndLabel
,
query
,
fuzzy
);
if
(
labelDescriptionScore
)
{
const
labelDescriptionMatches
=
createMatches
(
labelDescriptionPositions
);
const
labelMatch
:
IMatch
[]
=
[];
...
...
src/vs/base/test/common/fuzzyScorer.test.ts
浏览文件 @
c1c90f8e
...
...
@@ -43,7 +43,7 @@ class NullAccessorClass implements scorer.IItemAccessor<URI> {
}
function
_doScore
(
target
:
string
,
query
:
string
,
fuzzy
:
boolean
):
scorer
.
Score
{
return
scorer
.
score
(
target
,
query
,
query
.
toLowerCase
(
),
fuzzy
);
return
scorer
.
score
(
target
,
scorer
.
prepareQuery
(
query
),
fuzzy
);
}
function
scoreItem
<
T
>
(
item
:
T
,
query
:
string
,
fuzzy
:
boolean
,
accessor
:
scorer
.
IItemAccessor
<
T
>
,
cache
:
scorer
.
ScorerCache
):
scorer
.
IItemScore
{
...
...
@@ -109,6 +109,42 @@ suite('Fuzzy Scorer', () => {
assert
.
equal
(
_doScore
(
target
,
'
eo
'
,
false
)[
0
],
0
);
});
test
(
'
score (fuzzy, multiple)
'
,
function
()
{
const
target
=
'
HeLlo-World
'
;
const
[
firstSingleScore
,
firstSinglePositions
]
=
_doScore
(
target
,
'
HelLo
'
,
true
);
const
[
secondSingleScore
,
secondSinglePositions
]
=
_doScore
(
target
,
'
World
'
,
true
);
const
firstAndSecondSinglePositions
=
[...
firstSinglePositions
,
...
secondSinglePositions
];
let
[
multiScore
,
multiPositions
]
=
_doScore
(
target
,
'
HelLo World
'
,
true
);
function
assertScore
()
{
assert
.
ok
(
multiScore
>=
firstSingleScore
+
secondSingleScore
);
for
(
let
i
=
0
;
i
<
multiPositions
.
length
;
i
++
)
{
assert
.
equal
(
multiPositions
[
i
],
firstAndSecondSinglePositions
[
i
]);
}
}
function
assertNoScore
()
{
assert
.
equal
(
multiScore
,
0
);
assert
.
equal
(
multiPositions
.
length
,
0
);
}
assertScore
();
[
multiScore
,
multiPositions
]
=
_doScore
(
target
,
'
World HelLo
'
,
true
);
assertScore
();
[
multiScore
,
multiPositions
]
=
_doScore
(
target
,
'
World HelLo World
'
,
true
);
assertScore
();
[
multiScore
,
multiPositions
]
=
_doScore
(
target
,
'
World HelLo Nothing
'
,
true
);
assertNoScore
();
[
multiScore
,
multiPositions
]
=
_doScore
(
target
,
'
More Nothing
'
,
true
);
assertNoScore
();
});
test
(
'
scoreItem - matches are proper
'
,
function
()
{
let
res
=
scoreItem
(
null
,
'
something
'
,
true
,
ResourceAccessor
,
cache
);
assert
.
ok
(
!
res
.
score
);
...
...
@@ -820,11 +856,42 @@ suite('Fuzzy Scorer', () => {
assert
.
equal
(
res
[
0
],
resourceB
);
});
test
(
'
prepare
SearchForScoring
'
,
()
=>
{
test
(
'
prepare
Query
'
,
()
=>
{
assert
.
equal
(
scorer
.
prepareQuery
(
'
f*a
'
).
value
,
'
fa
'
);
assert
.
equal
(
scorer
.
prepareQuery
(
'
model Tester.ts
'
).
original
,
'
model Tester.ts
'
);
assert
.
equal
(
scorer
.
prepareQuery
(
'
model Tester.ts
'
).
originalLowercase
,
'
model Tester.ts
'
.
toLowerCase
());
assert
.
equal
(
scorer
.
prepareQuery
(
'
model Tester.ts
'
).
value
,
'
modelTester.ts
'
);
assert
.
equal
(
scorer
.
prepareQuery
(
'
Model Tester.ts
'
).
l
owercase
,
'
modeltester.ts
'
);
assert
.
equal
(
scorer
.
prepareQuery
(
'
Model Tester.ts
'
).
valueL
owercase
,
'
modeltester.ts
'
);
assert
.
equal
(
scorer
.
prepareQuery
(
'
ModelTester.ts
'
).
containsPathSeparator
,
false
);
assert
.
equal
(
scorer
.
prepareQuery
(
'
Model
'
+
sep
+
'
Tester.ts
'
).
containsPathSeparator
,
true
);
// with spaces
let
query
=
scorer
.
prepareQuery
(
'
He*llo World
'
);
assert
.
equal
(
query
.
original
,
'
He*llo World
'
);
assert
.
equal
(
query
.
value
,
'
HelloWorld
'
);
assert
.
equal
(
query
.
valueLowercase
,
'
HelloWorld
'
.
toLowerCase
());
assert
.
equal
(
query
.
values
?.
length
,
2
);
assert
.
equal
(
query
.
values
?.[
0
].
original
,
'
He*llo
'
);
assert
.
equal
(
query
.
values
?.[
0
].
value
,
'
Hello
'
);
assert
.
equal
(
query
.
values
?.[
0
].
valueLowercase
,
'
Hello
'
.
toLowerCase
());
assert
.
equal
(
query
.
values
?.[
1
].
original
,
'
World
'
);
assert
.
equal
(
query
.
values
?.[
1
].
value
,
'
World
'
);
assert
.
equal
(
query
.
values
?.[
1
].
valueLowercase
,
'
World
'
.
toLowerCase
());
// with spaces that are empty
query
=
scorer
.
prepareQuery
(
'
Hello World
'
);
assert
.
equal
(
query
.
original
,
'
Hello World
'
);
assert
.
equal
(
query
.
originalLowercase
,
'
Hello World
'
.
toLowerCase
());
assert
.
equal
(
query
.
value
,
'
HelloWorld
'
);
assert
.
equal
(
query
.
valueLowercase
,
'
HelloWorld
'
.
toLowerCase
());
assert
.
equal
(
query
.
values
?.
length
,
2
);
assert
.
equal
(
query
.
values
?.[
0
].
original
,
'
Hello
'
);
assert
.
equal
(
query
.
values
?.[
0
].
originalLowercase
,
'
Hello
'
.
toLowerCase
());
assert
.
equal
(
query
.
values
?.[
0
].
value
,
'
Hello
'
);
assert
.
equal
(
query
.
values
?.[
0
].
valueLowercase
,
'
Hello
'
.
toLowerCase
());
assert
.
equal
(
query
.
values
?.[
1
].
original
,
'
World
'
);
assert
.
equal
(
query
.
values
?.[
1
].
originalLowercase
,
'
World
'
.
toLowerCase
());
assert
.
equal
(
query
.
values
?.[
1
].
value
,
'
World
'
);
assert
.
equal
(
query
.
values
?.[
1
].
valueLowercase
,
'
World
'
.
toLowerCase
());
});
});
src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts
浏览文件 @
c1c90f8e
...
...
@@ -17,6 +17,7 @@ import { values } from 'vs/base/common/collections';
import
{
trim
,
format
}
from
'
vs/base/common/strings
'
;
import
{
fuzzyScore
,
FuzzyScore
,
createMatches
}
from
'
vs/base/common/filters
'
;
import
{
assign
}
from
'
vs/base/common/objects
'
;
import
{
prepareQuery
,
IPreparedQuery
}
from
'
vs/base/common/fuzzyScorer
'
;
export
interface
IGotoSymbolQuickPickItem
extends
IQuickPickItem
{
kind
:
SymbolKind
,
...
...
@@ -155,7 +156,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
// Collect symbol picks
picker
.
busy
=
true
;
try
{
const
items
=
await
this
.
doGetSymbolPicks
(
symbolsPromise
,
p
icker
.
value
.
substr
(
AbstractGotoSymbolQuickAccessProvider
.
PREFIX
.
length
).
trim
(
),
picksCts
.
token
);
const
items
=
await
this
.
doGetSymbolPicks
(
symbolsPromise
,
p
repareQuery
(
picker
.
value
.
substr
(
AbstractGotoSymbolQuickAccessProvider
.
PREFIX
.
length
).
trim
()
),
picksCts
.
token
);
if
(
token
.
isCancellationRequested
)
{
return
;
}
...
...
@@ -194,18 +195,24 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
return
disposables
;
}
protected
async
doGetSymbolPicks
(
symbolsPromise
:
Promise
<
DocumentSymbol
[]
>
,
filter
:
string
,
token
:
CancellationToken
):
Promise
<
Array
<
IGotoSymbolQuickPickItem
|
IQuickPickSeparator
>>
{
protected
async
doGetSymbolPicks
(
symbolsPromise
:
Promise
<
DocumentSymbol
[]
>
,
query
:
IPreparedQuery
,
token
:
CancellationToken
):
Promise
<
Array
<
IGotoSymbolQuickPickItem
|
IQuickPickSeparator
>>
{
const
symbols
=
await
symbolsPromise
;
if
(
token
.
isCancellationRequested
)
{
return
[];
}
// Normalize filter
const
filterBySymbolKind
=
filter
.
indexOf
(
AbstractGotoSymbolQuickAccessProvider
.
SCOPE_PREFIX
)
===
0
;
const
filterBySymbolKind
=
query
.
original
.
indexOf
(
AbstractGotoSymbolQuickAccessProvider
.
SCOPE_PREFIX
)
===
0
;
const
filterPos
=
filterBySymbolKind
?
1
:
0
;
const
[
symbolFilter
,
containerFilter
]
=
filter
.
split
(
'
'
)
as
[
string
,
string
|
undefined
];
const
symbolFilterLow
=
symbolFilter
.
toLowerCase
();
const
containerFilterLow
=
containerFilter
?.
toLowerCase
();
// Split between symbol and container query if separated by space
let
symbolQuery
:
IPreparedQuery
;
let
containerQuery
:
IPreparedQuery
|
undefined
;
if
(
query
.
values
&&
query
.
values
.
length
>
1
)
{
symbolQuery
=
prepareQuery
(
query
.
values
[
0
].
original
);
containerQuery
=
prepareQuery
(
query
.
values
[
1
].
original
);
}
else
{
symbolQuery
=
query
;
}
// Convert to symbol picks and apply filtering
const
filteredSymbolPicks
:
IGotoSymbolQuickPickItem
[]
=
[];
...
...
@@ -219,16 +226,16 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
let
containerScore
:
FuzzyScore
|
undefined
=
undefined
;
let
includeSymbol
=
true
;
if
(
filter
.
length
>
filterPos
)
{
if
(
query
.
original
.
length
>
filterPos
)
{
// Score by symbol
symbolScore
=
fuzzyScore
(
symbol
Filter
,
symbolFilterLow
,
filterPos
,
symbolLabel
,
symbolLabel
.
toLowerCase
(),
0
,
true
);
symbolScore
=
fuzzyScore
(
symbol
Query
.
original
,
symbolQuery
.
originalLowercase
,
filterPos
,
symbolLabel
,
symbolLabel
.
toLowerCase
(),
0
,
true
);
includeSymbol
=
!!
symbolScore
;
// Score by container if specified
if
(
includeSymbol
&&
container
Filter
&&
containerFilterLow
)
{
if
(
includeSymbol
&&
container
Query
)
{
if
(
containerLabel
)
{
containerScore
=
fuzzyScore
(
container
Filter
,
containerFilterLow
,
filterPos
,
containerLabel
,
containerLabel
.
toLowerCase
(),
0
,
true
);
containerScore
=
fuzzyScore
(
container
Query
.
original
,
containerQuery
.
originalLowercase
,
filterPos
,
containerLabel
,
containerLabel
.
toLowerCase
(),
0
,
true
);
}
includeSymbol
=
!!
containerScore
;
...
...
src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts
浏览文件 @
c1c90f8e
...
...
@@ -21,6 +21,7 @@ import { Action } from 'vs/base/common/actions';
import
{
IWorkbenchActionRegistry
,
Extensions
as
ActionExtensions
}
from
'
vs/workbench/common/actions
'
;
import
{
SyncActionDescriptor
}
from
'
vs/platform/actions/common/actions
'
;
import
{
KeyMod
,
KeyCode
}
from
'
vs/base/common/keyCodes
'
;
import
{
prepareQuery
}
from
'
vs/base/common/fuzzyScorer
'
;
export
class
GotoSymbolQuickAccessProvider
extends
AbstractGotoSymbolQuickAccessProvider
{
...
...
@@ -85,7 +86,7 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess
return
[];
}
return
this
.
doGetSymbolPicks
(
this
.
getDocumentSymbols
(
model
,
true
,
token
),
filter
,
token
);
return
this
.
doGetSymbolPicks
(
this
.
getDocumentSymbols
(
model
,
true
,
token
),
prepareQuery
(
filter
)
,
token
);
}
addDecorations
(
editor
:
IEditor
,
range
:
IRange
):
void
{
...
...
src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts
浏览文件 @
c1c90f8e
...
...
@@ -357,28 +357,30 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return
[];
}
//
Sort top 512 items by score
//
Perform sorting (top results by score)
const
sortedAnythingPicks
=
top
(
[...
filePicks
,
...
symbolPicks
],
(
anyPickA
,
anyPickB
)
=>
compareItemsByScore
(
anyPickA
,
anyPickB
,
query
,
true
,
quickPickItemScorerAccessor
,
this
.
pickState
.
scorerCache
),
AnythingQuickAccessProvider
.
MAX_RESULTS
);
// Adjust highlights
// Perform filtering
const
filteredAnythingPicks
:
IAnythingQuickPickItem
[]
=
[];
for
(
const
anythingPick
of
sortedAnythingPicks
)
{
if
(
anythingPick
.
highlights
)
{
continue
;
// preserve any highlights we got already (e.g. symbols)
const
{
score
,
labelMatch
,
descriptionMatch
}
=
scoreItem
(
anythingPick
,
query
,
true
,
quickPickItemScorerAccessor
,
this
.
pickState
.
scorerCache
);
if
(
!
score
)
{
continue
;
// exclude files/symbols not matching query
}
const
{
labelMatch
,
descriptionMatch
}
=
scoreItem
(
anythingPick
,
query
,
true
,
quickPickItemScorerAccessor
,
this
.
pickState
.
scorerCache
);
anythingPick
.
highlights
=
{
label
:
labelMatch
,
description
:
descriptionMatch
};
filteredAnythingPicks
.
push
(
anythingPick
);
}
return
sort
edAnythingPicks
;
return
filter
edAnythingPicks
;
}
...
...
@@ -398,10 +400,8 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return
[];
// disabled when searching
}
// Only match on label of the editor unless the search includes path separators
const
editorHistoryScorerAccessor
=
query
.
containsPathSeparator
?
quickPickItemScorerAccessor
:
this
.
labelOnlyEditorHistoryPickAccessor
;
// Otherwise filter and sort by query
// Perform filtering
const
editorHistoryScorerAccessor
=
query
.
containsPathSeparator
?
quickPickItemScorerAccessor
:
this
.
labelOnlyEditorHistoryPickAccessor
;
// Only match on label of the editor unless the search includes path separators
const
editorHistoryPicks
:
Array
<
IAnythingQuickPickItem
>
=
[];
for
(
const
editor
of
this
.
historyService
.
getHistory
())
{
const
resource
=
editor
.
resource
;
...
...
@@ -429,6 +429,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return
editorHistoryPicks
;
}
// Perform sorting
return
editorHistoryPicks
.
sort
((
editorA
,
editorB
)
=>
compareItemsByScore
(
editorA
,
editorB
,
query
,
false
,
editorHistoryScorerAccessor
,
this
.
pickState
.
scorerCache
));
}
...
...
@@ -501,7 +502,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
this
.
fileQueryBuilder
.
file
(
this
.
contextService
.
getWorkspace
().
folders
,
this
.
getFileQueryOptions
({
filePattern
:
query
.
original
,
query
,
cacheKey
:
this
.
pickState
.
fileQueryCache
?.
cacheKey
,
maxResults
:
AnythingQuickAccessProvider
.
MAX_RESULTS
})
...
...
@@ -536,17 +537,32 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
];
}
private
getFileQueryOptions
(
input
:
{
filePattern
?:
string
,
cacheKey
?:
string
,
maxResults
?:
number
}):
IFileQueryBuilderOptions
{
const
fileQueryOptions
:
IFileQueryBuilderOptions
=
{
private
getFileQueryOptions
(
input
:
{
query
?:
IPreparedQuery
,
cacheKey
?:
string
,
maxResults
?:
number
}):
IFileQueryBuilderOptions
{
// filePattern for search depends on the number of queries in input:
// - with multiple: only take the first one and let the filter later drop non-matching results
// - with single: just take the original in full
//
// This enables to e.g. search for "someFile someFolder" by only returning
// search results for "someFile" and not both that would normally not match.
//
let
filePattern
=
''
;
if
(
input
.
query
)
{
if
(
input
.
query
.
values
&&
input
.
query
.
values
.
length
>
1
)
{
filePattern
=
input
.
query
.
values
[
0
].
original
;
}
else
{
filePattern
=
input
.
query
.
original
;
}
}
return
{
_reason
:
'
openFileHandler
'
,
// used for telemetry - do not change
extraFileResources
:
this
.
instantiationService
.
invokeFunction
(
getOutOfWorkspaceEditorResources
),
filePattern
:
input
.
filePattern
||
''
,
filePattern
,
cacheKey
:
input
.
cacheKey
,
maxResults
:
input
.
maxResults
||
0
,
sortByScore
:
true
};
return
fileQueryOptions
;
}
private
async
getAbsolutePathFileResult
(
query
:
IPreparedQuery
,
token
:
CancellationToken
):
Promise
<
URI
|
undefined
>
{
...
...
@@ -638,11 +654,25 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return
[];
}
// symbolPattern for search depends on the number of queries in input:
// - with multiple: only take the first one and let the filter later drop non-matching results
// - with single: just take the original in full
//
// This enables to e.g. search for "someFile someFolder" by only returning
// symbol results for "someFile" and not both that would normally not match.
//
let
symbolPattern
=
''
;
if
(
query
.
values
&&
query
.
values
.
length
>
1
)
{
symbolPattern
=
query
.
values
[
0
].
original
;
}
else
{
symbolPattern
=
query
.
original
;
}
// Delegate to the existing symbols quick access
// but skip local results and also do not s
ort
return
this
.
workspaceSymbolsQuickAccess
.
getSymbolPicks
(
query
.
value
,
{
// but skip local results and also do not s
core
return
this
.
workspaceSymbolsQuickAccess
.
getSymbolPicks
(
symbolPattern
,
{
skipLocal
:
true
,
skipS
ort
ing
:
true
,
skipS
cor
ing
:
true
,
delay
:
AnythingQuickAccessProvider
.
TYPING_SEARCH_DELAY
},
token
);
}
...
...
src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts
浏览文件 @
c1c90f8e
...
...
@@ -6,7 +6,6 @@
import
{
localize
}
from
'
vs/nls
'
;
import
{
IPickerQuickAccessItem
,
PickerQuickAccessProvider
,
TriggerAction
}
from
'
vs/platform/quickinput/browser/pickerQuickAccess
'
;
import
{
fuzzyScore
,
createMatches
,
FuzzyScore
}
from
'
vs/base/common/filters
'
;
import
{
stripWildcards
}
from
'
vs/base/common/strings
'
;
import
{
CancellationToken
}
from
'
vs/base/common/cancellation
'
;
import
{
DisposableStore
}
from
'
vs/base/common/lifecycle
'
;
import
{
ThrottledDelayer
}
from
'
vs/base/common/async
'
;
...
...
@@ -27,6 +26,7 @@ import { URI } from 'vs/base/common/uri';
import
{
ICodeEditorService
}
from
'
vs/editor/browser/services/codeEditorService
'
;
import
{
getSelectionSearchString
}
from
'
vs/editor/contrib/find/findController
'
;
import
{
withNullAsUndefined
}
from
'
vs/base/common/types
'
;
import
{
prepareQuery
,
IPreparedQuery
}
from
'
vs/base/common/fuzzyScorer
'
;
interface
ISymbolQuickPickItem
extends
IPickerQuickAccessItem
{
resource
:
URI
|
undefined
;
...
...
@@ -89,28 +89,33 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
return
this
.
getSymbolPicks
(
filter
,
undefined
,
token
);
}
async
getSymbolPicks
(
filter
:
string
,
options
:
{
skipLocal
?:
boolean
,
skipS
ort
ing
?:
boolean
,
delay
?:
number
}
|
undefined
,
token
:
CancellationToken
):
Promise
<
Array
<
ISymbolQuickPickItem
>>
{
async
getSymbolPicks
(
filter
:
string
,
options
:
{
skipLocal
?:
boolean
,
skipS
cor
ing
?:
boolean
,
delay
?:
number
}
|
undefined
,
token
:
CancellationToken
):
Promise
<
Array
<
ISymbolQuickPickItem
>>
{
return
this
.
delayer
.
trigger
(
async
()
=>
{
if
(
token
.
isCancellationRequested
)
{
return
[];
}
return
this
.
doGetSymbolPicks
(
filter
,
options
,
token
);
return
this
.
doGetSymbolPicks
(
prepareQuery
(
filter
)
,
options
,
token
);
},
options
?.
delay
);
}
private
async
doGetSymbolPicks
(
filter
:
string
,
options
:
{
skipLocal
?:
boolean
,
skipSort
ing
?:
boolean
}
|
undefined
,
token
:
CancellationToken
):
Promise
<
Array
<
ISymbolQuickPickItem
>>
{
const
workspaceSymbols
=
await
getWorkspaceSymbols
(
filter
,
token
);
private
async
doGetSymbolPicks
(
query
:
IPreparedQuery
,
options
:
{
skipLocal
?:
boolean
,
skipScor
ing
?:
boolean
}
|
undefined
,
token
:
CancellationToken
):
Promise
<
Array
<
ISymbolQuickPickItem
>>
{
const
workspaceSymbols
=
await
getWorkspaceSymbols
(
query
.
original
,
token
);
if
(
token
.
isCancellationRequested
)
{
return
[];
}
const
symbolPicks
:
Array
<
ISymbolQuickPickItem
>
=
[];
// Normalize filter
const
[
symbolFilter
,
containerFilter
]
=
stripWildcards
(
filter
).
split
(
'
'
)
as
[
string
,
string
|
undefined
];
const
symbolFilterLow
=
symbolFilter
.
toLowerCase
();
const
containerFilterLow
=
containerFilter
?.
toLowerCase
();
// Split between symbol and container query
let
symbolQuery
:
IPreparedQuery
;
let
containerQuery
:
IPreparedQuery
|
undefined
;
if
(
query
.
values
&&
query
.
values
.
length
>
1
)
{
symbolQuery
=
prepareQuery
(
query
.
values
[
0
].
original
);
containerQuery
=
prepareQuery
(
query
.
values
[
1
].
original
);
}
else
{
symbolQuery
=
query
;
}
// Convert to symbol picks and apply filtering
const
openSideBySideDirection
=
this
.
configuration
.
openSideBySideDirection
;
...
...
@@ -125,9 +130,9 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
continue
;
}
// Score by symbol label
// Score by symbol label
(unless disabled)
const
symbolLabel
=
symbol
.
name
;
const
symbolScore
=
fuzzyScore
(
symbolFilter
,
symbolFilterLow
,
0
,
symbolLabel
,
symbolLabel
.
toLowerCase
(),
0
,
true
);
const
symbolScore
=
options
?.
skipScoring
?
FuzzyScore
.
Default
:
fuzzyScore
(
symbolQuery
.
original
,
symbolQuery
.
originalLowercase
,
0
,
symbolLabel
,
symbolLabel
.
toLowerCase
(),
0
,
true
);
if
(
!
symbolScore
)
{
continue
;
}
...
...
@@ -143,11 +148,13 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
}
}
// Score by container if specified
// Score by container if specified
(unless disabled)
let
containerScore
:
FuzzyScore
|
undefined
=
undefined
;
if
(
containerFilter
&&
containerFilterLow
)
{
if
(
options
?.
skipScoring
)
{
containerScore
=
FuzzyScore
.
Default
;
}
else
if
(
containerQuery
)
{
if
(
containerLabel
)
{
containerScore
=
fuzzyScore
(
container
Filter
,
containerFilterLow
,
0
,
containerLabel
,
containerLabel
.
toLowerCase
(),
0
,
true
);
containerScore
=
fuzzyScore
(
container
Query
.
original
,
containerQuery
.
originalLowercase
,
0
,
containerLabel
,
containerLabel
.
toLowerCase
(),
0
,
true
);
}
if
(
!
containerScore
)
{
...
...
@@ -177,7 +184,7 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
score
:
symbolScore
,
label
:
symbolLabelWithIcon
,
ariaLabel
:
localize
(
'
symbolAriaLabel
'
,
"
{0}, symbols picker
"
,
symbolLabel
),
highlights
:
deprecated
?
undefined
:
{
highlights
:
(
deprecated
||
options
?.
skipScoring
)
?
undefined
:
{
label
:
createMatches
(
symbolScore
,
symbolLabelWithIcon
.
length
-
symbolLabel
.
length
/* Readjust matches to account for codicons in label */
),
description
:
createMatches
(
containerScore
)
},
...
...
@@ -200,7 +207,7 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
}
// Sort picks (unless disabled)
if
(
!
options
?.
skipS
ort
ing
)
{
if
(
!
options
?.
skipS
cor
ing
)
{
symbolPicks
.
sort
((
symbolA
,
symbolB
)
=>
this
.
compareSymbols
(
symbolA
,
symbolB
));
}
...
...
src/vs/workbench/services/search/node/fileSearch.ts
浏览文件 @
c1c90f8e
...
...
@@ -77,7 +77,7 @@ export class FileWalker {
this
.
errors
=
[];
if
(
this
.
filePattern
)
{
this
.
normalizedFilePatternLowercase
=
prepareQuery
(
this
.
filePattern
).
l
owercase
;
this
.
normalizedFilePatternLowercase
=
prepareQuery
(
this
.
filePattern
).
valueL
owercase
;
}
this
.
globalExcludePattern
=
config
.
excludePattern
&&
glob
.
parse
(
config
.
excludePattern
);
...
...
src/vs/workbench/services/search/node/rawSearchService.ts
浏览文件 @
c1c90f8e
...
...
@@ -312,7 +312,7 @@ export class SearchService implements IRawSearchService {
// Pattern match on results
const
results
:
IRawFileMatch
[]
=
[];
const
normalizedSearchValueLowercase
=
prepareQuery
(
searchValue
).
l
owercase
;
const
normalizedSearchValueLowercase
=
prepareQuery
(
searchValue
).
valueL
owercase
;
for
(
const
entry
of
cachedEntries
)
{
// Check if this entry is a match for the search value
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录