Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
250c58e6
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,发现更多精彩内容 >>
提交
250c58e6
编写于
9月 03, 2019
作者:
R
Rob Lourens
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Enable unicode mode for regex search in editor,
and remap \u{1234} for rg Fix #62416, fix #61746
上级
1c623c16
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
78 addition
and
34 deletion
+78
-34
src/vs/base/common/strings.ts
src/vs/base/common/strings.ts
+1
-1
src/vs/editor/common/model/textModelSearch.ts
src/vs/editor/common/model/textModelSearch.ts
+2
-1
src/vs/editor/contrib/find/findModel.ts
src/vs/editor/contrib/find/findModel.ts
+1
-1
src/vs/editor/test/common/model/textModelSearch.test.ts
src/vs/editor/test/common/model/textModelSearch.test.ts
+30
-16
src/vs/workbench/services/search/common/replace.ts
src/vs/workbench/services/search/common/replace.ts
+1
-1
src/vs/workbench/services/search/common/search.ts
src/vs/workbench/services/search/common/search.ts
+1
-0
src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts
...workbench/services/search/node/ripgrepTextSearchEngine.ts
+17
-12
src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts
...services/search/test/node/ripgrepTextSearchEngine.test.ts
+5
-2
src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts
...h/services/search/test/node/textSearch.integrationTest.ts
+20
-0
未找到文件。
src/vs/base/common/strings.ts
浏览文件 @
250c58e6
...
...
@@ -70,7 +70,7 @@ export function escape(html: string): string {
* Escapes regular expression characters in a given string
*/
export
function
escapeRegExpCharacters
(
value
:
string
):
string
{
return
value
.
replace
(
/
[\
-\
\\{\}\*\+\?\|\^\$\.\[\]\(\)\#]
/g
,
'
\\
$&
'
);
return
value
.
replace
(
/
[\\\{\}\*\+\?\|\^\$\.\[\]\(\)\#]
/g
,
'
\\
$&
'
);
}
/**
...
...
src/vs/editor/common/model/textModelSearch.ts
浏览文件 @
250c58e6
...
...
@@ -45,7 +45,8 @@ export class SearchParams {
matchCase
:
this
.
matchCase
,
wholeWord
:
false
,
multiline
:
multiline
,
global
:
true
global
:
true
,
unicode
:
true
});
}
catch
(
err
)
{
return
null
;
...
...
src/vs/editor/contrib/find/findModel.ts
浏览文件 @
250c58e6
...
...
@@ -467,7 +467,7 @@ export class FindModelBoundToEditorModel {
let
searchRegex
=
searchData
.
regex
;
if
(
!
searchRegex
.
multiline
)
{
let
mod
=
'
m
'
;
let
mod
=
'
m
u
'
;
if
(
searchRegex
.
ignoreCase
)
{
mod
+=
'
i
'
;
}
...
...
src/vs/editor/test/common/model/textModelSearch.test.ts
浏览文件 @
250c58e6
...
...
@@ -611,25 +611,25 @@ suite('TextModelSearch', () => {
});
test
(
'
parseSearchRequest non regex
'
,
()
=>
{
assertParseSearchResult
(
'
foo
'
,
false
,
false
,
null
,
new
SearchData
(
/foo/gi
,
null
,
null
));
assertParseSearchResult
(
'
foo
'
,
false
,
false
,
USUAL_WORD_SEPARATORS
,
new
SearchData
(
/foo/gi
,
usualWordSeparators
,
null
));
assertParseSearchResult
(
'
foo
'
,
false
,
true
,
null
,
new
SearchData
(
/foo/g
,
null
,
'
foo
'
));
assertParseSearchResult
(
'
foo
'
,
false
,
true
,
USUAL_WORD_SEPARATORS
,
new
SearchData
(
/foo/g
,
usualWordSeparators
,
'
foo
'
));
assertParseSearchResult
(
'
foo
\\
n
'
,
false
,
false
,
null
,
new
SearchData
(
/foo
\\
n/gi
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\\\
n
'
,
false
,
false
,
null
,
new
SearchData
(
/foo
\\\\
n/gi
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\
r
'
,
false
,
false
,
null
,
new
SearchData
(
/foo
\\
r/gi
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\\\
r
'
,
false
,
false
,
null
,
new
SearchData
(
/foo
\\\\
r/gi
,
null
,
null
));
assertParseSearchResult
(
'
foo
'
,
false
,
false
,
null
,
new
SearchData
(
/foo/gi
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
'
,
false
,
false
,
USUAL_WORD_SEPARATORS
,
new
SearchData
(
/foo/gi
u
,
usualWordSeparators
,
null
));
assertParseSearchResult
(
'
foo
'
,
false
,
true
,
null
,
new
SearchData
(
/foo/g
u
,
null
,
'
foo
'
));
assertParseSearchResult
(
'
foo
'
,
false
,
true
,
USUAL_WORD_SEPARATORS
,
new
SearchData
(
/foo/g
u
,
usualWordSeparators
,
'
foo
'
));
assertParseSearchResult
(
'
foo
\\
n
'
,
false
,
false
,
null
,
new
SearchData
(
/foo
\\
n/gi
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\\\
n
'
,
false
,
false
,
null
,
new
SearchData
(
/foo
\\\\
n/gi
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\
r
'
,
false
,
false
,
null
,
new
SearchData
(
/foo
\\
r/gi
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\\\
r
'
,
false
,
false
,
null
,
new
SearchData
(
/foo
\\\\
r/gi
u
,
null
,
null
));
});
test
(
'
parseSearchRequest regex
'
,
()
=>
{
assertParseSearchResult
(
'
foo
'
,
true
,
false
,
null
,
new
SearchData
(
/foo/gi
,
null
,
null
));
assertParseSearchResult
(
'
foo
'
,
true
,
false
,
USUAL_WORD_SEPARATORS
,
new
SearchData
(
/foo/gi
,
usualWordSeparators
,
null
));
assertParseSearchResult
(
'
foo
'
,
true
,
true
,
null
,
new
SearchData
(
/foo/g
,
null
,
null
));
assertParseSearchResult
(
'
foo
'
,
true
,
true
,
USUAL_WORD_SEPARATORS
,
new
SearchData
(
/foo/g
,
usualWordSeparators
,
null
));
assertParseSearchResult
(
'
foo
\\
n
'
,
true
,
false
,
null
,
new
SearchData
(
/foo
\n
/gim
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\\\
n
'
,
true
,
false
,
null
,
new
SearchData
(
/foo
\\
n/gi
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\
r
'
,
true
,
false
,
null
,
new
SearchData
(
/foo
\r
/gim
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\\\
r
'
,
true
,
false
,
null
,
new
SearchData
(
/foo
\\
r/gi
,
null
,
null
));
assertParseSearchResult
(
'
foo
'
,
true
,
false
,
null
,
new
SearchData
(
/foo/gi
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
'
,
true
,
false
,
USUAL_WORD_SEPARATORS
,
new
SearchData
(
/foo/gi
u
,
usualWordSeparators
,
null
));
assertParseSearchResult
(
'
foo
'
,
true
,
true
,
null
,
new
SearchData
(
/foo/g
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
'
,
true
,
true
,
USUAL_WORD_SEPARATORS
,
new
SearchData
(
/foo/g
u
,
usualWordSeparators
,
null
));
assertParseSearchResult
(
'
foo
\\
n
'
,
true
,
false
,
null
,
new
SearchData
(
/foo
\n
/gim
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\\\
n
'
,
true
,
false
,
null
,
new
SearchData
(
/foo
\\
n/gi
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\
r
'
,
true
,
false
,
null
,
new
SearchData
(
/foo
\r
/gim
u
,
null
,
null
));
assertParseSearchResult
(
'
foo
\\\\
r
'
,
true
,
false
,
null
,
new
SearchData
(
/foo
\\
r/gi
u
,
null
,
null
));
});
test
(
'
issue #53415.
\
W should match line break.
'
,
()
=>
{
...
...
@@ -721,6 +721,20 @@ suite('TextModelSearch', () => {
);
});
test
(
'
Simple find using unicode escape sequences
'
,
()
=>
{
assertFindMatches
(
regularText
.
join
(
'
\n
'
),
'
\\
u{0066}
\\
u006f
\\
u006F
'
,
true
,
false
,
null
,
[
[
1
,
14
,
1
,
17
],
[
1
,
44
,
1
,
47
],
[
2
,
22
,
2
,
25
],
[
2
,
48
,
2
,
51
],
[
4
,
59
,
4
,
62
]
]
);
});
test
(
'
isMultilineRegexSource
'
,
()
=>
{
assert
(
!
isMultilineRegexSource
(
'
foo
'
));
assert
(
!
isMultilineRegexSource
(
''
));
...
...
src/vs/workbench/services/search/common/replace.ts
浏览文件 @
250c58e6
...
...
@@ -27,7 +27,7 @@ export class ReplacePattern {
}
else
{
searchPatternInfo
=
arg2
;
parseParameters
=
!!
searchPatternInfo
.
isRegExp
;
this
.
_regExp
=
strings
.
createRegExp
(
searchPatternInfo
.
pattern
,
!!
searchPatternInfo
.
isRegExp
,
{
matchCase
:
searchPatternInfo
.
isCaseSensitive
,
wholeWord
:
searchPatternInfo
.
isWordMatch
,
multiline
:
searchPatternInfo
.
isMultiline
,
global
:
false
});
this
.
_regExp
=
strings
.
createRegExp
(
searchPatternInfo
.
pattern
,
!!
searchPatternInfo
.
isRegExp
,
{
matchCase
:
searchPatternInfo
.
isCaseSensitive
,
wholeWord
:
searchPatternInfo
.
isWordMatch
,
multiline
:
searchPatternInfo
.
isMultiline
,
global
:
false
,
unicode
:
true
});
}
if
(
parseParameters
)
{
...
...
src/vs/workbench/services/search/common/search.ts
浏览文件 @
250c58e6
...
...
@@ -132,6 +132,7 @@ export interface IPatternInfo {
isWordMatch
?:
boolean
;
wordSeparators
?:
string
;
isMultiline
?:
boolean
;
isUnicode
?:
boolean
;
isCaseSensitive
?:
boolean
;
}
...
...
src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts
浏览文件 @
250c58e6
...
...
@@ -394,13 +394,11 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[]
args
.
push
(
'
--encoding
'
,
options
.
encoding
);
}
let
pattern
=
query
.
pattern
;
// Ripgrep handles -- as a -- arg separator. Only --.
// - is ok, --- is ok, --some-flag is also ok. Need to special case.
if
(
pattern
===
'
--
'
)
{
if
(
query
.
pattern
===
'
--
'
)
{
query
.
isRegExp
=
true
;
pattern
=
'
\\
-
\\
-
'
;
query
.
pattern
=
'
\\
-
\\
-
'
;
}
if
(
query
.
isMultiline
&&
!
query
.
isRegExp
)
{
...
...
@@ -413,7 +411,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[]
}
if
(
query
.
isRegExp
)
{
pattern
=
unicodeEscapesToPCRE2
(
pattern
);
query
.
pattern
=
unicodeEscapesToPCRE2
(
query
.
pattern
);
}
// Allow $ to match /r/n
...
...
@@ -421,7 +419,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[]
let
searchPatternAfterDoubleDashes
:
Maybe
<
string
>
;
if
(
query
.
isWordMatch
)
{
const
regexp
=
createRegExp
(
pattern
,
!!
query
.
isRegExp
,
{
wholeWord
:
query
.
isWordMatch
});
const
regexp
=
createRegExp
(
query
.
pattern
,
!!
query
.
isRegExp
,
{
wholeWord
:
query
.
isWordMatch
});
const
regexpStr
=
regexp
.
source
.
replace
(
/
\\\/
/g
,
'
/
'
);
// RegExp.source arbitrarily returns escaped slashes. Search and destroy.
args
.
push
(
'
--regexp
'
,
regexpStr
);
}
else
if
(
query
.
isRegExp
)
{
...
...
@@ -430,7 +428,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[]
args
.
push
(
'
--regexp
'
,
fixedRegexpQuery
);
args
.
push
(
'
--auto-hybrid-regex
'
);
}
else
{
searchPatternAfterDoubleDashes
=
pattern
;
searchPatternAfterDoubleDashes
=
query
.
pattern
;
args
.
push
(
'
--fixed-strings
'
);
}
...
...
@@ -479,11 +477,18 @@ export function spreadGlobComponents(globArg: string): string[] {
}
export
function
unicodeEscapesToPCRE2
(
pattern
:
string
):
string
{
const
reg
=
/
((?:[^\\]
|^
)(?:\\\\)
*
)\\
u
([
a-z0-9
]{4})(?!\d)
/g
;
// Replace an unescaped $ at the end of the pattern with \r?$
// Match $ preceeded by none or even number of literal \
while
(
pattern
.
match
(
reg
))
{
pattern
=
pattern
.
replace
(
reg
,
`$1\\x{$2}`
);
// Match \u1234
const
unicodePattern
=
/
((?:[^\\]
|^
)(?:\\\\)
*
)\\
u
([
a-z0-9
]{4})
/g
;
while
(
pattern
.
match
(
unicodePattern
))
{
pattern
=
pattern
.
replace
(
unicodePattern
,
`$1\\x{$2}`
);
}
// Match \u{1234}
// \u with 5-6 characters will be left alone because \x only takes 4 characters.
const
unicodePatternWithBraces
=
/
((?:[^\\]
|^
)(?:\\\\)
*
)\\
u
\{([
a-z0-9
]{4})\}
/g
;
while
(
pattern
.
match
(
unicodePatternWithBraces
))
{
pattern
=
pattern
.
replace
(
unicodePatternWithBraces
,
`$1\\x{$2}`
);
}
return
pattern
;
...
...
src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts
浏览文件 @
250c58e6
...
...
@@ -17,9 +17,12 @@ suite('RipgrepTextSearchEngine', () => {
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
\\\\\\
u1234
'
),
'
\\\\\\
x{1234}
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
foo
\\\\\\
u1234
'
),
'
foo
\\\\\\
x{1234}
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
\\
u{1234}
'
),
'
\\
x{1234}
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
\\
u{1234}
\\
u{0001}
'
),
'
\\
x{1234}
\\
x{0001}
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
foo
\\
u{1234}bar
'
),
'
foo
\\
x{1234}bar
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
foo
\\
u{123456}7bar
'
),
'
foo
\\
u{123456}7bar
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
\\
u123
'
),
'
\\
u123
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
\\
u12345
'
),
'
\\
u12345
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
\\\\
u12345
'
),
'
\\\\
u12345
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
'
foo
'
),
'
foo
'
);
assert
.
equal
(
unicodeEscapesToPCRE2
(
''
),
''
);
});
...
...
src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts
浏览文件 @
250c58e6
...
...
@@ -69,6 +69,26 @@ suite('Search-integration', function () {
return
doSearchTest
(
config
,
4
);
});
test
(
'
Text: GameOfLife (unicode escape sequences)
'
,
()
=>
{
const
config
:
ITextQuery
=
{
type
:
QueryType
.
Text
,
folderQueries
:
ROOT_FOLDER_QUERY
,
contentPattern
:
{
pattern
:
'
G
\\
u{0061}m
\\
u0065OfLife
'
,
isRegExp
:
true
}
};
return
doSearchTest
(
config
,
4
);
});
test
(
'
Text: GameOfLife (unicode escape sequences, force PCRE2)
'
,
()
=>
{
const
config
:
ITextQuery
=
{
type
:
QueryType
.
Text
,
folderQueries
:
ROOT_FOLDER_QUERY
,
contentPattern
:
{
pattern
:
'
(?<!a)G
\\
u{0061}m
\\
u0065OfLife
'
,
isRegExp
:
true
}
};
return
doSearchTest
(
config
,
4
);
});
test
(
'
Text: GameOfLife (PCRE2 RegExp)
'
,
()
=>
{
const
config
:
ITextQuery
=
{
type
:
QueryType
.
Text
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录