diff --git a/src/dir.rs b/src/dir.rs
index f9f8437..d938cbb 100644
--- a/src/dir.rs
+++ b/src/dir.rs
@@ -21,11 +21,11 @@ impl Dir {
/// Create a new Dir object filled with all the files in the directory
/// pointed to by the given path. Fails if the directory can't be read, or
/// isn't actually a directory.
- pub fn readdir(path: Path) -> IoResult
{
- fs::readdir(&path).map(|paths| Dir {
+ pub fn readdir(path: &Path) -> IoResult {
+ fs::readdir(path).map(|paths| Dir {
contents: paths,
path: path.clone(),
- git: Git::scan(&path).ok(),
+ git: Git::scan(path).ok(),
})
}
diff --git a/src/main.rs b/src/main.rs
index 5bab5ac..c31c6cb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -25,37 +25,24 @@ pub mod output;
pub mod term;
fn exa(options: &Options) {
- let mut dirs: Vec = vec![];
+ let mut dirs: Vec = vec![];
let mut files: Vec = vec![];
// It's only worth printing out directory names if the user supplied
// 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.
- loop {
- let file = match stack.pop() {
- None => break,
- Some(f) => f,
- };
-
- let path = Path::new(file.clone());
+ for file in options.path_strs.iter() {
+ let path = Path::new(file);
match fs::stat(&path) {
Ok(stat) => {
- 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 */ },
- }
+ if stat.kind == FileType::Directory && options.dir_action != DirAction::AsFile {
+ dirs.push(path);
}
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));
}
}
@@ -68,10 +55,19 @@ fn exa(options: &Options) {
let mut first = files.is_empty();
if !files.is_empty() {
- options.view(None, files);
+ options.view(None, &files[]);
}
- for dir_name in dirs.iter() {
+ // Directories are put on a stack rather than just being iterated through,
+ // as the vector can change as more directories are added.
+ loop {
+ let dir_path = match dirs.pop() {
+ None => break,
+ Some(f) => f,
+ };
+
+ // Put a gap between directories, or between the list of files and the
+ // first directory.
if first {
first = false;
}
@@ -79,19 +75,30 @@ fn exa(options: &Options) {
print!("\n");
}
- match Dir::readdir(Path::new(dir_name.clone())) {
+ match Dir::readdir(&dir_path) {
Ok(ref dir) => {
let unsorted_files = dir.files();
let files: Vec = options.transform_files(unsorted_files);
- if count > 1 {
- println!("{}:", dir_name);
+ // When recursing, add any directories to the dirs stack
+ // backwards: the *last* element of the stack is used each
+ // time, so by inserting them backwards, they get displayed in
+ // the correct sort order.
+ if options.dir_action == DirAction::Recurse {
+ for dir in files.iter().filter(|f| f.stat.kind == FileType::Directory).rev() {
+ dirs.push(dir.path.clone());
+ }
}
- options.view(Some(dir), files);
+ if count > 1 {
+ println!("{}:", dir_path.display());
+ }
+ count += 1;
+
+ options.view(Some(dir), &files[]);
}
Err(e) => {
- println!("{}: {}", dir_name, e);
+ println!("{}: {}", dir_path.display(), e);
return;
}
};
diff --git a/src/options.rs b/src/options.rs
index 219b67d..8d1f355 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -74,7 +74,7 @@ impl Options {
}
/// Display the files using this Option's View.
- pub fn view(&self, dir: Option<&Dir>, files: Vec) {
+ pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
self.view.view(dir, files)
}
diff --git a/src/output.rs b/src/output.rs
index 7b8bd39..52251d4 100644
--- a/src/output.rs
+++ b/src/output.rs
@@ -18,7 +18,7 @@ pub enum View {
}
impl View {
- pub fn view(&self, dir: Option<&Dir>, files: Vec) {
+ pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
match *self {
View::Grid(across, width) => grid_view(across, width, files),
View::Details(ref cols, header) => details_view(&*cols.for_dir(dir), files, header),
@@ -28,13 +28,13 @@ impl View {
}
/// The lines view literally just displays each file, line-by-line.
-fn lines_view(files: Vec) {
+fn lines_view(files: &[File]) {
for file in files.iter() {
println!("{}", file.file_name_view().text);
}
}
-fn fit_into_grid(across: bool, console_width: usize, files: &Vec) -> Option<(usize, Vec)> {
+fn fit_into_grid(across: bool, console_width: usize, files: &[File]) -> Option<(usize, Vec)> {
// TODO: this function could almost certainly be optimised...
// surely not *all* of the numbers of lines are worth searching through!
@@ -86,8 +86,8 @@ fn fit_into_grid(across: bool, console_width: usize, files: &Vec) -> Optio
return None;
}
-fn grid_view(across: bool, console_width: usize, files: Vec) {
- if let Some((num_lines, widths)) = fit_into_grid(across, console_width, &files) {
+fn grid_view(across: bool, console_width: usize, files: &[File]) {
+ if let Some((num_lines, widths)) = fit_into_grid(across, console_width, files) {
for y in range(0, num_lines) {
for x in range(0, widths.len()) {
let num = if across {
@@ -122,7 +122,7 @@ fn grid_view(across: bool, console_width: usize, files: Vec) {
}
}
-fn details_view(columns: &[Column], files: Vec, header: bool) {
+fn details_view(columns: &[Column], files: &[File], header: bool) {
// The output gets formatted into columns, which looks nicer. To
// do this, we have to write the results into a table, instead of
// displaying each file immediately, then calculating the maximum