exa/src/options/view.rs

619 lines
27 KiB
Rust
Raw Normal View History

2018-12-07 23:43:31 +00:00
use lazy_static::lazy_static;
use crate::fs::feature::xattr;
2018-12-07 23:43:31 +00:00
use crate::options::{flags, Misfire, Vars};
use crate::options::parser::MatchedFlags;
use crate::output::{View, Mode, grid, details, lines};
use crate::output::grid_details::{self, RowThreshold};
use crate::output::table::{TimeTypes, Environment, SizeFormat, Columns, Options as TableOptions};
use crate::output::time::TimeFormat;
2017-08-24 22:38:26 +00:00
impl View {
/// Determine which view to use and all of that views arguments.
pub fn deduce<V: Vars>(matches: &MatchedFlags, vars: &V) -> Result<Self, Misfire> {
2018-12-07 23:43:31 +00:00
use crate::options::style::Styles;
let mode = Mode::deduce(matches, vars)?;
let Styles { colours, style } = Styles::deduce(matches, vars, || *TERM_WIDTH)?;
Ok(Self { mode, colours, style })
}
}
impl Mode {
/// Determine the mode from the command-line arguments.
pub fn deduce<V: Vars>(matches: &MatchedFlags, vars: &V) -> Result<Self, Misfire> {
let long = || {
if matches.has(&flags::ACROSS)? && ! matches.has(&flags::GRID)? {
Err(Misfire::Useless(&flags::ACROSS, true, &flags::LONG))
}
else if matches.has(&flags::ONE_LINE)? {
Err(Misfire::Useless(&flags::ONE_LINE, true, &flags::LONG))
}
else {
Ok(details::Options {
table: Some(TableOptions::deduce(matches, vars)?),
header: matches.has(&flags::HEADER)?,
xattr: xattr::ENABLED && matches.has(&flags::EXTENDED)?,
2018-04-01 22:28:31 +00:00
icons: matches.has(&flags::ICONS)?,
})
}
};
let other_options_scan = || {
if let Some(width) = TerminalWidth::deduce(vars)?.width() {
if matches.has(&flags::ONE_LINE)? {
if matches.has(&flags::ACROSS)? {
Err(Misfire::Useless(&flags::ACROSS, true, &flags::ONE_LINE))
}
else {
2018-04-01 23:00:27 +00:00
let lines = lines::Options { icons: matches.has(&flags::ICONS)? };
Ok(Self::Lines(lines))
}
}
else if matches.has(&flags::TREE)? {
let details = details::Options {
table: None,
header: false,
xattr: xattr::ENABLED && matches.has(&flags::EXTENDED)?,
2018-04-01 22:28:31 +00:00
icons: matches.has(&flags::ICONS)?,
};
Ok(Self::Details(details))
}
else {
let grid = grid::Options {
across: matches.has(&flags::ACROSS)?,
console_width: width,
2018-03-26 20:01:53 +00:00
icons: matches.has(&flags::ICONS)?,
};
Ok(Self::Grid(grid))
}
}
2018-06-19 12:58:03 +00:00
// If the terminal width couldnt be matched for some reason, such
// as the programs stdout being connected to a file, then
// fallback to the lines or details view.
2018-06-19 12:58:03 +00:00
else if matches.has(&flags::TREE)? {
let details = details::Options {
table: None,
header: false,
xattr: xattr::ENABLED && matches.has(&flags::EXTENDED)?,
icons: matches.has(&flags::ICONS)?,
2018-06-19 12:58:03 +00:00
};
Ok(Self::Details(details))
2018-06-19 12:58:03 +00:00
}
else if matches.has(&flags::LONG)? {
let details = long()?;
Ok(Self::Details(details))
} else {
let lines = lines::Options { icons: matches.has(&flags::ICONS)?, };
Ok(Self::Lines(lines))
}
};
if matches.has(&flags::LONG)? {
let details = long()?;
if matches.has(&flags::GRID)? {
2017-08-12 21:51:45 +00:00
let other_options_mode = other_options_scan()?;
if let Self::Grid(grid) = other_options_mode {
let row_threshold = RowThreshold::deduce(vars)?;
let opts = grid_details::Options { grid, details, row_threshold };
return Ok(Self::GridDetails(opts));
2017-08-12 21:51:45 +00:00
}
else {
return Ok(other_options_mode);
}
}
else {
return Ok(Self::Details(details));
}
}
// If --long hasnt been passed, then check if we need to warn the
// user about flags that wont have any effect.
if matches.is_strict() {
for option in &[ &flags::BINARY, &flags::BYTES, &flags::INODE, &flags::LINKS,
&flags::HEADER, &flags::BLOCKS, &flags::TIME, &flags::GROUP ] {
if matches.has(option)? {
return Err(Misfire::Useless(*option, false, &flags::LONG));
}
}
if cfg!(feature = "git") && matches.has(&flags::GIT)? {
return Err(Misfire::Useless(&flags::GIT, false, &flags::LONG));
}
else if matches.has(&flags::LEVEL)? && ! matches.has(&flags::RECURSE)? && ! matches.has(&flags::TREE)? {
// TODO: Im not sure if the code even gets this far.
// There is an identical check in dir_action
return Err(Misfire::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE));
}
}
other_options_scan()
}
}
/// The width of the terminal requested by the user.
#[derive(PartialEq, Debug, Copy, Clone)]
enum TerminalWidth {
/// The user requested this specific number of columns.
Set(usize),
/// The terminal was found to have this number of columns.
Terminal(usize),
/// The user didnt request any particular terminal width.
Unset,
}
impl TerminalWidth {
/// Determine a requested terminal width from the command-line arguments.
///
/// Returns an error if a requested width doesnt parse to an integer.
fn deduce<V: Vars>(vars: &V) -> Result<Self, Misfire> {
2018-12-07 23:43:31 +00:00
use crate::options::vars;
if let Some(columns) = vars.get(vars::COLUMNS).and_then(|s| s.into_string().ok()) {
match columns.parse() {
Ok(width) => Ok(Self::Set(width)),
Err(e) => Err(Misfire::FailedParse(e)),
}
}
else if let Some(width) = *TERM_WIDTH {
Ok(Self::Terminal(width))
}
else {
Ok(Self::Unset)
}
}
fn width(self) -> Option<usize> {
match self {
Self::Set(width) |
Self::Terminal(width) => Some(width),
Self::Unset => None,
}
}
}
impl RowThreshold {
/// Determine whether to use a row threshold based on the given
/// environment variables.
fn deduce<V: Vars>(vars: &V) -> Result<Self, Misfire> {
2018-12-07 23:43:31 +00:00
use crate::options::vars;
if let Some(columns) = vars.get(vars::EXA_GRID_ROWS).and_then(|s| s.into_string().ok()) {
match columns.parse() {
Ok(rows) => Ok(Self::MinimumRows(rows)),
Err(e) => Err(Misfire::FailedParse(e)),
}
}
else {
Ok(Self::AlwaysGrid)
}
}
}
impl TableOptions {
fn deduce<V: Vars>(matches: &MatchedFlags, vars: &V) -> Result<Self, Misfire> {
let env = Environment::load_all();
let time_format = TimeFormat::deduce(matches, vars)?;
let size_format = SizeFormat::deduce(matches)?;
let columns = Columns::deduce(matches)?;
Ok(Self { env, time_format, size_format, columns })
}
}
impl Columns {
fn deduce(matches: &MatchedFlags) -> Result<Self, Misfire> {
let time_types = TimeTypes::deduce(matches)?;
let git = cfg!(feature = "git") && matches.has(&flags::GIT)?;
let blocks = matches.has(&flags::BLOCKS)?;
let group = matches.has(&flags::GROUP)?;
let inode = matches.has(&flags::INODE)?;
let links = matches.has(&flags::LINKS)?;
let octal = matches.has(&flags::OCTAL)?;
let permissions = ! matches.has(&flags::NO_PERMISSIONS)?;
let filesize = ! matches.has(&flags::NO_FILESIZE)?;
let user = ! matches.has(&flags::NO_USER)?;
Ok(Self { time_types, git, octal, blocks, group, inode, links, permissions, filesize, user })
}
}
impl SizeFormat {
/// Determine which file size to use in the file size column based on
/// the users options.
///
/// The default mode is to use the decimal prefixes, as they are the
/// most commonly-understood, and dont involve trying to parse large
/// strings of digits in your head. Changing the format to anything else
/// involves the `--binary` or `--bytes` flags, and these conflict with
/// each other.
fn deduce(matches: &MatchedFlags) -> Result<Self, Misfire> {
let flag = matches.has_where(|f| f.matches(&flags::BINARY) || f.matches(&flags::BYTES))?;
Ok(match flag {
Some(f) if f.matches(&flags::BINARY) => Self::BinaryBytes,
Some(f) if f.matches(&flags::BYTES) => Self::JustBytes,
_ => Self::DecimalBytes,
})
}
}
2017-07-05 22:27:48 +00:00
impl TimeFormat {
/// Determine how time should be formatted in timestamp columns.
fn deduce<V: Vars>(matches: &MatchedFlags, vars: &V) -> Result<Self, Misfire> {
2018-12-07 23:43:31 +00:00
pub use crate::output::time::{DefaultFormat, ISOFormat};
let word = match matches.get(&flags::TIME_STYLE)? {
Some(w) => {
w.to_os_string()
}
None => {
2018-12-07 23:43:31 +00:00
use crate::options::vars;
match vars.get(vars::TIME_STYLE) {
Some(ref t) if ! t.is_empty() => t.clone(),
_ => return Ok(Self::DefaultFormat(DefaultFormat::load()))
}
},
};
if &word == "default" {
Ok(Self::DefaultFormat(DefaultFormat::load()))
}
else if &word == "iso" {
Ok(Self::ISOFormat(ISOFormat::load()))
}
else if &word == "long-iso" {
Ok(Self::LongISO)
}
else if &word == "full-iso" {
Ok(Self::FullISO)
}
else {
2020-04-19 04:33:42 +00:00
Err(Misfire::BadArgument(&flags::TIME_STYLE, word))
}
2017-07-05 22:27:48 +00:00
}
}
impl TimeTypes {
/// Determine which of a files time fields should be displayed for it
/// based on the users options.
///
/// There are two separate ways to pick which fields to show: with a
/// flag (such as `--modified`) or with a parameter (such as
/// `--time=modified`). An error is signaled if both ways are used.
///
/// Its valid to show more than one column by passing in more than one
/// option, but passing *no* options means that the user just wants to
/// see the default set.
fn deduce(matches: &MatchedFlags) -> Result<Self, Misfire> {
let possible_word = matches.get(&flags::TIME)?;
let modified = matches.has(&flags::MODIFIED)?;
let changed = matches.has(&flags::CHANGED)?;
let accessed = matches.has(&flags::ACCESSED)?;
let created = matches.has(&flags::CREATED)?;
let no_time = matches.has(&flags::NO_TIME)?;
let time_types = if no_time {
Self { modified: false, changed: false, accessed: false, created: false }
} else if let Some(word) = possible_word {
if modified {
return Err(Misfire::Useless(&flags::MODIFIED, true, &flags::TIME));
}
else if changed {
return Err(Misfire::Useless(&flags::CHANGED, true, &flags::TIME));
}
else if accessed {
return Err(Misfire::Useless(&flags::ACCESSED, true, &flags::TIME));
}
else if created {
return Err(Misfire::Useless(&flags::CREATED, true, &flags::TIME));
}
2017-08-05 10:55:41 +00:00
else if word == "mod" || word == "modified" {
Self { modified: true, changed: false, accessed: false, created: false }
}
else if word == "ch" || word == "changed" {
Self { modified: false, changed: true, accessed: false, created: false }
}
else if word == "acc" || word == "accessed" {
Self { modified: false, changed: false, accessed: true, created: false }
}
else if word == "cr" || word == "created" {
Self { modified: false, changed: false, accessed: false, created: true }
}
else {
return Err(Misfire::BadArgument(&flags::TIME, word.into()));
}
}
else if modified || changed || accessed || created {
Self { modified, changed, accessed, created }
}
else {
Self::default()
};
Ok(time_types)
}
}
// Gets, then caches, the width of the terminal that exa is running in.
// This gets used multiple times above, with no real guarantee of order,
// so its easier to just cache it the first time it runs.
lazy_static! {
static ref TERM_WIDTH: Option<usize> = {
// All of stdin, stdout, and stderr could not be connected to a
// terminal, but were only interested in stdout because its
// where the output goes.
use term_size::dimensions_stdout;
dimensions_stdout().map(|t| t.0)
};
}
2017-07-26 22:05:45 +00:00
#[cfg(test)]
mod test {
use super::*;
use std::ffi::OsString;
2018-12-07 23:43:31 +00:00
use crate::options::flags;
use crate::options::parser::{Flag, Arg};
2017-08-09 16:14:16 +00:00
2018-12-07 23:43:31 +00:00
use crate::options::test::parse_for_test;
use crate::options::test::Strictnesses::*;
2017-08-09 16:14:16 +00:00
static TEST_ARGS: &[&Arg] = &[ &flags::BINARY, &flags::BYTES, &flags::TIME_STYLE,
2018-12-17 10:05:25 +00:00
&flags::TIME, &flags::MODIFIED, &flags::CHANGED,
&flags::CREATED, &flags::ACCESSED, &flags::ICONS,
&flags::HEADER, &flags::GROUP, &flags::INODE, &flags::GIT,
&flags::LINKS, &flags::BLOCKS, &flags::LONG, &flags::LEVEL,
&flags::GRID, &flags::ACROSS, &flags::ONE_LINE ];
2017-08-09 16:14:16 +00:00
2017-07-26 22:05:45 +00:00
macro_rules! test {
($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
/// Macro that writes a test.
/// If testing both strictnesses, theyll both be done in the same function.
2017-07-26 22:05:45 +00:00
#[test]
fn $name() {
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
assert_eq!(result, $result);
}
2017-07-26 22:05:45 +00:00
}
};
2017-08-09 16:14:16 +00:00
($name:ident: $type:ident <- $inputs:expr; $stricts:expr => err $result:expr) => {
/// Special macro for testing Err results.
/// This is needed because sometimes the Ok type doesnt implement PartialEq.
#[test]
fn $name() {
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
assert_eq!(result.unwrap_err(), $result);
}
}
};
2017-08-09 16:14:16 +00:00
($name:ident: $type:ident <- $inputs:expr; $stricts:expr => like $pat:pat) => {
/// More general macro for testing against a pattern.
/// Instead of using PartialEq, this just tests if it matches a pat.
2017-08-09 16:14:16 +00:00
#[test]
fn $name() {
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
println!("Testing {:?}", result);
match result {
$pat => assert!(true),
_ => assert!(false),
}
}
}
};
($name:ident: $type:ident <- $inputs:expr, $vars:expr; $stricts:expr => err $result:expr) => {
/// Like above, but with $vars.
#[test]
fn $name() {
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$vars)) {
assert_eq!(result.unwrap_err(), $result);
}
}
};
($name:ident: $type:ident <- $inputs:expr, $vars:expr; $stricts:expr => like $pat:pat) => {
/// Like further above, but with $vars.
#[test]
fn $name() {
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$vars)) {
println!("Testing {:?}", result);
match result {
$pat => assert!(true),
_ => assert!(false),
}
}
}
};
2017-07-26 22:05:45 +00:00
}
2017-07-26 22:05:45 +00:00
mod size_formats {
use super::*;
2017-08-09 16:14:16 +00:00
// Default behaviour
test!(empty: SizeFormat <- []; Both => Ok(SizeFormat::DecimalBytes));
2017-08-09 16:14:16 +00:00
// Individual flags
test!(binary: SizeFormat <- ["--binary"]; Both => Ok(SizeFormat::BinaryBytes));
test!(bytes: SizeFormat <- ["--bytes"]; Both => Ok(SizeFormat::JustBytes));
2017-08-09 16:14:16 +00:00
// Overriding
test!(both_1: SizeFormat <- ["--binary", "--binary"]; Last => Ok(SizeFormat::BinaryBytes));
test!(both_2: SizeFormat <- ["--bytes", "--binary"]; Last => Ok(SizeFormat::BinaryBytes));
test!(both_3: SizeFormat <- ["--binary", "--bytes"]; Last => Ok(SizeFormat::JustBytes));
test!(both_4: SizeFormat <- ["--bytes", "--bytes"]; Last => Ok(SizeFormat::JustBytes));
test!(both_5: SizeFormat <- ["--binary", "--binary"]; Complain => err Misfire::Duplicate(Flag::Long("binary"), Flag::Long("binary")));
test!(both_6: SizeFormat <- ["--bytes", "--binary"]; Complain => err Misfire::Duplicate(Flag::Long("bytes"), Flag::Long("binary")));
test!(both_7: SizeFormat <- ["--binary", "--bytes"]; Complain => err Misfire::Duplicate(Flag::Long("binary"), Flag::Long("bytes")));
test!(both_8: SizeFormat <- ["--bytes", "--bytes"]; Complain => err Misfire::Duplicate(Flag::Long("bytes"), Flag::Long("bytes")));
2017-07-26 22:05:45 +00:00
}
2017-08-09 16:14:16 +00:00
mod time_formats {
use super::*;
// These tests use pattern matching because TimeFormat doesnt
// implement PartialEq.
// Default behaviour
test!(empty: TimeFormat <- [], None; Both => like Ok(TimeFormat::DefaultFormat(_)));
2017-08-09 16:14:16 +00:00
// Individual settings
test!(default: TimeFormat <- ["--time-style=default"], None; Both => like Ok(TimeFormat::DefaultFormat(_)));
test!(iso: TimeFormat <- ["--time-style", "iso"], None; Both => like Ok(TimeFormat::ISOFormat(_)));
test!(long_iso: TimeFormat <- ["--time-style=long-iso"], None; Both => like Ok(TimeFormat::LongISO));
test!(full_iso: TimeFormat <- ["--time-style", "full-iso"], None; Both => like Ok(TimeFormat::FullISO));
2017-08-09 16:14:16 +00:00
// Overriding
test!(actually: TimeFormat <- ["--time-style=default", "--time-style", "iso"], None; Last => like Ok(TimeFormat::ISOFormat(_)));
test!(actual_2: TimeFormat <- ["--time-style=default", "--time-style", "iso"], None; Complain => err Misfire::Duplicate(Flag::Long("time-style"), Flag::Long("time-style")));
2017-08-09 16:14:16 +00:00
test!(nevermind: TimeFormat <- ["--time-style", "long-iso", "--time-style=full-iso"], None; Last => like Ok(TimeFormat::FullISO));
test!(nevermore: TimeFormat <- ["--time-style", "long-iso", "--time-style=full-iso"], None; Complain => err Misfire::Duplicate(Flag::Long("time-style"), Flag::Long("time-style")));
2017-08-09 16:14:16 +00:00
// Errors
test!(daily: TimeFormat <- ["--time-style=24-hour"], None; Both => err Misfire::BadArgument(&flags::TIME_STYLE, OsString::from("24-hour")));
// `TIME_STYLE` environment variable is defined.
// If the time-style argument is not given, `TIME_STYLE` is used.
test!(use_env: TimeFormat <- [], Some("long-iso".into()); Both => like Ok(TimeFormat::LongISO));
// If the time-style argument is given, `TIME_STYLE` is overriding.
test!(override_env: TimeFormat <- ["--time-style=full-iso"], Some("long-iso".into()); Both => like Ok(TimeFormat::FullISO));
2017-08-09 16:14:16 +00:00
}
mod time_types {
use super::*;
// Default behaviour
test!(empty: TimeTypes <- []; Both => Ok(TimeTypes::default()));
// Modified
2018-12-17 10:05:25 +00:00
test!(modified: TimeTypes <- ["--modified"]; Both => Ok(TimeTypes { modified: true, changed: false, accessed: false, created: false }));
test!(m: TimeTypes <- ["-m"]; Both => Ok(TimeTypes { modified: true, changed: false, accessed: false, created: false }));
test!(time_mod: TimeTypes <- ["--time=modified"]; Both => Ok(TimeTypes { modified: true, changed: false, accessed: false, created: false }));
2019-07-15 02:37:05 +00:00
test!(t_m: TimeTypes <- ["-tmod"]; Both => Ok(TimeTypes { modified: true, changed: false, accessed: false, created: false }));
2018-12-17 10:05:25 +00:00
// Changed
#[cfg(target_family = "unix")]
test!(changed: TimeTypes <- ["--changed"]; Both => Ok(TimeTypes { modified: false, changed: true, accessed: false, created: false }));
#[cfg(target_family = "unix")]
test!(time_ch: TimeTypes <- ["--time=changed"]; Both => Ok(TimeTypes { modified: false, changed: true, accessed: false, created: false }));
#[cfg(target_family = "unix")]
2019-07-15 02:37:05 +00:00
test!(t_ch: TimeTypes <- ["-t", "ch"]; Both => Ok(TimeTypes { modified: false, changed: true, accessed: false, created: false }));
// Accessed
2018-12-17 10:05:25 +00:00
test!(acc: TimeTypes <- ["--accessed"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: true, created: false }));
test!(a: TimeTypes <- ["-u"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: true, created: false }));
test!(time_acc: TimeTypes <- ["--time", "accessed"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: true, created: false }));
test!(time_a: TimeTypes <- ["-t", "acc"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: true, created: false }));
// Created
2018-12-17 10:05:25 +00:00
test!(cr: TimeTypes <- ["--created"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true }));
test!(c: TimeTypes <- ["-U"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true }));
test!(time_cr: TimeTypes <- ["--time=created"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true }));
2019-07-15 02:37:05 +00:00
test!(t_cr: TimeTypes <- ["-tcr"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true }));
// Multiples
2018-12-17 10:05:25 +00:00
test!(time_uu: TimeTypes <- ["-u", "--modified"]; Both => Ok(TimeTypes { modified: true, changed: false, accessed: true, created: false }));
// Errors
test!(time_tea: TimeTypes <- ["--time=tea"]; Both => err Misfire::BadArgument(&flags::TIME, OsString::from("tea")));
2019-07-15 02:37:05 +00:00
test!(t_ea: TimeTypes <- ["-tea"]; Both => err Misfire::BadArgument(&flags::TIME, OsString::from("ea")));
// Overriding
2018-12-17 10:05:25 +00:00
test!(overridden: TimeTypes <- ["-tcr", "-tmod"]; Last => Ok(TimeTypes { modified: true, changed: false, accessed: false, created: false }));
test!(overridden_2: TimeTypes <- ["-tcr", "-tmod"]; Complain => err Misfire::Duplicate(Flag::Short(b't'), Flag::Short(b't')));
}
mod views {
use super::*;
2018-12-07 23:43:31 +00:00
use crate::output::grid::Options as GridOptions;
use crate::output::lines::Options as LineOptions;
// Default
test!(empty: Mode <- [], None; Both => like Ok(Mode::Grid(_)));
// Grid views
2018-03-26 20:01:53 +00:00
test!(original_g: Mode <- ["-G"], None; Both => like Ok(Mode::Grid(GridOptions { across: false, console_width: _, icons: _ })));
test!(grid: Mode <- ["--grid"], None; Both => like Ok(Mode::Grid(GridOptions { across: false, console_width: _, icons: _ })));
test!(across: Mode <- ["--across"], None; Both => like Ok(Mode::Grid(GridOptions { across: true, console_width: _, icons: _ })));
test!(gracross: Mode <- ["-xG"], None; Both => like Ok(Mode::Grid(GridOptions { across: true, console_width: _, icons: _ })));
test!(icons: Mode <- ["--icons"], None; Both => like Ok(Mode::Grid(GridOptions { across: _, console_width: _, icons: true})));
// Lines views
2018-04-01 23:00:27 +00:00
test!(lines: Mode <- ["--oneline"], None; Both => like Ok(Mode::Lines(LineOptions{ icons: _ })));
test!(prima: Mode <- ["-1"], None; Both => like Ok(Mode::Lines(LineOptions{ icons: _ })));
test!(line_icon: Mode <- ["-1", "--icons"], None; Both => like Ok(Mode::Lines(LineOptions { icons: true })));
// Details views
test!(long: Mode <- ["--long"], None; Both => like Ok(Mode::Details(_)));
test!(ell: Mode <- ["-l"], None; Both => like Ok(Mode::Details(_)));
// Grid-details views
test!(lid: Mode <- ["--long", "--grid"], None; Both => like Ok(Mode::GridDetails(_)));
test!(leg: Mode <- ["-lG"], None; Both => like Ok(Mode::GridDetails(_)));
// Options that do nothing without --long
test!(just_header: Mode <- ["--header"], None; Last => like Ok(Mode::Grid(_)));
test!(just_group: Mode <- ["--group"], None; Last => like Ok(Mode::Grid(_)));
test!(just_inode: Mode <- ["--inode"], None; Last => like Ok(Mode::Grid(_)));
test!(just_links: Mode <- ["--links"], None; Last => like Ok(Mode::Grid(_)));
test!(just_blocks: Mode <- ["--blocks"], None; Last => like Ok(Mode::Grid(_)));
test!(just_binary: Mode <- ["--binary"], None; Last => like Ok(Mode::Grid(_)));
test!(just_bytes: Mode <- ["--bytes"], None; Last => like Ok(Mode::Grid(_)));
#[cfg(feature = "git")]
test!(just_git: Mode <- ["--git"], None; Last => like Ok(Mode::Grid(_)));
test!(just_header_2: Mode <- ["--header"], None; Complain => err Misfire::Useless(&flags::HEADER, false, &flags::LONG));
test!(just_group_2: Mode <- ["--group"], None; Complain => err Misfire::Useless(&flags::GROUP, false, &flags::LONG));
test!(just_inode_2: Mode <- ["--inode"], None; Complain => err Misfire::Useless(&flags::INODE, false, &flags::LONG));
test!(just_links_2: Mode <- ["--links"], None; Complain => err Misfire::Useless(&flags::LINKS, false, &flags::LONG));
test!(just_blocks_2: Mode <- ["--blocks"], None; Complain => err Misfire::Useless(&flags::BLOCKS, false, &flags::LONG));
test!(just_binary_2: Mode <- ["--binary"], None; Complain => err Misfire::Useless(&flags::BINARY, false, &flags::LONG));
test!(just_bytes_2: Mode <- ["--bytes"], None; Complain => err Misfire::Useless(&flags::BYTES, false, &flags::LONG));
#[cfg(feature = "git")]
test!(just_git_2: Mode <- ["--git"], None; Complain => err Misfire::Useless(&flags::GIT, false, &flags::LONG));
}
2017-07-26 22:05:45 +00:00
}