Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
f38c5007
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,发现更多精彩内容 >>
提交
f38c5007
编写于
1月 22, 2020
作者:
J
Jackson Kearl
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add SearchEditorInput instantiation manager and enable hot exit in search editors
上级
c4d53a19
变更
7
展开全部
显示空白变更内容
内联
并排
Showing
7 changed file
with
650 addition
and
46 deletion
+650
-46
src/vs/workbench/contrib/search/browser/search.contribution.ts
...s/workbench/contrib/search/browser/search.contribution.ts
+1
-1
src/vs/workbench/contrib/search/browser/searchActions.ts
src/vs/workbench/contrib/search/browser/searchActions.ts
+3
-5
src/vs/workbench/contrib/search/browser/searchEditor.ts
src/vs/workbench/contrib/search/browser/searchEditor.ts
+32
-38
src/vs/workbench/contrib/search/browser/searchEditorActions.ts
...s/workbench/contrib/search/browser/searchEditorActions.ts
+55
-0
src/vs/workbench/contrib/search/browser/searchEditorInput.ts
src/vs/workbench/contrib/search/browser/searchEditorInput.ts
+309
-0
src/vs/workbench/contrib/search/browser/searchEditorSerialization.ts
...bench/contrib/search/browser/searchEditorSerialization.ts
+248
-0
src/vs/workbench/contrib/search/browser/searchView.ts
src/vs/workbench/contrib/search/browser/searchView.ts
+2
-2
未找到文件。
src/vs/workbench/contrib/search/browser/search.contribution.ts
浏览文件 @
f38c5007
...
...
@@ -56,7 +56,7 @@ import { ExplorerViewPaneContainer } from 'vs/workbench/contrib/files/browser/ex
import
{
assertType
}
from
'
vs/base/common/types
'
;
import
{
SearchViewPaneContainer
}
from
'
vs/workbench/contrib/search/browser/searchViewlet
'
;
import
{
EditorDescriptor
,
Extensions
as
EditorExtensions
,
IEditorRegistry
}
from
'
vs/workbench/browser/editor
'
;
import
{
SearchEditorInput
,
SearchEditorInputFactory
,
SearchEditorContribution
}
from
'
vs/workbench/contrib/search/browser/searchEditor
Commands
'
;
import
{
SearchEditorInput
,
SearchEditorInputFactory
,
SearchEditorContribution
}
from
'
vs/workbench/contrib/search/browser/searchEditor
Input
'
;
import
{
SearchEditor
}
from
'
vs/workbench/contrib/search/browser/searchEditor
'
;
import
{
SyncDescriptor
}
from
'
vs/platform/instantiation/common/descriptors
'
;
import
{
Extensions
as
EditorInputExtensions
,
IEditorInputFactoryRegistry
}
from
'
vs/workbench/common/editor
'
;
...
...
src/vs/workbench/contrib/search/browser/searchActions.ts
浏览文件 @
f38c5007
...
...
@@ -29,10 +29,9 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import
{
SearchViewPaneContainer
}
from
'
vs/workbench/contrib/search/browser/searchViewlet
'
;
import
{
SearchPanel
}
from
'
vs/workbench/contrib/search/browser/searchPanel
'
;
import
{
ITreeNavigator
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
createEditorFromSearchResult
,
openNewSearchEditor
,
SearchEditorInput
}
from
'
vs/workbench/contrib/search/browser/searchEditorCommands
'
;
import
{
createEditorFromSearchResult
,
openNewSearchEditor
}
from
'
vs/workbench/contrib/search/browser/searchEditorActions
'
;
import
type
{
SearchEditor
}
from
'
vs/workbench/contrib/search/browser/searchEditor
'
;
import
{
ITextFileService
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
SearchEditorInput
}
from
'
vs/workbench/contrib/search/browser/searchEditorInput
'
;
export
function
isSearchViewFocused
(
viewletService
:
IViewletService
,
panelService
:
IPanelService
):
boolean
{
const
searchView
=
getSearchView
(
viewletService
,
panelService
);
...
...
@@ -587,7 +586,6 @@ export class OpenResultsInEditorAction extends Action {
@
IEditorService
private
editorService
:
IEditorService
,
@
IConfigurationService
private
configurationService
:
IConfigurationService
,
@
IInstantiationService
private
readonly
instantiationService
:
IInstantiationService
,
@
ITextFileService
private
readonly
textFileService
:
ITextFileService
)
{
super
(
id
,
label
,
'
codicon-go-to-file
'
);
}
...
...
@@ -604,7 +602,7 @@ export class OpenResultsInEditorAction extends Action {
async
run
()
{
const
searchView
=
getSearchView
(
this
.
viewletService
,
this
.
panelService
);
if
(
searchView
&&
this
.
configurationService
.
getValue
<
ISearchConfigurationProperties
>
(
'
search
'
).
enableSearchEditorPreview
)
{
await
createEditorFromSearchResult
(
searchView
.
searchResult
,
searchView
.
searchIncludePattern
.
getValue
(),
searchView
.
searchExcludePattern
.
getValue
(),
this
.
labelService
,
this
.
editorService
,
this
.
textFileService
,
this
.
instantiationService
);
await
createEditorFromSearchResult
(
searchView
.
searchResult
,
searchView
.
searchIncludePattern
.
getValue
(),
searchView
.
searchExcludePattern
.
getValue
(),
this
.
labelService
,
this
.
editorService
,
this
.
instantiationService
);
}
}
}
...
...
src/vs/workbench/contrib/search/browser/searchEditor.ts
浏览文件 @
f38c5007
...
...
@@ -23,10 +23,10 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import
{
ILabelService
}
from
'
vs/platform/label/common/label
'
;
import
{
IStorageService
}
from
'
vs/platform/storage/common/storage
'
;
import
{
ITelemetryService
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
IThemeService
}
from
'
vs/platform/theme/common/themeService
'
;
import
{
IThemeService
,
registerThemingParticipant
}
from
'
vs/platform/theme/common/themeService
'
;
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
BaseEditor
}
from
'
vs/workbench/browser/parts/editor/baseEditor
'
;
import
{
Editor
Input
,
Editor
Options
}
from
'
vs/workbench/common/editor
'
;
import
{
EditorOptions
}
from
'
vs/workbench/common/editor
'
;
import
{
ExcludePatternInputWidget
,
PatternInputWidget
}
from
'
vs/workbench/contrib/search/browser/patternInputWidget
'
;
import
{
SearchWidget
}
from
'
vs/workbench/contrib/search/browser/searchWidget
'
;
import
{
ITextQueryBuilderOptions
,
QueryBuilder
}
from
'
vs/workbench/contrib/search/common/queryBuilder
'
;
...
...
@@ -34,19 +34,15 @@ import { getOutOfWorkspaceEditorResources } from 'vs/workbench/contrib/search/co
import
{
SearchModel
}
from
'
vs/workbench/contrib/search/common/searchModel
'
;
import
{
IPatternInfo
,
ISearchConfigurationProperties
,
ITextQuery
}
from
'
vs/workbench/services/search/common/search
'
;
import
{
Delayer
}
from
'
vs/base/common/async
'
;
import
{
serializeSearchResultForEditor
,
SearchConfiguration
,
SearchEditorInput
}
from
'
vs/workbench/contrib/search/browser/searchEditorCommands
'
;
import
{
ITextFileService
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
serializeSearchResultForEditor
}
from
'
vs/workbench/contrib/search/browser/searchEditorSerialization
'
;
import
{
IContextKeyService
,
IContextKey
}
from
'
vs/platform/contextkey/common/contextkey
'
;
import
{
InSearchEditor
,
InputBoxFocusedKey
}
from
'
vs/workbench/contrib/search/common/constants
'
;
import
{
IEditorProgressService
,
LongRunningOperation
}
from
'
vs/platform/progress/common/progress
'
;
import
type
{
SearchEditorInput
,
SearchConfiguration
}
from
'
vs/workbench/contrib/search/browser/searchEditorInput
'
;
import
{
searchEditorFindMatchBorder
,
searchEditorFindMatch
}
from
'
vs/platform/theme/common/colorRegistry
'
;
const
RESULT_LINE_REGEX
=
/^
(\s
+
)(\d
+
)(
:|
)(\s
+
)(
.*
)
$/
;
// Using \r\n on Windows inserts an extra newline between results.
const
lineDelimiter
=
'
\n
'
;
export
class
SearchEditor
extends
BaseEditor
{
static
readonly
ID
:
string
=
'
workbench.editor.searchEditor
'
;
...
...
@@ -78,7 +74,6 @@ export class SearchEditor extends BaseEditor {
@
IInstantiationService
private
readonly
instantiationService
:
IInstantiationService
,
@
IContextViewService
private
readonly
contextViewService
:
IContextViewService
,
@
ICommandService
private
readonly
commandService
:
ICommandService
,
@
ITextFileService
private
readonly
textFileService
:
ITextFileService
,
@
IContextKeyService
readonly
contextKeyService
:
IContextKeyService
,
@
IEditorProgressService
readonly
progressService
:
IEditorProgressService
,
)
{
...
...
@@ -304,16 +299,17 @@ export class SearchEditor extends BaseEditor {
return
;
}
(
assertIsDefined
(
this
.
_input
)
as
SearchEditorInput
).
setConfig
(
config
);
const
labelFormatter
=
(
uri
:
URI
):
string
=>
this
.
labelService
.
getUriLabel
(
uri
,
{
relative
:
true
});
const
results
=
serializeSearchResultForEditor
(
searchModel
.
searchResult
,
config
.
includes
,
config
.
excludes
,
config
.
contextLines
,
labelFormatter
,
true
);
const
textModel
=
assertIsDefined
(
this
.
searchResultEditor
.
getModel
());
this
.
modelService
.
updateModel
(
textModel
,
results
.
text
.
join
(
lineDelimiter
)
);
this
.
modelService
.
updateModel
(
textModel
,
results
.
text
);
this
.
getInput
()?.
setDirty
(
this
.
getInput
()?.
resource
.
scheme
!==
'
search-editor
'
);
this
.
hideHeader
();
textModel
.
deltaDecorations
([],
results
.
matchRanges
.
map
(
range
=>
({
range
,
options
:
{
className
:
'
searchEditorFindMatch
'
,
stickiness
:
TrackedRangeStickiness
.
NeverGrowsWhenTypingAtEdges
}
})));
(
assertIsDefined
(
this
.
_input
)
as
SearchEditorInput
).
reloadModel
();
searchModel
.
dispose
();
}
...
...
@@ -327,7 +323,8 @@ export class SearchEditor extends BaseEditor {
.
length
??
0
;
this
.
searchResultEditor
.
setHiddenAreas
([
new
Range
(
1
,
1
,
headerLines
+
1
,
1
)]);
// const length = this.searchResultEditor.getModel()?.getLineLength(headerLines);
this
.
searchResultEditor
.
setHiddenAreas
([
new
Range
(
1
,
1
,
headerLines
,
1
)]);
}
layout
(
dimension
:
DOM
.
Dimension
)
{
...
...
@@ -352,38 +349,26 @@ export class SearchEditor extends BaseEditor {
return
this
.
_input
as
SearchEditorInput
;
}
async
setInput
(
newInput
:
EditorInput
,
options
:
EditorOptions
|
undefined
,
token
:
CancellationToken
):
Promise
<
void
>
{
async
setInput
(
newInput
:
Search
EditorInput
,
options
:
EditorOptions
|
undefined
,
token
:
CancellationToken
):
Promise
<
void
>
{
await
super
.
setInput
(
newInput
,
options
,
token
);
this
.
inSearchEditorContextKey
.
set
(
true
);
if
(
!
(
newInput
instanceof
SearchEditorInput
))
{
return
;
}
const
model
=
assertIsDefined
(
this
.
modelService
.
getModel
(
newInput
.
resource
));
const
{
model
}
=
await
newInput
.
reloadModel
();
this
.
searchResultEditor
.
setModel
(
model
);
const
backup
=
await
newInput
.
resolveBackup
();
if
(
backup
)
{
model
.
setValueFromTextBuffer
(
backup
);
}
else
{
if
(
newInput
.
resource
.
scheme
!==
'
search-editor
'
)
{
if
(
model
.
getValue
()
===
''
)
{
model
.
setValue
((
await
this
.
textFileService
.
read
(
newInput
.
resource
)).
value
);
}
}
}
this
.
hideHeader
();
this
.
pauseSearching
=
true
;
this
.
queryEditorWidget
.
setValue
(
newInput
.
config
.
query
,
true
);
this
.
queryEditorWidget
.
searchInput
.
setCaseSensitive
(
newInput
.
config
.
caseSensitive
);
this
.
queryEditorWidget
.
searchInput
.
setRegex
(
newInput
.
config
.
regexp
);
this
.
queryEditorWidget
.
searchInput
.
setWholeWords
(
newInput
.
config
.
wholeWord
);
this
.
queryEditorWidget
.
setContextLines
(
newInput
.
config
.
contextLines
);
this
.
inputPatternExcludes
.
setValue
(
newInput
.
config
.
excludes
);
this
.
inputPatternIncludes
.
setValue
(
newInput
.
config
.
includes
);
this
.
inputPatternExcludes
.
setUseExcludesAndIgnoreFiles
(
newInput
.
config
.
useIgnores
);
this
.
toggleIncludesExcludes
(
newInput
.
config
.
showIncludesExcludes
);
const
{
query
}
=
await
newInput
.
reloadModel
();
this
.
queryEditorWidget
.
setValue
(
query
.
query
,
true
);
this
.
queryEditorWidget
.
searchInput
.
setCaseSensitive
(
query
.
caseSensitive
);
this
.
queryEditorWidget
.
searchInput
.
setRegex
(
query
.
regexp
);
this
.
queryEditorWidget
.
searchInput
.
setWholeWords
(
query
.
wholeWord
);
this
.
queryEditorWidget
.
setContextLines
(
query
.
contextLines
);
this
.
inputPatternExcludes
.
setValue
(
query
.
excludes
);
this
.
inputPatternIncludes
.
setValue
(
query
.
includes
);
this
.
inputPatternExcludes
.
setUseExcludesAndIgnoreFiles
(
query
.
useIgnores
);
this
.
toggleIncludesExcludes
(
query
.
showIncludesExcludes
);
this
.
focusInput
();
this
.
pauseSearching
=
false
;
...
...
@@ -415,3 +400,12 @@ export class SearchEditor extends BaseEditor {
this
.
inSearchEditorContextKey
.
set
(
false
);
}
}
registerThemingParticipant
((
theme
,
collector
)
=>
{
collector
.
addRule
(
`.monaco-editor .searchEditorFindMatch { background-color:
${
theme
.
getColor
(
searchEditorFindMatch
)}
; }`
);
const
findMatchHighlightBorder
=
theme
.
getColor
(
searchEditorFindMatchBorder
);
if
(
findMatchHighlightBorder
)
{
collector
.
addRule
(
`.monaco-editor .searchEditorFindMatch { border: 1px
${
theme
.
type
===
'
hc
'
?
'
dotted
'
:
'
solid
'
}
${
findMatchHighlightBorder
}
; box-sizing: border-box; }`
);
}
});
src/vs/workbench/contrib/search/browser/searchEditorActions.ts
0 → 100644
浏览文件 @
f38c5007
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
assertIsDefined
}
from
'
vs/base/common/types
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
'
vs/css!./media/searchEditor
'
;
import
{
isDiffEditor
,
ICodeEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
TrackedRangeStickiness
}
from
'
vs/editor/common/model
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
ILabelService
}
from
'
vs/platform/label/common/label
'
;
import
{
SearchResult
}
from
'
vs/workbench/contrib/search/common/searchModel
'
;
import
{
IEditorService
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
SearchEditor
}
from
'
vs/workbench/contrib/search/browser/searchEditor
'
;
import
{
getOrMakeSearchEditorInput
}
from
'
vs/workbench/contrib/search/browser/searchEditorInput
'
;
import
{
serializeSearchResultForEditor
,
serializeSearchConfiguration
}
from
'
vs/workbench/contrib/search/browser/searchEditorSerialization
'
;
export
const
openNewSearchEditor
=
async
(
editorService
:
IEditorService
,
instantiationService
:
IInstantiationService
)
=>
{
const
activeEditor
=
editorService
.
activeTextEditorWidget
;
let
activeModel
:
ICodeEditor
|
undefined
;
if
(
isDiffEditor
(
activeEditor
))
{
if
(
activeEditor
.
getOriginalEditor
().
hasTextFocus
())
{
activeModel
=
activeEditor
.
getOriginalEditor
();
}
else
{
activeModel
=
activeEditor
.
getModifiedEditor
();
}
}
else
{
activeModel
=
activeEditor
as
ICodeEditor
|
undefined
;
}
const
selection
=
activeModel
?.
getSelection
();
let
selected
=
(
selection
&&
activeModel
?.
getModel
()?.
getValueInRange
(
selection
))
??
''
;
const
input
=
instantiationService
.
invokeFunction
(
getOrMakeSearchEditorInput
,
{
text
:
serializeSearchConfiguration
({
query
:
selected
})
});
await
editorService
.
openEditor
(
input
,
{
pinned
:
true
});
};
export
const
createEditorFromSearchResult
=
async
(
searchResult
:
SearchResult
,
rawIncludePattern
:
string
,
rawExcludePattern
:
string
,
labelService
:
ILabelService
,
editorService
:
IEditorService
,
instantiationService
:
IInstantiationService
)
=>
{
if
(
!
searchResult
.
query
)
{
console
.
error
(
'
Expected searchResult.query to be defined. Got
'
,
searchResult
);
return
;
}
const
labelFormatter
=
(
uri
:
URI
):
string
=>
labelService
.
getUriLabel
(
uri
,
{
relative
:
true
});
const
{
text
,
matchRanges
}
=
serializeSearchResultForEditor
(
searchResult
,
rawIncludePattern
,
rawExcludePattern
,
0
,
labelFormatter
,
true
);
const
input
=
instantiationService
.
invokeFunction
(
getOrMakeSearchEditorInput
,
{
text
});
const
editor
=
await
editorService
.
openEditor
(
input
,
{
pinned
:
true
})
as
SearchEditor
;
const
model
=
assertIsDefined
(
editor
.
getModel
());
model
.
deltaDecorations
([],
matchRanges
.
map
(
range
=>
({
range
,
options
:
{
className
:
'
searchEditorFindMatch
'
,
stickiness
:
TrackedRangeStickiness
.
NeverGrowsWhenTypingAtEdges
}
})));
};
src/vs/workbench/contrib/search/browser/searchEditor
Commands
.ts
→
src/vs/workbench/contrib/search/browser/searchEditor
Input
.ts
浏览文件 @
f38c5007
此差异已折叠。
点击以展开。
src/vs/workbench/contrib/search/browser/searchEditorSerialization.ts
0 → 100644
浏览文件 @
f38c5007
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
'
vs/css!./media/searchEditor
'
;
import
{
coalesce
,
flatten
}
from
'
vs/base/common/arrays
'
;
import
{
repeat
}
from
'
vs/base/common/strings
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
FileMatch
,
Match
,
searchMatchComparer
,
SearchResult
}
from
'
vs/workbench/contrib/search/common/searchModel
'
;
import
{
ITextQuery
}
from
'
vs/workbench/services/search/common/search
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
type
{
ITextModel
}
from
'
vs/editor/common/model
'
;
import
type
{
SearchConfiguration
}
from
'
vs/workbench/contrib/search/browser/searchEditorInput
'
;
// Using \r\n on Windows inserts an extra newline between results.
const
lineDelimiter
=
'
\n
'
;
const
translateRangeLines
=
(
n
:
number
)
=>
(
range
:
Range
)
=>
new
Range
(
range
.
startLineNumber
+
n
,
range
.
startColumn
,
range
.
endLineNumber
+
n
,
range
.
endColumn
);
const
matchToSearchResultFormat
=
(
match
:
Match
):
{
line
:
string
,
ranges
:
Range
[],
lineNumber
:
string
}[]
=>
{
const
getLinePrefix
=
(
i
:
number
)
=>
`
${
match
.
range
().
startLineNumber
+
i
}
`
;
const
fullMatchLines
=
match
.
fullPreviewLines
();
const
largestPrefixSize
=
fullMatchLines
.
reduce
((
largest
,
_
,
i
)
=>
Math
.
max
(
getLinePrefix
(
i
).
length
,
largest
),
0
);
const
results
:
{
line
:
string
,
ranges
:
Range
[],
lineNumber
:
string
}[]
=
[];
fullMatchLines
.
forEach
((
sourceLine
,
i
)
=>
{
const
lineNumber
=
getLinePrefix
(
i
);
const
paddingStr
=
repeat
(
'
'
,
largestPrefixSize
-
lineNumber
.
length
);
const
prefix
=
`
${
lineNumber
}
:
${
paddingStr
}
`
;
const
prefixOffset
=
prefix
.
length
;
const
line
=
(
prefix
+
sourceLine
).
replace
(
/
\r?\n?
$/
,
''
);
const
rangeOnThisLine
=
({
start
,
end
}:
{
start
?:
number
;
end
?:
number
;
})
=>
new
Range
(
1
,
(
start
??
1
)
+
prefixOffset
,
1
,
(
end
??
sourceLine
.
length
+
1
)
+
prefixOffset
);
const
matchRange
=
match
.
range
();
const
matchIsSingleLine
=
matchRange
.
startLineNumber
===
matchRange
.
endLineNumber
;
let
lineRange
;
if
(
matchIsSingleLine
)
{
lineRange
=
(
rangeOnThisLine
({
start
:
matchRange
.
startColumn
,
end
:
matchRange
.
endColumn
}));
}
else
if
(
i
===
0
)
{
lineRange
=
(
rangeOnThisLine
({
start
:
matchRange
.
startColumn
}));
}
else
if
(
i
===
fullMatchLines
.
length
-
1
)
{
lineRange
=
(
rangeOnThisLine
({
end
:
matchRange
.
endColumn
}));
}
else
{
lineRange
=
(
rangeOnThisLine
({}));
}
results
.
push
({
lineNumber
:
lineNumber
,
line
,
ranges
:
[
lineRange
]
});
});
return
results
;
};
type
SearchResultSerialization
=
{
text
:
string
[],
matchRanges
:
Range
[]
};
function
fileMatchToSearchResultFormat
(
fileMatch
:
FileMatch
,
labelFormatter
:
(
x
:
URI
)
=>
string
):
SearchResultSerialization
{
const
serializedMatches
=
flatten
(
fileMatch
.
matches
()
.
sort
(
searchMatchComparer
)
.
map
(
match
=>
matchToSearchResultFormat
(
match
)));
const
uriString
=
labelFormatter
(
fileMatch
.
resource
);
let
text
:
string
[]
=
[
`
${
uriString
}
:`
];
let
matchRanges
:
Range
[]
=
[];
const
targetLineNumberToOffset
:
Record
<
string
,
number
>
=
{};
const
context
:
{
line
:
string
,
lineNumber
:
number
}[]
=
[];
fileMatch
.
context
.
forEach
((
line
,
lineNumber
)
=>
context
.
push
({
line
,
lineNumber
}));
context
.
sort
((
a
,
b
)
=>
a
.
lineNumber
-
b
.
lineNumber
);
let
lastLine
:
number
|
undefined
=
undefined
;
const
seenLines
=
new
Set
<
string
>
();
serializedMatches
.
forEach
(
match
=>
{
if
(
!
seenLines
.
has
(
match
.
line
))
{
while
(
context
.
length
&&
context
[
0
].
lineNumber
<
+
match
.
lineNumber
)
{
const
{
line
,
lineNumber
}
=
context
.
shift
()
!
;
if
(
lastLine
!==
undefined
&&
lineNumber
!==
lastLine
+
1
)
{
text
.
push
(
''
);
}
text
.
push
(
`
${
lineNumber
}
${
line
}
`
);
lastLine
=
lineNumber
;
}
targetLineNumberToOffset
[
match
.
lineNumber
]
=
text
.
length
;
seenLines
.
add
(
match
.
line
);
text
.
push
(
match
.
line
);
lastLine
=
+
match
.
lineNumber
;
}
matchRanges
.
push
(...
match
.
ranges
.
map
(
translateRangeLines
(
targetLineNumberToOffset
[
match
.
lineNumber
])));
});
while
(
context
.
length
)
{
const
{
line
,
lineNumber
}
=
context
.
shift
()
!
;
text
.
push
(
`
${
lineNumber
}
${
line
}
`
);
}
return
{
text
,
matchRanges
};
}
const
contentPatternToSearchResultHeader
=
(
pattern
:
ITextQuery
|
null
,
includes
:
string
,
excludes
:
string
,
contextLines
:
number
):
string
[]
=>
{
if
(
!
pattern
)
{
return
[];
}
const
removeNullFalseAndUndefined
=
<
T
>
(
a
:
(
T
|
null
|
false
|
undefined
)[])
=>
a
.
filter
(
a
=>
a
!==
false
&&
a
!==
null
&&
a
!==
undefined
)
as
T
[];
const
escapeNewlines
=
(
str
:
string
)
=>
str
.
replace
(
/
\\
/g
,
'
\\\\
'
).
replace
(
/
\n
/g
,
'
\\
n
'
);
return
removeNullFalseAndUndefined
([
`# Query:
${
escapeNewlines
(
pattern
.
contentPattern
.
pattern
)}
`
,
(
pattern
.
contentPattern
.
isCaseSensitive
||
pattern
.
contentPattern
.
isWordMatch
||
pattern
.
contentPattern
.
isRegExp
||
pattern
.
userDisabledExcludesAndIgnoreFiles
)
&&
`# Flags:
${
coalesce
([
pattern
.
contentPattern
.
isCaseSensitive
&&
'
CaseSensitive
'
,
pattern
.
contentPattern
.
isWordMatch
&&
'
WordMatch
'
,
pattern
.
contentPattern
.
isRegExp
&&
'
RegExp
'
,
pattern
.
userDisabledExcludesAndIgnoreFiles
&&
'
IgnoreExcludeSettings
'
]).
join
(
'
'
)}
`
,
includes
?
`# Including:
${
includes
}
`
:
undefined
,
excludes
?
`# Excluding:
${
excludes
}
`
:
undefined
,
contextLines
?
`# ContextLines:
${
contextLines
}
`
:
undefined
]);
};
export
const
serializeSearchConfiguration
=
(
config
:
Partial
<
SearchConfiguration
>
):
string
=>
{
const
removeNullFalseAndUndefined
=
<
T
>
(
a
:
(
T
|
null
|
false
|
undefined
)[])
=>
a
.
filter
(
a
=>
a
!==
false
&&
a
!==
null
&&
a
!==
undefined
)
as
T
[];
const
escapeNewlines
=
(
str
:
string
)
=>
str
.
replace
(
/
\\
/g
,
'
\\\\
'
).
replace
(
/
\n
/g
,
'
\\
n
'
);
return
removeNullFalseAndUndefined
([
`# Query:
${
escapeNewlines
(
config
.
query
??
''
)}
`
,
(
config
.
caseSensitive
||
config
.
wholeWord
||
config
.
regexp
||
config
.
useIgnores
===
false
)
&&
`# Flags:
${
coalesce
([
config
.
caseSensitive
&&
'
CaseSensitive
'
,
config
.
wholeWord
&&
'
WordMatch
'
,
config
.
regexp
&&
'
RegExp
'
,
(
config
.
useIgnores
===
false
)
&&
'
IgnoreExcludeSettings
'
]).
join
(
'
'
)}
`
,
config
.
includes
?
`# Including:
${
config
.
includes
}
`
:
undefined
,
config
.
excludes
?
`# Excluding:
${
config
.
excludes
}
`
:
undefined
,
config
.
contextLines
?
`# ContextLines:
${
config
.
contextLines
}
`
:
undefined
,
''
]).
join
(
lineDelimiter
);
};
export
const
extractSearchQuery
=
(
model
:
ITextModel
):
SearchConfiguration
=>
{
const
header
=
model
.
getValueInRange
(
new
Range
(
1
,
1
,
6
,
1
)).
split
(
lineDelimiter
);
const
query
:
SearchConfiguration
=
{
query
:
''
,
includes
:
''
,
excludes
:
''
,
regexp
:
false
,
caseSensitive
:
false
,
useIgnores
:
true
,
wholeWord
:
false
,
contextLines
:
0
,
showIncludesExcludes
:
false
,
};
const
unescapeNewlines
=
(
str
:
string
)
=>
{
let
out
=
''
;
for
(
let
i
=
0
;
i
<
str
.
length
;
i
++
)
{
if
(
str
[
i
]
===
'
\\
'
)
{
i
++
;
const
escaped
=
str
[
i
];
if
(
escaped
===
'
n
'
)
{
out
+=
'
\n
'
;
}
else
if
(
escaped
===
'
\\
'
)
{
out
+=
'
\\
'
;
}
else
{
throw
Error
(
localize
(
'
invalidQueryStringError
'
,
"
All backslashes in Query string must be escaped (
\\\\
)
"
));
}
}
else
{
out
+=
str
[
i
];
}
}
return
out
;
};
const
parseYML
=
/^#
([^
:
]
*
)
:
(
.*
)
$/
;
for
(
const
line
of
header
)
{
const
parsed
=
parseYML
.
exec
(
line
);
if
(
!
parsed
)
{
continue
;
}
const
[,
key
,
value
]
=
parsed
;
switch
(
key
)
{
case
'
Query
'
:
query
.
query
=
unescapeNewlines
(
value
);
break
;
case
'
Including
'
:
query
.
includes
=
value
;
break
;
case
'
Excluding
'
:
query
.
excludes
=
value
;
break
;
case
'
ContextLines
'
:
query
.
contextLines
=
+
value
;
break
;
case
'
Flags
'
:
{
query
.
regexp
=
value
.
indexOf
(
'
RegExp
'
)
!==
-
1
;
query
.
caseSensitive
=
value
.
indexOf
(
'
CaseSensitive
'
)
!==
-
1
;
query
.
useIgnores
=
value
.
indexOf
(
'
IgnoreExcludeSettings
'
)
===
-
1
;
query
.
wholeWord
=
value
.
indexOf
(
'
WordMatch
'
)
!==
-
1
;
}
}
}
query
.
showIncludesExcludes
=
!!
(
query
.
includes
||
query
.
excludes
||
!
query
.
useIgnores
);
return
query
;
};
export
const
serializeSearchResultForEditor
=
(
searchResult
:
SearchResult
,
rawIncludePattern
:
string
,
rawExcludePattern
:
string
,
contextLines
:
number
,
labelFormatter
:
(
x
:
URI
)
=>
string
,
includeHeader
:
boolean
):
{
matchRanges
:
Range
[],
text
:
string
}
=>
{
const
header
=
includeHeader
?
contentPatternToSearchResultHeader
(
searchResult
.
query
,
rawIncludePattern
,
rawExcludePattern
,
contextLines
)
:
[];
const
allResults
=
flattenSearchResultSerializations
(
flatten
(
searchResult
.
folderMatches
().
sort
(
searchMatchComparer
)
.
map
(
folderMatch
=>
folderMatch
.
matches
().
sort
(
searchMatchComparer
)
.
map
(
fileMatch
=>
fileMatchToSearchResultFormat
(
fileMatch
,
labelFormatter
)))));
return
{
matchRanges
:
allResults
.
matchRanges
.
map
(
translateRangeLines
(
header
.
length
)),
text
:
header
.
concat
(
allResults
.
text
.
length
?
allResults
.
text
:
[
'
No Results
'
])
.
join
(
lineDelimiter
)
};
};
const
flattenSearchResultSerializations
=
(
serializations
:
SearchResultSerialization
[]):
SearchResultSerialization
=>
{
let
text
:
string
[]
=
[];
let
matchRanges
:
Range
[]
=
[];
serializations
.
forEach
(
serialized
=>
{
serialized
.
matchRanges
.
map
(
translateRangeLines
(
text
.
length
)).
forEach
(
range
=>
matchRanges
.
push
(
range
));
serialized
.
text
.
forEach
(
line
=>
text
.
push
(
line
));
text
.
push
(
''
);
// new line
});
return
{
text
,
matchRanges
};
};
src/vs/workbench/contrib/search/browser/searchView.ts
浏览文件 @
f38c5007
...
...
@@ -64,7 +64,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
import
{
MultiCursorSelectionController
}
from
'
vs/editor/contrib/multicursor/multicursor
'
;
import
{
Selection
}
from
'
vs/editor/common/core/selection
'
;
import
{
SIDE_BAR_BACKGROUND
,
PANEL_BACKGROUND
}
from
'
vs/workbench/common/theme
'
;
import
{
createEditorFromSearchResult
}
from
'
vs/workbench/contrib/search/browser/searchEditor
Command
s
'
;
import
{
createEditorFromSearchResult
}
from
'
vs/workbench/contrib/search/browser/searchEditor
Action
s
'
;
import
{
ILabelService
}
from
'
vs/platform/label/common/label
'
;
import
{
Color
,
RGBA
}
from
'
vs/base/common/color
'
;
...
...
@@ -1559,7 +1559,7 @@ export class SearchView extends ViewPane {
this
.
messageDisposables
.
push
(
dom
.
addDisposableListener
(
openInEditorLink
,
dom
.
EventType
.
CLICK
,
(
e
:
MouseEvent
)
=>
{
dom
.
EventHelper
.
stop
(
e
,
false
);
createEditorFromSearchResult
(
this
.
searchResult
,
this
.
searchIncludePattern
.
getValue
(),
this
.
searchExcludePattern
.
getValue
(),
this
.
labelService
,
this
.
editorService
,
this
.
textFileService
,
this
.
instantiationService
);
createEditorFromSearchResult
(
this
.
searchResult
,
this
.
searchIncludePattern
.
getValue
(),
this
.
searchExcludePattern
.
getValue
(),
this
.
labelService
,
this
.
editorService
,
this
.
instantiationService
);
}));
}
else
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录