|
|
@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
//! User-defined arbitrary format string ordering key spec & replacement.
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
use std::{
|
|
|
|
|
|
|
|
path::Path,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Used to identify and parse a token in a format string `%[OPT...]C` where `C` is the character used to idenfity the type's parser as valid for the sequence.
|
|
|
|
|
|
|
|
pub trait ParseToken {
|
|
|
|
|
|
|
|
/// The returned order-by object that can be reduced to a comparable `Cow<str>`-like slice for comparing with other tokens in a `Format` string.
|
|
|
|
|
|
|
|
type Substitute: Ord; //TODO: What trait bounds should be on this? Is it okay to just be `Ord`??? Or must it be something like... `<T: ParseToken>: PartialOrd<T>` instead? (XXX: Is `Ord` enough here? Since the list index of `ParseToken`s will be the same for every path in any given `Format` instance... How can we do this non-polymorphically??? Am I forgetting how to write Rust now...???? ehh...)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Parsing stage (during arg-parse).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Attempt to check if `substring` should match this parser.
|
|
|
|
|
|
|
|
/// The layout of `substring` will be in the format `/%.*(.)/` where group 1 is the character matched (and `end_char` is the extracted codepoint of it.)
|
|
|
|
|
|
|
|
/// # Returns
|
|
|
|
|
|
|
|
/// If it does, the matched portion of `substring` should be returned. (__NOTE__: The returned string **must** be *within* `substring`.)
|
|
|
|
|
|
|
|
fn visit<'matched>(&self, substring: &'matched str, end_char: char) -> Option<&'matched str>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Parse from a matched `visit()` call into the options of this instance of the parser type.
|
|
|
|
|
|
|
|
/// The options encoded in `substring` should set the state in `self` (if there is state.)
|
|
|
|
|
|
|
|
/// If parsing fails, the parser should return an error (which will be wrapped in context by the caller before reporting.)
|
|
|
|
|
|
|
|
fn parse(&mut self, substring: &str) -> eyre::Result<()>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Substituting state (during work for individual paths)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Create a substitute for this specific substring (identified in parsing stage above) for this specific path that can inserted into the `Format`'s list of reconstituted substrings to be compared with other outputs of the *same token index* for the *same substring* of a different path in the *same `Format` host*.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Panics
|
|
|
|
|
|
|
|
/// A panic should be used to signal failure, as this method should not fail in general. Any possible failures should be reported in `parse()`
|
|
|
|
|
|
|
|
// TOOD: Should we pass more then the `path`? I think when this `OrderBy` mode is selected, we should *not* do the `statx()` of the pathname itself before the comparison, since it may be irrelevent to the operation of this specific token, so.
|
|
|
|
|
|
|
|
fn substitute(&self, path: &Path) -> Self::Substitute;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Options available for filename/path-like tokens (see below.)
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Example
|
|
|
|
|
|
|
|
/// The token `%p` and `%n` can be modified with `PathTokenOpt` as: `%[S..[-]E]n` or `%[S..[-]E]p` to slice the name.
|
|
|
|
|
|
|
|
struct PathTokenOpt {
|
|
|
|
|
|
|
|
slice: Option<(usize, Option<usize>)>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl ParseToken for PathTokenOpt {
|
|
|
|
|
|
|
|
//TODO: Impl visit, parse & substitute for `%[S..[-]E]C`
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum Token<'source> {
|
|
|
|
|
|
|
|
/// Part is a string literal, no replacement.
|
|
|
|
|
|
|
|
Literal(&'source str),
|
|
|
|
|
|
|
|
/// Specifically for escaped characters (e.g. `"%%"` -> `'%'`)
|
|
|
|
|
|
|
|
Escaped(char),
|
|
|
|
|
|
|
|
/// Part is `%[S..E]n`: Filename (not path, just the file *name*.)
|
|
|
|
|
|
|
|
Filename(PathTokenOpt),
|
|
|
|
|
|
|
|
/// Part is `%[S..E]p`: *Full* path.
|
|
|
|
|
|
|
|
Path(PathTokenOpt),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: Add rest...
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<'source> ParseToken for Token<'source> {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: Add forwarding impl for each variant (where needed, like `Filename` & `Path`; for literals and escapes this can be handled here.)
|
|
|
|
|
|
|
|
// XXX: `visit()` can be implemented without forwarding since implementors like `PathTokenOpt` can be invariant wrt. the thing they're operating on.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//XXX: How are we going to define `Self::Substitute` here??? I think maybe having `Token` as an enum is not going to work here...
|
|
|
|
|
|
|
|
//TODO: We might need to do this with `dyn ParseToken` and have `Format::tokens: Vec<Box<dyn ParseToken + 'input>>` instead or something...
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A parsed format-string whose values are replaced with that of the target file when comparing via order.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// TODO: See if we can make it work as `<&[&dyn AsRef<str> + PartialOrd<str> + '_] as PartialOrd>` or something in implementation to avoid allocating where possible when substituting the parsed tokens (order each split part of the string)
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
|
|
|
|
pub struct Format<'input> {
|
|
|
|
|
|
|
|
/// The parsed tokens
|
|
|
|
|
|
|
|
tokens: Vec<Token<'input>>,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: How to design this type...? See above `ParseToken` trait & its impl for `Token<'source>`...
|
|
|
|
|
|
|
|
}
|