jj/cli/src/config/templates.toml
Siva Mahadevan 24cd079307 templates: create new git_format_patch_email_headers template
With this template, a 'git format-patch' compatible
email message can be generated using something like:

jj show --git --template git_format_patch_email_headers <rev>
2025-04-02 13:16:47 +00:00

423 lines
12 KiB
TOML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[templates]
backout_description = '''
concat(
'Back out "' ++ description.first_line() ++ '"' ++ "\n",
"\n",
"This backs out commit " ++ commit_id ++ ".\n",
)
'''
bookmark_list = '''
if(remote,
if(tracked,
" " ++ separate(" ",
label("bookmark", "@" ++ remote),
format_tracked_remote_ref_distances(self),
) ++ format_ref_targets(self),
label("bookmark", name ++ "@" ++ remote) ++ format_ref_targets(self),
),
label("bookmark", name) ++ if(present, format_ref_targets(self), " (deleted)"),
) ++ "\n"
'''
commit_summary = 'format_commit_summary_with_refs(self, bookmarks)'
file_annotate = '''
separate(" ",
commit.change_id().shortest(8),
pad_end(8, truncate_end(8, commit.author().email().local())),
commit_timestamp(commit).local().format('%Y-%m-%d %H:%M:%S'),
pad_start(4, line_number),
) ++ ": " ++ content
'''
config_list = 'builtin_config_list'
draft_commit_description = 'builtin_draft_commit_description'
file_list = '''
path.display() ++ "\n"
'''
log = 'builtin_log_compact'
op_log = 'builtin_op_log_compact'
show = 'builtin_log_detailed'
revert_description = '''
concat(
'Revert "' ++ description.first_line() ++ '"' ++ "\n",
"\n",
"This reverts commit " ++ commit_id ++ ".\n",
)
'''
tag_list = '''
label("tag", name) ++ format_ref_targets(self) ++ "\n"
'''
op_summary = '''
separate(" ",
self.id().short(),
if(root,
label("root", "root()"),
surround("(", ")", format_timestamp(self.time().end())),
),
self.description().first_line(),
)
'''
[template-aliases]
'format_config_item(x)' = '''
if(x.overridden(),
indent("# ", x.name() ++ " = " ++ x.value()),
x.name() ++ " = " ++ x.value(),
)
'''
builtin_config_list = '''
label(if(overridden, "overridden"),
format_config_item(self) ++ "\n")
'''
builtin_config_list_detailed = '''
label(if(overridden, "overridden"),
format_config_item(self) ++ " # " ++ separate(" ", source, path) ++ "\n")
'''
builtin_draft_commit_description = '''
concat(
coalesce(description, "\n"),
surround(
"\nJJ: This commit contains the following changes:\n", "",
indent("JJ: ", diff.summary()),
),
)
'''
builtin_log_oneline = '''
if(root,
format_root_commit(self),
label(if(current_working_copy, "working_copy"),
concat(
separate(" ",
format_short_change_id_with_hidden_and_divergent_info(self),
format_short_signature_oneline(author),
format_timestamp(commit_timestamp(self)),
bookmarks,
tags,
working_copies,
if(git_head, label("git_head", "git_head()")),
format_short_commit_id(commit_id),
if(conflict, label("conflict", "conflict")),
if(config("ui.show-cryptographic-signatures").as_boolean(),
format_short_cryptographic_signature(signature)),
if(empty, label("empty", "(empty)")),
if(description,
description.first_line(),
label(if(empty, "empty"), description_placeholder),
),
) ++ "\n",
),
)
)
'''
builtin_log_compact = '''
if(root,
format_root_commit(self),
label(if(current_working_copy, "working_copy"),
concat(
format_short_commit_header(self) ++ "\n",
separate(" ",
if(empty, label("empty", "(empty)")),
if(description,
description.first_line(),
label(if(empty, "empty"), description_placeholder),
),
) ++ "\n",
),
)
)
'''
builtin_log_compact_full_description = '''
if(root,
format_root_commit(self),
label(if(current_working_copy, "working_copy"),
concat(
format_short_commit_header(self) ++ "\n",
separate(" ",
if(empty, label("empty", "(empty)")),
if(description,
description,
label(if(empty, "empty"), description_placeholder),
),
) ++ "\n",
),
)
)
'''
builtin_log_comfortable = 'builtin_log_compact ++ "\n"'
builtin_log_detailed = '''
concat(
"Commit ID: " ++ commit_id ++ "\n",
"Change ID: " ++ change_id ++ "\n",
surround("Bookmarks: ", "\n", separate(" ", local_bookmarks, remote_bookmarks)),
surround("Tags : ", "\n", tags),
"Author : " ++ format_detailed_signature(author) ++ "\n",
"Committer: " ++ format_detailed_signature(committer) ++ "\n",
if(config("ui.show-cryptographic-signatures").as_boolean(),
"Signature: " ++ format_detailed_cryptographic_signature(signature) ++ "\n"),
"\n",
indent(" ",
coalesce(description, label(if(empty, "empty"), description_placeholder) ++ "\n")),
"\n",
)
'''
builtin_op_log_compact = '''
label(if(current_operation, "current_operation"),
coalesce(
if(snapshot, format_snapshot_operation(self)),
if(root, format_root_operation(self)),
format_operation(self),
)
)
'''
builtin_op_log_comfortable = 'builtin_op_log_compact ++ "\n"'
builtin_op_log_oneline = '''
label(if(current_operation, "current_operation"),
coalesce(
if(snapshot, format_snapshot_operation_oneline(self)),
if(root, format_root_operation(self)),
format_operation_oneline(self),
)
)
'''
description_placeholder = 'label("description placeholder", "(no description set)")'
email_placeholder = 'label("email placeholder", "(no email set)")'
name_placeholder = 'label("name placeholder", "(no name set)")'
commit_summary_separator = 'label("separator", " | ")'
# Hook points for users to customize the default templates:
'commit_timestamp(commit)' = 'commit.committer().timestamp()'
'format_short_id(id)' = 'id.shortest(8)'
'format_short_change_id(id)' = 'format_short_id(id)'
'format_short_commit_id(id)' = 'format_short_id(id)'
'format_short_operation_id(id)' = 'id.short()'
'format_short_signature(signature)' = '''
coalesce(signature.email(), email_placeholder)'''
'format_short_signature_oneline(signature)' = '''
coalesce(signature.email().local(), email_placeholder)'''
'format_detailed_signature(signature)' = '''
coalesce(signature.name(), name_placeholder)
++ " <" ++ coalesce(signature.email(), email_placeholder) ++ ">"
++ " (" ++ format_timestamp(signature.timestamp()) ++ ")"'''
# For operations, when it makes a difference whether to use the start time or
# the end time, the latter is more meaningful. For mutating operations, this is
# the moment when the repo was actually modified due to this operation. TODO:
# This macro might need a better name, e.g. `format_operation_time_range`.
'format_time_range(time_range)' = '''
time_range.end().ago() ++ label("time", ", lasted ") ++ time_range.duration()'''
'format_timestamp(timestamp)' = 'timestamp.local().format("%Y-%m-%d %H:%M:%S")'
'format_commit_summary_with_refs(commit, refs)' = '''
separate(" ",
format_short_change_id_with_hidden_and_divergent_info(commit),
format_short_commit_id(commit.commit_id()),
separate(commit_summary_separator,
refs,
separate(" ",
if(commit.conflict(), label("conflict", "(conflict)")),
if(commit.empty(), label("empty", "(empty)")),
if(commit.description(),
commit.description().first_line(),
label(if(commit.empty(), "empty"), description_placeholder),
),
),
),
)
'''
'format_root_commit(root)' = '''
separate(" ",
format_short_change_id(root.change_id()),
label("root", "root()"),
format_short_commit_id(root.commit_id()),
root.bookmarks(),
) ++ "\n"
'''
'format_ref_targets(ref)' = '''
if(ref.conflict(),
separate("\n",
" " ++ label("conflict", "(conflicted)") ++ ":",
ref.removed_targets().map(|c| " - " ++ format_commit_summary_with_refs(c, "")).join("\n"),
ref.added_targets().map(|c| " + " ++ format_commit_summary_with_refs(c, "")).join("\n"),
),
": " ++ format_commit_summary_with_refs(ref.normal_target(), ""),
)
'''
'format_tracked_remote_ref_distances(ref)' = '''
if(ref.tracking_present(), surround("(", ")", separate(", ",
if(!ref.tracking_ahead_count().zero(),
if(ref.tracking_ahead_count().exact(),
"ahead by " ++ ref.tracking_ahead_count().exact() ++ " commits",
"ahead by at least " ++ ref.tracking_ahead_count().lower() ++ " commits")),
if(!ref.tracking_behind_count().zero(),
if(ref.tracking_behind_count().exact(),
"behind by " ++ ref.tracking_behind_count().exact() ++ " commits",
"behind by at least " ++ ref.tracking_behind_count().lower() ++ " commits")),
)))
'''
'format_operation(op)' = '''
concat(
separate(" ", format_short_operation_id(op.id()), op.user(), format_time_range(op.time())), "\n",
op.description().first_line(), "\n",
if(op.tags(), op.tags() ++ "\n"),
)
'''
'format_snapshot_operation(op)' = 'format_operation(op)'
'format_root_operation(root)' = 'separate(" ", root.id().short(), label("root", "root()")) ++ "\n"'
'format_operation_oneline(op)' = '''
separate(" ",
format_short_operation_id(op.id()), op.user(), format_time_range(op.time()),
op.description().first_line(),
if(op.tags(), op.tags()),
) ++ "\n"
'''
'format_snapshot_operation_oneline(op)' = 'format_operation_oneline(op)'
# We have "hidden" override "divergent", since a hidden revision does not cause
# change id conflicts and is not affected by such conflicts; you have to use the
# commit id to refer to a hidden revision regardless.
'format_short_change_id_with_hidden_and_divergent_info(commit)' = '''
if(commit.hidden(),
label("hidden",
format_short_change_id(commit.change_id()) ++ " hidden"
),
label(if(commit.divergent(), "divergent"),
format_short_change_id(commit.change_id()) ++ if(commit.divergent(), "??")
)
)
'''
'format_short_commit_header(commit)' = '''
separate(" ",
format_short_change_id_with_hidden_and_divergent_info(commit),
format_short_signature(commit.author()),
format_timestamp(commit_timestamp(commit)),
commit.bookmarks(),
commit.tags(),
commit.working_copies(),
if(commit.git_head(), label("git_head", "git_head()")),
format_short_commit_id(commit.commit_id()),
if(commit.conflict(), label("conflict", "conflict")),
if(config("ui.show-cryptographic-signatures").as_boolean(),
format_short_cryptographic_signature(commit.signature())),
)
'''
'format_detailed_cryptographic_signature(signature)' = '''
if(signature,
separate(" ",
label("signature status " ++ signature.status(), signature.status()),
"signature by",
coalesce(signature.display(), "(unknown)"),
signature.key(),
),
"(no signature)",
)
'''
'format_short_cryptographic_signature(signature)' = '''
if(signature,
label("signature status", concat(
"[",
label(signature.status(), coalesce(
if(signature.status() == "good", "✓︎"),
if(signature.status() == "unknown", "?"),
"x",
)),
"]",
))
)
'''
builtin_log_node = '''
coalesce(
if(!self, label("elided", "~")),
label(
separate(" ",
if(current_working_copy, "working_copy"),
if(immutable, "immutable"),
if(conflict, "conflict"),
),
coalesce(
if(current_working_copy, "@"),
if(immutable, "◆"),
if(conflict, "×"),
"○",
)
)
)
'''
builtin_log_node_ascii = '''
coalesce(
if(!self, label("elided", "~")),
label(
separate(" ",
if(current_working_copy, "working_copy"),
if(immutable, "immutable"),
if(conflict, "conflict"),
),
coalesce(
if(current_working_copy, "@"),
if(immutable, "+"),
if(conflict, "x"),
"o",
)
)
)
'''
builtin_op_log_node = '''
coalesce(
if(current_operation, label("current_operation", "@")),
"○",
)
'''
builtin_op_log_node_ascii = '''
coalesce(
if(current_operation, label("current_operation", "@")),
"o",
)
'''
# The first line is a fixed magic date string used by
# programs like file(1) to identify that this is output from
# 'git format-patch'.
# See https://git-scm.com/docs/git-format-patch#_description
git_format_patch_email_headers = '''
concat(
"From " ++ commit_id ++ " Mon Sep 17 00:00:00 2001\n",
"From: " ++ author ++ "\n",
"Date: " ++ author.timestamp().format("%a, %-e %b %Y %T %z") ++ "\n",
"Subject: [PATCH] " ++ description.first_line() ++ "\n",
"\n",
description.remove_prefix(description.first_line()).trim_start(),
"---\n",
indent(" ", diff.stat()),
"\n"
)
'''