options.rs 4.6 KB
Newer Older
B
Ben S 已提交
1 2
extern crate getopts;

B
Ben S 已提交
3
use file::File;
B
Ben S 已提交
4
use column::{Column, Permissions, FileName, FileSize, User, Group, HardLinks, Inode, Blocks};
B
Ben S 已提交
5
use std::ascii::StrAsciiExt;
B
Ben S 已提交
6
use term;
B
Ben S 已提交
7 8

pub enum SortField {
B
Ben S 已提交
9
    Unsorted, Name, Extension, Size, FileInode
B
Ben S 已提交
10 11 12
}

impl SortField {
13
    fn from_word(word: String) -> SortField {
B
Ben S 已提交
14
        match word.as_slice() {
B
Ben S 已提交
15 16 17 18 19 20
            "name"  => Name,
            "size"  => Size,
            "ext"   => Extension,
            "none"  => Unsorted,
            "inode" => FileInode,
            _       => fail!("Invalid sorting order"),
B
Ben S 已提交
21 22 23 24
        }
    }
}

B
Ben S 已提交
25
pub enum View {
B
Ben S 已提交
26 27 28
    Details(Vec<Column>),
    Lines,
    Grid(bool, uint),
B
Ben S 已提交
29 30 31 32 33 34 35 36 37 38 39 40
}

pub struct Options {
    pub show_invisibles: bool,
    pub sort_field: SortField,
    pub reverse: bool,
    pub dirs: Vec<String>,
    pub view: View,
    pub header: bool,
}


B
Ben S 已提交
41
impl Options {
B
Ben S 已提交
42
    pub fn getopts(args: Vec<String>) -> Result<Options, getopts::Fail_> {
B
Ben S 已提交
43
        let opts = [
B
Ben S 已提交
44
            getopts::optflag("1", "oneline", "display one entry per line"),
B
Ben S 已提交
45
            getopts::optflag("a", "all", "show dot-files"),
B
Ben S 已提交
46
            getopts::optflag("b", "binary", "use binary prefixes in file sizes"),
B
Ben S 已提交
47
            getopts::optflag("g", "group", "show group as well as user"),
B
Ben S 已提交
48
            getopts::optflag("h", "header", "show a header row at the top"),
B
Ben S 已提交
49 50
            getopts::optflag("H", "links", "show number of hard links"),
            getopts::optflag("l", "long", "display extended details and attributes"),
B
Ben S 已提交
51
            getopts::optflag("i", "inode", "show each file's inode number"),
B
Ben S 已提交
52 53
            getopts::optflag("r", "reverse", "reverse order of files"),
            getopts::optopt("s", "sort", "field to sort by", "WORD"),
B
Ben S 已提交
54
            getopts::optflag("S", "blocks", "show number of file system blocks"),
B
Ben S 已提交
55
            getopts::optflag("x", "across", "sort multi-column view entries across"),
B
Ben S 已提交
56 57 58 59 60
        ];

        match getopts::getopts(args.tail(), opts) {
            Err(f) => Err(f),
            Ok(matches) => Ok(Options {
B
Ben S 已提交
61
                show_invisibles: matches.opt_present("all"),
B
Ben S 已提交
62
                reverse: matches.opt_present("reverse"),
B
Ben S 已提交
63
                header: matches.opt_present("header"),
B
Ben S 已提交
64
                sort_field: matches.opt_str("sort").map(|word| SortField::from_word(word)).unwrap_or(Name),
65
                dirs: if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
B
Ben S 已提交
66
                view: Options::view(matches),
B
Ben S 已提交
67 68 69
            })
        }
    }
B
Ben S 已提交
70 71 72
    
    fn view(matches: getopts::Matches) -> View {
        if matches.opt_present("long") {
B
Ben S 已提交
73 74 75 76
            Details(Options::columns(matches))
        }
        else if matches.opt_present("oneline") {
            Lines
B
Ben S 已提交
77 78
        }
        else {
79 80 81 82
            match term::dimensions() {
                None => Lines,
                Some((width, _)) => Grid(matches.opt_present("across"), width),
            }
B
Ben S 已提交
83 84 85
        }
    }
    
B
Ben S 已提交
86
    fn columns(matches: getopts::Matches) -> Vec<Column> {
B
Ben S 已提交
87 88 89 90 91 92 93
        let mut columns = vec![];

        if matches.opt_present("inode") {
            columns.push(Inode);
        }

        columns.push(Permissions);
B
Ben S 已提交
94 95 96 97 98 99

        if matches.opt_present("links") {
            columns.push(HardLinks);
        }
        
        columns.push(FileSize(matches.opt_present("binary")));
B
Ben S 已提交
100 101 102 103 104

        if matches.opt_present("blocks") {
            columns.push(Blocks);
        }

B
Ben S 已提交
105
        columns.push(User);
B
Ben S 已提交
106 107 108 109 110 111 112 113

        if matches.opt_present("group") {
            columns.push(Group);
        }

        columns.push(FileName);

        return columns;
B
Ben S 已提交
114 115
    }

B
Ben S 已提交
116
    fn should_display(&self, f: &File) -> bool {
B
Ben S 已提交
117
        if self.show_invisibles {
B
Ben S 已提交
118 119
            true
        } else {
B
Ben S 已提交
120
            !f.name.as_slice().starts_with(".")
B
Ben S 已提交
121 122
        }
    }
B
Ben S 已提交
123

B
Ben S 已提交
124 125
    pub fn transform_files<'a>(&self, unordered_files: &'a Vec<File<'a>>) -> Vec<&'a File<'a>> {
        let mut files: Vec<&'a File<'a>> = unordered_files.iter()
B
Ben S 已提交
126
            .filter(|&f| self.should_display(f))
B
Ben S 已提交
127
            .collect();
128

B
Ben S 已提交
129
        match self.sort_field {
B
Ben S 已提交
130
            Unsorted => {},
B
Ben S 已提交
131
            Name => files.sort_by(|a, b| a.parts.cmp(&b.parts)),
132
            Size => files.sort_by(|a, b| a.stat.size.cmp(&b.stat.size)),
B
Ben S 已提交
133
            FileInode => files.sort_by(|a, b| a.stat.unstable.inode.cmp(&b.stat.unstable.inode)),
134
            Extension => files.sort_by(|a, b| {
B
Ben S 已提交
135 136
                let exts = a.ext.clone().map(|e| e.as_slice().to_ascii_lower()).cmp(&b.ext.clone().map(|e| e.as_slice().to_ascii_lower()));
                let names = a.name.as_slice().to_ascii_lower().cmp(&b.name.as_slice().to_ascii_lower());
B
Ben S 已提交
137
                exts.cmp(&names)
138 139 140 141 142 143 144 145 146
            }),
        }

        if self.reverse {
            files.reverse();
        }

        return files;
    }
B
Ben S 已提交
147
}