Ben S 11 лет назад
Родитель
Сommit
5611a5768a
4 измененных файлов с 41 добавлено и 34 удалено
  1. 3 3
      src/dir.rs
  2. 31 24
      src/main.rs
  3. 1 1
      src/options.rs
  4. 6 6
      src/output.rs

+ 3 - 3
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<Dir> {
-        fs::readdir(&path).map(|paths| Dir {
+    pub fn readdir(path: &Path) -> IoResult<Dir> {
+        fs::readdir(path).map(|paths| Dir {
             contents: paths,
             path: path.clone(),
-            git: Git::scan(&path).ok(),
+            git: Git::scan(path).ok(),
         })
     }
 

+ 31 - 24
src/main.rs

@@ -25,37 +25,24 @@ pub mod output;
 pub mod term;
 
 fn exa(options: &Options) {
-    let mut dirs: Vec<String> = vec![];
+    let mut dirs: Vec<Path> = vec![];
     let mut files: Vec<File> = 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<File> = options.transform_files(unsorted_files);
 
+                // 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());
+                    }
+                }
+
                 if count > 1 {
-                    println!("{}:", dir_name);
+                    println!("{}:", dir_path.display());
                 }
+                count += 1;
 
-                options.view(Some(dir), files);
+                options.view(Some(dir), &files[]);
             }
             Err(e) => {
-                println!("{}: {}", dir_name, e);
+                println!("{}: {}", dir_path.display(), e);
                 return;
             }
         };

+ 1 - 1
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<File>) {
+    pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
         self.view.view(dir, files)
     }
 

+ 6 - 6
src/output.rs

@@ -18,7 +18,7 @@ pub enum View {
 }
 
 impl View {
-    pub fn view(&self, dir: Option<&Dir>, files: Vec<File>) {
+    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<File>) {
+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<File>) -> Option<(usize, Vec<usize>)> {
+fn fit_into_grid(across: bool, console_width: usize, files: &[File]) -> Option<(usize, Vec<usize>)> {
     // 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<File>) -> Optio
     return None;
 }
 
-fn grid_view(across: bool, console_width: usize, files: Vec<File>) {
-    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<File>) {
     }
 }
 
-fn details_view(columns: &[Column], files: Vec<File>, 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