exa.rs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. use std::io::fs;
  2. use std::io;
  3. use std::os;
  4. use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan};
  5. mod colours;
  6. fn main() {
  7. match os::args().as_slice() {
  8. [] => unreachable!(),
  9. [_] => { list(Path::new(".")) },
  10. [_, ref p] => { list(Path::new(p.as_slice())) },
  11. _ => { fail!("args?") },
  12. }
  13. }
  14. fn list(path: Path) {
  15. let mut files = match fs::readdir(&path) {
  16. Ok(files) => files,
  17. Err(e) => fail!("readdir: {}", e),
  18. };
  19. files.sort_by(|a, b| a.filename_str().cmp(&b.filename_str()));
  20. for file in files.iter() {
  21. let filename: &str = file.filename_str().unwrap();
  22. // We have to use lstat here instad of file.stat(), as it
  23. // doesn't follow symbolic links. Otherwise, the stat() call
  24. // will fail if it encounters a link that's target is
  25. // non-existent.
  26. let stat: io::FileStat = match fs::lstat(file) {
  27. Ok(stat) => stat,
  28. Err(e) => fail!("Couldn't stat {}: {}", filename, e),
  29. };
  30. let colour = file_colour(&stat, filename);
  31. println!("{} {}", perm_str(&stat), colour.paint(filename.to_owned()));
  32. }
  33. }
  34. fn file_colour(stat: &io::FileStat, filename: &str) -> Style {
  35. if stat.kind == io::TypeDirectory {
  36. Blue.normal()
  37. } else if stat.perm & io::UserExecute == io::UserExecute {
  38. Green.normal()
  39. } else if filename.ends_with("~") {
  40. Black.bold()
  41. } else {
  42. Plain
  43. }
  44. }
  45. fn perm_str(stat: &io::FileStat) -> ~str {
  46. let bits = stat.perm;
  47. return format!("{}{}{}{}{}{}{}{}{}{}",
  48. type_char(stat.kind),
  49. bit(bits, io::UserRead, ~"r", Yellow.bold()),
  50. bit(bits, io::UserWrite, ~"w", Red.bold()),
  51. bit(bits, io::UserExecute, ~"x", Green.bold().underline()),
  52. bit(bits, io::GroupRead, ~"r", Yellow.normal()),
  53. bit(bits, io::GroupWrite, ~"w", Red.normal()),
  54. bit(bits, io::GroupExecute, ~"x", Green.normal()),
  55. bit(bits, io::OtherRead, ~"r", Yellow.normal()),
  56. bit(bits, io::OtherWrite, ~"w", Red.normal()),
  57. bit(bits, io::OtherExecute, ~"x", Green.normal()),
  58. );
  59. }
  60. fn bit(bits: u32, bit: u32, other: ~str, style: Style) -> ~str {
  61. if bits & bit == bit {
  62. style.paint(other)
  63. } else {
  64. Black.bold().paint(~"-")
  65. }
  66. }
  67. fn type_char(t: io::FileType) -> ~str {
  68. return match t {
  69. io::TypeFile => ~".",
  70. io::TypeDirectory => Blue.paint("d"),
  71. io::TypeNamedPipe => Yellow.paint("|"),
  72. io::TypeBlockSpecial => Purple.paint("s"),
  73. io::TypeSymlink => Cyan.paint("l"),
  74. _ => ~"?",
  75. }
  76. }