Skip to content

Commit

Permalink
templater: add Email template type, deprecate Signature.username()
Browse files Browse the repository at this point in the history
The `Signature.email()` method is also updated to return the new Email
type. The `Signature.username()` method is deprecated for
`Signature.email().local()`.
  • Loading branch information
bnjmnt4n committed Dec 12, 2024
1 parent db5e7dd commit eee3065
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 19 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Deprecations

* The `Signature.username()` template method is deprecated for
`Signature().email().local()`.

### New features

* `jj` command no longer fails due to new working-copy files larger than the
`snapshot.max-new-file-size` config option. It will print a warning and large
files will be left untracked.

* A new Email template type is added. `Signature.email()` now returns an Email
template type instead of a String.

### Fixed bugs

* The `$NO_COLOR` environment variable must now be non-empty to be respected.
Expand Down
4 changes: 2 additions & 2 deletions cli/src/config/templates.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ commit_summary = 'format_commit_summary_with_refs(self, bookmarks)'
annotate_commit_summary = '''
separate(" ",
change_id.shortest(8),
pad_end(8, truncate_end(8, author.username())),
pad_end(8, truncate_end(8, author.email().local())),
committer.timestamp().local().format('%Y-%m-%d %H:%M:%S'),
)
'''
Expand Down Expand Up @@ -72,7 +72,7 @@ if(root,
concat(
separate(" ",
format_short_change_id_with_hidden_and_divergent_info(self),
if(author.email(), author.username(), email_placeholder),
if(author.email(), author.email().local(), email_placeholder),
format_timestamp(committer.timestamp()),
bookmarks,
tags,
Expand Down
55 changes: 52 additions & 3 deletions cli/src/template_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use crate::template_parser::UnaryOp;
use crate::templater::CoalesceTemplate;
use crate::templater::ConcatTemplate;
use crate::templater::ConditionalTemplate;
use crate::templater::Email;
use crate::templater::LabelTemplate;
use crate::templater::ListPropertyTemplate;
use crate::templater::ListTemplate;
Expand Down Expand Up @@ -70,6 +71,7 @@ pub trait TemplateLanguage<'a> {
property: impl TemplateProperty<Output = Option<i64>> + 'a,
) -> Self::Property;
fn wrap_signature(property: impl TemplateProperty<Output = Signature> + 'a) -> Self::Property;
fn wrap_email(property: impl TemplateProperty<Output = Email> + 'a) -> Self::Property;
fn wrap_size_hint(property: impl TemplateProperty<Output = SizeHint> + 'a) -> Self::Property;
fn wrap_timestamp(property: impl TemplateProperty<Output = Timestamp> + 'a) -> Self::Property;
fn wrap_timestamp_range(
Expand Down Expand Up @@ -116,6 +118,7 @@ macro_rules! impl_core_wrap_property_fns {
wrap_integer(i64) => Integer,
wrap_integer_opt(Option<i64>) => IntegerOpt,
wrap_signature(jj_lib::backend::Signature) => Signature,
wrap_email($crate::templater::Email) => Email,
wrap_size_hint($crate::templater::SizeHint) => SizeHint,
wrap_timestamp(jj_lib::backend::Timestamp) => Timestamp,
wrap_timestamp_range($crate::templater::TimestampRange) => TimestampRange,
Expand Down Expand Up @@ -174,6 +177,7 @@ pub enum CoreTemplatePropertyKind<'a> {
Integer(Box<dyn TemplateProperty<Output = i64> + 'a>),
IntegerOpt(Box<dyn TemplateProperty<Output = Option<i64>> + 'a>),
Signature(Box<dyn TemplateProperty<Output = Signature> + 'a>),
Email(Box<dyn TemplateProperty<Output = Email> + 'a>),
SizeHint(Box<dyn TemplateProperty<Output = SizeHint> + 'a>),
Timestamp(Box<dyn TemplateProperty<Output = Timestamp> + 'a>),
TimestampRange(Box<dyn TemplateProperty<Output = TimestampRange> + 'a>),
Expand Down Expand Up @@ -201,6 +205,7 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
CoreTemplatePropertyKind::Integer(_) => "Integer",
CoreTemplatePropertyKind::IntegerOpt(_) => "Option<Integer>",
CoreTemplatePropertyKind::Signature(_) => "Signature",
CoreTemplatePropertyKind::Email(_) => "Email",
CoreTemplatePropertyKind::SizeHint(_) => "SizeHint",
CoreTemplatePropertyKind::Timestamp(_) => "Timestamp",
CoreTemplatePropertyKind::TimestampRange(_) => "TimestampRange",
Expand All @@ -217,6 +222,9 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
CoreTemplatePropertyKind::StringList(property) => {
Some(Box::new(property.map(|l| !l.is_empty())))
}
CoreTemplatePropertyKind::Email(property) => Some(Box::new(
property.map(|e| !e.local.is_empty() || e.domain.is_some()),
)),
CoreTemplatePropertyKind::Boolean(property) => Some(property),
CoreTemplatePropertyKind::Integer(_) => None,
CoreTemplatePropertyKind::IntegerOpt(property) => {
Expand Down Expand Up @@ -262,6 +270,7 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
CoreTemplatePropertyKind::Integer(property) => Some(property.into_template()),
CoreTemplatePropertyKind::IntegerOpt(property) => Some(property.into_template()),
CoreTemplatePropertyKind::Signature(property) => Some(property.into_template()),
CoreTemplatePropertyKind::Email(property) => Some(property.into_template()),
CoreTemplatePropertyKind::SizeHint(_) => None,
CoreTemplatePropertyKind::Timestamp(property) => Some(property.into_template()),
CoreTemplatePropertyKind::TimestampRange(property) => Some(property.into_template()),
Expand All @@ -287,6 +296,7 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
(CoreTemplatePropertyKind::Integer(_), _) => None,
(CoreTemplatePropertyKind::IntegerOpt(_), _) => None,
(CoreTemplatePropertyKind::Signature(_), _) => None,
(CoreTemplatePropertyKind::Email(_), _) => None,
(CoreTemplatePropertyKind::SizeHint(_), _) => None,
(CoreTemplatePropertyKind::Timestamp(_), _) => None,
(CoreTemplatePropertyKind::TimestampRange(_), _) => None,
Expand Down Expand Up @@ -333,6 +343,7 @@ pub struct CoreTemplateBuildFnTable<'a, L: TemplateLanguage<'a> + ?Sized> {
pub string_methods: TemplateBuildMethodFnMap<'a, L, String>,
pub boolean_methods: TemplateBuildMethodFnMap<'a, L, bool>,
pub integer_methods: TemplateBuildMethodFnMap<'a, L, i64>,
pub email_methods: TemplateBuildMethodFnMap<'a, L, Email>,
pub signature_methods: TemplateBuildMethodFnMap<'a, L, Signature>,
pub size_hint_methods: TemplateBuildMethodFnMap<'a, L, SizeHint>,
pub timestamp_methods: TemplateBuildMethodFnMap<'a, L, Timestamp>,
Expand All @@ -356,6 +367,7 @@ impl<'a, L: TemplateLanguage<'a> + ?Sized> CoreTemplateBuildFnTable<'a, L> {
boolean_methods: HashMap::new(),
integer_methods: HashMap::new(),
signature_methods: builtin_signature_methods(),
email_methods: builtin_email_methods(),
size_hint_methods: builtin_size_hint_methods(),
timestamp_methods: builtin_timestamp_methods(),
timestamp_range_methods: builtin_timestamp_range_methods(),
Expand All @@ -369,6 +381,7 @@ impl<'a, L: TemplateLanguage<'a> + ?Sized> CoreTemplateBuildFnTable<'a, L> {
boolean_methods: HashMap::new(),
integer_methods: HashMap::new(),
signature_methods: HashMap::new(),
email_methods: HashMap::new(),
size_hint_methods: HashMap::new(),
timestamp_methods: HashMap::new(),
timestamp_range_methods: HashMap::new(),
Expand All @@ -382,6 +395,7 @@ impl<'a, L: TemplateLanguage<'a> + ?Sized> CoreTemplateBuildFnTable<'a, L> {
boolean_methods,
integer_methods,
signature_methods,
email_methods,
size_hint_methods,
timestamp_methods,
timestamp_range_methods,
Expand All @@ -392,6 +406,7 @@ impl<'a, L: TemplateLanguage<'a> + ?Sized> CoreTemplateBuildFnTable<'a, L> {
merge_fn_map(&mut self.boolean_methods, boolean_methods);
merge_fn_map(&mut self.integer_methods, integer_methods);
merge_fn_map(&mut self.signature_methods, signature_methods);
merge_fn_map(&mut self.email_methods, email_methods);
merge_fn_map(&mut self.size_hint_methods, size_hint_methods);
merge_fn_map(&mut self.timestamp_methods, timestamp_methods);
merge_fn_map(&mut self.timestamp_range_methods, timestamp_range_methods);
Expand Down Expand Up @@ -466,6 +481,11 @@ impl<'a, L: TemplateLanguage<'a> + ?Sized> CoreTemplateBuildFnTable<'a, L> {
let build = template_parser::lookup_method(type_name, table, function)?;
build(language, diagnostics, build_ctx, property, function)
}
CoreTemplatePropertyKind::Email(property) => {
let table = &self.email_methods;
let build = template_parser::lookup_method(type_name, table, function)?;
build(language, diagnostics, build_ctx, property, function)
}
CoreTemplatePropertyKind::SizeHint(property) => {
let table = &self.size_hint_methods;
let build = template_parser::lookup_method(type_name, table, function)?;
Expand Down Expand Up @@ -820,14 +840,19 @@ fn builtin_signature_methods<'a, L: TemplateLanguage<'a> + ?Sized>(
"email",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|signature| signature.email);
Ok(L::wrap_string(out_property))
let out_property = self_property.map(|signature| signature.email.clone().into());
Ok(L::wrap_email(out_property))
},
);
map.insert(
"username",
|_language, _diagnostics, _build_ctx, self_property, function| {
|_language, diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
// TODO: Remove in jj 0.30+
diagnostics.add_warning(TemplateParseError::expression(
"username() is deprecated; use email().local() instead",
function.name_span,
));
let out_property = self_property.map(|signature| {
let (username, _) = text_util::split_email(&signature.email);
username.to_owned()
Expand All @@ -846,6 +871,30 @@ fn builtin_signature_methods<'a, L: TemplateLanguage<'a> + ?Sized>(
map
}

fn builtin_email_methods<'a, L: TemplateLanguage<'a> + ?Sized>(
) -> TemplateBuildMethodFnMap<'a, L, Email> {
// Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted.
let mut map = TemplateBuildMethodFnMap::<L, Email>::new();
map.insert(
"local",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|email| email.local);
Ok(L::wrap_string(out_property))
},
);
map.insert(
"domain",
|_language, _diagnostics, _build_ctx, self_property, function| {
function.expect_no_arguments()?;
let out_property = self_property.map(|email| email.domain.unwrap_or_default());
Ok(L::wrap_string(out_property))
},
);
map
}

fn builtin_size_hint_methods<'a, L: TemplateLanguage<'a> + ?Sized>(
) -> TemplateBuildMethodFnMap<'a, L, SizeHint> {
// Not using maplit::hashmap!{} or custom declarative macro here because
Expand Down
31 changes: 30 additions & 1 deletion cli/src/templater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::formatter::FormatRecorder;
use crate::formatter::Formatter;
use crate::formatter::LabeledWriter;
use crate::formatter::PlainTextFormatter;
use crate::text_util;
use crate::time_util;

/// Represents printable type or compiled template containing placeholder value.
Expand Down Expand Up @@ -75,13 +76,41 @@ impl Template for Signature {
}
if !self.email.is_empty() {
write!(formatter, "<")?;
write!(formatter.labeled("email"), "{}", self.email)?;
let email: Email = self.email.clone().into();
email.format(formatter)?;
write!(formatter, ">")?;
}
Ok(())
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Email {
pub local: String,
pub domain: Option<String>,
}

impl From<String> for Email {
fn from(value: String) -> Self {
let (local, domain) = text_util::split_email(&value);
Email {
local: local.to_owned(),
domain: domain.map(|d| d.to_owned()),
}
}
}

impl Template for Email {
fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {
write!(formatter.labeled("local"), "{}", self.local)?;
if let Some(domain) = &self.domain {
write!(formatter, "@")?;
write!(formatter.labeled("domain"), "{domain}")?;
}
Ok(())
}
}

// In template language, an integer value is represented as i64. However, we use
// usize here because it's more convenient to guarantee that the lower value is
// bounded to 0.
Expand Down
Loading

0 comments on commit eee3065

Please sign in to comment.