Code changes in preparation for recursion

This commit is contained in:
Ben S 2015-01-31 16:10:40 +00:00
parent c7e8a28e17
commit 6d4b30d531
6 changed files with 60 additions and 32 deletions

24
Cargo.lock generated
View File

@ -2,17 +2,17 @@
name = "exa"
version = "0.1.0"
dependencies = [
"ansi_term 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ansi_term 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"natord 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"users 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"natord 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"users 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"regex 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -26,7 +26,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getopts"
version = "0.1.4"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -55,7 +55,7 @@ name = "libressl-pnacl-sys"
version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"pnacl-build-helper 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pnacl-build-helper 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -83,12 +83,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "natord"
version = "1.0.6"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "number_prefix"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -107,7 +107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pnacl-build-helper"
version = "1.3.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -139,6 +139,6 @@ dependencies = [
[[package]]
name = "users"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"

View File

@ -8,7 +8,7 @@ name = "exa"
[dependencies]
ansi_term = "0.4.2"
getopts = "0.1.4"
getopts = "0.2.0"
natord = "1.0.6"
number_prefix = "0.2.1"
users = "0.2.1"

View File

@ -21,6 +21,7 @@ exa is a replacement for `ls` written in Rust.
- **-i**, **--inode**: show inode number column
- **-l**, **--long**: display extended details and attributes
- **-r**, **--reverse**: reverse sort order
- **-R**, **--recurse**: recurse into subdirectories
- **-s**, **--sort=(field)**: field to sort by
- **-S**, **--blocks**: show number of file system blocks
- **-x**, **--across**: sort multi-column view entries across

View File

@ -45,7 +45,7 @@ impl<'a> File<'a> {
/// Create a new File object from the given Stat result, and other data.
pub fn with_stat(stat: io::FileStat, path: &Path, parent: Option<&'a Dir>) -> File<'a> {
let v = path.filename().unwrap(); // fails if / or . or ..
let v = path.filename().unwrap_or_else(|| panic!("Failed to get filename for {:?}", path)); // fails if / or . or ..
let filename = String::from_utf8_lossy(v);
File {

View File

@ -1,6 +1,8 @@
#![feature(collections, core, io, libc, os, path, std_misc)]
extern crate ansi_term;
extern crate getopts;
extern crate natord;
extern crate number_prefix;
extern crate users;
@ -12,7 +14,7 @@ use std::os::{args, set_exit_status};
use dir::Dir;
use file::File;
use options::Options;
use options::{Options, DirAction};
pub mod column;
pub mod dir;
@ -30,15 +32,26 @@ fn exa(options: &Options) {
// more than one of them.
let mut count = 0;
let mut stack = options.path_strs.clone();
// 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 options.path_strings() {
let path = Path::new(file);
loop {
let file = match stack.pop() {
None => break,
Some(f) => f,
};
let path = Path::new(file.clone());
match fs::stat(&path) {
Ok(stat) => {
if !options.list_dirs && stat.kind == FileType::Directory {
dirs.push(file.clone());
if stat.kind == FileType::Directory {
match options.dir_action {
DirAction::AsFile => files.push(File::with_stat(stat, &path, None)),
DirAction::List => dirs.push(file.clone()),
DirAction::Recurse => { /* todo */ },
}
}
else {
// May as well reuse the stat result from earlier

View File

@ -1,6 +1,3 @@
extern crate getopts;
extern crate natord;
use dir::Dir;
use file::File;
use column::{Column, SizeFormat};
@ -13,14 +10,17 @@ use std::cmp::Ordering;
use std::fmt;
use std::slice::Iter;
use getopts;
use natord;
use self::Misfire::*;
/// The *Options* struct represents a parsed version of the user's
/// command-line options.
#[derive(PartialEq, Debug)]
pub struct Options {
pub list_dirs: bool,
path_strs: Vec<String>,
pub dir_action: DirAction,
pub path_strs: Vec<String>,
reverse: bool,
show_invisibles: bool,
sort_field: SortField,
@ -43,6 +43,7 @@ impl Options {
getopts::optflag("l", "long", "display extended details and attributes"),
getopts::optflag("i", "inode", "show each file's inode number"),
getopts::optflag("r", "reverse", "reverse order of files"),
getopts::optflag("R", "recurse", "recurse into directories"),
getopts::optopt ("s", "sort", "field to sort by", "WORD"),
getopts::optflag("S", "blocks", "show number of file system blocks"),
getopts::optflag("x", "across", "sort multi-column view entries across"),
@ -64,7 +65,7 @@ impl Options {
};
Ok(Options {
list_dirs: matches.opt_present("list-dirs"),
dir_action: try!(dir_action(&matches)),
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"),
@ -73,11 +74,6 @@ impl Options {
})
}
/// Iterate over the non-option arguments left oven from getopts.
pub fn path_strings(&self) -> Iter<String> {
self.path_strs.iter()
}
/// Display the files using this Option's View.
pub fn view(&self, dir: Option<&Dir>, files: Vec<File>) {
self.view.view(dir, files)
@ -113,7 +109,13 @@ impl Options {
}
}
/// User-supplied field to sort by
/// What to do when encountering a directory?
#[derive(PartialEq, Debug, Copy)]
pub enum DirAction {
AsFile, List, Recurse
}
/// User-supplied field to sort by.
#[derive(PartialEq, Debug, Copy)]
pub enum SortField {
Unsorted, Name, Extension, Size, FileInode
@ -228,7 +230,7 @@ fn view(matches: &getopts::Matches) -> Result<View, Misfire> {
/// Finds out which file size the user has asked for.
fn file_size(matches: &getopts::Matches) -> Result<SizeFormat, Misfire> {
let binary = matches.opt_present("binary");
let bytes = matches.opt_present("bytes");
let bytes = matches.opt_present("bytes");
match (binary, bytes) {
(true, true ) => Err(Misfire::Conflict("binary", "bytes")),
@ -238,6 +240,18 @@ fn file_size(matches: &getopts::Matches) -> Result<SizeFormat, Misfire> {
}
}
fn dir_action(matches: &getopts::Matches) -> Result<DirAction, Misfire> {
let recurse = matches.opt_present("recurse");
let list = matches.opt_present("list-dirs");
match (recurse, list) {
(true, true ) => Err(Misfire::Conflict("recurse", "list-dirs")),
(true, false) => Ok(DirAction::Recurse),
(false, true ) => Ok(DirAction::AsFile),
(false, false) => Ok(DirAction::List),
}
}
#[derive(PartialEq, Copy, Debug)]
pub struct Columns {
size_format: SizeFormat,