Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
后端镜像
rust镜像
Ripgrep
提交
03d9df43
R
Ripgrep
项目概览
后端镜像
/
rust镜像
/
Ripgrep
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Ripgrep
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
03d9df43
编写于
8月 31, 2016
作者:
A
Andrew Gallant
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
tests and refactoring search
上级
d011cea0
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
251 addition
and
61 deletion
+251
-61
src/search.rs
src/search.rs
+251
-61
未找到文件。
src/search.rs
浏览文件 @
03d9df43
...
...
@@ -63,6 +63,9 @@ pub struct Searcher<'a, R, W: 'a> {
grep
:
&
'a
Grep
,
path
:
&
'a
Path
,
haystack
:
R
,
match_count
:
u64
,
line_count
:
Option
<
u64
>
,
last_match
:
Match
,
count
:
bool
,
invert_match
:
bool
,
line_number
:
bool
,
...
...
@@ -94,6 +97,9 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
grep
:
grep
,
path
:
path
,
haystack
:
haystack
,
match_count
:
0
,
line_count
:
None
,
last_match
:
Match
::
default
(),
count
:
false
,
invert_match
:
false
,
line_number
:
false
,
...
...
@@ -127,9 +133,9 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
#[inline(never)]
pub
fn
run
(
mut
self
)
->
Result
<
u64
,
Error
>
{
self
.inp
.reset
();
let
mut
match_count
=
0
;
let
mut
line_count
=
if
self
.line_number
{
Some
(
0
)
}
else
{
None
};
let
mut
mat
=
Match
::
default
();
self
.
match_count
=
0
;
self
.
line_count
=
if
self
.line_number
{
Some
(
0
)
}
else
{
None
};
self
.last_match
=
Match
::
default
();
loop
{
let
ok
=
try!
(
self
.inp
.fill
(
&
mut
self
.haystack
)
.map_err
(|
err
|
{
Error
::
from_io
(
err
,
&
self
.path
)
...
...
@@ -139,88 +145,88 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
}
while
self
.inp.pos
<
self
.inp.lastnl
{
let
ok
=
self
.grep
.read_match
(
&
mut
mat
,
&
mut
self
.last_match
,
&
mut
self
.inp.buf
[
..
self
.inp.lastnl
],
self
.inp.pos
);
if
!
ok
{
let
upto
=
self
.inp.lastnl
;
if
self
.invert_match
{
while
let
Some
(
pos
)
=
memchr
(
b
'\n'
,
&
self
.inp.buf
[
self
.inp.pos
..
self
.inp.lastnl
])
{
if
let
Some
(
ref
mut
line_count
)
=
line_count
{
*
line_count
+=
1
;
}
self
.printer
.matched
(
&
self
.path
,
&
self
.inp.buf
,
self
.inp.pos
,
self
.inp.pos
+
pos
,
line_count
,
);
self
.inp.pos
+=
pos
+
1
;
match_count
+=
1
;
if
self
.inp.pos
>=
self
.inp.lastnl
{
break
;
}
}
self
.inp.pos
=
self
.inp.lastnl
;
}
else
if
let
Some
(
ref
mut
line_count
)
=
line_count
{
*
line_count
+=
count_lines
(
&
self
.inp.buf
[
self
.inp.pos
..
self
.inp.lastnl
]);
self
.find_inverted_matches
(
upto
);
}
else
{
self
.count_lines
(
upto
);
}
self
.inp.pos
=
upto
;
break
;
}
if
self
.invert_match
{
while
let
Some
(
pos
)
=
memchr
(
b
'\n'
,
&
self
.inp.buf
[
self
.inp.pos
..
mat
.start
()])
{
if
let
Some
(
ref
mut
line_count
)
=
line_count
{
*
line_count
+=
1
;
}
self
.printer
.matched
(
&
self
.path
,
&
self
.inp.buf
,
self
.inp.pos
,
self
.inp.pos
+
pos
,
line_count
,
);
self
.inp.pos
+=
pos
+
1
;
match_count
+=
1
;
}
if
let
Some
(
ref
mut
line_count
)
=
line_count
{
let
inverted_upto
=
self
.last_match
.start
();
self
.find_inverted_matches
(
inverted_upto
);
// Add a line to account for the match...
if
let
Some
(
ref
mut
line_count
)
=
self
.line_count
{
*
line_count
+=
1
;
}
self
.inp.pos
=
mat
.end
()
+
1
;
// ... and skip over the match.
self
.inp.pos
=
self
.last_match
.end
()
+
1
;
}
else
{
if
let
Some
(
ref
mut
line_count
)
=
line_count
{
// mat.end() always points immediately after the end
// of a match, which could be *at* a nl or past our
// current search buffer. Either way, count it as one
// more line.
*
line_count
+=
1
+
count_lines
(
&
self
.inp.buf
[
self
.inp.pos
..
mat
.end
()]);
}
match_count
+=
1
;
self
.match_count
+=
1
;
if
!
self
.count
{
let
upto
=
cmp
::
min
(
self
.inp.lastnl
,
self
.last_match
.end
()
+
1
);
self
.count_lines
(
upto
);
self
.printer
.matched
(
self
.path
,
&
self
.inp.buf
,
mat
.start
(),
mat
.end
(),
line_count
,
self
.last_match
.start
(),
self
.last_match
.end
(),
self
.
line_count
,
);
}
// Move the position one past the end of the match so that
// the next search starts after the nl. If we're at EOF,
// then pos will be past EOF.
self
.inp.pos
=
mat
.end
()
+
1
;
self
.inp.pos
=
self
.last_match
.end
()
+
1
;
}
}
}
if
self
.count
&&
match_count
>
0
{
self
.printer
.path_count
(
self
.path
,
match_count
);
if
self
.count
&&
self
.match_count
>
0
{
self
.printer
.path_count
(
self
.path
,
self
.match_count
);
}
Ok
(
self
.match_count
)
}
#[inline(always)]
fn
find_inverted_matches
(
&
mut
self
,
upto
:
usize
)
{
debug_assert!
(
self
.invert_match
);
while
self
.inp.pos
<
upto
{
let
pos
=
memchr
(
b
'\n'
,
&
self
.inp.buf
[
self
.inp.pos
..
upto
])
.unwrap_or
(
upto
);
if
!
self
.count
{
if
let
Some
(
ref
mut
line_count
)
=
self
.line_count
{
*
line_count
+=
1
;
}
self
.printer
.matched
(
&
self
.path
,
&
self
.inp.buf
,
self
.inp.pos
,
self
.inp.pos
+
pos
,
self
.line_count
,
);
}
self
.inp.pos
+=
pos
+
1
;
self
.match_count
+=
1
;
}
}
#[inline(always)]
fn
count_lines
(
&
mut
self
,
upto
:
usize
)
{
if
let
Some
(
ref
mut
line_count
)
=
self
.line_count
{
*
line_count
+=
count_lines
(
&
self
.inp.buf
[
self
.inp.pos
..
upto
]);
}
Ok
(
match_count
)
}
}
pub
struct
InputBuffer
{
read_size
:
usize
,
buf
:
Vec
<
u8
>
,
tmp
:
Vec
<
u8
>
,
pos
:
usize
,
...
...
@@ -240,8 +246,12 @@ impl InputBuffer {
///
/// The capacity determines the size of each read from the underlying
/// reader.
pub
fn
with_capacity
(
cap
:
usize
)
->
InputBuffer
{
pub
fn
with_capacity
(
mut
cap
:
usize
)
->
InputBuffer
{
if
cap
==
0
{
cap
=
1
;
}
InputBuffer
{
read_size
:
cap
,
buf
:
vec!
[
0
;
cap
],
tmp
:
vec!
[],
pos
:
0
,
...
...
@@ -272,13 +282,13 @@ impl InputBuffer {
self
.pos
=
0
;
self
.lastnl
=
0
;
while
self
.lastnl
==
0
{
if
self
.buf
.len
()
-
self
.end
<
READ_SIZE
{
let
min_len
=
READ_SIZE
+
self
.buf
.len
()
-
self
.end
;
if
self
.buf
.len
()
-
self
.end
<
self
.read_size
{
let
min_len
=
self
.read_size
+
self
.buf
.len
()
-
self
.end
;
let
new_len
=
cmp
::
max
(
min_len
,
self
.buf
.len
()
*
2
);
self
.buf
.resize
(
new_len
,
0
);
}
let
n
=
try!
(
rdr
.read
(
&
mut
self
.buf
[
self
.end
..
self
.end
+
READ_SIZE
]));
&
mut
self
.buf
[
self
.end
..
self
.end
+
self
.read_size
]));
if
self
.first
{
if
is_binary
(
&
self
.buf
[
self
.end
..
self
.end
+
n
])
{
return
Ok
(
false
);
...
...
@@ -306,6 +316,7 @@ impl InputBuffer {
}
}
#[inline(always)]
fn
is_binary
(
buf
:
&
[
u8
])
->
bool
{
if
buf
.len
()
>=
4
&&
&
buf
[
0
..
4
]
==
b
"%PDF"
{
return
true
;
...
...
@@ -313,6 +324,7 @@ fn is_binary(buf: &[u8]) -> bool {
memchr
(
b
'\x00'
,
&
buf
[
0
..
cmp
::
min
(
1024
,
buf
.len
())])
.is_some
()
}
#[inline(always)]
fn
count_lines
(
mut
buf
:
&
[
u8
])
->
u64
{
let
mut
count
=
0
;
while
let
Some
(
pos
)
=
memchr
(
b
'\n'
,
buf
)
{
...
...
@@ -321,3 +333,181 @@ fn count_lines(mut buf: &[u8]) -> u64 {
}
count
}
#[cfg(test)]
mod
tests
{
use
std
::
io
;
use
std
::
path
::
Path
;
use
grep
::{
Grep
,
GrepBuilder
};
use
printer
::
Printer
;
use
super
::{
InputBuffer
,
Searcher
};
fn
hay
(
s
:
&
str
)
->
io
::
Cursor
<
Vec
<
u8
>>
{
io
::
Cursor
::
new
(
s
.to_string
()
.into_bytes
())
}
fn
matcher
(
pat
:
&
str
)
->
Grep
{
GrepBuilder
::
new
(
pat
)
.build
()
.unwrap
()
}
fn
test_path
()
->
&
'static
Path
{
&
Path
::
new
(
"/baz.rs"
)
}
#[test]
fn
basic_search
()
{
let
text
=
hay
(
"
\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.
\
"
);
let
mut
inp
=
InputBuffer
::
with_capacity
(
1
);
let
mut
pp
=
Printer
::
new
(
vec!
[]);
let
grep
=
matcher
(
"Sherlock"
);
let
count
=
{
let
searcher
=
Searcher
::
new
(
&
mut
inp
,
&
mut
pp
,
&
grep
,
test_path
(),
text
);
searcher
.run
()
.unwrap
()
};
assert_eq!
(
2
,
count
);
let
out
=
String
::
from_utf8
(
pp
.into_inner
())
.unwrap
();
assert_eq!
(
out
,
"
\
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
/baz.rs:be, to a very large extent, the result of luck. Sherlock Holmes
"
);
}
#[test]
fn
line_numbers
()
{
let
text
=
hay
(
"
\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.
\
"
);
let
mut
inp
=
InputBuffer
::
with_capacity
(
1
);
let
mut
pp
=
Printer
::
new
(
vec!
[]);
let
grep
=
matcher
(
"Sherlock"
);
let
count
=
{
let
searcher
=
Searcher
::
new
(
&
mut
inp
,
&
mut
pp
,
&
grep
,
test_path
(),
text
);
searcher
.line_number
(
true
)
.run
()
.unwrap
()
};
assert_eq!
(
2
,
count
);
let
out
=
String
::
from_utf8
(
pp
.into_inner
())
.unwrap
();
assert_eq!
(
out
,
"
\
/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock
/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes
"
);
}
#[test]
fn
count
()
{
let
text
=
hay
(
"
\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.
\
"
);
let
mut
inp
=
InputBuffer
::
with_capacity
(
1
);
let
mut
pp
=
Printer
::
new
(
vec!
[]);
let
grep
=
matcher
(
"Sherlock"
);
let
count
=
{
let
searcher
=
Searcher
::
new
(
&
mut
inp
,
&
mut
pp
,
&
grep
,
test_path
(),
text
);
searcher
.count
(
true
)
.run
()
.unwrap
()
};
assert_eq!
(
2
,
count
);
let
out
=
String
::
from_utf8
(
pp
.into_inner
())
.unwrap
();
assert_eq!
(
out
,
"/baz.rs:2
\n
"
);
}
#[test]
fn
invert_match
()
{
let
text
=
hay
(
"
\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.
\
"
);
let
mut
inp
=
InputBuffer
::
with_capacity
(
1
);
let
mut
pp
=
Printer
::
new
(
vec!
[]);
let
grep
=
matcher
(
"Sherlock"
);
let
count
=
{
let
searcher
=
Searcher
::
new
(
&
mut
inp
,
&
mut
pp
,
&
grep
,
test_path
(),
text
);
searcher
.invert_match
(
true
)
.run
()
.unwrap
()
};
assert_eq!
(
4
,
count
);
let
out
=
String
::
from_utf8
(
pp
.into_inner
())
.unwrap
();
assert_eq!
(
out
,
"
\
/baz.rs:Holmeses, success in the province of detective work must always
/baz.rs:can extract a clew from a wisp of straw or a flake of cigar ash;
/baz.rs:but Doctor Watson has to have it taken out for him and dusted,
/baz.rs:and exhibited clearly, with a label attached.
"
);
}
#[test]
fn
invert_match_line_numbers
()
{
let
text
=
hay
(
"
\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.
\
"
);
let
mut
inp
=
InputBuffer
::
with_capacity
(
1
);
let
mut
pp
=
Printer
::
new
(
vec!
[]);
let
grep
=
matcher
(
"Sherlock"
);
let
count
=
{
let
searcher
=
Searcher
::
new
(
&
mut
inp
,
&
mut
pp
,
&
grep
,
test_path
(),
text
);
searcher
.invert_match
(
true
)
.line_number
(
true
)
.run
()
.unwrap
()
};
assert_eq!
(
4
,
count
);
let
out
=
String
::
from_utf8
(
pp
.into_inner
())
.unwrap
();
assert_eq!
(
out
,
"
\
/baz.rs:2:Holmeses, success in the province of detective work must always
/baz.rs:4:can extract a clew from a wisp of straw or a flake of cigar ash;
/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted,
/baz.rs:6:and exhibited clearly, with a label attached.
"
);
}
#[test]
fn
invert_match_count
()
{
let
text
=
hay
(
"
\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.
\
"
);
let
mut
inp
=
InputBuffer
::
with_capacity
(
1
);
let
mut
pp
=
Printer
::
new
(
vec!
[]);
let
grep
=
matcher
(
"Sherlock"
);
let
count
=
{
let
searcher
=
Searcher
::
new
(
&
mut
inp
,
&
mut
pp
,
&
grep
,
test_path
(),
text
);
searcher
.invert_match
(
true
)
.count
(
true
)
.run
()
.unwrap
()
};
assert_eq!
(
4
,
count
);
let
out
=
String
::
from_utf8
(
pp
.into_inner
())
.unwrap
();
assert_eq!
(
out
,
"/baz.rs:4
\n
"
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录