Commit graph

96 commits

Author SHA1 Message Date
Yuya Nishihara
a4be118981 templater: check number of method arguments 2023-02-05 11:53:11 +09:00
Yuya Nishihara
28c1989257 templater: add helper to extract argument pairs 2023-02-05 11:53:11 +09:00
Yuya Nishihara
945f9c1552 templater: pass parse_keyword() down to method parsing functions
It's needed to parse argument expressions.
2023-02-05 11:53:11 +09:00
Yuya Nishihara
db172aa7c9 templater: process property composition by parse_<type>_method()
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.
2023-02-05 11:53:11 +09:00
Yuya Nishihara
bdf809c6c3 templater: do not turn method arguments into iterator by caller
parse_<type>_method() will need args_pair.as_span() to report invalid
argument error.
2023-02-05 11:53:11 +09:00
Yuya Nishihara
5072469eca templater: extract generic parsing functions
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.
2023-02-05 11:53:11 +09:00
Yuya Nishihara
1b78fb5b5d templater: add shorthand for Result<T, TemplateParseError>
This will appear in "impl Fn(..) -> .." and we can't alias it.
2023-02-05 11:53:11 +09:00
Yuya Nishihara
13b5661094 templater: add separate(sep, contents...) function
This is a copy of Mercurial's separate() function.
2023-02-04 15:19:02 +09:00
Yuya Nishihara
5850575d53 templater: add separate variants for exact/range argument count errors
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.
2023-02-04 15:19:02 +09:00
Yuya Nishihara
e2eda9f72f templater: inline "current_working_copy" keyword
Maybe I didn't make this change before because the closure needs to capture
WorkspaceId by value. Since the inlined version looks pretty simple, let's
go forward to do that.
2023-02-04 01:58:13 +09:00
Yuya Nishihara
45a018ec6b templater: report invalid argument count as error
We'll probably need a helper to extract N..M arguments, but let's revisit
it later.
2023-02-03 12:06:04 +09:00
Yuya Nishihara
baf911459f templater: report invalid argument type as error 2023-02-03 12:06:04 +09:00
Yuya Nishihara
4eff802d87 templater: report keyword/function/method name error 2023-02-03 12:06:04 +09:00
Yuya Nishihara
8653cc885a templater: wrap inner parsing functions with Result<T> 2023-02-03 12:06:04 +09:00
Yuya Nishihara
7090fa0374 templater: report syntax error, don't panic()
Even though the template syntax is experimental, panicking parser makes
it difficult to write tests. So let's add minimal error handling. The error
types are basically copied from the revset module.

I made write_commit_summary() fall back to the default template if user
template had syntax error. It should be better than reporting parse error
after e.g. "jj abandon" finished successfully.
2023-02-03 12:06:04 +09:00
Yuya Nishihara
d6592573d0 templater: abstract Dynamic/LabelTemplate over labels type, unify them 2023-02-02 01:12:23 +09:00
Yuya Nishihara
1911734acc templater: add wrapper that turns template back to string property
I have no idea whether or not any template expressions are intentionally
allowed as a label, but it makes sense to write something like
'label("phase-" phase, ...)' (if we had a phase keyword.) So I decided to
add .into_plain_text() instead of stricter .try_into_string().
2023-02-02 01:12:23 +09:00
Yuya Nishihara
6da43734cb templater: migrate trivial commit keywords to closure wrapper
Perhaps, non-trivial keywords can be extracted to free functions, and both
parsing and property functions can be eventually moved to a commit templater
module?
2023-02-01 17:54:35 +09:00
Yuya Nishihara
e4cb1afd61 templater: fix crash on "".first_line() 2023-02-01 16:13:43 +09:00
Yuya Nishihara
259314b442 templater: reuse parse_commit_term() to coerce if() condition to bool
This should fix some inconsistent parsing of condition term.
2023-02-01 10:25:28 +09:00
Yuya Nishihara
553bee6ac4 templater: extract method that coerces property to boolean 2023-02-01 10:25:28 +09:00
Yuya Nishihara
5eee7186ba templater: add enum that holds property or template
This allows us to merge parse_boolean_commit_property() into
parse_commit_term(). We'll probably need similar type coercion methods
for the other basic types.

I considered adding something like Property::Template(), which could be
reused for map operation (e.g. 'revset().map(commit_id).join(" ")'.)
However, a mapped commit template would be different from the top-level
commit template regarding the lifetime of the context.
"Expression::<Commit>::Template()" takes "for<'b> &'b Commit" as an argument,
whereas a mapped template property would capture Commit object somewhere.
2023-02-01 10:25:28 +09:00
Yuya Nishihara
8d7ba8ddd3 templater: extract PropertyAndLabels::into_template() 2023-02-01 10:25:28 +09:00
Yuya Nishihara
41afdd48c7 templater: reorder declaration of PropertyAndLabels struct 2023-02-01 10:25:28 +09:00
Yuya Nishihara
f1e6146d6d templater: add newtype to implement property over closure
Many template keywords and methods are one liners, and I think that's actually
good because writing tests for templater would be more involved than for pure
functions.

This patch introduces a wrapper for such one-line functions, and migrates
method parser to that. Some of the commit keyword structs can also be ported
to this wrapper.
2023-01-31 16:27:52 +09:00
Ilya Grigoriev
26cc290157 Templater: Create shortest_styled_prefix function for ids 2023-01-30 22:48:38 -08:00
Ilya Grigoriev
3ee87aa5a7 Rename short => shortest 2023-01-30 22:48:38 -08:00
Martin von Zweigbergk
6cf7d98465 templater: replace is_git_head keyword by git_head keyword
I'm about to make it possible for `HEAD@git` to be conflicted. For
that, we need to be able to include the trailing `?`. This patch
prepares for that.
2023-01-30 09:05:03 -08:00
Yuya Nishihara
3d965f22ab templater: disallow empty template in function arguments and parens
Before, "f()" was parsed as a function call with one empty argument. In
practice, this change means "if(divergent,,false_template)" is no longer
valid.
2023-01-30 12:50:40 +09:00
Yuya Nishihara
a5bb48d47e templater: introduce top-level rule that wraps template terms
An epsilon rule will be moved here to disambiguate f() with f("").
2023-01-30 12:50:40 +09:00
Yuya Nishihara
c44dda55e3 templater: extract function arguments to inner node
This should help to represent an empty argument properly.
2023-01-30 12:50:40 +09:00
Yuya Nishihara
62def97f58 templater: remove redundant boxing of single template term
It was a copy-paste error.
2023-01-30 12:50:40 +09:00
Yuya Nishihara
a3d3947499 templater: move epsilon rule out of term rule
Suppose "template" is a sequence of "term"s, it makes more sense to handle
an empty sequence there. It might be even better to disallow empty template
other than the top-level one.
2023-01-29 08:54:14 +09:00
Yuya Nishihara
d1281ef48e templater: ensure "template" node is passed to parse_commit_template_rule()
Assertion will be added by the next commit.
2023-01-29 08:54:14 +09:00
Yuya Nishihara
bf66beab36 templater: fix parsing of parenthesized expression
A "list" is a sequence of more than one "term" nodes, so it shouldn't contain
a single parenthesized node.

Also, a parenthesized "term" rule wasn't handled.
2023-01-29 08:54:14 +09:00
Yuya Nishihara
f7993f0fe9 templater: eliminate whitespace nodes from parse tree 2023-01-29 08:54:14 +09:00
Yuya Nishihara
29eb7a16b8 templater: process method chaining from left to right
A method call is typically left associative, and LTR processing is simpler.
2023-01-28 10:53:03 +09:00
Yuya Nishihara
2ae892efab templater: reuse function rule to represent a method chain
A method call is typically parsed as (obj.meth)(), not as obj.(meth()),
but the latter is good enough for our needs. It's unlikely we'll add a
first-class function support.

.into_inner().next().unwrap() mess will be cleaned up by the next commit.
2023-01-28 10:53:03 +09:00
Yuya Nishihara
2c4856c47b templater: remove Box<dyn> from generic wrappers, parameterize type
This basically removes 'a lifetime from these wrappers, and add trait bounds
instead. I have no idea which version would look less scary, but let's see.

I also added trait bounds to constructor functions. They aren't strictly
required, but help type inference of closure (and will probably improve
an error message.)
2023-01-26 23:42:13 +09:00
Yuya Nishihara
8163b87a54 templater: store repo in CommitOrChangeId struct
This one was the outlier, and I think propagating 'repo' by context variable
is more correct.
2023-01-24 01:46:41 +09:00
Yuya Nishihara
e15b35ba56 templater: remove unused repo from CommitOrChangeIdShort 2023-01-24 01:46:41 +09:00
Yuya Nishihara
f47552b744 templater: turn output parameter of TemplateProperty into associated type
When implementing FormattablePropertyTemplate, I tried a generic 'property: P'
first, and I couldn't figure out how to constrain the output type.

    impl<C, O, P> Template<C> for FormattablePropertyTemplate<P>
    where
        P: TemplateProperty<C, O>, // 'O' isn't constrained by type
        O: Template<()>,

According to the book, the problem is that we can add multiple implementations
of 'TemplateProperty<C, *>'. Since TemplateProperty is basically a function
to extract data from 'C', I think the output parameter shouldn't be freely
chosen.

https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

With this change, I can express the type constraint as follows:

    impl<C, P> Template<C> for FormattablePropertyTemplate<P>
    where
        P: TemplateProperty<C>,
        P::Output: Template<()>,
2023-01-24 01:46:41 +09:00
Yuya Nishihara
4e661ecd40 templater: format context-less property value instead of coercing to string
This unblocks labeled outputs for these value types.
2023-01-23 15:23:26 +09:00
Yuya Nishihara
431395a7ee templater: generalize Literal/Constant wrapper for any context-less template
Now we have 'impl Template<()> for String', 'LiteralTemplate(String)' is
a bit redundant. Let's generalize it for any 'Template<()>'. I noticed
'ConstantTemplateProperty' serves as a similar role, so unified these.
2023-01-23 15:23:26 +09:00
Yuya Nishihara
c1f0ca9b5a templater: rewrite Property match arms with generic function
We might want to go further by rewriting the Property enum with trait, but
let's start small.
2023-01-23 15:23:26 +09:00
Yuya Nishihara
1a6e71170e templater: remove string.short() method
I think this is a remainder of 68ad712e12 "Templater: Combine Change and
Commit id templates." It doesn't make sense that description.short() prints
the first 12 characters.
2023-01-23 00:29:55 +09:00
Ilya Grigoriev
1bcdcea3ef Fix typo in function name 2023-01-20 22:05:33 -08:00
Yuya Nishihara
38e6924482 templater: move CommitOrChangeIdKeyword functions to CommitOrChangeId
CommitOrChangeIdKeyword is no longer needed.
2023-01-19 16:41:50 +09:00
Yuya Nishihara
bf58051c55 templater: split tag structs for commit_id/change_id property
These structs are basically functions taking &Commit, so there's no point
to abstract them.
2023-01-19 16:41:50 +09:00
Ilya Grigoriev
19d341d32a Templater: naive implementation of shortest prefix highlight for ids
This creates a templater function `short_underscore_prefix` for commit and
change ids. It is similar to `short` function, but shows one fewer hexadecimal
digit and inserts an underscore after the shortest unique prefix.

Highlighting with an underline and perhaps color/bold will be in a follow-up
PR.

The implementation is quadratic, a simple comparison of each id with every
other id. It is replaced in a subsequent commit. The problem with it is that,
while it works fine for a `jj`-sized repo, it becomes is painfully slow with a
repo the size of git/git. 

Still, this naive implemenation is included here since it's simple, and could
be used as a reference implementation. 

The `shortest_unique_prefix_length` function goes into `repo.rs` since that's
convenient for follow-up commits in this PR to have nicer diffs.
2023-01-17 22:01:09 -08:00