Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
vnotepad
Exa
提交
98235200
E
Exa
项目概览
vnotepad
/
Exa
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
Exa
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
98235200
编写于
2月 26, 2015
作者:
B
Ben S
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'cleanup'
上级
3e6cce5b
8615f440
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
200 addition
and
78 deletion
+200
-78
src/column.rs
src/column.rs
+1
-1
src/main.rs
src/main.rs
+4
-1
src/options.rs
src/options.rs
+3
-4
src/output/details.rs
src/output/details.rs
+192
-72
未找到文件。
src/column.rs
浏览文件 @
98235200
...
@@ -4,7 +4,7 @@ use ansi_term::Style;
...
@@ -4,7 +4,7 @@ use ansi_term::Style;
use
options
::{
SizeFormat
,
TimeType
};
use
options
::{
SizeFormat
,
TimeType
};
#[derive(PartialEq,
Debug,
Copy)]
#[derive(PartialEq,
Debug,
Copy
,
Clone
)]
pub
enum
Column
{
pub
enum
Column
{
Permissions
,
Permissions
,
FileSize
(
SizeFormat
),
FileSize
(
SizeFormat
),
...
...
src/main.rs
浏览文件 @
98235200
#![feature(collections,
core,
env,
libc,
old_io,
old_path,
plugin
,
std_misc)]
#![feature(collections,
core,
env,
io,
libc,
old_io,
old_path
,
std_misc)]
// Other platforms than macos don't need std_misc but you can't
// Other platforms than macos don't need std_misc but you can't
// use #[cfg] on features.
// use #[cfg] on features.
...
@@ -33,6 +33,7 @@ pub mod output;
...
@@ -33,6 +33,7 @@ pub mod output;
pub
mod
term
;
pub
mod
term
;
pub
mod
xattr
;
pub
mod
xattr
;
#[cfg(not(test))]
struct
Exa
<
'a
>
{
struct
Exa
<
'a
>
{
count
:
usize
,
count
:
usize
,
options
:
Options
,
options
:
Options
,
...
@@ -40,6 +41,7 @@ struct Exa<'a> {
...
@@ -40,6 +41,7 @@ struct Exa<'a> {
files
:
Vec
<
File
<
'a
>>
,
files
:
Vec
<
File
<
'a
>>
,
}
}
#[cfg(not(test))]
impl
<
'a
>
Exa
<
'a
>
{
impl
<
'a
>
Exa
<
'a
>
{
fn
new
(
options
:
Options
)
->
Exa
<
'a
>
{
fn
new
(
options
:
Options
)
->
Exa
<
'a
>
{
Exa
{
Exa
{
...
@@ -145,6 +147,7 @@ impl<'a> Exa<'a> {
...
@@ -145,6 +147,7 @@ impl<'a> Exa<'a> {
}
}
}
}
#[cfg(not(test))]
fn
main
()
{
fn
main
()
{
let
args
:
Vec
<
String
>
=
env
::
args
()
.collect
();
let
args
:
Vec
<
String
>
=
env
::
args
()
.collect
();
...
...
src/options.rs
浏览文件 @
98235200
...
@@ -233,9 +233,8 @@ impl View {
...
@@ -233,9 +233,8 @@ impl View {
let
details
=
Details
{
let
details
=
Details
{
columns
:
try!
(
Columns
::
deduce
(
matches
)),
columns
:
try!
(
Columns
::
deduce
(
matches
)),
header
:
matches
.opt_present
(
"header"
),
header
:
matches
.opt_present
(
"header"
),
recurse
:
dir_action
.recurse_options
(),
recurse
:
dir_action
.recurse_options
()
.map
(|
o
|
(
o
,
filter
))
,
xattr
:
xattr
::
feature_implemented
()
&&
matches
.opt_present
(
"extended"
),
xattr
:
xattr
::
feature_implemented
()
&&
matches
.opt_present
(
"extended"
),
filter
:
filter
,
};
};
Ok
(
View
::
Details
(
details
))
Ok
(
View
::
Details
(
details
))
...
@@ -298,7 +297,7 @@ impl View {
...
@@ -298,7 +297,7 @@ impl View {
}
}
}
}
#[derive(PartialEq,
Debug,
Copy)]
#[derive(PartialEq,
Debug,
Copy
,
Clone
)]
pub
enum
SizeFormat
{
pub
enum
SizeFormat
{
DecimalBytes
,
DecimalBytes
,
BinaryBytes
,
BinaryBytes
,
...
@@ -319,7 +318,7 @@ impl SizeFormat {
...
@@ -319,7 +318,7 @@ impl SizeFormat {
}
}
}
}
#[derive(PartialEq,
Debug,
Copy)]
#[derive(PartialEq,
Debug,
Copy
,
Clone
)]
pub
enum
TimeType
{
pub
enum
TimeType
{
FileAccessed
,
FileAccessed
,
FileModified
,
FileModified
,
...
...
src/output/details.rs
浏览文件 @
98235200
...
@@ -8,75 +8,205 @@ use users::OSUsers;
...
@@ -8,75 +8,205 @@ use users::OSUsers;
use
locale
;
use
locale
;
use
ansi_term
::
Style
::
Plain
;
use
ansi_term
::
Style
::
Plain
;
/// With the **Details** view, the output gets formatted into columns, with
/// each `Column` object showing some piece of information about the file,
/// such as its size, or its permissions.
///
/// To do this, the results have to be written to a table, instead of
/// displaying each file immediately. Then, the width of each column can be
/// calculated based on the individual results, and the fields are padded
/// during output.
///
/// Almost all the heavy lifting is done in a Table object, which handles the
/// columns for each row.
#[derive(PartialEq,
Debug,
Copy)]
#[derive(PartialEq,
Debug,
Copy)]
pub
struct
Details
{
pub
struct
Details
{
/// A Columns object that says which columns should be included in the
/// output in the general case. Directories themselves can pick which
/// columns are *added* to this list, such as the Git column.
pub
columns
:
Columns
,
pub
columns
:
Columns
,
/// Whether to recurse through directories with a tree view, and if so,
/// which options to use. This field is only relevant here if the `tree`
/// field of the RecurseOptions is `true`.
pub
recurse
:
Option
<
(
RecurseOptions
,
FileFilter
)
>
,
/// Whether to show a header line or not.
pub
header
:
bool
,
pub
header
:
bool
,
pub
recurse
:
Option
<
RecurseOptions
>
,
/// Whether to show each file's extended attributes.
pub
xattr
:
bool
,
pub
xattr
:
bool
,
pub
filter
:
FileFilter
,
}
}
impl
Details
{
impl
Details
{
pub
fn
view
(
&
self
,
dir
:
Option
<&
Dir
>
,
files
:
&
[
File
])
{
pub
fn
view
(
&
self
,
dir
:
Option
<&
Dir
>
,
files
:
&
[
File
])
{
// The output gets formatted into columns, which looks nicer. To
// First, transform the Columns object into a vector of columns for
// do this, we have to write the results into a table, instead of
// the current directory.
// displaying each file immediately, then calculating the maximum
let
mut
table
=
Table
::
with_columns
(
self
.columns
.for_dir
(
dir
));
// width of each column based on the length of the results and
if
self
.header
{
table
.add_header
()
}
// padding the fields during output.
// Then add files to the table and print it out.
let
columns
=
self
.columns
.for_dir
(
dir
);
self
.add_files_to_table
(
&
mut
table
,
files
,
0
);
let
locale
=
UserLocale
::
new
();
table
.print_table
(
self
.xattr
,
self
.recurse
.is_some
());
let
mut
cache
=
OSUsers
::
empty_cache
();
}
let
mut
table
=
Vec
::
new
();
self
.get_files
(
&
columns
[
..
],
&
mut
cache
,
&
locale
,
&
mut
table
,
files
,
0
);
/// Adds files to the table - recursively, if the `recurse` option
/// is present.
if
self
.header
{
fn
add_files_to_table
(
&
self
,
table
:
&
mut
Table
,
src
:
&
[
File
],
depth
:
usize
)
{
let
row
=
Row
{
for
(
index
,
file
)
in
src
.iter
()
.enumerate
()
{
depth
:
0
,
table
.add_file
(
file
,
depth
,
index
==
src
.len
()
-
1
);
cells
:
columns
.iter
()
.map
(|
c
|
Cell
::
paint
(
Plain
.underline
(),
c
.header
()))
.collect
(),
name
:
Plain
.underline
()
.paint
(
"Name"
)
.to_string
(),
// There are two types of recursion that exa supports: a tree
last
:
false
,
// view, which is dealt with here, and multiple listings, which is
attrs
:
Vec
::
new
(),
// dealt with in the main module. So only actually recurse if we
children
:
false
,
// are in tree mode - the other case will be dealt with elsewhere.
};
if
let
Some
((
r
,
filter
))
=
self
.recurse
{
if
r
.tree
==
false
||
r
.is_too_deep
(
depth
)
{
table
.insert
(
0
,
row
);
continue
;
}
// Use the filter to remove unwanted files *before* expanding
// them, so we don't examine any directories that wouldn't
// have their contents listed anyway.
if
let
Some
(
ref
dir
)
=
file
.this
{
let
mut
files
=
dir
.files
(
true
);
filter
.transform_files
(
&
mut
files
);
self
.add_files_to_table
(
table
,
&
files
,
depth
+
1
);
}
}
}
}
}
}
let
column_widths
:
Vec
<
usize
>
=
range
(
0
,
columns
.len
())
struct
Row
{
.map
(|
n
|
table
.iter
()
.map
(|
row
|
row
.cells
[
n
]
.length
)
.max
()
.unwrap_or
(
0
))
.collect
();
/// Vector of cells to display.
cells
:
Vec
<
Cell
>
,
/// This file's name, in coloured output. The name is treated separately
/// from the other cells, as it never requires padding.
name
:
String
,
/// How many directories deep into the tree structure this is. Directories
/// on top have depth 0.
depth
:
usize
,
/// Vector of this file's extended attributes, if that feature is active.
attrs
:
Vec
<
Attribute
>
,
/// Whether this is the last entry in the directory. This flag is used
/// when calculating the tree view.
last
:
bool
,
/// Whether this file is a directory and has any children. Also used when
/// calculating the tree view.
children
:
bool
,
}
/// A **Table** object gets built up by the view as it lists files and
/// directories.
struct
Table
{
columns
:
Vec
<
Column
>
,
users
:
OSUsers
,
locale
:
UserLocale
,
rows
:
Vec
<
Row
>
,
}
impl
Table
{
/// Create a new, empty Table object, setting the caching fields to their
/// empty states.
fn
with_columns
(
columns
:
Vec
<
Column
>
)
->
Table
{
Table
{
columns
:
columns
,
users
:
OSUsers
::
empty_cache
(),
locale
:
UserLocale
::
new
(),
rows
:
Vec
::
new
(),
}
}
/// Add a dummy "header" row to the table, which contains the names of all
/// the columns, underlined. This has dummy data for the cases that aren't
/// actually used, such as the depth or list of attributes.
fn
add_header
(
&
mut
self
)
{
let
row
=
Row
{
depth
:
0
,
cells
:
self
.columns
.iter
()
.map
(|
c
|
Cell
::
paint
(
Plain
.underline
(),
c
.header
()))
.collect
(),
name
:
Plain
.underline
()
.paint
(
"Name"
)
.to_string
(),
last
:
false
,
attrs
:
Vec
::
new
(),
children
:
false
,
};
self
.rows
.push
(
row
);
}
/// Use the list of columns to find which cells should be produced for
/// this file, per-column.
fn
cells_for_file
(
&
mut
self
,
file
:
&
File
)
->
Vec
<
Cell
>
{
self
.columns
.clone
()
.iter
()
.map
(|
c
|
file
.display
(
c
,
&
mut
self
.users
,
&
self
.locale
))
.collect
()
}
/// Get the cells for the given file, and add the result to the table.
fn
add_file
(
&
mut
self
,
file
:
&
File
,
depth
:
usize
,
last
:
bool
)
{
let
row
=
Row
{
depth
:
depth
,
cells
:
self
.cells_for_file
(
file
),
name
:
file
.file_name_view
(),
last
:
last
,
attrs
:
file
.xattrs
.clone
(),
children
:
file
.this
.is_some
(),
};
self
.rows
.push
(
row
)
}
/// Print the table to standard output, consuming it in the process.
fn
print_table
(
self
,
xattr
:
bool
,
show_children
:
bool
)
{
let
mut
stack
=
Vec
::
new
();
let
mut
stack
=
Vec
::
new
();
for
row
in
table
{
// Work out the list of column widths by finding the longest cell for
for
(
num
,
column
)
in
columns
.iter
()
.enumerate
()
{
// each column, then formatting each cell in that column to be the
let
padding
=
column_widths
[
num
]
-
row
.cells
[
num
]
.length
;
// width of that one.
print!
(
"{} "
,
column
.alignment
()
.pad_string
(
&
row
.cells
[
num
]
.text
,
padding
));
let
column_widths
:
Vec
<
usize
>
=
range
(
0
,
self
.columns
.len
())
.map
(|
n
|
self
.rows
.iter
()
.map
(|
row
|
row
.cells
[
n
]
.length
)
.max
()
.unwrap_or
(
0
))
.collect
();
for
row
in
self
.rows
.into_iter
()
{
for
(
n
,
width
)
in
column_widths
.iter
()
.enumerate
()
{
let
padding
=
width
-
row
.cells
[
n
]
.length
;
print!
(
"{} "
,
self
.columns
[
n
]
.alignment
()
.pad_string
(
&
row
.cells
[
n
]
.text
,
padding
));
}
}
if
self
.recurse
.is_some
()
{
// A stack tracks which tree characters should be printed. It's
stack
.resize
(
row
.depth
+
1
,
"├──"
);
// necessary to maintain information about the previously-printed
stack
[
row
.depth
]
=
if
row
.last
{
"└──"
}
else
{
"├──"
};
// lines, as the output will change based on whether the
// *previous* entry was the last in its directory.
if
show_children
{
stack
.resize
(
row
.depth
+
1
,
TreePart
::
Edge
);
stack
[
row
.depth
]
=
if
row
.last
{
TreePart
::
Corner
}
else
{
TreePart
::
Edge
};
for
i
in
1
..
row
.depth
+
1
{
for
i
in
1
..
row
.depth
+
1
{
print!
(
"{}"
,
GREY
.paint
(
stack
[
i
]));
print!
(
"{}"
,
GREY
.paint
(
stack
[
i
]
.ascii_art
()
));
}
}
if
row
.children
{
if
row
.children
{
stack
[
row
.depth
]
=
if
row
.last
{
" "
}
else
{
"│ "
};
stack
[
row
.depth
]
=
if
row
.last
{
TreePart
::
Blank
}
else
{
TreePart
::
Line
};
}
}
// If any tree characters have been printed, then add an extra
// space, which makes the output look much better.
if
row
.depth
!=
0
{
if
row
.depth
!=
0
{
print!
(
" "
);
print!
(
" "
);
}
}
}
}
// Print the name without worrying about padding.
print!
(
"{}
\n
"
,
row
.name
);
print!
(
"{}
\n
"
,
row
.name
);
if
self
.
xattr
{
if
xattr
{
let
width
=
row
.attrs
.iter
()
.map
(|
a
|
a
.name
()
.len
())
.max
()
.unwrap_or
(
0
);
let
width
=
row
.attrs
.iter
()
.map
(|
a
|
a
.name
()
.len
())
.max
()
.unwrap_or
(
0
);
for
attr
in
row
.attrs
.iter
()
{
for
attr
in
row
.attrs
.iter
()
{
let
name
=
attr
.name
();
let
name
=
attr
.name
();
...
@@ -88,61 +218,51 @@ impl Details {
...
@@ -88,61 +218,51 @@ impl Details {
}
}
}
}
}
}
}
fn
get_files
(
&
self
,
columns
:
&
[
Column
],
cache
:
&
mut
OSUsers
,
locale
:
&
UserLocale
,
dest
:
&
mut
Vec
<
Row
>
,
src
:
&
[
File
],
depth
:
usize
)
{
#[derive(PartialEq,
Debug,
Clone)]
for
(
index
,
file
)
in
src
.iter
()
.enumerate
()
{
enum
TreePart
{
let
row
=
Row
{
/// Rightmost column, *not* the last in the directory.
depth
:
depth
,
Edge
,
cells
:
columns
.iter
()
.map
(|
c
|
file
.display
(
c
,
cache
,
locale
))
.collect
(),
name
:
file
.file_name_view
(),
last
:
index
==
src
.len
()
-
1
,
attrs
:
file
.xattrs
.clone
(),
children
:
file
.this
.is_some
(),
};
dest
.push
(
row
);
/// Not the rightmost column, and the directory has not finished yet.
Line
,
if
let
Some
(
r
)
=
self
.recurse
{
/// Rightmost column, and the last in the directory.
if
r
.tree
==
false
||
r
.is_too_deep
(
depth
)
{
Corner
,
continue
;
}
if
let
Some
(
ref
dir
)
=
file
.this
{
/// Not the rightmost column, and the directory *has* finished.
let
mut
files
=
dir
.files
(
true
);
Blank
,
self
.filter
.transform_files
(
&
mut
files
);
self
.get_files
(
columns
,
cache
,
locale
,
dest
,
&
files
,
depth
+
1
);
}
}
}
}
}
}
struct
Row
{
impl
TreePart
{
pub
depth
:
usize
,
fn
ascii_art
(
&
self
)
->
&
'static
str
{
pub
cells
:
Vec
<
Cell
>
,
match
*
self
{
pub
name
:
String
,
TreePart
::
Edge
=>
"├──"
,
pub
last
:
bool
,
TreePart
::
Line
=>
"│ "
,
pub
attrs
:
Vec
<
Attribute
>
,
TreePart
::
Corner
=>
"└──"
,
pub
children
:
bool
,
TreePart
::
Blank
=>
" "
,
}
}
}
}
pub
struct
UserLocale
{
pub
struct
UserLocale
{
pub
time
:
locale
::
Time
,
pub
time
:
locale
::
Time
,
pub
numeric
:
locale
::
Numeric
,
pub
numeric
:
locale
::
Numeric
,
}
}
impl
UserLocale
{
impl
UserLocale
{
pub
fn
new
()
->
UserLocale
{
pub
fn
new
()
->
UserLocale
{
UserLocale
{
UserLocale
{
time
:
locale
::
Time
::
load_user_locale
()
.unwrap_or_else
(|
_
|
locale
::
Time
::
english
()),
time
:
locale
::
Time
::
load_user_locale
()
.unwrap_or_else
(|
_
|
locale
::
Time
::
english
()),
numeric
:
locale
::
Numeric
::
load_user_locale
()
.unwrap_or_else
(|
_
|
locale
::
Numeric
::
english
()),
numeric
:
locale
::
Numeric
::
load_user_locale
()
.unwrap_or_else
(|
_
|
locale
::
Numeric
::
english
()),
}
}
}
}
pub
fn
default
()
->
UserLocale
{
pub
fn
default
()
->
UserLocale
{
UserLocale
{
UserLocale
{
time
:
locale
::
Time
::
english
(),
time
:
locale
::
Time
::
english
(),
numeric
:
locale
::
Numeric
::
english
(),
numeric
:
locale
::
Numeric
::
english
(),
}
}
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录