2014-05-22 00:02:47 +00:00
#![ feature(phase) ]
extern crate regex ;
2014-06-18 12:39:55 +00:00
#[ phase(plugin) ] extern crate regex_macros ;
2014-05-22 00:02:47 +00:00
2014-05-03 10:30:37 +00:00
use std ::os ;
2014-05-04 20:33:14 +00:00
use file ::File ;
2014-06-16 23:27:05 +00:00
use dir ::Dir ;
2014-05-25 16:14:50 +00:00
use options ::Options ;
2014-06-21 16:50:37 +00:00
use unix ::Unix ;
2014-06-23 17:26:35 +00:00
use colours ::Plain ;
2014-05-03 10:30:37 +00:00
2014-05-04 20:33:14 +00:00
pub mod colours ;
pub mod column ;
2014-06-16 23:27:05 +00:00
pub mod dir ;
2014-05-04 20:33:14 +00:00
pub mod format ;
pub mod file ;
2014-06-17 08:35:40 +00:00
pub mod filetype ;
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-06-21 17:12:29 +00:00
2014-05-25 16:14:50 +00:00
match Options ::getopts ( args ) {
2014-06-18 12:39:55 +00:00
Err ( err ) = > println! ( " Invalid options: \n {} " , err ) ,
2014-05-25 16:14:50 +00:00
Ok ( opts ) = > {
2014-06-21 17:12:29 +00:00
if opts . dirs . is_empty ( ) {
exa ( & opts , false , " . " . to_string ( ) )
2014-05-25 16:14:50 +00:00
}
else {
2014-06-21 17:12:29 +00:00
let mut first = true ;
let print_header = opts . dirs . len ( ) > 1 ;
for dir in opts . dirs . clone ( ) . move_iter ( ) {
if first {
first = false ;
}
else {
print! ( " \n " ) ;
}
exa ( & opts , print_header , dir )
}
2014-05-25 16:14:50 +00:00
}
}
2014-05-05 09:51:24 +00:00
} ;
2014-05-03 10:30:37 +00:00
}
2014-06-21 17:12:29 +00:00
fn exa ( options : & Options , print_header : bool , string : String ) {
2014-06-20 20:07:53 +00:00
let path = Path ::new ( string . clone ( ) ) ;
let dir = match Dir ::readdir ( path ) {
Ok ( dir ) = > dir ,
Err ( e ) = > {
println! ( " {} : {} " , string , e ) ;
return ;
}
} ;
2014-06-21 17:12:29 +00:00
// Print header *after* readdir must have succeeded
if print_header {
println! ( " {} : " , string ) ;
}
2014-06-16 23:27:05 +00:00
let unsorted_files = dir . files ( ) ;
let files : Vec < & File > = options . transform_files ( & unsorted_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-06-21 16:50:37 +00:00
let mut cache = Unix ::empty_cache ( ) ;
2014-06-23 17:26:35 +00:00
let mut table : Vec < Vec < String > > = files . iter ( )
2014-06-21 16:50:37 +00:00
. map ( | f | options . columns . iter ( ) . map ( | c | f . display ( c , & mut cache ) ) . collect ( ) )
2014-05-22 00:02:47 +00:00
. collect ( ) ;
2014-05-03 13:26:49 +00:00
2014-06-23 17:26:35 +00:00
if options . header {
table . unshift ( options . columns . iter ( ) . map ( | c | Plain . underline ( ) . paint ( c . header ( ) ) ) . collect ( ) ) ;
}
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-06-20 18:43:15 +00:00
for ( ( ( column_length , cell ) , field_length ) , ( num , column ) ) in column_widths . iter ( ) . zip ( row . iter ( ) ) . zip ( field_lengths . iter ( ) ) . zip ( options . columns . iter ( ) . enumerate ( ) ) { // this is getting messy
if num ! = 0 {
2014-05-03 11:15:35 +00:00
print! ( " " ) ;
}
2014-06-21 17:12:29 +00:00
2014-06-20 18:43:15 +00:00
if num = = options . columns . len ( ) - 1 {
print! ( " {} " , cell ) ;
}
else {
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
}
}