Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
后端镜像
rust镜像
Ripgrep
提交
0766617e
R
Ripgrep
项目概览
后端镜像
/
rust镜像
/
Ripgrep
通知
0
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,体验更适合开发者的 AI 搜索 >>
提交
0766617e
编写于
9月 08, 2016
作者:
A
Andrew Gallant
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Refactor how coloring is done.
All in the name of appeasing Windows.
上级
afd99c43
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
497 addition
and
380 deletion
+497
-380
src/args.rs
src/args.rs
+13
-7
src/main.rs
src/main.rs
+14
-11
src/out.rs
src/out.rs
+438
-42
src/printer.rs
src/printer.rs
+18
-312
src/search.rs
src/search.rs
+8
-4
src/search_buffer.rs
src/search_buffer.rs
+6
-4
未找到文件。
src/args.rs
浏览文件 @
0766617e
...
...
@@ -9,11 +9,12 @@ use grep::{Grep, GrepBuilder};
use
log
;
use
num_cpus
;
use
regex
;
use
term
::
Terminal
;
use
walkdir
::
WalkDir
;
use
gitignore
::{
Gitignore
,
GitignoreBuilder
};
use
ignore
::
Ignore
;
use
out
::
Out
;
use
out
::
{
Out
,
OutBuffer
}
;
use
printer
::
Printer
;
use
search
::{
InputBuffer
,
Searcher
};
use
search_buffer
::
BufferSearcher
;
...
...
@@ -438,8 +439,8 @@ impl Args {
/// Create a new printer of individual search results that writes to the
/// writer given.
pub
fn
printer
<
W
:
Send
+
io
::
Write
>
(
&
self
,
wtr
:
W
)
->
Printer
<
W
>
{
let
mut
p
=
Printer
::
new
(
wtr
,
self
.color
)
pub
fn
printer
<
W
:
Send
+
Terminal
>
(
&
self
,
wtr
:
W
)
->
Printer
<
W
>
{
let
mut
p
=
Printer
::
new
(
wtr
)
.column
(
self
.column
)
.context_separator
(
self
.context_separator
.clone
())
.eol
(
self
.eol
)
...
...
@@ -454,8 +455,8 @@ impl Args {
/// Create a new printer of search results for an entire file that writes
/// to the writer given.
pub
fn
out
<
W
:
io
::
Write
>
(
&
self
,
wtr
:
W
)
->
Out
<
W
>
{
let
mut
out
=
Out
::
new
(
wt
r
);
pub
fn
out
(
&
self
)
->
Out
{
let
mut
out
=
Out
::
new
(
self
.colo
r
);
if
self
.heading
&&
!
self
.count
{
out
=
out
.file_separator
(
b
""
.to_vec
());
}
else
if
self
.before_context
>
0
||
self
.after_context
>
0
{
...
...
@@ -464,6 +465,11 @@ impl Args {
out
}
/// Create a new buffer for use with searching.
pub
fn
outbuf
(
&
self
)
->
OutBuffer
{
OutBuffer
::
new
(
self
.color
)
}
/// Return the paths that should be searched.
pub
fn
paths
(
&
self
)
->
&
[
PathBuf
]
{
&
self
.paths
...
...
@@ -472,7 +478,7 @@ impl Args {
/// Create a new line based searcher whose configuration is taken from the
/// command line. This searcher supports a dizzying array of features:
/// inverted matching, line counting, context control and more.
pub
fn
searcher
<
'a
,
R
:
io
::
Read
,
W
:
Send
+
io
::
Write
>
(
pub
fn
searcher
<
'a
,
R
:
io
::
Read
,
W
:
Send
+
Terminal
>
(
&
self
,
inp
:
&
'a
mut
InputBuffer
,
printer
:
&
'a
mut
Printer
<
W
>
,
...
...
@@ -493,7 +499,7 @@ impl Args {
/// Create a new line based searcher whose configuration is taken from the
/// command line. This search operates on an entire file all once (which
/// may have been memory mapped).
pub
fn
searcher_buffer
<
'a
,
W
:
Send
+
io
::
Write
>
(
pub
fn
searcher_buffer
<
'a
,
W
:
Send
+
Terminal
>
(
&
self
,
printer
:
&
'a
mut
Printer
<
W
>
,
grep
:
&
'a
Grep
,
...
...
src/main.rs
浏览文件 @
0766617e
...
...
@@ -39,7 +39,7 @@ use term::Terminal;
use
walkdir
::
DirEntry
;
use
args
::
Args
;
use
out
::
Out
;
use
out
::
{
NoColorTerminal
,
Out
,
OutBuffer
}
;
use
printer
::
Printer
;
use
search
::
InputBuffer
;
...
...
@@ -90,7 +90,8 @@ fn run(args: Args) -> Result<u64> {
return
run_types
(
args
);
}
let
args
=
Arc
::
new
(
args
);
let
out
=
Arc
::
new
(
Mutex
::
new
(
args
.out
(
io
::
stdout
())));
let
out
=
Arc
::
new
(
Mutex
::
new
(
args
.out
()));
let
outbuf
=
args
.outbuf
();
let
mut
workers
=
vec!
[];
let
mut
workq
=
{
...
...
@@ -101,7 +102,7 @@ fn run(args: Args) -> Result<u64> {
out
:
out
.clone
(),
chan_work
:
stealer
.clone
(),
inpbuf
:
args
.input_buffer
(),
outbuf
:
Some
(
vec!
[]
),
outbuf
:
Some
(
outbuf
.clone
()
),
grep
:
args
.grep
(),
match_count
:
0
,
};
...
...
@@ -129,7 +130,8 @@ fn run(args: Args) -> Result<u64> {
}
fn
run_files
(
args
:
Args
)
->
Result
<
u64
>
{
let
mut
printer
=
args
.printer
(
io
::
BufWriter
::
new
(
io
::
stdout
()));
let
term
=
NoColorTerminal
::
new
(
io
::
BufWriter
::
new
(
io
::
stdout
()));
let
mut
printer
=
args
.printer
(
term
);
let
mut
file_count
=
0
;
for
p
in
args
.paths
()
{
if
p
==
Path
::
new
(
"-"
)
{
...
...
@@ -146,7 +148,8 @@ fn run_files(args: Args) -> Result<u64> {
}
fn
run_types
(
args
:
Args
)
->
Result
<
u64
>
{
let
mut
printer
=
args
.printer
(
io
::
BufWriter
::
new
(
io
::
stdout
()));
let
term
=
NoColorTerminal
::
new
(
io
::
BufWriter
::
new
(
io
::
stdout
()));
let
mut
printer
=
args
.printer
(
term
);
let
mut
ty_count
=
0
;
for
def
in
args
.type_defs
()
{
printer
.type_def
(
def
);
...
...
@@ -168,10 +171,10 @@ enum WorkReady {
struct
Worker
{
args
:
Arc
<
Args
>
,
out
:
Arc
<
Mutex
<
Out
<
io
::
Stdout
>
>>
,
out
:
Arc
<
Mutex
<
Out
>>
,
chan_work
:
Stealer
<
Work
>
,
inpbuf
:
InputBuffer
,
outbuf
:
Option
<
Vec
<
u8
>
>
,
outbuf
:
Option
<
OutBuffer
>
,
grep
:
Grep
,
match_count
:
u64
,
}
...
...
@@ -203,12 +206,12 @@ impl Worker {
let
mut
out
=
self
.out
.lock
()
.unwrap
();
out
.write
(
&
outbuf
);
}
self
.outbuf
=
Some
(
outbuf
.into_inner
()
);
self
.outbuf
=
Some
(
outbuf
);
}
self
.match_count
}
fn
do_work
<
W
:
Send
+
io
::
Write
>
(
fn
do_work
<
W
:
Send
+
Terminal
>
(
&
mut
self
,
printer
:
&
mut
Printer
<
W
>
,
work
:
WorkReady
,
...
...
@@ -241,7 +244,7 @@ impl Worker {
}
}
fn
search
<
R
:
io
::
Read
,
W
:
Send
+
io
::
Write
>
(
fn
search
<
R
:
io
::
Read
,
W
:
Send
+
Terminal
>
(
&
mut
self
,
printer
:
&
mut
Printer
<
W
>
,
path
:
&
Path
,
...
...
@@ -256,7 +259,7 @@ impl Worker {
)
.run
()
.map_err
(
From
::
from
)
}
fn
search_mmap
<
W
:
Send
+
io
::
Write
>
(
fn
search_mmap
<
W
:
Send
+
Terminal
>
(
&
mut
self
,
printer
:
&
mut
Printer
<
W
>
,
path
:
&
Path
,
...
...
src/out.rs
浏览文件 @
0766617e
use
std
::
io
::{
self
,
Write
};
use
std
::
sync
::
Arc
;
use
term
::{
StdoutTerminal
,
Terminal
};
use
term
::{
self
,
Terminal
};
use
term
::
color
::
Color
;
use
term
::
terminfo
::
TermInfo
;
#[cfg(windows)]
use
term
::
WinConsole
;
use
printer
::
Writer
;
use
terminal
::
TerminfoTerminal
;
pub
type
StdoutTerminal
=
Box
<
Terminal
<
Output
=
io
::
BufWriter
<
io
::
Stdout
>>
+
Send
>
;
/// Gets a terminal that supports color if available.
#[cfg(windows)]
fn
term_stdout
(
color
:
bool
)
->
StdoutTerminal
{
let
stdout
=
io
::
BufWriter
::
new
(
io
::
stdout
());
WinConsole
::
new
(
stdout
)
.ok
()
.map
(|
t
|
Box
::
new
(
t
))
.unwrap_or_else
(||
{
let
stdout
=
io
::
BufWriter
::
new
(
io
::
stdout
());
Box
::
new
(
NoColorTerminal
::
new
(
stdout
))
})
}
/// Gets a terminal that supports color if available.
#[cfg(not(windows))]
fn
term_stdout
(
color
:
bool
)
->
StdoutTerminal
{
let
stdout
=
io
::
BufWriter
::
new
(
io
::
stdout
());
if
!
color
||
TERMINFO
.is_none
()
{
Box
::
new
(
NoColorTerminal
::
new
(
stdout
))
}
else
{
let
info
=
TERMINFO
.clone
()
.unwrap
();
Box
::
new
(
TerminfoTerminal
::
new_with_terminfo
(
stdout
,
info
))
}
}
/// Out controls the actual output of all search results for a particular file
/// to the end user.
...
...
@@ -12,34 +42,17 @@ use printer::Writer;
/// (The difference between Out and Printer is that a Printer works with
/// individual search results where as Out works with search results for each
/// file as a whole. For example, it knows when to print a file separator.)
pub
struct
Out
<
W
:
io
::
Write
>
{
wtr
:
io
::
BufWriter
<
W
>
,
term
:
Option
<
Box
<
StdoutTerminal
>>
,
pub
struct
Out
{
term
:
StdoutTerminal
,
printed
:
bool
,
file_separator
:
Option
<
Vec
<
u8
>>
,
}
/// This is like term::stdout, but on Windows always uses WinConsole instead
/// of trying for a TerminfoTerminal. This may be a mistake.
#[cfg(windows)]
fn
term_stdout
()
->
Option
<
Box
<
StdoutTerminal
>>
{
WinConsole
::
new
(
io
::
stdout
())
.ok
()
.map
(|
t
|
Box
::
new
(
t
)
as
Box
<
StdoutTerminal
>
)
}
#[cfg(not(windows))]
fn
term_stdout
()
->
Option
<
Box
<
StdoutTerminal
>>
{
// We never use this crap on *nix.
None
}
impl
<
W
:
io
::
Write
>
Out
<
W
>
{
impl
Out
{
/// Create a new Out that writes to the wtr given.
pub
fn
new
(
wtr
:
W
)
->
Out
<
W
>
{
pub
fn
new
(
color
:
bool
)
->
Out
{
Out
{
wtr
:
io
::
BufWriter
::
new
(
wtr
),
term
:
term_stdout
(),
term
:
term_stdout
(
color
),
printed
:
false
,
file_separator
:
None
,
}
...
...
@@ -49,39 +62,422 @@ impl<W: io::Write> Out<W> {
/// By default, no separator is printed.
///
/// If sep is empty, then no file separator is printed.
pub
fn
file_separator
(
mut
self
,
sep
:
Vec
<
u8
>
)
->
Out
<
W
>
{
pub
fn
file_separator
(
mut
self
,
sep
:
Vec
<
u8
>
)
->
Out
{
self
.file_separator
=
Some
(
sep
);
self
}
/// Write the search results of a single file to the underlying wtr and
/// flush wtr.
pub
fn
write
(
&
mut
self
,
buf
:
&
Writer
<
Vec
<
u8
>>
)
{
pub
fn
write
(
&
mut
self
,
buf
:
&
OutBuffer
)
{
if
let
Some
(
ref
sep
)
=
self
.file_separator
{
if
self
.printed
{
let
_
=
self
.
wtr
.write_all
(
sep
);
let
_
=
self
.
wtr
.write_all
(
b
"
\n
"
);
let
_
=
self
.
term
.write_all
(
sep
);
let
_
=
self
.
term
.write_all
(
b
"
\n
"
);
}
}
match
*
buf
{
Writ
er
::
Colored
(
ref
tt
)
=>
{
let
_
=
self
.
wtr
.write_all
(
tt
.get_ref
());
OutBuff
er
::
Colored
(
ref
tt
)
=>
{
let
_
=
self
.
term
.write_all
(
tt
.get_ref
());
}
Writer
::
Windows
(
ref
w
)
=>
{
match
self
.term
{
None
=>
{
let
_
=
self
.wtr
.write_all
(
w
.get_ref
());
}
Some
(
ref
mut
stdout
)
=>
{
w
.print_stdout
(
stdout
);
}
}
OutBuffer
::
Windows
(
ref
w
)
=>
{
w
.print_stdout
(
&
mut
self
.term
);
}
Writ
er
::
NoColor
(
ref
buf
)
=>
{
let
_
=
self
.
wtr
.write_all
(
buf
);
OutBuff
er
::
NoColor
(
ref
buf
)
=>
{
let
_
=
self
.
term
.write_all
(
buf
);
}
}
let
_
=
self
.
wtr
.flush
();
let
_
=
self
.
term
.flush
();
self
.printed
=
true
;
}
}
/// OutBuffer corresponds to the final output buffer for search results. All
/// search results are written to a buffer and then a buffer is flushed to
/// stdout only after the full search has completed.
#[derive(Clone,
Debug)]
pub
enum
OutBuffer
{
Colored
(
TerminfoTerminal
<
Vec
<
u8
>>
),
Windows
(
WindowsBuffer
),
NoColor
(
Vec
<
u8
>
),
}
#[derive(Clone,
Debug)]
pub
struct
WindowsBuffer
{
buf
:
Vec
<
u8
>
,
pos
:
usize
,
colors
:
Vec
<
WindowsColor
>
,
}
#[derive(Clone,
Debug)]
pub
struct
WindowsColor
{
pos
:
usize
,
opt
:
WindowsOption
,
}
#[derive(Clone,
Debug)]
pub
enum
WindowsOption
{
Foreground
(
Color
),
Background
(
Color
),
Reset
,
}
lazy_static!
{
static
ref
TERMINFO
:
Option
<
Arc
<
TermInfo
>>
=
{
match
TermInfo
::
from_env
()
{
Ok
(
info
)
=>
Some
(
Arc
::
new
(
info
)),
Err
(
err
)
=>
{
debug!
(
"error loading terminfo for coloring: {}"
,
err
);
None
}
}
};
}
impl
OutBuffer
{
/// Create a new output buffer.
///
/// When color is true, the buffer will attempt to support coloring.
pub
fn
new
(
color
:
bool
)
->
OutBuffer
{
// If we want color, build a TerminfoTerminal and see if the current
// environment supports coloring. If not, bail with NoColor. To avoid
// losing our writer (ownership), do this the long way.
if
!
color
{
return
OutBuffer
::
NoColor
(
vec!
[]);
}
if
cfg!
(
windows
)
{
return
OutBuffer
::
Windows
(
WindowsBuffer
{
buf
:
vec!
[],
pos
:
0
,
colors
:
vec!
[]
});
}
if
TERMINFO
.is_none
()
{
return
OutBuffer
::
NoColor
(
vec!
[]);
}
let
info
=
TERMINFO
.clone
()
.unwrap
();
let
tt
=
TerminfoTerminal
::
new_with_terminfo
(
vec!
[],
info
);
if
!
tt
.supports_color
()
{
debug!
(
"environment doesn't support coloring"
);
return
OutBuffer
::
NoColor
(
tt
.into_inner
());
}
OutBuffer
::
Colored
(
tt
)
}
/// Clear the give buffer of all search results such that it is reusable
/// in another search.
pub
fn
clear
(
&
mut
self
)
{
match
*
self
{
OutBuffer
::
Colored
(
ref
mut
tt
)
=>
{
tt
.get_mut
()
.clear
();
}
OutBuffer
::
Windows
(
ref
mut
win
)
=>
{
win
.buf
.clear
();
win
.colors
.clear
();
win
.pos
=
0
;
}
OutBuffer
::
NoColor
(
ref
mut
buf
)
=>
{
buf
.clear
();
}
}
}
fn
map_result
<
F
,
G
>
(
&
mut
self
,
mut
f
:
F
,
mut
g
:
G
,
)
->
term
::
Result
<
()
>
where
F
:
FnMut
(
&
mut
TerminfoTerminal
<
Vec
<
u8
>>
)
->
term
::
Result
<
()
>
,
G
:
FnMut
(
&
mut
WindowsBuffer
)
->
term
::
Result
<
()
>
{
match
*
self
{
OutBuffer
::
Colored
(
ref
mut
w
)
=>
f
(
w
),
OutBuffer
::
Windows
(
ref
mut
w
)
=>
g
(
w
),
OutBuffer
::
NoColor
(
_
)
=>
Err
(
term
::
Error
::
NotSupported
),
}
}
fn
map_bool
<
F
,
G
>
(
&
self
,
mut
f
:
F
,
mut
g
:
G
,
)
->
bool
where
F
:
FnMut
(
&
TerminfoTerminal
<
Vec
<
u8
>>
)
->
bool
,
G
:
FnMut
(
&
WindowsBuffer
)
->
bool
{
match
*
self
{
OutBuffer
::
Colored
(
ref
w
)
=>
f
(
w
),
OutBuffer
::
Windows
(
ref
w
)
=>
g
(
w
),
OutBuffer
::
NoColor
(
_
)
=>
false
,
}
}
}
impl
io
::
Write
for
OutBuffer
{
fn
write
(
&
mut
self
,
buf
:
&
[
u8
])
->
io
::
Result
<
usize
>
{
match
*
self
{
OutBuffer
::
Colored
(
ref
mut
w
)
=>
w
.write
(
buf
),
OutBuffer
::
Windows
(
ref
mut
w
)
=>
w
.write
(
buf
),
OutBuffer
::
NoColor
(
ref
mut
w
)
=>
w
.write
(
buf
),
}
}
fn
flush
(
&
mut
self
)
->
io
::
Result
<
()
>
{
Ok
(())
}
}
impl
term
::
Terminal
for
OutBuffer
{
type
Output
=
Vec
<
u8
>
;
fn
fg
(
&
mut
self
,
fg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.fg
(
fg
),
|
w
|
w
.fg
(
fg
))
}
fn
bg
(
&
mut
self
,
bg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.bg
(
bg
),
|
w
|
w
.bg
(
bg
))
}
fn
attr
(
&
mut
self
,
attr
:
term
::
Attr
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.attr
(
attr
),
|
w
|
w
.attr
(
attr
))
}
fn
supports_attr
(
&
self
,
attr
:
term
::
Attr
)
->
bool
{
self
.map_bool
(|
w
|
w
.supports_attr
(
attr
),
|
w
|
w
.supports_attr
(
attr
))
}
fn
reset
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.reset
(),
|
w
|
w
.reset
())
}
fn
supports_reset
(
&
self
)
->
bool
{
self
.map_bool
(|
w
|
w
.supports_reset
(),
|
w
|
w
.supports_reset
())
}
fn
supports_color
(
&
self
)
->
bool
{
self
.map_bool
(|
w
|
w
.supports_color
(),
|
w
|
w
.supports_color
())
}
fn
cursor_up
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.cursor_up
(),
|
w
|
w
.cursor_up
())
}
fn
delete_line
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.delete_line
(),
|
w
|
w
.delete_line
())
}
fn
carriage_return
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.carriage_return
(),
|
w
|
w
.carriage_return
())
}
fn
get_ref
(
&
self
)
->
&
Vec
<
u8
>
{
match
*
self
{
OutBuffer
::
Colored
(
ref
w
)
=>
w
.get_ref
(),
OutBuffer
::
Windows
(
ref
w
)
=>
w
.get_ref
(),
OutBuffer
::
NoColor
(
ref
w
)
=>
w
,
}
}
fn
get_mut
(
&
mut
self
)
->
&
mut
Vec
<
u8
>
{
match
*
self
{
OutBuffer
::
Colored
(
ref
mut
w
)
=>
w
.get_mut
(),
OutBuffer
::
Windows
(
ref
mut
w
)
=>
w
.get_mut
(),
OutBuffer
::
NoColor
(
ref
mut
w
)
=>
w
,
}
}
fn
into_inner
(
self
)
->
Vec
<
u8
>
{
match
self
{
OutBuffer
::
Colored
(
w
)
=>
w
.into_inner
(),
OutBuffer
::
Windows
(
w
)
=>
w
.into_inner
(),
OutBuffer
::
NoColor
(
w
)
=>
w
,
}
}
}
impl
WindowsBuffer
{
fn
push
(
&
mut
self
,
opt
:
WindowsOption
)
{
let
pos
=
self
.pos
;
self
.colors
.push
(
WindowsColor
{
pos
:
pos
,
opt
:
opt
});
}
}
impl
WindowsBuffer
{
/// Print the contents to the given terminal.
pub
fn
print_stdout
(
&
self
,
tt
:
&
mut
StdoutTerminal
)
{
if
!
tt
.supports_color
()
{
let
_
=
tt
.write_all
(
&
self
.buf
);
let
_
=
tt
.flush
();
return
;
}
let
mut
last
=
0
;
for
col
in
&
self
.colors
{
let
_
=
tt
.write_all
(
&
self
.buf
[
last
..
col
.pos
]);
match
col
.opt
{
WindowsOption
::
Foreground
(
c
)
=>
{
let
_
=
tt
.fg
(
c
);
}
WindowsOption
::
Background
(
c
)
=>
{
let
_
=
tt
.bg
(
c
);
}
WindowsOption
::
Reset
=>
{
let
_
=
tt
.reset
();
}
}
last
=
col
.pos
;
}
let
_
=
tt
.write_all
(
&
self
.buf
[
last
..
]);
let
_
=
tt
.flush
();
}
}
impl
io
::
Write
for
WindowsBuffer
{
fn
write
(
&
mut
self
,
buf
:
&
[
u8
])
->
io
::
Result
<
usize
>
{
let
n
=
try!
(
self
.buf
.write
(
buf
));
self
.pos
+=
n
;
Ok
(
n
)
}
fn
flush
(
&
mut
self
)
->
io
::
Result
<
()
>
{
Ok
(())
}
}
impl
term
::
Terminal
for
WindowsBuffer
{
type
Output
=
Vec
<
u8
>
;
fn
fg
(
&
mut
self
,
fg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
self
.push
(
WindowsOption
::
Foreground
(
fg
));
Ok
(())
}
fn
bg
(
&
mut
self
,
bg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
self
.push
(
WindowsOption
::
Background
(
bg
));
Ok
(())
}
fn
attr
(
&
mut
self
,
attr
:
term
::
Attr
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
supports_attr
(
&
self
,
attr
:
term
::
Attr
)
->
bool
{
false
}
fn
reset
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.push
(
WindowsOption
::
Reset
);
Ok
(())
}
fn
supports_reset
(
&
self
)
->
bool
{
true
}
fn
supports_color
(
&
self
)
->
bool
{
true
}
fn
cursor_up
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
delete_line
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
carriage_return
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
get_ref
(
&
self
)
->
&
Vec
<
u8
>
{
&
self
.buf
}
fn
get_mut
(
&
mut
self
)
->
&
mut
Vec
<
u8
>
{
&
mut
self
.buf
}
fn
into_inner
(
self
)
->
Vec
<
u8
>
{
self
.buf
}
}
/// NoColorTerminal implements Terminal, but supports no coloring.
///
/// Its useful when an API requires a Terminal, but coloring isn't needed.
pub
struct
NoColorTerminal
<
W
>
{
wtr
:
W
,
}
impl
<
W
:
Send
+
io
::
Write
>
NoColorTerminal
<
W
>
{
/// Wrap the given writer in a Terminal interface.
pub
fn
new
(
wtr
:
W
)
->
NoColorTerminal
<
W
>
{
NoColorTerminal
{
wtr
:
wtr
,
}
}
}
impl
<
W
:
Send
+
io
::
Write
>
io
::
Write
for
NoColorTerminal
<
W
>
{
fn
write
(
&
mut
self
,
buf
:
&
[
u8
])
->
io
::
Result
<
usize
>
{
self
.wtr
.write
(
buf
)
}
fn
flush
(
&
mut
self
)
->
io
::
Result
<
()
>
{
self
.wtr
.flush
()
}
}
impl
<
W
:
Send
+
io
::
Write
>
term
::
Terminal
for
NoColorTerminal
<
W
>
{
type
Output
=
W
;
fn
fg
(
&
mut
self
,
fg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
bg
(
&
mut
self
,
bg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
attr
(
&
mut
self
,
attr
:
term
::
Attr
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
supports_attr
(
&
self
,
attr
:
term
::
Attr
)
->
bool
{
false
}
fn
reset
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
supports_reset
(
&
self
)
->
bool
{
false
}
fn
supports_color
(
&
self
)
->
bool
{
false
}
fn
cursor_up
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
delete_line
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
carriage_return
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
get_ref
(
&
self
)
->
&
W
{
&
self
.wtr
}
fn
get_mut
(
&
mut
self
)
->
&
mut
W
{
&
mut
self
.wtr
}
fn
into_inner
(
self
)
->
W
{
self
.wtr
}
}
src/printer.rs
浏览文件 @
0766617e
use
std
::
io
::{
self
,
Write
};
use
std
::
path
::
Path
;
use
std
::
sync
::
Arc
;
use
regex
::
bytes
::
Regex
;
use
term
::{
self
,
StdoutTerminal
,
Terminal
};
use
term
::
color
::
*
;
use
term
::
terminfo
::
TermInfo
;
use
term
::{
Attr
,
Terminal
};
use
term
::
color
;
use
terminal
::
TerminfoTerminal
;
use
types
::
FileTypeDef
;
use
self
::
Writer
::
*
;
/// Printer encapsulates all output logic for searching.
///
/// Note that we currently ignore all write errors. It's probably worthwhile
...
...
@@ -19,7 +13,7 @@ use self::Writer::*;
/// writes to memory, neither of which commonly fail.
pub
struct
Printer
<
W
>
{
/// The underlying writer.
wtr
:
W
riter
<
W
>
,
wtr
:
W
,
/// Whether anything has been printed to wtr yet.
has_printed
:
bool
,
/// Whether to show column numbers for the first match or not.
...
...
@@ -42,13 +36,11 @@ pub struct Printer<W> {
with_filename
:
bool
,
}
impl
<
W
:
Send
+
io
::
Write
>
Printer
<
W
>
{
impl
<
W
:
Send
+
Terminal
>
Printer
<
W
>
{
/// Create a new printer that writes to wtr.
///
/// `color` should be true if the printer should try to use coloring.
pub
fn
new
(
wtr
:
W
,
color
:
bool
)
->
Printer
<
W
>
{
pub
fn
new
(
wtr
:
W
)
->
Printer
<
W
>
{
Printer
{
wtr
:
Writer
::
new
(
wtr
,
color
)
,
wtr
:
wtr
,
has_printed
:
false
,
column
:
false
,
context_separator
:
"--"
.to_string
()
.into_bytes
(),
...
...
@@ -115,7 +107,7 @@ impl<W: Send + io::Write> Printer<W> {
}
/// Flushes the underlying writer and returns it.
pub
fn
into_inner
(
mut
self
)
->
W
riter
<
W
>
{
pub
fn
into_inner
(
mut
self
)
->
W
{
let
_
=
self
.wtr
.flush
();
self
.wtr
}
...
...
@@ -201,15 +193,15 @@ impl<W: Send + io::Write> Printer<W> {
}
pub
fn
write_match
(
&
mut
self
,
re
:
&
Regex
,
buf
:
&
[
u8
])
{
if
!
self
.wtr
.
i
s_color
()
{
if
!
self
.wtr
.
support
s_color
()
{
self
.write
(
buf
);
return
;
}
let
mut
last_written
=
0
;
for
(
s
,
e
)
in
re
.find_iter
(
buf
)
{
self
.write
(
&
buf
[
last_written
..
s
]);
let
_
=
self
.wtr
.fg
(
BRIGHT_RED
);
let
_
=
self
.wtr
.attr
(
term
::
Attr
::
Bold
);
let
_
=
self
.wtr
.fg
(
color
::
BRIGHT_RED
);
let
_
=
self
.wtr
.attr
(
Attr
::
Bold
);
self
.write
(
&
buf
[
s
..
e
]);
let
_
=
self
.wtr
.reset
();
last_written
=
e
;
...
...
@@ -241,24 +233,24 @@ impl<W: Send + io::Write> Printer<W> {
}
fn
write_heading
<
P
:
AsRef
<
Path
>>
(
&
mut
self
,
path
:
P
)
{
if
self
.wtr
.
i
s_color
()
{
let
_
=
self
.wtr
.fg
(
BRIGHT_GREEN
);
let
_
=
self
.wtr
.attr
(
term
::
Attr
::
Bold
);
if
self
.wtr
.
support
s_color
()
{
let
_
=
self
.wtr
.fg
(
color
::
BRIGHT_GREEN
);
let
_
=
self
.wtr
.attr
(
Attr
::
Bold
);
}
self
.write
(
path
.as_ref
()
.to_string_lossy
()
.as_bytes
());
self
.write_eol
();
if
self
.wtr
.
i
s_color
()
{
if
self
.wtr
.
support
s_color
()
{
let
_
=
self
.wtr
.reset
();
}
}
fn
line_number
(
&
mut
self
,
n
:
u64
,
sep
:
u8
)
{
if
self
.wtr
.
i
s_color
()
{
let
_
=
self
.wtr
.fg
(
BRIGHT_BLUE
);
let
_
=
self
.wtr
.attr
(
term
::
Attr
::
Bold
);
if
self
.wtr
.
support
s_color
()
{
let
_
=
self
.wtr
.fg
(
color
::
BRIGHT_BLUE
);
let
_
=
self
.wtr
.attr
(
Attr
::
Bold
);
}
self
.write
(
n
.to_string
()
.as_bytes
());
if
self
.wtr
.
i
s_color
()
{
if
self
.wtr
.
support
s_color
()
{
let
_
=
self
.wtr
.reset
();
}
self
.write
(
&
[
sep
]);
...
...
@@ -277,289 +269,3 @@ impl<W: Send + io::Write> Printer<W> {
self
.write
(
&
[
eol
]);
}
}
/// Writer corresponds to the final output buffer for search results. All
/// search results are written to a Writer and then a Writer is flushed to
/// stdout only after the full search has completed.
pub
enum
Writer
<
W
>
{
Colored
(
TerminfoTerminal
<
W
>
),
Windows
(
WindowsWriter
<
W
>
),
NoColor
(
W
),
}
pub
struct
WindowsWriter
<
W
>
{
wtr
:
W
,
pos
:
usize
,
colors
:
Vec
<
WindowsColor
>
,
}
pub
struct
WindowsColor
{
pos
:
usize
,
opt
:
WindowsOption
,
}
pub
enum
WindowsOption
{
Foreground
(
Color
),
Background
(
Color
),
Reset
,
}
lazy_static!
{
static
ref
TERMINFO
:
Option
<
Arc
<
TermInfo
>>
=
{
match
term
::
terminfo
::
TermInfo
::
from_env
()
{
Ok
(
info
)
=>
Some
(
Arc
::
new
(
info
)),
Err
(
err
)
=>
{
debug!
(
"error loading terminfo for coloring: {}"
,
err
);
None
}
}
};
}
impl
<
W
:
Send
+
io
::
Write
>
Writer
<
W
>
{
fn
new
(
wtr
:
W
,
color
:
bool
)
->
Writer
<
W
>
{
// If we want color, build a TerminfoTerminal and see if the current
// environment supports coloring. If not, bail with NoColor. To avoid
// losing our writer (ownership), do this the long way.
if
!
color
{
return
NoColor
(
wtr
);
}
if
cfg!
(
windows
)
{
return
Windows
(
WindowsWriter
{
wtr
:
wtr
,
pos
:
0
,
colors
:
vec!
[]
});
}
if
TERMINFO
.is_none
()
{
return
NoColor
(
wtr
);
}
let
info
=
TERMINFO
.clone
()
.unwrap
();
let
tt
=
TerminfoTerminal
::
new_with_terminfo
(
wtr
,
info
);
if
!
tt
.supports_color
()
{
debug!
(
"environment doesn't support coloring"
);
return
NoColor
(
tt
.into_inner
());
}
Colored
(
tt
)
}
fn
is_color
(
&
self
)
->
bool
{
match
*
self
{
Colored
(
_
)
=>
true
,
Windows
(
_
)
=>
true
,
NoColor
(
_
)
=>
false
,
}
}
fn
map_result
<
F
,
G
>
(
&
mut
self
,
mut
f
:
F
,
mut
g
:
G
,
)
->
term
::
Result
<
()
>
where
F
:
FnMut
(
&
mut
TerminfoTerminal
<
W
>
)
->
term
::
Result
<
()
>
,
G
:
FnMut
(
&
mut
WindowsWriter
<
W
>
)
->
term
::
Result
<
()
>
{
match
*
self
{
Colored
(
ref
mut
w
)
=>
f
(
w
),
Windows
(
ref
mut
w
)
=>
g
(
w
),
NoColor
(
_
)
=>
Err
(
term
::
Error
::
NotSupported
),
}
}
fn
map_bool
<
F
,
G
>
(
&
self
,
mut
f
:
F
,
mut
g
:
G
,
)
->
bool
where
F
:
FnMut
(
&
TerminfoTerminal
<
W
>
)
->
bool
,
G
:
FnMut
(
&
WindowsWriter
<
W
>
)
->
bool
{
match
*
self
{
Colored
(
ref
w
)
=>
f
(
w
),
Windows
(
ref
w
)
=>
g
(
w
),
NoColor
(
_
)
=>
false
,
}
}
}
impl
<
W
:
Send
+
io
::
Write
>
io
::
Write
for
Writer
<
W
>
{
fn
write
(
&
mut
self
,
buf
:
&
[
u8
])
->
io
::
Result
<
usize
>
{
match
*
self
{
Colored
(
ref
mut
w
)
=>
w
.write
(
buf
),
Windows
(
ref
mut
w
)
=>
w
.write
(
buf
),
NoColor
(
ref
mut
w
)
=>
w
.write
(
buf
),
}
}
fn
flush
(
&
mut
self
)
->
io
::
Result
<
()
>
{
match
*
self
{
Colored
(
ref
mut
w
)
=>
w
.flush
(),
Windows
(
ref
mut
w
)
=>
w
.flush
(),
NoColor
(
ref
mut
w
)
=>
w
.flush
(),
}
}
}
impl
<
W
:
Send
+
io
::
Write
>
term
::
Terminal
for
Writer
<
W
>
{
type
Output
=
W
;
fn
fg
(
&
mut
self
,
fg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.fg
(
fg
),
|
w
|
w
.fg
(
fg
))
}
fn
bg
(
&
mut
self
,
bg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.bg
(
bg
),
|
w
|
w
.bg
(
bg
))
}
fn
attr
(
&
mut
self
,
attr
:
term
::
Attr
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.attr
(
attr
),
|
w
|
w
.attr
(
attr
))
}
fn
supports_attr
(
&
self
,
attr
:
term
::
Attr
)
->
bool
{
self
.map_bool
(|
w
|
w
.supports_attr
(
attr
),
|
w
|
w
.supports_attr
(
attr
))
}
fn
reset
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.reset
(),
|
w
|
w
.reset
())
}
fn
supports_reset
(
&
self
)
->
bool
{
self
.map_bool
(|
w
|
w
.supports_reset
(),
|
w
|
w
.supports_reset
())
}
fn
supports_color
(
&
self
)
->
bool
{
self
.map_bool
(|
w
|
w
.supports_color
(),
|
w
|
w
.supports_color
())
}
fn
cursor_up
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.cursor_up
(),
|
w
|
w
.cursor_up
())
}
fn
delete_line
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.delete_line
(),
|
w
|
w
.delete_line
())
}
fn
carriage_return
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.map_result
(|
w
|
w
.carriage_return
(),
|
w
|
w
.carriage_return
())
}
fn
get_ref
(
&
self
)
->
&
W
{
match
*
self
{
Colored
(
ref
w
)
=>
w
.get_ref
(),
Windows
(
ref
w
)
=>
w
.get_ref
(),
NoColor
(
ref
w
)
=>
w
,
}
}
fn
get_mut
(
&
mut
self
)
->
&
mut
W
{
match
*
self
{
Colored
(
ref
mut
w
)
=>
w
.get_mut
(),
Windows
(
ref
mut
w
)
=>
w
.get_mut
(),
NoColor
(
ref
mut
w
)
=>
w
,
}
}
fn
into_inner
(
self
)
->
W
{
match
self
{
Colored
(
w
)
=>
w
.into_inner
(),
Windows
(
w
)
=>
w
.into_inner
(),
NoColor
(
w
)
=>
w
,
}
}
}
impl
<
W
:
Send
+
io
::
Write
>
WindowsWriter
<
W
>
{
fn
push
(
&
mut
self
,
opt
:
WindowsOption
)
{
let
pos
=
self
.pos
;
self
.colors
.push
(
WindowsColor
{
pos
:
pos
,
opt
:
opt
});
}
}
impl
WindowsWriter
<
Vec
<
u8
>>
{
/// Print the contents to the given terminal.
pub
fn
print_stdout
(
&
self
,
tt
:
&
mut
Box
<
StdoutTerminal
>
)
{
let
mut
last
=
0
;
for
col
in
&
self
.colors
{
let
_
=
tt
.write_all
(
&
self
.wtr
[
last
..
col
.pos
]);
match
col
.opt
{
WindowsOption
::
Foreground
(
c
)
=>
{
let
_
=
tt
.fg
(
c
);
}
WindowsOption
::
Background
(
c
)
=>
{
let
_
=
tt
.bg
(
c
);
}
WindowsOption
::
Reset
=>
{
let
_
=
tt
.reset
();
}
}
last
=
col
.pos
;
}
let
_
=
tt
.write_all
(
&
self
.wtr
[
last
..
]);
let
_
=
tt
.flush
();
}
}
impl
<
W
:
Send
+
io
::
Write
>
io
::
Write
for
WindowsWriter
<
W
>
{
fn
write
(
&
mut
self
,
buf
:
&
[
u8
])
->
io
::
Result
<
usize
>
{
let
n
=
try!
(
self
.wtr
.write
(
buf
));
self
.pos
+=
n
;
Ok
(
n
)
}
fn
flush
(
&
mut
self
)
->
io
::
Result
<
()
>
{
self
.wtr
.flush
()
}
}
impl
<
W
:
Send
+
io
::
Write
>
term
::
Terminal
for
WindowsWriter
<
W
>
{
type
Output
=
W
;
fn
fg
(
&
mut
self
,
fg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
self
.push
(
WindowsOption
::
Foreground
(
fg
));
Ok
(())
}
fn
bg
(
&
mut
self
,
bg
:
term
::
color
::
Color
)
->
term
::
Result
<
()
>
{
self
.push
(
WindowsOption
::
Background
(
bg
));
Ok
(())
}
fn
attr
(
&
mut
self
,
attr
:
term
::
Attr
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
supports_attr
(
&
self
,
attr
:
term
::
Attr
)
->
bool
{
false
}
fn
reset
(
&
mut
self
)
->
term
::
Result
<
()
>
{
self
.push
(
WindowsOption
::
Reset
);
Ok
(())
}
fn
supports_reset
(
&
self
)
->
bool
{
true
}
fn
supports_color
(
&
self
)
->
bool
{
true
}
fn
cursor_up
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
delete_line
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
carriage_return
(
&
mut
self
)
->
term
::
Result
<
()
>
{
Err
(
term
::
Error
::
NotSupported
)
}
fn
get_ref
(
&
self
)
->
&
W
{
&
self
.wtr
}
fn
get_mut
(
&
mut
self
)
->
&
mut
W
{
&
mut
self
.wtr
}
fn
into_inner
(
self
)
->
W
{
self
.wtr
}
}
src/search.rs
浏览文件 @
0766617e
...
...
@@ -11,6 +11,7 @@ use std::path::{Path, PathBuf};
use
grep
::{
Grep
,
Match
};
use
memchr
::{
memchr
,
memrchr
};
use
term
::
Terminal
;
use
printer
::
Printer
;
...
...
@@ -98,7 +99,7 @@ impl Default for Options {
}
}
impl
<
'a
,
R
:
io
::
Read
,
W
:
Send
+
io
::
Write
>
Searcher
<
'a
,
R
,
W
>
{
impl
<
'a
,
R
:
io
::
Read
,
W
:
Send
+
Terminal
>
Searcher
<
'a
,
R
,
W
>
{
/// Create a new searcher.
///
/// `inp` is a reusable input buffer that is used as scratch space by this
...
...
@@ -689,6 +690,7 @@ mod tests {
use
grep
::{
Grep
,
GrepBuilder
};
use
term
::
Terminal
;
use
out
::
OutBuffer
;
use
printer
::
Printer
;
use
super
::{
InputBuffer
,
Searcher
,
start_of_previous_lines
};
...
...
@@ -731,7 +733,7 @@ fn main() {
&
Path
::
new
(
"/baz.rs"
)
}
type
TestSearcher
<
'a
>
=
Searcher
<
'a
,
io
::
Cursor
<
Vec
<
u8
>>
,
Vec
<
u8
>
>
;
type
TestSearcher
<
'a
>
=
Searcher
<
'a
,
io
::
Cursor
<
Vec
<
u8
>>
,
OutBuffer
>
;
fn
search_smallcap
<
F
:
FnMut
(
TestSearcher
)
->
TestSearcher
>
(
pat
:
&
str
,
...
...
@@ -739,7 +741,8 @@ fn main() {
mut
map
:
F
,
)
->
(
u64
,
String
)
{
let
mut
inp
=
InputBuffer
::
with_capacity
(
1
);
let
mut
pp
=
Printer
::
new
(
vec!
[],
false
)
.with_filename
(
true
);
let
outbuf
=
OutBuffer
::
NoColor
(
vec!
[]);
let
mut
pp
=
Printer
::
new
(
outbuf
)
.with_filename
(
true
);
let
grep
=
GrepBuilder
::
new
(
pat
)
.build
()
.unwrap
();
let
count
=
{
let
searcher
=
Searcher
::
new
(
...
...
@@ -755,7 +758,8 @@ fn main() {
mut
map
:
F
,
)
->
(
u64
,
String
)
{
let
mut
inp
=
InputBuffer
::
with_capacity
(
4096
);
let
mut
pp
=
Printer
::
new
(
vec!
[],
false
)
.with_filename
(
true
);
let
outbuf
=
OutBuffer
::
NoColor
(
vec!
[]);
let
mut
pp
=
Printer
::
new
(
outbuf
)
.with_filename
(
true
);
let
grep
=
GrepBuilder
::
new
(
pat
)
.build
()
.unwrap
();
let
count
=
{
let
searcher
=
Searcher
::
new
(
...
...
src/search_buffer.rs
浏览文件 @
0766617e
use
std
::
cmp
;
use
std
::
io
;
use
std
::
path
::
Path
;
use
grep
::
Grep
;
use
term
::
Terminal
;
use
printer
::
Printer
;
use
search
::{
IterLines
,
Options
,
count_lines
,
is_binary
};
...
...
@@ -18,7 +18,7 @@ pub struct BufferSearcher<'a, W: 'a> {
last_line
:
usize
,
}
impl
<
'a
,
W
:
Send
+
io
::
Write
>
BufferSearcher
<
'a
,
W
>
{
impl
<
'a
,
W
:
Send
+
Terminal
>
BufferSearcher
<
'a
,
W
>
{
pub
fn
new
(
printer
:
&
'a
mut
Printer
<
W
>
,
grep
:
&
'a
Grep
,
...
...
@@ -146,6 +146,7 @@ mod tests {
use
grep
::{
Grep
,
GrepBuilder
};
use
term
::
Terminal
;
use
out
::
OutBuffer
;
use
printer
::
Printer
;
use
super
::
BufferSearcher
;
...
...
@@ -184,14 +185,15 @@ fn main() {
&
Path
::
new
(
"/baz.rs"
)
}
type
TestSearcher
<
'a
>
=
BufferSearcher
<
'a
,
Vec
<
u8
>
>
;
type
TestSearcher
<
'a
>
=
BufferSearcher
<
'a
,
OutBuffer
>
;
fn
search
<
F
:
FnMut
(
TestSearcher
)
->
TestSearcher
>
(
pat
:
&
str
,
haystack
:
&
str
,
mut
map
:
F
,
)
->
(
u64
,
String
)
{
let
mut
pp
=
Printer
::
new
(
vec!
[],
false
)
.with_filename
(
true
);
let
outbuf
=
OutBuffer
::
NoColor
(
vec!
[]);
let
mut
pp
=
Printer
::
new
(
outbuf
)
.with_filename
(
true
);
let
grep
=
GrepBuilder
::
new
(
pat
)
.build
()
.unwrap
();
let
count
=
{
let
searcher
=
BufferSearcher
::
new
(
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录