From 7d6045c17ad107805a318aaeb61baac2ecf8e98a Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Sat, 17 Sep 2016 09:48:14 +0200 Subject: Added more generic printing --- src/config.rs | 4 ++ src/lib.rs | 22 ++----- src/parser.rs | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 183 insertions(+), 43 deletions(-) diff --git a/src/config.rs b/src/config.rs index aff8812..f4a19f3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -49,6 +49,9 @@ pub struct Config { /// Set to false if the output should not be colored pub colored_output: bool, + /// The default template for the changelog printing + pub default_template: String, + /// Show or hide the debug messages like `[OKAY] ...` or `[INFO] ...` pub enable_debug: bool, @@ -78,6 +81,7 @@ impl Config { pub fn new() -> Self { Config { colored_output: true, + default_template: "changelog_template.toml".to_owned(), enable_debug: true, excluded_tags: vec![], output_file: "CHANGELOG.md".to_owned(), diff --git a/src/lib.rs b/src/lib.rs index d9ee6da..5e12d42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ extern crate lazy_static; use git2::{ObjectType, Oid, Repository}; use chrono::{UTC, TimeZone}; -use parser::{Parser, ParsedCommit, ParsedTag, Print, PrintWithTag}; +use parser::{Parser, ParsedCommit, ParsedTag}; pub use config::Config; use std::{fmt, fs}; @@ -209,6 +209,9 @@ impl GitJournal { /// # Set to false if the output should not be colored /// colored_output = true /// + /// # The default template for the changelog printing + /// default_template = "changelog_template.toml" + /// /// # Show or hide the debug messages like `[OKAY] ...` or `[INFO] ...` /// enable_debug = true /// @@ -484,22 +487,7 @@ impl GitJournal { if let Some(template) = template { try!(Parser::parse_template_and_print(template, &self.parse_result, &self.config, &compact)); } else { - // Print without any template - let mut t = try!(term::stdout().ok_or(term::Error::NotSupported)); - for &(ref tag, ref commits) in &self.parse_result { - try!(tag.print(&mut t, &self.config)); - let mut c = commits.clone(); - - // Sort by category - c.sort_by(|a, b| a.summary.category.cmp(&b.summary.category)); - for commit in c { - if compact { - try!(commit.summary.print(&mut t, &self.config, None)); - } else { - try!(commit.print(&mut t, &self.config, None)); - } - } - } + try!(Parser::print(&self.parse_result, &self.config, &compact)); } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index 812848c..af98f78 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -63,10 +63,23 @@ pub enum Printed { Something, } -pub trait PrintWithTag { - fn print(&self, t: &mut Box, config: &Config, tag: Option<&str>) -> Result; +trait PrintWithTag { + fn print(&self, + t: &mut T, + config: &Config, + tag: Option<&str>, + c1: &F, + c2: &G, + c3: &H) + -> Result + where F: Fn(&mut T) -> Result<(), Error>, + G: Fn(&mut T) -> Result<(), Error>, + H: Fn(&mut T) -> Result<(), Error>; + fn contains_tag(&self, tag: Option<&str>) -> bool; + fn contains_untagged(&self) -> bool; + fn matches_default_tag(&self, tag: Option<&str>) -> bool { if let Some(tag) = tag { tag == "default" && self.contains_untagged() @@ -76,8 +89,11 @@ pub trait PrintWithTag { } } -pub trait Print { - fn print(&self, t: &mut Box, config: &Config) -> Result; +trait Print { + fn print(&self, t: &mut T, config: &Config, c1: &F, c2: &G, c3: &H) -> Result + where F: Fn(&mut T) -> Result<(), Error>, + G: Fn(&mut T) -> Result<(), Error>, + H: Fn(&mut T) -> Result<(), Error>; } #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] @@ -87,13 +103,17 @@ pub struct ParsedTag { } impl Print for ParsedTag { - fn print(&self, t: &mut Box, config: &Config) -> Result { + fn print(&self, t: &mut T, config: &Config, c1: &F, c2: &G, c3: &H) -> Result + where F: Fn(&mut T) -> Result<(), Error>, + G: Fn(&mut T) -> Result<(), Error>, + H: Fn(&mut T) -> Result<(), Error> + { if config.colored_output { - try!(t.fg(term::color::GREEN)); + try!(c1(t)); } try!(write!(t, "\n{} ", self.name)); if config.colored_output { - try!(t.fg(term::color::YELLOW)); + try!(c2(t)); } try!(writeln!(t, "({}-{:02}-{:02}):", @@ -101,7 +121,7 @@ impl Print for ParsedTag { self.date.month(), self.date.day())); if config.colored_output { - try!(t.reset()); + try!(c3(t)); } Ok(Printed::Something) } @@ -115,13 +135,24 @@ pub struct ParsedCommit { } impl PrintWithTag for ParsedCommit { - fn print(&self, t: &mut Box, config: &Config, tag: Option<&str>) -> Result { + fn print(&self, + t: &mut T, + config: &Config, + tag: Option<&str>, + c1: &F, + c2: &G, + c3: &H) + -> Result + where F: Fn(&mut T) -> Result<(), Error>, + G: Fn(&mut T) -> Result<(), Error>, + H: Fn(&mut T) -> Result<(), Error> + { // If summary is already filtered out then do not print at all - if try!(self.summary.print(t, config, tag)) == Printed::Nothing { + if try!(self.summary.print(t, config, tag, c1, c2, c3)) == Printed::Nothing { return Ok(Printed::Nothing); } for item in &self.body { - try!(item.print(t, config, tag)); + try!(item.print(t, config, tag, c1, c2, c3)); } Ok(Printed::Something) } @@ -144,7 +175,18 @@ pub struct SummaryElement { } impl PrintWithTag for SummaryElement { - fn print(&self, t: &mut Box, config: &Config, tag: Option<&str>) -> Result { + fn print(&self, + t: &mut T, + config: &Config, + tag: Option<&str>, + c1: &F, + c2: &G, + c3: &H) + -> Result + where F: Fn(&mut T) -> Result<(), Error>, + G: Fn(&mut T) -> Result<(), Error>, + H: Fn(&mut T) -> Result<(), Error> + { // Filter out excluded tags if self.tags.iter().filter(|x| config.excluded_tags.contains(x)).count() > 0usize { return Ok(Printed::Nothing); @@ -156,14 +198,14 @@ impl PrintWithTag for SummaryElement { try!(write!(t, "{} ", self.prefix)); } if config.colored_output { - try!(t.fg(term::color::BRIGHT_BLUE)); + try!(c1(t)); } print!("[{}]", self.category); if config.colored_output { - try!(t.fg(term::color::WHITE)); + try!(c2(t)); } try!(writeln!(t, "{}", self.text)); - try!(t.reset()); + try!(c3(t)); } Ok(Printed::Something) } @@ -202,15 +244,26 @@ pub struct ParagraphElement { impl PrintWithTag for BodyElement { - fn print(&self, t: &mut Box, config: &Config, tag: Option<&str>) -> Result { + fn print(&self, + t: &mut T, + config: &Config, + tag: Option<&str>, + c1: &F, + c2: &G, + c3: &H) + -> Result + where F: Fn(&mut T) -> Result<(), Error>, + G: Fn(&mut T) -> Result<(), Error>, + H: Fn(&mut T) -> Result<(), Error> + { match *self { BodyElement::List(ref vec) => { for list_item in vec { - try!(list_item.print(t, config, tag)); + try!(list_item.print(t, config, tag, c1, c2, c3)); } } BodyElement::Paragraph(ref paragraph) => { - try!(paragraph.print(t, config, tag)); + try!(paragraph.print(t, config, tag, c1, c2, c3)); } } Ok(Printed::Something) @@ -232,7 +285,18 @@ impl PrintWithTag for BodyElement { } impl PrintWithTag for ListElement { - fn print(&self, t: &mut Box, config: &Config, tag: Option<&str>) -> Result { + fn print(&self, + t: &mut T, + config: &Config, + tag: Option<&str>, + c1: &F, + c2: &G, + c3: &H) + -> Result + where F: Fn(&mut T) -> Result<(), Error>, + G: Fn(&mut T) -> Result<(), Error>, + H: Fn(&mut T) -> Result<(), Error> + { // Check if list item contains excluded tag if self.tags.iter().filter(|x| config.excluded_tags.contains(x)).count() > 0usize { return Ok(Printed::Nothing); @@ -248,15 +312,15 @@ impl PrintWithTag for ListElement { })); if !self.category.is_empty() { if config.colored_output { - try!(t.fg(term::color::BRIGHT_BLUE)); + try!(c1(t)); } try!(write!(t, "[{}]", self.category)); if config.colored_output { - try!(t.fg(term::color::WHITE)); + try!(c2(t)); } } try!(writeln!(t, "{}", self.text)); - try!(t.reset()); + try!(c3(t)); } Ok(Printed::Something) @@ -276,7 +340,19 @@ impl PrintWithTag for ListElement { } impl PrintWithTag for ParagraphElement { - fn print(&self, t: &mut Box, config: &Config, tag: Option<&str>) -> Result { + #[allow(unused_variables)] + fn print(&self, + t: &mut T, + config: &Config, + tag: Option<&str>, + c1: &F, + c2: &G, + c3: &H) + -> Result + where F: Fn(&mut T) -> Result<(), Error>, + G: Fn(&mut T) -> Result<(), Error>, + H: Fn(&mut T) -> Result<(), Error> + { // Check if paragraph contains excluded tag if self.tags.iter().filter(|x| config.excluded_tags.contains(x)).count() > 0usize { return Ok(Printed::Nothing); @@ -454,26 +530,89 @@ impl Parser { }) } + /// Prints the commits without any template (sorted by category) + pub fn print(parsed_commits: &[(ParsedTag, Vec)], + config: &Config, + compact: &bool) + -> Result<(), Error> { + let mut t = try!(term::stdout().ok_or(term::Error::NotSupported)); + for &(ref tag, ref commits) in parsed_commits { + try!(tag.print(&mut t, config, &|t| { + try!(t.fg(term::color::GREEN)); + Ok(()) + }, &|t| { + try!(t.fg(term::color::YELLOW)); + Ok(()) + }, &|t| { + try!(t.reset()); + Ok(()) + })); + let mut c = commits.clone(); + + // Sort by category + c.sort_by(|a, b| a.summary.category.cmp(&b.summary.category)); + for commit in c { + if *compact { + try!(commit.summary.print(&mut t, config, None, &|t| { + try!(t.fg(term::color::BRIGHT_BLUE)); + Ok(()) + }, &|t| { + try!(t.fg(term::color::WHITE)); + Ok(()) + }, &|t| { + try!(t.reset()); + Ok(()) + })); + } else { + try!(commit.print(&mut t, config, None, &|t| { + try!(t.fg(term::color::BRIGHT_BLUE)); + Ok(()) + }, &|t| { + try!(t.fg(term::color::WHITE)); + Ok(()) + }, &|t| { + try!(t.reset()); + Ok(()) + })); + } + } + } + try!(t.reset()); + Ok(()) + } + /// Parses a toml output template and filters it through parsed commits pub fn parse_template_and_print(template: &str, parsed_commits: &[(ParsedTag, Vec)], config: &Config, compact: &bool) -> Result<(), Error> { + // Parse toml from file let mut file = try!(File::open(template)); let mut toml_string = String::new(); try!(file.read_to_string(&mut toml_string)); let toml = try!(toml::Parser::new(&toml_string).parse().ok_or(toml::Error::Custom("Could not parse toml template.".to_owned()))); + + // Print the commits let mut t = try!(term::stdout().ok_or(Error::Terminal)); for &(ref tag, ref commits) in parsed_commits { - try!(tag.print(&mut t, config)); + try!(tag.print(&mut t, config, &|t| { + try!(t.fg(term::color::GREEN)); + Ok(()) + }, &|t| { + try!(t.fg(term::color::YELLOW)); + Ok(()) + }, &|t| { + try!(t.reset()); + Ok(()) + })); try!(Parser::print_commits_in_table(&mut t, &toml, &mut 1, commits, config, &compact)); } try!(t.reset()); Ok(()) } - fn print_commits_in_table(t: &mut Box, + fn print_commits_in_table(mut t: &mut Box, table: &toml::Table, level: &mut usize, commits: &[ParsedCommit], @@ -503,7 +642,16 @@ impl Parser { // Print commits for this tag for commit in commits { - try!(commit.print(t, config, Some(tag))); + try!(commit.print(&mut t, config, Some(tag), &|t| { + try!(t.fg(term::color::BRIGHT_BLUE)); + Ok(()) + }, &|t| { + try!(t.fg(term::color::WHITE)); + Ok(()) + }, &|t| { + try!(t.reset()); + Ok(()) + })); } try!(writeln!(t, "")); -- cgit v1.2.3