diff --git a/README.md b/README.md index 7f6ec2a..54c6aeb 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,9 @@ Options - **-b**, **--binary**: use binary (power of two) file sizes - **-g**, **--group**: show group as well as user - **-h**, **--header**: show a header row +- **-H**, **--links**: show number of hard links column - **-i**, **--inode**: show inode number column -- **-l**, **--links**: show number of hard links column +- **-l**, **--long**: display extended details and attributes - **-r**, **--reverse**: reverse sort order - **-s**, **--sort=(name, size, ext)**: field to sort by - **-S**, **--blocks**: show number of file system blocks diff --git a/src/exa.rs b/src/exa.rs index 37a6ebd..2d38a95 100644 --- a/src/exa.rs +++ b/src/exa.rs @@ -7,7 +7,8 @@ use std::os; use file::File; use dir::Dir; -use options::Options; +use column::{Column, Left}; +use options::{Options, Lines, Grid}; use unix::Unix; use ansi_term::{Paint, Plain, strip_formatting}; @@ -48,7 +49,10 @@ fn exa(opts: &Options) { match Dir::readdir(Path::new(dir_name.clone())) { Ok(dir) => { if print_dir_names { println!("{}:", dir_name); } - lines_view(opts, dir); + match opts.view { + Lines(ref cols) => lines_view(opts, cols, dir), + Grid => grid_view(opts, dir), + } } Err(e) => { println!("{}: {}", dir_name, e); @@ -58,7 +62,24 @@ fn exa(opts: &Options) { } } -fn lines_view(options: &Options, dir: Dir) { +fn grid_view(options: &Options, dir: Dir) { + let unsorted_files = dir.files(); + let files: Vec<&File> = options.transform_files(&unsorted_files); + + let max_column_length = files.iter().map(|f| f.name.len()).max().unwrap(); + let console_width = 80; + let num_columns = console_width / max_column_length; + + for y in range(0, files.len() / num_columns) { + for x in range(0, num_columns) { + let file_name = files.get(y * num_columns + x).name.clone(); + print!("{}", Left.pad_string(&file_name, max_column_length - strip_formatting(file_name.clone()).len() + 1)); + } + print!("\n"); + } +} + +fn lines_view(options: &Options, columns: &Vec, dir: Dir) { let unsorted_files = dir.files(); let files: Vec<&File> = options.transform_files(&unsorted_files); @@ -71,11 +92,11 @@ fn lines_view(options: &Options, dir: Dir) { let mut cache = Unix::empty_cache(); let mut table: Vec> = files.iter() - .map(|f| options.columns.iter().map(|c| f.display(c, &mut cache)).collect()) + .map(|f| columns.iter().map(|c| f.display(c, &mut cache)).collect()) .collect(); if options.header { - table.unshift(options.columns.iter().map(|c| Plain.underline().paint(c.header())).collect()); + table.unshift(columns.iter().map(|c| Plain.underline().paint(c.header())).collect()); } // Each column needs to have its invisible colour-formatting @@ -88,17 +109,17 @@ fn lines_view(options: &Options, dir: Dir) { .map(|row| row.iter().map(|col| strip_formatting(col.clone()).len()).collect()) .collect(); - let column_widths: Vec = range(0, options.columns.len()) + let column_widths: Vec = range(0, columns.len()) .map(|n| lengths.iter().map(|row| *row.get(n)).max().unwrap()) .collect(); for (field_widths, row) in lengths.iter().zip(table.iter()) { - for (num, column) in options.columns.iter().enumerate() { + for (num, column) in columns.iter().enumerate() { if num != 0 { print!(" "); } - if num == options.columns.len() - 1 { + if num == columns.len() - 1 { print!("{}", row.get(num)); } else { diff --git a/src/options.rs b/src/options.rs index 3afa8b9..ab35448 100644 --- a/src/options.rs +++ b/src/options.rs @@ -9,15 +9,6 @@ pub enum SortField { Name, Extension, Size } -pub struct Options { - pub showInvisibles: bool, - pub sortField: SortField, - pub reverse: bool, - pub dirs: Vec, - pub columns: Vec, - pub header: bool, -} - impl SortField { fn from_word(word: String) -> SortField { match word.as_slice() { @@ -29,6 +20,21 @@ impl SortField { } } +pub enum View { + Lines(Vec), + Grid, +} + +pub struct Options { + pub show_invisibles: bool, + pub sort_field: SortField, + pub reverse: bool, + pub dirs: Vec, + pub view: View, + pub header: bool, +} + + impl Options { pub fn getopts(args: Vec) -> Result { let opts = [ @@ -36,8 +42,9 @@ impl Options { getopts::optflag("b", "binary", "use binary prefixes in file sizes"), 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"), + getopts::optflag("l", "long", "display extended details and attributes"), getopts::optflag("i", "inode", "show each file's inode number"), - getopts::optflag("l", "links", "show number of hard links"), getopts::optflag("r", "reverse", "reverse order of files"), getopts::optopt("s", "sort", "field to sort by", "WORD"), getopts::optflag("S", "blocks", "show number of file system blocks"), @@ -46,16 +53,25 @@ impl Options { match getopts::getopts(args.tail(), opts) { Err(f) => Err(f), Ok(matches) => Ok(Options { - showInvisibles: matches.opt_present("all"), + show_invisibles: matches.opt_present("all"), reverse: matches.opt_present("reverse"), header: matches.opt_present("header"), - sortField: matches.opt_str("sort").map(|word| SortField::from_word(word)).unwrap_or(Name), + sort_field: matches.opt_str("sort").map(|word| SortField::from_word(word)).unwrap_or(Name), dirs: if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() }, - columns: Options::columns(matches), + view: Options::view(matches), }) } } - + + fn view(matches: getopts::Matches) -> View { + if matches.opt_present("long") { + Lines(Options::columns(matches)) + } + else { + Grid + } + } + fn columns(matches: getopts::Matches) -> Vec { let mut columns = vec![]; @@ -87,7 +103,7 @@ impl Options { } fn should_display(&self, f: &File) -> bool { - if self.showInvisibles { + if self.show_invisibles { true } else { !f.name.as_slice().starts_with(".") @@ -99,7 +115,7 @@ impl Options { .filter(|&f| self.should_display(f)) .collect(); - match self.sortField { + match self.sort_field { Name => files.sort_by(|a, b| a.parts.cmp(&b.parts)), Size => files.sort_by(|a, b| a.stat.size.cmp(&b.stat.size)), Extension => files.sort_by(|a, b| {