Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
back to prompting the user if the heuristics are inconclusive. It can also run
in non-interactive mode, which aborts if prompting would be needed.

* `jj git fetch`'s output can be customized with `templates.git_fetch` or `-T`
[#9311](https://github.com/jj-vcs/jj/pull/9311).

### Fixed bugs

* `jj arrange` now scrolls the viewport to keep the selected commit visible
Expand Down
29 changes: 26 additions & 3 deletions cli/src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ use crate::command_error::config_error_with_message;
use crate::command_error::handle_command_result;
use crate::command_error::internal_error;
use crate::command_error::internal_error_with_message;
use crate::command_error::print_error_sources;
use crate::command_error::print_parse_diagnostics;
use crate::command_error::user_error;
use crate::command_error::user_error_with_message;
Expand Down Expand Up @@ -1237,6 +1236,8 @@ pub struct WorkspaceCommandHelper {
// TODO: Parsed template can be cached if it doesn't capture 'repo lifetime
commit_summary_template_text: String,
op_summary_template_text: String,
#[cfg(feature = "git")]
fetch_summary_template_text: String,
may_snapshot_working_copy: bool,
may_update_working_copy: bool,
}
Expand Down Expand Up @@ -1274,6 +1275,8 @@ impl WorkspaceCommandHelper {
let settings = workspace.settings();
let commit_summary_template_text = settings.get_string("templates.commit_summary")?;
let op_summary_template_text = settings.get_string("templates.op_summary")?;
#[cfg(feature = "git")]
let fetch_summary_template_text = settings.get_string("templates.git_fetch")?;
let may_update_working_copy =
may_snapshot_working_copy && env.command.should_commit_transaction();

Expand All @@ -1282,6 +1285,8 @@ impl WorkspaceCommandHelper {
user_repo: ReadonlyUserRepo::new(repo),
env,
commit_summary_template_text,
#[cfg(feature = "git")]
fetch_summary_template_text,
op_summary_template_text,
may_snapshot_working_copy,
may_update_working_copy,
Expand All @@ -1290,6 +1295,8 @@ impl WorkspaceCommandHelper {
// mutable operation.
helper.parse_operation_template(ui, &helper.op_summary_template_text)?;
helper.parse_commit_template(ui, &helper.commit_summary_template_text)?;
#[cfg(feature = "git")]
helper.parse_refstatus_template(ui, &helper.fetch_summary_template_text)?;
helper.parse_commit_template(ui, SHORT_CHANGE_ID_TEMPLATE_TEXT)?;
Ok(helper)
}
Expand Down Expand Up @@ -1511,6 +1518,11 @@ impl WorkspaceCommandHelper {
&self.env
}

#[cfg(feature = "git")]
pub fn fetch_summary_template_text(&self) -> &str {
&self.fetch_summary_template_text
}

async fn prepare_working_copy_mutation(&self) -> Result<Commit, CommandError> {
self.check_working_copy_writable()?;
if let Some(wc_commit_id) = self.get_wc_commit_id() {
Expand Down Expand Up @@ -1931,7 +1943,7 @@ to the current parents may contain changes from multiple commits.
}

/// Parses template that is validated by `Self::new()`.
fn reparse_valid_template<'a, C, L>(
pub(crate) fn reparse_valid_template<'a, C, L>(
&self,
language: &L,
template_text: &str,
Expand Down Expand Up @@ -1960,6 +1972,17 @@ to the current parents may contain changes from multiple commits.
self.parse_template(ui, &language, template_text)
}

/// Parses refstatus template into evaluation tree.
#[cfg(feature = "git")]
pub fn parse_refstatus_template(
&self,
ui: &Ui,
template_text: &str,
) -> Result<TemplateRenderer<'_, crate::git_util::RefStatus>, CommandError> {
let language = self.commit_template_language();
self.parse_template(ui, &language, template_text)
}

/// Parses commit template into evaluation tree.
pub fn parse_operation_template(
&self,
Expand Down Expand Up @@ -2741,7 +2764,7 @@ async fn try_reset_git_head(
Ok(()) => Ok(()),
Err(err @ jj_lib::git::GitResetHeadError::UpdateHeadRef(_)) => {
writeln!(ui.warning_default(), "{err}")?;
print_error_sources(ui, err.source())?;
crate::command_error::print_error_sources(ui, err.source())?;
Ok(())
}
Err(err) => Err(err.into()),
Expand Down
5 changes: 4 additions & 1 deletion cli/src/commands/git/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,10 @@ async fn fetch_new_remote(
let remote_symbol = name.to_remote_symbol(remote_name);
tx.repo_mut().track_remote_bookmark(remote_symbol).await?;
}
print_git_import_stats(ui, &tx, &import_stats)?;
{
let template = crate::git_util::commit_fetch_template(&tx);
print_git_import_stats(ui, &tx, &import_stats, &template)?;
}
tx.finish(ui, "fetch from git remote into empty repo")
.await?;
Ok((working_branch.map(ToOwned::to_owned), working_is_default))
Expand Down
5 changes: 4 additions & 1 deletion cli/src/commands/git/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,10 @@ pub async fn cmd_git_fetch(
}

let import_stats = git_fetch.import_refs().await?;
print_git_import_stats(ui, &tx, &import_stats)?;
{
let template = crate::git_util::commit_fetch_template(&tx);
print_git_import_stats(ui, &tx, &import_stats, &template)?;
}

if let Some(bookmark_expr) = &common_bookmark_expr {
warn_if_branches_not_found(ui, &tx, bookmark_expr, &matching_remotes)?;
Expand Down
5 changes: 4 additions & 1 deletion cli/src/commands/git/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ pub async fn cmd_git_import(
let import_options = load_git_import_options(ui, &git_settings, &remote_settings)?;
let mut tx = workspace_command.start_transaction();
let stats = git::import_refs(tx.repo_mut(), &import_options).await?;
print_git_import_stats(ui, &tx, &stats)?;
{
let template = crate::git_util::commit_fetch_template(&tx);
print_git_import_stats(ui, &tx, &stats, &template)?;
}
tx.finish(ui, "import git refs").await?;
Ok(())
}
97 changes: 97 additions & 0 deletions cli/src/commit_templater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ use crate::diff_util::DiffStatEntry;
use crate::diff_util::DiffStatOptions;
use crate::diff_util::DiffStats;
use crate::formatter::Formatter;
#[cfg(feature = "git")]
use crate::git_util::RefStatus;
use crate::operation_templater;
use crate::operation_templater::OperationTemplateBuildFnTable;
use crate::operation_templater::OperationTemplateEnvironment;
Expand Down Expand Up @@ -407,6 +409,12 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
let build = template_parser::lookup_method(type_name, table, function)?;
build(self, diagnostics, build_ctx, property, function)
}
#[cfg(feature = "git")]
CommitTemplatePropertyKind::RefStatus(property) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we introduce a generic diff type for CommitRef or RemoteRef? It should probably support both fetch and push summaries.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To check I understand, are you saying we want to change RefStatus to something like RefDiff so it'll work with a template for jj git push ?

let table = &self.build_fn_table.ref_status_methods;
let build = template_parser::lookup_method(type_name, table, function)?;
build(self, diagnostics, build_ctx, property, function)
}
}
}
}
Expand Down Expand Up @@ -474,6 +482,8 @@ pub enum CommitTemplatePropertyKind<'repo> {
AnnotationLine(BoxedTemplateProperty<'repo, AnnotationLine>),
Trailer(BoxedTemplateProperty<'repo, Trailer>),
TrailerList(BoxedTemplateProperty<'repo, Vec<Trailer>>),
#[cfg(feature = "git")]
RefStatus(BoxedTemplateProperty<'repo, RefStatus>),
}

template_builder::impl_core_property_wrappers!(<'repo> CommitTemplatePropertyKind<'repo> => Core);
Expand Down Expand Up @@ -508,6 +518,8 @@ template_builder::impl_property_wrappers!(<'repo> CommitTemplatePropertyKind<'re
AnnotationLine(AnnotationLine),
Trailer(Trailer),
TrailerList(Vec<Trailer>),
#[cfg(feature = "git")]
RefStatus(RefStatus),
});

impl<'repo> CoreTemplatePropertyVar<'repo> for CommitTemplatePropertyKind<'repo> {
Expand Down Expand Up @@ -556,6 +568,8 @@ impl<'repo> CoreTemplatePropertyVar<'repo> for CommitTemplatePropertyKind<'repo>
Self::AnnotationLine(_) => "AnnotationLine",
Self::Trailer(_) => "Trailer",
Self::TrailerList(_) => "List<Trailer>",
#[cfg(feature = "git")]
Self::RefStatus(_) => "RefStatus",
}
}

Expand Down Expand Up @@ -616,6 +630,8 @@ impl<'repo> CoreTemplatePropertyVar<'repo> for CommitTemplatePropertyKind<'repo>
Self::AnnotationLine(_) => Err(self),
Self::Trailer(_) => Err(self),
Self::TrailerList(property) => Ok(property.map(|l| !l.is_empty()).into_dyn()),
#[cfg(feature = "git")]
Self::RefStatus(_) => Err(self),
}
}

Expand Down Expand Up @@ -668,6 +684,8 @@ impl<'repo> CoreTemplatePropertyVar<'repo> for CommitTemplatePropertyKind<'repo>
Self::AnnotationLine(_) => None,
Self::Trailer(_) => None,
Self::TrailerList(_) => None,
#[cfg(feature = "git")]
Self::RefStatus(_) => None,
}
}

Expand Down Expand Up @@ -704,6 +722,8 @@ impl<'repo> CoreTemplatePropertyVar<'repo> for CommitTemplatePropertyKind<'repo>
Self::AnnotationLine(_) => None,
Self::Trailer(property) => Some(property.into_template()),
Self::TrailerList(property) => Some(property.into_template()),
#[cfg(feature = "git")]
Self::RefStatus(property) => Some(property.into_template()),
}
}

Expand Down Expand Up @@ -773,6 +793,8 @@ impl<'repo> CoreTemplatePropertyVar<'repo> for CommitTemplatePropertyKind<'repo>
(Self::AnnotationLine(_), _) => None,
(Self::Trailer(_), _) => None,
(Self::TrailerList(_), _) => None,
#[cfg(feature = "git")]
(Self::RefStatus(_), _) => None,
}
}

Expand Down Expand Up @@ -815,6 +837,8 @@ impl<'repo> CoreTemplatePropertyVar<'repo> for CommitTemplatePropertyKind<'repo>
(Self::AnnotationLine(_), _) => None,
(Self::Trailer(_), _) => None,
(Self::TrailerList(_), _) => None,
#[cfg(feature = "git")]
(Self::RefStatus(_), _) => None,
}
}
}
Expand Down Expand Up @@ -853,6 +877,8 @@ pub struct CommitTemplateBuildFnTable<'repo> {
pub annotation_line_methods: CommitTemplateBuildMethodFnMap<'repo, AnnotationLine>,
pub trailer_methods: CommitTemplateBuildMethodFnMap<'repo, Trailer>,
pub trailer_list_methods: CommitTemplateBuildMethodFnMap<'repo, Vec<Trailer>>,
#[cfg(feature = "git")]
pub ref_status_methods: CommitTemplateBuildMethodFnMap<'repo, RefStatus>,
}

impl CommitTemplateBuildFnTable<'_> {
Expand Down Expand Up @@ -883,6 +909,8 @@ impl CommitTemplateBuildFnTable<'_> {
annotation_line_methods: HashMap::new(),
trailer_methods: HashMap::new(),
trailer_list_methods: HashMap::new(),
#[cfg(feature = "git")]
ref_status_methods: HashMap::new(),
}
}

Expand Down Expand Up @@ -913,6 +941,8 @@ impl CommitTemplateBuildFnTable<'_> {
annotation_line_methods,
trailer_methods,
trailer_list_methods,
#[cfg(feature = "git")]
ref_status_methods,
} = other;

self.core.merge(core);
Expand Down Expand Up @@ -958,6 +988,8 @@ impl CommitTemplateBuildFnTable<'_> {
merge_fn_map(&mut self.annotation_line_methods, annotation_line_methods);
merge_fn_map(&mut self.trailer_methods, trailer_methods);
merge_fn_map(&mut self.trailer_list_methods, trailer_list_methods);
#[cfg(feature = "git")]
merge_fn_map(&mut self.ref_status_methods, ref_status_methods);
}

/// Creates new symbol table containing the builtin methods.
Expand Down Expand Up @@ -990,6 +1022,8 @@ impl CommitTemplateBuildFnTable<'_> {
annotation_line_methods: builtin_annotation_line_methods(),
trailer_methods: builtin_trailer_methods(),
trailer_list_methods: builtin_trailer_list_methods(),
#[cfg(feature = "git")]
ref_status_methods: builtin_ref_status_methods(),
}
}
}
Expand Down Expand Up @@ -2060,6 +2094,69 @@ impl Display for RefSymbolBuf {
}
}

#[cfg(feature = "git")]
impl Template for RefStatus {
fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {
write!(formatter, "{}", self.name())
}
}

#[cfg(feature = "git")]
fn builtin_ref_status_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, RefStatus> {
let mut map = CommitTemplateBuildMethodFnMap::<RefStatus>::new();
map.insert(
"name",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|ref_status| ref_status.name().to_owned());
Ok(out_property.into_dyn_wrapped())
},
);
map.insert(
"tracked",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|ref_status| ref_status.is_tracked());
Ok(out_property.into_dyn_wrapped())
},
);
map.insert(
"remote_ref_state",
Comment thread
bobrippling marked this conversation as resolved.
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property =
self_property.map(|ref_status| ref_status.remote_ref_state().to_owned());
Ok(out_property.into_dyn_wrapped())
},
);
map.insert(
"import_status",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property =
self_property.map(|ref_status| ref_status.import_status().to_owned());
Ok(out_property.into_dyn_wrapped())
},
);
map.insert(
"kind",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|ref_status| ref_status.kind().to_owned());
Ok(out_property.into_dyn_wrapped())
},
);
map.insert(
"max_name_width",
Comment thread
bobrippling marked this conversation as resolved.
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|ref_status| ref_status.max_name_width() as i64);
Ok(out_property.into_dyn_wrapped())
},
);
map
}

impl Template for RefSymbolBuf {
fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {
write!(formatter, "{self}")
Expand Down
4 changes: 4 additions & 0 deletions cli/src/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,10 @@
"type": "string",
"description": "`jj file show`'s output"
},
"git_fetch": {
"type": "string",
"description": "`jj git fetch`'s output"
},
"git_push_bookmark": {
"type": "string",
"description": "Bookmark name to be assigned when pushing a change to Git remote"
Expand Down
8 changes: 8 additions & 0 deletions cli/src/config/templates.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ evolog = 'builtin_evolog_compact'
file_list = 'format_path(path) ++ "\n"'
file_show = ''

git_fetch = '''
separate(" ",
kind ++ ":",
pad_end(max_name_width, label(kind, name)),
"[" ++ import_status ++ "]",
remote_ref_state,
) ++ "\n"
'''
git_push_bookmark = '"push-" ++ change_id.short()'

log = 'builtin_log_compact'
Expand Down
Loading
Loading