2022-01-22 16:41:24 +00:00
|
|
|
// SPDX-FileCopyrightText: 2021-2022 Lynnesbian
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2021-10-05 14:24:08 +00:00
|
|
|
|
2021-10-05 15:30:13 +00:00
|
|
|
//! Command line argument parsing logic and associated functions.
|
2021-02-28 14:06:05 +00:00
|
|
|
|
2021-04-28 09:33:42 +00:00
|
|
|
use std::collections::BTreeSet;
|
2021-04-02 17:51:49 +00:00
|
|
|
use std::path::PathBuf;
|
2021-03-25 14:28:03 +00:00
|
|
|
|
2021-09-24 08:11:25 +00:00
|
|
|
use cfg_if::cfg_if;
|
2022-01-18 08:44:46 +00:00
|
|
|
use clap::{ArgEnum, Parser};
|
2021-09-24 08:11:25 +00:00
|
|
|
|
2021-09-24 14:53:35 +00:00
|
|
|
use crate::utils::{CLAP_LONG_VERSION, CLAP_VERSION};
|
2021-09-24 08:11:25 +00:00
|
|
|
use crate::String as StringType;
|
|
|
|
|
2021-03-25 14:28:03 +00:00
|
|
|
cfg_if! {
|
|
|
|
if #[cfg(windows)] {
|
2021-10-05 15:30:13 +00:00
|
|
|
/// The default [`OutputFormat`] to use.
|
2021-03-25 14:28:03 +00:00
|
|
|
const DEFAULT_FORMAT: &str = "powershell";
|
|
|
|
} else {
|
2021-10-05 15:30:13 +00:00
|
|
|
/// The default [`OutputFormat`] to use.
|
2021-04-06 15:47:40 +00:00
|
|
|
const DEFAULT_FORMAT: &str = "sh";
|
2021-03-25 14:28:03 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-10 09:20:22 +00:00
|
|
|
|
2022-09-04 02:55:30 +00:00
|
|
|
#[derive(ArgEnum, Eq, PartialEq, Debug, Copy, Clone)]
|
2021-10-05 15:30:13 +00:00
|
|
|
/// The format to use when running fif without the `--fix` flag. Specified at runtime with the `-o`/`--output-format`
|
|
|
|
/// flag.
|
2021-02-10 09:20:22 +00:00
|
|
|
pub enum OutputFormat {
|
2021-03-01 10:20:46 +00:00
|
|
|
/// A Bourne shell compatible script.
|
2021-04-28 11:27:06 +00:00
|
|
|
#[clap(alias = "shell", alias = "bash")]
|
2021-04-06 15:47:40 +00:00
|
|
|
Sh,
|
2021-03-25 14:28:03 +00:00
|
|
|
/// A PowerShell script.
|
2021-04-28 09:33:42 +00:00
|
|
|
#[clap(alias = "powershell")]
|
2021-03-25 14:28:03 +00:00
|
|
|
PowerShell,
|
2021-03-01 10:20:46 +00:00
|
|
|
/// Plain text.
|
2021-02-14 17:12:27 +00:00
|
|
|
Text,
|
2021-05-05 22:57:42 +00:00
|
|
|
/// JSON.
|
|
|
|
#[cfg(feature = "json")]
|
|
|
|
Json,
|
2021-02-10 09:20:22 +00:00
|
|
|
}
|
2021-02-04 11:22:19 +00:00
|
|
|
|
2022-09-04 02:55:30 +00:00
|
|
|
#[derive(ArgEnum, Eq, PartialEq, Debug, Copy, Clone)]
|
2021-10-05 15:30:13 +00:00
|
|
|
/// Specifies under what conditions the user should be prompted when running fif in `--fix` mode. Defaults to `Error`.
|
|
|
|
/// Specified at runtime with the `-p`/`--prompt` flag.
|
2021-10-04 13:33:48 +00:00
|
|
|
pub enum Prompt {
|
2021-10-04 14:18:42 +00:00
|
|
|
/// Never prompt.
|
2021-10-04 13:33:48 +00:00
|
|
|
Never,
|
2021-10-04 14:18:42 +00:00
|
|
|
/// Prompt only on errors, and on overwrites, if `--overwrite` is set.
|
2021-10-04 13:33:48 +00:00
|
|
|
Error,
|
2021-10-04 14:18:42 +00:00
|
|
|
/// Prompt for every rename.
|
|
|
|
Always,
|
2021-10-04 13:33:48 +00:00
|
|
|
}
|
|
|
|
|
2022-01-01 03:28:45 +00:00
|
|
|
#[derive(Parser, Debug)]
|
2021-06-18 05:17:30 +00:00
|
|
|
#[allow(clippy::struct_excessive_bools)]
|
2021-03-01 10:20:46 +00:00
|
|
|
#[clap(
|
2021-09-24 14:53:35 +00:00
|
|
|
version = CLAP_VERSION.as_str(),
|
|
|
|
long_version = CLAP_LONG_VERSION.as_str(),
|
2021-03-01 10:20:46 +00:00
|
|
|
author = option_env!("CARGO_PKG_AUTHORS").unwrap_or("Lynnesbian"),
|
|
|
|
about = option_env!("CARGO_PKG_DESCRIPTION").unwrap_or("File Info Fixer"),
|
2022-01-22 16:41:24 +00:00
|
|
|
before_help = "Copyright © 2021-2022 Lynnesbian under the GPL3 (or later) License.",
|
|
|
|
after_long_help = "Copyright © 2021-2022 Lynnesbian\n\
|
2021-03-01 10:20:46 +00:00
|
|
|
This program is free software: you can redistribute it and/or modify \
|
|
|
|
it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 \
|
|
|
|
of the License, or (at your option) any later version.",
|
2022-02-18 04:36:50 +00:00
|
|
|
max_term_width = 120,
|
|
|
|
setting(clap::AppSettings::DeriveDisplayOrder)
|
2021-03-01 10:20:46 +00:00
|
|
|
)]
|
2021-10-05 15:30:13 +00:00
|
|
|
/// [`Clap`]-derived struct used to parse command line arguments.
|
2021-02-04 11:22:19 +00:00
|
|
|
pub struct Parameters {
|
2021-10-04 13:33:48 +00:00
|
|
|
/// Automatically rename files to use the correct extension, prompting the user for every rename.
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(long, help_heading = "RENAMING")]
|
2021-10-04 10:22:15 +00:00
|
|
|
pub fix: bool,
|
|
|
|
|
2021-10-04 13:33:48 +00:00
|
|
|
/// Requires --fix. Should fif prompt you `Never`, only on `Error`s and overwrites, or `Always`?
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(short = 'p', long, arg_enum, requires = "fix", help_heading = "RENAMING")]
|
2021-10-04 13:33:48 +00:00
|
|
|
pub prompt: Option<Prompt>,
|
|
|
|
|
|
|
|
/// Requires --fix. Allow overwriting files. Warning: When used in combination with `--prompt never`, fif will
|
|
|
|
/// overwrite files without prompting!
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(long, requires = "fix", help_heading = "RENAMING")]
|
2021-10-04 13:33:48 +00:00
|
|
|
pub overwrite: bool,
|
2021-10-04 10:22:15 +00:00
|
|
|
|
2022-01-22 17:18:25 +00:00
|
|
|
// NOTE: it is impossible (as far as i can tell) to accept extensions with commas in their name. i don't know why
|
|
|
|
// you would ever want a file named something like "example.xy,z", though... fif's -e and -x flags don't support this.
|
2021-04-28 06:44:29 +00:00
|
|
|
/// Only examine files with these extensions.
|
|
|
|
/// Multiple extensions can be specified by either using the flag multiple times (`-e jpg -e png -e gif`), or by
|
|
|
|
/// separating them with commas (`-e jpg,png,gif`).
|
2022-02-18 04:24:17 +00:00
|
|
|
#[clap(short, long, use_value_delimiter = true, require_value_delimiter = true, value_name = "ext", takes_value = true,
|
2022-02-18 04:36:50 +00:00
|
|
|
validator = validate_exts, help_heading = "FILTERING")]
|
2021-04-02 17:51:49 +00:00
|
|
|
pub exts: Option<Vec<StringType>>,
|
2021-02-18 11:43:24 +00:00
|
|
|
|
2021-04-28 06:44:29 +00:00
|
|
|
/// Use these preset lists of extensions as the search filter (comma-separated list).
|
|
|
|
/// `media` includes all extensions from the `audio`, `video`, and `images` sets, making `-E media` equivalent to
|
|
|
|
/// `-E audio,video,images`.
|
2021-04-29 07:07:58 +00:00
|
|
|
#[clap(
|
|
|
|
short = 'E',
|
|
|
|
long,
|
|
|
|
arg_enum,
|
2022-02-18 04:24:17 +00:00
|
|
|
use_value_delimiter = true,
|
|
|
|
require_value_delimiter = true,
|
2022-04-12 05:09:31 +00:00
|
|
|
value_name = "set",
|
|
|
|
help_heading = "FILTERING"
|
2021-04-29 07:07:58 +00:00
|
|
|
)]
|
2021-04-28 08:09:44 +00:00
|
|
|
pub ext_set: Vec<ExtensionSet>,
|
2021-02-04 11:22:19 +00:00
|
|
|
|
2021-04-28 06:44:29 +00:00
|
|
|
/// Don't scan files with these extensions.
|
|
|
|
/// This option takes precedence over extensions specified with `-e` or `-E`.
|
2022-02-18 04:24:17 +00:00
|
|
|
#[clap(short = 'x', long, use_value_delimiter = true, require_value_delimiter = true, value_name = "ext", validator =
|
2022-02-18 04:36:50 +00:00
|
|
|
validate_exts, help_heading = "FILTERING")]
|
2021-04-27 10:25:41 +00:00
|
|
|
pub exclude: Option<Vec<StringType>>,
|
|
|
|
|
2021-04-28 06:16:32 +00:00
|
|
|
/// Exclude files using a preset list of extensions.
|
2021-04-28 06:44:29 +00:00
|
|
|
/// This option takes precedence over extensions specified with `-e` or `-E`.
|
2021-04-29 07:07:58 +00:00
|
|
|
#[clap(
|
|
|
|
short = 'X',
|
|
|
|
long,
|
|
|
|
arg_enum,
|
2022-02-18 04:24:17 +00:00
|
|
|
use_value_delimiter = true,
|
|
|
|
require_value_delimiter = true,
|
2022-04-12 05:09:31 +00:00
|
|
|
value_name = "set",
|
|
|
|
help_heading = "FILTERING"
|
2021-04-29 07:07:58 +00:00
|
|
|
)]
|
2021-04-28 08:09:44 +00:00
|
|
|
pub exclude_set: Vec<ExtensionSet>,
|
2021-04-28 05:17:40 +00:00
|
|
|
|
2021-04-06 15:47:40 +00:00
|
|
|
/// Don't skip hidden files and directories.
|
|
|
|
/// Even if this flag is not present, fif will still recurse into a hidden root directory - for example, `fif
|
|
|
|
/// ~/.hidden` will recurse into `~/.hidden` regardless of whether or not -s was passed as an argument.
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(short, long, help_heading = "FILTERING")]
|
2021-02-04 11:22:19 +00:00
|
|
|
pub scan_hidden: bool,
|
|
|
|
|
2021-04-06 15:47:40 +00:00
|
|
|
/// Scan files without extensions.
|
|
|
|
/// By default, fif will ignore files without extensions - for example, a jpeg file named `photo` won't be considered
|
|
|
|
/// misnamed. Supplying the -S flag will cause fif to recommend renaming this file to `photo.jpg`.
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(short = 'S', long, help_heading = "FILTERING")]
|
2021-03-02 15:12:29 +00:00
|
|
|
pub scan_extensionless: bool,
|
|
|
|
|
2022-02-18 04:36:50 +00:00
|
|
|
/// Follow symlinks.
|
|
|
|
#[clap(short, long, help_heading = "FILTERING")]
|
|
|
|
pub follow_symlinks: bool,
|
|
|
|
|
|
|
|
/// Don't rename files with extensions unknown to fif.
|
|
|
|
/// For example, with this option, fif will not rename "image.unknown" to "image.jpg"
|
|
|
|
#[clap(short = 'I', long, help_heading = "FILTERING")]
|
|
|
|
pub ignore_unknown_exts: bool,
|
|
|
|
|
2021-04-06 15:47:40 +00:00
|
|
|
/// Output format to use.
|
|
|
|
/// By default, fif will output a PowerShell script on Windows, and a Bourne Shell script on other platforms.
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(short, long, default_value = DEFAULT_FORMAT, arg_enum, value_name = "format", help_heading = "OUTPUT")]
|
2021-02-10 09:20:22 +00:00
|
|
|
pub output_format: OutputFormat,
|
2021-02-06 03:24:13 +00:00
|
|
|
|
2021-04-28 12:20:10 +00:00
|
|
|
/// Output verbosity. Each additional `-v` increases verbosity.
|
2021-07-01 08:52:53 +00:00
|
|
|
/// Can be overridden by FIF_LOG or RUST_LOG.
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(short, long, parse(from_occurrences), group = "verbosity", help_heading = "OUTPUT")]
|
2021-04-26 12:15:14 +00:00
|
|
|
pub verbose: u8,
|
|
|
|
|
2021-04-28 12:20:10 +00:00
|
|
|
/// Output quietness. Each additional `-q` decreases verbosity.
|
2021-07-01 08:52:53 +00:00
|
|
|
/// Can be overridden by FIF_LOG or RUST_LOG.
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(short, long, parse(from_occurrences), group = "verbosity", help_heading = "OUTPUT")]
|
2021-04-28 12:20:10 +00:00
|
|
|
pub quiet: u8,
|
|
|
|
|
2021-06-18 05:17:30 +00:00
|
|
|
/// Use canonical (absolute) paths in output.
|
|
|
|
/// A canonical path is the "one true path" to a given file, and is always an absolute path. While a file may have
|
|
|
|
/// many absolute paths (for example, on Windows, '\\?\C:\file.txt' and 'C:\file.txt' are both absolute paths to the
|
|
|
|
/// same file), but only one canonical path. This does not effect logged output.
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(long, help_heading = "OUTPUT")]
|
2021-06-18 05:17:30 +00:00
|
|
|
pub canonical_paths: bool,
|
|
|
|
|
2021-04-06 15:47:40 +00:00
|
|
|
/// The directory to process.
|
2021-02-06 03:24:13 +00:00
|
|
|
#[clap(name = "DIR", default_value = ".", parse(from_os_str))]
|
2021-05-08 00:10:51 +00:00
|
|
|
pub dir: PathBuf,
|
2021-08-06 14:12:26 +00:00
|
|
|
|
2021-09-25 08:55:50 +00:00
|
|
|
#[cfg(feature = "multi-threaded")]
|
|
|
|
/// Number of jobs (threads) to use when scanning results.
|
|
|
|
/// The default behaviour is to use one thread per CPU thread. This behaviour can be manually requested by setting
|
|
|
|
/// `-j 0`. Using `-j 1` will disable multi-threading behaviour, as if you had compiled fif with the multi-threading
|
|
|
|
/// feature disabled. Setting more jobs than you have CPU threads is not recommended.
|
2022-02-18 04:36:50 +00:00
|
|
|
#[clap(short = 'j', long, default_value = "0", help_heading = "MISC")]
|
2021-09-25 08:55:50 +00:00
|
|
|
pub jobs: usize,
|
2021-02-04 11:22:19 +00:00
|
|
|
}
|
2021-02-28 12:16:54 +00:00
|
|
|
|
2022-01-01 03:28:45 +00:00
|
|
|
/// Validation function for argument parsing that ensures passed-in extensions are lowercase, and that the user
|
|
|
|
/// didn't supply an empty list.
|
|
|
|
fn validate_exts(exts: &str) -> Result<(), String> {
|
2021-04-29 07:02:28 +00:00
|
|
|
// TODO: i would much rather accept uppercase exts and convert them to lowercase than just rejecting lowercase exts...
|
2022-01-01 03:28:45 +00:00
|
|
|
|
|
|
|
if exts.is_empty() {
|
|
|
|
return Err(String::from("Cannot specify empty extensions"));
|
|
|
|
}
|
|
|
|
|
2021-04-29 07:02:28 +00:00
|
|
|
if exts.to_lowercase() != exts {
|
2021-04-29 07:07:58 +00:00
|
|
|
return Err(String::from("Supplied extensions must be lowercase"));
|
2021-04-29 07:02:28 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-03-02 15:12:29 +00:00
|
|
|
/// Further options relating to scanning.
|
2022-09-04 02:55:30 +00:00
|
|
|
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
2021-08-06 14:36:19 +00:00
|
|
|
#[allow(clippy::struct_excessive_bools)]
|
2021-03-02 15:12:29 +00:00
|
|
|
pub struct ScanOpts {
|
|
|
|
/// Whether hidden files and directories should be scanned.
|
|
|
|
pub hidden: bool,
|
|
|
|
/// Whether files without extensions should be scanned.
|
2021-03-11 17:44:31 +00:00
|
|
|
pub extensionless: bool,
|
2021-04-04 13:52:16 +00:00
|
|
|
/// Should symlinks be followed?
|
|
|
|
pub follow_symlinks: bool,
|
2021-08-06 14:12:26 +00:00
|
|
|
/// Whether to rename files with unknown extensions.
|
|
|
|
pub ignore_unknown_exts: bool,
|
2021-03-02 15:12:29 +00:00
|
|
|
}
|
|
|
|
|
2021-02-28 12:16:54 +00:00
|
|
|
impl Parameters {
|
2021-04-27 10:25:41 +00:00
|
|
|
/// Returns an optional vec of the extensions to be scanned - i.e., extensions specified via the `-e` or `-E` flag,
|
2021-04-28 07:14:03 +00:00
|
|
|
/// minus the extensions excluded with the `-x` flag; i.e., the difference between the included and excluded sets.
|
2021-04-28 09:33:42 +00:00
|
|
|
pub fn extensions(&self) -> Option<BTreeSet<&str>> {
|
2021-04-28 07:14:03 +00:00
|
|
|
if let Some(included) = self.included_extensions() {
|
|
|
|
if let Some(excluded) = self.excluded_extensions() {
|
|
|
|
// return included extensions without excluded extensions
|
|
|
|
// ...maybe i should have called them "suffixes" instead of extensions...
|
|
|
|
Some(included.into_iter().filter(|ext| !excluded.contains(ext)).collect())
|
|
|
|
} else {
|
|
|
|
// no extensions excluded - just return all included
|
|
|
|
Some(included)
|
|
|
|
}
|
2021-02-28 12:16:54 +00:00
|
|
|
} else {
|
2021-04-28 07:14:03 +00:00
|
|
|
// no extensions included - return none
|
2021-04-04 13:52:16 +00:00
|
|
|
None
|
2021-02-28 12:16:54 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-02 15:12:29 +00:00
|
|
|
|
2021-04-28 07:14:03 +00:00
|
|
|
/// Returns an optional vec of extensions that were specified by `-e` or `-E`. Note that this doesn't account for
|
|
|
|
/// extensions excluded by the exclusion flags.
|
2021-04-28 09:33:42 +00:00
|
|
|
pub fn included_extensions(&self) -> Option<BTreeSet<&str>> {
|
|
|
|
let mut included = BTreeSet::new();
|
|
|
|
if let Some(exts) = self.exts.as_ref() {
|
|
|
|
// -e
|
2021-04-28 07:14:03 +00:00
|
|
|
included.extend(exts.iter().map(|ext| ext.as_str()));
|
|
|
|
}
|
|
|
|
|
2021-04-28 09:33:42 +00:00
|
|
|
if !&self.ext_set.is_empty() {
|
|
|
|
// -E
|
2021-04-28 08:09:44 +00:00
|
|
|
included.extend(self.ext_set.iter().flat_map(|set| set.extensions()));
|
2021-04-28 07:14:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
match included {
|
|
|
|
x if x.is_empty() => None,
|
2021-04-28 09:33:42 +00:00
|
|
|
x => Some(x),
|
2021-04-28 07:14:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns an optional vec of extensions that were specified by `-x` or `-X`.
|
2021-04-28 09:33:42 +00:00
|
|
|
pub fn excluded_extensions(&self) -> Option<BTreeSet<&str>> {
|
|
|
|
let mut excluded = BTreeSet::new();
|
|
|
|
if let Some(exclude) = self.exclude.as_ref() {
|
|
|
|
// -x
|
2021-04-28 06:59:09 +00:00
|
|
|
excluded.extend(exclude.iter().map(|ext| ext.as_str()));
|
2021-04-28 06:16:32 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 09:33:42 +00:00
|
|
|
if !&self.exclude_set.is_empty() {
|
|
|
|
// -X
|
2021-04-28 08:09:44 +00:00
|
|
|
excluded.extend(self.exclude_set.iter().flat_map(|set| set.extensions()));
|
2021-04-28 06:16:32 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 07:14:03 +00:00
|
|
|
// excluded doesn't sound like a word anymore
|
|
|
|
// tongue twister: enter X-options' excellent extension exclusion
|
2021-04-28 06:59:09 +00:00
|
|
|
match excluded {
|
|
|
|
x if x.is_empty() => None,
|
2021-04-28 09:33:42 +00:00
|
|
|
x => Some(x),
|
2021-04-28 06:16:32 +00:00
|
|
|
}
|
2021-04-27 10:25:41 +00:00
|
|
|
}
|
|
|
|
|
2021-10-04 16:12:16 +00:00
|
|
|
/// Populates a [`ScanOpts`] struct with values from [`self`].
|
2021-03-11 17:44:31 +00:00
|
|
|
pub const fn get_scan_opts(&self) -> ScanOpts {
|
|
|
|
ScanOpts {
|
|
|
|
hidden: self.scan_hidden,
|
|
|
|
extensionless: self.scan_extensionless,
|
2021-04-04 13:52:16 +00:00
|
|
|
follow_symlinks: self.follow_symlinks,
|
2021-08-06 14:36:19 +00:00
|
|
|
ignore_unknown_exts: self.ignore_unknown_exts,
|
2021-03-11 17:44:31 +00:00
|
|
|
}
|
2021-03-02 15:12:29 +00:00
|
|
|
}
|
2021-04-26 12:15:14 +00:00
|
|
|
|
2021-10-04 16:12:16 +00:00
|
|
|
/// Gets the verbosity set by the user via the `-v` and `-q` flags.
|
|
|
|
pub const fn get_verbosity(&self) -> log::LevelFilter {
|
2021-07-01 08:52:53 +00:00
|
|
|
use log::LevelFilter;
|
|
|
|
|
2021-04-28 12:20:10 +00:00
|
|
|
match self.quiet {
|
|
|
|
0 => {
|
|
|
|
match self.verbose {
|
2021-07-01 08:52:53 +00:00
|
|
|
0 => LevelFilter::Info, // no verbosity flags specified
|
|
|
|
1 => LevelFilter::Debug, // -v
|
|
|
|
_ => LevelFilter::Trace, // -vv...
|
2021-04-28 12:20:10 +00:00
|
|
|
}
|
2021-04-29 07:07:58 +00:00
|
|
|
}
|
2021-07-01 08:52:53 +00:00
|
|
|
1 => LevelFilter::Warn, // -q
|
|
|
|
2 => LevelFilter::Error, // -qq
|
|
|
|
_ => LevelFilter::Off, // -qqq...
|
2021-04-26 12:15:14 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-28 14:06:05 +00:00
|
|
|
}
|
2021-04-26 12:17:57 +00:00
|
|
|
|
|
|
|
/// Sets of extensions for use with [Parameter](crate::parameters::Parameters)'s `-E` flag.
|
2022-09-04 02:55:30 +00:00
|
|
|
#[derive(ArgEnum, Eq, PartialEq, Debug, Copy, Clone)]
|
2021-04-26 12:17:57 +00:00
|
|
|
pub enum ExtensionSet {
|
|
|
|
/// Extensions used for image file formats, such as `png`, `jpeg`, `webp`, etc.
|
|
|
|
Images,
|
|
|
|
/// Extensions used for audio file formats, such as `mp3`, `ogg`, `flac`, etc.
|
|
|
|
Audio,
|
|
|
|
/// Extensions used for video file formats, such as `mkv`, `mp4`, `mov`, etc.
|
2021-05-07 14:32:44 +00:00
|
|
|
#[clap(alias = "videos")]
|
2021-04-28 06:44:29 +00:00
|
|
|
Video,
|
2021-04-26 12:17:57 +00:00
|
|
|
/// Extensions used for media file formats. This acts as a combination of the [Images](ExtensionSet::Images),
|
2021-09-24 14:53:35 +00:00
|
|
|
/// [Audio](ExtensionSet::Audio) and [Video](ExtensionSet::Video) variants.
|
2021-04-26 12:17:57 +00:00
|
|
|
Media,
|
|
|
|
/// Extensions used for document file formats, such as `pdf`, `odt`, `docx`, etc.
|
|
|
|
Documents,
|
|
|
|
/// Extensions used for text file formats, such as `txt`, `toml`, `html`, etc.
|
|
|
|
Text,
|
|
|
|
/// Extensions used for archive file formats, such as `zip`, `zst`, `gz`, etc.
|
|
|
|
Archives,
|
|
|
|
/// Extensions used for system file formats, such as `mbr`, `crash`, `dll`, etc.
|
|
|
|
System,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ExtensionSet {
|
|
|
|
/// The list of known extensions for this `ExtensionSet`.
|
|
|
|
pub fn extensions(&self) -> Vec<&str> {
|
|
|
|
match self {
|
|
|
|
Self::Images => mime_guess::get_mime_extensions_str("image/*").unwrap().to_vec(),
|
|
|
|
Self::Audio => mime_guess::get_mime_extensions_str("audio/*").unwrap().to_vec(),
|
2021-04-28 06:44:29 +00:00
|
|
|
Self::Video => mime_guess::get_mime_extensions_str("video/*").unwrap().to_vec(),
|
2021-11-05 15:30:34 +00:00
|
|
|
Self::Media => [Self::Images.extensions(), Self::Audio.extensions(), Self::Video.extensions()].concat(),
|
2021-04-26 12:17:57 +00:00
|
|
|
Self::Documents => vec![
|
|
|
|
"pdf", "doc", "docx", "ppt", "pptx", "xls", "xlsx", "csv", "tsv", "odt", "ods", "odp", "oda", "rtf", "ps",
|
|
|
|
"pages", "key", "numbers",
|
|
|
|
],
|
2021-04-28 11:27:06 +00:00
|
|
|
Self::Text => [
|
|
|
|
mime_guess::get_mime_extensions_str("text/*").unwrap(),
|
|
|
|
&["js", "pl", "csh", "sh", "bash", "zsh", "fish", "bat", "php"],
|
|
|
|
]
|
|
|
|
.concat(),
|
2021-04-26 12:17:57 +00:00
|
|
|
// many compressed file types follow the name scheme "application/x.+compressed.*" - maybe this can be used
|
|
|
|
// somehow to extract extensions for compressed files from mime_guess?
|
2021-04-28 09:33:42 +00:00
|
|
|
Self::Archives => vec![
|
|
|
|
"zip", "tar", "gz", "zst", "xz", "rar", "7z", "bz", "bz2", "tgz", "rpa", "txz", "tz2", "sea", "sitx", "z",
|
|
|
|
"cpio",
|
|
|
|
],
|
2021-04-26 12:17:57 +00:00
|
|
|
Self::System => vec![
|
|
|
|
"com", "dll", "exe", "sys", "reg", "nt", "cpl", "msi", "efi", "bio", "rcv", "mbr", "sbf", "grub", "ko",
|
2021-04-28 09:33:42 +00:00
|
|
|
"dylib", "pdb", "hdmp", "crash", "cab",
|
2021-04-26 12:17:57 +00:00
|
|
|
],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|