Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
8bc931bd
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,发现更多精彩内容 >>
未验证
提交
8bc931bd
编写于
7月 09, 2018
作者:
J
João Moreno
提交者:
GitHub
7月 09, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #53536 from Microsoft/joao/search-progress-events
Use events instead of PPromise for search IPC
上级
61e0cf06
1030cf90
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
317 addition
and
202 deletion
+317
-202
src/vs/workbench/services/search/node/fileSearch.ts
src/vs/workbench/services/search/node/fileSearch.ts
+3
-2
src/vs/workbench/services/search/node/rawSearchService.ts
src/vs/workbench/services/search/node/rawSearchService.ts
+132
-97
src/vs/workbench/services/search/node/ripgrepTextSearch.ts
src/vs/workbench/services/search/node/ripgrepTextSearch.ts
+6
-2
src/vs/workbench/services/search/node/search.ts
src/vs/workbench/services/search/node/search.ts
+29
-6
src/vs/workbench/services/search/node/searchIpc.ts
src/vs/workbench/services/search/node/searchIpc.ts
+18
-18
src/vs/workbench/services/search/node/searchService.ts
src/vs/workbench/services/search/node/searchService.ts
+31
-7
src/vs/workbench/services/search/node/textSearch.ts
src/vs/workbench/services/search/node/textSearch.ts
+3
-2
src/vs/workbench/services/search/test/node/searchService.test.ts
...workbench/services/search/test/node/searchService.test.ts
+95
-68
未找到文件。
src/vs/workbench/services/search/node/fileSearch.ts
浏览文件 @
8bc931bd
...
...
@@ -25,7 +25,7 @@ import { IProgress, IUncachedSearchStats } from 'vs/platform/search/common/searc
import
*
as
extfs
from
'
vs/base/node/extfs
'
;
import
*
as
flow
from
'
vs/base/node/flow
'
;
import
{
IRawFileMatch
,
I
SerializedSearchComplete
,
IRawSearch
,
ISearchEngine
,
IFolderSearch
}
from
'
./search
'
;
import
{
IRawFileMatch
,
I
RawSearch
,
ISearchEngine
,
IFolderSearch
,
ISerializedSearchSuccess
}
from
'
./search
'
;
import
{
spawnRipgrepCmd
}
from
'
./ripgrepFileSearch
'
;
import
{
rgErrorMsgForDisplay
}
from
'
./ripgrepTextSearch
'
;
...
...
@@ -721,9 +721,10 @@ export class Engine implements ISearchEngine<IRawFileMatch> {
this
.
walker
=
new
FileWalker
(
config
);
}
public
search
(
onResult
:
(
result
:
IRawFileMatch
)
=>
void
,
onProgress
:
(
progress
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Complete
)
=>
void
):
void
{
public
search
(
onResult
:
(
result
:
IRawFileMatch
)
=>
void
,
onProgress
:
(
progress
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Success
)
=>
void
):
void
{
this
.
walker
.
walk
(
this
.
folderQueries
,
this
.
extraFiles
,
onResult
,
onProgress
,
(
err
:
Error
,
isLimitHit
:
boolean
)
=>
{
done
(
err
,
{
type
:
'
success
'
,
limitHit
:
isLimitHit
,
stats
:
this
.
walker
.
getStats
()
});
...
...
src/vs/workbench/services/search/node/rawSearchService.ts
浏览文件 @
8bc931bd
...
...
@@ -11,7 +11,7 @@ import { join, sep } from 'path';
import
*
as
arrays
from
'
vs/base/common/arrays
'
;
import
*
as
objects
from
'
vs/base/common/objects
'
;
import
*
as
strings
from
'
vs/base/common/strings
'
;
import
{
PPromise
,
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
compareItemsByScore
,
IItemAccessor
,
prepareQuery
,
ScorerCache
}
from
'
vs/base/parts/quickopen/common/quickOpenScorer
'
;
import
{
MAX_FILE_SIZE
}
from
'
vs/platform/files/node/files
'
;
import
{
ICachedSearchStats
,
IProgress
}
from
'
vs/platform/search/common/search
'
;
...
...
@@ -19,10 +19,14 @@ import { Engine as FileSearchEngine, FileWalker } from 'vs/workbench/services/se
import
{
RipgrepEngine
}
from
'
vs/workbench/services/search/node/ripgrepTextSearch
'
;
import
{
Engine
as
TextSearchEngine
}
from
'
vs/workbench/services/search/node/textSearch
'
;
import
{
TextSearchWorkerProvider
}
from
'
vs/workbench/services/search/node/textSearchWorkerProvider
'
;
import
{
IFileSearchProgressItem
,
IRawFileMatch
,
IRawSearch
,
IRawSearchService
,
ISearchEngine
,
ISerializedFileMatch
,
ISerializedSearchComplete
,
ISerializedSearchProgressItem
,
ITelemetryEvent
}
from
'
./search
'
;
import
{
IFileSearchProgressItem
,
IRawFileMatch
,
IRawSearch
,
IRawSearchService
,
ISearchEngine
,
ISerializedFileMatch
,
ISerializedSearchComplete
,
ISerializedSearchProgressItem
,
ITelemetryEvent
,
ISerializedSearchSuccess
}
from
'
./search
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
gracefulFs
.
gracefulify
(
fs
);
type
IProgressCallback
=
(
p
:
ISerializedSearchProgressItem
)
=>
void
;
type
IFileProgressCallback
=
(
p
:
IFileSearchProgressItem
)
=>
void
;
export
class
SearchService
implements
IRawSearchService
{
private
static
readonly
BATCH_SIZE
=
512
;
...
...
@@ -31,29 +35,52 @@ export class SearchService implements IRawSearchService {
private
textSearchWorkerProvider
:
TextSearchWorkerProvider
;
private
telemetryPipe
:
(
event
:
ITelemetryEvent
)
=>
void
;
private
_onTelemetry
=
new
Emitter
<
ITelemetryEvent
>
();
readonly
onTelemetry
:
Event
<
ITelemetryEvent
>
=
this
.
_onTelemetry
.
event
;
public
fileSearch
(
config
:
IRawSearch
,
batchSize
=
SearchService
.
BATCH_SIZE
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
{
let
promise
:
TPromise
<
ISerializedSearchSuccess
>
;
const
emitter
=
new
Emitter
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
({
onFirstListenerAdd
:
()
=>
{
promise
=
this
.
doFileSearch
(
FileSearchEngine
,
config
,
p
=>
emitter
.
fire
(
p
),
batchSize
)
.
then
(
c
=>
emitter
.
fire
(
c
),
err
=>
emitter
.
fire
({
type
:
'
error
'
,
error
:
err
}));
},
onLastListenerRemove
:
()
=>
{
promise
.
cancel
();
}
});
public
fileSearch
(
config
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
{
return
this
.
doFileSearch
(
FileSearchEngine
,
config
,
SearchService
.
BATCH_SIZE
);
return
emitter
.
event
;
}
public
textSearch
(
config
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
{
return
config
.
useRipgrep
?
this
.
ripgrepTextSearch
(
config
)
:
this
.
legacyTextSearch
(
config
);
public
textSearch
(
config
:
IRawSearch
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
{
let
promise
:
TPromise
<
ISerializedSearchSuccess
>
;
const
emitter
=
new
Emitter
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
({
onFirstListenerAdd
:
()
=>
{
promise
=
(
config
.
useRipgrep
?
this
.
ripgrepTextSearch
(
config
,
p
=>
emitter
.
fire
(
p
))
:
this
.
legacyTextSearch
(
config
,
p
=>
emitter
.
fire
(
p
)))
.
then
(
c
=>
emitter
.
fire
(
c
),
err
=>
emitter
.
fire
({
type
:
'
error
'
,
error
:
err
}));
},
onLastListenerRemove
:
()
=>
{
promise
.
cancel
();
}
});
return
emitter
.
event
;
}
p
ublic
ripgrepTextSearch
(
config
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
{
p
rivate
ripgrepTextSearch
(
config
:
IRawSearch
,
progressCallback
:
IProgressCallback
):
TPromise
<
ISerializedSearchSuccess
>
{
config
.
maxFilesize
=
MAX_FILE_SIZE
;
let
engine
=
new
RipgrepEngine
(
config
);
return
new
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
((
c
,
e
,
p
)
=>
{
return
new
TPromise
<
ISerializedSearchSuccess
>
((
c
,
e
)
=>
{
// Use BatchedCollector to get new results to the frontend every 2s at least, until 50 results have been returned
const
collector
=
new
BatchedCollector
<
ISerializedFileMatch
>
(
SearchService
.
BATCH_SIZE
,
p
);
const
collector
=
new
BatchedCollector
<
ISerializedFileMatch
>
(
SearchService
.
BATCH_SIZE
,
p
rogressCallback
);
engine
.
search
((
match
)
=>
{
collector
.
addItem
(
match
,
match
.
numMatches
);
},
(
message
)
=>
{
p
(
message
);
p
rogressCallback
(
message
);
},
(
error
,
stats
)
=>
{
collector
.
flush
();
...
...
@@ -68,7 +95,7 @@ export class SearchService implements IRawSearchService {
});
}
p
ublic
legacyTextSearch
(
config
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
{
p
rivate
legacyTextSearch
(
config
:
IRawSearch
,
progressCallback
:
IProgressCallback
):
TPromise
<
ISerializedSearchComplete
>
{
if
(
!
this
.
textSearchWorkerProvider
)
{
this
.
textSearchWorkerProvider
=
new
TextSearchWorkerProvider
();
}
...
...
@@ -86,75 +113,75 @@ export class SearchService implements IRawSearchService {
}),
this
.
textSearchWorkerProvider
);
return
this
.
doTextSearch
(
engine
,
SearchService
.
BATCH_SIZE
);
return
this
.
doTextSearch
(
engine
,
progressCallback
,
SearchService
.
BATCH_SIZE
);
}
public
doFileSearch
(
EngineClass
:
{
new
(
config
:
IRawSearch
):
ISearchEngine
<
IRawFileMatch
>
;
},
config
:
IRawSearch
,
batchSize
?:
number
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
{
doFileSearch
(
EngineClass
:
{
new
(
config
:
IRawSearch
):
ISearchEngine
<
IRawFileMatch
>
;
},
config
:
IRawSearch
,
progressCallback
:
IProgressCallback
,
batchSize
?:
number
):
TPromise
<
ISerializedSearchSuccess
>
{
const
fileProgressCallback
:
IFileProgressCallback
=
progress
=>
{
if
(
Array
.
isArray
(
progress
))
{
progressCallback
(
progress
.
map
(
m
=>
this
.
rawMatchToSearchItem
(
m
)));
}
else
if
((
<
IRawFileMatch
>
progress
).
relativePath
)
{
progressCallback
(
this
.
rawMatchToSearchItem
(
<
IRawFileMatch
>
progress
));
}
else
{
progressCallback
(
<
IProgress
>
progress
);
}
};
if
(
config
.
sortByScore
)
{
let
sortedSearch
=
this
.
trySortedSearchFromCache
(
config
);
let
sortedSearch
=
this
.
trySortedSearchFromCache
(
config
,
fileProgressCallback
);
if
(
!
sortedSearch
)
{
const
walkerConfig
=
config
.
maxResults
?
objects
.
assign
({},
config
,
{
maxResults
:
null
})
:
config
;
const
engine
=
new
EngineClass
(
walkerConfig
);
sortedSearch
=
this
.
doSortedSearch
(
engine
,
config
);
sortedSearch
=
this
.
doSortedSearch
(
engine
,
config
,
progressCallback
,
fileProgressCallback
);
}
return
new
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
((
c
,
e
,
p
)
=>
{
return
new
TPromise
<
ISerializedSearchSuccess
>
((
c
,
e
)
=>
{
process
.
nextTick
(()
=>
{
// allow caller to register progress callback first
sortedSearch
.
then
(([
result
,
rawMatches
])
=>
{
const
serializedMatches
=
rawMatches
.
map
(
rawMatch
=>
this
.
rawMatchToSearchItem
(
rawMatch
));
this
.
sendProgress
(
serializedMatches
,
p
,
batchSize
);
this
.
sendProgress
(
serializedMatches
,
p
rogressCallback
,
batchSize
);
c
(
result
);
},
e
,
p
);
},
e
);
});
},
()
=>
{
sortedSearch
.
cancel
();
});
}
let
searchPromise
:
PPromise
<
void
,
IFileSearchProgressItem
>
;
return
new
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
((
c
,
e
,
p
)
=>
{
const
engine
=
new
EngineClass
(
config
);
searchPromise
=
this
.
doSearch
(
engine
,
batchSize
)
.
then
(
c
,
e
,
progress
=>
{
if
(
Array
.
isArray
(
progress
))
{
p
(
progress
.
map
(
m
=>
this
.
rawMatchToSearchItem
(
m
)));
}
else
if
((
<
IRawFileMatch
>
progress
).
relativePath
)
{
p
(
this
.
rawMatchToSearchItem
(
<
IRawFileMatch
>
progress
));
}
else
{
p
(
<
IProgress
>
progress
);
}
});
},
()
=>
{
searchPromise
.
cancel
();
});
const
engine
=
new
EngineClass
(
config
);
return
this
.
doSearch
(
engine
,
fileProgressCallback
,
batchSize
);
}
private
rawMatchToSearchItem
(
match
:
IRawFileMatch
):
ISerializedFileMatch
{
return
{
path
:
match
.
base
?
join
(
match
.
base
,
match
.
relativePath
)
:
match
.
relativePath
};
}
private
doSortedSearch
(
engine
:
ISearchEngine
<
IRawFileMatch
>
,
config
:
IRawSearch
):
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[]],
IProgress
>
{
let
searchPromise
:
PPromise
<
void
,
IFileSearchProgressItem
>
;
let
allResultsPromise
=
new
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[]],
IFileSearchProgressItem
>
((
c
,
e
,
p
)
=>
{
private
doSortedSearch
(
engine
:
ISearchEngine
<
IRawFileMatch
>
,
config
:
IRawSearch
,
progressCallback
:
IProgressCallback
,
fileProgressCallback
:
IFileProgressCallback
):
TPromise
<
[
ISerializedSearchSuccess
,
IRawFileMatch
[]]
>
{
let
searchPromise
:
TPromise
<
void
>
;
const
emitter
=
new
Emitter
<
IFileSearchProgressItem
>
();
let
allResultsPromise
=
new
TPromise
<
[
ISerializedSearchSuccess
,
IRawFileMatch
[]]
>
((
c
,
e
)
=>
{
let
results
:
IRawFileMatch
[]
=
[];
searchPromise
=
this
.
doSearch
(
engine
,
-
1
)
const
innerProgressCallback
:
IFileProgressCallback
=
progress
=>
{
if
(
Array
.
isArray
(
progress
))
{
results
=
progress
;
}
else
{
fileProgressCallback
(
progress
);
emitter
.
fire
(
progress
);
}
};
searchPromise
=
this
.
doSearch
(
engine
,
innerProgressCallback
,
-
1
)
.
then
(
result
=>
{
c
([
result
,
results
]);
if
(
this
.
telemetryPipe
)
{
// __GDPR__TODO__ classify event
this
.
telemetryPipe
({
eventName
:
'
fileSearch
'
,
data
:
result
.
stats
});
}
},
e
,
progress
=>
{
if
(
Array
.
isArray
(
progress
))
{
results
=
progress
;
}
else
{
p
(
progress
);
}
});
// __GDPR__TODO__ classify event
this
.
_onTelemetry
.
fire
({
eventName
:
'
fileSearch
'
,
data
:
result
.
stats
});
},
e
);
},
()
=>
{
searchPromise
.
cancel
();
});
...
...
@@ -162,7 +189,10 @@ export class SearchService implements IRawSearchService {
let
cache
:
Cache
;
if
(
config
.
cacheKey
)
{
cache
=
this
.
getOrCreateCache
(
config
.
cacheKey
);
cache
.
resultsToSearchCache
[
config
.
filePattern
]
=
allResultsPromise
;
cache
.
resultsToSearchCache
[
config
.
filePattern
]
=
{
promise
:
allResultsPromise
,
event
:
emitter
.
event
};
allResultsPromise
.
then
(
null
,
err
=>
{
delete
cache
.
resultsToSearchCache
[
config
.
filePattern
];
});
...
...
@@ -170,7 +200,7 @@ export class SearchService implements IRawSearchService {
}
let
chained
:
TPromise
<
void
>
;
return
new
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[]],
IProgress
>
((
c
,
e
,
p
)
=>
{
return
new
TPromise
<
[
ISerializedSearchSuccess
,
IRawFileMatch
[]]
>
((
c
,
e
)
=>
{
chained
=
allResultsPromise
.
then
(([
result
,
results
])
=>
{
const
scorerCache
:
ScorerCache
=
cache
?
cache
.
scorerCache
:
Object
.
create
(
null
);
const
unsortedResultTime
=
Date
.
now
();
...
...
@@ -179,14 +209,15 @@ export class SearchService implements IRawSearchService {
const
sortedResultTime
=
Date
.
now
();
c
([{
type
:
'
success
'
,
stats
:
objects
.
assign
({},
result
.
stats
,
{
unsortedResultTime
,
sortedResultTime
}),
limitHit
:
result
.
limitHit
||
typeof
config
.
maxResults
===
'
number
'
&&
results
.
length
>
config
.
maxResults
},
sortedResults
]);
}
as
ISerializedSearchSuccess
,
sortedResults
]);
});
},
e
,
p
);
},
e
);
},
()
=>
{
chained
.
cancel
();
});
...
...
@@ -200,17 +231,17 @@ export class SearchService implements IRawSearchService {
return
this
.
caches
[
cacheKey
]
=
new
Cache
();
}
private
trySortedSearchFromCache
(
config
:
IRawSearch
):
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[]],
IProgress
>
{
private
trySortedSearchFromCache
(
config
:
IRawSearch
,
progressCallback
:
IFileProgressCallback
):
TPromise
<
[
ISerializedSearchSuccess
,
IRawFileMatch
[]]
>
{
const
cache
=
config
.
cacheKey
&&
this
.
caches
[
config
.
cacheKey
];
if
(
!
cache
)
{
return
undefined
;
}
const
cacheLookupStartTime
=
Date
.
now
();
const
cached
=
this
.
getResultsFromCache
(
cache
,
config
.
filePattern
);
const
cached
=
this
.
getResultsFromCache
(
cache
,
config
.
filePattern
,
progressCallback
);
if
(
cached
)
{
let
chained
:
TPromise
<
void
>
;
return
new
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[]],
IProgress
>
((
c
,
e
,
p
)
=>
{
return
new
TPromise
<
[
ISerializedSearchSuccess
,
IRawFileMatch
[]]
>
((
c
,
e
)
=>
{
chained
=
cached
.
then
(([
result
,
results
,
cacheStats
])
=>
{
const
cacheLookupResultTime
=
Date
.
now
();
return
this
.
sortResults
(
config
,
results
,
cache
.
scorerCache
)
...
...
@@ -234,13 +265,14 @@ export class SearchService implements IRawSearchService {
}
c
([
{
type
:
'
success
'
,
limitHit
:
result
.
limitHit
||
typeof
config
.
maxResults
===
'
number
'
&&
results
.
length
>
config
.
maxResults
,
stats
:
stats
},
}
as
ISerializedSearchSuccess
,
sortedResults
]);
});
},
e
,
p
);
},
e
);
},
()
=>
{
chained
.
cancel
();
});
...
...
@@ -259,7 +291,7 @@ export class SearchService implements IRawSearchService {
return
arrays
.
topAsync
(
results
,
compare
,
config
.
maxResults
,
10000
);
}
private
sendProgress
(
results
:
ISerializedFileMatch
[],
progressCb
:
(
batch
:
ISerializedFileMatch
[])
=>
void
,
batchSize
:
number
)
{
private
sendProgress
(
results
:
ISerializedFileMatch
[],
progressCb
:
IProgressCallback
,
batchSize
:
number
)
{
if
(
batchSize
&&
batchSize
>
0
)
{
for
(
let
i
=
0
;
i
<
results
.
length
;
i
+=
batchSize
)
{
progressCb
(
results
.
slice
(
i
,
i
+
batchSize
));
...
...
@@ -269,10 +301,10 @@ export class SearchService implements IRawSearchService {
}
}
private
getResultsFromCache
(
cache
:
Cache
,
searchValue
:
string
):
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[],
CacheStats
],
IProgress
>
{
private
getResultsFromCache
(
cache
:
Cache
,
searchValue
:
string
,
progressCallback
:
IFileProgressCallback
):
TPromise
<
[
ISerializedSearchSuccess
,
IRawFileMatch
[],
CacheStats
]
>
{
// Find cache entries by prefix of search value
const
hasPathSep
=
searchValue
.
indexOf
(
sep
)
>=
0
;
let
cached
:
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[]],
IFileSearchProgressItem
>
;
let
cached
Row
:
CacheRow
;
let
wasResolved
:
boolean
;
for
(
let
previousSearch
in
cache
.
resultsToSearchCache
)
{
...
...
@@ -282,20 +314,25 @@ export class SearchService implements IRawSearchService {
continue
;
// since a path character widens the search for potential more matches, require it in previous search too
}
const
c
=
cache
.
resultsToSearchCache
[
previousSearch
];
c
.
then
(()
=>
{
wasResolved
=
false
;
});
const
row
=
cache
.
resultsToSearchCache
[
previousSearch
];
row
.
promise
.
then
(()
=>
{
wasResolved
=
false
;
});
wasResolved
=
true
;
cached
=
this
.
preventCancellation
(
c
);
cachedRow
=
{
promise
:
this
.
preventCancellation
(
row
.
promise
),
event
:
row
.
event
};
break
;
}
}
if
(
!
cached
)
{
if
(
!
cached
Row
)
{
return
null
;
}
return
new
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[],
CacheStats
],
IProgress
>
((
c
,
e
,
p
)
=>
{
cached
.
then
(([
complete
,
cachedEntries
])
=>
{
const
listener
=
cachedRow
.
event
(
progressCallback
);
return
new
TPromise
<
[
ISerializedSearchSuccess
,
IRawFileMatch
[],
CacheStats
]
>
((
c
,
e
)
=>
{
cachedRow
.
promise
.
then
(([
complete
,
cachedEntries
])
=>
{
const
cacheFilterStartTime
=
Date
.
now
();
// Pattern match on results
...
...
@@ -317,21 +354,22 @@ export class SearchService implements IRawSearchService {
cacheFilterStartTime
:
cacheFilterStartTime
,
cacheFilterResultCount
:
cachedEntries
.
length
}]);
},
e
,
p
);
},
e
);
},
()
=>
{
cached
.
cancel
();
cachedRow
.
promise
.
cancel
();
listener
.
dispose
();
});
}
private
doTextSearch
(
engine
:
TextSearchEngine
,
batchSize
:
number
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
{
return
new
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
((
c
,
e
,
p
)
=>
{
private
doTextSearch
(
engine
:
TextSearchEngine
,
progressCallback
:
IProgressCallback
,
batchSize
:
number
):
TPromise
<
ISerializedSearchSuccess
>
{
return
new
TPromise
<
ISerializedSearchSuccess
>
((
c
,
e
)
=>
{
// Use BatchedCollector to get new results to the frontend every 2s at least, until 50 results have been returned
const
collector
=
new
BatchedCollector
<
ISerializedFileMatch
>
(
batchSize
,
p
);
const
collector
=
new
BatchedCollector
<
ISerializedFileMatch
>
(
batchSize
,
p
rogressCallback
);
engine
.
search
((
matches
)
=>
{
const
totalMatches
=
matches
.
reduce
((
acc
,
m
)
=>
acc
+
m
.
numMatches
,
0
);
collector
.
addItems
(
matches
,
totalMatches
);
},
(
progress
)
=>
{
p
(
progress
);
p
rogressCallback
(
progress
);
},
(
error
,
stats
)
=>
{
collector
.
flush
();
...
...
@@ -346,28 +384,28 @@ export class SearchService implements IRawSearchService {
});
}
private
doSearch
(
engine
:
ISearchEngine
<
IRawFileMatch
>
,
batchSize
?:
number
):
PPromise
<
ISerializedSearchComplete
,
IFileSearchProgressItem
>
{
return
new
PPromise
<
ISerializedSearchComplete
,
IFileSearchProgressItem
>
((
c
,
e
,
p
)
=>
{
private
doSearch
(
engine
:
ISearchEngine
<
IRawFileMatch
>
,
progressCallback
:
IFileProgressCallback
,
batchSize
?:
number
):
TPromise
<
ISerializedSearchSuccess
>
{
return
new
TPromise
<
ISerializedSearchSuccess
>
((
c
,
e
)
=>
{
let
batch
:
IRawFileMatch
[]
=
[];
engine
.
search
((
match
)
=>
{
if
(
match
)
{
if
(
batchSize
)
{
batch
.
push
(
match
);
if
(
batchSize
>
0
&&
batch
.
length
>=
batchSize
)
{
p
(
batch
);
p
rogressCallback
(
batch
);
batch
=
[];
}
}
else
{
p
(
match
);
p
rogressCallback
(
match
);
}
}
},
(
progress
)
=>
{
process
.
nextTick
(()
=>
{
p
(
progress
);
p
rogressCallback
(
progress
);
});
},
(
error
,
stats
)
=>
{
if
(
batch
.
length
)
{
p
(
batch
);
p
rogressCallback
(
batch
);
}
if
(
error
)
{
e
(
error
);
...
...
@@ -385,19 +423,11 @@ export class SearchService implements IRawSearchService {
return
TPromise
.
as
(
undefined
);
}
public
fetchTelemetry
():
PPromise
<
void
,
ITelemetryEvent
>
{
return
new
PPromise
((
c
,
e
,
p
)
=>
{
this
.
telemetryPipe
=
p
;
},
()
=>
{
this
.
telemetryPipe
=
null
;
});
}
private
preventCancellation
<
C
,
P
>
(
promise
:
PPromise
<
C
,
P
>
):
PPromise
<
C
,
P
>
{
return
new
PPromise
<
C
,
P
>
((
c
,
e
,
p
)
=>
{
private
preventCancellation
<
C
,
P
>
(
promise
:
TPromise
<
C
>
):
TPromise
<
C
>
{
return
new
TPromise
<
C
>
((
c
,
e
)
=>
{
// Allow for piled up cancellations to come through first.
process
.
nextTick
(()
=>
{
promise
.
then
(
c
,
e
,
p
);
promise
.
then
(
c
,
e
);
});
},
()
=>
{
// Do not propagate.
...
...
@@ -405,9 +435,14 @@ export class SearchService implements IRawSearchService {
}
}
interface
CacheRow
{
promise
:
TPromise
<
[
ISerializedSearchSuccess
,
IRawFileMatch
[]]
>
;
event
:
Event
<
IFileSearchProgressItem
>
;
}
class
Cache
{
public
resultsToSearchCache
:
{
[
searchValue
:
string
]:
PPromise
<
[
ISerializedSearchComplete
,
IRawFileMatch
[]],
IFileSearchProgressItem
>
;
}
=
Object
.
create
(
null
);
public
resultsToSearchCache
:
{
[
searchValue
:
string
]:
CacheRow
;
}
=
Object
.
create
(
null
);
public
scorerCache
:
ScorerCache
=
Object
.
create
(
null
);
}
...
...
src/vs/workbench/services/search/node/ripgrepTextSearch.ts
浏览文件 @
8bc931bd
...
...
@@ -18,7 +18,7 @@ import * as encoding from 'vs/base/node/encoding';
import
*
as
extfs
from
'
vs/base/node/extfs
'
;
import
{
IProgress
}
from
'
vs/platform/search/common/search
'
;
import
{
rgPath
}
from
'
vscode-ripgrep
'
;
import
{
FileMatch
,
IFolderSearch
,
IRawSearch
,
ISerializedFileMatch
,
ISerializedSearchComplete
,
LineMatch
}
from
'
./search
'
;
import
{
FileMatch
,
IFolderSearch
,
IRawSearch
,
ISerializedFileMatch
,
LineMatch
,
ISerializedSearchSuccess
}
from
'
./search
'
;
// If vscode-ripgrep is in an .asar file, then the binary is unpacked.
const
rgDiskPath
=
rgPath
.
replace
(
/
\b
node_modules
\.
asar
\b
/
,
'
node_modules.asar.unpacked
'
);
...
...
@@ -44,10 +44,11 @@ export class RipgrepEngine {
}
// TODO@Rob - make promise-based once the old search is gone, and I don't need them to have matching interfaces anymore
search
(
onResult
:
(
match
:
ISerializedFileMatch
)
=>
void
,
onMessage
:
(
message
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Complete
)
=>
void
):
void
{
search
(
onResult
:
(
match
:
ISerializedFileMatch
)
=>
void
,
onMessage
:
(
message
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Success
)
=>
void
):
void
{
if
(
!
this
.
config
.
folderQueries
.
length
&&
!
this
.
config
.
extraFiles
.
length
)
{
process
.
removeListener
(
'
exit
'
,
this
.
killRgProcFn
);
done
(
null
,
{
type
:
'
success
'
,
limitHit
:
false
,
stats
:
null
});
...
...
@@ -94,6 +95,7 @@ export class RipgrepEngine {
this
.
cancel
();
process
.
removeListener
(
'
exit
'
,
this
.
killRgProcFn
);
done
(
null
,
{
type
:
'
success
'
,
limitHit
:
true
,
stats
:
null
});
...
...
@@ -124,11 +126,13 @@ export class RipgrepEngine {
process
.
removeListener
(
'
exit
'
,
this
.
killRgProcFn
);
if
(
stderr
&&
!
gotData
&&
(
displayMsg
=
rgErrorMsgForDisplay
(
stderr
)))
{
done
(
new
Error
(
displayMsg
),
{
type
:
'
success
'
,
limitHit
:
false
,
stats
:
null
});
}
else
{
done
(
null
,
{
type
:
'
success
'
,
limitHit
:
false
,
stats
:
null
});
...
...
src/vs/workbench/services/search/node/search.ts
浏览文件 @
8bc931bd
...
...
@@ -5,10 +5,11 @@
'
use strict
'
;
import
{
PPromise
,
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IExpression
}
from
'
vs/base/common/glob
'
;
import
{
IProgress
,
ILineMatch
,
IPatternInfo
,
ISearchStats
}
from
'
vs/platform/search/common/search
'
;
import
{
ITelemetryData
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
export
interface
IFolderSearch
{
folder
:
string
;
...
...
@@ -41,10 +42,10 @@ export interface ITelemetryEvent {
}
export
interface
IRawSearchService
{
fileSearch
(
search
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
;
textSearch
(
search
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
;
fileSearch
(
search
:
IRawSearch
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
;
textSearch
(
search
:
IRawSearch
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
;
clearCache
(
cacheKey
:
string
):
TPromise
<
void
>
;
fetchTelemetry
():
PPromise
<
void
,
ITelemetryEvent
>
;
readonly
onTelemetry
:
Event
<
ITelemetryEvent
>
;
}
export
interface
IRawFileMatch
{
...
...
@@ -55,15 +56,37 @@ export interface IRawFileMatch {
}
export
interface
ISearchEngine
<
T
>
{
search
:
(
onResult
:
(
matches
:
T
)
=>
void
,
onProgress
:
(
progress
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Complete
)
=>
void
)
=>
void
;
search
:
(
onResult
:
(
matches
:
T
)
=>
void
,
onProgress
:
(
progress
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Success
)
=>
void
)
=>
void
;
cancel
:
()
=>
void
;
}
export
interface
ISerializedSearchComplete
{
export
interface
ISerializedSearchSuccess
{
type
:
'
success
'
;
limitHit
:
boolean
;
stats
:
ISearchStats
;
}
export
interface
ISerializedSearchError
{
type
:
'
error
'
;
error
:
any
;
}
export
type
ISerializedSearchComplete
=
ISerializedSearchSuccess
|
ISerializedSearchError
;
export
function
isSerializedSearchComplete
(
arg
:
ISerializedSearchProgressItem
|
ISerializedSearchComplete
):
arg
is
ISerializedSearchComplete
{
if
((
arg
as
any
).
type
===
'
error
'
)
{
return
true
;
}
else
if
((
arg
as
any
).
type
===
'
success
'
)
{
return
true
;
}
else
{
return
false
;
}
}
export
function
isSerializedSearchSuccess
(
arg
:
ISerializedSearchComplete
):
arg
is
ISerializedSearchSuccess
{
return
arg
.
type
===
'
success
'
;
}
export
interface
ISerializedFileMatch
{
path
:
string
;
lineMatches
?:
ILineMatch
[];
...
...
src/vs/workbench/services/search/node/searchIpc.ts
浏览文件 @
8bc931bd
...
...
@@ -5,16 +5,16 @@
'
use strict
'
;
import
{
PPromise
,
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IChannel
}
from
'
vs/base/parts/ipc/common/ipc
'
;
import
{
IRawSearchService
,
IRawSearch
,
ISerializedSearchComplete
,
ISerializedSearchProgressItem
,
ITelemetryEvent
}
from
'
./search
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
export
interface
ISearchChannel
extends
IChannel
{
call
(
command
:
'
fileSearch
'
,
search
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
;
call
(
command
:
'
textSearch
'
,
search
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
;
listen
(
event
:
'
telemetry
'
):
Event
<
ITelemetryEvent
>
;
listen
(
event
:
'
fileSearch
'
,
search
:
IRawSearch
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
;
listen
(
event
:
'
textSearch
'
,
search
:
IRawSearch
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
;
call
(
command
:
'
clearCache
'
,
cacheKey
:
string
):
TPromise
<
void
>
;
call
(
command
:
'
fetchTelemetry
'
):
PPromise
<
void
,
ITelemetryEvent
>
;
call
(
command
:
string
,
arg
:
any
):
TPromise
<
any
>
;
}
...
...
@@ -22,38 +22,38 @@ export class SearchChannel implements ISearchChannel {
constructor
(
private
service
:
IRawSearchService
)
{
}
listen
<
T
>
(
event
:
string
,
arg
?:
any
):
Event
<
T
>
{
throw
new
Error
(
'
No events
'
);
listen
<
T
>
(
event
:
string
,
arg
?:
any
):
Event
<
any
>
{
switch
(
event
)
{
case
'
telemetry
'
:
return
this
.
service
.
onTelemetry
;
case
'
fileSearch
'
:
return
this
.
service
.
fileSearch
(
arg
);
case
'
textSearch
'
:
return
this
.
service
.
textSearch
(
arg
);
}
throw
new
Error
(
'
Event not found
'
);
}
call
(
command
:
string
,
arg
?:
any
):
TPromise
<
any
>
{
switch
(
command
)
{
case
'
fileSearch
'
:
return
this
.
service
.
fileSearch
(
arg
);
case
'
textSearch
'
:
return
this
.
service
.
textSearch
(
arg
);
case
'
clearCache
'
:
return
this
.
service
.
clearCache
(
arg
);
case
'
fetchTelemetry
'
:
return
this
.
service
.
fetchTelemetry
();
}
return
undefined
;
throw
new
Error
(
'
Call not found
'
)
;
}
}
export
class
SearchChannelClient
implements
IRawSearchService
{
get
onTelemetry
():
Event
<
ITelemetryEvent
>
{
return
this
.
channel
.
listen
(
'
telemetry
'
);
}
constructor
(
private
channel
:
ISearchChannel
)
{
}
fileSearch
(
search
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
{
return
this
.
channel
.
call
(
'
fileSearch
'
,
search
);
fileSearch
(
search
:
IRawSearch
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
{
return
this
.
channel
.
listen
(
'
fileSearch
'
,
search
);
}
textSearch
(
search
:
IRawSearch
):
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
{
return
this
.
channel
.
call
(
'
textSearch
'
,
search
);
textSearch
(
search
:
IRawSearch
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
{
return
this
.
channel
.
listen
(
'
textSearch
'
,
search
);
}
clearCache
(
cacheKey
:
string
):
TPromise
<
void
>
{
return
this
.
channel
.
call
(
'
clearCache
'
,
cacheKey
);
}
fetchTelemetry
():
PPromise
<
void
,
ITelemetryEvent
>
{
return
this
.
channel
.
call
(
'
fetchTelemetry
'
);
}
}
\ No newline at end of file
src/vs/workbench/services/search/node/searchService.ts
浏览文件 @
8bc931bd
...
...
@@ -15,7 +15,7 @@ import { IProgress, LineMatch, FileMatch, ISearchComplete, ISearchProgressItem,
import
{
IUntitledEditorService
}
from
'
vs/workbench/services/untitled/common/untitledEditorService
'
;
import
{
IModelService
}
from
'
vs/editor/common/services/modelService
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
IRawSearch
,
ISerializedSearchComplete
,
ISerializedSearchProgressItem
,
ISerializedFileMatch
,
IRawSearchService
,
ITelemetryEvent
}
from
'
./search
'
;
import
{
IRawSearch
,
ISerializedSearchComplete
,
ISerializedSearchProgressItem
,
ISerializedFileMatch
,
IRawSearchService
,
ITelemetryEvent
,
isSerializedSearchComplete
,
isSerializedSearchSuccess
,
ISerializedSearchSuccess
}
from
'
./search
'
;
import
{
ISearchChannel
,
SearchChannelClient
}
from
'
./searchIpc
'
;
import
{
IEnvironmentService
,
IDebugParams
}
from
'
vs/platform/environment/common/environment
'
;
import
{
ResourceMap
}
from
'
vs/base/common/map
'
;
...
...
@@ -26,6 +26,7 @@ import { Schemas } from 'vs/base/common/network';
import
*
as
pfs
from
'
vs/base/node/pfs
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
IExtensionService
}
from
'
vs/workbench/services/extensions/common/extensions
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
export
class
SearchService
implements
ISearchService
{
public
_serviceBrand
:
any
;
...
...
@@ -320,14 +321,14 @@ export class DiskSearch implements ISearchResultProvider {
const
existingFolders
=
folderQueries
.
filter
((
q
,
index
)
=>
exists
[
index
]);
const
rawSearch
=
this
.
rawSearchQuery
(
query
,
existingFolders
);
let
request
:
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
;
let
event
:
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
;
if
(
query
.
type
===
QueryType
.
File
)
{
reques
t
=
this
.
raw
.
fileSearch
(
rawSearch
);
even
t
=
this
.
raw
.
fileSearch
(
rawSearch
);
}
else
{
reques
t
=
this
.
raw
.
textSearch
(
rawSearch
);
even
t
=
this
.
raw
.
textSearch
(
rawSearch
);
}
return
DiskSearch
.
collectResults
(
reques
t
);
return
DiskSearch
.
collectResults
FromEvent
(
even
t
);
});
}
...
...
@@ -372,7 +373,28 @@ export class DiskSearch implements ISearchResultProvider {
return
rawSearch
;
}
public
static
collectResults
(
request
:
PPromise
<
ISerializedSearchComplete
,
ISerializedSearchProgressItem
>
):
PPromise
<
ISearchComplete
,
ISearchProgressItem
>
{
public
static
collectResultsFromEvent
(
event
:
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
):
PPromise
<
ISearchComplete
,
ISearchProgressItem
>
{
const
promise
=
new
PPromise
<
ISerializedSearchSuccess
,
ISerializedSearchProgressItem
>
((
c
,
e
,
p
)
=>
{
setTimeout
(()
=>
{
const
listener
=
event
(
ev
=>
{
if
(
isSerializedSearchComplete
(
ev
))
{
if
(
isSerializedSearchSuccess
(
ev
))
{
c
(
ev
);
}
else
{
e
(
ev
.
error
);
}
listener
.
dispose
();
}
else
{
p
(
ev
);
}
});
},
0
);
});
return
DiskSearch
.
collectResults
(
promise
);
}
public
static
collectResults
(
request
:
PPromise
<
ISerializedSearchSuccess
,
ISerializedSearchProgressItem
>
):
PPromise
<
ISearchComplete
,
ISearchProgressItem
>
{
let
result
:
IFileMatch
[]
=
[];
return
new
PPromise
<
ISearchComplete
,
ISearchProgressItem
>
((
c
,
e
,
p
)
=>
{
request
.
done
((
complete
)
=>
{
...
...
@@ -420,6 +442,8 @@ export class DiskSearch implements ISearchResultProvider {
}
public
fetchTelemetry
():
PPromise
<
void
,
ITelemetryEvent
>
{
return
this
.
raw
.
fetchTelemetry
();
return
new
PPromise
<
void
,
ITelemetryEvent
>
((
c
,
e
,
p
)
=>
{
this
.
raw
.
onTelemetry
(
p
);
});
}
}
src/vs/workbench/services/search/node/textSearch.ts
浏览文件 @
8bc931bd
...
...
@@ -11,7 +11,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import
{
IProgress
}
from
'
vs/platform/search/common/search
'
;
import
{
FileWalker
}
from
'
vs/workbench/services/search/node/fileSearch
'
;
import
{
ISerializedFileMatch
,
I
SerializedSearchComplete
,
IRawSearch
,
ISearchEngine
}
from
'
./search
'
;
import
{
ISerializedFileMatch
,
I
RawSearch
,
ISearchEngine
,
ISerializedSearchSuccess
}
from
'
./search
'
;
import
{
ISearchWorker
}
from
'
./worker/searchWorkerIpc
'
;
import
{
ITextSearchWorkerProvider
}
from
'
./textSearchWorkerProvider
'
;
...
...
@@ -60,7 +60,7 @@ export class Engine implements ISearchEngine<ISerializedFileMatch[]> {
});
}
search
(
onResult
:
(
match
:
ISerializedFileMatch
[])
=>
void
,
onProgress
:
(
progress
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Complete
)
=>
void
):
void
{
search
(
onResult
:
(
match
:
ISerializedFileMatch
[])
=>
void
,
onProgress
:
(
progress
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Success
)
=>
void
):
void
{
this
.
workers
=
this
.
workerProvider
.
getWorkers
();
this
.
initializeWorkers
();
...
...
@@ -86,6 +86,7 @@ export class Engine implements ISearchEngine<ISerializedFileMatch[]> {
if
(
!
this
.
isDone
&&
this
.
processedBytes
===
this
.
totalBytes
&&
this
.
walkerIsDone
)
{
this
.
isDone
=
true
;
done
(
this
.
walkerError
,
{
type
:
'
success
'
,
limitHit
:
this
.
limitReached
,
stats
:
this
.
walker
.
getStats
()
});
...
...
src/vs/workbench/services/search/test/node/searchService.test.ts
浏览文件 @
8bc931bd
...
...
@@ -9,9 +9,11 @@ import * as assert from 'assert';
import
*
as
path
from
'
path
'
;
import
{
IProgress
,
IUncachedSearchStats
}
from
'
vs/platform/search/common/search
'
;
import
{
ISearchEngine
,
IRawSearch
,
IRawFileMatch
,
ISerializedFileMatch
,
I
SerializedSearchComplete
,
IFolderSearch
}
from
'
vs/workbench/services/search/node/search
'
;
import
{
ISearchEngine
,
IRawSearch
,
IRawFileMatch
,
ISerializedFileMatch
,
I
FolderSearch
,
ISerializedSearchSuccess
,
ISerializedSearchProgressItem
,
ISerializedSearchComplete
}
from
'
vs/workbench/services/search/node/search
'
;
import
{
SearchService
as
RawSearchService
}
from
'
vs/workbench/services/search/node/rawSearchService
'
;
import
{
DiskSearch
}
from
'
vs/workbench/services/search/node/searchService
'
;
import
{
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
const
TEST_FOLDER_QUERIES
=
[
{
folder
:
path
.
normalize
(
'
/some/where
'
)
}
...
...
@@ -44,12 +46,13 @@ class TestSearchEngine implements ISearchEngine<IRawFileMatch> {
TestSearchEngine
.
last
=
this
;
}
public
search
(
onResult
:
(
match
:
IRawFileMatch
)
=>
void
,
onProgress
:
(
progress
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Complete
)
=>
void
):
void
{
public
search
(
onResult
:
(
match
:
IRawFileMatch
)
=>
void
,
onProgress
:
(
progress
:
IProgress
)
=>
void
,
done
:
(
error
:
Error
,
complete
:
ISerializedSearch
Success
)
=>
void
):
void
{
const
self
=
this
;
(
function
next
()
{
process
.
nextTick
(()
=>
{
if
(
self
.
isCanceled
)
{
done
(
null
,
{
type
:
'
success
'
,
limitHit
:
false
,
stats
:
stats
});
...
...
@@ -58,6 +61,7 @@ class TestSearchEngine implements ISearchEngine<IRawFileMatch> {
const
result
=
self
.
result
();
if
(
!
result
)
{
done
(
null
,
{
type
:
'
success
'
,
limitHit
:
false
,
stats
:
stats
});
...
...
@@ -101,17 +105,17 @@ suite('SearchService', () => {
const
service
=
new
RawSearchService
();
let
results
=
0
;
return
service
.
doFileSearch
(
Engine
,
rawSearch
)
.
then
(()
=>
{
assert
.
strictEqual
(
results
,
5
);
},
null
,
value
=>
{
if
(
!
Array
.
isArray
(
value
))
{
assert
.
deepStrictEqual
(
value
,
match
);
results
++
;
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
}
);
const
cb
:
(
p
:
ISerializedSearchProgressItem
)
=>
void
=
value
=>
{
if
(
!
Array
.
isArray
(
value
))
{
assert
.
deepStrictEqual
(
value
,
match
);
results
++
;
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
)
);
}
};
return
service
.
doFileSearch
(
Engine
,
rawSearch
,
cb
)
.
then
(()
=>
assert
.
strictEqual
(
results
,
5
)
);
});
test
(
'
Batch results
'
,
function
()
{
...
...
@@ -121,19 +125,20 @@ suite('SearchService', () => {
const
service
=
new
RawSearchService
();
const
results
=
[];
return
service
.
doFileSearch
(
Engine
,
rawSearch
,
10
)
.
then
(()
=>
{
assert
.
deepStrictEqual
(
results
,
[
10
,
10
,
5
]);
},
null
,
value
=>
{
if
(
Array
.
isArray
(
value
))
{
value
.
forEach
(
m
=>
{
assert
.
deepStrictEqual
(
m
,
match
);
});
results
.
push
(
value
.
length
);
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
});
const
cb
:
(
p
:
ISerializedSearchProgressItem
)
=>
void
=
value
=>
{
if
(
Array
.
isArray
(
value
))
{
value
.
forEach
(
m
=>
{
assert
.
deepStrictEqual
(
m
,
match
);
});
results
.
push
(
value
.
length
);
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
};
return
service
.
doFileSearch
(
Engine
,
rawSearch
,
cb
,
10
).
then
(()
=>
{
assert
.
deepStrictEqual
(
results
,
[
10
,
10
,
5
]);
});
});
test
(
'
Collect batched results
'
,
function
()
{
...
...
@@ -143,8 +148,24 @@ suite('SearchService', () => {
const
Engine
=
TestSearchEngine
.
bind
(
null
,
()
=>
i
--
&&
rawMatch
);
const
service
=
new
RawSearchService
();
function
fileSearch
(
config
:
IRawSearch
,
batchSize
:
number
):
Event
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
{
let
promise
:
TPromise
<
ISerializedSearchSuccess
>
;
const
emitter
=
new
Emitter
<
ISerializedSearchProgressItem
|
ISerializedSearchComplete
>
({
onFirstListenerAdd
:
()
=>
{
promise
=
service
.
doFileSearch
(
Engine
,
config
,
p
=>
emitter
.
fire
(
p
),
batchSize
)
.
then
(
c
=>
emitter
.
fire
(
c
),
err
=>
emitter
.
fire
({
type
:
'
error
'
,
error
:
err
}));
},
onLastListenerRemove
:
()
=>
{
promise
.
cancel
();
}
});
return
emitter
.
event
;
}
const
progressResults
=
[];
return
DiskSearch
.
collectResults
(
service
.
doFileSearch
(
Engine
,
rawSearch
,
10
))
return
DiskSearch
.
collectResults
FromEvent
(
fileSearch
(
rawSearch
,
10
))
.
then
(
result
=>
{
assert
.
strictEqual
(
result
.
results
.
length
,
25
,
'
Result
'
);
assert
.
strictEqual
(
progressResults
.
length
,
25
,
'
Progress
'
);
...
...
@@ -167,7 +188,7 @@ suite('SearchService', () => {
},
};
return
DiskSearch
.
collectResults
(
service
.
fileSearch
(
query
))
return
DiskSearch
.
collectResults
FromEvent
(
service
.
fileSearch
(
query
))
.
then
(
result
=>
{
assert
.
strictEqual
(
result
.
results
.
length
,
1
,
'
Result
'
);
});
...
...
@@ -186,7 +207,7 @@ suite('SearchService', () => {
},
};
return
DiskSearch
.
collectResults
(
service
.
fileSearch
(
query
))
return
DiskSearch
.
collectResults
FromEvent
(
service
.
fileSearch
(
query
))
.
then
(
result
=>
{
assert
.
strictEqual
(
result
.
results
.
length
,
0
,
'
Result
'
);
assert
.
ok
(
result
.
limitHit
);
...
...
@@ -206,20 +227,22 @@ suite('SearchService', () => {
const
service
=
new
RawSearchService
();
const
results
=
[];
const
cb
=
value
=>
{
if
(
Array
.
isArray
(
value
))
{
results
.
push
(...
value
.
map
(
v
=>
v
.
path
));
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
};
return
service
.
doFileSearch
(
Engine
,
{
folderQueries
:
TEST_FOLDER_QUERIES
,
filePattern
:
'
bb
'
,
sortByScore
:
true
,
maxResults
:
2
},
1
).
then
(()
=>
{
},
cb
,
1
).
then
(()
=>
{
assert
.
notStrictEqual
(
typeof
TestSearchEngine
.
last
.
config
.
maxResults
,
'
number
'
);
assert
.
deepStrictEqual
(
results
,
[
path
.
normalize
(
'
/some/where/bbc
'
),
path
.
normalize
(
'
/some/where/bab
'
)]);
},
null
,
value
=>
{
if
(
Array
.
isArray
(
value
))
{
results
.
push
(...
value
.
map
(
v
=>
v
.
path
));
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
});
});
...
...
@@ -230,23 +253,24 @@ suite('SearchService', () => {
const
service
=
new
RawSearchService
();
const
results
=
[];
const
cb
=
value
=>
{
if
(
Array
.
isArray
(
value
))
{
value
.
forEach
(
m
=>
{
assert
.
deepStrictEqual
(
m
,
match
);
});
results
.
push
(
value
.
length
);
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
};
return
service
.
doFileSearch
(
Engine
,
{
folderQueries
:
TEST_FOLDER_QUERIES
,
filePattern
:
'
a
'
,
sortByScore
:
true
,
maxResults
:
23
},
10
)
},
cb
,
10
)
.
then
(()
=>
{
assert
.
deepStrictEqual
(
results
,
[
10
,
10
,
3
]);
},
null
,
value
=>
{
if
(
Array
.
isArray
(
value
))
{
value
.
forEach
(
m
=>
{
assert
.
deepStrictEqual
(
m
,
match
);
});
results
.
push
(
value
.
length
);
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
});
});
...
...
@@ -263,37 +287,39 @@ suite('SearchService', () => {
const
service
=
new
RawSearchService
();
const
results
=
[];
const
cb
=
value
=>
{
if
(
Array
.
isArray
(
value
))
{
results
.
push
(...
value
.
map
(
v
=>
v
.
path
));
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
};
return
service
.
doFileSearch
(
Engine
,
{
folderQueries
:
TEST_FOLDER_QUERIES
,
filePattern
:
'
b
'
,
sortByScore
:
true
,
cacheKey
:
'
x
'
},
-
1
).
then
(
complete
=>
{
},
cb
,
-
1
).
then
(
complete
=>
{
assert
.
strictEqual
(
complete
.
stats
.
fromCache
,
false
);
assert
.
deepStrictEqual
(
results
,
[
path
.
normalize
(
'
/some/where/bcb
'
),
path
.
normalize
(
'
/some/where/bbc
'
),
path
.
normalize
(
'
/some/where/aab
'
)]);
},
null
,
value
=>
{
if
(
Array
.
isArray
(
value
))
{
results
.
push
(...
value
.
map
(
v
=>
v
.
path
));
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
}).
then
(()
=>
{
const
results
=
[];
const
cb
=
value
=>
{
if
(
Array
.
isArray
(
value
))
{
results
.
push
(...
value
.
map
(
v
=>
v
.
path
));
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
};
return
service
.
doFileSearch
(
Engine
,
{
folderQueries
:
TEST_FOLDER_QUERIES
,
filePattern
:
'
bc
'
,
sortByScore
:
true
,
cacheKey
:
'
x
'
},
-
1
).
then
(
complete
=>
{
},
cb
,
-
1
).
then
(
complete
=>
{
assert
.
ok
(
complete
.
stats
.
fromCache
);
assert
.
deepStrictEqual
(
results
,
[
path
.
normalize
(
'
/some/where/bcb
'
),
path
.
normalize
(
'
/some/where/bbc
'
)]);
},
null
,
value
=>
{
if
(
Array
.
isArray
(
value
))
{
results
.
push
(...
value
.
map
(
v
=>
v
.
path
));
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
});
},
null
);
}).
then
(()
=>
{
return
service
.
clearCache
(
'
x
'
);
}).
then
(()
=>
{
...
...
@@ -304,20 +330,21 @@ suite('SearchService', () => {
size
:
3
});
const
results
=
[];
const
cb
=
value
=>
{
if
(
Array
.
isArray
(
value
))
{
results
.
push
(...
value
.
map
(
v
=>
v
.
path
));
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
};
return
service
.
doFileSearch
(
Engine
,
{
folderQueries
:
TEST_FOLDER_QUERIES
,
filePattern
:
'
bc
'
,
sortByScore
:
true
,
cacheKey
:
'
x
'
},
-
1
).
then
(
complete
=>
{
},
cb
,
-
1
).
then
(
complete
=>
{
assert
.
strictEqual
(
complete
.
stats
.
fromCache
,
false
);
assert
.
deepStrictEqual
(
results
,
[
path
.
normalize
(
'
/some/where/bc
'
)]);
},
null
,
value
=>
{
if
(
Array
.
isArray
(
value
))
{
results
.
push
(...
value
.
map
(
v
=>
v
.
path
));
}
else
{
assert
.
fail
(
JSON
.
stringify
(
value
));
}
});
});
});
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录