1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
use super::{entry::Entry, Result}; use chrono::prelude::*; use colored::*; use handlebars::{ Context, Handlebars, Helper, HelperDef, HelperResult, JsonRender, Output, RenderContext, }; use std::collections::BTreeMap; pub struct Format<'a> { renderer: Handlebars<'a>, } impl<'a> Format<'a> { pub fn with_template(template: &str) -> Result<Self> { let mut renderer = Handlebars::new(); renderer.set_strict_mode(true); renderer.register_escape_fn(|s| s.trim().to_owned()); renderer.register_template_string("template", template)?; renderer.register_helper("indent", Box::new(IndentHelper::new())); renderer.register_helper("strftime", Box::new(StrftimeHelper {})); renderer.register_helper("color", Box::new(ColorHelper {})); Ok(Format { renderer }) } pub fn format_entry(&self, entry: &Entry) -> Result<String> { let mut data = BTreeMap::new(); data.insert("raw".to_owned(), entry.to_csv_row()?); data.insert("datetime".to_owned(), entry.datetime().to_rfc3339()); data.insert("message".to_owned(), entry.message().to_owned()); Ok(self.renderer.render("template", &data)?) } } struct IndentHelper<'a> { wrapper: textwrap::Wrapper<'a, textwrap::HyphenSplitter>, } impl<'a> IndentHelper<'a> { fn new() -> Self { let wrapper = textwrap::Wrapper::with_termwidth() .initial_indent("| ") .subsequent_indent("| "); IndentHelper { wrapper } } } impl<'a> HelperDef for IndentHelper<'a> { fn call<'reg: 'rc, 'rc>( &self, h: &Helper, _: &Handlebars, _: &Context, _: &mut RenderContext, out: &mut dyn Output, ) -> HelperResult { let param = h.param(0).unwrap(); Ok(out.write(&self.wrapper.fill(¶m.value().render()))?) } } struct StrftimeHelper {} impl HelperDef for StrftimeHelper { fn call<'reg: 'rc, 'rc>( &self, h: &Helper, _: &Handlebars, _: &Context, _: &mut RenderContext, out: &mut dyn Output, ) -> HelperResult { let date_str = h.param(1).unwrap().value().render(); let date = DateTime::parse_from_rfc3339(&date_str) .map_err(|_| handlebars::RenderError::new("couldn't parse date"))?; let local_date = date.with_timezone(&Local); let format_str = h.param(0).unwrap().value().render(); Ok(out.write(&local_date.format(&format_str).to_string())?) } } struct ColorHelper {} impl HelperDef for ColorHelper { fn call<'reg: 'rc, 'rc>( &self, h: &Helper, _: &Handlebars, _: &Context, _: &mut RenderContext, out: &mut dyn Output, ) -> HelperResult { let color = h.param(0).unwrap().value().render(); let s = h.param(1).unwrap().value().render(); Ok(out.write(&format!("{}", s.color(color)))?) } }