2017-07-22 17:06:05 +00:00
|
|
|
|
//! Parsing command-line strings into exa options.
|
|
|
|
|
//!
|
2017-07-24 07:34:50 +00:00
|
|
|
|
//! This module imports exa’s configuration types, such as `View` (the details
|
|
|
|
|
//! of displaying multiple files) and `DirAction` (what to do when encountering
|
|
|
|
|
//! a directory), and implements `deduce` methods on them so they can be
|
|
|
|
|
//! configured using command-line options.
|
|
|
|
|
//!
|
2017-07-22 17:06:05 +00:00
|
|
|
|
//!
|
|
|
|
|
//! ## Useless and overridden options
|
|
|
|
|
//!
|
|
|
|
|
//! Let’s say exa was invoked with just one argument: `exa --inode`. The
|
|
|
|
|
//! `--inode` option is used in the details view, where it adds the inode
|
|
|
|
|
//! column to the output. But because the details view is *only* activated with
|
|
|
|
|
//! the `--long` argument, adding `--inode` without it would not have any
|
|
|
|
|
//! effect.
|
|
|
|
|
//!
|
|
|
|
|
//! For a long time, exa’s philosophy was that the user should be warned
|
|
|
|
|
//! whenever they could be mistaken like this. If you tell exa to display the
|
|
|
|
|
//! inode, and it *doesn’t* display the inode, isn’t that more annoying than
|
|
|
|
|
//! having it throw an error back at you?
|
|
|
|
|
//!
|
|
|
|
|
//! However, this doesn’t take into account *configuration*. Say a user wants
|
|
|
|
|
//! to configure exa so that it lists inodes in the details view, but otherwise
|
|
|
|
|
//! functions normally. A common way to do this for command-line programs is to
|
|
|
|
|
//! define a shell alias that specifies the details they want to use every
|
|
|
|
|
//! time. For the inode column, the alias would be:
|
|
|
|
|
//!
|
|
|
|
|
//! `alias exa="exa --inode"`
|
|
|
|
|
//!
|
|
|
|
|
//! Using this alias means that although the inode column will be shown in the
|
|
|
|
|
//! details view, you’re now *only* allowed to use the details view, as any
|
|
|
|
|
//! other view type will result in an error. Oops!
|
|
|
|
|
//!
|
|
|
|
|
//! Another example is when an option is specified twice, such as `exa
|
|
|
|
|
//! --sort=Name --sort=size`. Did the user change their mind about sorting, and
|
|
|
|
|
//! accidentally specify the option twice?
|
|
|
|
|
//!
|
|
|
|
|
//! Again, exa rejected this case, throwing an error back to the user instead
|
|
|
|
|
//! of trying to guess how they want their output sorted. And again, this
|
|
|
|
|
//! doesn’t take into account aliases being used to set defaults. A user who
|
|
|
|
|
//! wants their files to be sorted case-insensitively may configure their shell
|
|
|
|
|
//! with the following:
|
|
|
|
|
//!
|
|
|
|
|
//! `alias exa="exa --sort=Name"`
|
|
|
|
|
//!
|
|
|
|
|
//! Just like the earlier example, the user now can’t use any other sort order,
|
|
|
|
|
//! because exa refuses to guess which one they meant. It’s *more* annoying to
|
|
|
|
|
//! have to go back and edit the command than if there were no error.
|
|
|
|
|
//!
|
|
|
|
|
//! Fortunately, there’s a heuristic for telling which options came from an
|
|
|
|
|
//! alias and which came from the actual command-line: aliased options are
|
|
|
|
|
//! nearer the beginning of the options array, and command-line options are
|
|
|
|
|
//! nearer the end. This means that after the options have been parsed, exa
|
|
|
|
|
//! needs to traverse them *backwards* to find the last-most-specified one.
|
|
|
|
|
//!
|
|
|
|
|
//! For example, invoking exa with `exa --sort=size` when that alias is present
|
|
|
|
|
//! would result in a full command-line of:
|
|
|
|
|
//!
|
|
|
|
|
//! `exa --sort=Name --sort=size`
|
|
|
|
|
//!
|
|
|
|
|
//! `--sort=size` should override `--sort=Name` because it’s closer to the end
|
|
|
|
|
//! of the arguments array. In fact, because there’s no way to tell where the
|
2020-10-10 18:49:46 +00:00
|
|
|
|
//! arguments came from — it’s just a heuristic — this will still work even
|
2017-07-22 17:06:05 +00:00
|
|
|
|
//! if no aliases are being used!
|
|
|
|
|
//!
|
|
|
|
|
//! Finally, this isn’t just useful when options could override each other.
|
2017-09-03 18:50:40 +00:00
|
|
|
|
//! Creating an alias `exal="exa --long --inode --header"` then invoking `exal
|
2017-07-22 17:06:05 +00:00
|
|
|
|
//! --grid --long` shouldn’t complain about `--long` being given twice when
|
|
|
|
|
//! it’s clear what the user wants.
|
|
|
|
|
|
|
|
|
|
|
2020-10-12 23:29:49 +00:00
|
|
|
|
use std::ffi::OsStr;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
2018-12-07 23:43:31 +00:00
|
|
|
|
use crate::fs::dir_action::DirAction;
|
2020-10-10 18:49:46 +00:00
|
|
|
|
use crate::fs::filter::{FileFilter, GitIgnore};
|
2018-12-07 23:43:31 +00:00
|
|
|
|
use crate::output::{View, Mode, details, grid_details};
|
Massive theming and view options refactor
This commit significantly refactors the way that options are parsed. It introduces the Theme type which contains both styling and extension configuration, converts the option-parsing process into a being a pure function, and removes some rather gnarly old code.
The main purpose of the refactoring is to fix GH-318, "Tests fail when not connected to a terminal". Even though exa was compiling fine on my machine and on Travis, it was failing for automated build scripts. This was because of what the option-parsing code was trying to accomplish: it wasn't just providing a struct of the user's settings, it was also checking the terminal, providing a View directly.
This has been changed so that the options module now _only_ looks at the command-line arguments and environment variables. Instead of returning a View, it returns the user's _preference_, and it's then up to the 'main' module to examine the terminal width and figure out if the view is doable, downgrading it if necessary.
The code that used to determine the view was horrible and I'm pleased it can be cut out. Also, the terminal width used to be in a lazy_static because it was queried multiple times, and now it's not in one because it's only queried once, which is a good sign for things going in the right direction.
There are also some naming and organisational changes around themes. The blanket terms "Colours" and "Styles" have been yeeted in favour of "Theme", which handles both extensions and UI colours. The FileStyle struct has been replaced with file_name::Options, making it similar to the views in how it has an Options struct and a Render struct.
Finally, eight unit tests have been removed because they turned out to be redundant (testing --colour and --color) after examining the tangled code, and the default theme has been put in its own file in preparation for more themes.
2020-10-22 21:34:00 +00:00
|
|
|
|
use crate::theme::Options as ThemeOptions;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
mod dir_action;
|
Massive theming and view options refactor
This commit significantly refactors the way that options are parsed. It introduces the Theme type which contains both styling and extension configuration, converts the option-parsing process into a being a pure function, and removes some rather gnarly old code.
The main purpose of the refactoring is to fix GH-318, "Tests fail when not connected to a terminal". Even though exa was compiling fine on my machine and on Travis, it was failing for automated build scripts. This was because of what the option-parsing code was trying to accomplish: it wasn't just providing a struct of the user's settings, it was also checking the terminal, providing a View directly.
This has been changed so that the options module now _only_ looks at the command-line arguments and environment variables. Instead of returning a View, it returns the user's _preference_, and it's then up to the 'main' module to examine the terminal width and figure out if the view is doable, downgrading it if necessary.
The code that used to determine the view was horrible and I'm pleased it can be cut out. Also, the terminal width used to be in a lazy_static because it was queried multiple times, and now it's not in one because it's only queried once, which is a good sign for things going in the right direction.
There are also some naming and organisational changes around themes. The blanket terms "Colours" and "Styles" have been yeeted in favour of "Theme", which handles both extensions and UI colours. The FileStyle struct has been replaced with file_name::Options, making it similar to the views in how it has an Options struct and a Render struct.
Finally, eight unit tests have been removed because they turned out to be redundant (testing --colour and --color) after examining the tangled code, and the default theme has been put in its own file in preparation for more themes.
2020-10-22 21:34:00 +00:00
|
|
|
|
mod file_name;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
mod filter;
|
2020-10-10 18:49:46 +00:00
|
|
|
|
mod flags;
|
Massive theming and view options refactor
This commit significantly refactors the way that options are parsed. It introduces the Theme type which contains both styling and extension configuration, converts the option-parsing process into a being a pure function, and removes some rather gnarly old code.
The main purpose of the refactoring is to fix GH-318, "Tests fail when not connected to a terminal". Even though exa was compiling fine on my machine and on Travis, it was failing for automated build scripts. This was because of what the option-parsing code was trying to accomplish: it wasn't just providing a struct of the user's settings, it was also checking the terminal, providing a View directly.
This has been changed so that the options module now _only_ looks at the command-line arguments and environment variables. Instead of returning a View, it returns the user's _preference_, and it's then up to the 'main' module to examine the terminal width and figure out if the view is doable, downgrading it if necessary.
The code that used to determine the view was horrible and I'm pleased it can be cut out. Also, the terminal width used to be in a lazy_static because it was queried multiple times, and now it's not in one because it's only queried once, which is a good sign for things going in the right direction.
There are also some naming and organisational changes around themes. The blanket terms "Colours" and "Styles" have been yeeted in favour of "Theme", which handles both extensions and UI colours. The FileStyle struct has been replaced with file_name::Options, making it similar to the views in how it has an Options struct and a Render struct.
Finally, eight unit tests have been removed because they turned out to be redundant (testing --colour and --color) after examining the tangled code, and the default theme has been put in its own file in preparation for more themes.
2020-10-22 21:34:00 +00:00
|
|
|
|
mod theme;
|
2017-07-24 07:34:50 +00:00
|
|
|
|
mod view;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
mod error;
|
2021-04-12 20:42:45 +00:00
|
|
|
|
pub use self::error::{OptionsError, NumberSource};
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
|
2016-04-17 19:38:37 +00:00
|
|
|
|
mod help;
|
2017-06-23 21:50:29 +00:00
|
|
|
|
use self::help::HelpString;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
mod parser;
|
|
|
|
|
use self::parser::MatchedFlags;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
2017-08-26 20:19:06 +00:00
|
|
|
|
pub mod vars;
|
2017-08-26 19:48:51 +00:00
|
|
|
|
pub use self::vars::Vars;
|
|
|
|
|
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
mod version;
|
|
|
|
|
use self::version::VersionString;
|
2017-07-12 11:03:07 +00:00
|
|
|
|
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
/// These **options** represent a parsed, error-checked versions of the
|
|
|
|
|
/// user’s command-line options.
|
2017-07-05 19:16:04 +00:00
|
|
|
|
#[derive(Debug)]
|
2016-04-17 19:38:37 +00:00
|
|
|
|
pub struct Options {
|
|
|
|
|
|
|
|
|
|
/// The action to perform when encountering a directory rather than a
|
|
|
|
|
/// regular file.
|
|
|
|
|
pub dir_action: DirAction,
|
|
|
|
|
|
|
|
|
|
/// How to sort and filter files before outputting them.
|
|
|
|
|
pub filter: FileFilter,
|
|
|
|
|
|
Massive theming and view options refactor
This commit significantly refactors the way that options are parsed. It introduces the Theme type which contains both styling and extension configuration, converts the option-parsing process into a being a pure function, and removes some rather gnarly old code.
The main purpose of the refactoring is to fix GH-318, "Tests fail when not connected to a terminal". Even though exa was compiling fine on my machine and on Travis, it was failing for automated build scripts. This was because of what the option-parsing code was trying to accomplish: it wasn't just providing a struct of the user's settings, it was also checking the terminal, providing a View directly.
This has been changed so that the options module now _only_ looks at the command-line arguments and environment variables. Instead of returning a View, it returns the user's _preference_, and it's then up to the 'main' module to examine the terminal width and figure out if the view is doable, downgrading it if necessary.
The code that used to determine the view was horrible and I'm pleased it can be cut out. Also, the terminal width used to be in a lazy_static because it was queried multiple times, and now it's not in one because it's only queried once, which is a good sign for things going in the right direction.
There are also some naming and organisational changes around themes. The blanket terms "Colours" and "Styles" have been yeeted in favour of "Theme", which handles both extensions and UI colours. The FileStyle struct has been replaced with file_name::Options, making it similar to the views in how it has an Options struct and a Render struct.
Finally, eight unit tests have been removed because they turned out to be redundant (testing --colour and --color) after examining the tangled code, and the default theme has been put in its own file in preparation for more themes.
2020-10-22 21:34:00 +00:00
|
|
|
|
/// The user’s preference of view to use (lines, grid, details, or
|
|
|
|
|
/// grid-details) along with the options on how to render file names.
|
|
|
|
|
/// If the view requires the terminal to have a width, and there is no
|
|
|
|
|
/// width, then the view will be downgraded.
|
2016-04-17 19:38:37 +00:00
|
|
|
|
pub view: View,
|
Massive theming and view options refactor
This commit significantly refactors the way that options are parsed. It introduces the Theme type which contains both styling and extension configuration, converts the option-parsing process into a being a pure function, and removes some rather gnarly old code.
The main purpose of the refactoring is to fix GH-318, "Tests fail when not connected to a terminal". Even though exa was compiling fine on my machine and on Travis, it was failing for automated build scripts. This was because of what the option-parsing code was trying to accomplish: it wasn't just providing a struct of the user's settings, it was also checking the terminal, providing a View directly.
This has been changed so that the options module now _only_ looks at the command-line arguments and environment variables. Instead of returning a View, it returns the user's _preference_, and it's then up to the 'main' module to examine the terminal width and figure out if the view is doable, downgrading it if necessary.
The code that used to determine the view was horrible and I'm pleased it can be cut out. Also, the terminal width used to be in a lazy_static because it was queried multiple times, and now it's not in one because it's only queried once, which is a good sign for things going in the right direction.
There are also some naming and organisational changes around themes. The blanket terms "Colours" and "Styles" have been yeeted in favour of "Theme", which handles both extensions and UI colours. The FileStyle struct has been replaced with file_name::Options, making it similar to the views in how it has an Options struct and a Render struct.
Finally, eight unit tests have been removed because they turned out to be redundant (testing --colour and --color) after examining the tangled code, and the default theme has been put in its own file in preparation for more themes.
2020-10-22 21:34:00 +00:00
|
|
|
|
|
|
|
|
|
/// The options to make up the styles of the UI and file names.
|
|
|
|
|
pub theme: ThemeOptions,
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Options {
|
|
|
|
|
|
2017-08-10 16:54:28 +00:00
|
|
|
|
/// Parse the given iterator of command-line strings into an Options
|
|
|
|
|
/// struct and a list of free filenames, using the environment variables
|
|
|
|
|
/// for extra options.
|
2016-04-17 19:38:37 +00:00
|
|
|
|
#[allow(unused_results)]
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
pub fn parse<'args, I, V>(args: I, vars: &V) -> OptionsResult<'args>
|
2020-10-12 23:29:49 +00:00
|
|
|
|
where I: IntoIterator<Item = &'args OsStr>,
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
V: Vars,
|
2020-10-10 18:49:46 +00:00
|
|
|
|
{
|
2018-12-07 23:43:31 +00:00
|
|
|
|
use crate::options::parser::{Matches, Strictness};
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
2017-08-26 20:19:06 +00:00
|
|
|
|
let strictness = match vars.get(vars::EXA_STRICT) {
|
2017-08-10 17:45:26 +00:00
|
|
|
|
None => Strictness::UseLastArguments,
|
|
|
|
|
Some(ref t) if t.is_empty() => Strictness::UseLastArguments,
|
2020-10-13 00:46:17 +00:00
|
|
|
|
Some(_) => Strictness::ComplainAboutRedundantArguments,
|
2017-08-10 17:45:26 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let Matches { flags, frees } = match flags::ALL_ARGS.parse(args, strictness) {
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
Ok(m) => m,
|
|
|
|
|
Err(pe) => return OptionsResult::InvalidOptions(OptionsError::Parse(pe)),
|
2016-04-17 19:38:37 +00:00
|
|
|
|
};
|
|
|
|
|
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
if let Some(help) = HelpString::deduce(&flags) {
|
|
|
|
|
return OptionsResult::Help(help);
|
|
|
|
|
}
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
if let Some(version) = VersionString::deduce(&flags) {
|
|
|
|
|
return OptionsResult::Version(version);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match Self::deduce(&flags, vars) {
|
|
|
|
|
Ok(options) => OptionsResult::Ok(options, frees),
|
|
|
|
|
Err(oe) => OptionsResult::InvalidOptions(oe),
|
|
|
|
|
}
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Whether the View specified in this set of options includes a Git
|
|
|
|
|
/// status column. It’s only worth trying to discover a repository if the
|
|
|
|
|
/// results will end up being displayed.
|
|
|
|
|
pub fn should_scan_for_git(&self) -> bool {
|
2020-04-19 03:52:35 +00:00
|
|
|
|
if self.filter.git_ignore == GitIgnore::CheckAndIgnore {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-24 21:39:15 +00:00
|
|
|
|
match self.view.mode {
|
2017-07-05 20:01:01 +00:00
|
|
|
|
Mode::Details(details::Options { table: Some(ref table), .. }) |
|
2019-08-29 12:34:30 +00:00
|
|
|
|
Mode::GridDetails(grid_details::Options { details: details::Options { table: Some(ref table), .. }, .. }) => table.columns.git,
|
2016-04-17 19:38:37 +00:00
|
|
|
|
_ => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Determines the complete set of options based on the given command-line
|
|
|
|
|
/// arguments, after they’ve been parsed.
|
2020-10-13 00:36:41 +00:00
|
|
|
|
fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
|
2020-12-03 01:06:29 +00:00
|
|
|
|
if cfg!(not(feature = "git")) &&
|
|
|
|
|
matches.has_where_any(|f| f.matches(&flags::GIT) || f.matches(&flags::GIT_IGNORE)).is_some() {
|
|
|
|
|
return Err(OptionsError::Unsupported(format!(
|
|
|
|
|
"Options --git and --git-ignore can't be used because `git` feature was disabled in this build of exa"
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 16:54:28 +00:00
|
|
|
|
let view = View::deduce(matches, vars)?;
|
Make View command-line args position-dependent
This commit changes the way the View (long mode, lines mode, grid mode, etc) is parsed from the command-line arguments.
Previously, it checked for long and long-grid, then tree, then lines, then grid, in that order, no matter which order the arguments were given in on the command-line. Now, it bases the view on whichever argument comes last in the list.
Unfortunately, the options-parsing code for Views is getting really complicated, but I can't see a way to simplify it while retaining the existing functionality.
It also links the parsing of DirAction to the result of parsing the View, so that you can't use tree mode if your view isn't Details. This is to fix an issue where `exa --tree --oneline` would just emit ".", because the DirAction was treating directories as files, and the argument was ".", and the View made it use lines view. Now, the --tree is ignored, as the view isn't Details.
Fixes GH-407 and GH-583.
2020-10-23 22:04:22 +00:00
|
|
|
|
let dir_action = DirAction::deduce(matches, matches!(view.mode, Mode::Details(_)))?;
|
|
|
|
|
let filter = FileFilter::deduce(matches)?;
|
Massive theming and view options refactor
This commit significantly refactors the way that options are parsed. It introduces the Theme type which contains both styling and extension configuration, converts the option-parsing process into a being a pure function, and removes some rather gnarly old code.
The main purpose of the refactoring is to fix GH-318, "Tests fail when not connected to a terminal". Even though exa was compiling fine on my machine and on Travis, it was failing for automated build scripts. This was because of what the option-parsing code was trying to accomplish: it wasn't just providing a struct of the user's settings, it was also checking the terminal, providing a View directly.
This has been changed so that the options module now _only_ looks at the command-line arguments and environment variables. Instead of returning a View, it returns the user's _preference_, and it's then up to the 'main' module to examine the terminal width and figure out if the view is doable, downgrading it if necessary.
The code that used to determine the view was horrible and I'm pleased it can be cut out. Also, the terminal width used to be in a lazy_static because it was queried multiple times, and now it's not in one because it's only queried once, which is a good sign for things going in the right direction.
There are also some naming and organisational changes around themes. The blanket terms "Colours" and "Styles" have been yeeted in favour of "Theme", which handles both extensions and UI colours. The FileStyle struct has been replaced with file_name::Options, making it similar to the views in how it has an Options struct and a Render struct.
Finally, eight unit tests have been removed because they turned out to be redundant (testing --colour and --color) after examining the tangled code, and the default theme has been put in its own file in preparation for more themes.
2020-10-22 21:34:00 +00:00
|
|
|
|
let theme = ThemeOptions::deduce(matches, vars)?;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
Massive theming and view options refactor
This commit significantly refactors the way that options are parsed. It introduces the Theme type which contains both styling and extension configuration, converts the option-parsing process into a being a pure function, and removes some rather gnarly old code.
The main purpose of the refactoring is to fix GH-318, "Tests fail when not connected to a terminal". Even though exa was compiling fine on my machine and on Travis, it was failing for automated build scripts. This was because of what the option-parsing code was trying to accomplish: it wasn't just providing a struct of the user's settings, it was also checking the terminal, providing a View directly.
This has been changed so that the options module now _only_ looks at the command-line arguments and environment variables. Instead of returning a View, it returns the user's _preference_, and it's then up to the 'main' module to examine the terminal width and figure out if the view is doable, downgrading it if necessary.
The code that used to determine the view was horrible and I'm pleased it can be cut out. Also, the terminal width used to be in a lazy_static because it was queried multiple times, and now it's not in one because it's only queried once, which is a good sign for things going in the right direction.
There are also some naming and organisational changes around themes. The blanket terms "Colours" and "Styles" have been yeeted in favour of "Theme", which handles both extensions and UI colours. The FileStyle struct has been replaced with file_name::Options, making it similar to the views in how it has an Options struct and a Render struct.
Finally, eight unit tests have been removed because they turned out to be redundant (testing --colour and --color) after examining the tangled code, and the default theme has been put in its own file in preparation for more themes.
2020-10-22 21:34:00 +00:00
|
|
|
|
Ok(Self { dir_action, filter, view, theme })
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
Replace Misfire with a testable OptionsResult
This was meant to be a small change, but it spiralled into a big one.
The original intention was to separate OptionsResult and OptionsError. With these types separated, the Help and Version variants can only be returned from the Options::parse function, and the later option-parsing functions can only return success or errors.
Also, Misfire was a silly name.
As a side-effect of Options::parse returning OptionsResult instead of Result<Options, Misfire>, we could no longer use unwrap() or unwrap_err() to get the contents out. This commit makes OptionsResult into a value type, and Options::parse a pure function. It feels like it should be one, having its return value entirely dependent on its arguments, but it also loaded locales and time zones. These parts have been moved into lazy_static references, and the code still passes tests without much change.
OptionsResult isn't PartialEq yet, because the file colouring uses a Box internally.
2020-10-12 22:47:36 +00:00
|
|
|
|
/// The result of the `Options::getopts` function.
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum OptionsResult<'args> {
|
|
|
|
|
|
|
|
|
|
/// The options were parsed successfully.
|
|
|
|
|
Ok(Options, Vec<&'args OsStr>),
|
|
|
|
|
|
|
|
|
|
/// There was an error parsing the arguments.
|
|
|
|
|
InvalidOptions(OptionsError),
|
|
|
|
|
|
|
|
|
|
/// One of the arguments was `--help`, so display help.
|
|
|
|
|
Help(HelpString),
|
|
|
|
|
|
|
|
|
|
/// One of the arguments was `--version`, so display the version number.
|
|
|
|
|
Version(VersionString),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-04-17 19:38:37 +00:00
|
|
|
|
#[cfg(test)]
|
2017-08-08 08:18:17 +00:00
|
|
|
|
pub mod test {
|
2018-12-07 23:43:31 +00:00
|
|
|
|
use crate::options::parser::{Arg, MatchedFlags};
|
2020-10-12 23:29:49 +00:00
|
|
|
|
use std::ffi::OsStr;
|
2017-08-10 16:54:28 +00:00
|
|
|
|
|
2017-08-08 08:18:17 +00:00
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
|
|
|
pub enum Strictnesses {
|
|
|
|
|
Last,
|
|
|
|
|
Complain,
|
|
|
|
|
Both,
|
|
|
|
|
}
|
|
|
|
|
|
Be stricter in strict mode
Now the code actually starts to use the Strictness flag that was added in the earlier commit! Well, the *code* doesn’t, but the tests do: the macros that create the test cases now have a parameter for which tests they should run. It’s usually ‘Both’ for both strict mode and default mode, but can be specified to only run in one, for when the results differ (usually when options override one another)
The downside to strict mode is that, now, *any* call to `matches.has` or `matches.get` could fail, because an option could have been specified twice, and this is the place where those are checked for. This makes the code a little less ergonomic in places, but that’s what the ? operator is for. The only place this has really had an effect is in `Classify::deduce`, which used to just return a boolean but can now fail.
In order to more thoroughly test the mode, some of the older parts of the code can now act more strict. For example, `TerminalColours::deduce` will now use the last-given option rather than searching for “colours” before “colors”.
Help and Version continue doing their own thing.
2017-08-09 08:21:29 +00:00
|
|
|
|
/// This function gets used by the other testing modules.
|
|
|
|
|
/// It can run with one or both strictness values: if told to run with
|
|
|
|
|
/// both, then both should resolve to the same result.
|
2017-08-09 12:36:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// It returns a vector with one or two elements in.
|
|
|
|
|
/// These elements can then be tested with assert_eq or what have you.
|
|
|
|
|
pub fn parse_for_test<T, F>(inputs: &[&str], args: &'static [&'static Arg], strictnesses: Strictnesses, get: F) -> Vec<T>
|
2020-10-13 00:36:41 +00:00
|
|
|
|
where F: Fn(&MatchedFlags<'_>) -> T
|
2017-08-08 08:18:17 +00:00
|
|
|
|
{
|
|
|
|
|
use self::Strictnesses::*;
|
2018-12-07 23:43:31 +00:00
|
|
|
|
use crate::options::parser::{Args, Strictness};
|
2017-08-08 08:18:17 +00:00
|
|
|
|
|
2020-10-12 23:29:49 +00:00
|
|
|
|
let bits = inputs.into_iter().map(OsStr::new).collect::<Vec<_>>();
|
2017-10-31 05:24:31 +00:00
|
|
|
|
let mut result = Vec::new();
|
2017-08-08 08:18:17 +00:00
|
|
|
|
|
|
|
|
|
if strictnesses == Last || strictnesses == Both {
|
2020-10-12 23:29:49 +00:00
|
|
|
|
let results = Args(args).parse(bits.clone(), Strictness::UseLastArguments);
|
2017-10-31 05:24:31 +00:00
|
|
|
|
result.push(get(&results.unwrap().flags));
|
2017-08-08 08:18:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strictnesses == Complain || strictnesses == Both {
|
2020-10-12 23:29:49 +00:00
|
|
|
|
let results = Args(args).parse(bits, Strictness::ComplainAboutRedundantArguments);
|
2017-10-31 05:24:31 +00:00
|
|
|
|
result.push(get(&results.unwrap().flags));
|
2017-08-08 08:18:17 +00:00
|
|
|
|
}
|
2017-08-09 12:36:06 +00:00
|
|
|
|
|
2017-10-31 05:24:31 +00:00
|
|
|
|
result
|
2017-08-08 08:18:17 +00:00
|
|
|
|
}
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|