1 use crate::*; 2 3 #[derive(Debug, Clone)] 4 pub struct CellDef { 5 /// how the cell will be filled, may be a template 6 pub md: String, 7 8 pub align: Alignment, 9 } 10 11 #[derive(Debug, Clone)] 12 pub struct Col { 13 pub header: CellDef, 14 pub content: CellDef, 15 } 16 17 /// A facility to build templates for tables 18 /// 19 /// You can for example build a table this two ways: 20 /// 21 /// ### with an explicit string: 22 /// 23 /// ``` 24 /// static MD: &str = r#" 25 /// |-:|:-:|:-:|:-:|:-:|-:|:-:|:-:|:-|:- 26 /// |id|dev|filesystem|disk|type|used|use%|free|size|mount point 27 /// |-:|:-|:-|:-:|:-:|-:|-:|-:|:- 28 /// ${rows 29 /// |${id}|${dev-major}:${dev-minor}|${filesystem}|${disk}|${type}|~~${used}~~|~~${use-percents}~~ `${bar}`|*${free}*|**${size}**|${mount-point} 30 /// } 31 /// |-: 32 /// "#; 33 /// ``` 34 /// ### with a table_builder: 35 /// 36 /// ``` 37 /// use minimad::{*, Alignment::*}; 38 /// 39 /// let mut tbl = TableBuilder::default(); 40 /// tbl 41 /// .col(Col::simple("id").align(Right)) 42 /// .col(Col::new("dev", "${dev-major}:${dev-minor}")) 43 /// .col(Col::simple("filesystem")) 44 /// .col(Col::simple("disk").align_content(Center)) 45 /// .col(Col::simple("type")) 46 /// .col(Col::new("used", "~~${used}~~")) 47 /// .col(Col::new("use%", "~~${use-percents}~~ `${bar}`").align_content(Right)) 48 /// .col(Col::new("free", "*${free}*").align(Right)) 49 /// .col(Col::new("size", "**${size}**")) 50 /// .col(Col::simple("mount point").align(Left)); 51 /// ``` 52 /// 53 /// Both ways are mostly equivalent but a table builder makes it easier to dynamically 54 /// define the columns. 55 /// 56 /// (example taken from [lfs](https://github.com/Canop/lfs)) 57 #[derive(Debug, Clone, Default)] 58 pub struct TableBuilder { 59 pub cols: Vec<Col>, 60 /// an optional name for the sub template for the rows. 61 /// This is mostly useful when you want to concatenate 62 /// table templates and you need to distinguish their 63 /// subs 64 pub rows_sub_name: Option<String>, 65 } 66 67 impl CellDef { new<S: Into<String>>(md: S) -> Self68 pub fn new<S: Into<String>>(md: S) -> Self { 69 Self { 70 md: md.into(), 71 align: Alignment::Unspecified, 72 } 73 } align(mut self, align: Alignment) -> Self74 pub fn align(mut self, align: Alignment) -> Self { 75 self.align = align; 76 self 77 } 78 } 79 80 impl Col { simple<S: AsRef<str>>(var_name: S) -> Self81 pub fn simple<S: AsRef<str>>(var_name: S) -> Self { 82 Self::new( 83 var_name.as_ref().to_string(), 84 format!("${{{}}}", var_name.as_ref().replace(' ', "-")), 85 ) 86 } new<H: Into<String>, C: Into<String>>(header_md: H, content_md: C) -> Self87 pub fn new<H: Into<String>, C: Into<String>>(header_md: H, content_md: C) -> Self { 88 Self { 89 header: CellDef::new(header_md).align(Alignment::Center), 90 content: CellDef::new(content_md), 91 } 92 } align(mut self, align: Alignment) -> Self93 pub fn align(mut self, align: Alignment) -> Self { 94 self.header.align = align; 95 self.content.align = align; 96 self 97 } align_header(mut self, align: Alignment) -> Self98 pub fn align_header(mut self, align: Alignment) -> Self { 99 self.header.align = align; 100 self 101 } align_content(mut self, align: Alignment) -> Self102 pub fn align_content(mut self, align: Alignment) -> Self { 103 self.content.align = align; 104 self 105 } 106 } 107 108 impl TableBuilder { col(&mut self, col: Col) -> &mut Self109 pub fn col(&mut self, col: Col) -> &mut Self { 110 self.cols.push(col); 111 self 112 } 113 /// build the string of a template of the table template_md(&self) -> String114 pub fn template_md(&self) -> String { 115 let mut md = String::new(); 116 for col in &self.cols { 117 md.push_str(col.header.align.col_spec()); 118 } 119 md.push('\n'); 120 for col in &self.cols { 121 md.push('|'); 122 md.push_str(&col.header.md); 123 } 124 md.push('\n'); 125 for col in &self.cols { 126 md.push_str(col.content.align.col_spec()); 127 } 128 md.push_str("\n${"); 129 if let Some(name) = self.rows_sub_name.as_ref() { 130 md.push_str(name); 131 } else { 132 md.push_str("rows"); 133 } 134 md.push('\n'); 135 for col in &self.cols { 136 md.push('|'); 137 md.push_str(&col.content.md); 138 } 139 md.push_str("\n}\n|-\n"); 140 md 141 } 142 } 143 144 145 impl From<&TableBuilder> for String { from(tblbl: &TableBuilder) -> String146 fn from(tblbl: &TableBuilder) -> String { 147 tblbl.template_md() 148 } 149 } 150