2014-05-22 00:02:47 +00:00
#![ feature(phase) ]
extern crate regex ;
#[ phase(syntax) ] extern crate regex_macros ;
2014-05-03 10:30:37 +00:00
use std ::os ;
2014-05-04 20:33:14 +00:00
use std ::io ::fs ;
use file ::File ;
2014-05-25 16:14:50 +00:00
use options ::Options ;
2014-05-03 10:30:37 +00:00
2014-05-04 20:33:14 +00:00
pub mod colours ;
pub mod column ;
pub mod format ;
pub mod file ;
2014-05-05 10:29:50 +00:00
pub mod unix ;
2014-05-24 01:17:43 +00:00
pub mod options ;
2014-06-01 10:54:31 +00:00
pub mod sort ;
2014-05-04 16:01:54 +00:00
2014-05-03 10:30:37 +00:00
fn main ( ) {
2014-05-26 19:24:51 +00:00
let args = os ::args ( ) ;
2014-05-25 16:14:50 +00:00
match Options ::getopts ( args ) {
Err ( err ) = > println! ( " Invalid options: \n {} " , err . to_err_msg ( ) ) ,
Ok ( opts ) = > {
2014-05-26 19:24:51 +00:00
// Default to listing the current directory when a target
// isn't specified (mimic the behaviour of ls)
2014-05-25 16:14:50 +00:00
let strs = if opts . dirs . is_empty ( ) {
2014-06-02 20:02:06 +00:00
vec! ( " . " . to_string ( ) )
2014-05-25 16:14:50 +00:00
}
else {
opts . dirs . clone ( )
} ;
for dir in strs . move_iter ( ) {
exa ( & opts , Path ::new ( dir ) )
}
}
2014-05-05 09:51:24 +00:00
} ;
2014-05-03 10:30:37 +00:00
}
2014-05-25 16:14:50 +00:00
fn exa ( options : & Options , path : Path ) {
2014-05-24 01:17:43 +00:00
let paths = match fs ::readdir ( & path ) {
Ok ( paths ) = > paths ,
2014-05-04 15:28:42 +00:00
Err ( e ) = > fail! ( " readdir: {} " , e ) ,
} ;
2014-05-26 11:46:51 +00:00
let unordered_files : Vec < File > = paths . iter ( ) . map ( | path | File ::from_path ( path ) ) . collect ( ) ;
let files : Vec < & File > = options . transform_files ( & unordered_files ) ;
2014-05-25 16:14:50 +00:00
2014-05-26 19:24:51 +00:00
// 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.
2014-05-26 10:08:33 +00:00
let table : Vec < Vec < String > > = files . iter ( )
2014-05-26 14:44:16 +00:00
. map ( | f | options . columns . iter ( ) . map ( | c | f . display ( c ) ) . collect ( ) )
2014-05-22 00:02:47 +00:00
. collect ( ) ;
2014-05-03 13:26:49 +00:00
2014-05-26 19:24:51 +00:00
// 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.
2014-05-25 16:14:50 +00:00
let lengths : Vec < Vec < uint > > = table . iter ( )
2014-05-26 10:50:46 +00:00
. map ( | row | row . iter ( ) . map ( | col | colours ::strip_formatting ( col ) . len ( ) ) . collect ( ) )
2014-05-25 16:14:50 +00:00
. collect ( ) ;
2014-05-26 19:24:51 +00:00
let column_widths : Vec < uint > = range ( 0 , options . columns . len ( ) )
2014-05-25 16:14:50 +00:00
. map ( | n | lengths . iter ( ) . map ( | row | * row . get ( n ) ) . max ( ) . unwrap ( ) )
2014-05-22 00:02:47 +00:00
. collect ( ) ;
2014-05-03 10:30:37 +00:00
2014-05-25 16:14:50 +00:00
for ( field_lengths , row ) in lengths . iter ( ) . zip ( table . iter ( ) ) {
2014-05-03 11:15:35 +00:00
let mut first = true ;
2014-06-03 20:14:35 +00:00
for ( ( ( column_length , cell ) , field_length ) , column ) in column_widths . iter ( ) . zip ( row . iter ( ) ) . zip ( field_lengths . iter ( ) ) . zip ( options . columns . iter ( ) ) { // this is getting messy
2014-05-03 11:15:35 +00:00
if first {
first = false ;
} else {
print! ( " " ) ;
}
2014-06-03 20:14:35 +00:00
print! ( " {} " , column . alignment ( ) . pad_string ( cell , * field_length , * column_length ) ) ;
2014-05-03 11:15:35 +00:00
}
print! ( " \n " ) ;
2014-05-03 10:30:37 +00:00
}
}