mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-25 21:37:33 +00:00
Add a flag to print directories as files
Also, re-use the stat result from directory-checking.
This commit is contained in:
parent
cbd2f1fa37
commit
bcaf54d7dd
@ -16,6 +16,7 @@ Options
|
||||
- **-1**, **--oneline**: display one entry per line
|
||||
- **-a**, **--all**: show dot files
|
||||
- **-b**, **--binary**: use binary (power of two) file sizes
|
||||
- **-d**, **--list-dirs**: list directories as regular files
|
||||
- **-g**, **--group**: show group as well as user
|
||||
- **-h**, **--header**: show a header row
|
||||
- **-H**, **--links**: show number of hard links column
|
||||
@ -31,4 +32,4 @@ You can sort by **name**, **size**, **ext**, **inode**, or **none**.
|
||||
Installation
|
||||
------------
|
||||
|
||||
exa is written in [Rust](http://www.rust-lang.org). You'll have to use the nightly -- I try to keep it up to date with the latest version when possible. You will also need [Cargo](http://crates.io), the Rust package manager. Once you have them both set up, a simple `cargo build` will pull in all the dependencies and compile exa.
|
||||
exa is written in [Rust](http://www.rust-lang.org). You'll have to use the nightly -- I try to keep it up to date with the latest version when possible. Once you have it set up, a simple `cargo build` will pull in all the dependencies and compile exa.
|
||||
|
36
src/exa.rs
36
src/exa.rs
@ -37,23 +37,37 @@ fn main() {
|
||||
}
|
||||
|
||||
fn exa(opts: &Options) {
|
||||
let mut dirs: Vec<String> = vec![];
|
||||
let mut files: Vec<File> = vec![];
|
||||
|
||||
// Separate the user-supplied paths into directories and files.
|
||||
// Files are shown first, and then each directory is expanded
|
||||
// and listed second.
|
||||
for file in opts.path_strs.iter() {
|
||||
let path = Path::new(file);
|
||||
match fs::stat(&path) {
|
||||
Ok(stat) => {
|
||||
if !opts.list_dirs && stat.kind == TypeDirectory {
|
||||
dirs.push(file.clone());
|
||||
}
|
||||
else {
|
||||
// May as well reuse the stat result from earlier
|
||||
// instead of just using File::from_path().
|
||||
files.push(File::with_stat(stat, path, None));
|
||||
}
|
||||
}
|
||||
Err(e) => println!("{}: {}", file, e),
|
||||
}
|
||||
}
|
||||
|
||||
// It's only worth printing out directory names if the user supplied
|
||||
// more than one of them.
|
||||
let print_dir_names = opts.path_strs.len() > 1;
|
||||
let (dir_strs, file_strs) = opts.path_strs.clone().partition(|n| fs::stat(&Path::new(n)).unwrap().kind == TypeDirectory);
|
||||
|
||||
let mut first = file_strs.is_empty();
|
||||
let mut files = vec![];
|
||||
for f in file_strs.iter() {
|
||||
match File::from_path(Path::new(f), None) {
|
||||
Ok(file) => files.push(file),
|
||||
Err(e) => println!("{}: {}", f, e),
|
||||
}
|
||||
}
|
||||
let mut first = files.is_empty();
|
||||
|
||||
view(opts, files);
|
||||
|
||||
for dir_name in dir_strs.into_iter() {
|
||||
for dir_name in dirs.into_iter() {
|
||||
if first {
|
||||
first = false;
|
||||
}
|
||||
|
13
src/file.rs
13
src/file.rs
@ -32,21 +32,24 @@ pub struct File<'a> {
|
||||
|
||||
impl<'a> File<'a> {
|
||||
pub fn from_path(path: Path, parent: Option<&'a Dir<'a>>) -> IoResult<File<'a>> {
|
||||
let v = path.filename().unwrap(); // fails if / or . or ..
|
||||
let filename = String::from_utf8(v.to_vec()).unwrap_or_else(|_| panic!("Name was not valid UTF-8"));
|
||||
|
||||
// Use lstat here instead of file.stat(), as it doesn't follow
|
||||
// symbolic links. Otherwise, the stat() call will fail if it
|
||||
// encounters a link that's target is non-existent.
|
||||
fs::lstat(&path).map(|stat| File::with_stat(stat, path.clone(), parent))
|
||||
}
|
||||
|
||||
fs::lstat(&path).map(|stat| File {
|
||||
pub fn with_stat(stat: io::FileStat, path: Path, parent: Option<&'a Dir<'a>>) -> File<'a> {
|
||||
let v = path.filename().unwrap(); // fails if / or . or ..
|
||||
let filename = String::from_utf8(v.to_vec()).unwrap_or_else(|_| panic!("Name was not valid UTF-8"));
|
||||
|
||||
File {
|
||||
path: path.clone(),
|
||||
dir: parent,
|
||||
stat: stat,
|
||||
name: filename.clone(),
|
||||
ext: File::ext(filename.clone()),
|
||||
parts: SortPart::split_into_parts(filename.clone()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn ext(name: String) -> Option<String> {
|
||||
|
@ -32,6 +32,7 @@ pub enum View {
|
||||
|
||||
pub struct Options {
|
||||
pub header: bool,
|
||||
pub list_dirs: bool,
|
||||
pub path_strs: Vec<String>,
|
||||
pub reverse: bool,
|
||||
pub show_invisibles: bool,
|
||||
@ -46,6 +47,7 @@ impl Options {
|
||||
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"),
|
||||
getopts::optflag("d", "list-dirs", "list directories as regular files"),
|
||||
getopts::optflag("g", "group", "show group as well as user"),
|
||||
getopts::optflag("h", "header", "show a header row at the top"),
|
||||
getopts::optflag("H", "links", "show number of hard links"),
|
||||
@ -61,6 +63,7 @@ impl Options {
|
||||
Err(f) => Err(f),
|
||||
Ok(ref matches) => Ok(Options {
|
||||
header: matches.opt_present("header"),
|
||||
list_dirs: matches.opt_present("list-dirs"),
|
||||
path_strs: if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
|
||||
reverse: matches.opt_present("reverse"),
|
||||
show_invisibles: matches.opt_present("all"),
|
||||
|
Loading…
Reference in New Issue
Block a user