summaryrefslogtreecommitdiffstats
path: root/src/options.rs
diff options
context:
space:
mode:
authorBen S <ogham@bsago.me>2015-02-05 14:39:56 +0000
committerBen S <ogham@bsago.me>2015-02-05 14:39:56 +0000
commit42ae7b3d332fa46df3bb27f474f6b91a2d399d62 (patch)
treeb046d4d87a08cf7080224bf05617728e2efc7769 /src/options.rs
parent5f2acf570c99c8e5fad5b7fabacd8c3d9b4c5c43 (diff)
Refactor the code after tree view changes
- Turn the views and main program loop into structs, rather than just as one gigantic function - Separate views into their own files The addition of the git column and the tree view meant that a lot of functions now just took extra arguments that didn't seem to fit. For example, it didn't really work to have only one 'view' method that printed out everything, as the different view options now all take different parameters.
Diffstat (limited to 'src/options.rs')
-rw-r--r--src/options.rs219
1 files changed, 127 insertions, 92 deletions
diff --git a/src/options.rs b/src/options.rs
index ba0ff59..d37af1e 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -1,8 +1,8 @@
use dir::Dir;
use file::File;
-use column::{Column, SizeFormat};
+use column::Column;
use column::Column::*;
-use output::View;
+use output::{Grid, Details};
use term::dimensions;
use std::ascii::AsciiExt;
@@ -16,12 +16,11 @@ use self::Misfire::*;
/// The *Options* struct represents a parsed version of the user's
/// command-line options.
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Debug, Copy)]
pub struct Options {
pub dir_action: DirAction,
- pub path_strs: Vec<String>,
pub filter: FileFilter,
- view: View,
+ pub view: View,
}
#[derive(PartialEq, Debug, Copy)]
@@ -31,10 +30,17 @@ pub struct FileFilter {
sort_field: SortField,
}
+#[derive(PartialEq, Copy, Debug)]
+pub enum View {
+ Details(Details),
+ Lines,
+ Grid(Grid),
+}
+
impl Options {
/// Call getopts on the given slice of command-line strings.
- pub fn getopts(args: &[String]) -> Result<Options, Misfire> {
+ pub fn getopts(args: &[String]) -> Result<(Options, Vec<String>), Misfire> {
let mut opts = getopts::Options::new();
opts.optflag("1", "oneline", "display one entry per line");
opts.optflag("a", "all", "show dot-files");
@@ -68,26 +74,29 @@ impl Options {
None => SortField::Name,
};
- Ok(Options {
- dir_action: try!(dir_action(&matches)),
- path_strs: if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
- view: try!(view(&matches)),
- filter: FileFilter {
- reverse: matches.opt_present("reverse"),
- show_invisibles: matches.opt_present("all"),
- sort_field: sort_field,
- },
- })
+ let filter = FileFilter {
+ reverse: matches.opt_present("reverse"),
+ show_invisibles: matches.opt_present("all"),
+ sort_field: sort_field,
+ };
+
+ let path_strs = if matches.free.is_empty() {
+ vec![ ".".to_string() ]
+ }
+ else {
+ matches.free.clone()
+ };
+
+ Ok((Options {
+ dir_action: try!(DirAction::deduce(&matches)),
+ view: try!(View::deduce(&matches, filter)),
+ filter: filter,
+ }, path_strs))
}
pub fn transform_files<'a>(&self, files: &mut Vec<File<'a>>) {
self.filter.transform_files(files)
}
-
- /// Display the files using this Option's View.
- pub fn view(&self, dir: Option<&Dir>, files: &[File], filter: FileFilter) {
- self.view.view(dir, files, filter)
- }
}
impl FileFilter {
@@ -119,12 +128,6 @@ impl FileFilter {
}
}
-/// What to do when encountering a directory?
-#[derive(PartialEq, Debug, Copy)]
-pub enum DirAction {
- AsFile, List, Recurse, Tree
-}
-
/// User-supplied field to sort by.
#[derive(PartialEq, Debug, Copy)]
pub enum SortField {
@@ -190,77 +193,111 @@ impl fmt::Display for Misfire {
}
}
-/// Turns the Getopts results object into a View object.
-fn view(matches: &getopts::Matches) -> Result<View, Misfire> {
- if matches.opt_present("long") {
- if matches.opt_present("across") {
- Err(Misfire::Useless("across", true, "long"))
+impl View {
+ pub fn deduce(matches: &getopts::Matches, filter: FileFilter) -> Result<View, Misfire> {
+ if matches.opt_present("long") {
+ if matches.opt_present("across") {
+ Err(Misfire::Useless("across", true, "long"))
+ }
+ else if matches.opt_present("oneline") {
+ Err(Misfire::Useless("oneline", true, "long"))
+ }
+ else {
+ let details = Details {
+ columns: try!(Columns::deduce(matches)),
+ header: matches.opt_present("tree"),
+ tree: matches.opt_present("recurse"),
+ filter: filter,
+ };
+
+ Ok(View::Details(details))
+ }
}
- else if matches.opt_present("oneline") {
- Err(Misfire::Useless("oneline", true, "long"))
+ else if matches.opt_present("binary") {
+ Err(Misfire::Useless("binary", false, "long"))
}
- else {
- Ok(View::Details(try!(Columns::new(matches)), matches.opt_present("header"), matches.opt_present("tree")))
+ else if matches.opt_present("bytes") {
+ Err(Misfire::Useless("bytes", false, "long"))
}
- }
- else if matches.opt_present("binary") {
- Err(Misfire::Useless("binary", false, "long"))
- }
- else if matches.opt_present("bytes") {
- Err(Misfire::Useless("bytes", false, "long"))
- }
- else if matches.opt_present("inode") {
- Err(Misfire::Useless("inode", false, "long"))
- }
- else if matches.opt_present("links") {
- Err(Misfire::Useless("links", false, "long"))
- }
- else if matches.opt_present("header") {
- Err(Misfire::Useless("header", false, "long"))
- }
- else if matches.opt_present("blocks") {
- Err(Misfire::Useless("blocks", false, "long"))
- }
- else if matches.opt_present("oneline") {
- if matches.opt_present("across") {
- Err(Misfire::Useless("across", true, "oneline"))
+ else if matches.opt_present("inode") {
+ Err(Misfire::Useless("inode", false, "long"))
}
- else {
- Ok(View::Lines)
+ else if matches.opt_present("links") {
+ Err(Misfire::Useless("links", false, "long"))
}
- }
- else {
- match dimensions() {
- None => Ok(View::Lines),
- Some((width, _)) => Ok(View::Grid(matches.opt_present("across"), width)),
+ else if matches.opt_present("header") {
+ Err(Misfire::Useless("header", false, "long"))
+ }
+ else if matches.opt_present("blocks") {
+ Err(Misfire::Useless("blocks", false, "long"))
+ }
+ else if matches.opt_present("oneline") {
+ if matches.opt_present("across") {
+ Err(Misfire::Useless("across", true, "oneline"))
+ }
+ else {
+ Ok(View::Lines)
+ }
+ }
+ else {
+ if let Some((width, _)) = dimensions() {
+ let grid = Grid {
+ across: matches.opt_present("across"),
+ console_width: width
+ };
+
+ Ok(View::Grid(grid))
+ }
+ else {
+ // If the terminal width couldn't be matched for some reason, such
+ // as the program's stdout being connected to a file, then
+ // fallback to the lines view.
+ Ok(View::Lines)
+ }
}
}
}
-/// Finds out which file size the user has asked for.
-fn file_size(matches: &getopts::Matches) -> Result<SizeFormat, Misfire> {
- let binary = matches.opt_present("binary");
- let bytes = matches.opt_present("bytes");
+#[derive(PartialEq, Debug, Copy)]
+pub enum SizeFormat {
+ DecimalBytes,
+ BinaryBytes,
+ JustBytes,
+}
- match (binary, bytes) {
- (true, true ) => Err(Misfire::Conflict("binary", "bytes")),
- (true, false) => Ok(SizeFormat::BinaryBytes),
- (false, true ) => Ok(SizeFormat::JustBytes),
- (false, false) => Ok(SizeFormat::DecimalBytes),
+impl SizeFormat {
+ pub fn deduce(matches: &getopts::Matches) -> Result<SizeFormat, Misfire> {
+ let binary = matches.opt_present("binary");
+ let bytes = matches.opt_present("bytes");
+
+ match (binary, bytes) {
+ (true, true ) => Err(Misfire::Conflict("binary", "bytes")),
+ (true, false) => Ok(SizeFormat::BinaryBytes),
+ (false, true ) => Ok(SizeFormat::JustBytes),
+ (false, false) => Ok(SizeFormat::DecimalBytes),
+ }
}
}
-fn dir_action(matches: &getopts::Matches) -> Result<DirAction, Misfire> {
- let recurse = matches.opt_present("recurse");
- let list = matches.opt_present("list-dirs");
- let tree = matches.opt_present("tree");
-
- match (recurse, list, tree) {
- (true, true, _ ) => Err(Misfire::Conflict("recurse", "list-dirs")),
- (true, false, false) => Ok(DirAction::Recurse),
- (true, false, true ) => Ok(DirAction::Tree),
- (false, true, _ ) => Ok(DirAction::AsFile),
- (false, false, _ ) => Ok(DirAction::List),
+/// What to do when encountering a directory?
+#[derive(PartialEq, Debug, Copy)]
+pub enum DirAction {
+ AsFile, List, Recurse, Tree
+}
+
+impl DirAction {
+ pub fn deduce(matches: &getopts::Matches) -> Result<DirAction, Misfire> {
+ let recurse = matches.opt_present("recurse");
+ let list = matches.opt_present("list-dirs");
+ let tree = matches.opt_present("tree");
+
+ match (recurse, list, tree) {
+ (true, true, _ ) => Err(Misfire::Conflict("recurse", "list-dirs")),
+ (true, false, false) => Ok(DirAction::Recurse),
+ (true, false, true ) => Ok(DirAction::Tree),
+ (false, true, _ ) => Ok(DirAction::AsFile),
+ (false, false, _ ) => Ok(DirAction::List),
+ }
}
}
@@ -274,9 +311,9 @@ pub struct Columns {
}
impl Columns {
- pub fn new(matches: &getopts::Matches) -> Result<Columns, Misfire> {
+ pub fn deduce(matches: &getopts::Matches) -> Result<Columns, Misfire> {
Ok(Columns {
- size_format: try!(file_size(matches)),
+ size_format: try!(SizeFormat::deduce(matches)),
inode: matches.opt_present("inode"),
links: matches.opt_present("links"),
blocks: matches.opt_present("blocks"),
@@ -327,7 +364,7 @@ mod test {
use super::Misfire;
use super::Misfire::*;
- fn is_helpful(misfire: Result<Options, Misfire>) -> bool {
+ fn is_helpful<T>(misfire: Result<T, Misfire>) -> bool {
match misfire {
Err(Help(_)) => true,
_ => false,
@@ -348,15 +385,13 @@ mod test {
#[test]
fn files() {
- let opts = Options::getopts(&[ "this file".to_string(), "that file".to_string() ]).unwrap();
- let args: Vec<String> = opts.path_strs;
+ let args = Options::getopts(&[ "this file".to_string(), "that file".to_string() ]).unwrap().1;
assert_eq!(args, vec![ "this file".to_string(), "that file".to_string() ])
}
#[test]
fn no_args() {
- let opts = Options::getopts(&[]).unwrap();
- let args: Vec<String> = opts.path_strs;
+ let args = Options::getopts(&[]).unwrap().1;
assert_eq!(args, vec![ ".".to_string() ])
}