Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
de70176d
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,发现更多精彩内容 >>
提交
de70176d
编写于
8月 24, 2018
作者:
R
Rob Lourens
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fix #57186, Fix #31551 - implement previewOptions for text search API
上级
3d69f453
变更
21
隐藏空白更改
内联
并排
Showing
21 changed file
with
405 addition
and
286 deletion
+405
-286
extensions/search-rg/src/ripgrepTextSearch.ts
extensions/search-rg/src/ripgrepTextSearch.ts
+14
-4
src/vs/platform/search/common/search.ts
src/vs/platform/search/common/search.ts
+59
-11
src/vs/vscode.proposed.d.ts
src/vs/vscode.proposed.d.ts
+7
-4
src/vs/workbench/api/electron-browser/mainThreadSearch.ts
src/vs/workbench/api/electron-browser/mainThreadSearch.ts
+3
-3
src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts
src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts
+1
-1
src/vs/workbench/api/node/extHostSearch.ts
src/vs/workbench/api/node/extHostSearch.ts
+31
-16
src/vs/workbench/parts/search/browser/searchView.ts
src/vs/workbench/parts/search/browser/searchView.ts
+9
-1
src/vs/workbench/parts/search/common/queryBuilder.ts
src/vs/workbench/parts/search/common/queryBuilder.ts
+2
-1
src/vs/workbench/parts/search/common/searchModel.ts
src/vs/workbench/parts/search/common/searchModel.ts
+49
-37
src/vs/workbench/parts/search/test/browser/searchActions.test.ts
...workbench/parts/search/test/browser/searchActions.test.ts
+16
-3
src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts
...workbench/parts/search/test/browser/searchViewlet.test.ts
+22
-9
src/vs/workbench/parts/search/test/common/searchModel.test.ts
...vs/workbench/parts/search/test/common/searchModel.test.ts
+26
-12
src/vs/workbench/parts/search/test/common/searchResult.test.ts
...s/workbench/parts/search/test/common/searchResult.test.ts
+76
-85
src/vs/workbench/services/search/node/ripgrepTextSearch.ts
src/vs/workbench/services/search/node/ripgrepTextSearch.ts
+10
-9
src/vs/workbench/services/search/node/search.ts
src/vs/workbench/services/search/node/search.ts
+11
-44
src/vs/workbench/services/search/node/searchService.ts
src/vs/workbench/services/search/node/searchService.ts
+10
-7
src/vs/workbench/services/search/node/textSearch.ts
src/vs/workbench/services/search/node/textSearch.ts
+2
-2
src/vs/workbench/services/search/node/worker/searchWorker.ts
src/vs/workbench/services/search/node/worker/searchWorker.ts
+10
-14
src/vs/workbench/services/search/node/worker/searchWorkerIpc.ts
.../workbench/services/search/node/worker/searchWorkerIpc.ts
+2
-1
src/vs/workbench/services/search/test/node/ripgrepTextSearch.test.ts
...bench/services/search/test/node/ripgrepTextSearch.test.ts
+36
-14
src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts
...workbench/test/electron-browser/api/extHostSearch.test.ts
+9
-8
未找到文件。
extensions/search-rg/src/ripgrepTextSearch.ts
浏览文件 @
de70176d
...
...
@@ -67,7 +67,7 @@ export class RipgrepTextSearchEngine {
});
let
gotResult
=
false
;
this
.
ripgrepParser
=
new
RipgrepParser
(
MAX_TEXT_RESULTS
,
cwd
);
this
.
ripgrepParser
=
new
RipgrepParser
(
MAX_TEXT_RESULTS
,
cwd
,
options
.
previewOptions
);
this
.
ripgrepParser
.
on
(
'
result
'
,
(
match
:
vscode
.
TextSearchResult
)
=>
{
gotResult
=
true
;
progress
.
report
(
match
);
...
...
@@ -160,7 +160,7 @@ export class RipgrepParser extends EventEmitter {
private
numResults
=
0
;
constructor
(
private
maxResults
:
number
,
private
rootFolder
:
string
)
{
constructor
(
private
maxResults
:
number
,
private
rootFolder
:
string
,
private
previewOptions
?:
vscode
.
TextSearchPreviewOptions
)
{
super
();
this
.
stringDecoder
=
new
StringDecoder
();
}
...
...
@@ -293,12 +293,22 @@ export class RipgrepParser extends EventEmitter {
lineMatches
.
map
(
range
=>
{
let
trimmedPreview
=
preview
;
let
trimmedPreviewRange
=
range
;
if
(
this
.
previewOptions
)
{
const
previewStart
=
Math
.
max
(
range
.
start
.
character
-
this
.
previewOptions
.
leadingChars
,
0
);
trimmedPreview
=
preview
.
substr
(
previewStart
,
this
.
previewOptions
.
totalChars
-
previewStart
);
if
(
previewStart
>
0
)
{
trimmedPreviewRange
=
new
vscode
.
Range
(
0
,
range
.
start
.
character
-
previewStart
,
0
,
range
.
end
.
character
-
previewStart
);
}
}
return
<
vscode
.
TextSearchResult
>
{
uri
:
vscode
.
Uri
.
file
(
path
.
join
(
this
.
rootFolder
,
this
.
currentFile
)),
range
,
preview
:
{
text
:
p
review
,
match
:
new
vscode
.
Range
(
0
,
range
.
start
.
character
,
0
,
range
.
end
.
character
)
text
:
trimmedP
review
,
match
:
trimmedPreviewRange
||
new
vscode
.
Range
(
0
,
range
.
start
.
character
,
0
,
range
.
end
.
character
)
}
};
})
...
...
src/vs/platform/search/common/search.ts
浏览文件 @
de70176d
...
...
@@ -85,6 +85,7 @@ export interface ICommonQueryOptions<U> {
disregardExcludeSettings
?:
boolean
;
ignoreSymlinks
?:
boolean
;
maxFileSize
?:
number
;
previewOptions
?:
ITextSearchPreviewOptions
;
}
export
interface
IQueryOptions
extends
ICommonQueryOptions
<
uri
>
{
...
...
@@ -132,15 +133,33 @@ export interface IPatternInfo {
export
interface
IFileMatch
<
U
extends
UriComponents
=
uri
>
{
resource
?:
U
;
lineMatches
?:
ILineMatch
[];
matches
?:
ITextSearchResult
[];
}
export
type
IRawFileMatch2
=
IFileMatch
<
UriComponents
>
;
export
interface
ILineMatch
{
preview
:
string
;
lineNumber
:
number
;
offsetAndLengths
:
number
[][];
export
interface
ITextSearchPreviewOptions
{
maxLines
:
number
;
leadingChars
:
number
;
totalChars
:
number
;
}
export
interface
ISearchRange
{
readonly
startLineNumber
:
number
;
readonly
startColumn
:
number
;
readonly
endLineNumber
:
number
;
readonly
endColumn
:
number
;
}
export
interface
ITextSearchResultPreview
{
text
:
string
;
match
:
ISearchRange
;
}
export
interface
ITextSearchResult
{
uri
?:
uri
;
range
:
ISearchRange
;
preview
:
ITextSearchResultPreview
;
}
export
interface
IProgress
{
...
...
@@ -204,18 +223,47 @@ export interface IFileIndexProviderStats {
filesWalked
:
number
;
}
// ---- very simple implementation of the search model --------------------
export
class
FileMatch
implements
IFileMatch
{
public
lineMatches
:
LineMatch
[]
=
[];
public
matches
:
ITextSearchResult
[]
=
[];
constructor
(
public
resource
:
uri
)
{
// empty
}
}
export
class
LineMatch
implements
ILineMatch
{
constructor
(
public
preview
:
string
,
public
lineNumber
:
number
,
public
offsetAndLengths
:
number
[][])
{
// empty
export
class
TextSearchResult
implements
ITextSearchResult
{
range
:
ISearchRange
;
preview
:
ITextSearchResultPreview
;
constructor
(
fullLine
:
string
,
range
:
ISearchRange
,
previewOptions
?:
ITextSearchPreviewOptions
)
{
this
.
range
=
range
;
if
(
previewOptions
)
{
const
previewStart
=
Math
.
max
(
range
.
startColumn
-
previewOptions
.
leadingChars
,
0
);
const
previewEnd
=
Math
.
max
(
previewOptions
.
totalChars
+
previewStart
,
range
.
endColumn
);
this
.
preview
=
{
text
:
fullLine
.
substring
(
previewStart
,
previewEnd
),
match
:
new
OneLineRange
(
0
,
range
.
startColumn
-
previewStart
,
range
.
endColumn
-
previewStart
)
};
}
else
{
this
.
preview
=
{
text
:
fullLine
,
match
:
new
OneLineRange
(
0
,
range
.
startColumn
,
range
.
endColumn
)
};
}
}
}
export
class
OneLineRange
implements
ISearchRange
{
startLineNumber
:
number
;
startColumn
:
number
;
endLineNumber
:
number
;
endColumn
:
number
;
constructor
(
lineNumber
:
number
,
startColumn
:
number
,
endColumn
:
number
)
{
this
.
startLineNumber
=
lineNumber
;
this
.
startColumn
=
startColumn
;
this
.
endLineNumber
=
lineNumber
;
this
.
endColumn
=
endColumn
;
}
}
...
...
src/vs/vscode.proposed.d.ts
浏览文件 @
de70176d
...
...
@@ -77,6 +77,12 @@ declare module 'vscode' {
followSymlinks
:
boolean
;
}
export
interface
TextSearchPreviewOptions
{
maxLines
:
number
;
leadingChars
:
number
;
totalChars
:
number
;
}
/**
* Options that apply to text search.
*/
...
...
@@ -86,10 +92,7 @@ declare module 'vscode' {
*/
maxResults
:
number
;
/**
* TODO@roblou - total length? # of context lines? leading and trailing # of chars?
*/
previewOptions
?:
any
;
previewOptions
?:
TextSearchPreviewOptions
;
/**
* Exclude files larger than `maxFileSize` in bytes.
...
...
src/vs/workbench/api/electron-browser/mainThreadSearch.ts
浏览文件 @
de70176d
...
...
@@ -78,7 +78,7 @@ class SearchOperation {
addMatch
(
match
:
IFileMatch
):
void
{
if
(
this
.
matches
.
has
(
match
.
resource
.
toString
()))
{
// Merge with previous IFileMatches
this
.
matches
.
get
(
match
.
resource
.
toString
()).
lineMatches
.
push
(...
match
.
lineM
atches
);
this
.
matches
.
get
(
match
.
resource
.
toString
()).
matches
.
push
(...
match
.
m
atches
);
}
else
{
this
.
matches
.
set
(
match
.
resource
.
toString
(),
match
);
}
...
...
@@ -149,10 +149,10 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
const
searchOp
=
this
.
_searches
.
get
(
session
);
dataOrUri
.
forEach
(
result
=>
{
if
((
<
IRawFileMatch2
>
result
).
lineM
atches
)
{
if
((
<
IRawFileMatch2
>
result
).
m
atches
)
{
searchOp
.
addMatch
({
resource
:
URI
.
revive
((
<
IRawFileMatch2
>
result
).
resource
),
lineMatches
:
(
<
IRawFileMatch2
>
result
).
lineM
atches
matches
:
(
<
IRawFileMatch2
>
result
).
m
atches
});
}
else
{
searchOp
.
addMatch
({
...
...
src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts
浏览文件 @
de70176d
...
...
@@ -181,7 +181,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
const
query
=
queryBuilder
.
text
(
pattern
,
folders
,
options
);
const
onProgress
=
(
p
:
ISearchProgressItem
)
=>
{
if
(
p
.
lineM
atches
)
{
if
(
p
.
m
atches
)
{
this
.
_proxy
.
$handleTextSearchResult
(
p
,
requestId
);
}
};
...
...
src/vs/workbench/api/node/extHostSearch.ts
浏览文件 @
de70176d
...
...
@@ -5,20 +5,20 @@
'
use strict
'
;
import
*
as
path
from
'
path
'
;
import
{
CancellationToken
Source
,
CancellationToken
}
from
'
vs/base/common/cancellation
'
;
import
{
CancellationToken
,
CancellationTokenSource
}
from
'
vs/base/common/cancellation
'
;
import
{
toErrorMessage
}
from
'
vs/base/common/errorMessage
'
;
import
{
isPromiseCanceledError
}
from
'
vs/base/common/errors
'
;
import
*
as
glob
from
'
vs/base/common/glob
'
;
import
{
toDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
*
as
resources
from
'
vs/base/common/resources
'
;
import
{
StopWatch
}
from
'
vs/base/common/stopwatch
'
;
import
URI
,
{
UriComponents
}
from
'
vs/base/common/uri
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
*
as
extfs
from
'
vs/base/node/extfs
'
;
import
{
IFileMatch
,
IFolderQuery
,
IPatternInfo
,
IRawSearchQuery
,
ISearchCompleteStats
,
ISearchQuery
,
IFileSearchProviderStats
}
from
'
vs/platform/search/common/search
'
;
import
{
IFileMatch
,
IFileSearchProviderStats
,
IFolderQuery
,
IPatternInfo
,
IRawSearchQuery
,
ISearchCompleteStats
,
ISearchQuery
,
ITextSearchResult
}
from
'
vs/platform/search/common/search
'
;
import
{
FileIndexSearchManager
,
IDirectoryEntry
,
IDirectoryTree
,
IInternalFileMatch
,
QueryGlobTester
,
resolvePatternsForProvider
}
from
'
vs/workbench/api/node/extHostSearch.fileIndex
'
;
import
*
as
vscode
from
'
vscode
'
;
import
{
ExtHostSearchShape
,
IMainContext
,
MainContext
,
MainThreadSearchShape
}
from
'
./extHost.protocol
'
;
import
{
toDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IInternalFileMatch
,
QueryGlobTester
,
resolvePatternsForProvider
,
IDirectoryTree
,
IDirectoryEntry
,
FileIndexSearchManager
}
from
'
vs/workbench/api/node/extHostSearch.fileIndex
'
;
import
{
StopWatch
}
from
'
vs/base/common/stopwatch
'
;
import
{
isPromiseCanceledError
}
from
'
vs/base/common/errors
'
;
export
interface
ISchemeTransformer
{
transformOutgoing
(
scheme
:
string
):
string
;
...
...
@@ -172,22 +172,16 @@ class TextSearchResultsCollector {
if
(
!
this
.
_currentFileMatch
)
{
this
.
_currentFileMatch
=
{
resource
:
data
.
uri
,
lineM
atches
:
[]
m
atches
:
[]
};
}
// TODO@roblou - line text is sent for every match
const
matchRange
=
data
.
preview
.
match
;
this
.
_currentFileMatch
.
lineMatches
.
push
({
lineNumber
:
data
.
range
.
start
.
line
,
preview
:
data
.
preview
.
text
,
offsetAndLengths
:
[[
matchRange
.
start
.
character
,
matchRange
.
end
.
character
-
matchRange
.
start
.
character
]]
});
this
.
_currentFileMatch
.
matches
.
push
(
extensionResultToFrontendResult
(
data
));
}
private
pushToCollector
():
void
{
const
size
=
this
.
_currentFileMatch
?
this
.
_currentFileMatch
.
lineMatches
.
reduce
((
acc
,
match
)
=>
acc
+
match
.
offsetAndLengths
.
length
,
0
)
:
this
.
_currentFileMatch
.
matches
.
length
:
0
;
this
.
_batchedCollector
.
addItem
(
this
.
_currentFileMatch
,
size
);
}
...
...
@@ -202,6 +196,26 @@ class TextSearchResultsCollector {
}
}
function
extensionResultToFrontendResult
(
data
:
vscode
.
TextSearchResult
):
ITextSearchResult
{
return
{
preview
:
{
match
:
{
startLineNumber
:
data
.
preview
.
match
.
start
.
line
,
startColumn
:
data
.
preview
.
match
.
start
.
character
,
endLineNumber
:
data
.
preview
.
match
.
end
.
line
,
endColumn
:
data
.
preview
.
match
.
end
.
character
},
text
:
data
.
preview
.
text
},
range
:
{
startLineNumber
:
data
.
range
.
start
.
line
,
startColumn
:
data
.
range
.
start
.
character
,
endLineNumber
:
data
.
range
.
end
.
line
,
endColumn
:
data
.
range
.
end
.
character
}
};
}
/**
* Collects items that have a size - before the cumulative size of collected items reaches START_BATCH_AFTER_COUNT, the callback is called for every
* set of items collected.
...
...
@@ -414,7 +428,8 @@ class TextSearchEngine {
followSymlinks
:
!
this
.
config
.
ignoreSymlinks
,
encoding
:
this
.
config
.
fileEncoding
,
maxFileSize
:
this
.
config
.
maxFileSize
,
maxResults
:
this
.
config
.
maxResults
maxResults
:
this
.
config
.
maxResults
,
previewOptions
:
this
.
config
.
previewOptions
};
}
}
...
...
src/vs/workbench/parts/search/browser/searchView.ts
浏览文件 @
de70176d
...
...
@@ -108,6 +108,7 @@ export class SearchView extends Viewlet implements IViewlet, IPanel {
private
readonly
selectCurrentMatchEmitter
:
Emitter
<
string
>
;
private
delayedRefresh
:
Delayer
<
void
>
;
private
changedWhileHidden
:
boolean
;
private
isWide
:
boolean
;
private
searchWithoutFolderMessageBuilder
:
Builder
;
...
...
@@ -826,8 +827,10 @@ export class SearchView extends Viewlet implements IViewlet, IPanel {
}
if
(
this
.
size
.
width
>=
SearchView
.
WIDE_VIEW_SIZE
)
{
this
.
isWide
=
true
;
dom
.
addClass
(
this
.
getContainer
(),
SearchView
.
WIDE_CLASS_NAME
);
}
else
{
this
.
isWide
=
false
;
dom
.
removeClass
(
this
.
getContainer
(),
SearchView
.
WIDE_CLASS_NAME
);
}
...
...
@@ -1081,7 +1084,12 @@ export class SearchView extends Viewlet implements IViewlet, IPanel {
disregardIgnoreFiles
:
!
useExcludesAndIgnoreFiles
,
disregardExcludeSettings
:
!
useExcludesAndIgnoreFiles
,
excludePattern
,
includePattern
includePattern
,
previewOptions
:
{
leadingChars
:
5
,
maxLines
:
1
,
totalChars
:
this
.
isWide
?
1000
:
100
}
};
const
folderResources
=
this
.
contextService
.
getWorkspace
().
folders
;
...
...
src/vs/workbench/parts/search/common/queryBuilder.ts
浏览文件 @
de70176d
...
...
@@ -95,7 +95,8 @@ export class QueryBuilder {
useRipgrep
,
disregardIgnoreFiles
:
options
.
disregardIgnoreFiles
||
!
useIgnoreFiles
,
disregardExcludeSettings
:
options
.
disregardExcludeSettings
,
ignoreSymlinks
ignoreSymlinks
,
previewOptions
:
options
.
previewOptions
};
// Filter extraFileResources against global include/exclude patterns - they are already expected to not belong to a workspace
...
...
src/vs/workbench/parts/search/common/searchModel.ts
浏览文件 @
de70176d
...
...
@@ -3,39 +3,50 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
objects
from
'
vs/base/common/objects
'
;
import
*
as
strings
from
'
vs/base/common/strings
'
;
import
*
as
errors
from
'
vs/base/common/errors
'
;
import
{
RunOnceScheduler
}
from
'
vs/base/common/async
'
;
import
{
IDisposable
,
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
*
as
errors
from
'
vs/base/common/errors
'
;
import
{
anyEvent
,
Emitter
,
Event
,
fromPromise
,
stopwatch
}
from
'
vs/base/common/event
'
;
import
{
getBaseLabel
}
from
'
vs/base/common/labels
'
;
import
{
Disposable
,
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
ResourceMap
,
TernarySearchTree
,
values
}
from
'
vs/base/common/map
'
;
import
*
as
objects
from
'
vs/base/common/objects
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
values
,
ResourceMap
,
TernarySearchTree
}
from
'
vs/base/common/map
'
;
import
{
Event
,
Emitter
,
fromPromise
,
stopwatch
,
anyEvent
}
from
'
vs/base/common/event
'
;
import
{
ISearchService
,
ISearchProgressItem
,
ISearchComplete
,
ISearchQuery
,
IPatternInfo
,
IFileMatch
,
ITextSearchStats
}
from
'
vs/platform/search/common/search
'
;
import
{
ReplacePattern
}
from
'
vs/platform/search/common/replace
'
;
import
{
ITelemetryService
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
ITextModel
,
IModelDeltaDecoration
,
OverviewRulerLane
,
TrackedRangeStickiness
,
FindMatch
}
from
'
vs/editor/common/model
'
;
import
{
IInstantiationService
,
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
FindMatch
,
IModelDeltaDecoration
,
ITextModel
,
OverviewRulerLane
,
TrackedRangeStickiness
}
from
'
vs/editor/common/model
'
;
import
{
ModelDecorationOptions
}
from
'
vs/editor/common/model/textModel
'
;
import
{
IModelService
}
from
'
vs/editor/common/services/modelService
'
;
import
{
IReplaceService
}
from
'
vs/workbench/parts/search/common/replace
'
;
import
{
createDecorator
,
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IProgressRunner
}
from
'
vs/platform/progress/common/progress
'
;
import
{
ModelDecorationOptions
}
from
'
vs/editor/common/model/textModel
'
;
import
{
ReplacePattern
}
from
'
vs/platform/search/common/replace
'
;
import
{
IFileMatch
,
IPatternInfo
,
ISearchComplete
,
ISearchProgressItem
,
ISearchQuery
,
ISearchService
,
ITextSearchPreviewOptions
,
ITextSearchResult
,
ITextSearchStats
,
TextSearchResult
}
from
'
vs/platform/search/common/search
'
;
import
{
ITelemetryService
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
overviewRulerFindMatchForeground
}
from
'
vs/platform/theme/common/colorRegistry
'
;
import
{
themeColorFromId
}
from
'
vs/platform/theme/common/themeService
'
;
import
{
getBaseLabel
}
from
'
vs/base/common/labels
'
;
import
{
IReplaceService
}
from
'
vs/workbench/parts/search/common/replace
'
;
export
class
Match
{
private
_lineText
:
string
;
private
_id
:
string
;
private
_range
:
Range
;
private
_previewText
:
string
;
private
_rangeInPreviewText
:
Range
;
constructor
(
private
_parent
:
FileMatch
,
text
:
string
,
lineNumber
:
number
,
offset
:
number
,
length
:
number
)
{
this
.
_lineText
=
text
;
this
.
_range
=
new
Range
(
1
+
lineNumber
,
1
+
offset
,
1
+
lineNumber
,
1
+
offset
+
length
);
this
.
_id
=
this
.
_parent
.
id
()
+
'
>
'
+
lineNumber
+
'
>
'
+
offset
+
this
.
getMatchString
();
constructor
(
private
_parent
:
FileMatch
,
_result
:
ITextSearchResult
)
{
this
.
_range
=
new
Range
(
_result
.
range
.
startLineNumber
+
1
,
_result
.
range
.
startColumn
+
1
,
_result
.
range
.
endLineNumber
+
1
,
_result
.
range
.
endColumn
+
1
);
this
.
_rangeInPreviewText
=
new
Range
(
_result
.
preview
.
match
.
startLineNumber
+
1
,
_result
.
preview
.
match
.
startColumn
+
1
,
_result
.
preview
.
match
.
endLineNumber
+
1
,
_result
.
preview
.
match
.
endColumn
+
1
);
this
.
_previewText
=
_result
.
preview
.
text
;
this
.
_id
=
this
.
_parent
.
id
()
+
'
>
'
+
this
.
_range
+
this
.
getMatchString
();
}
public
id
():
string
{
...
...
@@ -47,7 +58,7 @@ export class Match {
}
public
text
():
string
{
return
this
.
_
line
Text
;
return
this
.
_
preview
Text
;
}
public
range
():
Range
{
...
...
@@ -55,11 +66,9 @@ export class Match {
}
public
preview
():
{
before
:
string
;
inside
:
string
;
after
:
string
;
}
{
let
before
=
this
.
_lineText
.
substring
(
0
,
this
.
_range
.
startColumn
-
1
),
const
before
=
this
.
_previewText
.
substring
(
0
,
this
.
_rangeInPreviewText
.
startColumn
-
1
),
inside
=
this
.
getMatchString
(),
after
=
this
.
_lineText
.
substring
(
this
.
_range
.
endColumn
-
1
,
Math
.
min
(
this
.
_range
.
endColumn
+
150
,
this
.
_lineText
.
length
));
before
=
strings
.
lcut
(
before
,
26
);
after
=
this
.
_previewText
.
substring
(
this
.
_rangeInPreviewText
.
endColumn
-
1
);
return
{
before
,
...
...
@@ -75,7 +84,7 @@ export class Match {
// If match string is not matching then regex pattern has a lookahead expression
if
(
replaceString
===
null
)
{
replaceString
=
searchModel
.
replacePattern
.
getReplaceString
(
matchString
+
this
.
_
lineText
.
substring
(
this
.
_range
.
endColumn
-
1
));
replaceString
=
searchModel
.
replacePattern
.
getReplaceString
(
matchString
+
this
.
_
previewText
.
substring
(
this
.
_rangeInPreviewText
.
endColumn
-
1
));
}
// Match string is still not matching. Could be unsupported matches (multi-line).
...
...
@@ -87,7 +96,7 @@ export class Match {
}
public
getMatchString
():
string
{
return
this
.
_
lineText
.
substring
(
this
.
_range
.
startColumn
-
1
,
this
.
_range
.
endColumn
-
1
);
return
this
.
_
previewText
.
substring
(
this
.
_rangeInPreviewText
.
startColumn
-
1
,
this
.
_rangeInPreviewText
.
endColumn
-
1
);
}
}
...
...
@@ -134,7 +143,7 @@ export class FileMatch extends Disposable {
private
_updateScheduler
:
RunOnceScheduler
;
private
_modelDecorations
:
string
[]
=
[];
constructor
(
private
_query
:
IPatternInfo
,
private
_maxResults
:
number
,
private
_parent
:
FolderMatch
,
private
rawMatch
:
IFileMatch
,
constructor
(
private
_query
:
IPatternInfo
,
private
_
previewOptions
:
ITextSearchPreviewOptions
,
private
_
maxResults
:
number
,
private
_parent
:
FolderMatch
,
private
rawMatch
:
IFileMatch
,
@
IModelService
private
modelService
:
IModelService
,
@
IReplaceService
private
replaceService
:
IReplaceService
)
{
super
();
this
.
_resource
=
this
.
rawMatch
.
resource
;
...
...
@@ -152,11 +161,9 @@ export class FileMatch extends Disposable {
this
.
bindModel
(
model
);
this
.
updateMatchesForModel
();
}
else
{
this
.
rawMatch
.
lineMatches
.
forEach
((
rawLineMatch
)
=>
{
rawLineMatch
.
offsetAndLengths
.
forEach
(
offsetAndLength
=>
{
let
match
=
new
Match
(
this
,
rawLineMatch
.
preview
,
rawLineMatch
.
lineNumber
,
offsetAndLength
[
0
],
offsetAndLength
[
1
]);
this
.
add
(
match
);
});
this
.
rawMatch
.
matches
.
forEach
((
rawLineMatch
)
=>
{
let
match
=
new
Match
(
this
,
rawLineMatch
);
this
.
add
(
match
);
});
}
}
...
...
@@ -222,7 +229,12 @@ export class FileMatch extends Disposable {
private
updateMatches
(
matches
:
FindMatch
[],
modelChange
:
boolean
)
{
matches
.
forEach
(
m
=>
{
let
match
=
new
Match
(
this
,
this
.
_model
.
getLineContent
(
m
.
range
.
startLineNumber
),
m
.
range
.
startLineNumber
-
1
,
m
.
range
.
startColumn
-
1
,
m
.
range
.
endColumn
-
m
.
range
.
startColumn
);
const
textSearchResult
=
new
TextSearchResult
(
this
.
_model
.
getLineContent
(
m
.
range
.
startLineNumber
),
new
Range
(
m
.
range
.
startLineNumber
-
1
,
m
.
range
.
startColumn
-
1
,
m
.
range
.
startLineNumber
-
1
,
m
.
range
.
endColumn
),
this
.
_previewOptions
);
const
match
=
new
Match
(
this
,
textSearchResult
);
if
(
!
this
.
_removedMatches
.
has
(
match
.
id
()))
{
this
.
add
(
match
);
if
(
this
.
isMatchSelected
(
match
))
{
...
...
@@ -392,16 +404,16 @@ export class FolderMatch extends Disposable {
}
public
add
(
raw
:
IFileMatch
[],
silent
:
boolean
):
void
{
le
t
changed
:
FileMatch
[]
=
[];
cons
t
changed
:
FileMatch
[]
=
[];
raw
.
forEach
((
rawFileMatch
)
=>
{
if
(
this
.
_fileMatches
.
has
(
rawFileMatch
.
resource
))
{
this
.
_fileMatches
.
get
(
rawFileMatch
.
resource
).
dispose
();
}
let
fileMatch
=
this
.
instantiationService
.
createInstance
(
FileMatch
,
this
.
_query
.
contentPattern
,
this
.
_query
.
maxResults
,
this
,
rawFileMatch
);
const
fileMatch
=
this
.
instantiationService
.
createInstance
(
FileMatch
,
this
.
_query
.
contentPattern
,
this
.
_query
.
previewOptions
,
this
.
_query
.
maxResults
,
this
,
rawFileMatch
);
this
.
doAdd
(
fileMatch
);
changed
.
push
(
fileMatch
);
le
t
disposable
=
fileMatch
.
onChange
(()
=>
this
.
onFileChange
(
fileMatch
));
cons
t
disposable
=
fileMatch
.
onChange
(()
=>
this
.
onFileChange
(
fileMatch
));
fileMatch
.
onDispose
(()
=>
disposable
.
dispose
());
});
if
(
!
silent
&&
changed
.
length
)
{
...
...
src/vs/workbench/parts/search/test/browser/searchActions.test.ts
浏览文件 @
de70176d
...
...
@@ -129,13 +129,26 @@ suite('Search Actions', () => {
function
aFileMatch
():
FileMatch
{
let
rawMatch
:
IFileMatch
=
{
resource
:
URI
.
file
(
'
somepath
'
+
++
counter
),
lineM
atches
:
[]
m
atches
:
[]
};
return
instantiationService
.
createInstance
(
FileMatch
,
null
,
null
,
null
,
rawMatch
);
return
instantiationService
.
createInstance
(
FileMatch
,
null
,
null
,
null
,
null
,
rawMatch
);
}
function
aMatch
(
fileMatch
:
FileMatch
):
Match
{
let
match
=
new
Match
(
fileMatch
,
'
some match
'
,
++
counter
,
0
,
2
);
const
line
=
++
counter
;
const
range
=
{
startLineNumber
:
line
,
startColumn
:
0
,
endLineNumber
:
line
,
endColumn
:
2
};
let
match
=
new
Match
(
fileMatch
,
{
preview
:
{
text
:
'
some match
'
,
match
:
range
},
range
});
fileMatch
.
add
(
match
);
return
match
;
}
...
...
src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts
浏览文件 @
de70176d
...
...
@@ -9,7 +9,7 @@ import uri from 'vs/base/common/uri';
import
{
Match
,
FileMatch
,
SearchResult
}
from
'
vs/workbench/parts/search/common/searchModel
'
;
import
{
TestInstantiationService
}
from
'
vs/platform/instantiation/test/common/instantiationServiceMock
'
;
import
{
SearchDataSource
,
SearchSorter
}
from
'
vs/workbench/parts/search/browser/searchResultsView
'
;
import
{
IFileMatch
,
ILineMatch
}
from
'
vs/platform/search/common/search
'
;
import
{
IFileMatch
,
TextSearchResult
,
OneLineRange
,
ITextSearchResult
}
from
'
vs/platform/search/common/search
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
TestConfigurationService
}
from
'
vs/platform/configuration/test/common/testConfigurationService
'
;
import
{
ModelServiceImpl
}
from
'
vs/editor/common/services/modelServiceImpl
'
;
...
...
@@ -31,9 +31,22 @@ suite('Search - Viewlet', () => {
let
ds
=
instantiation
.
createInstance
(
SearchDataSource
);
let
result
:
SearchResult
=
instantiation
.
createInstance
(
SearchResult
,
null
);
result
.
query
=
{
type
:
1
,
folderQueries
:
[{
folder
:
uri
.
parse
(
'
file://c:/
'
)
}]
};
const
range
=
{
startLineNumber
:
1
,
startColumn
:
0
,
endLineNumber
:
1
,
endColumn
:
1
};
result
.
add
([{
resource
:
uri
.
parse
(
'
file:///c:/foo
'
),
lineMatches
:
[{
lineNumber
:
1
,
preview
:
'
bar
'
,
offsetAndLengths
:
[[
0
,
1
]]
}]
matches
:
[{
preview
:
{
text
:
'
bar
'
,
match
:
range
},
range
}]
}]);
let
fileMatch
=
result
.
matches
()[
0
];
...
...
@@ -41,7 +54,7 @@ suite('Search - Viewlet', () => {
assert
.
equal
(
ds
.
getId
(
null
,
result
),
'
root
'
);
assert
.
equal
(
ds
.
getId
(
null
,
fileMatch
),
'
file:///c%3A/foo
'
);
assert
.
equal
(
ds
.
getId
(
null
,
lineMatch
),
'
file:///c%3A/foo>
1>0
b
'
);
assert
.
equal
(
ds
.
getId
(
null
,
lineMatch
),
'
file:///c%3A/foo>
[2,1 -> 2,2]
b
'
);
assert
(
!
ds
.
hasChildren
(
null
,
'
foo
'
));
assert
(
ds
.
hasChildren
(
null
,
result
));
...
...
@@ -53,9 +66,9 @@ suite('Search - Viewlet', () => {
let
fileMatch1
=
aFileMatch
(
'
C:
\\
foo
'
);
let
fileMatch2
=
aFileMatch
(
'
C:
\\
with
\\
path
'
);
let
fileMatch3
=
aFileMatch
(
'
C:
\\
with
\\
path
\\
foo
'
);
let
lineMatch1
=
new
Match
(
fileMatch1
,
'
bar
'
,
1
,
1
,
1
);
let
lineMatch2
=
new
Match
(
fileMatch1
,
'
bar
'
,
2
,
1
,
1
);
let
lineMatch3
=
new
Match
(
fileMatch1
,
'
bar
'
,
2
,
1
,
1
);
let
lineMatch1
=
new
Match
(
fileMatch1
,
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
0
,
1
,
1
))
);
let
lineMatch2
=
new
Match
(
fileMatch1
,
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
2
,
1
,
1
))
);
let
lineMatch3
=
new
Match
(
fileMatch1
,
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
2
,
1
,
1
))
);
let
s
=
new
SearchSorter
();
...
...
@@ -69,12 +82,12 @@ suite('Search - Viewlet', () => {
assert
(
s
.
compare
(
null
,
lineMatch2
,
lineMatch3
)
===
0
);
});
function
aFileMatch
(
path
:
string
,
searchResult
?:
SearchResult
,
...
lineMatches
:
I
LineMatch
[]):
FileMatch
{
function
aFileMatch
(
path
:
string
,
searchResult
?:
SearchResult
,
...
lineMatches
:
I
TextSearchResult
[]):
FileMatch
{
let
rawMatch
:
IFileMatch
=
{
resource
:
uri
.
file
(
'
C:
\\
'
+
path
),
lineM
atches
:
lineMatches
m
atches
:
lineMatches
};
return
instantiation
.
createInstance
(
FileMatch
,
null
,
null
,
searchResult
,
rawMatch
);
return
instantiation
.
createInstance
(
FileMatch
,
null
,
null
,
null
,
searchResult
,
rawMatch
);
}
function
stubModelService
(
instantiationService
:
TestInstantiationService
):
IModelService
{
...
...
src/vs/workbench/parts/search/test/common/searchModel.test.ts
浏览文件 @
de70176d
...
...
@@ -16,7 +16,7 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
TestConfigurationService
}
from
'
vs/platform/configuration/test/common/testConfigurationService
'
;
import
{
TestInstantiationService
}
from
'
vs/platform/instantiation/test/common/instantiationServiceMock
'
;
import
{
IFileMatch
,
IFileSearchStats
,
IFolderQuery
,
I
LineMatch
,
ISearchComplete
,
ISearchProgressItem
,
ISearchQuery
,
ISearchServic
e
}
from
'
vs/platform/search/common/search
'
;
import
{
IFileMatch
,
IFileSearchStats
,
IFolderQuery
,
I
SearchComplete
,
ISearchProgressItem
,
ISearchQuery
,
ISearchService
,
ITextSearchResult
,
TextSearchResult
,
OneLineRang
e
}
from
'
vs/platform/search/common/search
'
;
import
{
ITelemetryService
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
NullTelemetryService
}
from
'
vs/platform/telemetry/common/telemetryUtils
'
;
import
{
SearchModel
}
from
'
vs/workbench/parts/search/common/searchModel
'
;
...
...
@@ -41,6 +41,7 @@ const nullEvent = new class {
}
};
const
lineOneRange
=
new
OneLineRange
(
1
,
0
,
1
);
suite
(
'
SearchModel
'
,
()
=>
{
...
...
@@ -104,7 +105,11 @@ suite('SearchModel', () => {
}
test
(
'
Search Model: Search adds to results
'
,
async
()
=>
{
let
results
=
[
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
,
1
,
[[
1
,
3
],
[
4
,
7
]])),
aRawMatch
(
'
file://c:/2
'
,
aLineMatch
(
'
preview 2
'
))];
let
results
=
[
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
1
,
4
)),
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
4
,
11
))),
aRawMatch
(
'
file://c:/2
'
,
new
TextSearchResult
(
'
preview 2
'
,
lineOneRange
))];
instantiationService
.
stub
(
ISearchService
,
searchServiceWithResults
(
results
));
let
testObject
:
SearchModel
=
instantiationService
.
createInstance
(
SearchModel
);
...
...
@@ -130,7 +135,12 @@ suite('SearchModel', () => {
test
(
'
Search Model: Search reports telemetry on search completed
'
,
async
()
=>
{
let
target
=
instantiationService
.
spy
(
ITelemetryService
,
'
publicLog
'
);
let
results
=
[
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
,
1
,
[[
1
,
3
],
[
4
,
7
]])),
aRawMatch
(
'
file://c:/2
'
,
aLineMatch
(
'
preview 2
'
))];
let
results
=
[
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
1
,
4
)),
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
4
,
11
))),
aRawMatch
(
'
file://c:/2
'
,
new
TextSearchResult
(
'
preview 2
'
,
lineOneRange
))];
instantiationService
.
stub
(
ISearchService
,
searchServiceWithResults
(
results
));
let
testObject
:
SearchModel
=
instantiationService
.
createInstance
(
SearchModel
);
...
...
@@ -168,7 +178,7 @@ suite('SearchModel', () => {
instantiationService
.
stub
(
ITelemetryService
,
'
publicLog
'
,
target1
);
instantiationService
.
stub
(
ISearchService
,
searchServiceWithResults
(
[
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
some preview
'
))],
[
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
some preview
'
,
lineOneRange
))],
{
results
:
[],
stats
:
testSearchStats
}));
let
testObject
=
instantiationService
.
createInstance
(
SearchModel
);
...
...
@@ -229,7 +239,12 @@ suite('SearchModel', () => {
});
test
(
'
Search Model: Search results are cleared during search
'
,
async
()
=>
{
let
results
=
[
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
,
1
,
[[
1
,
3
],
[
4
,
7
]])),
aRawMatch
(
'
file://c:/2
'
,
aLineMatch
(
'
preview 2
'
))];
let
results
=
[
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
1
,
4
)),
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
4
,
11
))),
aRawMatch
(
'
file://c:/2
'
,
new
TextSearchResult
(
'
preview 2
'
,
lineOneRange
))];
instantiationService
.
stub
(
ISearchService
,
searchServiceWithResults
(
results
));
let
testObject
:
SearchModel
=
instantiationService
.
createInstance
(
SearchModel
);
await
testObject
.
search
({
contentPattern
:
{
pattern
:
'
somestring
'
},
type
:
1
,
folderQueries
});
...
...
@@ -254,7 +269,10 @@ suite('SearchModel', () => {
});
test
(
'
getReplaceString returns proper replace string for regExpressions
'
,
async
()
=>
{
let
results
=
[
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
,
1
,
[[
1
,
3
],
[
4
,
7
]]))];
let
results
=
[
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
1
,
4
)),
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
4
,
11
)))];
instantiationService
.
stub
(
ISearchService
,
searchServiceWithResults
(
results
));
let
testObject
:
SearchModel
=
instantiationService
.
createInstance
(
SearchModel
);
...
...
@@ -281,12 +299,8 @@ suite('SearchModel', () => {
assert
.
equal
(
'
helloe
'
,
match
.
replaceString
);
});
function
aRawMatch
(
resource
:
string
,
...
lineMatches
:
ILineMatch
[]):
IFileMatch
{
return
{
resource
:
URI
.
parse
(
resource
),
lineMatches
};
}
function
aLineMatch
(
preview
:
string
,
lineNumber
:
number
=
1
,
offsetAndLengths
:
number
[][]
=
[[
0
,
1
]]):
ILineMatch
{
return
{
preview
,
lineNumber
,
offsetAndLengths
};
function
aRawMatch
(
resource
:
string
,
...
matches
:
ITextSearchResult
[]):
IFileMatch
{
return
{
resource
:
URI
.
parse
(
resource
),
matches
};
}
function
stub
(
arg1
:
any
,
arg2
:
any
,
arg3
:
any
):
sinon
.
SinonStub
{
...
...
src/vs/workbench/parts/search/test/common/searchResult.test.ts
浏览文件 @
de70176d
...
...
@@ -9,7 +9,7 @@ import * as sinon from 'sinon';
import
{
TestInstantiationService
}
from
'
vs/platform/instantiation/test/common/instantiationServiceMock
'
;
import
{
Match
,
FileMatch
,
SearchResult
,
SearchModel
}
from
'
vs/workbench/parts/search/common/searchModel
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
IFileMatch
,
ILineMatch
}
from
'
vs/platform/search/common/search
'
;
import
{
IFileMatch
,
TextSearchResult
,
OneLineRange
,
ITextSearchResult
}
from
'
vs/platform/search/common/search
'
;
import
{
ITelemetryService
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
NullTelemetryService
}
from
'
vs/platform/telemetry/common/telemetryUtils
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
...
...
@@ -19,6 +19,8 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import
{
IModelService
}
from
'
vs/editor/common/services/modelService
'
;
import
{
IReplaceService
}
from
'
vs/workbench/parts/search/common/replace
'
;
const
lineOneRange
=
new
OneLineRange
(
1
,
0
,
1
);
suite
(
'
SearchResult
'
,
()
=>
{
let
instantiationService
:
TestInstantiationService
;
...
...
@@ -33,21 +35,17 @@ suite('SearchResult', () => {
test
(
'
Line Match
'
,
function
()
{
let
fileMatch
=
aFileMatch
(
'
folder/file.txt
'
,
null
);
let
lineMatch
=
new
Match
(
fileMatch
,
'
foo bar
'
,
1
,
0
,
3
);
let
lineMatch
=
new
Match
(
fileMatch
,
new
TextSearchResult
(
'
foo bar
'
,
new
OneLineRange
(
1
,
0
,
3
))
);
assert
.
equal
(
lineMatch
.
text
(),
'
foo bar
'
);
assert
.
equal
(
lineMatch
.
range
().
startLineNumber
,
2
);
assert
.
equal
(
lineMatch
.
range
().
endLineNumber
,
2
);
assert
.
equal
(
lineMatch
.
range
().
startColumn
,
1
);
assert
.
equal
(
lineMatch
.
range
().
endColumn
,
4
);
assert
.
equal
(
'
file:///folder/file.txt>
1>0
foo
'
,
lineMatch
.
id
());
assert
.
equal
(
'
file:///folder/file.txt>
[2,1 -> 2,4]
foo
'
,
lineMatch
.
id
());
});
test
(
'
Line Match - Remove
'
,
function
()
{
let
fileMatch
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
...[{
preview
:
'
foo bar
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
0
,
3
]]
}]);
let
fileMatch
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
new
TextSearchResult
(
'
foo bar
'
,
new
OneLineRange
(
1
,
0
,
3
)));
let
lineMatch
=
fileMatch
.
matches
()[
0
];
fileMatch
.
remove
(
lineMatch
);
assert
.
equal
(
fileMatch
.
matches
().
length
,
0
);
...
...
@@ -66,15 +64,11 @@ suite('SearchResult', () => {
});
test
(
'
File Match: Select an existing match
'
,
function
()
{
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
...[{
preview
:
'
foo
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
0
,
3
]]
},
{
preview
:
'
bar
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
5
,
3
]]
}]);
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
new
TextSearchResult
(
'
foo
'
,
new
OneLineRange
(
1
,
0
,
3
)),
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
1
,
5
,
3
)));
testObject
.
setSelectedMatch
(
testObject
.
matches
()[
0
]);
...
...
@@ -82,15 +76,11 @@ suite('SearchResult', () => {
});
test
(
'
File Match: Select non existing match
'
,
function
()
{
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
...[{
preview
:
'
foo
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
0
,
3
]]
},
{
preview
:
'
bar
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
5
,
3
]]
}]);
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
new
TextSearchResult
(
'
foo
'
,
new
OneLineRange
(
1
,
0
,
3
)),
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
1
,
5
,
3
)));
let
target
=
testObject
.
matches
()[
0
];
testObject
.
remove
(
target
);
...
...
@@ -100,15 +90,11 @@ suite('SearchResult', () => {
});
test
(
'
File Match: isSelected return true for selected match
'
,
function
()
{
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
...[{
preview
:
'
foo
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
0
,
3
]]
},
{
preview
:
'
bar
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
5
,
3
]]
}]);
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
new
TextSearchResult
(
'
foo
'
,
new
OneLineRange
(
1
,
0
,
3
)),
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
1
,
5
,
3
)));
let
target
=
testObject
.
matches
()[
0
];
testObject
.
setSelectedMatch
(
target
);
...
...
@@ -116,32 +102,20 @@ suite('SearchResult', () => {
});
test
(
'
File Match: isSelected return false for un-selected match
'
,
function
()
{
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
...[{
preview
:
'
foo
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
0
,
3
]]
},
{
preview
:
'
bar
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
5
,
3
]]
}]);
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
new
TextSearchResult
(
'
foo
'
,
new
OneLineRange
(
1
,
0
,
3
)),
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
1
,
5
,
3
)));
testObject
.
setSelectedMatch
(
testObject
.
matches
()[
0
]);
assert
.
ok
(
!
testObject
.
isMatchSelected
(
testObject
.
matches
()[
1
]));
});
test
(
'
File Match: unselect
'
,
function
()
{
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
...[{
preview
:
'
foo
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
0
,
3
]]
},
{
preview
:
'
bar
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
5
,
3
]]
}]);
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
new
TextSearchResult
(
'
foo
'
,
new
OneLineRange
(
1
,
0
,
3
)),
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
1
,
5
,
3
)));
testObject
.
setSelectedMatch
(
testObject
.
matches
()[
0
]);
testObject
.
setSelectedMatch
(
null
);
...
...
@@ -149,16 +123,11 @@ suite('SearchResult', () => {
});
test
(
'
File Match: unselect when not selected
'
,
function
()
{
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
...[{
preview
:
'
foo
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
0
,
3
]]
},
{
preview
:
'
bar
'
,
lineNumber
:
1
,
offsetAndLengths
:
[[
5
,
3
]]
}]);
let
testObject
=
aFileMatch
(
'
folder/file.txt
'
,
aSearchResult
(),
new
TextSearchResult
(
'
foo
'
,
new
OneLineRange
(
1
,
0
,
3
)),
new
TextSearchResult
(
'
bar
'
,
new
OneLineRange
(
1
,
5
,
3
)));
testObject
.
setSelectedMatch
(
null
);
assert
.
equal
(
null
,
testObject
.
getSelectedMatch
());
...
...
@@ -167,7 +136,7 @@ suite('SearchResult', () => {
test
(
'
Alle Drei Zusammen
'
,
function
()
{
let
searchResult
=
instantiationService
.
createInstance
(
SearchResult
,
null
);
let
fileMatch
=
aFileMatch
(
'
far/boo
'
,
searchResult
);
let
lineMatch
=
new
Match
(
fileMatch
,
'
foo bar
'
,
1
,
0
,
3
);
let
lineMatch
=
new
Match
(
fileMatch
,
new
TextSearchResult
(
'
foo bar
'
,
new
OneLineRange
(
1
,
0
,
3
))
);
assert
(
lineMatch
.
parent
()
===
fileMatch
);
assert
(
fileMatch
.
parent
()
===
searchResult
);
...
...
@@ -175,7 +144,10 @@ suite('SearchResult', () => {
test
(
'
Adding a raw match will add a file match with line matches
'
,
function
()
{
let
testObject
=
aSearchResult
();
let
target
=
[
aRawMatch
(
'
file://c:/
'
,
aLineMatch
(
'
preview 1
'
,
1
,
[[
1
,
3
],
[
4
,
7
]]),
aLineMatch
(
'
preview 2
'
))];
let
target
=
[
aRawMatch
(
'
file://c:/
'
,
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
1
,
4
)),
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
4
,
11
)),
new
TextSearchResult
(
'
preview 2
'
,
lineOneRange
))];
testObject
.
add
(
target
);
...
...
@@ -200,7 +172,12 @@ suite('SearchResult', () => {
test
(
'
Adding multiple raw matches
'
,
function
()
{
let
testObject
=
aSearchResult
();
let
target
=
[
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
,
1
,
[[
1
,
3
],
[
4
,
7
]])),
aRawMatch
(
'
file://c:/2
'
,
aLineMatch
(
'
preview 2
'
))];
let
target
=
[
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
1
,
4
)),
new
TextSearchResult
(
'
preview 1
'
,
new
OneLineRange
(
1
,
4
,
11
))),
aRawMatch
(
'
file://c:/2
'
,
new
TextSearchResult
(
'
preview 2
'
,
lineOneRange
))];
testObject
.
add
(
target
);
...
...
@@ -228,7 +205,11 @@ suite('SearchResult', () => {
let
target2
=
sinon
.
spy
();
let
testObject
=
aSearchResult
();
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
)),
aRawMatch
(
'
file://c:/2
'
,
aLineMatch
(
'
preview 2
'
))]);
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
lineOneRange
)),
aRawMatch
(
'
file://c:/2
'
,
new
TextSearchResult
(
'
preview 2
'
,
lineOneRange
))]);
testObject
.
matches
()[
0
].
onDispose
(
target1
);
testObject
.
matches
()[
1
].
onDispose
(
target2
);
...
...
@@ -243,7 +224,9 @@ suite('SearchResult', () => {
test
(
'
remove triggers change event
'
,
function
()
{
let
target
=
sinon
.
spy
();
let
testObject
=
aSearchResult
();
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
))]);
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
lineOneRange
))]);
let
objectRoRemove
=
testObject
.
matches
()[
0
];
testObject
.
onChange
(
target
);
...
...
@@ -256,7 +239,9 @@ suite('SearchResult', () => {
test
(
'
remove triggers change event
'
,
function
()
{
let
target
=
sinon
.
spy
();
let
testObject
=
aSearchResult
();
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
))]);
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
lineOneRange
))]);
let
objectRoRemove
=
testObject
.
matches
()[
0
];
testObject
.
onChange
(
target
);
...
...
@@ -268,7 +253,9 @@ suite('SearchResult', () => {
test
(
'
Removing all line matches and adding back will add file back to result
'
,
function
()
{
let
testObject
=
aSearchResult
();
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
))]);
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
lineOneRange
))]);
let
target
=
testObject
.
matches
()[
0
];
let
matchToRemove
=
target
.
matches
()[
0
];
target
.
remove
(
matchToRemove
);
...
...
@@ -283,7 +270,9 @@ suite('SearchResult', () => {
test
(
'
replace should remove the file match
'
,
function
()
{
instantiationService
.
stubPromise
(
IReplaceService
,
'
replace
'
,
null
);
let
testObject
=
aSearchResult
();
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
))]);
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
lineOneRange
))]);
testObject
.
replace
(
testObject
.
matches
()[
0
]);
...
...
@@ -294,7 +283,9 @@ suite('SearchResult', () => {
let
target
=
sinon
.
spy
();
instantiationService
.
stubPromise
(
IReplaceService
,
'
replace
'
,
null
);
let
testObject
=
aSearchResult
();
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
))]);
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
lineOneRange
))]);
testObject
.
onChange
(
target
);
let
objectRoRemove
=
testObject
.
matches
()[
0
];
...
...
@@ -307,7 +298,11 @@ suite('SearchResult', () => {
test
(
'
replaceAll should remove all file matches
'
,
function
()
{
instantiationService
.
stubPromise
(
IReplaceService
,
'
replace
'
,
null
);
let
testObject
=
aSearchResult
();
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
aLineMatch
(
'
preview 1
'
)),
aRawMatch
(
'
file://c:/2
'
,
aLineMatch
(
'
preview 2
'
))]);
testObject
.
add
([
aRawMatch
(
'
file://c:/1
'
,
new
TextSearchResult
(
'
preview 1
'
,
lineOneRange
)),
aRawMatch
(
'
file://c:/2
'
,
new
TextSearchResult
(
'
preview 2
'
,
lineOneRange
))]);
testObject
.
replaceAll
(
null
);
...
...
@@ -358,12 +353,12 @@ suite('SearchResult', () => {
// lineHasNoDecoration(oneModel, 2);
//});
function
aFileMatch
(
path
:
string
,
searchResult
?:
SearchResult
,
...
lineMatches
:
I
LineMatch
[]):
FileMatch
{
function
aFileMatch
(
path
:
string
,
searchResult
?:
SearchResult
,
...
lineMatches
:
I
TextSearchResult
[]):
FileMatch
{
let
rawMatch
:
IFileMatch
=
{
resource
:
URI
.
file
(
'
/
'
+
path
),
lineM
atches
:
lineMatches
m
atches
:
lineMatches
};
return
instantiationService
.
createInstance
(
FileMatch
,
null
,
null
,
searchResult
,
rawMatch
);
return
instantiationService
.
createInstance
(
FileMatch
,
null
,
null
,
null
,
searchResult
,
rawMatch
);
}
function
aSearchResult
():
SearchResult
{
...
...
@@ -372,12 +367,8 @@ suite('SearchResult', () => {
return
searchModel
.
searchResult
;
}
function
aRawMatch
(
resource
:
string
,
...
lineMatches
:
ILineMatch
[]):
IFileMatch
{
return
{
resource
:
URI
.
parse
(
resource
),
lineMatches
};
}
function
aLineMatch
(
preview
:
string
,
lineNumber
:
number
=
1
,
offsetAndLengths
:
number
[][]
=
[[
0
,
1
]]):
ILineMatch
{
return
{
preview
,
lineNumber
,
offsetAndLengths
};
function
aRawMatch
(
resource
:
string
,
...
matches
:
ITextSearchResult
[]):
IFileMatch
{
return
{
resource
:
URI
.
parse
(
resource
),
matches
};
}
function
stubModelService
(
instantiationService
:
TestInstantiationService
):
IModelService
{
...
...
src/vs/workbench/services/search/node/ripgrepTextSearch.ts
浏览文件 @
de70176d
...
...
@@ -16,9 +16,10 @@ import * as strings from 'vs/base/common/strings';
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
*
as
encoding
from
'
vs/base/node/encoding
'
;
import
*
as
extfs
from
'
vs/base/node/extfs
'
;
import
{
IProgress
,
ITextSearchStats
}
from
'
vs/platform/search/common/search
'
;
import
{
IRange
,
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
IProgress
,
ITextSearchPreviewOptions
,
ITextSearchStats
,
TextSearchResult
}
from
'
vs/platform/search/common/search
'
;
import
{
rgPath
}
from
'
vscode-ripgrep
'
;
import
{
FileMatch
,
IFolderSearch
,
IRawSearch
,
ISerializedFileMatch
,
LineMatch
,
ISerializedSearchSuccess
}
from
'
./search
'
;
import
{
FileMatch
,
IFolderSearch
,
IRawSearch
,
ISerializedFileMatch
,
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
'
);
...
...
@@ -77,7 +78,7 @@ export class RipgrepEngine {
this
.
rgProc
=
cp
.
spawn
(
rgDiskPath
,
rgArgs
.
args
,
{
cwd
});
process
.
once
(
'
exit
'
,
this
.
killRgProcFn
);
this
.
ripgrepParser
=
new
RipgrepParser
(
this
.
config
.
maxResults
,
cwd
,
this
.
config
.
extraFiles
);
this
.
ripgrepParser
=
new
RipgrepParser
(
this
.
config
.
maxResults
,
cwd
,
this
.
config
.
extraFiles
,
this
.
config
.
previewOptions
);
this
.
ripgrepParser
.
on
(
'
result
'
,
(
match
:
ISerializedFileMatch
)
=>
{
if
(
this
.
postProcessExclusions
)
{
const
handleResultP
=
(
<
TPromise
<
string
>>
this
.
postProcessExclusions
(
match
.
path
,
undefined
,
glob
.
hasSiblingPromiseFn
(()
=>
getSiblings
(
match
.
path
))))
...
...
@@ -197,7 +198,7 @@ export class RipgrepParser extends EventEmitter {
private
numResults
=
0
;
constructor
(
private
maxResults
:
number
,
private
rootFolder
:
string
,
extraFiles
?:
string
[])
{
constructor
(
private
maxResults
:
number
,
private
rootFolder
:
string
,
extraFiles
?:
string
[]
,
private
previewOptions
?:
ITextSearchPreviewOptions
)
{
super
();
this
.
stringDecoder
=
new
StringDecoder
();
...
...
@@ -275,7 +276,6 @@ export class RipgrepParser extends EventEmitter {
text
=
strings
.
stripUTF8BOM
(
text
);
}
const
lineMatch
=
new
LineMatch
(
text
,
lineNum
);
if
(
!
this
.
fileMatch
)
{
// When searching a single file and no folderQueries, rg does not print the file line, so create it here
const
singleFile
=
this
.
extraSearchFiles
[
0
];
...
...
@@ -286,8 +286,6 @@ export class RipgrepParser extends EventEmitter {
this
.
fileMatch
=
this
.
getFileMatch
(
singleFile
);
}
this
.
fileMatch
.
addMatch
(
lineMatch
);
let
lastMatchEndPos
=
0
;
let
matchTextStartPos
=
-
1
;
...
...
@@ -296,6 +294,7 @@ export class RipgrepParser extends EventEmitter {
let
textRealIdx
=
0
;
let
hitLimit
=
false
;
const
matchRanges
:
IRange
[]
=
[];
const
realTextParts
:
string
[]
=
[];
for
(
let
i
=
0
;
i
<
text
.
length
-
(
RipgrepParser
.
MATCH_END_MARKER
.
length
-
1
);)
{
...
...
@@ -311,7 +310,7 @@ export class RipgrepParser extends EventEmitter {
const
chunk
=
text
.
slice
(
matchTextStartPos
,
i
);
realTextParts
.
push
(
chunk
);
if
(
!
hitLimit
)
{
lineMatch
.
addMatch
(
matchTextStartRealIdx
,
textRealIdx
-
matchTextStartRealIdx
);
matchRanges
.
push
(
new
Range
(
lineNum
,
matchTextStartRealIdx
,
lineNum
,
textRealIdx
)
);
}
matchTextStartPos
=
-
1
;
...
...
@@ -336,7 +335,9 @@ export class RipgrepParser extends EventEmitter {
// Replace preview with version without color codes
const
preview
=
realTextParts
.
join
(
''
);
lineMatch
.
preview
=
preview
;
matchRanges
.
map
(
r
=>
new
TextSearchResult
(
preview
,
r
,
this
.
previewOptions
))
.
forEach
(
m
=>
this
.
fileMatch
.
addMatch
(
m
));
if
(
hitLimit
)
{
this
.
cancel
();
...
...
src/vs/workbench/services/search/node/search.ts
浏览文件 @
de70176d
...
...
@@ -5,11 +5,11 @@
'
use strict
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
IExpression
}
from
'
vs/base/common/glob
'
;
import
{
IProgress
,
ILineMatch
,
IPatternInfo
,
IFileSearchStats
,
ISearchEngineStats
,
ITextSearchStats
}
from
'
vs/platform/search/common/search
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IFileSearchStats
,
IPatternInfo
,
IProgress
,
ISearchEngineStats
,
ITextSearchPreviewOptions
,
ITextSearchResult
,
ITextSearchStats
}
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
;
...
...
@@ -34,6 +34,7 @@ export interface IRawSearch {
maxFilesize
?:
number
;
useRipgrep
?:
boolean
;
disregardIgnoreFiles
?:
boolean
;
previewOptions
?:
ITextSearchPreviewOptions
;
}
export
interface
ITelemetryEvent
{
...
...
@@ -96,7 +97,7 @@ export function isSerializedSearchSuccess(arg: ISerializedSearchComplete): arg i
export
interface
ISerializedFileMatch
{
path
:
string
;
lineMatches
?:
ILineMatch
[];
matches
?:
ITextSearchResult
[];
numMatches
?:
number
;
}
...
...
@@ -107,56 +108,22 @@ export type IFileSearchProgressItem = IRawFileMatch | IRawFileMatch[] | IProgres
export
class
FileMatch
implements
ISerializedFileMatch
{
path
:
string
;
lineMatches
:
LineMatch
[];
matches
:
ITextSearchResult
[];
constructor
(
path
:
string
)
{
this
.
path
=
path
;
this
.
lineM
atches
=
[];
this
.
m
atches
=
[];
}
addMatch
(
lineMatch
:
LineMatch
):
void
{
this
.
lineMatches
.
push
(
lineM
atch
);
addMatch
(
match
:
ITextSearchResult
):
void
{
this
.
matches
.
push
(
m
atch
);
}
serialize
():
ISerializedFileMatch
{
let
lineMatches
:
ILineMatch
[]
=
[];
let
numMatches
=
0
;
for
(
let
i
=
0
;
i
<
this
.
lineMatches
.
length
;
i
++
)
{
numMatches
+=
this
.
lineMatches
[
i
].
offsetAndLengths
.
length
;
lineMatches
.
push
(
this
.
lineMatches
[
i
].
serialize
());
}
return
{
path
:
this
.
path
,
lineM
atches
,
numMatches
matches
:
this
.
m
atches
,
numMatches
:
this
.
matches
.
length
};
}
}
export
class
LineMatch
implements
ILineMatch
{
preview
:
string
;
lineNumber
:
number
;
offsetAndLengths
:
number
[][];
constructor
(
preview
:
string
,
lineNumber
:
number
)
{
this
.
preview
=
preview
.
replace
(
/
(\r
|
\n)
*$/
,
''
);
this
.
lineNumber
=
lineNumber
;
this
.
offsetAndLengths
=
[];
}
addMatch
(
offset
:
number
,
length
:
number
):
void
{
this
.
offsetAndLengths
.
push
([
offset
,
length
]);
}
serialize
():
ILineMatch
{
const
result
=
{
preview
:
this
.
preview
,
lineNumber
:
this
.
lineNumber
,
offsetAndLengths
:
this
.
offsetAndLengths
};
return
result
;
}
}
\ No newline at end of file
src/vs/workbench/services/search/node/searchService.ts
浏览文件 @
de70176d
...
...
@@ -22,13 +22,14 @@ import { IModelService } from 'vs/editor/common/services/modelService';
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
IDebugParams
,
IEnvironmentService
}
from
'
vs/platform/environment/common/environment
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
FileMatch
,
ICachedSearchStats
,
IFileMatch
,
IFolderQuery
,
IProgress
,
ISearchComplete
,
ISearchConfiguration
,
ISearchEngineStats
,
ISearchProgressItem
,
ISearchQuery
,
ISearchResultProvider
,
ISearchService
,
LineMatch
,
pathIncludedInQuery
,
QueryType
,
SearchProviderType
,
IFileSearchStats
}
from
'
vs/platform/search/common/search
'
;
import
{
FileMatch
,
ICachedSearchStats
,
IFileMatch
,
IFolderQuery
,
IProgress
,
ISearchComplete
,
ISearchConfiguration
,
ISearchEngineStats
,
ISearchProgressItem
,
ISearchQuery
,
ISearchResultProvider
,
ISearchService
,
pathIncludedInQuery
,
QueryType
,
SearchProviderType
,
IFileSearchStats
,
TextSearchResult
}
from
'
vs/platform/search/common/search
'
;
import
{
ITelemetryService
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
IEditorService
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
IExtensionService
}
from
'
vs/workbench/services/extensions/common/extensions
'
;
import
{
IUntitledEditorService
}
from
'
vs/workbench/services/untitled/common/untitledEditorService
'
;
import
{
IRawSearch
,
IRawSearchService
,
ISerializedFileMatch
,
ISerializedSearchComplete
,
ISerializedSearchProgressItem
,
isSerializedSearchComplete
,
isSerializedSearchSuccess
}
from
'
./search
'
;
import
{
ISearchChannel
,
SearchChannelClient
}
from
'
./searchIpc
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
export
class
SearchService
extends
Disposable
implements
ISearchService
{
public
_serviceBrand
:
any
;
...
...
@@ -346,7 +347,10 @@ export class SearchService extends Disposable implements ISearchService {
localResults
.
set
(
resource
,
fileMatch
);
matches
.
forEach
((
match
)
=>
{
fileMatch
.
lineMatches
.
push
(
new
LineMatch
(
model
.
getLineContent
(
match
.
range
.
startLineNumber
),
match
.
range
.
startLineNumber
-
1
,
[[
match
.
range
.
startColumn
-
1
,
match
.
range
.
endColumn
-
match
.
range
.
startColumn
]]));
fileMatch
.
matches
.
push
(
new
TextSearchResult
(
model
.
getLineContent
(
match
.
range
.
startLineNumber
),
new
Range
(
match
.
range
.
startLineNumber
-
1
,
match
.
range
.
startColumn
-
1
,
match
.
range
.
startLineNumber
-
1
,
match
.
range
.
endColumn
),
query
.
previewOptions
));
});
}
else
{
localResults
.
set
(
resource
,
null
);
...
...
@@ -458,7 +462,8 @@ export class DiskSearch implements ISearchResultProvider {
cacheKey
:
query
.
cacheKey
,
useRipgrep
:
query
.
useRipgrep
,
disregardIgnoreFiles
:
query
.
disregardIgnoreFiles
,
ignoreSymlinks
:
query
.
ignoreSymlinks
ignoreSymlinks
:
query
.
ignoreSymlinks
,
previewOptions
:
query
.
previewOptions
};
for
(
const
q
of
existingFolders
)
{
...
...
@@ -536,10 +541,8 @@ export class DiskSearch implements ISearchResultProvider {
private
static
createFileMatch
(
data
:
ISerializedFileMatch
):
FileMatch
{
let
fileMatch
=
new
FileMatch
(
uri
.
file
(
data
.
path
));
if
(
data
.
lineMatches
)
{
for
(
let
j
=
0
;
j
<
data
.
lineMatches
.
length
;
j
++
)
{
fileMatch
.
lineMatches
.
push
(
new
LineMatch
(
data
.
lineMatches
[
j
].
preview
,
data
.
lineMatches
[
j
].
lineNumber
,
data
.
lineMatches
[
j
].
offsetAndLengths
));
}
if
(
data
.
matches
)
{
fileMatch
.
matches
.
push
(...
data
.
matches
);
// TODO why
}
return
fileMatch
;
}
...
...
src/vs/workbench/services/search/node/textSearch.ts
浏览文件 @
de70176d
...
...
@@ -11,7 +11,7 @@ import { IProgress } from 'vs/platform/search/common/search';
import
{
FileWalker
}
from
'
vs/workbench/services/search/node/fileSearch
'
;
import
{
IRawSearch
,
ISearchEngine
,
ISearchEngineSuccess
,
ISerializedFileMatch
}
from
'
./search
'
;
import
{
ITextSearchWorkerProvider
}
from
'
./textSearchWorkerProvider
'
;
import
{
ISearchWorker
}
from
'
./worker/searchWorkerIpc
'
;
import
{
ISearchWorker
,
ISearchWorkerSearchArgs
}
from
'
./worker/searchWorkerIpc
'
;
export
class
Engine
implements
ISearchEngine
<
ISerializedFileMatch
[]
>
{
...
...
@@ -95,7 +95,7 @@ export class Engine implements ISearchEngine<ISerializedFileMatch[]> {
this
.
nextWorker
=
(
this
.
nextWorker
+
1
)
%
this
.
workers
.
length
;
const
maxResults
=
this
.
config
.
maxResults
&&
(
this
.
config
.
maxResults
-
this
.
numResults
);
const
searchArgs
=
{
absolutePaths
:
batch
,
maxResults
,
pattern
:
this
.
config
.
contentPattern
,
fileEncoding
};
const
searchArgs
:
ISearchWorkerSearchArgs
=
{
absolutePaths
:
batch
,
maxResults
,
pattern
:
this
.
config
.
contentPattern
,
fileEncoding
,
previewOptions
:
this
.
config
.
previewOptions
};
worker
.
search
(
searchArgs
).
then
(
result
=>
{
if
(
!
result
||
this
.
limitReached
||
this
.
isCanceled
)
{
return
unwind
(
batchBytes
);
...
...
src/vs/workbench/services/search/node/worker/searchWorker.ts
浏览文件 @
de70176d
...
...
@@ -7,16 +7,17 @@
import
*
as
fs
from
'
fs
'
;
import
*
as
gracefulFs
from
'
graceful-fs
'
;
gracefulFs
.
gracefulify
(
fs
);
import
{
onUnexpectedError
}
from
'
vs/base/common/errors
'
;
import
*
as
strings
from
'
vs/base/common/strings
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
LineMatch
,
FileMatch
}
from
'
../search
'
;
import
{
UTF16le
,
UTF16be
,
UTF8
,
UTF8_with_bom
,
encodingExists
,
decode
,
bomLength
,
detectEncodingFromBuffer
}
from
'
vs/base/node/encoding
'
;
import
{
bomLength
,
decode
,
detectEncodingFromBuffer
,
encodingExists
,
UTF16be
,
UTF16le
,
UTF8
,
UTF8_with_bom
}
from
'
vs/base/node/encoding
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
ITextSearchPreviewOptions
,
TextSearchResult
}
from
'
vs/platform/search/common/search
'
;
import
{
FileMatch
}
from
'
../search
'
;
import
{
ISearchWorker
,
ISearchWorkerSearchArgs
,
ISearchWorkerSearchResult
}
from
'
./searchWorkerIpc
'
;
gracefulFs
.
gracefulify
(
fs
);
interface
ReadLinesOptions
{
bufferLength
:
number
;
encoding
:
string
;
...
...
@@ -95,7 +96,7 @@ export class SearchWorkerEngine {
// Search in the given path, and when it's finished, search in the next path in absolutePaths
const
startSearchInFile
=
(
absolutePath
:
string
):
TPromise
<
void
>
=>
{
return
this
.
searchInFile
(
absolutePath
,
contentPattern
,
fileEncoding
,
args
.
maxResults
&&
(
args
.
maxResults
-
result
.
numMatches
)).
then
(
fileResult
=>
{
return
this
.
searchInFile
(
absolutePath
,
contentPattern
,
fileEncoding
,
args
.
maxResults
&&
(
args
.
maxResults
-
result
.
numMatches
)
,
args
.
previewOptions
).
then
(
fileResult
=>
{
// Finish early if search is canceled
if
(
this
.
isCanceled
)
{
return
;
...
...
@@ -124,13 +125,12 @@ export class SearchWorkerEngine {
this
.
isCanceled
=
true
;
}
private
searchInFile
(
absolutePath
:
string
,
contentPattern
:
RegExp
,
fileEncoding
:
string
,
maxResults
?:
number
):
TPromise
<
IFileSearchResult
>
{
private
searchInFile
(
absolutePath
:
string
,
contentPattern
:
RegExp
,
fileEncoding
:
string
,
maxResults
?:
number
,
previewOptions
?:
ITextSearchPreviewOptions
):
TPromise
<
IFileSearchResult
>
{
let
fileMatch
:
FileMatch
=
null
;
let
limitReached
=
false
;
let
numMatches
=
0
;
const
perLineCallback
=
(
line
:
string
,
lineNumber
:
number
)
=>
{
let
lineMatch
:
LineMatch
=
null
;
let
match
=
contentPattern
.
exec
(
line
);
// Record all matches into file result
...
...
@@ -139,12 +139,8 @@ export class SearchWorkerEngine {
fileMatch
=
new
FileMatch
(
absolutePath
);
}
if
(
lineMatch
===
null
)
{
lineMatch
=
new
LineMatch
(
line
,
lineNumber
);
fileMatch
.
addMatch
(
lineMatch
);
}
lineMatch
.
addMatch
(
match
.
index
,
match
[
0
].
length
);
const
lineMatch
=
new
TextSearchResult
(
line
,
new
Range
(
lineNumber
,
match
.
index
,
lineNumber
,
match
.
index
+
match
[
0
].
length
),
previewOptions
);
fileMatch
.
addMatch
(
lineMatch
);
numMatches
++
;
if
(
maxResults
&&
numMatches
>=
maxResults
)
{
...
...
src/vs/workbench/services/search/node/worker/searchWorkerIpc.ts
浏览文件 @
de70176d
...
...
@@ -8,7 +8,7 @@
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IChannel
}
from
'
vs/base/parts/ipc/node/ipc
'
;
import
{
ISerializedFileMatch
}
from
'
../search
'
;
import
{
IPatternInfo
}
from
'
vs/platform/search/common/search
'
;
import
{
IPatternInfo
,
ITextSearchPreviewOptions
}
from
'
vs/platform/search/common/search
'
;
import
{
SearchWorker
}
from
'
./searchWorker
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
...
...
@@ -17,6 +17,7 @@ export interface ISearchWorkerSearchArgs {
fileEncoding
:
string
;
absolutePaths
:
string
[];
maxResults
?:
number
;
previewOptions
?:
ITextSearchPreviewOptions
;
}
export
interface
ISearchWorkerSearchResult
{
...
...
src/vs/workbench/services/search/test/node/ripgrepTextSearch.test.ts
浏览文件 @
de70176d
...
...
@@ -5,16 +5,13 @@
'
use strict
'
;
import
*
as
path
from
'
path
'
;
import
*
as
assert
from
'
assert
'
;
import
*
as
path
from
'
path
'
;
import
*
as
arrays
from
'
vs/base/common/arrays
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
{
RipgrepParser
,
getAbsoluteGlob
,
fixDriveC
,
fixRegexEndingPattern
}
from
'
vs/workbench/services/search/node/ripgrepTextSearch
'
;
import
{
fixDriveC
,
fixRegexEndingPattern
,
getAbsoluteGlob
,
RipgrepParser
}
from
'
vs/workbench/services/search/node/ripgrepTextSearch
'
;
import
{
ISerializedFileMatch
}
from
'
vs/workbench/services/search/node/search
'
;
suite
(
'
RipgrepParser
'
,
()
=>
{
const
rootFolder
=
'
/workspace
'
;
const
fileSectionEnd
=
'
\n
'
;
...
...
@@ -76,16 +73,40 @@ suite('RipgrepParser', () => {
<
ISerializedFileMatch
>
{
numMatches
:
2
,
path
:
path
.
join
(
rootFolder
,
'
a.txt
'
),
lineM
atches
:
[
m
atches
:
[
{
lineNumber
:
0
,
preview
:
'
beforematchafter
'
,
offsetAndLengths
:
[[
6
,
5
]]
preview
:
{
match
:
{
endColumn
:
11
,
endLineNumber
:
0
,
startColumn
:
6
,
startLineNumber
:
0
,
},
text
:
'
beforematchafter
'
},
range
:
{
endColumn
:
11
,
endLineNumber
:
0
,
startColumn
:
6
,
startLineNumber
:
0
,
}
},
{
lineNumber
:
1
,
preview
:
'
beforematchafter
'
,
offsetAndLengths
:
[[
6
,
5
]]
preview
:
{
match
:
{
endColumn
:
11
,
endLineNumber
:
0
,
startColumn
:
6
,
startLineNumber
:
0
,
},
text
:
'
beforematchafter
'
},
range
:
{
endColumn
:
11
,
endLineNumber
:
1
,
startColumn
:
6
,
startLineNumber
:
1
,
}
}
]
});
...
...
@@ -168,8 +189,9 @@ suite('RipgrepParser', () => {
const
results
=
parseInput
(
inputBufs
);
assert
.
equal
(
results
.
length
,
1
);
assert
.
equal
(
results
[
0
].
lineMatches
.
length
,
1
);
assert
.
deepEqual
(
results
[
0
].
lineMatches
[
0
].
offsetAndLengths
,
[[
7
,
5
]]);
assert
.
equal
(
results
[
0
].
matches
.
length
,
1
);
assert
.
equal
(
results
[
0
].
matches
[
0
].
range
.
startColumn
,
7
);
assert
.
equal
(
results
[
0
].
matches
[
0
].
range
.
endColumn
,
12
);
}
});
});
...
...
src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts
浏览文件 @
de70176d
...
...
@@ -650,14 +650,15 @@ suite('ExtHostSearch', () => {
const
actualTextSearchResults
:
vscode
.
TextSearchResult
[]
=
[];
for
(
let
fileMatch
of
actual
)
{
// Make relative
for
(
let
lineMatch
of
fileMatch
.
lineMatches
)
{
for
(
let
[
offset
,
length
]
of
lineMatch
.
offsetAndLengths
)
{
actualTextSearchResults
.
push
({
preview
:
{
text
:
lineMatch
.
preview
,
match
:
null
},
range
:
new
Range
(
lineMatch
.
lineNumber
,
offset
,
lineMatch
.
lineNumber
,
length
+
offset
),
uri
:
fileMatch
.
resource
});
}
for
(
let
lineMatch
of
fileMatch
.
matches
)
{
actualTextSearchResults
.
push
({
preview
:
{
text
:
lineMatch
.
preview
.
text
,
match
:
new
Range
(
lineMatch
.
preview
.
match
.
startLineNumber
,
lineMatch
.
preview
.
match
.
startColumn
,
lineMatch
.
preview
.
match
.
endLineNumber
,
lineMatch
.
preview
.
match
.
endColumn
)
},
range
:
new
Range
(
lineMatch
.
range
.
startLineNumber
,
lineMatch
.
range
.
startColumn
,
lineMatch
.
range
.
endLineNumber
,
lineMatch
.
range
.
endColumn
),
uri
:
fileMatch
.
resource
});
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录