templater: add TimestampRange type, migrate operation time to it

This commit is contained in:
Yuya Nishihara 2023-02-19 16:20:41 +09:00
parent da3c1d2286
commit eafbd977a3
3 changed files with 93 additions and 17 deletions

View file

@ -7,10 +7,8 @@ use jujutsu_lib::operation::Operation;
use crate::cli_util::{user_error, CommandError, CommandHelper};
use crate::formatter::Formatter;
use crate::graphlog::{get_graphlog, Edge};
use crate::templater::Template;
use crate::time_util::{
format_absolute_timestamp, format_duration, format_timestamp_relative_to_now,
};
use crate::templater::{Template, TimestampRange};
use crate::time_util::format_timestamp_relative_to_now;
use crate::ui::Ui;
/// Commands for working with the operation log
@ -71,22 +69,19 @@ fn cmd_op_log(
metadata.hostname
)?;
formatter.write_str(" ")?;
let time_range = TimestampRange {
start: metadata.start_time.clone(),
end: metadata.end_time.clone(),
};
if self.relative_timestamps {
let mut f = timeago::Formatter::new();
f.min_unit(timeago::TimeUnit::Microseconds).ago("");
let mut duration = format_duration(&metadata.start_time, &metadata.end_time, &f);
if duration == "now" {
duration = "less than a microsecond".to_string()
}
let start = format_timestamp_relative_to_now(&metadata.start_time);
write!(formatter.labeled("time"), "{start}, lasted {duration}")?;
} else {
let start = format_timestamp_relative_to_now(&time_range.start);
write!(
formatter.labeled("time"),
"{} - {}",
format_absolute_timestamp(&metadata.start_time),
format_absolute_timestamp(&metadata.end_time)
"{start}, lasted {duration}",
duration = time_range.duration()
)?;
} else {
time_range.format(&(), formatter)?;
}
formatter.write_str("\n")?;
write!(

View file

@ -27,7 +27,7 @@ use thiserror::Error;
use crate::templater::{
ConditionalTemplate, IntoTemplate, LabelTemplate, ListTemplate, Literal,
PlainTextFormattedProperty, SeparateTemplate, Template, TemplateFunction, TemplateProperty,
TemplatePropertyFn,
TemplatePropertyFn, TimestampRange,
};
use crate::time_util;
@ -610,6 +610,10 @@ pub trait TemplateLanguage<'a> {
&self,
property: Box<dyn TemplateProperty<Self::Context, Output = Timestamp> + 'a>,
) -> Self::Property;
fn wrap_timestamp_range(
&self,
property: Box<dyn TemplateProperty<Self::Context, Output = TimestampRange> + 'a>,
) -> Self::Property;
fn build_keyword(&self, name: &str, span: pest::Span) -> TemplateParseResult<Self::Property>;
fn build_method(
@ -635,6 +639,7 @@ macro_rules! impl_core_wrap_property_fns {
wrap_integer(i64) => Integer,
wrap_signature(jujutsu_lib::backend::Signature) => Signature,
wrap_timestamp(jujutsu_lib::backend::Timestamp) => Timestamp,
wrap_timestamp_range($crate::templater::TimestampRange) => TimestampRange,
}
);
};
@ -672,6 +677,7 @@ pub enum CoreTemplatePropertyKind<'a, I> {
Integer(Box<dyn TemplateProperty<I, Output = i64> + 'a>),
Signature(Box<dyn TemplateProperty<I, Output = Signature> + 'a>),
Timestamp(Box<dyn TemplateProperty<I, Output = Timestamp> + 'a>),
TimestampRange(Box<dyn TemplateProperty<I, Output = TimestampRange> + 'a>),
}
impl<'a, I: 'a> IntoTemplateProperty<'a, I> for CoreTemplatePropertyKind<'a, I> {
@ -708,6 +714,7 @@ impl<'a, I: 'a> IntoTemplate<'a, I> for CoreTemplatePropertyKind<'a, I> {
CoreTemplatePropertyKind::Integer(property) => property.into_template(),
CoreTemplatePropertyKind::Signature(property) => property.into_template(),
CoreTemplatePropertyKind::Timestamp(property) => property.into_template(),
CoreTemplatePropertyKind::TimestampRange(property) => property.into_template(),
}
}
}
@ -869,6 +876,9 @@ pub fn build_core_method<'a, L: TemplateLanguage<'a>>(
CoreTemplatePropertyKind::Timestamp(property) => {
build_timestamp_method(language, property, function)
}
CoreTemplatePropertyKind::TimestampRange(property) => {
build_timestamp_range_method(language, property, function)
}
}
}
@ -977,6 +987,43 @@ fn build_timestamp_method<'a, L: TemplateLanguage<'a>>(
Ok(property)
}
fn build_timestamp_range_method<'a, L: TemplateLanguage<'a>>(
language: &L,
self_property: impl TemplateProperty<L::Context, Output = TimestampRange> + 'a,
function: &FunctionCallNode,
) -> TemplateParseResult<L::Property> {
let property = match function.name {
"start" => {
expect_no_arguments(function)?;
language.wrap_timestamp(chain_properties(
self_property,
TemplatePropertyFn(|time_range: &TimestampRange| time_range.start.clone()),
))
}
"end" => {
expect_no_arguments(function)?;
language.wrap_timestamp(chain_properties(
self_property,
TemplatePropertyFn(|time_range: &TimestampRange| time_range.end.clone()),
))
}
"duration" => {
expect_no_arguments(function)?;
language.wrap_string(chain_properties(
self_property,
TemplatePropertyFn(TimestampRange::duration),
))
}
_ => {
return Err(TemplateParseError::no_such_method(
"TimestampRange",
function,
))
}
};
Ok(property)
}
fn build_global_function<'a, L: TemplateLanguage<'a>>(
language: &L,
function: &FunctionCallNode,

View file

@ -73,6 +73,40 @@ impl Template<()> for Timestamp {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TimestampRange {
// Could be aliased to Range<Timestamp> if needed.
pub start: Timestamp,
pub end: Timestamp,
}
impl TimestampRange {
// TODO: Introduce duration type, and move formatting to it.
pub fn duration(&self) -> String {
let mut f = timeago::Formatter::new();
f.min_unit(timeago::TimeUnit::Microseconds).ago("");
let duration = time_util::format_duration(&self.start, &self.end, &f);
if duration == "now" {
"less than a microsecond".to_owned()
} else {
duration
}
}
}
impl Template<()> for TimestampRange {
fn format(&self, _: &(), formatter: &mut dyn Formatter) -> io::Result<()> {
self.start.format(&(), formatter)?;
write!(formatter, " - ")?;
self.end.format(&(), formatter)?;
Ok(())
}
fn has_content(&self, _: &()) -> bool {
true
}
}
impl Template<()> for bool {
fn format(&self, _: &(), formatter: &mut dyn Formatter) -> io::Result<()> {
formatter.write_str(if *self { "true" } else { "false" })