file.rs 3.6 KB
Newer Older
B
Ben S 已提交
1 2 3 4
use std::io::fs;
use std::io;

use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan};
B
Ben S 已提交
5
use column::{Column, Permissions, FileName, FileSize, User, Group};
B
Ben S 已提交
6
use format::{formatBinaryBytes, formatDecimalBytes};
B
Ben S 已提交
7
use unix::{get_user_name, get_group_name};
B
Ben S 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

// Each file is definitely going to get `stat`ted at least once, if
// only to determine what kind of file it is, so carry the `stat`
// result around with the file for safe keeping.
pub struct File<'a> {
    name: &'a str,
    path: &'a Path,
    stat: io::FileStat,
}

impl<'a> File<'a> {
    pub fn from_path(path: &'a Path) -> File<'a> {
        let filename: &str = path.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(path) {
            Ok(stat) => stat,
            Err(e) => fail!("Couldn't stat {}: {}", filename, e),
        };

        return File { path: path, stat: stat, name: filename };
    }

B
Ben S 已提交
34 35 36 37
    pub fn is_dotfile(&self) -> bool {
        self.name.starts_with(".")
    }

B
Ben S 已提交
38 39 40 41 42
    pub fn display(&self, column: &Column) -> ~str {
        match *column {
            Permissions => self.permissions(),
            FileName => self.file_colour().paint(self.name.to_owned()),
            FileSize(si) => self.file_size(si),
43 44
            User => get_user_name(self.stat.unstable.uid as i32).unwrap_or(self.stat.unstable.uid.to_str()),
            Group => get_group_name(self.stat.unstable.gid as u32).unwrap_or(self.stat.unstable.gid.to_str()),
B
Ben S 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
        }
    }

    fn file_size(&self, si: bool) -> ~str {
        let sizeStr = if si {
            formatBinaryBytes(self.stat.size)
        } else {
            formatDecimalBytes(self.stat.size)
        };

        return if self.stat.kind == io::TypeDirectory {
            Green.normal()
        } else {
            Green.bold()
        }.paint(sizeStr);
    }

    fn type_char(&self) -> ~str {
        return match self.stat.kind {
B
Ben S 已提交
64
            io::TypeFile => ".".to_owned(),
B
Ben S 已提交
65 66 67 68
            io::TypeDirectory => Blue.paint("d"),
            io::TypeNamedPipe => Yellow.paint("|"),
            io::TypeBlockSpecial => Purple.paint("s"),
            io::TypeSymlink => Cyan.paint("l"),
B
Ben S 已提交
69
            _ => "?".to_owned(),
B
Ben S 已提交
70 71 72 73 74 75 76
        }
    }


    fn file_colour(&self) -> Style {
        if self.stat.kind == io::TypeDirectory {
            Blue.normal()
B
Ben S 已提交
77
        } else if self.stat.perm.contains(io::UserExecute) {
B
Ben S 已提交
78 79 80 81 82 83 84 85 86 87 88 89
            Green.normal()
        } else if self.name.ends_with("~") {
            Black.bold()
        } else {
            Plain
        }
    }

    fn permissions(&self) -> ~str {
        let bits = self.stat.perm;
        return format!("{}{}{}{}{}{}{}{}{}{}",
            self.type_char(),
B
Ben S 已提交
90 91 92 93 94 95 96 97 98
            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()),
B
Ben S 已提交
99 100 101 102
       );
    }
}

B
Ben S 已提交
103 104
fn bit(bits: io::FilePermission, bit: io::FilePermission, other: &'static str, style: Style) -> ~str {
    if bits.contains(bit) {
B
Ben S 已提交
105
        style.paint(other.to_owned())
B
Ben S 已提交
106
    } else {
B
Ben S 已提交
107
        Black.bold().paint("-".to_owned())
B
Ben S 已提交
108 109
    }
}