This commit moves the parse_string_pattern helper function into the
str_util module in jj lib and adds tests for it.
I'd like to reuse this code in a function defined by `UserSettings`, which is
part of the jj lib crate and cannot use functions from the cli crate.
The idea is that, if .extract() succeeded in static context, it means the
property can be evaluated as constant. This will potentially eliminate
expect_string_literal_with(), though I'm not too sure if it's a good idea.
If needed, maybe we can extend the idea to suppress type/name resolution errors
by "if(some_static_config_knob, x, y)".
This allows us to propagate property evaluation error to a string property. For
instance, "s.contains(x ++ y)" will be an error if "y" failed to evaluate,
whereas bare "x ++ y" shouldn't.
The other implementation ideas:
a. add Template::into_string_property() to enable strict evaluation
=> it's tedious to implement it for each printable type
b. pass (formatter, error_handler) arguments separately
=> works, but most implementors don't need error_handler argument
c. pass strict=bool flag around build_*() functions
=> didn't tried, but it would be more complicated than this patch
Because Template trait is now implementation detail of the templater, it
should be okay to use a non-standard formatter wrapper.
Commands like `new`, `duplicate`, and `abandon` can take multiple revset
arguments which results in their collective union. They take the revisions
directly as arguments. But for consistency with many other commands, they can
also take the `-r` argument, which is a no-op. However, due to the flag being
specified as a `bool`, the `-r` option can only be specified once, so e.g.
`abandon -r x -r y` often fails. I normally use `-r` for consistency and muscle
memory, so this bites me often.
Instead, use `clap::ArgAction::Count` in order to allow `-r` to be specified
multiple times. It remains unused, of course.
With this change, all the following invocations are equivalent. Before this
change, the second example would fail due to giving `-r` multiple times.
jj abandon x y
jj abandon -r x -r y
jj abandon -r 'x | y'
Note: `jj new` already supported this exact case actually, but it used an
awkward trick where it used `.overrides_with()` in order to override *itself* so
it could be specified multiple times. I believe this is a bit clearer.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: Ib36cf81d46dae4f698f06d0a32e8fd3120bfb4a4
This makes the summary line more informative. Even though it just duplicates
the message printed later, I think it's easier to follow.
This patch also adjusts some RevsetParseError messages because it seemed
redundant to repeat "revset function", "argument", etc.
Because the CLI error handler now prints error sources in multi-line format,
it doesn't make much sense to render Revset/TemplateParseError differently.
This patch also fixes the source() of the SyntaxError kind. It should be
self.pest_error.source() (= None), not self.pest_error.
I'm going to make TemplateParseError hold RevsetParseError as Box<dyn _>, but
Box<dyn std::error::Error ..> doesn't implement Eq. I could remove Eq from
ErrorKind enums, but it's handly if these enums remain as value types.
This change will also simplify fmt::Display and error::Error impls.
It's common to normalize an empty directory path as ".". This change unblocks
the use of from_relative_path() in edit_sparse().
There are a couple of callers who do to_fs_path(Path::new("")), but they all
translate non-directory paths, which should never be empty.
This can be used to flatten nested "if()"s. It's not exactly the same as "case"
or "switch" expression, but works reasonably well in template. It's not uncommon
to show placeholder text in place of an empty content, and a nullish value
(e.g. empty string, list, option) is usually rendered as an empty text.
A formatted error is not a string containing ANSI escape sequences because 1.
the output may be differently colored inside "hint", 2. the caller might not
be accessible to ui.new_formatter().
We currently include the commits in `parent_mapping` and `abandoned`
in the set of commits to visit when rebasing descendants. The reason
was that we used to update branches and working copies when we visited
these commits. Since we started updating refs after rebasing all
commits, there's no need to even visit these commits.
We only use `new_commits` in `update_heads()`, so let's calculate it
there. It should also be more correct in case other commits were
created after we initialized `DescendantRebaser`.
Now that we only call `update_references()` in one place, there's no
reason to have it also update `heads_to_add` and `heads_to_remove`. By
moving it out of the function, we can consolidate the logic in one
place.
When `rebase_commit_with_options()` decides to abandons a commit, it
records the new parents in the `MutableRepo`, but it's currently the
caller's responsibility to remember to mark it as abandoned. Let's
move that logic into the function to reduce the risk of future bugs.
By adding the abandoned commit's parents to `parent_mapping`, we can
remove a bit more of the special handling of abandoned commitsin
`DescendantRebaser`.
Highlighting "{n}: " will help to follow error sources containing multi-line
messages. I'm going to make revset/template alias errors be formatted as plain
error chain.
In the normal case when we don't abandon a commit because it became
empty, then `CommitBuilder::write()` will have recorded the new commit
as a rewrite of the old commit. We don't need to do that again in
`rebase_one()`.
A subset of the state in `DescendantRebaser` now matches exactly what
`MutableRepo` already stores, so we can avoid copying that state and
have `DescendantRebaser` use it directly instead. Having a single
source of truth for the state will enable further simplifications and
improvements.
I'm going to make `DescendantRebaser` share the state about rewritten
commits with `MutableRepo` next. That means that the call to
`rebase_commit_with_options()` will update that state, which would
make this assertion fail. So let's move it a little earlier to avoid
that.
This is just to match `DescendantRebaser`, to make the next commit a
bit simpler. I think `MutableRepo` still has few enough fields that
just `abandoned` is clear enough. Maybe we'll move the three
rewrite-related fields into a new struct at some point.
With this patch, `MutableRepo` has the same tracking of rewritten
commits as `DescendantRebaser`, so we can simply pass that state into
`DescendantRebaser` when we create it. The next step is to remove the
state from `DescendantRebaser`.