exa/src/options/filter.rs
Benjamin Sago 2d1f462bfa Switch to the new options parser
This commit removes the dependency on the ‘getopts’ crate entirely, and re-writes all its uses to use the new options parser instead.

As expected there are casualties galore:

- We now need to collect the options into a vector at the start, so we can use references to them, knowing they’ll be stored *somewhere*.
- Because OsString isn’t Display, its Debug impl gets used instead. (This is hopefully temporary)
- Options that take values (such as ‘sort’ or ‘time-style’) now parse those values with ‘to_string_lossy’. The ‘lossy’ part means “I’m at a loss for what to do here”
- Error messages got a lot worse, but “--tree --all --all” is now a special case of error rather than just another Misfire::Useless.
- Some tests had to be re-written to deal with the fact that the parser works with references.
- ParseError loses its lifetime and owns its contents, to avoid having to attach <'a> to Misfire.
- The parser now takes an iterator instead of a slice.
- OsStrings can’t be ‘match’ patterns, so the code devolves to using long Eq chains instead.
- Make a change to the xtest that assumed an input argument with invalid UTF-8 in was always an error to stderr, when that now in fact works!
- Fix a bug in Vagrant where ‘exa’ and ‘rexa’ didn’t properly escape filenames with spaces in.
2017-07-26 17:48:18 +01:00

123 lines
3.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use glob;
use fs::DotFilter;
use fs::filter::{FileFilter, SortField, SortCase, IgnorePatterns};
use options::{flags, Misfire};
use options::parser::Matches;
impl FileFilter {
/// Determines the set of file filter options to use, based on the users
/// command-line arguments.
pub fn deduce(matches: &Matches) -> Result<FileFilter, Misfire> {
Ok(FileFilter {
list_dirs_first: matches.has(&flags::DIRS_FIRST),
reverse: matches.has(&flags::REVERSE),
sort_field: SortField::deduce(matches)?,
dot_filter: DotFilter::deduce(matches)?,
ignore_patterns: IgnorePatterns::deduce(matches)?,
})
}
}
impl Default for SortField {
fn default() -> SortField {
SortField::Name(SortCase::Sensitive)
}
}
impl SortField {
/// Determine the sort field to use, based on the presence of a “sort”
/// argument. This will return `Err` if the option is there, but does not
/// correspond to a valid field.
fn deduce(matches: &Matches) -> Result<SortField, Misfire> {
const SORTS: &[&str] = &[ "name", "Name", "size", "extension",
"Extension", "modified", "accessed",
"created", "inode", "type", "none" ];
let word = match matches.get(&flags::SORT) {
Some(w) => w,
None => return Ok(SortField::default()),
};
if word == "name" || word == "filename" {
Ok(SortField::Name(SortCase::Sensitive))
}
else if word == "Name" || word == "Filename" {
Ok(SortField::Name(SortCase::Insensitive))
}
else if word == "size" || word == "filesize" {
Ok(SortField::Size)
}
else if word == "ext" || word == "extension" {
Ok(SortField::Extension(SortCase::Sensitive))
}
else if word == "Ext" || word == "Extension" {
Ok(SortField::Extension(SortCase::Insensitive))
}
else if word == "mod" || word == "modified" {
Ok(SortField::ModifiedDate)
}
else if word == "acc" || word == "accessed" {
Ok(SortField::AccessedDate)
}
else if word == "cr" || word == "created" {
Ok(SortField::CreatedDate)
}
else if word == "inode" {
Ok(SortField::FileInode)
}
else if word == "type" {
Ok(SortField::FileType)
}
else if word == "none" {
Ok(SortField::Unsorted)
}
else {
Err(Misfire::bad_argument(&flags::SORT, word, SORTS))
}
}
}
impl DotFilter {
pub fn deduce(matches: &Matches) -> Result<DotFilter, Misfire> {
let dots = match matches.count(&flags::ALL) {
0 => return Ok(DotFilter::JustFiles),
1 => DotFilter::Dotfiles,
_ => DotFilter::DotfilesAndDots,
};
if matches.has(&flags::TREE) {
Err(Misfire::TreeAllAll)
}
else {
Ok(dots)
}
}
}
impl IgnorePatterns {
/// Determines the set of file filter options to use, based on the users
/// command-line arguments.
pub fn deduce(matches: &Matches) -> Result<IgnorePatterns, Misfire> {
let patterns = match matches.get(&flags::IGNORE_GLOB) {
None => Ok(Vec::new()),
Some(is) => is.to_string_lossy().split('|').map(|a| glob::Pattern::new(a)).collect(),
}?;
// TODO: is to_string_lossy really the best way to handle
// invalid UTF-8 there?
Ok(IgnorePatterns { patterns })
}
}