Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
vnotepad
Exa
提交
933f98d2
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,发现更多精彩内容 >>
提交
933f98d2
编写于
11月 23, 2014
作者:
B
Ben S
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Upgrade to latest Rust nightly
上级
26f8ad08
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
89 addition
and
86 deletion
+89
-86
src/column.rs
src/column.rs
+15
-15
src/exa.rs
src/exa.rs
+9
-8
src/file.rs
src/file.rs
+17
-17
src/filetype.rs
src/filetype.rs
+8
-8
src/options.rs
src/options.rs
+25
-23
src/sort.rs
src/sort.rs
+7
-6
src/term.rs
src/term.rs
+3
-4
src/unix.rs
src/unix.rs
+5
-5
未找到文件。
src/column.rs
浏览文件 @
933f98d2
...
...
@@ -19,24 +19,24 @@ pub enum Alignment {
impl
Column
{
pub
fn
alignment
(
&
self
)
->
Alignment
{
match
*
self
{
FileSize
(
_
)
=>
Right
,
HardLinks
=>
Right
,
Inode
=>
Right
,
Blocks
=>
Right
,
_
=>
Left
,
Column
::
FileSize
(
_
)
=>
Alignment
::
Right
,
Column
::
HardLinks
=>
Alignment
::
Right
,
Column
::
Inode
=>
Alignment
::
Right
,
Column
::
Blocks
=>
Alignment
::
Right
,
_
=>
Alignment
::
Left
,
}
}
pub
fn
header
(
&
self
)
->
&
'static
str
{
match
*
self
{
Permissions
=>
"Permissions"
,
FileName
=>
"Name"
,
FileSize
(
_
)
=>
"Size"
,
Blocks
=>
"Blocks"
,
User
=>
"User"
,
Group
=>
"Group"
,
HardLinks
=>
"Links"
,
Inode
=>
"inode"
,
Column
::
Permissions
=>
"Permissions"
,
Column
::
FileName
=>
"Name"
,
Column
::
FileSize
(
_
)
=>
"Size"
,
Column
::
Blocks
=>
"Blocks"
,
Column
::
User
=>
"User"
,
Column
::
Group
=>
"Group"
,
Column
::
HardLinks
=>
"Links"
,
Column
::
Inode
=>
"inode"
,
}
}
}
...
...
@@ -49,8 +49,8 @@ impl Column {
impl
Alignment
{
pub
fn
pad_string
(
&
self
,
string
:
&
String
,
padding
:
uint
)
->
String
{
match
*
self
{
Left
=>
string
.clone
()
.append
(
" "
.to_string
()
.repeat
(
padding
)
.as_slice
()
),
Right
=>
" "
.to_string
()
.repeat
(
padding
)
.append
(
string
.as_slice
()
),
Alignment
::
Left
=>
string
.clone
()
+
" "
.to_string
()
.repeat
(
padding
)
.as_slice
(
),
Alignment
::
Right
=>
" "
.to_string
()
.repeat
(
padding
)
+
string
.as_slice
(
),
}
}
}
...
...
src/exa.rs
浏览文件 @
933f98d2
#![feature(phase)]
#![feature(phase
,
globs
)]
extern
crate
regex
;
#[phase(plugin)]
extern
crate
regex_macros
;
extern
crate
ansi_term
;
...
...
@@ -8,8 +8,9 @@ use std::os;
use
file
::
File
;
use
dir
::
Dir
;
use
column
::{
Column
,
Left
};
use
options
::{
Options
,
Details
,
Lines
,
Grid
};
use
column
::
Column
;
use
column
::
Alignment
::
Left
;
use
options
::{
Options
,
View
};
use
unix
::
Unix
;
use
ansi_term
::{
Paint
,
Plain
,
strip_formatting
};
...
...
@@ -25,7 +26,7 @@ pub mod sort;
pub
mod
term
;
fn
main
()
{
let
args
=
os
::
args
();
let
args
:
Vec
<
String
>
=
os
::
args
();
match
Options
::
getopts
(
args
)
{
Err
(
err
)
=>
println!
(
"Invalid options:
\n
{}"
,
err
),
...
...
@@ -58,9 +59,9 @@ fn exa(opts: &Options) {
}
match
opts
.view
{
Details
(
ref
cols
)
=>
details_view
(
opts
,
cols
,
files
),
Lines
=>
lines_view
(
files
),
Grid
(
across
,
width
)
=>
grid_view
(
across
,
width
,
files
),
View
::
Details
(
ref
cols
)
=>
details_view
(
opts
,
cols
,
files
),
View
::
Lines
=>
lines_view
(
files
),
View
::
Grid
(
across
,
width
)
=>
grid_view
(
across
,
width
,
files
),
}
}
Err
(
e
)
=>
{
...
...
@@ -156,7 +157,7 @@ fn details_view(options: &Options, columns: &Vec<Column>, files: Vec<&File>) {
}
else
{
let
padding
=
column_widths
[
num
]
-
field_widths
[
num
];
print!
(
"{}"
,
column
.alignment
()
.pad_string
(
row
.get
(
num
)
,
padding
));
print!
(
"{}"
,
column
.alignment
()
.pad_string
(
&
row
[
num
]
,
padding
));
}
}
print!
(
"
\n
"
);
...
...
src/file.rs
浏览文件 @
933f98d2
use
std
::
io
::{
fs
,
IoResult
};
use
std
::
io
;
use
unicode
::
str
::
UnicodeStrSlice
;
use
ansi_term
::{
Paint
,
Colour
,
Plain
,
Style
,
Red
,
Green
,
Yellow
,
Blue
,
Purple
,
Cyan
,
Fixed
};
use
column
::{
Column
,
Permissions
,
FileName
,
FileSize
,
User
,
Group
,
HardLinks
,
Inode
,
Blocks
};
use
column
::
Column
;
use
column
::
Column
::
*
;
use
format
::{
format_metric_bytes
,
format_IEC_bytes
};
use
unix
::
Unix
;
use
sort
::
SortPart
;
use
dir
::
Dir
;
use
filetype
::
HasType
;
static
Grey
:
Colour
=
Fixed
(
244
);
pub
static
GREY
:
Colour
=
Fixed
(
244
);
// Instead of working with Rust's Paths, we have our own File object
// that holds the Path and various cached information. Each file is
...
...
@@ -32,7 +32,7 @@ pub struct File<'a> {
impl
<
'a
>
File
<
'a
>
{
pub
fn
from_path
(
path
:
&
'a
Path
,
parent
:
&
'a
Dir
)
->
IoResult
<
File
<
'a
>>
{
let
v
=
path
.filename
()
.unwrap
();
// fails if / or . or ..
let
filename
=
String
::
from_utf8
_lossy
(
v
)
.to_string
();
let
filename
=
String
::
from_utf8
(
v
.to_vec
()
)
.to_string
();
// Use lstat here instead of file.stat(), as it doesn't follow
// symbolic links. Otherwise, the stat() call will fail if it
...
...
@@ -129,7 +129,7 @@ impl<'a> File<'a> {
Cyan
.paint
(
self
.stat.unstable.blocks
.to_string
()
.as_slice
())
}
else
{
G
rey
.paint
(
"-"
)
G
REY
.paint
(
"-"
)
}
},
...
...
@@ -195,7 +195,7 @@ impl<'a> File<'a> {
// that reason anyway.
match
link_target
{
Ok
(
file
)
=>
format!
(
"{} {}"
,
G
rey
.paint
(
"=>"
),
file
.file_colour
()
.paint
(
filename
.as_slice
())),
Ok
(
file
)
=>
format!
(
"{} {}"
,
G
REY
.paint
(
"=>"
),
file
.file_colour
()
.paint
(
filename
.as_slice
())),
Err
(
_
)
=>
format!
(
"{} {}"
,
Red
.paint
(
"=>"
),
Red
.underline
()
.paint
(
filename
.as_slice
())),
}
}
...
...
@@ -204,7 +204,7 @@ impl<'a> File<'a> {
// Don't report file sizes for directories. I've never looked
// at one of those numbers and gained any information from it.
if
self
.stat.kind
==
io
::
TypeDirectory
{
G
rey
.paint
(
"-"
)
G
REY
.paint
(
"-"
)
}
else
{
let
(
size
,
suffix
)
=
if
use_iec_prefixes
{
format_IEC_bytes
(
self
.stat.size
)
...
...
@@ -242,15 +242,15 @@ impl<'a> File<'a> {
// The first three are bold because they're the ones used
// most often.
File
::
permission_bit
(
bits
,
io
::
U
serRead
,
"r"
,
Yellow
.bold
()),
File
::
permission_bit
(
bits
,
io
::
U
serWrite
,
"w"
,
Red
.bold
()),
File
::
permission_bit
(
bits
,
io
::
U
serExecute
,
"x"
,
Green
.bold
()
.underline
()),
File
::
permission_bit
(
bits
,
io
::
G
roupRead
,
"r"
,
Yellow
.normal
()),
File
::
permission_bit
(
bits
,
io
::
G
roupWrite
,
"w"
,
Red
.normal
()),
File
::
permission_bit
(
bits
,
io
::
G
roupExecute
,
"x"
,
Green
.normal
()),
File
::
permission_bit
(
bits
,
io
::
O
therRead
,
"r"
,
Yellow
.normal
()),
File
::
permission_bit
(
bits
,
io
::
O
therWrite
,
"w"
,
Red
.normal
()),
File
::
permission_bit
(
bits
,
io
::
O
therExecute
,
"x"
,
Green
.normal
()),
File
::
permission_bit
(
bits
,
io
::
U
SER_READ
,
"r"
,
Yellow
.bold
()),
File
::
permission_bit
(
bits
,
io
::
U
SER_WRITE
,
"w"
,
Red
.bold
()),
File
::
permission_bit
(
bits
,
io
::
U
SER_EXECUTE
,
"x"
,
Green
.bold
()
.underline
()),
File
::
permission_bit
(
bits
,
io
::
G
ROUP_READ
,
"r"
,
Yellow
.normal
()),
File
::
permission_bit
(
bits
,
io
::
G
ROUP_WRITE
,
"w"
,
Red
.normal
()),
File
::
permission_bit
(
bits
,
io
::
G
ROUP_EXECUTE
,
"x"
,
Green
.normal
()),
File
::
permission_bit
(
bits
,
io
::
O
THER_READ
,
"r"
,
Yellow
.normal
()),
File
::
permission_bit
(
bits
,
io
::
O
THER_WRITE
,
"w"
,
Red
.normal
()),
File
::
permission_bit
(
bits
,
io
::
O
THER_EXECUTE
,
"x"
,
Green
.normal
()),
);
}
...
...
@@ -258,7 +258,7 @@ impl<'a> File<'a> {
if
bits
.contains
(
bit
)
{
style
.paint
(
character
.as_slice
())
}
else
{
G
rey
.paint
(
"-"
.as_slice
())
G
REY
.paint
(
"-"
.as_slice
())
}
}
}
src/filetype.rs
浏览文件 @
933f98d2
use
file
::
File
;
use
std
::
io
;
use
std
::
ascii
::
StrAsciiExt
;
use
file
::{
File
,
GREY
};
use
self
::
FileType
::
*
;
use
ansi_term
::{
Paint
,
Colour
,
Plain
,
Style
,
Red
,
Green
,
Yellow
,
Blue
,
Cyan
,
Fixed
};
use
std
::
io
;
use
std
::
ascii
::
AsciiExt
;
static
Grey
:
Colour
=
Fixed
(
244
)
;
use
ansi_term
::{
Paint
,
Plain
,
Style
,
Red
,
Green
,
Yellow
,
Blue
,
Cyan
,
Fixed
}
;
pub
enum
FileType
{
Normal
,
Directory
,
Executable
,
Immediate
,
Compiled
,
Symlink
,
Special
,
...
...
@@ -64,7 +64,7 @@ impl FileType {
Crypto
=>
Fixed
(
109
)
.normal
(),
Document
=>
Fixed
(
105
)
.normal
(),
Compressed
=>
Red
.normal
(),
Temp
=>
G
rey
.normal
(),
Temp
=>
G
REY
.normal
(),
Immediate
=>
Yellow
.bold
()
.underline
(),
Compiled
=>
Fixed
(
137
)
.normal
(),
}
...
...
@@ -87,14 +87,14 @@ impl<'a> HasType for File<'a> {
else
if
self
.stat.kind
==
io
::
TypeBlockSpecial
||
self
.stat.kind
==
io
::
TypeNamedPipe
||
self
.stat.kind
==
io
::
TypeUnknown
{
return
Special
;
}
else
if
self
.stat.perm
.contains
(
io
::
U
serExecute
)
{
else
if
self
.stat.perm
.contains
(
io
::
U
SER_EXECUTE
)
{
return
Executable
;
}
else
if
name
.starts_with
(
"README"
)
||
BUILD_TYPES
.iter
()
.any
(|
&
s
|
s
==
name
)
{
return
Immediate
;
}
else
if
self
.ext
.is_some
()
{
let
e
=
self
.ext
.clone
()
.unwrap
()
.
as_slice
()
.
to_ascii_lower
();
let
e
=
self
.ext
.clone
()
.unwrap
()
.to_ascii_lower
();
let
ext
=
e
.as_slice
();
if
IMAGE_TYPES
.iter
()
.any
(|
&
s
|
s
==
ext
)
{
return
Image
;
...
...
src/options.rs
浏览文件 @
933f98d2
extern
crate
getopts
;
use
file
::
File
;
use
column
::{
Column
,
Permissions
,
FileName
,
FileSize
,
User
,
Group
,
HardLinks
,
Inode
,
Blocks
};
use
std
::
ascii
::
StrAsciiExt
;
use
term
;
use
column
::
Column
;
use
column
::
Column
::
*
;
use
term
::
dimensions
;
use
std
::
ascii
::
AsciiExt
;
pub
enum
SortField
{
Unsorted
,
Name
,
Extension
,
Size
,
FileInode
...
...
@@ -12,12 +14,12 @@ pub enum SortField {
impl
SortField
{
fn
from_word
(
word
:
String
)
->
SortField
{
match
word
.as_slice
()
{
"name"
=>
Name
,
"size"
=>
Size
,
"ext"
=>
Extension
,
"none"
=>
Unsorted
,
"inode"
=>
FileInode
,
_
=>
fail
!
(
"Invalid sorting order"
),
"name"
=>
SortField
::
Name
,
"size"
=>
S
ortField
::
S
ize
,
"ext"
=>
SortField
::
Extension
,
"none"
=>
SortField
::
Unsorted
,
"inode"
=>
SortField
::
FileInode
,
_
=>
panic
!
(
"Invalid sorting order"
),
}
}
}
...
...
@@ -40,7 +42,7 @@ pub struct Options {
impl
Options
{
pub
fn
getopts
(
args
:
Vec
<
String
>
)
->
Result
<
Options
,
getopts
::
Fail_
>
{
let
opts
=
[
let
opts
=
&
[
getopts
::
optflag
(
"1"
,
"oneline"
,
"display one entry per line"
),
getopts
::
optflag
(
"a"
,
"all"
,
"show dot-files"
),
getopts
::
optflag
(
"b"
,
"binary"
,
"use binary prefixes in file sizes"
),
...
...
@@ -61,7 +63,7 @@ impl Options {
show_invisibles
:
matches
.opt_present
(
"all"
),
reverse
:
matches
.opt_present
(
"reverse"
),
header
:
matches
.opt_present
(
"header"
),
sort_field
:
matches
.opt_str
(
"sort"
)
.map
(|
word
|
SortField
::
from_word
(
word
))
.unwrap_or
(
Name
),
sort_field
:
matches
.opt_str
(
"sort"
)
.map
(|
word
|
SortField
::
from_word
(
word
))
.unwrap_or
(
SortField
::
Name
),
dirs
:
if
matches
.free
.is_empty
()
{
vec!
[
"."
.to_string
()
]
}
else
{
matches
.free
.clone
()
},
view
:
Options
::
view
(
matches
),
})
...
...
@@ -70,15 +72,15 @@ impl Options {
fn
view
(
matches
:
getopts
::
Matches
)
->
View
{
if
matches
.opt_present
(
"long"
)
{
Details
(
Options
::
columns
(
matches
))
View
::
Details
(
Options
::
columns
(
matches
))
}
else
if
matches
.opt_present
(
"oneline"
)
{
Lines
View
::
Lines
}
else
{
match
term
::
dimensions
()
{
None
=>
Lines
,
Some
((
width
,
_
))
=>
Grid
(
matches
.opt_present
(
"across"
),
width
),
match
dimensions
()
{
None
=>
View
::
Lines
,
Some
((
width
,
_
))
=>
View
::
Grid
(
matches
.opt_present
(
"across"
),
width
),
}
}
}
...
...
@@ -127,13 +129,13 @@ impl Options {
.collect
();
match
self
.sort_field
{
Unsorted
=>
{},
Name
=>
files
.sort_by
(|
a
,
b
|
a
.parts
.cmp
(
&
b
.parts
)),
Size
=>
files
.sort_by
(|
a
,
b
|
a
.stat.size
.cmp
(
&
b
.stat.size
)),
FileInode
=>
files
.sort_by
(|
a
,
b
|
a
.stat.unstable.inode
.cmp
(
&
b
.stat.unstable.inode
)),
Extension
=>
files
.sort_by
(|
a
,
b
|
{
let
exts
=
a
.ext
.clone
()
.map
(|
e
|
e
.
as_slice
()
.to_ascii_lower
())
.cmp
(
&
b
.ext
.clone
()
.map
(|
e
|
e
.as_slice
()
.to_ascii_lower
()));
let
names
=
a
.name
.
as_slice
()
.to_ascii_lower
()
.cmp
(
&
b
.name
.as_slice
()
.to_ascii_lower
());
SortField
::
Unsorted
=>
{},
SortField
::
Name
=>
files
.sort_by
(|
a
,
b
|
a
.parts
.cmp
(
&
b
.parts
)),
S
ortField
::
S
ize
=>
files
.sort_by
(|
a
,
b
|
a
.stat.size
.cmp
(
&
b
.stat.size
)),
SortField
::
FileInode
=>
files
.sort_by
(|
a
,
b
|
a
.stat.unstable.inode
.cmp
(
&
b
.stat.unstable.inode
)),
SortField
::
Extension
=>
files
.sort_by
(|
a
,
b
|
{
let
exts
=
a
.ext
.clone
()
.map
(|
e
|
e
.
to_ascii_lower
())
.cmp
(
&
b
.ext
.clone
()
.map
(|
e
|
e
.to_ascii_lower
()));
let
names
=
a
.name
.
to_ascii_lower
()
.cmp
(
&
b
.name
.to_ascii_lower
());
exts
.cmp
(
&
names
)
}),
}
...
...
src/sort.rs
浏览文件 @
933f98d2
use
std
::
ascii
::
StrAsciiExt
;
use
self
::
SortPart
::
*
;
use
std
::
ascii
::
AsciiExt
;
// This is an implementation of "natural sort order". See
// http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
...
...
@@ -20,11 +21,11 @@ impl SortPart {
if
is_digit
{
// numbers too big for a u64 fall back into strings.
match
from_str
::
<
u64
>
(
slice
)
{
Some
(
num
)
=>
Numeric
(
num
),
None
=>
Stringular
(
slice
.to_string
()),
Some
(
num
)
=>
SortPart
::
Numeric
(
num
),
None
=>
S
ortPart
::
S
tringular
(
slice
.to_string
()),
}
}
else
{
Stringular
(
slice
.to_ascii_lower
())
S
ortPart
::
S
tringular
(
slice
.to_ascii_lower
())
}
}
...
...
@@ -38,11 +39,11 @@ impl SortPart {
return
parts
}
let
mut
is_digit
=
input
.as_slice
()
.char_at
(
0
)
.is_digit
();
let
mut
is_digit
=
input
.as_slice
()
.char_at
(
0
)
.is_digit
(
10
);
let
mut
start
=
0
;
for
(
i
,
c
)
in
input
.as_slice
()
.char_indices
()
{
if
is_digit
!=
c
.is_digit
()
{
if
is_digit
!=
c
.is_digit
(
10
)
{
parts
.push
(
SortPart
::
from_string
(
is_digit
,
input
.as_slice
()
.slice
(
start
,
i
)));
is_digit
=
!
is_digit
;
start
=
i
;
...
...
src/term.rs
浏览文件 @
933f98d2
...
...
@@ -21,12 +21,11 @@ mod c {
// Unfortunately the actual command is not standardised...
#[cfg(target_os
=
"linux"
)]
#[cfg(target_os
=
"android"
)]
#[cfg(any(target_os
=
"linux"
,
target_os
=
"android"
)
)]
static
TIOCGWINSZ
:
c_ulong
=
0x5413
;
#[cfg(target_os
=
"freebsd"
)]
#[cfg(target_os
=
"macos"
)]
#[cfg(any(target_os
=
"macos"
,
target_os
=
"ios"
))]
static
TIOCGWINSZ
:
c_ulong
=
0x40087468
;
extern
{
...
...
src/unix.rs
浏览文件 @
933f98d2
use
std
::
string
::
raw
::
from_buf
;
use
std
::
ptr
::
read
;
use
std
::
collections
::
hashmap
::
HashMap
;
use
std
::
collections
::
HashMap
;
mod
c
{
#![allow(non_camel_case_types)]
...
...
@@ -127,13 +127,13 @@ impl Unix {
pub
fn
load_group
(
&
mut
self
,
gid
:
u32
)
{
match
unsafe
{
c
::
getgrgid
(
gid
)
.as_ref
()
}
{
None
=>
{
self
.group_names
.
find_or_
insert
(
gid
,
None
);
self
.groups
.
find_or_
insert
(
gid
,
false
);
self
.group_names
.insert
(
gid
,
None
);
self
.groups
.insert
(
gid
,
false
);
},
Some
(
r
)
=>
{
let
group_name
=
unsafe
{
Some
(
from_buf
(
r
.gr_name
as
*
const
u8
))
};
self
.groups
.
find_or_
insert
(
gid
,
Unix
::
group_membership
(
r
.gr_mem
,
&
self
.username
));
self
.group_names
.
find_or_
insert
(
gid
,
group_name
);
self
.groups
.insert
(
gid
,
Unix
::
group_membership
(
r
.gr_mem
,
&
self
.username
));
self
.group_names
.insert
(
gid
,
group_name
);
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录