exa.rs 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #![feature(phase)]
  2. extern crate regex;
  3. #[phase(plugin)] extern crate regex_macros;
  4. use std::os;
  5. use file::File;
  6. use dir::Dir;
  7. use options::Options;
  8. pub mod colours;
  9. pub mod column;
  10. pub mod dir;
  11. pub mod format;
  12. pub mod file;
  13. pub mod filetype;
  14. pub mod unix;
  15. pub mod options;
  16. pub mod sort;
  17. fn main() {
  18. let args = os::args();
  19. match Options::getopts(args) {
  20. Err(err) => println!("Invalid options:\n{}", err),
  21. Ok(opts) => {
  22. // Default to listing the current directory when a target
  23. // isn't specified (mimic the behaviour of ls)
  24. let strs = if opts.dirs.is_empty() {
  25. vec!(".".to_string())
  26. }
  27. else {
  28. opts.dirs.clone()
  29. };
  30. for dir in strs.move_iter() {
  31. exa(&opts, Path::new(dir))
  32. }
  33. }
  34. };
  35. }
  36. fn exa(options: &Options, path: Path) {
  37. let dir = Dir::readdir(path);
  38. let unsorted_files = dir.files();
  39. let files: Vec<&File> = options.transform_files(&unsorted_files);
  40. // The output gets formatted into columns, which looks nicer. To
  41. // do this, we have to write the results into a table, instead of
  42. // displaying each file immediately, then calculating the maximum
  43. // width of each column based on the length of the results and
  44. // padding the fields during output.
  45. let table: Vec<Vec<String>> = files.iter()
  46. .map(|f| options.columns.iter().map(|c| f.display(c)).collect())
  47. .collect();
  48. // Each column needs to have its invisible colour-formatting
  49. // characters stripped before it has its width calculated, or the
  50. // width will be incorrect and the columns won't line up properly.
  51. // This is fairly expensive to do (it uses a regex), so the
  52. // results are cached.
  53. let lengths: Vec<Vec<uint>> = table.iter()
  54. .map(|row| row.iter().map(|col| colours::strip_formatting(col).len()).collect())
  55. .collect();
  56. let column_widths: Vec<uint> = range(0, options.columns.len())
  57. .map(|n| lengths.iter().map(|row| *row.get(n)).max().unwrap())
  58. .collect();
  59. for (field_lengths, row) in lengths.iter().zip(table.iter()) {
  60. let mut first = true;
  61. 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
  62. if first {
  63. first = false;
  64. } else {
  65. print!(" ");
  66. }
  67. print!("{}", column.alignment().pad_string(cell, *field_length, *column_length));
  68. }
  69. print!("\n");
  70. }
  71. }