Compare commits

..

6 Commits

Author SHA1 Message Date
Daniel Luz
87f6db0a70 completion: revset expression completer 2025-05-05 02:54:51 +00:00
Yuya Nishihara
8936a7bc4b templater: unify property conversion traits
We could define separate traits for conversion "from" and "to", but there aren't
many users who benefit from precise trait bounds.
2025-05-05 01:16:41 +00:00
Yuya Nishihara
780f9e547d templater: call property wrap_() functions directly, delete old forwarding fns
This patch replaces single-char L type aliases with P, and renames the L aliases
where that makes sense. Many of the P aliases will be removed later by
introducing generic wrap<T>() trait.
2025-05-05 01:16:41 +00:00
Yuya Nishihara
b611c313aa templater: move non-core wrap_*() functions to property types, leverage macro
Since the return type is now Self, we can reuse impl_wrap_property_fns!() macro
for non-core types.
2025-05-05 01:16:41 +00:00
Yuya Nishihara
7643364a76 templater: move core wrap_*() functions to property wrapper type
I think this was remainder of the old design where wrap_*() functions took
&TemplateLanguage as self argument. Since the wrapper type implements accessor
functions like .try_into_boolean(), it makes sense that the same type implements
::wrap_boolean(), etc.

These .wrap_<T>() functions will become generic over T.
2025-05-05 01:16:41 +00:00
Yuya Nishihara
577a484d1d templater: remove unneeded trait bound from build_lambda_expression()
This function just passes P down to the build_body() callback transparently.
2025-05-05 01:16:41 +00:00
49 changed files with 679 additions and 587 deletions

View File

@ -73,6 +73,11 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
* `jj config edit` will now roll back to previous version if a syntax error has been introduced in the new config.
* When using dynamic command-line completion, revision names will be completed
in more complex expressions. For example, typing
`jj log -r first-bookmark..sec` and then pressing Tab could complete the
expression to `first-bookmark..second-bookmark`.
### Fixed bugs

View File

@ -18,9 +18,9 @@ use std::rc::Rc;
use itertools::Itertools as _;
use jj_cli::cli_util::CliRunner;
use jj_cli::commit_templater::CommitTemplateBuildFnTable;
use jj_cli::commit_templater::CommitTemplateLanguage;
use jj_cli::commit_templater::CommitTemplateLanguageExtension;
use jj_cli::template_builder::TemplateLanguage as _;
use jj_cli::commit_templater::CommitTemplatePropertyKind;
use jj_cli::template_builder::CoreTemplatePropertyVar as _;
use jj_cli::template_parser;
use jj_cli::template_parser::TemplateParseError;
use jj_cli::templater::TemplatePropertyExt as _;
@ -121,7 +121,7 @@ impl SymbolResolverExtension for TheDigitest {
impl CommitTemplateLanguageExtension for HexCounter {
fn build_fn_table<'repo>(&self) -> CommitTemplateBuildFnTable<'repo> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
let mut table = CommitTemplateBuildFnTable::empty();
table.commit_methods.insert(
"has_most_digits",
@ -133,7 +133,7 @@ impl CommitTemplateLanguageExtension for HexCounter {
.count(language.repo());
let out_property =
property.map(move |commit| num_digits_in_id(commit.id()) == most_digits);
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
table.commit_methods.insert(
@ -141,7 +141,7 @@ impl CommitTemplateLanguageExtension for HexCounter {
|_language, _diagnostics, _build_context, property, call| {
call.expect_no_arguments()?;
let out_property = property.map(|commit| num_digits_in_id(commit.id()));
Ok(L::wrap_integer(out_property.into_dyn()))
Ok(P::wrap_integer(out_property.into_dyn()))
},
);
table.commit_methods.insert(
@ -161,7 +161,7 @@ impl CommitTemplateLanguageExtension for HexCounter {
})?;
let out_property = property.map(move |commit| num_char_in_id(commit, char_arg));
Ok(L::wrap_integer(out_property.into_dyn()))
Ok(P::wrap_integer(out_property.into_dyn()))
},
);

View File

@ -14,9 +14,9 @@
use jj_cli::cli_util::CliRunner;
use jj_cli::operation_templater::OperationTemplateBuildFnTable;
use jj_cli::operation_templater::OperationTemplateLanguage;
use jj_cli::operation_templater::OperationTemplateLanguageExtension;
use jj_cli::template_builder::TemplateLanguage as _;
use jj_cli::operation_templater::OperationTemplatePropertyKind;
use jj_cli::template_builder::CoreTemplatePropertyVar as _;
use jj_cli::template_parser;
use jj_cli::template_parser::TemplateParseError;
use jj_cli::templater::TemplatePropertyExt as _;
@ -49,14 +49,14 @@ fn num_char_in_id(operation: Operation, ch_match: char) -> i64 {
impl OperationTemplateLanguageExtension for HexCounter {
fn build_fn_table(&self) -> OperationTemplateBuildFnTable {
type L = OperationTemplateLanguage;
type P = OperationTemplatePropertyKind;
let mut table = OperationTemplateBuildFnTable::empty();
table.operation_methods.insert(
"num_digits_in_id",
|_language, _diagnostics, _build_context, property, call| {
call.expect_no_arguments()?;
let out_property = property.map(|operation| num_digits_in_id(operation.id()));
Ok(L::wrap_integer(out_property.into_dyn()))
Ok(P::wrap_integer(out_property.into_dyn()))
},
);
table.operation_methods.insert(
@ -77,7 +77,7 @@ impl OperationTemplateLanguageExtension for HexCounter {
let out_property =
property.map(move |operation| num_char_in_id(operation, char_arg));
Ok(L::wrap_integer(out_property.into_dyn()))
Ok(P::wrap_integer(out_property.into_dyn()))
},
);

View File

@ -152,6 +152,7 @@ use crate::command_error::user_error_with_hint;
use crate::command_error::CommandError;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplateLanguageExtension;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::config::config_from_environment;
use crate::config::parse_config_args;
@ -171,6 +172,7 @@ use crate::merge_tools::MergeEditor;
use crate::merge_tools::MergeToolConfigError;
use crate::operation_templater::OperationTemplateLanguage;
use crate::operation_templater::OperationTemplateLanguageExtension;
use crate::operation_templater::OperationTemplatePropertyKind;
use crate::revset_util;
use crate::revset_util::RevsetExpressionEvaluator;
use crate::template_builder;
@ -1738,7 +1740,7 @@ to the current parents may contain changes from multiple commits.
ui,
&language,
template_text,
CommitTemplateLanguage::wrap_commit,
CommitTemplatePropertyKind::wrap_commit,
)
}
@ -1753,7 +1755,7 @@ to the current parents may contain changes from multiple commits.
ui,
&language,
template_text,
OperationTemplateLanguage::wrap_operation,
OperationTemplatePropertyKind::wrap_operation,
)
}
@ -1778,7 +1780,7 @@ to the current parents may contain changes from multiple commits.
self.reparse_valid_template(
&language,
&self.commit_summary_template_text,
CommitTemplateLanguage::wrap_commit,
CommitTemplatePropertyKind::wrap_commit,
)
}
@ -1788,7 +1790,7 @@ to the current parents may contain changes from multiple commits.
self.reparse_valid_template(
&language,
&self.op_summary_template_text,
OperationTemplateLanguage::wrap_operation,
OperationTemplatePropertyKind::wrap_operation,
)
.labeled("operation")
}
@ -1798,7 +1800,7 @@ to the current parents may contain changes from multiple commits.
self.reparse_valid_template(
&language,
SHORT_CHANGE_ID_TEMPLATE_TEXT,
CommitTemplateLanguage::wrap_commit,
CommitTemplatePropertyKind::wrap_commit,
)
}
@ -2460,7 +2462,7 @@ impl WorkspaceCommandTransaction<'_> {
self.helper.reparse_valid_template(
&language,
&self.helper.commit_summary_template_text,
CommitTemplateLanguage::wrap_commit,
CommitTemplatePropertyKind::wrap_commit,
)
}
@ -2486,7 +2488,7 @@ impl WorkspaceCommandTransaction<'_> {
ui,
&language,
template_text,
CommitTemplateLanguage::wrap_commit,
CommitTemplatePropertyKind::wrap_commit,
)
}

View File

@ -16,7 +16,7 @@ use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Write as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::backend::CommitId;
use jj_lib::commit::CommitIteratorExt as _;
@ -47,14 +47,14 @@ pub(crate) struct AbandonArgs {
/// The revision(s) to abandon (default: @)
#[arg(
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revisions_pos: Vec<RevisionArg>,
#[arg(
short = 'r',
hide = true,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revisions_opt: Vec<RevisionArg>,
// TODO: Remove in jj 0.34+

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use jj_lib::absorb::absorb_hunks;
use jj_lib::absorb::split_hunks_to_trees;
use jj_lib::absorb::AbsorbSource;
@ -46,7 +46,7 @@ pub(crate) struct AbsorbArgs {
long, short,
default_value = "@",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
from: RevisionArg,
/// Destination revisions to absorb into
@ -56,7 +56,7 @@ pub(crate) struct AbsorbArgs {
long, short = 't', visible_alias = "to",
default_value = "mutable()",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
into: Vec<RevisionArg>,
/// Move only changes to these paths (instead of all paths)

View File

@ -13,7 +13,7 @@
// limitations under the License.
use bstr::ByteVec as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::object_id::ObjectId as _;
use jj_lib::rewrite::merge_commit_trees;
@ -38,7 +38,7 @@ pub(crate) struct BackoutArgs {
long, short,
default_value = "@",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revisions: Vec<RevisionArg>,
/// The revision to apply the reverse changes on top of
@ -48,7 +48,7 @@ pub(crate) struct BackoutArgs {
long, short,
default_value = "@",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
destination: Vec<RevisionArg>,
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::object_id::ObjectId as _;
use jj_lib::op_store::RefTarget;
@ -41,7 +41,7 @@ pub struct BookmarkCreateArgs {
long, short,
visible_alias = "to",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revision: Option<RevisionArg>,

View File

@ -33,7 +33,7 @@ use crate::cli_util::CommandHelper;
use crate::cli_util::RevisionArg;
use crate::command_error::CommandError;
use crate::commit_templater::CommitRef;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::ui::Ui;
@ -184,7 +184,7 @@ pub fn cmd_bookmark_list(
ui,
&language,
&text,
CommitTemplateLanguage::wrap_commit_ref,
CommitTemplatePropertyKind::wrap_commit_ref,
)?
.labeled("bookmark_list")
};

View File

@ -13,6 +13,7 @@
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::object_id::ObjectId as _;
use jj_lib::op_store::RefTarget;
@ -47,7 +48,7 @@ pub struct BookmarkMoveArgs {
long, short,
group = "source",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
from: Vec<RevisionArg>,
@ -58,7 +59,7 @@ pub struct BookmarkMoveArgs {
#[arg(
long, short,
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
to: Option<RevisionArg>,

View File

@ -13,6 +13,7 @@
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::object_id::ObjectId as _;
use jj_lib::op_store::RefTarget;
@ -40,7 +41,7 @@ pub struct BookmarkSetArgs {
long, short,
visible_alias = "to",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revision: Option<RevisionArg>,

View File

@ -22,7 +22,7 @@ use crate::cli_util::CommandHelper;
use crate::cli_util::RemoteBookmarkNamePattern;
use crate::command_error::CommandError;
use crate::commit_templater::CommitRef;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::ui::Ui;
@ -97,7 +97,7 @@ pub fn cmd_bookmark_track(
ui,
&language,
&text,
CommitTemplateLanguage::wrap_commit_ref,
CommitTemplatePropertyKind::wrap_commit_ref,
)?
.labeled("bookmark_list")
};

View File

@ -25,7 +25,9 @@ use crate::complete;
use crate::config::resolved_config_values;
use crate::config::AnnotatedValue;
use crate::generic_templater::GenericTemplateLanguage;
use crate::template_builder::TemplateLanguage as _;
use crate::generic_templater::GenericTemplatePropertyKind;
use crate::template_builder::CoreTemplatePropertyVar as _;
use crate::template_builder::TemplateLanguage;
use crate::templater::TemplatePropertyExt as _;
use crate::ui::Ui;
@ -83,7 +85,7 @@ pub fn cmd_config_list(
None => command.settings().get_string("templates.config_list")?,
};
command
.parse_template(ui, &language, &text, GenericTemplateLanguage::wrap_self)?
.parse_template(ui, &language, &text, GenericTemplatePropertyKind::wrap_self)?
.labeled("config_list")
};
@ -118,25 +120,25 @@ pub fn cmd_config_list(
Ok(())
}
type ConfigTemplateLanguage = GenericTemplateLanguage<'static, AnnotatedValue>;
// AnnotatedValue will be cloned internally in the templater. If the cloning
// cost matters, wrap it with Rc.
fn config_template_language(
settings: &UserSettings,
) -> GenericTemplateLanguage<'static, AnnotatedValue> {
type L = GenericTemplateLanguage<'static, AnnotatedValue>;
let mut language = L::new(settings);
fn config_template_language(settings: &UserSettings) -> ConfigTemplateLanguage {
type P = <ConfigTemplateLanguage as TemplateLanguage<'static>>::Property;
let mut language = ConfigTemplateLanguage::new(settings);
language.add_keyword("name", |self_property| {
let out_property = self_property.map(|annotated| annotated.name.to_string());
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
});
language.add_keyword("value", |self_property| {
// .decorated("", "") to trim leading/trailing whitespace
let out_property = self_property.map(|annotated| annotated.value.decorated("", ""));
Ok(L::wrap_config_value(out_property.into_dyn()))
Ok(P::wrap_config_value(out_property.into_dyn()))
});
language.add_keyword("source", |self_property| {
let out_property = self_property.map(|annotated| annotated.source.to_string());
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
});
language.add_keyword("path", |self_property| {
let out_property = self_property.map(|annotated| {
@ -146,11 +148,11 @@ fn config_template_language(
.as_ref()
.map_or_else(String::new, |path| path.to_string_lossy().into_owned())
});
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
});
language.add_keyword("overridden", |self_property| {
let out_property = self_property.map(|annotated| annotated.is_overridden);
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
});
language
}

View File

@ -17,7 +17,7 @@ use std::io;
use std::io::Read as _;
use std::iter;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::backend::Signature;
use jj_lib::commit::CommitIteratorExt as _;
@ -49,14 +49,14 @@ pub(crate) struct DescribeArgs {
/// The revision(s) whose description to edit (default: @)
#[arg(
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable)
)]
revisions_pos: Vec<RevisionArg>,
#[arg(
short = 'r',
hide = true,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable)
)]
revisions_opt: Vec<RevisionArg>,
/// The change description to use (don't open editor)

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use indexmap::IndexSet;
use itertools::Itertools as _;
@ -63,7 +62,7 @@ pub(crate) struct DiffArgs {
short,
value_name = "REVSETS",
alias = "revision",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revisions: Option<Vec<RevisionArg>>,
/// Show changes from this revision
@ -72,7 +71,7 @@ pub(crate) struct DiffArgs {
short,
conflicts_with = "revisions",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
from: Option<RevisionArg>,
/// Show changes to this revision
@ -81,7 +80,7 @@ pub(crate) struct DiffArgs {
short,
conflicts_with = "revisions",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
to: Option<RevisionArg>,
/// Restrict the diff to these paths

View File

@ -14,7 +14,7 @@
use std::io::Write as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::matchers::EverythingMatcher;
use jj_lib::object_id::ObjectId as _;
@ -54,7 +54,7 @@ pub(crate) struct DiffeditArgs {
long,
short,
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revision: Option<RevisionArg>,
/// Show changes from this revision
@ -64,7 +64,7 @@ pub(crate) struct DiffeditArgs {
long, short,
conflicts_with = "revision",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
from: Option<RevisionArg>,
/// Edit changes in this revision
@ -74,7 +74,7 @@ pub(crate) struct DiffeditArgs {
long, short,
conflicts_with = "revision",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
to: Option<RevisionArg>,
/// Specify diff editor to be used

View File

@ -15,7 +15,7 @@
use std::io::Write as _;
use bstr::ByteVec as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::backend::BackendResult;
use jj_lib::backend::CommitId;
@ -56,14 +56,14 @@ pub(crate) struct DuplicateArgs {
/// The revision(s) to duplicate (default: @)
#[arg(
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revisions_pos: Vec<RevisionArg>,
#[arg(
short = 'r',
hide = true,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revisions_opt: Vec<RevisionArg>,
/// The revision(s) to duplicate onto (can be repeated to create a merge
@ -72,7 +72,7 @@ pub(crate) struct DuplicateArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
destination: Option<Vec<RevisionArg>>,
/// The revision(s) to insert after (can be repeated to create a merge
@ -83,7 +83,7 @@ pub(crate) struct DuplicateArgs {
visible_alias = "after",
conflicts_with = "destination",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
insert_after: Option<Vec<RevisionArg>>,
/// The revision(s) to insert before (can be repeated to create a merge
@ -94,7 +94,7 @@ pub(crate) struct DuplicateArgs {
visible_alias = "before",
conflicts_with = "destination",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
insert_before: Option<Vec<RevisionArg>>,
}

View File

@ -14,7 +14,7 @@
use std::io::Write as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use jj_lib::object_id::ObjectId as _;
use tracing::instrument;
@ -34,7 +34,7 @@ use crate::ui::Ui;
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct EditArgs {
/// The commit to edit
#[arg(value_name = "REVSET", add = ArgValueCandidates::new(complete::mutable_revisions))]
#[arg(value_name = "REVSET", add = ArgValueCompleter::new(complete::revset_expression_mutable))]
revision: RevisionArg,
/// Ignored (but lets you pass `-r` for consistency with other commands)
#[arg(short = 'r', hide = true)]

View File

@ -15,6 +15,7 @@
use std::convert::Infallible;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::commit::Commit;
use jj_lib::dag_walk::topo_order_reverse_ok;
@ -29,7 +30,7 @@ use crate::cli_util::CommandHelper;
use crate::cli_util::LogContentFormat;
use crate::cli_util::RevisionArg;
use crate::command_error::CommandError;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::diff_util::DiffFormatArgs;
use crate::graphlog::get_graphlog;
@ -46,7 +47,7 @@ pub(crate) struct EvologArgs {
long, short,
default_value = "@",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revision: RevisionArg,
/// Limit number of revisions to show
@ -114,7 +115,7 @@ pub(crate) fn cmd_evolog(
ui,
&language,
&template_string,
CommitTemplateLanguage::wrap_commit,
CommitTemplatePropertyKind::wrap_commit,
)?
.labeled("log");
node_template = workspace_command
@ -122,7 +123,7 @@ pub(crate) fn cmd_evolog(
ui,
&language,
&get_node_template(graph_style, workspace_command.settings())?,
CommitTemplateLanguage::wrap_commit_opt,
CommitTemplatePropertyKind::wrap_commit_opt,
)?
.labeled("node");
}

View File

@ -25,7 +25,7 @@ use crate::cli_util::RevisionArg;
use crate::command_error::user_error;
use crate::command_error::CommandError;
use crate::commit_templater::AnnotationLine;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::templater::TemplateRenderer;
use crate::ui::Ui;
@ -47,7 +47,7 @@ pub(crate) struct FileAnnotateArgs {
long,
short,
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revision: Option<RevisionArg>,
/// Render each line using the given template
@ -101,7 +101,7 @@ pub(crate) fn cmd_file_annotate(
ui,
&language,
&template_text,
CommitTemplateLanguage::wrap_annotation_line,
CommitTemplatePropertyKind::wrap_annotation_line,
)?;
// TODO: Should we add an option to limit the domain to e.g. recent commits?

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use jj_lib::backend::TreeValue;
use jj_lib::merged_tree::MergedTreeBuilder;
@ -50,7 +49,7 @@ pub(crate) struct FileChmodArgs {
long, short,
default_value = "@",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revision: RevisionArg,
/// Paths to change the executable bit for

View File

@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use tracing::instrument;
use crate::cli_util::CommandHelper;
use crate::cli_util::RevisionArg;
use crate::command_error::CommandError;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::commit_templater::TreeEntry;
use crate::complete;
use crate::ui::Ui;
@ -31,7 +31,7 @@ pub(crate) struct FileListArgs {
long, short,
default_value = "@",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revision: RevisionArg,
@ -77,7 +77,7 @@ pub(crate) fn cmd_file_list(
ui,
&language,
&text,
CommitTemplateLanguage::wrap_tree_entry,
CommitTemplatePropertyKind::wrap_tree_entry,
)?
.labeled("file_list")
};

View File

@ -15,7 +15,6 @@
use std::io;
use std::io::Write as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use jj_lib::backend::BackendResult;
use jj_lib::conflicts::materialize_merge_result;
@ -49,7 +48,7 @@ pub(crate) struct FileShowArgs {
long, short,
default_value = "@",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revision: RevisionArg,
/// Paths to print

View File

@ -17,7 +17,7 @@ use std::io::Write as _;
use std::path::Path;
use std::process::Stdio;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::backend::CommitId;
use jj_lib::backend::FileId;
@ -108,7 +108,7 @@ pub(crate) struct FixArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
source: Vec<RevisionArg>,
/// Fix only these paths

View File

@ -160,7 +160,7 @@ pub struct GitPushArgs {
// While `-r` will often be used with mutable revisions, immutable
// revisions can be useful as parts of revsets or to push
// special-purpose branches.
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revisions: Vec<RevisionArg>,
/// Push this commit by creating a bookmark based on its change ID (can be
@ -177,7 +177,7 @@ pub struct GitPushArgs {
// recently created mutable revisions, even though it can in theory
// be used with immutable ones as well. We can change it if the guess
// turns out to be wrong.
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
change: Vec<RevisionArg>,
/// Specify a new bookmark name and a revision to push under that name, e.g.

View File

@ -15,7 +15,6 @@
use std::slice;
use clap::ArgGroup;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use tracing::instrument;
@ -41,7 +40,7 @@ pub(crate) struct InterdiffArgs {
long,
short,
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
from: Option<RevisionArg>,
/// Show changes to this revision
@ -49,7 +48,7 @@ pub(crate) struct InterdiffArgs {
long,
short,
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
to: Option<RevisionArg>,
/// Restrict the diff to these paths

View File

@ -35,7 +35,7 @@ use crate::cli_util::CommandHelper;
use crate::cli_util::LogContentFormat;
use crate::cli_util::RevisionArg;
use crate::command_error::CommandError;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::diff_util::DiffFormatArgs;
use crate::graphlog::get_graphlog;
@ -74,7 +74,7 @@ pub(crate) struct LogArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revisions: Vec<RevisionArg>,
/// Show revisions modifying the given paths
@ -176,7 +176,7 @@ pub(crate) fn cmd_log(
ui,
&language,
&template_string,
CommitTemplateLanguage::wrap_commit,
CommitTemplatePropertyKind::wrap_commit,
)?
.labeled("log");
node_template = workspace_command
@ -184,7 +184,7 @@ pub(crate) fn cmd_log(
ui,
&language,
&get_node_template(graph_style, settings)?,
CommitTemplateLanguage::wrap_commit_opt,
CommitTemplatePropertyKind::wrap_commit_opt,
)?
.labeled("node");
}

View File

@ -15,7 +15,7 @@
use std::collections::HashSet;
use std::io::Write as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::backend::CommitId;
use jj_lib::repo::Repo as _;
@ -49,7 +49,7 @@ pub(crate) struct NewArgs {
#[arg(
default_value = "@",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revisions: Option<Vec<RevisionArg>>,
/// Ignored (but lets you pass `-d`/`-r` for consistency with other
@ -98,7 +98,7 @@ pub(crate) struct NewArgs {
conflicts_with = "revisions",
value_name = "REVSETS",
verbatim_doc_comment,
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
insert_after: Option<Vec<RevisionArg>>,
/// Insert the new change before the given commit(s)
@ -137,7 +137,7 @@ pub(crate) struct NewArgs {
conflicts_with = "revisions",
value_name = "REVSETS",
verbatim_doc_comment,
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
insert_before: Option<Vec<RevisionArg>>,
}

View File

@ -40,7 +40,7 @@ use jj_lib::revset::RevsetIteratorExt as _;
use crate::cli_util::CommandHelper;
use crate::cli_util::LogContentFormat;
use crate::command_error::CommandError;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::diff_util::diff_formats_for_log;
use crate::diff_util::DiffFormatArgs;
@ -132,7 +132,12 @@ pub fn cmd_op_diff(
let commit_summary_template = {
let language = workspace_env.commit_template_language(merged_repo, &id_prefix_context);
let text = settings.get_string("templates.commit_summary")?;
workspace_env.parse_template(ui, &language, &text, CommitTemplateLanguage::wrap_commit)?
workspace_env.parse_template(
ui,
&language,
&text,
CommitTemplatePropertyKind::wrap_commit,
)?
};
let op_summary_template = workspace_command.operation_summary_template();

View File

@ -32,7 +32,7 @@ use crate::cli_util::CommandHelper;
use crate::cli_util::LogContentFormat;
use crate::cli_util::WorkspaceCommandEnvironment;
use crate::command_error::CommandError;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::diff_util::diff_formats_for_log;
use crate::diff_util::DiffFormatArgs;
@ -41,6 +41,7 @@ use crate::formatter::Formatter;
use crate::graphlog::get_graphlog;
use crate::graphlog::GraphStyle;
use crate::operation_templater::OperationTemplateLanguage;
use crate::operation_templater::OperationTemplatePropertyKind;
use crate::ui::Ui;
/// Show the operation log
@ -139,7 +140,7 @@ fn do_op_log(
ui,
&language,
&text,
OperationTemplateLanguage::wrap_operation,
OperationTemplatePropertyKind::wrap_operation,
)?
.labeled("operation")
.labeled("op_log");
@ -148,7 +149,7 @@ fn do_op_log(
ui,
&language,
&get_node_template(graph_style, settings)?,
OperationTemplateLanguage::wrap_operation,
OperationTemplatePropertyKind::wrap_operation,
)?
.labeled("node");
}
@ -173,7 +174,7 @@ fn do_op_log(
ui,
&language,
&template_text,
CommitTemplateLanguage::wrap_commit,
CommitTemplatePropertyKind::wrap_commit,
)?
};
let path_converter = workspace_env.path_converter();

View File

@ -19,7 +19,7 @@ use super::diff::show_op_diff;
use crate::cli_util::CommandHelper;
use crate::cli_util::LogContentFormat;
use crate::command_error::CommandError;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::diff_util::diff_formats_for_log;
use crate::diff_util::DiffFormatArgs;
@ -66,7 +66,12 @@ pub fn cmd_op_show(
let commit_summary_template = {
let language = workspace_env.commit_template_language(repo.as_ref(), &id_prefix_context);
let text = settings.get_string("templates.commit_summary")?;
workspace_env.parse_template(ui, &language, &text, CommitTemplateLanguage::wrap_commit)?
workspace_env.parse_template(
ui,
&language,
&text,
CommitTemplatePropertyKind::wrap_commit,
)?
};
let graph_style = GraphStyle::from_settings(settings)?;

View File

@ -14,7 +14,7 @@
use std::collections::HashMap;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use indexmap::IndexSet;
use itertools::Itertools as _;
use jj_lib::backend::CommitId;
@ -59,7 +59,7 @@ pub(crate) struct ParallelizeArgs {
/// Revisions to parallelize
#[arg(
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revisions: Vec<RevisionArg>,
}

View File

@ -16,7 +16,7 @@ use std::io::Write as _;
use std::sync::Arc;
use clap::ArgGroup;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::backend::CommitId;
use jj_lib::commit::Commit;
@ -278,7 +278,7 @@ pub(crate) struct RebaseArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
branch: Vec<RevisionArg>,
@ -294,7 +294,7 @@ pub(crate) struct RebaseArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
source: Vec<RevisionArg>,
/// Rebase the given revisions, rebasing descendants onto this revision's
@ -308,7 +308,7 @@ pub(crate) struct RebaseArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revisions: Vec<RevisionArg>,
@ -336,7 +336,7 @@ pub struct RebaseDestinationArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
destination: Option<Vec<RevisionArg>>,
/// The revision(s) to insert after (can be repeated to create a merge
@ -347,7 +347,7 @@ pub struct RebaseDestinationArgs {
visible_alias = "after",
conflicts_with = "destination",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
insert_after: Option<Vec<RevisionArg>>,
/// The revision(s) to insert before (can be repeated to create a merge
@ -358,7 +358,7 @@ pub struct RebaseDestinationArgs {
visible_alias = "before",
conflicts_with = "destination",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
insert_before: Option<Vec<RevisionArg>>,
}

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::object_id::ObjectId as _;
@ -50,7 +49,7 @@ pub(crate) struct ResolveArgs {
long, short,
default_value = "@",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revision: RevisionArg,
/// Instead of resolving conflicts, list all the conflicts

View File

@ -14,7 +14,6 @@
use std::io::Write as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use indoc::formatdoc;
use itertools::Itertools as _;
@ -58,7 +57,7 @@ pub(crate) struct RestoreArgs {
long,
short,
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
from: Option<RevisionArg>,
/// Revision to restore into (destination)
@ -66,7 +65,7 @@ pub(crate) struct RestoreArgs {
long, short = 't',
visible_alias = "to",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
into: Option<RevisionArg>,
/// Undo the changes in a revision as compared to the merge of its parents.
@ -81,7 +80,7 @@ pub(crate) struct RestoreArgs {
long, short,
value_name = "REVSET",
conflicts_with_all = ["into", "from"],
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
changes_in: Option<RevisionArg>,
/// Prints an error. DO NOT USE.

View File

@ -16,7 +16,7 @@ use std::collections::HashSet;
use bstr::ByteVec as _;
use clap::ArgGroup;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use indexmap::IndexSet;
use itertools::Itertools as _;
use jj_lib::backend::CommitId;
@ -48,14 +48,14 @@ pub(crate) struct RevertArgs {
#[arg(
long, short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revisions: Vec<RevisionArg>,
/// The revision(s) to apply the reverse changes on top of
#[arg(
long, short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
destination: Option<Vec<RevisionArg>>,
/// The revision(s) to insert the reverse changes after (can be repeated to
@ -66,7 +66,7 @@ pub(crate) struct RevertArgs {
visible_alias = "after",
conflicts_with = "destination",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::all_revisions),
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
insert_after: Option<Vec<RevisionArg>>,
/// The revision(s) to insert the reverse changes before (can be repeated to
@ -77,7 +77,7 @@ pub(crate) struct RevertArgs {
visible_alias = "before",
conflicts_with = "destination",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
insert_before: Option<Vec<RevisionArg>>,
}

View File

@ -13,6 +13,7 @@
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use jj_lib::matchers::EverythingMatcher;
use tracing::instrument;
@ -30,7 +31,7 @@ pub(crate) struct ShowArgs {
#[arg(
default_value = "@",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::all_revisions)
add = ArgValueCompleter::new(complete::revset_expression_all),
)]
revision: RevisionArg,
/// Ignored (but lets you pass `-r` for consistency with other commands)

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use indexmap::IndexSet;
use itertools::Itertools as _;
use jj_lib::commit::Commit;
@ -52,7 +52,7 @@ pub struct SignArgs {
#[arg(
long, short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revisions: Vec<RevisionArg>,

View File

@ -1,6 +1,6 @@
use std::collections::HashSet;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::backend::BackendError;
use jj_lib::revset::RevsetExpression;
@ -28,7 +28,7 @@ pub(crate) struct SimplifyParentsArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
source: Vec<RevisionArg>,
/// Simplify specified revision(s) (can be repeated)
@ -40,7 +40,7 @@ pub(crate) struct SimplifyParentsArgs {
long,
short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revisions: Vec<RevisionArg>,
}

View File

@ -13,7 +13,6 @@
// limitations under the License.
use std::io::Write as _;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use jj_lib::commit::Commit;
use jj_lib::matchers::Matcher;
@ -67,7 +66,7 @@ pub(crate) struct SplitArgs {
long, short,
default_value = "@",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revision: RevisionArg,
/// Split the revision into two parallel revisions instead of a parent and

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use indoc::formatdoc;
use itertools::Itertools as _;
@ -69,7 +68,7 @@ pub(crate) struct SquashArgs {
long,
short,
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions)
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revision: Option<RevisionArg>,
/// Revision(s) to squash from (default: @)
@ -77,7 +76,7 @@ pub(crate) struct SquashArgs {
long, short,
conflicts_with = "revision",
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
from: Vec<RevisionArg>,
/// Revision to squash into (default: @)
@ -86,7 +85,7 @@ pub(crate) struct SquashArgs {
conflicts_with = "revision",
visible_alias = "to",
value_name = "REVSET",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
into: Option<RevisionArg>,
/// The description to use for squashed revision (don't open editor)

View File

@ -18,7 +18,7 @@ use jj_lib::str_util::StringPattern;
use crate::cli_util::CommandHelper;
use crate::command_error::CommandError;
use crate::commit_templater::CommitRef;
use crate::commit_templater::CommitTemplateLanguage;
use crate::commit_templater::CommitTemplatePropertyKind;
use crate::complete;
use crate::ui::Ui;
@ -86,7 +86,7 @@ fn cmd_tag_list(
ui,
&language,
&text,
CommitTemplateLanguage::wrap_commit_ref,
CommitTemplatePropertyKind::wrap_commit_ref,
)?
.labeled("tag_list")
};

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use indexmap::IndexSet;
use itertools::Itertools as _;
use jj_lib::commit::Commit;
@ -38,7 +38,7 @@ pub struct UnsignArgs {
#[arg(
long, short,
value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions),
add = ArgValueCompleter::new(complete::revset_expression_mutable),
)]
revisions: Vec<RevisionArg>,
}

View File

@ -79,7 +79,7 @@ use crate::template_builder::merge_fn_map;
use crate::template_builder::BuildContext;
use crate::template_builder::CoreTemplateBuildFnTable;
use crate::template_builder::CoreTemplatePropertyKind;
use crate::template_builder::IntoTemplateProperty;
use crate::template_builder::CoreTemplatePropertyVar;
use crate::template_builder::TemplateBuildMethodFnMap;
use crate::template_builder::TemplateLanguage;
use crate::template_parser;
@ -164,8 +164,6 @@ impl<'repo> CommitTemplateLanguage<'repo> {
impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
type Property = CommitTemplatePropertyKind<'repo>;
template_builder::impl_core_wrap_property_fns!('repo, CommitTemplatePropertyKind::Core);
fn settings(&self) -> &UserSettings {
self.repo.base_repo().settings()
}
@ -213,8 +211,8 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
build_ctx,
property,
function,
Self::wrap_commit,
Self::wrap_commit_list,
Self::Property::wrap_commit,
Self::Property::wrap_commit_list,
)
}
CommitTemplatePropertyKind::CommitRef(property) => {
@ -237,8 +235,8 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
build_ctx,
property,
function,
Self::wrap_commit_ref,
Self::wrap_commit_ref_list,
Self::Property::wrap_commit_ref,
Self::Property::wrap_commit_ref_list,
)
}
CommitTemplatePropertyKind::RepoPath(property) => {
@ -281,8 +279,8 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
build_ctx,
property,
function,
Self::wrap_tree_diff_entry,
Self::wrap_tree_diff_entry_list,
Self::Property::wrap_tree_diff_entry,
Self::Property::wrap_tree_diff_entry_list,
)
}
CommitTemplatePropertyKind::TreeEntry(property) => {
@ -324,7 +322,7 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
expect_plain_text_expression(self, diagnostics, build_ctx, key_node)?;
let out_property = (property, key_property)
.map(|(trailers, key)| trailers.iter().any(|t| t.key == key));
Ok(Self::wrap_boolean(out_property.into_dyn()))
Ok(Self::Property::wrap_boolean(out_property.into_dyn()))
} else {
template_builder::build_formattable_list_method(
self,
@ -332,8 +330,8 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
build_ctx,
property,
function,
Self::wrap_trailer,
Self::wrap_trailer_list,
Self::Property::wrap_trailer,
Self::Property::wrap_trailer_list,
)
}
}
@ -359,120 +357,6 @@ impl<'repo> CommitTemplateLanguage<'repo> {
pub fn cache_extension<T: Any>(&self) -> Option<&T> {
self.cache_extensions.get::<T>()
}
pub fn wrap_commit(
property: BoxedTemplateProperty<'repo, Commit>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::Commit(property)
}
pub fn wrap_commit_opt(
property: BoxedTemplateProperty<'repo, Option<Commit>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::CommitOpt(property)
}
pub fn wrap_commit_list(
property: BoxedTemplateProperty<'repo, Vec<Commit>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::CommitList(property)
}
pub fn wrap_commit_ref(
property: BoxedTemplateProperty<'repo, Rc<CommitRef>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::CommitRef(property)
}
pub fn wrap_commit_ref_opt(
property: BoxedTemplateProperty<'repo, Option<Rc<CommitRef>>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::CommitRefOpt(property)
}
pub fn wrap_commit_ref_list(
property: BoxedTemplateProperty<'repo, Vec<Rc<CommitRef>>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::CommitRefList(property)
}
pub fn wrap_repo_path(
property: BoxedTemplateProperty<'repo, RepoPathBuf>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::RepoPath(property)
}
pub fn wrap_repo_path_opt(
property: BoxedTemplateProperty<'repo, Option<RepoPathBuf>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::RepoPathOpt(property)
}
pub fn wrap_commit_or_change_id(
property: BoxedTemplateProperty<'repo, CommitOrChangeId>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::CommitOrChangeId(property)
}
pub fn wrap_shortest_id_prefix(
property: BoxedTemplateProperty<'repo, ShortestIdPrefix>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::ShortestIdPrefix(property)
}
pub fn wrap_tree_diff(
property: BoxedTemplateProperty<'repo, TreeDiff>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::TreeDiff(property)
}
pub fn wrap_tree_diff_entry(
property: BoxedTemplateProperty<'repo, TreeDiffEntry>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::TreeDiffEntry(property)
}
pub fn wrap_tree_diff_entry_list(
property: BoxedTemplateProperty<'repo, Vec<TreeDiffEntry>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::TreeDiffEntryList(property)
}
pub fn wrap_tree_entry(
property: BoxedTemplateProperty<'repo, TreeEntry>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::TreeEntry(property)
}
pub fn wrap_diff_stats(
property: BoxedTemplateProperty<'repo, DiffStatsFormatted<'repo>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::DiffStats(property)
}
fn wrap_cryptographic_signature_opt(
property: BoxedTemplateProperty<'repo, Option<CryptographicSignature>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::CryptographicSignatureOpt(property)
}
pub fn wrap_annotation_line(
property: BoxedTemplateProperty<'repo, AnnotationLine>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::AnnotationLine(property)
}
pub fn wrap_trailer(
property: BoxedTemplateProperty<'repo, Trailer>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::Trailer(property)
}
pub fn wrap_trailer_list(
property: BoxedTemplateProperty<'repo, Vec<Trailer>>,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::TrailerList(property)
}
}
pub enum CommitTemplatePropertyKind<'repo> {
@ -498,7 +382,35 @@ pub enum CommitTemplatePropertyKind<'repo> {
TrailerList(BoxedTemplateProperty<'repo, Vec<Trailer>>),
}
impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> {
impl<'repo> CommitTemplatePropertyKind<'repo> {
template_builder::impl_wrap_property_fns!('repo, CommitTemplatePropertyKind, {
pub wrap_commit(Commit) => Commit,
pub wrap_commit_opt(Option<Commit>) => CommitOpt,
pub wrap_commit_list(Vec<Commit>) => CommitList,
pub wrap_commit_ref(Rc<CommitRef>) => CommitRef,
pub wrap_commit_ref_opt(Option<Rc<CommitRef>>) => CommitRefOpt,
pub wrap_commit_ref_list(Vec<Rc<CommitRef>>) => CommitRefList,
pub wrap_repo_path(RepoPathBuf) => RepoPath,
pub wrap_repo_path_opt(Option<RepoPathBuf>) => RepoPathOpt,
pub wrap_commit_or_change_id(CommitOrChangeId) => CommitOrChangeId,
pub wrap_shortest_id_prefix(ShortestIdPrefix) => ShortestIdPrefix,
pub wrap_tree_diff(TreeDiff) => TreeDiff,
pub wrap_tree_diff_entry(TreeDiffEntry) => TreeDiffEntry,
pub wrap_tree_diff_entry_list(Vec<TreeDiffEntry>) => TreeDiffEntryList,
pub wrap_tree_entry(TreeEntry) => TreeEntry,
pub wrap_diff_stats(DiffStatsFormatted<'repo>) => DiffStats,
pub wrap_cryptographic_signature_opt(
Option<CryptographicSignature>
) => CryptographicSignatureOpt,
pub wrap_annotation_line(AnnotationLine) => AnnotationLine,
pub wrap_trailer(Trailer) => Trailer,
pub wrap_trailer_list(Vec<Trailer>) => TrailerList,
});
}
impl<'repo> CoreTemplatePropertyVar<'repo> for CommitTemplatePropertyKind<'repo> {
template_builder::impl_core_wrap_property_fns!('repo, CommitTemplatePropertyKind::Core);
fn type_name(&self) -> &'static str {
match self {
CommitTemplatePropertyKind::Core(property) => property.type_name(),
@ -816,7 +728,7 @@ impl<'repo> CommitKeywordCache<'repo> {
}
fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Commit> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<Commit>::new();
@ -826,7 +738,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let out_property =
self_property.map(|commit| text_util::complete_newline(commit.description()));
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -835,7 +747,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let out_property = self_property
.map(|commit| trailer::parse_description_trailers(commit.description()));
Ok(L::wrap_trailer_list(out_property.into_dyn()))
Ok(P::wrap_trailer_list(out_property.into_dyn()))
},
);
map.insert(
@ -844,7 +756,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let out_property =
self_property.map(|commit| CommitOrChangeId::Change(commit.change_id().to_owned()));
Ok(L::wrap_commit_or_change_id(out_property.into_dyn()))
Ok(P::wrap_commit_or_change_id(out_property.into_dyn()))
},
);
map.insert(
@ -853,7 +765,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let out_property =
self_property.map(|commit| CommitOrChangeId::Commit(commit.id().to_owned()));
Ok(L::wrap_commit_or_change_id(out_property.into_dyn()))
Ok(P::wrap_commit_or_change_id(out_property.into_dyn()))
},
);
map.insert(
@ -862,7 +774,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let out_property =
self_property.and_then(|commit| Ok(commit.parents().try_collect()?));
Ok(L::wrap_commit_list(out_property.into_dyn()))
Ok(P::wrap_commit_list(out_property.into_dyn()))
},
);
map.insert(
@ -870,7 +782,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|commit| commit.author().clone());
Ok(L::wrap_signature(out_property.into_dyn()))
Ok(P::wrap_signature(out_property.into_dyn()))
},
);
map.insert(
@ -878,7 +790,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|commit| commit.committer().clone());
Ok(L::wrap_signature(out_property.into_dyn()))
Ok(P::wrap_signature(out_property.into_dyn()))
},
);
map.insert(
@ -887,7 +799,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let user_email = language.revset_parse_context.user_email.to_owned();
let out_property = self_property.map(move |commit| commit.author().email == user_email);
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -895,7 +807,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(CryptographicSignature::new);
Ok(L::wrap_cryptographic_signature_opt(out_property.into_dyn()))
Ok(P::wrap_cryptographic_signature_opt(out_property.into_dyn()))
},
);
map.insert(
@ -904,7 +816,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let repo = language.repo;
let out_property = self_property.map(|commit| extract_working_copies(repo, &commit));
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -915,7 +827,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
let name = language.workspace_name.clone();
let out_property = self_property
.map(move |commit| Some(commit.id()) == repo.view().get_wc_commit_id(&name));
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -934,7 +846,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
.cloned()
.collect()
});
Ok(L::wrap_commit_ref_list(out_property.into_dyn()))
Ok(P::wrap_commit_ref_list(out_property.into_dyn()))
},
);
map.insert(
@ -953,7 +865,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
.cloned()
.collect()
});
Ok(L::wrap_commit_ref_list(out_property.into_dyn()))
Ok(P::wrap_commit_ref_list(out_property.into_dyn()))
},
);
map.insert(
@ -972,7 +884,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
.cloned()
.collect()
});
Ok(L::wrap_commit_ref_list(out_property.into_dyn()))
Ok(P::wrap_commit_ref_list(out_property.into_dyn()))
},
);
map.insert(
@ -981,7 +893,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let index = language.keyword_cache.tags_index(language.repo).clone();
let out_property = self_property.map(move |commit| index.get(commit.id()).to_vec());
Ok(L::wrap_commit_ref_list(out_property.into_dyn()))
Ok(P::wrap_commit_ref_list(out_property.into_dyn()))
},
);
map.insert(
@ -990,7 +902,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let index = language.keyword_cache.git_refs_index(language.repo).clone();
let out_property = self_property.map(move |commit| index.get(commit.id()).to_vec());
Ok(L::wrap_commit_ref_list(out_property.into_dyn()))
Ok(P::wrap_commit_ref_list(out_property.into_dyn()))
},
);
map.insert(
@ -1002,7 +914,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
let target = repo.view().git_head();
target.added_ids().contains(commit.id())
});
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1015,7 +927,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
let maybe_entries = repo.resolve_change_id(commit.change_id());
maybe_entries.map_or(0, |entries| entries.len()) > 1
});
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1024,7 +936,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let repo = language.repo;
let out_property = self_property.map(|commit| commit.is_hidden(repo));
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1036,7 +948,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
.is_immutable_fn(language, function.name_span)?
.clone();
let out_property = self_property.and_then(move |commit| Ok(is_immutable(commit.id())?));
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1050,7 +962,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
})?;
let out_property = self_property.and_then(move |commit| Ok(is_contained(commit.id())?));
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1058,7 +970,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.and_then(|commit| Ok(commit.has_conflict()?));
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1067,7 +979,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
function.expect_no_arguments()?;
let repo = language.repo;
let out_property = self_property.and_then(|commit| Ok(commit.is_empty(repo)?));
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1085,7 +997,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
let matcher: Rc<dyn Matcher> = files.to_matcher().into();
let out_property = self_property
.and_then(move |commit| Ok(TreeDiff::from_commit(repo, &commit, matcher.clone())?));
Ok(L::wrap_tree_diff(out_property.into_dyn()))
Ok(P::wrap_tree_diff(out_property.into_dyn()))
},
);
map.insert(
@ -1095,7 +1007,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
let repo = language.repo;
let out_property =
self_property.map(|commit| commit.id() == repo.store().root_commit_id());
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map
@ -1385,7 +1297,7 @@ impl Template for Vec<Rc<CommitRef>> {
}
fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc<CommitRef>> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<Rc<CommitRef>>::new();
@ -1394,7 +1306,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|commit_ref| commit_ref.name.clone());
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -1403,7 +1315,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
function.expect_no_arguments()?;
let out_property =
self_property.map(|commit_ref| commit_ref.remote.clone().unwrap_or_default());
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -1411,7 +1323,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|commit_ref| commit_ref.is_present());
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1419,7 +1331,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|commit_ref| commit_ref.has_conflict());
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1431,7 +1343,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
let maybe_id = commit_ref.target.as_normal();
Ok(maybe_id.map(|id| repo.store().get_commit(id)).transpose()?)
});
Ok(L::wrap_commit_opt(out_property.into_dyn()))
Ok(P::wrap_commit_opt(out_property.into_dyn()))
},
);
map.insert(
@ -1443,7 +1355,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
let ids = commit_ref.target.removed_ids();
Ok(ids.map(|id| repo.store().get_commit(id)).try_collect()?)
});
Ok(L::wrap_commit_list(out_property.into_dyn()))
Ok(P::wrap_commit_list(out_property.into_dyn()))
},
);
map.insert(
@ -1455,7 +1367,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
let ids = commit_ref.target.added_ids();
Ok(ids.map(|id| repo.store().get_commit(id)).try_collect()?)
});
Ok(L::wrap_commit_list(out_property.into_dyn()))
Ok(P::wrap_commit_list(out_property.into_dyn()))
},
);
map.insert(
@ -1463,7 +1375,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|commit_ref| commit_ref.is_tracked());
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1471,7 +1383,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|commit_ref| commit_ref.is_tracking_present());
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -1481,7 +1393,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
let repo = language.repo;
let out_property =
self_property.and_then(|commit_ref| commit_ref.tracking_ahead_count(repo));
Ok(L::wrap_size_hint(out_property.into_dyn()))
Ok(P::wrap_size_hint(out_property.into_dyn()))
},
);
map.insert(
@ -1491,7 +1403,7 @@ fn builtin_commit_ref_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
let repo = language.repo;
let out_property =
self_property.and_then(|commit_ref| commit_ref.tracking_behind_count(repo));
Ok(L::wrap_size_hint(out_property.into_dyn()))
Ok(P::wrap_size_hint(out_property.into_dyn()))
},
);
map
@ -1556,7 +1468,7 @@ impl Template for RepoPathBuf {
}
fn builtin_repo_path_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, RepoPathBuf> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<RepoPathBuf>::new();
@ -1566,7 +1478,7 @@ fn builtin_repo_path_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, R
function.expect_no_arguments()?;
let path_converter = language.path_converter;
let out_property = self_property.map(|path| path_converter.format_file_path(&path));
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -1574,7 +1486,7 @@ fn builtin_repo_path_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, R
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|path| Some(path.parent()?.to_owned()));
Ok(L::wrap_repo_path_opt(out_property.into_dyn()))
Ok(P::wrap_repo_path_opt(out_property.into_dyn()))
},
);
map
@ -1627,7 +1539,7 @@ impl Template for CommitOrChangeId {
fn builtin_commit_or_change_id_methods<'repo>(
) -> CommitTemplateBuildMethodFnMap<'repo, CommitOrChangeId> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<CommitOrChangeId>::new();
@ -1644,7 +1556,7 @@ fn builtin_commit_or_change_id_methods<'repo>(
CommitOrChangeId::Change(id) => id.hex(),
}
});
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -1663,7 +1575,7 @@ fn builtin_commit_or_change_id_methods<'repo>(
.transpose()?;
let out_property =
(self_property, len_property).map(|(id, len)| id.short(len.unwrap_or(12)));
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -1698,7 +1610,7 @@ fn builtin_commit_or_change_id_methods<'repo>(
};
let out_property = (self_property, len_property)
.map(move |(id, len)| id.shortest(repo, &index, len.unwrap_or(0)));
Ok(L::wrap_shortest_id_prefix(out_property.into_dyn()))
Ok(P::wrap_shortest_id_prefix(out_property.into_dyn()))
},
);
map
@ -1734,7 +1646,7 @@ impl ShortestIdPrefix {
fn builtin_shortest_id_prefix_methods<'repo>(
) -> CommitTemplateBuildMethodFnMap<'repo, ShortestIdPrefix> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<ShortestIdPrefix>::new();
@ -1743,7 +1655,7 @@ fn builtin_shortest_id_prefix_methods<'repo>(
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|id| id.prefix);
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -1751,7 +1663,7 @@ fn builtin_shortest_id_prefix_methods<'repo>(
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|id| id.rest);
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -1759,7 +1671,7 @@ fn builtin_shortest_id_prefix_methods<'repo>(
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|id| id.to_upper());
Ok(L::wrap_shortest_id_prefix(out_property.into_dyn()))
Ok(P::wrap_shortest_id_prefix(out_property.into_dyn()))
},
);
map.insert(
@ -1767,7 +1679,7 @@ fn builtin_shortest_id_prefix_methods<'repo>(
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|id| id.to_lower());
Ok(L::wrap_shortest_id_prefix(out_property.into_dyn()))
Ok(P::wrap_shortest_id_prefix(out_property.into_dyn()))
},
);
map
@ -1843,7 +1755,7 @@ where
}
fn builtin_tree_diff_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, TreeDiff> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<TreeDiff>::new();
@ -1854,7 +1766,7 @@ fn builtin_tree_diff_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, T
// TODO: cache and reuse diff entries within the current evaluation?
let out_property =
self_property.and_then(|diff| Ok(diff.collect_entries().block_on()?));
Ok(L::wrap_tree_diff_entry_list(out_property.into_dyn()))
Ok(P::wrap_tree_diff_entry_list(out_property.into_dyn()))
},
);
map.insert(
@ -1896,7 +1808,7 @@ fn builtin_tree_diff_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, T
})
})
.into_template();
Ok(L::wrap_template(template))
Ok(P::wrap_template(template))
},
);
map.insert(
@ -1936,7 +1848,7 @@ fn builtin_tree_diff_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, T
})
})
.into_template();
Ok(L::wrap_template(template))
Ok(P::wrap_template(template))
},
);
map.insert(
@ -1970,7 +1882,7 @@ fn builtin_tree_diff_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, T
width: width.unwrap_or(80),
})
});
Ok(L::wrap_diff_stats(out_property.into_dyn()))
Ok(P::wrap_diff_stats(out_property.into_dyn()))
},
);
map.insert(
@ -1985,7 +1897,7 @@ fn builtin_tree_diff_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, T
})
})
.into_template();
Ok(L::wrap_template(template))
Ok(P::wrap_template(template))
},
);
// TODO: add support for external tools
@ -2036,7 +1948,7 @@ impl TreeDiffEntry {
fn builtin_tree_diff_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, TreeDiffEntry>
{
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<TreeDiffEntry>::new();
@ -2045,7 +1957,7 @@ fn builtin_tree_diff_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'r
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|entry| entry.path.target);
Ok(L::wrap_repo_path(out_property.into_dyn()))
Ok(P::wrap_repo_path(out_property.into_dyn()))
},
);
map.insert(
@ -2053,7 +1965,7 @@ fn builtin_tree_diff_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'r
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|entry| entry.status_label().to_owned());
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
// TODO: add status_code() or status_char()?
@ -2062,7 +1974,7 @@ fn builtin_tree_diff_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'r
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(TreeDiffEntry::into_source_entry);
Ok(L::wrap_tree_entry(out_property.into_dyn()))
Ok(P::wrap_tree_entry(out_property.into_dyn()))
},
);
map.insert(
@ -2070,7 +1982,7 @@ fn builtin_tree_diff_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'r
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(TreeDiffEntry::into_target_entry);
Ok(L::wrap_tree_entry(out_property.into_dyn()))
Ok(P::wrap_tree_entry(out_property.into_dyn()))
},
);
map
@ -2084,7 +1996,7 @@ pub struct TreeEntry {
}
fn builtin_tree_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, TreeEntry> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<TreeEntry>::new();
@ -2093,7 +2005,7 @@ fn builtin_tree_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|entry| entry.path);
Ok(L::wrap_repo_path(out_property.into_dyn()))
Ok(P::wrap_repo_path(out_property.into_dyn()))
},
);
map.insert(
@ -2101,7 +2013,7 @@ fn builtin_tree_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|entry| !entry.value.is_resolved());
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -2110,7 +2022,7 @@ fn builtin_tree_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
function.expect_no_arguments()?;
let out_property =
self_property.map(|entry| describe_file_type(&entry.value).to_owned());
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -2119,7 +2031,7 @@ fn builtin_tree_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
function.expect_no_arguments()?;
let out_property =
self_property.map(|entry| is_executable_file(&entry.value).unwrap_or_default());
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map
@ -2161,7 +2073,7 @@ impl Template for DiffStatsFormatted<'_> {
}
fn builtin_diff_stats_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, DiffStats> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<DiffStats>::new();
@ -2172,7 +2084,7 @@ fn builtin_diff_stats_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
function.expect_no_arguments()?;
let out_property =
self_property.and_then(|stats| Ok(stats.count_total_added().try_into()?));
Ok(L::wrap_integer(out_property.into_dyn()))
Ok(P::wrap_integer(out_property.into_dyn()))
},
);
map.insert(
@ -2181,7 +2093,7 @@ fn builtin_diff_stats_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo,
function.expect_no_arguments()?;
let out_property =
self_property.and_then(|stats| Ok(stats.count_total_removed().try_into()?));
Ok(L::wrap_integer(out_property.into_dyn()))
Ok(P::wrap_integer(out_property.into_dyn()))
},
);
map
@ -2223,7 +2135,7 @@ impl CryptographicSignature {
fn builtin_cryptographic_signature_methods<'repo>(
) -> CommitTemplateBuildMethodFnMap<'repo, CryptographicSignature> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = CommitTemplateBuildMethodFnMap::<CryptographicSignature>::new();
@ -2236,7 +2148,7 @@ fn builtin_cryptographic_signature_methods<'repo>(
Err(SignError::InvalidSignatureFormat) => Ok("invalid".to_string()),
Err(err) => Err(err.into()),
});
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -2244,7 +2156,7 @@ fn builtin_cryptographic_signature_methods<'repo>(
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.and_then(|sig| Ok(sig.key()?));
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -2252,7 +2164,7 @@ fn builtin_cryptographic_signature_methods<'repo>(
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.and_then(|sig| Ok(sig.display()?));
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map
@ -2268,14 +2180,14 @@ pub struct AnnotationLine {
fn builtin_annotation_line_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, AnnotationLine>
{
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
let mut map = CommitTemplateBuildMethodFnMap::<AnnotationLine>::new();
map.insert(
"commit",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|line| line.commit);
Ok(L::wrap_commit(out_property.into_dyn()))
Ok(P::wrap_commit(out_property.into_dyn()))
},
);
map.insert(
@ -2284,7 +2196,7 @@ fn builtin_annotation_line_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'r
function.expect_no_arguments()?;
let out_property = self_property.map(|line| line.content);
// TODO: Add Bytes or BString template type?
Ok(L::wrap_template(out_property.into_template()))
Ok(P::wrap_template(out_property.into_template()))
},
);
map.insert(
@ -2292,7 +2204,7 @@ fn builtin_annotation_line_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'r
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.and_then(|line| Ok(line.line_number.try_into()?));
Ok(L::wrap_integer(out_property.into_dyn()))
Ok(P::wrap_integer(out_property.into_dyn()))
},
);
map.insert(
@ -2300,7 +2212,7 @@ fn builtin_annotation_line_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'r
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|line| line.first_line_in_hunk);
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map
@ -2319,14 +2231,14 @@ impl Template for Vec<Trailer> {
}
fn builtin_trailer_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Trailer> {
type L<'repo> = CommitTemplateLanguage<'repo>;
type P<'repo> = CommitTemplatePropertyKind<'repo>;
let mut map = CommitTemplateBuildMethodFnMap::<Trailer>::new();
map.insert(
"key",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|trailer| trailer.key);
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -2334,7 +2246,7 @@ fn builtin_trailer_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Tra
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|trailer| trailer.value);
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map

View File

@ -230,7 +230,7 @@ pub fn aliases() -> Vec<CompletionCandidate> {
})
}
fn revisions(revisions: Option<&str>) -> Vec<CompletionCandidate> {
fn revisions(match_prefix: &str, revset_filter: Option<&str>) -> Vec<CompletionCandidate> {
with_jj(|jj, settings| {
// display order
const LOCAL_BOOKMARK_MINE: usize = 0;
@ -257,36 +257,40 @@ fn revisions(revisions: Option<&str>) -> Vec<CompletionCandidate> {
.arg(
r#"if(remote != "git", name ++ if(remote, "@" ++ remote) ++ bookmark_help() ++ "\n")"#,
);
if let Some(revs) = revisions {
if let Some(revs) = revset_filter {
cmd.arg("--revisions").arg(revs);
}
let output = cmd.output().map_err(user_error)?;
let stdout = String::from_utf8_lossy(&output.stdout);
candidates.extend(stdout.lines().map(|line| {
let (bookmark, help) = split_help_text(line);
candidates.extend(
stdout
.lines()
.map(split_help_text)
.filter(|(bookmark, _)| bookmark.starts_with(match_prefix))
.map(|(bookmark, help)| {
let local = !bookmark.contains('@');
let mine = prefix.as_ref().is_some_and(|p| bookmark.starts_with(p));
let local = !bookmark.contains('@');
let mine = prefix.as_ref().is_some_and(|p| bookmark.starts_with(p));
let display_order = match (local, mine) {
(true, true) => LOCAL_BOOKMARK_MINE,
(true, false) => LOCAL_BOOKMARK,
(false, true) => REMOTE_BOOKMARK_MINE,
(false, false) => REMOTE_BOOKMARK,
};
CompletionCandidate::new(bookmark)
.help(help)
.display_order(Some(display_order))
}));
let display_order = match (local, mine) {
(true, true) => LOCAL_BOOKMARK_MINE,
(true, false) => LOCAL_BOOKMARK,
(false, true) => REMOTE_BOOKMARK_MINE,
(false, false) => REMOTE_BOOKMARK,
};
CompletionCandidate::new(bookmark)
.help(help)
.display_order(Some(display_order))
}),
);
// tags
// Tags cannot be filtered by revisions. In order to avoid suggesting
// immutable tags for mutable revision args, we skip tags entirely if
// revisions is set. This is not a big loss, since tags usually point
// revset_filter is set. This is not a big loss, since tags usually point
// to immutable revisions anyway.
if revisions.is_none() {
if revset_filter.is_none() {
let output = jj
.build()
.arg("tag")
@ -295,6 +299,7 @@ fn revisions(revisions: Option<&str>) -> Vec<CompletionCandidate> {
.arg(BOOKMARK_HELP_TEMPLATE)
.arg("--template")
.arg(r#"name ++ bookmark_help() ++ "\n""#)
.arg(format!("glob:{}*", glob::Pattern::escape(match_prefix)))
.output()
.map_err(user_error)?;
let stdout = String::from_utf8_lossy(&output.stdout);
@ -309,7 +314,7 @@ fn revisions(revisions: Option<&str>) -> Vec<CompletionCandidate> {
// change IDs
let revisions = revisions
let revisions = revset_filter
.map(String::from)
.or_else(|| settings.get_string("revsets.short-prefixes").ok())
.or_else(|| settings.get_string("revsets.log").ok())
@ -329,35 +334,92 @@ fn revisions(revisions: Option<&str>) -> Vec<CompletionCandidate> {
.map_err(user_error)?;
let stdout = String::from_utf8_lossy(&output.stdout);
candidates.extend(stdout.lines().map(|line| {
let (id, desc) = split_help_text(line);
CompletionCandidate::new(id)
.help(desc)
.display_order(Some(CHANGE_ID))
}));
candidates.extend(
stdout
.lines()
.map(split_help_text)
.filter(|(id, _)| id.starts_with(match_prefix))
.map(|(id, desc)| {
CompletionCandidate::new(id)
.help(desc)
.display_order(Some(CHANGE_ID))
}),
);
// revset aliases
let revset_aliases = load_revset_aliases(&Ui::null(), settings.config())?;
let mut symbol_names: Vec<_> = revset_aliases.symbol_names().collect();
symbol_names.sort();
candidates.extend(symbol_names.into_iter().map(|symbol| {
let (_, defn) = revset_aliases.get_symbol(symbol).unwrap();
CompletionCandidate::new(symbol)
.help(Some(defn.into()))
.display_order(Some(REVSET_ALIAS))
}));
candidates.extend(
symbol_names
.into_iter()
.filter(|symbol| symbol.starts_with(match_prefix))
.map(|symbol| {
let (_, defn) = revset_aliases.get_symbol(symbol).unwrap();
CompletionCandidate::new(symbol)
.help(Some(defn.into()))
.display_order(Some(REVSET_ALIAS))
}),
);
Ok(candidates)
})
}
pub fn mutable_revisions() -> Vec<CompletionCandidate> {
revisions(Some("mutable()"))
fn revset_expression(
current: &std::ffi::OsStr,
revset_filter: Option<&str>,
) -> Vec<CompletionCandidate> {
let Some(current) = current.to_str() else {
return Vec::new();
};
let (prepend, match_prefix) = split_revset_trailing_name(current).unwrap_or(("", current));
let candidates = revisions(match_prefix, revset_filter);
if prepend.is_empty() {
candidates
} else {
candidates
.into_iter()
.map(|candidate| candidate.add_prefix(prepend))
.collect()
}
}
pub fn all_revisions() -> Vec<CompletionCandidate> {
revisions(None)
pub fn revset_expression_all(current: &std::ffi::OsStr) -> Vec<CompletionCandidate> {
revset_expression(current, None)
}
pub fn revset_expression_mutable(current: &std::ffi::OsStr) -> Vec<CompletionCandidate> {
revset_expression(current, Some("mutable()"))
}
/// Identifies if an incomplete expression ends with a name, or may be continued
/// with a name.
///
/// If the expression ends with an name or a partial name, returns a tuple that
/// splits the string at the point the name starts.
/// If the expression is empty or ends with a prefix or infix operator that
/// could plausibly be followed by a name, returns a tuple where the first
/// item is the entire input string, and the second item is empty.
/// Otherwise, returns `None`.
///
/// The input expression may be incomplete (e.g. missing closing parentheses),
/// and the ability to reject invalid expressions is limited.
fn split_revset_trailing_name(incomplete_revset_str: &str) -> Option<(&str, &str)> {
let final_part = incomplete_revset_str
.rsplit_once([':', '~', '|', '&', '(', ','])
.map(|(_, rest)| rest)
.unwrap_or(incomplete_revset_str);
let final_part = final_part
.rsplit_once("..")
.map(|(_, rest)| rest)
.unwrap_or(final_part)
.trim_ascii_start();
let re = regex::Regex::new(r"^(?:[\p{XID_CONTINUE}_/]+[@.+-])*[\p{XID_CONTINUE}_/]*$").unwrap();
re.is_match(final_part)
.then(|| incomplete_revset_str.split_at(incomplete_revset_str.len() - final_part.len()))
}
pub fn operations() -> Vec<CompletionCandidate> {
@ -557,13 +619,8 @@ pub fn branch_name_equals_any_revision(current: &std::ffi::OsStr) -> Vec<Complet
// Don't complete branch names since we want to create a new branch
return Vec::new();
};
all_revisions()
revset_expression(revision.as_ref(), None)
.into_iter()
.filter(|rev| {
rev.get_value()
.to_str()
.is_some_and(|s| s.starts_with(revision))
})
.map(|rev| rev.add_prefix(format!("{branch_name}=")))
.collect()
}
@ -1022,6 +1079,71 @@ mod parse {
mod tests {
use super::*;
#[test]
fn test_split_revset_trailing_name() {
assert_eq!(split_revset_trailing_name(""), Some(("", "")));
assert_eq!(split_revset_trailing_name(" "), Some((" ", "")));
assert_eq!(split_revset_trailing_name("foo"), Some(("", "foo")));
assert_eq!(split_revset_trailing_name(" foo"), Some((" ", "foo")));
assert_eq!(split_revset_trailing_name("foo "), None);
assert_eq!(split_revset_trailing_name("foo_"), Some(("", "foo_")));
assert_eq!(split_revset_trailing_name("foo/"), Some(("", "foo/")));
assert_eq!(split_revset_trailing_name("foo/b"), Some(("", "foo/b")));
assert_eq!(split_revset_trailing_name("foo-"), Some(("", "foo-")));
assert_eq!(split_revset_trailing_name("foo+"), Some(("", "foo+")));
assert_eq!(
split_revset_trailing_name("foo-bar-"),
Some(("", "foo-bar-"))
);
assert_eq!(
split_revset_trailing_name("foo-bar-b"),
Some(("", "foo-bar-b"))
);
assert_eq!(split_revset_trailing_name("foo."), Some(("", "foo.")));
assert_eq!(split_revset_trailing_name("foo..b"), Some(("foo..", "b")));
assert_eq!(split_revset_trailing_name("..foo"), Some(("..", "foo")));
assert_eq!(split_revset_trailing_name("foo(bar"), Some(("foo(", "bar")));
assert_eq!(split_revset_trailing_name("foo(bar)"), None);
assert_eq!(split_revset_trailing_name("(f"), Some(("(", "f")));
assert_eq!(split_revset_trailing_name("foo@"), Some(("", "foo@")));
assert_eq!(split_revset_trailing_name("foo@b"), Some(("", "foo@b")));
assert_eq!(split_revset_trailing_name("..foo@"), Some(("..", "foo@")));
assert_eq!(
split_revset_trailing_name("::F(foo@origin.1..bar@origin."),
Some(("::F(foo@origin.1..", "bar@origin."))
);
}
#[test]
fn test_split_revset_trailing_name_with_trailing_operator() {
assert_eq!(split_revset_trailing_name("foo|"), Some(("foo|", "")));
assert_eq!(split_revset_trailing_name("foo | "), Some(("foo | ", "")));
assert_eq!(split_revset_trailing_name("foo&"), Some(("foo&", "")));
assert_eq!(split_revset_trailing_name("foo~"), Some(("foo~", "")));
assert_eq!(split_revset_trailing_name(".."), Some(("..", "")));
assert_eq!(split_revset_trailing_name("foo.."), Some(("foo..", "")));
assert_eq!(split_revset_trailing_name("::"), Some(("::", "")));
assert_eq!(split_revset_trailing_name("foo::"), Some(("foo::", "")));
assert_eq!(split_revset_trailing_name("("), Some(("(", "")));
assert_eq!(split_revset_trailing_name("foo("), Some(("foo(", "")));
assert_eq!(split_revset_trailing_name("foo()"), None);
assert_eq!(split_revset_trailing_name("foo(bar)"), None);
}
#[test]
fn test_split_revset_trailing_name_with_modifier() {
assert_eq!(split_revset_trailing_name("all:"), Some(("all:", "")));
assert_eq!(split_revset_trailing_name("all: "), Some(("all: ", "")));
assert_eq!(split_revset_trailing_name("all:f"), Some(("all:", "f")));
assert_eq!(split_revset_trailing_name("all: f"), Some(("all: ", "f")));
}
#[test]
fn test_config_keys() {
// Just make sure the schema is parsed without failure.

View File

@ -21,7 +21,7 @@ use crate::template_builder;
use crate::template_builder::BuildContext;
use crate::template_builder::CoreTemplateBuildFnTable;
use crate::template_builder::CoreTemplatePropertyKind;
use crate::template_builder::IntoTemplateProperty;
use crate::template_builder::CoreTemplatePropertyVar;
use crate::template_builder::TemplateLanguage;
use crate::template_parser;
use crate::template_parser::FunctionCallNode;
@ -90,8 +90,6 @@ impl<'a, C> GenericTemplateLanguage<'a, C> {
impl<'a, C> TemplateLanguage<'a> for GenericTemplateLanguage<'a, C> {
type Property = GenericTemplatePropertyKind<'a, C>;
template_builder::impl_core_wrap_property_fns!('a, GenericTemplatePropertyKind::Core);
fn settings(&self) -> &UserSettings {
&self.settings
}
@ -130,18 +128,20 @@ impl<'a, C> TemplateLanguage<'a> for GenericTemplateLanguage<'a, C> {
}
}
impl<'a, C> GenericTemplateLanguage<'a, C> {
pub fn wrap_self(property: BoxedTemplateProperty<'a, C>) -> GenericTemplatePropertyKind<'a, C> {
GenericTemplatePropertyKind::Self_(property)
}
}
pub enum GenericTemplatePropertyKind<'a, C> {
Core(CoreTemplatePropertyKind<'a>),
Self_(BoxedTemplateProperty<'a, C>),
}
impl<'a, C> IntoTemplateProperty<'a> for GenericTemplatePropertyKind<'a, C> {
impl<'a, C> GenericTemplatePropertyKind<'a, C> {
template_builder::impl_wrap_property_fns!('a, GenericTemplatePropertyKind, {
pub wrap_self(C) => Self_,
});
}
impl<'a, C> CoreTemplatePropertyVar<'a> for GenericTemplatePropertyKind<'a, C> {
template_builder::impl_core_wrap_property_fns!('a, GenericTemplatePropertyKind::Core);
fn type_name(&self) -> &'static str {
match self {
GenericTemplatePropertyKind::Core(property) => property.type_name(),

View File

@ -30,7 +30,7 @@ use crate::template_builder::merge_fn_map;
use crate::template_builder::BuildContext;
use crate::template_builder::CoreTemplateBuildFnTable;
use crate::template_builder::CoreTemplatePropertyKind;
use crate::template_builder::IntoTemplateProperty;
use crate::template_builder::CoreTemplatePropertyVar;
use crate::template_builder::TemplateBuildMethodFnMap;
use crate::template_builder::TemplateLanguage;
use crate::template_parser;
@ -88,8 +88,6 @@ impl OperationTemplateLanguage {
impl TemplateLanguage<'static> for OperationTemplateLanguage {
type Property = OperationTemplatePropertyKind;
template_builder::impl_core_wrap_property_fns!('static, OperationTemplatePropertyKind::Core);
fn settings(&self) -> &UserSettings {
self.repo_loader.settings()
}
@ -135,18 +133,6 @@ impl OperationTemplateLanguage {
pub fn cache_extension<T: Any>(&self) -> Option<&T> {
self.cache_extensions.get::<T>()
}
pub fn wrap_operation(
property: BoxedTemplateProperty<'static, Operation>,
) -> OperationTemplatePropertyKind {
OperationTemplatePropertyKind::Operation(property)
}
pub fn wrap_operation_id(
property: BoxedTemplateProperty<'static, OperationId>,
) -> OperationTemplatePropertyKind {
OperationTemplatePropertyKind::OperationId(property)
}
}
pub enum OperationTemplatePropertyKind {
@ -155,7 +141,16 @@ pub enum OperationTemplatePropertyKind {
OperationId(BoxedTemplateProperty<'static, OperationId>),
}
impl IntoTemplateProperty<'static> for OperationTemplatePropertyKind {
impl OperationTemplatePropertyKind {
template_builder::impl_wrap_property_fns!('static, OperationTemplatePropertyKind, {
pub wrap_operation(Operation) => Operation,
pub wrap_operation_id(OperationId) => OperationId,
});
}
impl CoreTemplatePropertyVar<'static> for OperationTemplatePropertyKind {
template_builder::impl_core_wrap_property_fns!('static, OperationTemplatePropertyKind::Core);
fn type_name(&self) -> &'static str {
match self {
OperationTemplatePropertyKind::Core(property) => property.type_name(),
@ -265,7 +260,7 @@ impl OperationTemplateBuildFnTable {
}
fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
type L = OperationTemplateLanguage;
type P = OperationTemplatePropertyKind;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = OperationTemplateBuildMethodFnMap::<Operation>::new();
@ -275,7 +270,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
function.expect_no_arguments()?;
let current_op_id = language.current_op_id.clone();
let out_property = self_property.map(move |op| Some(op.id()) == current_op_id.as_ref());
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -283,7 +278,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|op| op.metadata().description.clone());
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -291,7 +286,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|op| op.id().clone());
Ok(L::wrap_operation_id(out_property.into_dyn()))
Ok(P::wrap_operation_id(out_property.into_dyn()))
},
);
map.insert(
@ -306,7 +301,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
.map(|(key, value)| format!("{key}: {value}"))
.join("\n")
});
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -314,7 +309,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|op| op.metadata().is_snapshot);
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map.insert(
@ -325,7 +320,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
start: op.metadata().start_time,
end: op.metadata().end_time,
});
Ok(L::wrap_timestamp_range(out_property.into_dyn()))
Ok(P::wrap_timestamp_range(out_property.into_dyn()))
},
);
map.insert(
@ -336,7 +331,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
// TODO: introduce dedicated type and provide accessors?
format!("{}@{}", op.metadata().username, op.metadata().hostname)
});
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map.insert(
@ -345,7 +340,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
function.expect_no_arguments()?;
let root_op_id = language.repo_loader.op_store().root_operation_id().clone();
let out_property = self_property.map(move |op| op.id() == &root_op_id);
Ok(L::wrap_boolean(out_property.into_dyn()))
Ok(P::wrap_boolean(out_property.into_dyn()))
},
);
map
@ -358,7 +353,7 @@ impl Template for OperationId {
}
fn builtin_operation_id_methods() -> OperationTemplateBuildMethodFnMap<OperationId> {
type L = OperationTemplateLanguage;
type P = OperationTemplatePropertyKind;
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = OperationTemplateBuildMethodFnMap::<OperationId>::new();
@ -381,7 +376,7 @@ fn builtin_operation_id_methods() -> OperationTemplateBuildMethodFnMap<Operation
hex.truncate(len.unwrap_or(12));
hex
});
Ok(L::wrap_string(out_property.into_dyn()))
Ok(P::wrap_string(out_property.into_dyn()))
},
);
map

File diff suppressed because it is too large Load Diff

View File

@ -792,6 +792,22 @@ fn test_revisions() {
[EOF]
");
// complete all revisions in a revset expression
let output = work_dir.complete_fish(["log", "-r", ".."]);
insta::assert_snapshot!(output, @r"
..immutable_bookmark immutable
..mutable_bookmark mutable
..k working_copy
..y mutable
..q immutable
..zq remote_commit
..zz (no description set)
..remote_bookmark@origin remote_commit
..alias_with_newline roots(
..siblings @-+ ~@
[EOF]
");
// complete only mutable revisions
let output = work_dir.complete_fish(["squash", "--into", ""]);
insta::assert_snapshot!(output, @r"
@ -804,6 +820,25 @@ fn test_revisions() {
[EOF]
");
// complete only mutable revisions in a revset expression
let output = work_dir.complete_fish(["abandon", "y::"]);
insta::assert_snapshot!(output, @r"
y::mutable_bookmark mutable
y::k working_copy
y::y mutable
y::zq remote_commit
y::alias_with_newline roots(
y::siblings @-+ ~@
[EOF]
");
// complete remote bookmarks in a revset expression
let output = work_dir.complete_fish(["log", "-r", "remote_bookmark@"]);
insta::assert_snapshot!(output, @r"
remote_bookmark@origin remote_commit
[EOF]
");
// complete args of the default command
test_env.add_config("ui.default-command = 'log'");
let output = work_dir.complete_fish(["-r", ""]);