938 lines · 27.0 KB · Rust
RawDownload
// Copyright 2020 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. //! Tools for lazily evaluating templates that produce text in a fallible//! manner. use std::cell::RefCell;use std::error;use std::fmt;use std::io;use std::io::Write;use std::iter;use std::rc::Rc; use bstr::BStr;use bstr::BString;use jj_lib::backend::Signature;use jj_lib::backend::Timestamp;use jj_lib::config::ConfigValue;use jj_lib::op_store::TimestampRange; 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 a printable type or a compiled template containing a placeholder/// value.////// This is analogous to [`std::fmt::Display`], but with customized error/// handling.pub trait Template {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()>;} /// Template that supports list-like behavior.pub trait ListTemplate: Template {    /// Concatenates items with the given separator.    fn join<'a>(self: Box<Self>, separator: Box<dyn Template + 'a>) -> Box<dyn Template + 'a>    where        Self: 'a;     /// Upcasts to the template type.    fn into_template<'a>(self: Box<Self>) -> Box<dyn Template + 'a>    where        Self: 'a;} impl<T: Template + ?Sized> Template for &T {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        <T as Template>::format(self, formatter)    }} impl<T: Template + ?Sized> Template for Box<T> {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        <T as Template>::format(self, formatter)    }} // All optional printable types should be printable, and it's unlikely to// implement different formatting per type.impl<T: Template> Template for Option<T> {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        self.as_ref().map_or(Ok(()), |t| t.format(formatter))    }} impl Template for BString {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        formatter.as_mut().write_all(self)    }} impl Template for &BStr {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        formatter.as_mut().write_all(self)    }} impl Template for ConfigValue {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        write!(formatter, "{self}")    }} impl Template for Signature {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        write!(formatter.labeled("name"), "{}", self.name)?;        if !self.name.is_empty() && !self.email.is_empty() {            write!(formatter, " ")?;        }        if !self.email.is_empty() {            write!(formatter, "<")?;            let email = Email(self.email.clone());            email.format(formatter)?;            write!(formatter, ">")?;        }        Ok(())    }} #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]#[serde(transparent)]pub struct Email(pub String); impl Template for Email {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        let (local, domain) = text_util::split_email(&self.0);        write!(formatter.labeled("local"), "{local}")?;        if let Some(domain) = 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.pub type SizeHint = (usize, Option<usize>); impl Template for String {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        write!(formatter, "{self}")    }} impl Template for &str {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        write!(formatter, "{self}")    }} impl Template for Timestamp {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        match time_util::format_absolute_timestamp(self) {            Ok(formatted) => write!(formatter, "{formatted}"),            Err(err) => formatter.handle_error(err.into()),        }    }} impl Template for TimestampRange {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        self.start.format(formatter)?;        write!(formatter, " - ")?;        self.end.format(formatter)?;        Ok(())    }} impl Template for Vec<String> {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        format_joined(formatter, self, " ")    }} impl Template for bool {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        let repr = if *self { "true" } else { "false" };        write!(formatter, "{repr}")    }} impl Template for i64 {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        write!(formatter, "{self}")    }} pub struct LabelTemplate<T, L> {    content: T,    labels: L,} impl<T, L> LabelTemplate<T, L> {    pub fn new(content: T, labels: L) -> Self    where        T: Template,        L: TemplateProperty<Output = Vec<String>>,    {        Self { content, labels }    }} impl<T, L> Template for LabelTemplate<T, L>where    T: Template,    L: TemplateProperty<Output = Vec<String>>,{    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        match self.labels.extract() {            Ok(labels) => format_labeled(formatter, &self.content, &labels),            Err(err) => formatter.handle_error(err),        }    }} pub struct RawEscapeSequenceTemplate<T>(pub T); impl<T: Template> Template for RawEscapeSequenceTemplate<T> {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        let rewrap = formatter.rewrap_fn();        let mut raw_formatter = PlainTextFormatter::new(formatter.raw()?);        self.0.format(&mut rewrap(&mut raw_formatter))    }} /// Renders contents in order, and returns the first non-empty output.pub struct CoalesceTemplate<T>(pub Vec<T>); impl<T: Template> Template for CoalesceTemplate<T> {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        let Some((last, contents)) = self.0.split_last() else {            return Ok(());        };        let record_non_empty = record_non_empty_fn(formatter);        if let Some(recorder) = contents.iter().find_map(record_non_empty) {            recorder?.replay(formatter.as_mut())        } else {            last.format(formatter) // no need to capture the last content        }    }} pub struct ConcatTemplate<T>(pub Vec<T>); impl<T: Template> Template for ConcatTemplate<T> {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        for template in &self.0 {            template.format(formatter)?;        }        Ok(())    }} /// 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(content: T, reformat: F) -> Self    where        T: Template,        F: Fn(&mut TemplateFormatter, &FormatRecorder) -> io::Result<()>,    {        Self { content, reformat }    }} impl<T, F> Template for ReformatTemplate<T, F>where    T: Template,    F: Fn(&mut TemplateFormatter, &FormatRecorder) -> io::Result<()>,{    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        let rewrap = formatter.rewrap_fn();        let mut recorder = FormatRecorder::new();        self.content.format(&mut rewrap(&mut recorder))?;        (self.reformat)(formatter, &recorder)    }} /// Like `ConcatTemplate`, but inserts a separator between non-empty templates.pub struct SeparateTemplate<S, T> {    separator: S,    contents: Vec<T>,} impl<S, T> SeparateTemplate<S, T> {    pub fn new(separator: S, contents: Vec<T>) -> Self    where        S: Template,        T: Template,    {        Self {            separator,            contents,        }    }} impl<S, T> Template for SeparateTemplate<S, T>where    S: Template,    T: Template,{    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        let record_non_empty = record_non_empty_fn(formatter);        let mut content_recorders = self.contents.iter().filter_map(record_non_empty).fuse();        if let Some(recorder) = content_recorders.next() {            recorder?.replay(formatter.as_mut())?;        }        for recorder in content_recorders {            self.separator.format(formatter)?;            recorder?.replay(formatter.as_mut())?;        }        Ok(())    }} /// Wrapper around an error occurred during template evaluation.#[derive(Debug)]pub struct TemplatePropertyError(pub Box<dyn error::Error + Send + Sync>); // Implements conversion from any error type to support `expr?` in function// binding. This type doesn't implement `std::error::Error` instead.// <https://github.com/dtolnay/anyhow/issues/25#issuecomment-544140480>impl<E> From<E> for TemplatePropertyErrorwhere    E: error::Error + Send + Sync + 'static,{    fn from(err: E) -> Self {        Self(err.into())    }} /// Lazily evaluated value which can fail to evaluate.pub trait TemplateProperty {    type Output;     fn extract(&self) -> Result<Self::Output, TemplatePropertyError>;} impl<P: TemplateProperty + ?Sized> TemplateProperty for Box<P> {    type Output = <P as TemplateProperty>::Output;     fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {        <P as TemplateProperty>::extract(self)    }} impl<P: TemplateProperty> TemplateProperty for Option<P> {    type Output = Option<P::Output>;     fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {        self.as_ref().map(|property| property.extract()).transpose()    }} // Implement TemplateProperty for tuplesmacro_rules! tuple_impls {    ($( ( $($n:tt $T:ident),+ ) )+) => {        $(            impl<$($T: TemplateProperty,)+> TemplateProperty for ($($T,)+) {                type Output = ($($T::Output,)+);                 fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {                    Ok(($(self.$n.extract()?,)+))                }            }        )+    }} tuple_impls! {    (0 T0)    (0 T0, 1 T1)    (0 T0, 1 T1, 2 T2)    (0 T0, 1 T1, 2 T2, 3 T3)} /// Type-erased [`TemplateProperty`].pub type BoxedTemplateProperty<'a, O> = Box<dyn TemplateProperty<Output = O> + 'a>;pub type BoxedSerializeProperty<'a> =    BoxedTemplateProperty<'a, Box<dyn erased_serde::Serialize + 'a>>; /// [`TemplateProperty`] adapters that are useful when implementing methods.pub trait TemplatePropertyExt: TemplateProperty {    /// Translates to a property that will apply fallible `function` to an    /// extracted value.    fn and_then<O, F>(self, function: F) -> TemplateFunction<Self, F>    where        Self: Sized,        F: Fn(Self::Output) -> Result<O, TemplatePropertyError>,    {        TemplateFunction::new(self, function)    }     /// Translates to a property that will apply `function` to an extracted    /// value, leaving `Err` untouched.    fn map<O, F>(self, function: F) -> impl TemplateProperty<Output = O>    where        Self: Sized,        F: Fn(Self::Output) -> O,    {        TemplateFunction::new(self, move |value| Ok(function(value)))    }     /// Translates to a property that will unwrap an extracted `Option` value    /// of the specified `type_name`, mapping `None` to `Err`.    fn try_unwrap<O>(self, type_name: &str) -> impl TemplateProperty<Output = O>    where        Self: TemplateProperty<Output = Option<O>> + Sized,    {        self.and_then(move |opt| {            opt.ok_or_else(|| TemplatePropertyError(format!("No {type_name} available").into()))        })    }     /// Converts this property into boxed serialize property.    fn into_serialize<'a>(self) -> BoxedSerializeProperty<'a>    where        Self: Sized + 'a,        Self::Output: serde::Serialize,    {        Box::new(self.map(|value| Box::new(value) as Box<dyn erased_serde::Serialize>))    }     /// Converts this property into `Template`.    fn into_template<'a>(self) -> Box<dyn Template + 'a>    where        Self: Sized + 'a,        Self::Output: Template,    {        Box::new(FormattablePropertyTemplate::new(self))    }     /// Converts this property into boxed trait object.    fn into_dyn<'a>(self) -> BoxedTemplateProperty<'a, Self::Output>    where        Self: Sized + 'a,    {        Box::new(self)    }     /// Converts this property into wrapped (or tagged) type.    ///    /// Use `W::wrap_property()` if the self type is known to be boxed.    fn into_dyn_wrapped<'a, W>(self) -> W    where        Self: Sized + 'a,        W: WrapTemplateProperty<'a, Self::Output>,    {        W::wrap_property(self.into_dyn())    }} impl<P: TemplateProperty + ?Sized> TemplatePropertyExt for P {} /// Wraps template property of type `O` in tagged type.////// This is basically [`From<BoxedTemplateProperty<'a, O>>`], but is restricted/// to property types.#[diagnostic::on_unimplemented(    message = "the template property of type `{O}` cannot be wrapped in `{Self}`")]pub trait WrapTemplateProperty<'a, O>: Sized {    fn wrap_property(property: BoxedTemplateProperty<'a, O>) -> Self;} /// Adapter that wraps literal value in `TemplateProperty`.pub struct Literal<O>(pub O); impl<O: Template> Template for Literal<O> {    fn format(&self, formatter: &mut TemplateFormatter) -> io::Result<()> {        self.0.format(formatter)    }} impl<O: Clone> TemplateProperty for Literal<O> {    type Output = O;     fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {        Ok(self.0.clone())    }} /// Adapter to extract template value from property for displaying.pub struct FormattablePropertyTemplate<P> {    property: P,} impl<P> FormattablePropertyTemplate<P> {    pub fn new(property: P) -> Self    where        P: TemplateProperty,        P::Output: Template,    {        Self { property }    }} 

Lines 1–500 of 938.