Skip to content

Commit

Permalink
templater: introduce Formatter wrapper to switch strict/lax evaluations
Browse files Browse the repository at this point in the history
This allows us to propagate property evaluation error to a string property. For
instance, "s.contains(x ++ y)" will be an error if "y" failed to evaluate,
whereas bare "x ++ y" shouldn't.

The other implementation ideas:

 a. add Template::into_string_property() to enable strict evaluation
    => it's tedious to implement it for each printable type
 b. pass (formatter, error_handler) arguments separately
    => works, but most implementors don't need error_handler argument
 c. pass strict=bool flag around build_*() functions
    => didn't tried, but it would be more complicated than this patch

Because Template trait is now implementation detail of the templater, it
should be okay to use a non-standard formatter wrapper.
  • Loading branch information
yuja committed Mar 29, 2024
1 parent e7edafc commit 71c2006
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 70 deletions.
11 changes: 5 additions & 6 deletions cli/src/commit_templater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,13 @@ use jj_lib::revset::{Revset, RevsetParseContext};
use jj_lib::{git, rewrite};
use once_cell::unsync::OnceCell;

use crate::formatter::Formatter;
use crate::template_builder::{
self, merge_fn_map, BuildContext, CoreTemplateBuildFnTable, CoreTemplatePropertyKind,
IntoTemplateProperty, TemplateBuildMethodFnMap, TemplateLanguage,
};
use crate::template_parser::{self, FunctionCallNode, TemplateParseError, TemplateParseResult};
use crate::templater::{
self, IntoTemplate, PlainTextFormattedProperty, Template, TemplateProperty,
self, IntoTemplate, PlainTextFormattedProperty, Template, TemplateFormatter, TemplateProperty,
TemplatePropertyError, TemplatePropertyExt as _,
};
use crate::{revset_util, text_util};
Expand Down Expand Up @@ -669,7 +668,7 @@ impl RefName {
}

impl Template for RefName {
fn format(&self, formatter: &mut dyn Formatter) -> io::Result<()> {
fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {
write!(formatter.labeled("name"), "{}", self.name)?;
if let Some(remote) = &self.remote {
write!(formatter, "@")?;
Expand All @@ -687,7 +686,7 @@ impl Template for RefName {
}

impl Template for Vec<RefName> {
fn format(&self, formatter: &mut dyn Formatter) -> io::Result<()> {
fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {
templater::format_joined(formatter, self, " ")
}
}
Expand Down Expand Up @@ -837,7 +836,7 @@ impl CommitOrChangeId {
}

impl Template for CommitOrChangeId {
fn format(&self, formatter: &mut dyn Formatter) -> io::Result<()> {
fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {
write!(formatter, "{}", self.hex())
}
}
Expand Down Expand Up @@ -879,7 +878,7 @@ pub struct ShortestIdPrefix {
}

impl Template for ShortestIdPrefix {
fn format(&self, formatter: &mut dyn Formatter) -> io::Result<()> {
fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {
write!(formatter.labeled("prefix"), "{}", self.prefix)?;
write!(formatter.labeled("rest"), "{}", self.rest)?;
Ok(())
Expand Down
7 changes: 3 additions & 4 deletions cli/src/operation_templater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@ use jj_lib::object_id::ObjectId;
use jj_lib::op_store::OperationId;
use jj_lib::operation::Operation;

use crate::formatter::Formatter;
use crate::template_builder::{
self, merge_fn_map, BuildContext, CoreTemplateBuildFnTable, CoreTemplatePropertyKind,
IntoTemplateProperty, TemplateBuildMethodFnMap, TemplateLanguage,
};
use crate::template_parser::{self, FunctionCallNode, TemplateParseResult};
use crate::templater::{
IntoTemplate, PlainTextFormattedProperty, Template, TemplateProperty, TemplatePropertyExt as _,
TimestampRange,
IntoTemplate, PlainTextFormattedProperty, Template, TemplateFormatter, TemplateProperty,
TemplatePropertyExt as _, TimestampRange,
};

pub trait OperationTemplateLanguageExtension {
Expand Down Expand Up @@ -276,7 +275,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
}

impl Template for OperationId {
fn format(&self, formatter: &mut dyn Formatter) -> io::Result<()> {
fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {
write!(formatter, "{}", self.hex())
}
}
Expand Down
11 changes: 7 additions & 4 deletions cli/src/template_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,8 @@ fn builtin_functions<'a, L: TemplateLanguage<'a> + ?Sized>() -> TemplateBuildFun
let content = expect_template_expression(language, build_ctx, content_node)?;
let template =
ReformatTemplate::new(content, move |formatter, recorded| match width.extract() {
Ok(width) => text_util::write_wrapped(formatter, recorded, width),
Err(err) => err.format(formatter),
Ok(width) => text_util::write_wrapped(formatter.as_mut(), recorded, width),
Err(err) => formatter.handle_error(err),
});
Ok(L::wrap_template(Box::new(template)))
});
Expand All @@ -896,7 +896,10 @@ fn builtin_functions<'a, L: TemplateLanguage<'a> + ?Sized>() -> TemplateBuildFun
let prefix = expect_template_expression(language, build_ctx, prefix_node)?;
let content = expect_template_expression(language, build_ctx, content_node)?;
let template = ReformatTemplate::new(content, move |formatter, recorded| {
text_util::write_indented(formatter, recorded, |formatter| prefix.format(formatter))
let rewrap = formatter.rewrap_fn();
text_util::write_indented(formatter.as_mut(), recorded, |formatter| {
prefix.format(&mut rewrap(formatter))
})
});
Ok(L::wrap_template(Box::new(template)))
});
Expand Down Expand Up @@ -959,7 +962,7 @@ fn builtin_functions<'a, L: TemplateLanguage<'a> + ?Sized>() -> TemplateBuildFun
return Ok(());
}
prefix.format(formatter)?;
recorded.replay(formatter)?;
recorded.replay(formatter.as_mut())?;
suffix.format(formatter)?;
Ok(())
});
Expand Down
Loading

0 comments on commit 71c2006

Please sign in to comment.