This backs out commit 0de36918e4c020e0e54816f29c47cb57cc9cfbf5. Documentation,
tests, and comments are updated accordingly. I also add ConfigTableLike type
alias as we decided to abstract table-like items away.
Closes#5255
Before, "jj config get"/"list" and .get() functions processed inline tables as
tables (or directories in filesystem analogy), whereas "set"/"unset" processed
ones as values (or files.) This patch makes all commands and functions process
inline tables as values. We rarely use the inline table syntax, and it's very
hard to pack many (unrelated) values into an inline table. TOML doesn't allow
newlines between { .. }. Our common use case is to define color styles, which
wouldn't be meant to inherit attributes from the default settings.
The default pager setting is flattened in case user overrides pager.env without
changing the command args.
This patch does not change the handling of inline tables yet. Both inline and
non-inline tables are merged as before. OTOH, .set_value() is strict about table
types because it should refuse to overwrite a table whereas an inline table
should be overwritten as a value. This matches "jj config set"/"unset"
semantics. rules_from_config() in formatter.rs uses .as_inline_table(), which is
valid because toml_edit::Value type never contains non-inline table.
Since toml_edit::Value doesn't implement PartialEq, stacking tests now use
insta::assert_snapshot!().
Since most callers don't need to handle loading/parsing errors, it's probably
better to add a separate error type for "get" operations. The other uses of
ConfigError will be migrated later.
Since ConfigGetError can preserve the source name/path information, this patch
also removes some ad-hock error handling codes.
The added function is not "get_table(name) -> Result<Table, Error>" because
callers need to know whether the value was missing or shadowed by non-table
value. We just don't have this problem in template/revset-aliases because these
tables are top-level items.
Both user and programmatic expressions use the same .evaluate() function now.
optimize() is applied globally after symbol resolution. The order shouldn't
matter, but it might be nicer because union of commit refs could be rewritten
to a single Commits(Vec<CommitId>) node.
This helps add library API that takes resolved revset expressions. For example,
"jj absorb" will first compute annotation within a user-specified ancestor range
such as "mutable()". Because the range expression may contain symbols, it should
be resolved by caller.
There are two ideas to check resolution state at compile time:
<https://github.com/martinvonz/jj/pull/4374>
a. add RevsetExpressionWrapper<PhantomState> and guarantee inner tree
consistency at public API boundary
b. parameterize RevsetExpression variant types in a way that invalid variants
can never be constructed
(a) is nice if we want to combine "resolved" and "unresolved" expressions. The
inner expression types are the same, so we can just calculate new state as
Resolved & Unresolved = Unresolved. (b) is stricter as the compiler can
guarantee invariants. This patch implements (b) because there are no existing
callers who need to construct "resolved" expression and convert it to "user"
expression.
.evaluate_programmatic() now requires that the expression is resolved.
Custom backends may rely on networking or other unreliable implementations to support revsets, this change allows them to return errors cleanly instead of panicking.
For simplicity, only the public-facing Revset and RevsetGraph types are changed in this commit; the internal revset engine remains mostly unchanged and error-free since it cannot generally produce errors.
This patch replaces all call sites with present(trunk()), and adds an explicit
check for unresolvable trunk(). If we add coalesce() expression, maybe it can
be rewritten to coalesce(present(trunk()), builtin_trunk()).
Fixes#4616
Stacking at AliasExpanded node looks wonky. If we migrate error handling to
Diagnostics API, it might make sense to remove AliasExpanded node and add
node.aliases: vec![(id, span), ..] field instead.
Some closure arguments are inlined in order to help type inference.
This will help simplify warning handling in future patches. I'm going to add
deprecation warnings to revset, so Ui will be required in order to parse a user
revset expression.
revset_util::parse_immutable_expression() is inlined as it's a thin wrapper
around parse_immutable_heads_expression().
* Add `builtin_immutable_heads()` in the `revsets.toml`.
* Redefine `immutable_heads()` in terms of `builtin_immutable_heads()`
* Warn if user redefines `builtin_immutable_heads()`, `mutable()` or
`immutable()`.
* Update module constant in revset_util.rs from BUILTIN_IMMUTABLE_HEADS
to USER_IMMUTABLE_HEADS to avoid confusion since it points at
`immutable_heads()` **and** we now have a revset-alias
literally named `builtin_immutable_heads()`.
* Add unittest
* Update CHANGELOG
* Update documentation.
Fixes: #4162
Still alias function shadows builtin function (of any arity) by name. This
allows to detect argument error as such, but might be a bit inconvenient if
user wants to overload heads() for example. If needed, maybe we can add some
config/revset syntax to import builtin function to alias namespace.
The functions table is keyed by name, not by (name, arity) pair. That's mainly
because std collections require keys to be Borrow, and a pair of borrowed
values is incompatible with owned pair. Another reason is it makes easy to look
up overloads by name.
Alias overloading could also be achieved by adding default parameters, but that
will complicate the implementation a bit more, and can't prevent shadowing of
0-ary immutable_heads().
Closes#2966
I'm going to reorganize "single"/"default_single" revset functions in a way
that resolve_single_rev_with_hint_about_all_prefix() is inlined.
evaluate_revset_to_single_commit() could be a private method of
WorkspaceCommandHelper, but I want to minimize the code that has to be hosted
there.
Many callers of resolve_revset() and evaluate_revset() will be migrated to
this wrapper. "single" and "default_single" APIs won't be replaced because
they require more contexts to construct error messages.
id_prefix_context() now uses bare revset::parse() to avoid dependency cycle.
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.
It's inconsistent that some warnings have headings and some don't, and it seems
the choice is arbitrary. Let's unify the style. There are two exceptions:
1. continued line following labeled message,
2. "unrecognized response" followed by prompt.
AST substitution is technically closer to parsing, but the parsed expression
can be modified further by caller. So I think it's better to do optimize() in
later pass.
revset_util::parse() is inlined.
I just wanted to remove CommandError from parse_immutable_expression(), which
will be called from the templater, but the new error message looks also better.
Some of them will be called directly from the commit templater which shouldn't
know WorkspaceCommandHelper. All parameters are passed as function arguments
instead of having a nicer wrapper struct. That's because some resources (e.g.
repo and id prefix context) are also used for different purposes, and it seemed
uneasy to introduce high-level abstraction satisfying all the use cases.