|
|
@@ -0,0 +1,86 @@
|
|
|
+use std::io::fs;
|
|
|
+use std::io;
|
|
|
+use std::os;
|
|
|
+
|
|
|
+use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan};
|
|
|
+mod colours;
|
|
|
+
|
|
|
+fn main() {
|
|
|
+ match os::args().as_slice() {
|
|
|
+ [] => unreachable!(),
|
|
|
+ [_] => { list(Path::new(".")) },
|
|
|
+ [_, ref p] => { list(Path::new(p.as_slice())) },
|
|
|
+ _ => { fail!("args?") },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn list(path: Path) {
|
|
|
+ let mut files = match fs::readdir(&path) {
|
|
|
+ Ok(files) => files,
|
|
|
+ Err(e) => fail!("readdir: {}", e),
|
|
|
+ };
|
|
|
+ files.sort_by(|a, b| a.filename_str().cmp(&b.filename_str()));
|
|
|
+ for file in files.iter() {
|
|
|
+ let filename: &str = file.filename_str().unwrap();
|
|
|
+
|
|
|
+ // We have to use lstat here instad of file.stat(), as it
|
|
|
+ // doesn't follow symbolic links. Otherwise, the stat() call
|
|
|
+ // will fail if it encounters a link that's target is
|
|
|
+ // non-existent.
|
|
|
+ let stat: io::FileStat = match fs::lstat(file) {
|
|
|
+ Ok(stat) => stat,
|
|
|
+ Err(e) => fail!("Couldn't stat {}: {}", filename, e),
|
|
|
+ };
|
|
|
+
|
|
|
+ let colour = file_colour(&stat, filename);
|
|
|
+
|
|
|
+ println!("{} {}", perm_str(&stat), colour.paint(filename.to_owned()));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn file_colour(stat: &io::FileStat, filename: &str) -> Style {
|
|
|
+ if stat.kind == io::TypeDirectory {
|
|
|
+ Blue.normal()
|
|
|
+ } else if stat.perm & io::UserExecute == io::UserExecute {
|
|
|
+ Green.normal()
|
|
|
+ } else if filename.ends_with("~") {
|
|
|
+ Black.bold()
|
|
|
+ } else {
|
|
|
+ Plain
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn perm_str(stat: &io::FileStat) -> ~str {
|
|
|
+ let bits = stat.perm;
|
|
|
+ return format!("{}{}{}{}{}{}{}{}{}{}",
|
|
|
+ type_char(stat.kind),
|
|
|
+ bit(bits, io::UserRead, ~"r", Yellow.bold()),
|
|
|
+ bit(bits, io::UserWrite, ~"w", Red.bold()),
|
|
|
+ bit(bits, io::UserExecute, ~"x", Green.bold().underline()),
|
|
|
+ bit(bits, io::GroupRead, ~"r", Yellow.normal()),
|
|
|
+ bit(bits, io::GroupWrite, ~"w", Red.normal()),
|
|
|
+ bit(bits, io::GroupExecute, ~"x", Green.normal()),
|
|
|
+ bit(bits, io::OtherRead, ~"r", Yellow.normal()),
|
|
|
+ bit(bits, io::OtherWrite, ~"w", Red.normal()),
|
|
|
+ bit(bits, io::OtherExecute, ~"x", Green.normal()),
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+fn bit(bits: u32, bit: u32, other: ~str, style: Style) -> ~str {
|
|
|
+ if bits & bit == bit {
|
|
|
+ style.paint(other)
|
|
|
+ } else {
|
|
|
+ Black.bold().paint(~"-")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn type_char(t: io::FileType) -> ~str {
|
|
|
+ return match t {
|
|
|
+ io::TypeFile => ~".",
|
|
|
+ io::TypeDirectory => Blue.paint("d"),
|
|
|
+ io::TypeNamedPipe => Yellow.paint("|"),
|
|
|
+ io::TypeBlockSpecial => Purple.paint("s"),
|
|
|
+ io::TypeSymlink => Cyan.paint("l"),
|
|
|
+ _ => ~"?",
|
|
|
+ }
|
|
|
+}
|