main.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #![warn(trivial_casts, trivial_numeric_casts)]
  2. #![warn(unused_qualifications)]
  3. #![warn(unused_results)]
  4. extern crate ansi_term;
  5. extern crate datetime;
  6. extern crate getopts;
  7. extern crate libc;
  8. extern crate locale;
  9. extern crate natord;
  10. extern crate num_cpus;
  11. extern crate number_prefix;
  12. extern crate scoped_threadpool;
  13. extern crate term_grid;
  14. extern crate unicode_width;
  15. extern crate users;
  16. extern crate zoneinfo_data;
  17. #[cfg(feature="git")] extern crate git2;
  18. #[macro_use] extern crate lazy_static;
  19. use std::env;
  20. use std::path::{Component, Path};
  21. use std::process;
  22. use dir::Dir;
  23. use file::File;
  24. use options::{Options, View};
  25. mod dir;
  26. mod feature;
  27. mod file;
  28. mod filetype;
  29. mod options;
  30. mod output;
  31. mod term;
  32. struct Exa {
  33. options: Options,
  34. }
  35. impl Exa {
  36. fn run(&mut self, mut args_file_names: Vec<String>) {
  37. let mut files = Vec::new();
  38. let mut dirs = Vec::new();
  39. if args_file_names.is_empty() {
  40. args_file_names.push(".".to_owned());
  41. }
  42. for file_name in args_file_names.iter() {
  43. match File::from_path(Path::new(&file_name), None) {
  44. Err(e) => {
  45. println!("{}: {}", file_name, e);
  46. },
  47. Ok(f) => {
  48. if f.is_directory() && !self.options.dir_action.treat_dirs_as_files() {
  49. match f.to_dir(self.options.should_scan_for_git()) {
  50. Ok(d) => dirs.push(d),
  51. Err(e) => println!("{}: {}", file_name, e),
  52. }
  53. }
  54. else {
  55. files.push(f);
  56. }
  57. },
  58. }
  59. }
  60. let no_files = files.is_empty();
  61. if !no_files {
  62. self.print_files(None, files);
  63. }
  64. let is_only_dir = dirs.len() == 1;
  65. self.print_dirs(dirs, no_files, is_only_dir);
  66. }
  67. fn print_dirs(&self, dir_files: Vec<Dir>, mut first: bool, is_only_dir: bool) {
  68. for dir in dir_files {
  69. // Put a gap between directories, or between the list of files and the
  70. // first directory.
  71. if first {
  72. first = false;
  73. }
  74. else {
  75. print!("\n");
  76. }
  77. if !is_only_dir {
  78. println!("{}:", dir.path.display());
  79. }
  80. let mut children = Vec::new();
  81. for file in dir.files() {
  82. match file {
  83. Ok(file) => children.push(file),
  84. Err((path, e)) => println!("[{}: {}]", path.display(), e),
  85. }
  86. };
  87. self.options.filter.filter_files(&mut children);
  88. self.options.filter.sort_files(&mut children);
  89. if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
  90. let depth = dir.path.components().filter(|&c| c != Component::CurDir).count() + 1;
  91. if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {
  92. let mut child_dirs = Vec::new();
  93. for child_dir in children.iter().filter(|f| f.is_directory()) {
  94. match child_dir.to_dir(false) {
  95. Ok(d) => child_dirs.push(d),
  96. Err(e) => println!("{}: {}", child_dir.path.display(), e),
  97. }
  98. }
  99. self.print_files(Some(&dir), children);
  100. if !child_dirs.is_empty() {
  101. self.print_dirs(child_dirs, false, false);
  102. }
  103. continue;
  104. }
  105. }
  106. self.print_files(Some(&dir), children);
  107. }
  108. }
  109. fn print_files(&self, dir: Option<&Dir>, files: Vec<File>) {
  110. match self.options.view {
  111. View::Grid(g) => g.view(&files),
  112. View::Details(d) => d.view(dir, files),
  113. View::GridDetails(gd) => gd.view(dir, files),
  114. View::Lines(l) => l.view(files),
  115. }
  116. }
  117. }
  118. fn main() {
  119. let args: Vec<String> = env::args().skip(1).collect();
  120. match Options::getopts(&args) {
  121. Ok((options, paths)) => {
  122. let mut exa = Exa { options: options };
  123. exa.run(paths);
  124. },
  125. Err(e) => {
  126. println!("{}", e);
  127. process::exit(e.error_code());
  128. },
  129. };
  130. }