Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
50bb7aad
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(gitcode.net)2024年7月9日维护升级公告
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
50bb7aad
编写于
9月 13, 2016
作者:
C
Christof Marti
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Prune find traversal with basename patterns
上级
3d1a7125
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
146 addition
and
14 deletion
+146
-14
src/vs/base/common/glob.ts
src/vs/base/common/glob.ts
+36
-4
src/vs/base/test/common/glob.test.ts
src/vs/base/test/common/glob.test.ts
+18
-2
src/vs/workbench/services/search/node/fileSearch.ts
src/vs/workbench/services/search/node/fileSearch.ts
+32
-3
src/vs/workbench/services/search/test/node/fixtures/more/file.txt
...orkbench/services/search/test/node/fixtures/more/file.txt
+0
-0
src/vs/workbench/services/search/test/node/search.test.ts
src/vs/workbench/services/search/test/node/search.test.ts
+60
-5
未找到文件。
src/vs/base/common/glob.ts
浏览文件 @
50bb7aad
...
...
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
arrays
=
require
(
'
vs/base/common/arrays
'
);
import
strings
=
require
(
'
vs/base/common/strings
'
);
import
paths
=
require
(
'
vs/base/common/paths
'
);
import
{
BoundedLinkedMap
}
from
'
vs/base/common/map
'
;
...
...
@@ -219,11 +220,13 @@ interface ParsedStringPattern {
(
path
:
string
,
basename
:
string
):
string
/* the matching pattern */
;
basenames
?:
string
[];
patterns
?:
string
[];
allBasenames
?:
string
[];
}
type
SiblingsPattern
=
{
siblings
:
string
[],
name
:
string
};
interface
ParsedExpressionPattern
{
(
path
:
string
,
basename
:
string
,
siblingsPatternFn
:
()
=>
SiblingsPattern
):
string
/* the matching pattern */
;
requiresSiblings
?:
boolean
;
allBasenames
?:
string
[];
}
const
CACHE
=
new
BoundedLinkedMap
<
ParsedStringPattern
>
(
10000
);
// bounded to 10000 elements
...
...
@@ -269,8 +272,10 @@ function parsePattern(pattern: string): ParsedStringPattern {
}
return
path
===
base
||
strings
.
endsWith
(
path
,
slashBase
)
||
strings
.
endsWith
(
path
,
backslashBase
)
?
pattern
:
null
;
};
parsedPattern
.
basenames
=
[
base
];
const
basenames
=
[
base
];
parsedPattern
.
basenames
=
basenames
;
parsedPattern
.
patterns
=
[
pattern
];
parsedPattern
.
allBasenames
=
basenames
;
}
else
if
(
T3
.
test
(
pattern
))
{
// repetition of common patterns (see above) {**/*.txt,**/*.png}
const
parsedPatterns
=
aggregateBasenameMatches
(
pattern
.
slice
(
1
,
-
1
).
split
(
'
,
'
)
.
map
(
pattern
=>
parsePattern
(
pattern
))
...
...
@@ -290,6 +295,10 @@ function parsePattern(pattern: string): ParsedStringPattern {
}
return
null
;
};
const
withBasenames
=
arrays
.
first
(
parsedPatterns
,
pattern
=>
!!
(
<
ParsedStringPattern
>
pattern
).
allBasenames
);
if
(
withBasenames
)
{
parsedPattern
.
allBasenames
=
(
<
ParsedStringPattern
>
withBasenames
).
allBasenames
;
}
}
// Otherwise convert to pattern
...
...
@@ -354,15 +363,23 @@ export function parse(arg1: string | IExpression): any {
if
(
parsedPattern
===
NULL
)
{
return
FALSE
;
}
return
function
(
path
:
string
,
basename
:
string
)
{
const
resultPattern
=
function
(
path
:
string
,
basename
:
string
)
{
return
!!
parsedPattern
(
path
,
basename
);
};
if
(
parsedPattern
.
allBasenames
)
{
(
<
ParsedStringPattern
><
any
>
resultPattern
).
allBasenames
=
parsedPattern
.
allBasenames
;
}
return
resultPattern
;
}
// Glob with Expression
return
parsedExpression
(
<
IExpression
>
arg1
);
}
export
function
getBasenameTerms
(
patternOrExpression
:
ParsedPattern
|
ParsedExpression
):
string
[]
{
return
(
<
ParsedStringPattern
>
patternOrExpression
).
allBasenames
||
[];
}
function
parsedExpression
(
expression
:
IExpression
):
ParsedExpression
{
const
parsedPatterns
=
aggregateBasenameMatches
(
Object
.
getOwnPropertyNames
(
expression
)
.
map
(
pattern
=>
parseExpressionPattern
(
pattern
,
expression
[
pattern
]))
...
...
@@ -378,7 +395,7 @@ function parsedExpression(expression: IExpression): ParsedExpression {
return
<
ParsedStringPattern
>
parsedPatterns
[
0
];
}
return
function
(
path
:
string
,
basename
:
string
,
siblingsFn
?:
()
=>
string
[])
{
const
resultExpression
:
ParsedStringPattern
=
function
(
path
:
string
,
basename
:
string
,
siblingsFn
?:
()
=>
string
[])
{
for
(
let
i
=
0
,
n
=
parsedPatterns
.
length
;
i
<
n
;
i
++
)
{
// Pattern matches path
const
result
=
(
<
ParsedStringPattern
>
parsedPatterns
[
i
])(
path
,
basename
);
...
...
@@ -389,9 +406,16 @@ function parsedExpression(expression: IExpression): ParsedExpression {
return
null
;
};
const
withBasenames
=
arrays
.
first
(
parsedPatterns
,
pattern
=>
!!
(
<
ParsedStringPattern
>
pattern
).
allBasenames
);
if
(
withBasenames
)
{
resultExpression
.
allBasenames
=
(
<
ParsedStringPattern
>
withBasenames
).
allBasenames
;
}
return
resultExpression
;
}
return
function
(
path
:
string
,
basename
:
string
,
siblingsFn
?:
()
=>
string
[])
{
const
resultExpression
:
ParsedStringPattern
=
function
(
path
:
string
,
basename
:
string
,
siblingsFn
?:
()
=>
string
[])
{
let
siblingsPattern
:
SiblingsPattern
;
let
siblingsResolved
=
!
siblingsFn
;
...
...
@@ -421,6 +445,13 @@ function parsedExpression(expression: IExpression): ParsedExpression {
return
null
;
};
const
withBasenames
=
arrays
.
first
(
parsedPatterns
,
pattern
=>
!!
(
<
ParsedStringPattern
>
pattern
).
allBasenames
);
if
(
withBasenames
)
{
resultExpression
.
allBasenames
=
(
<
ParsedStringPattern
>
withBasenames
).
allBasenames
;
}
return
resultExpression
;
}
function
parseExpressionPattern
(
pattern
:
string
,
value
:
any
):
(
ParsedStringPattern
|
ParsedExpressionPattern
)
{
...
...
@@ -503,6 +534,7 @@ function aggregateBasenameMatches(parsedPatterns: (ParsedStringPattern | ParsedE
};
aggregate
.
basenames
=
basenames
;
aggregate
.
patterns
=
patterns
;
aggregate
.
allBasenames
=
basenames
;
const
aggregatedPatterns
=
parsedPatterns
.
filter
(
parsedPattern
=>
!
(
<
ParsedStringPattern
>
parsedPattern
).
basenames
);
aggregatedPatterns
.
push
(
aggregate
);
...
...
src/vs/base/test/common/glob.test.ts
浏览文件 @
50bb7aad
...
...
@@ -668,7 +668,7 @@ suite('Glob', () => {
assert
.
strictEqual
(
glob
.
parse
(
''
)(
'
foo
'
),
false
);
});
test
(
'
expression
falsy path
'
,
function
()
{
test
(
'
falsy path
'
,
function
()
{
assert
.
strictEqual
(
glob
.
parse
(
'
foo
'
)(
null
),
false
);
assert
.
strictEqual
(
glob
.
parse
(
'
foo
'
)(
''
),
false
);
assert
.
strictEqual
(
glob
.
parse
(
'
**/*.j?
'
)(
null
),
false
);
...
...
@@ -683,7 +683,7 @@ suite('Glob', () => {
assert
.
strictEqual
(
glob
.
parse
(
'
{**/*.baz,**/*.foo}
'
)(
''
),
false
);
});
test
(
'
expression basename
'
,
function
()
{
test
(
'
expression
/pattern
basename
'
,
function
()
{
assert
.
strictEqual
(
glob
.
parse
(
'
**/foo
'
)(
'
bar/baz
'
,
'
baz
'
),
false
);
assert
.
strictEqual
(
glob
.
parse
(
'
**/foo
'
)(
'
bar/foo
'
,
'
foo
'
),
true
);
...
...
@@ -696,4 +696,20 @@ suite('Glob', () => {
assert
.
strictEqual
(
glob
.
parse
(
expr
)(
'
bar/baz.js
'
,
'
baz.js
'
,
sibilings
),
null
);
assert
.
strictEqual
(
glob
.
parse
(
expr
)(
'
bar/foo.js
'
,
'
foo.js
'
,
sibilings
),
'
**/*.js
'
);
});
test
(
'
expression/pattern basename terms
'
,
function
()
{
assert
.
deepStrictEqual
(
glob
.
getBasenameTerms
(
glob
.
parse
(
'
**/*.foo
'
)),
[]);
assert
.
deepStrictEqual
(
glob
.
getBasenameTerms
(
glob
.
parse
(
'
**/foo
'
)),
[
'
foo
'
]);
assert
.
deepStrictEqual
(
glob
.
getBasenameTerms
(
glob
.
parse
(
'
{**/baz,**/foo}
'
)),
[
'
baz
'
,
'
foo
'
]);
assert
.
deepStrictEqual
(
glob
.
getBasenameTerms
(
glob
.
parse
({
'
**/foo
'
:
true
,
'
{**/bar,**/baz}
'
:
true
,
'
**/bulb
'
:
false
})),
[
'
foo
'
,
'
bar
'
,
'
baz
'
]);
assert
.
deepStrictEqual
(
glob
.
getBasenameTerms
(
glob
.
parse
({
'
**/foo
'
:
{
when
:
'
$(basename).zip
'
},
'
**/bar
'
:
true
})),
[
'
bar
'
]);
});
});
\ No newline at end of file
src/vs/workbench/services/search/node/fileSearch.ts
浏览文件 @
50bb7aad
...
...
@@ -169,7 +169,7 @@ export class FileWalker {
}
private
macFindTraversal
(
rootFolder
:
string
,
onResult
:
(
result
:
IRawFileMatch
)
=>
void
,
done
:
(
err
?:
Error
)
=>
void
):
void
{
const
cmd
=
childProcess
.
spawn
(
'
find
'
,
[
'
-L
'
,
'
.
'
,
'
-type
'
,
'
f
'
],
{
cwd
:
rootFolder
}
);
const
cmd
=
this
.
spawnFindCmd
(
rootFolder
,
this
.
excludePattern
);
this
.
readStdout
(
cmd
,
'
utf8
'
,
(
err
:
Error
,
stdout
?:
string
)
=>
{
if
(
err
)
{
done
(
err
);
...
...
@@ -224,7 +224,7 @@ export class FileWalker {
}
private linuxFindTraversal(rootFolder: string, onResult: (result: IRawFileMatch) => void, done: (err?: Error) => void): void {
const cmd =
childProcess.spawn('find', ['-L', '.', '-type', 'f'], { cwd: rootFolder }
);
const cmd =
this.spawnFindCmd(rootFolder, this.excludePattern
);
this.readStdout(cmd, 'utf8', (err: Error, stdout?: string) => {
if (err) {
done(err);
...
...
@@ -250,7 +250,36 @@ export class FileWalker {
});
}
private readStdout(cmd: childProcess.ChildProcess, encoding: string, cb: (err: Error, stdout?: string) => void): void {
/**
* Public for testing.
*/
public spawnFindCmd(rootFolder: string, excludePattern: glob.ParsedExpression) {
const basenames = glob.getBasenameTerms(excludePattern);
let args = ['-L', '.'];
if (basenames.length) {
args.push('-not', '(', '(');
for (let i = 0, n = basenames.length; i < n; i++) {
if (i) {
args.push('-o');
}
args.push('-name', FileWalker.escapeGlobSpecials(basenames[i]));
}
args.push(')', '-prune', ')');
}
args.push('-type', 'f');
return childProcess.spawn('find', args, { cwd: rootFolder });
}
private static GLOB_SPECIALS = /[*?\[\]\\]/g;
private static ESCAPE_CHAR = '\
\$
&';
private static escapeGlobSpecials(string) {
return string.replace(this.GLOB_SPECIALS, this.ESCAPE_CHAR);
}
/**
* Public for testing.
*/
public readStdout(cmd: childProcess.ChildProcess, encoding: string, cb: (err: Error, stdout?: string) => void): void {
let done = (err: Error, stdout?: string) => {
done = () => {};
this.cmdForkResultTime = Date.now();
...
...
src/vs/workbench/services/search/test/node/fixtures/more/file.txt
0 → 100644
浏览文件 @
50bb7aad
src/vs/workbench/services/search/test/node/search.test.ts
浏览文件 @
50bb7aad
...
...
@@ -8,7 +8,9 @@
import
path
=
require
(
'
path
'
);
import
assert
=
require
(
'
assert
'
);
import
*
as
glob
from
'
vs/base/common/glob
'
;
import
{
join
,
normalize
}
from
'
vs/base/common/paths
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
{
LineMatch
}
from
'
vs/platform/search/common/search
'
;
import
{
FileWalker
,
Engine
as
FileSearchEngine
}
from
'
vs/workbench/services/search/node/fileSearch
'
;
...
...
@@ -119,7 +121,7 @@ suite('Search', () => {
}
},
()
=>
{
},
(
error
)
=>
{
assert
.
ok
(
!
error
);
assert
.
equal
(
count
,
1
2
);
assert
.
equal
(
count
,
1
3
);
done
();
});
});
...
...
@@ -178,7 +180,7 @@ suite('Search', () => {
}
},
()
=>
{
},
(
error
)
=>
{
assert
.
ok
(
!
error
);
assert
.
equal
(
count
,
7
);
assert
.
equal
(
count
,
8
);
done
();
});
});
...
...
@@ -197,7 +199,7 @@ suite('Search', () => {
}
},
()
=>
{
},
(
error
)
=>
{
assert
.
ok
(
!
error
);
assert
.
equal
(
count
,
7
);
assert
.
equal
(
count
,
8
);
done
();
});
});
...
...
@@ -216,7 +218,7 @@ suite('Search', () => {
}
},
()
=>
{
},
(
error
)
=>
{
assert
.
ok
(
!
error
);
assert
.
equal
(
count
,
7
);
assert
.
equal
(
count
,
8
);
done
();
});
});
...
...
@@ -235,7 +237,7 @@ suite('Search', () => {
}
},
()
=>
{
},
(
error
)
=>
{
assert
.
ok
(
!
error
);
assert
.
equal
(
count
,
1
1
);
assert
.
equal
(
count
,
1
2
);
done
();
});
});
...
...
@@ -421,6 +423,59 @@ suite('Search', () => {
});
});
test
(
'
Find: exclude subfolder
'
,
function
(
done
:
()
=>
void
)
{
if
(
platform
.
isWindows
)
{
return
;
}
const
walker
=
new
FileWalker
({
rootFolders
:
rootfolders
()
});
const
file0
=
'
./more/file.txt
'
;
const
file1
=
'
./examples/subfolder/subfile.txt
'
;
const
cmd1
=
walker
.
spawnFindCmd
(
rootfolders
()[
0
],
glob
.
parse
({
'
**/something
'
:
true
}));
walker
.
readStdout
(
cmd1
,
'
utf8
'
,
(
err1
,
stdout1
)
=>
{
assert
.
equal
(
err1
,
null
);
assert
.
notStrictEqual
(
stdout1
.
split
(
'
\n
'
).
indexOf
(
file0
),
-
1
,
stdout1
);
assert
.
notStrictEqual
(
stdout1
.
split
(
'
\n
'
).
indexOf
(
file1
),
-
1
,
stdout1
);
const
cmd2
=
walker
.
spawnFindCmd
(
rootfolders
()[
0
],
glob
.
parse
({
'
**/subfolder
'
:
true
}));
walker
.
readStdout
(
cmd2
,
'
utf8
'
,
(
err2
,
stdout2
)
=>
{
assert
.
equal
(
err2
,
null
);
assert
.
notStrictEqual
(
stdout1
.
split
(
'
\n
'
).
indexOf
(
file0
),
-
1
,
stdout1
);
assert
.
strictEqual
(
stdout2
.
split
(
'
\n
'
).
indexOf
(
file1
),
-
1
,
stdout2
);
done
();
});
});
});
test
(
'
Find: exclude multiple folders
'
,
function
(
done
:
()
=>
void
)
{
if
(
platform
.
isWindows
)
{
return
;
}
const
walker
=
new
FileWalker
({
rootFolders
:
rootfolders
()
});
const
file0
=
'
./index.html
'
;
const
file1
=
'
./examples/small.js
'
;
const
file2
=
'
./more/file.txt
'
;
const
cmd1
=
walker
.
spawnFindCmd
(
rootfolders
()[
0
],
glob
.
parse
({
'
**/something
'
:
true
}));
walker
.
readStdout
(
cmd1
,
'
utf8
'
,
(
err1
,
stdout1
)
=>
{
assert
.
equal
(
err1
,
null
);
assert
.
notStrictEqual
(
stdout1
.
split
(
'
\n
'
).
indexOf
(
file0
),
-
1
,
stdout1
);
assert
.
notStrictEqual
(
stdout1
.
split
(
'
\n
'
).
indexOf
(
file1
),
-
1
,
stdout1
);
assert
.
notStrictEqual
(
stdout1
.
split
(
'
\n
'
).
indexOf
(
file2
),
-
1
,
stdout1
);
const
cmd2
=
walker
.
spawnFindCmd
(
rootfolders
()[
0
],
glob
.
parse
({
'
{**/examples,**/more}
'
:
true
}));
walker
.
readStdout
(
cmd2
,
'
utf8
'
,
(
err2
,
stdout2
)
=>
{
assert
.
equal
(
err2
,
null
);
assert
.
notStrictEqual
(
stdout1
.
split
(
'
\n
'
).
indexOf
(
file0
),
-
1
,
stdout1
);
assert
.
strictEqual
(
stdout2
.
split
(
'
\n
'
).
indexOf
(
file1
),
-
1
,
stdout2
);
assert
.
strictEqual
(
stdout2
.
split
(
'
\n
'
).
indexOf
(
file2
),
-
1
,
stdout2
);
done
();
});
});
});
test
(
'
Text: GameOfLife
'
,
function
(
done
:
()
=>
void
)
{
let
c
=
0
;
let
config
=
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录