mirror of
https://github.com/martinvonz/jj.git
synced 2024-11-28 17:41:14 +00:00
templater: generalize IndentTemplate as reformatting template
New fill() function will also use this struct.
This commit is contained in:
parent
2af2aca7ff
commit
b41bdb548a
2 changed files with 45 additions and 42 deletions
|
@ -25,11 +25,11 @@ use pest_derive::Parser;
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::templater::{
|
||||
ConcatTemplate, ConditionalTemplate, FormattablePropertyListTemplate, IndentTemplate,
|
||||
IntoTemplate, LabelTemplate, Literal, PlainTextFormattedProperty, SeparateTemplate, Template,
|
||||
TemplateFunction, TemplateProperty, TimestampRange,
|
||||
ConcatTemplate, ConditionalTemplate, FormattablePropertyListTemplate, IntoTemplate,
|
||||
LabelTemplate, Literal, PlainTextFormattedProperty, ReformatTemplate, SeparateTemplate,
|
||||
Template, TemplateFunction, TemplateProperty, TimestampRange,
|
||||
};
|
||||
use crate::time_util;
|
||||
use crate::{text_util, time_util};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "template.pest"]
|
||||
|
@ -1075,7 +1075,18 @@ fn build_global_function<'a, L: TemplateLanguage<'a>>(
|
|||
let [prefix_node, content_node] = expect_exact_arguments(function)?;
|
||||
let prefix = build_expression(language, prefix_node)?.into_template();
|
||||
let content = build_expression(language, content_node)?.into_template();
|
||||
language.wrap_template(IndentTemplate::new(prefix, content))
|
||||
let template = ReformatTemplate::new(content, move |context, formatter, recorded| {
|
||||
text_util::write_indented(formatter, recorded, |formatter| {
|
||||
// If Template::format() returned a custom error type, we would need to
|
||||
// handle template evaluation error out of this closure:
|
||||
// prefix.format(context, &mut prefix_recorder)?;
|
||||
// write_indented(formatter, recorded, |formatter| {
|
||||
// prefix_recorder.replay(formatter)
|
||||
// })
|
||||
prefix.format(context, formatter)
|
||||
})
|
||||
});
|
||||
language.wrap_template(template)
|
||||
}
|
||||
"label" => {
|
||||
let [label_node, content_node] = expect_exact_arguments(function)?;
|
||||
|
|
|
@ -17,7 +17,7 @@ use std::io;
|
|||
use jujutsu_lib::backend::{Signature, Timestamp};
|
||||
|
||||
use crate::formatter::{FormatRecorder, Formatter, PlainTextFormatter};
|
||||
use crate::{text_util, time_util};
|
||||
use crate::time_util;
|
||||
|
||||
pub trait Template<C> {
|
||||
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()>;
|
||||
|
@ -115,42 +115,6 @@ impl Template<()> for i64 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Indents each line by the given prefix.
|
||||
pub struct IndentTemplate<S, T> {
|
||||
prefix: S,
|
||||
content: T,
|
||||
}
|
||||
|
||||
impl<S, T> IndentTemplate<S, T> {
|
||||
pub fn new<C>(prefix: S, content: T) -> Self
|
||||
where
|
||||
S: Template<C>,
|
||||
T: Template<C>,
|
||||
{
|
||||
IndentTemplate { prefix, content }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, S, T> Template<C> for IndentTemplate<S, T>
|
||||
where
|
||||
S: Template<C>,
|
||||
T: Template<C>,
|
||||
{
|
||||
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
let mut recorder = FormatRecorder::new();
|
||||
self.content.format(context, &mut recorder)?;
|
||||
text_util::write_indented(formatter, &recorder, |formatter| {
|
||||
// If Template::format() returned a custom error type, we would need to
|
||||
// handle template evaluation error out of this closure:
|
||||
// prefix.format(context, &mut prefix_recorder)?;
|
||||
// write_indented(formatter, recorded, |formatter| {
|
||||
// prefix_recorder.replay(formatter)
|
||||
// })
|
||||
self.prefix.format(context, formatter)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LabelTemplate<T, L> {
|
||||
content: T,
|
||||
labels: L,
|
||||
|
@ -195,6 +159,34 @@ impl<C, T: Template<C>> Template<C> for ConcatTemplate<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Renders the content to buffer, and transforms it without losing labels.
|
||||
pub struct ReformatTemplate<T, F> {
|
||||
content: T,
|
||||
reformat: F,
|
||||
}
|
||||
|
||||
impl<T, F> ReformatTemplate<T, F> {
|
||||
pub fn new<C>(content: T, reformat: F) -> Self
|
||||
where
|
||||
T: Template<C>,
|
||||
F: Fn(&C, &mut dyn Formatter, &FormatRecorder) -> io::Result<()>,
|
||||
{
|
||||
ReformatTemplate { content, reformat }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, T, F> Template<C> for ReformatTemplate<T, F>
|
||||
where
|
||||
T: Template<C>,
|
||||
F: Fn(&C, &mut dyn Formatter, &FormatRecorder) -> io::Result<()>,
|
||||
{
|
||||
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
let mut recorder = FormatRecorder::new();
|
||||
self.content.format(context, &mut recorder)?;
|
||||
(self.reformat)(context, formatter, &recorder)
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `ConcatTemplate`, but inserts a separator between non-empty templates.
|
||||
pub struct SeparateTemplate<S, T> {
|
||||
separator: S,
|
||||
|
|
Loading…
Reference in a new issue