exa.rs 4.8 KB
Newer Older
B
Ben S 已提交
1 2
#![feature(phase)]
extern crate regex;
B
Ben S 已提交
3
#[phase(plugin)] extern crate regex_macros;
4
extern crate ansi_term;
5 6
extern crate unicode;

B
Ben S 已提交
7
use std::os;
B
Ben S 已提交
8 9

use file::File;
B
Ben S 已提交
10
use dir::Dir;
B
Ben S 已提交
11
use column::{Column, Left};
B
Ben S 已提交
12
use options::{Options, Details, Lines, Grid};
B
Ben S 已提交
13
use unix::Unix;
B
Ben S 已提交
14

B
Ben S 已提交
15
use ansi_term::{Paint, Plain, strip_formatting};
16

B
Ben S 已提交
17
pub mod column;
B
Ben S 已提交
18
pub mod dir;
B
Ben S 已提交
19 20
pub mod format;
pub mod file;
21
pub mod filetype;
B
Ben S 已提交
22
pub mod unix;
B
Ben S 已提交
23
pub mod options;
B
Ben S 已提交
24
pub mod sort;
25
pub mod term;
B
Ben S 已提交
26

B
Ben S 已提交
27
fn main() {
B
Ben S 已提交
28
    let args = os::args();
29

B
Ben S 已提交
30
    match Options::getopts(args) {
B
Ben S 已提交
31
        Err(err) => println!("Invalid options:\n{}", err),
32
        Ok(opts) => exa(&opts),
B
Ben S 已提交
33
    };
B
Ben S 已提交
34 35
}

36 37 38 39 40 41 42 43 44 45 46 47 48
fn exa(opts: &Options) {
    let mut first = true;
    
    // It's only worth printing out directory names if the user supplied
    // more than one of them.
    let print_dir_names = opts.dirs.len() > 1;
    
    for dir_name in opts.dirs.clone().move_iter() {
        if first {
            first = false;
        }
        else {
            print!("\n");
B
Ben S 已提交
49
        }
50

51 52 53
        match Dir::readdir(Path::new(dir_name.clone())) {
            Ok(dir) => {
                if print_dir_names { println!("{}:", dir_name); }
B
Ben S 已提交
54
                match opts.view {
B
Ben S 已提交
55 56 57
                    Details(ref cols) => details_view(opts, cols, dir),
                    Lines => lines_view(opts, dir),
                    Grid(across, width) => grid_view(opts, across, width, dir),
B
Ben S 已提交
58
                }
59 60 61 62 63 64
            }
            Err(e) => {
                println!("{}: {}", dir_name, e);
                return;
            }
        };
65
    }
66
}
67

B
Ben S 已提交
68 69 70 71 72 73 74 75 76 77
fn lines_view(options: &Options, dir: Dir) {
    let unsorted_files = dir.files();
    let files: Vec<&File> = options.transform_files(&unsorted_files);
    
    for file in files.iter() {
        println!("{}", file.file_name());
    }
}

fn grid_view(options: &Options, across: bool, console_width: uint, dir: Dir) {
B
Ben S 已提交
78 79 80
    let unsorted_files = dir.files();
    let files: Vec<&File> = options.transform_files(&unsorted_files);
    
81
    let max_column_length = files.iter().map(|f| f.file_name_width()).max().unwrap();
B
Ben S 已提交
82
    let num_columns = (console_width + 1) / (max_column_length + 1);
B
Ben S 已提交
83
    let count = files.len();
B
Ben S 已提交
84

B
Ben S 已提交
85 86
    let mut num_rows = count / num_columns;
    if count % num_columns != 0 {
B
Ben S 已提交
87 88
        num_rows += 1;
    }
B
Ben S 已提交
89
    
B
Ben S 已提交
90
    for y in range(0, num_rows) {
B
Ben S 已提交
91
        for x in range(0, num_columns) {
B
Ben S 已提交
92 93 94 95 96 97 98 99
            let num = if across {
                y * num_columns + x
            }
            else {
                y + num_rows * x
            };
            
            if num >= count {
B
Ben S 已提交
100 101 102
                continue;
            }
            
B
Ben S 已提交
103
            let file = files[num];
B
Ben S 已提交
104 105
            let file_name = file.name.clone();
            let styled_name = file.file_colour().paint(file_name.as_slice());
B
Ben S 已提交
106 107 108 109 110 111
            if x == num_columns - 1 {
                print!("{}", styled_name);
            }
            else {
                print!("{}", Left.pad_string(&styled_name, max_column_length - file_name.len() + 1));
            }
B
Ben S 已提交
112 113 114 115 116
        }
        print!("\n");
    }
}

B
Ben S 已提交
117
fn details_view(options: &Options, columns: &Vec<Column>, dir: Dir) {
B
Ben S 已提交
118 119
    let unsorted_files = dir.files();
    let files: Vec<&File> = options.transform_files(&unsorted_files);
120

B
Ben S 已提交
121 122 123 124 125 126
    // 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
    // width of each column based on the length of the results and
    // padding the fields during output.

B
Ben S 已提交
127 128
    let mut cache = Unix::empty_cache();

B
Ben S 已提交
129
    let mut table: Vec<Vec<String>> = files.iter()
B
Ben S 已提交
130
        .map(|f| columns.iter().map(|c| f.display(c, &mut cache)).collect())
B
Ben S 已提交
131
        .collect();
B
Ben S 已提交
132

B
Ben S 已提交
133
    if options.header {
B
Ben S 已提交
134
        table.unshift(columns.iter().map(|c| Plain.underline().paint(c.header())).collect());
B
Ben S 已提交
135 136
    }

B
Ben S 已提交
137 138 139 140 141 142
    // Each column needs to have its invisible colour-formatting
    // characters stripped before it has its width calculated, or the
    // width will be incorrect and the columns won't line up properly.
    // This is fairly expensive to do (it uses a regex), so the
    // results are cached.

143
    let lengths: Vec<Vec<uint>> = table.iter()
B
Ben S 已提交
144
        .map(|row| row.iter().map(|col| strip_formatting(col.clone()).len()).collect())
145 146
        .collect();

B
Ben S 已提交
147
    let column_widths: Vec<uint> = range(0, columns.len())
B
Ben S 已提交
148
        .map(|n| lengths.iter().map(|row| row[n]).max().unwrap())
B
Ben S 已提交
149
        .collect();
B
Ben S 已提交
150

B
Ben S 已提交
151
    for (field_widths, row) in lengths.iter().zip(table.iter()) {
B
Ben S 已提交
152
        for (num, column) in columns.iter().enumerate() {
153
            if num != 0 {
B
Ben S 已提交
154 155
                print!(" ");
            }
156

B
Ben S 已提交
157
            if num == columns.len() - 1 {
B
Ben S 已提交
158
                print!("{}", row.get(num));
159 160
            }
            else {
B
Ben S 已提交
161
                let padding = column_widths[num] - field_widths[num];
B
Ben S 已提交
162
                print!("{}", column.alignment().pad_string(row.get(num), padding));
163
            }
B
Ben S 已提交
164 165
        }
        print!("\n");
B
Ben S 已提交
166 167
    }
}