Option<P> allows us to embed optional argument property in tuple.
let maybe_arg = maybe_pair.map(|pair| parse(...))?;
chain_properties((self, maybe_arg), |_: &(Context, Option<_>)| ...)
For one optional argument, we can instead switch the property functions:
if let Some(pair) = maybe_pair {
let arg = pair.map(|pair| parse(...))?;
chain_properties((self, arg), |_: &(Context, _)| ...)
} else {
chain_properties(self, |_: &Context| ...)
}
If we have various combinations of optional arguments, using Option<P> would
be better.
For stock merge-tools, having name -> args indirection makes sense. For
user-specific settings, it's simpler to set command name and arguments
together.
It might be a bit odd that "name with whitespace" can be parsed differently
depending on the existence of merge-tools."name with whitespace".
This will be used as a parameter of id.shortest*() methods. For now, only
decimal literal is supported, and there's no unary negate operator.
"0"-prefix is disallowed because it looks like an octal number.
I don't think we would want multiple integer types in the template language,
so I chose i64 as the integer type of reasonable width.
A method call with arguments will be combined to (self, args...) tuple.
Unary tuple is useless, but is implemented for consistency.
This tuple_impls! macro is based off the serde one as the Rust core one
requires unstable feature.
This prepares for adding method arguments support. Since a method argument
should be evaluated in the surrounding scope, its type will be
'TemplateProperty<I>', not 'TemplateProperty<J>' for the receiver type 'J'.
Then, the receiver of type 'TemplateProperty<I, Output = J>', and arguments
of type 'TemplateProperty<I, Output = Pn>' will be composed to an input of
type 'TemplateProperty<I, Output = (J, Pn...)>'.
wrap_fn() is removed since it's only useful for nullary methods, and we
no longer need Box<dyn> to abstract the return value.
We'll probably need a better abstraction, but a parameterized keyword
function is a good first step. This unblocks the use of parse_term() for
context-less properties (or literals). I'm going to add a proper support
for context-aware method arguments, but literals can be parsed without it.
parse_keyword() closure is passed by reference to avoid infinite expansion.
It's hard to read dark blue on black, at least with iTerm2's default
color scheme. Cyan makes it much more readable. That's the color
`cargo` uses. We could also consider coloring only the "Hint:" part
like `cargo` does. For errors, `cargo` colors the "Error:" part red
and uses bold/bright white for select parts of the message.
This allows us to insert a separator between non-empty template fragments.
Since FormattablePropertyTemplate::has_content() needs to extract
a TemplateProperty, using this function means the property function will
be evaluated twice, one by .has_content() and later by .format(). The cost
is basically the same as 'if(prop, " " prop)'.
I believe this isn't a good abstraction, but I need to add one more variant
for "at least n arguments" error. A stringified count like "2 to 3" could be
embedded in an error variant, but I don't think it's good idea to build error
message in that way.
The way I added support for processing custom global arguments - by
using the existing `dispatch_fn` - meant that it wouldn't be run if
`CliRunner::add_global_args()` was called before
`CliRunner::add_subcommand()` and the custom subcommand wasn't
run. That's clearly not what I intended. This commit fixes that by
adding a separate list of functions for processing global args.
It's easier to mutate `self` than to create a new instance. It does
increase the risk of forgetting to update a field when adding a new
field or a new function, so maybe that's why @yuja did it this way?