1#![warn(
2 missing_docs,
3 unused_extern_crates,
4 unused_import_braces,
5 unused_qualifications
6)]
7use std::fmt;
10use std::io::{
11 self,
12 Error,
13 Write,
14};
15use std::iter::{
16 FromIterator,
17 IntoIterator,
18};
19use std::ops::{
20 Index,
21 IndexMut,
22};
23use std::slice::{
24 Iter,
25 IterMut,
26};
27
28pub use term::{
29 color,
30 Attr,
31};
32pub(crate) use term::{
33 stdout,
34 Terminal,
35};
36
37mod cell;
38pub mod format;
39mod row;
40mod utils;
41
42#[cfg(feature = "csv")]
43pub mod csv;
44
45#[cfg(feature = "evcxr")]
46pub mod evcxr;
47
48pub use cell::Cell;
49use format::{
50 consts,
51 LinePosition,
52 TableFormat,
53};
54pub use row::Row;
55use utils::StringWriter;
56
57#[derive(Default, Clone, Debug, Hash, PartialEq, Eq)]
59pub struct Table {
60 format: Box<TableFormat>,
61 titles: Box<Option<Row>>,
62 rows: Vec<Row>,
63}
64
65#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
85pub struct TableSlice<'a> {
86 format: &'a TableFormat,
87 titles: &'a Option<Row>,
88 rows: &'a [Row],
89}
90
91impl TableSlice<'_> {
92 fn get_column_num(&self) -> usize {
95 let mut cnum = match *self.titles {
96 Some(ref t) => t.column_count(),
97 None => 0,
98 };
99 for r in self.rows {
100 let l = r.column_count();
101 if l > cnum {
102 cnum = l;
103 }
104 }
105 cnum
106 }
107
108 pub fn len(&self) -> usize {
110 self.rows.len()
111 }
112
113 pub fn is_empty(&self) -> bool {
115 self.rows.is_empty()
116 }
117
118 pub fn get_row(&self, row: usize) -> Option<&Row> {
120 self.rows.get(row)
121 }
122
123 fn get_column_width(&self, col_idx: usize) -> usize {
126 let mut width = match *self.titles {
127 Some(ref t) => t.get_column_width(col_idx, self.format),
128 None => 0,
129 };
130 for r in self.rows {
131 let l = r.get_column_width(col_idx, self.format);
132 if l > width {
133 width = l;
134 }
135 }
136 width
137 }
138
139 fn get_all_column_width(&self) -> Vec<usize> {
142 let colnum = self.get_column_num();
143 let mut col_width = vec![0usize; colnum];
144 #[allow(clippy::needless_range_loop)]
145 for i in 0..colnum {
146 col_width[i] = self.get_column_width(i);
148 }
149 col_width
150 }
151
152 pub fn column_iter(&self, column: usize) -> ColumnIter {
154 ColumnIter(self.rows.iter(), column)
155 }
156
157 pub fn row_iter(&self) -> Iter<Row> {
159 self.rows.iter()
160 }
161
162 fn __print<T: Write + ?Sized, F>(&self, out: &mut T, f: F) -> Result<usize, Error>
164 where
165 F: Fn(&Row, &mut T, &TableFormat, &[usize]) -> Result<usize, Error>,
166 {
167 let mut height = 0;
168 let col_width = self.get_all_column_width();
170 height += self
171 .format
172 .print_line_separator(out, &col_width, LinePosition::Top)?;
173 if let Some(ref t) = *self.titles {
174 height += f(t, out, self.format, &col_width)?;
175 height += self
176 .format
177 .print_line_separator(out, &col_width, LinePosition::Title)?;
178 }
179 let mut iter = self.rows.iter().peekable();
181 while let Some(r) = iter.next() {
182 height += f(r, out, self.format, &col_width)?;
183 if iter.peek().is_some() {
184 height += self
185 .format
186 .print_line_separator(out, &col_width, LinePosition::Intern)?;
187 }
188 }
189 height += self
190 .format
191 .print_line_separator(out, &col_width, LinePosition::Bottom)?;
192 out.flush()?;
193 Ok(height)
194 }
195
196 pub fn print<T: Write + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
199 self.__print(out, Row::print)
200 }
201
202 pub fn print_term<T: Terminal + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
205 self.__print(out, Row::print_term)
206 }
207
208 pub fn print_tty(&self, force_colorize: bool) -> Result<usize, Error> {
217 use is_terminal::IsTerminal;
218 match (stdout(), io::stdout().is_terminal() || force_colorize) {
219 (Some(mut o), true) => self.print_term(&mut *o),
220 _ => self.print(&mut io::stdout()),
221 }
222 }
223
224 pub fn printstd(&self) {
231 let _ = self.print_tty(false); }
233
234 pub fn print_html<T: Write + ?Sized>(&self, out: &mut T) -> Result<(), Error> {
236 let column_num = self.get_column_num();
238 out.write_all(b"<table>")?;
239 if let Some(ref t) = *self.titles {
241 out.write_all(b"<th>")?;
242 t.print_html(out, column_num)?;
243 out.write_all(b"</th>")?;
244 }
245 for r in self.rows {
247 out.write_all(b"<tr>")?;
248 r.print_html(out, column_num)?;
249 out.write_all(b"</tr>")?;
250 }
251 out.write_all(b"</table>")?;
252 out.flush()?;
253 Ok(())
254 }
255}
256
257impl<'a> IntoIterator for &'a TableSlice<'a> {
258 type Item = &'a Row;
259 type IntoIter = Iter<'a, Row>;
260 fn into_iter(self) -> Self::IntoIter {
261 self.row_iter()
262 }
263}
264
265impl Table {
266 pub fn new() -> Table {
268 Self::init(Vec::new())
269 }
270
271 pub fn init(rows: Vec<Row>) -> Table {
273 Table {
274 rows,
275 titles: Box::new(None),
276 format: Box::new(*consts::FORMAT_DEFAULT),
277 }
278 }
279
280 pub fn set_format(&mut self, format: TableFormat) {
282 *self.format = format;
283 }
284
285 pub fn get_format(&mut self) -> &mut TableFormat {
287 &mut self.format
288 }
289
290 #[cfg(test)] pub(crate) fn get_column_num(&self) -> usize {
294 self.as_slice().get_column_num()
295 }
296
297 pub fn len(&self) -> usize {
299 self.rows.len()
300 }
301
302 pub fn is_empty(&self) -> bool {
304 self.rows.is_empty()
305 }
306
307 pub fn set_titles(&mut self, titles: Row) {
309 *self.titles = Some(titles);
310 }
311
312 pub fn unset_titles(&mut self) {
314 *self.titles = None;
315 }
316
317 pub fn get_mut_row(&mut self, row: usize) -> Option<&mut Row> {
319 self.rows.get_mut(row)
320 }
321
322 pub fn get_row(&self, row: usize) -> Option<&Row> {
324 self.rows.get(row)
325 }
326
327 pub fn add_row(&mut self, row: Row) -> &mut Row {
330 self.rows.push(row);
331 let l = self.rows.len() - 1;
332 &mut self.rows[l]
333 }
334
335 pub fn add_empty_row(&mut self) -> &mut Row {
337 self.add_row(Row::default())
338 }
339
340 pub fn insert_row(&mut self, index: usize, row: Row) -> &mut Row {
343 if index < self.rows.len() {
344 self.rows.insert(index, row);
345 &mut self.rows[index]
346 } else {
347 self.add_row(row)
348 }
349 }
350
351 pub fn set_element(&mut self, element: &str, column: usize, row: usize) -> Result<(), &str> {
353 let rowline = self.get_mut_row(row).ok_or("Cannot find row")?;
354 rowline.set_cell(Cell::new(element), column)
356 }
357
358 pub fn remove_row(&mut self, index: usize) {
360 if index < self.rows.len() {
361 self.rows.remove(index);
362 }
363 }
364
365 pub fn column_iter(&self, column: usize) -> ColumnIter {
367 ColumnIter(self.rows.iter(), column)
368 }
369
370 pub fn column_iter_mut(&mut self, column: usize) -> ColumnIterMut {
372 ColumnIterMut(self.rows.iter_mut(), column)
373 }
374
375 pub fn row_iter(&self) -> Iter<Row> {
377 self.rows.iter()
378 }
379
380 pub fn row_iter_mut(&mut self) -> IterMut<Row> {
382 self.rows.iter_mut()
383 }
384
385 pub fn print<T: Write + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
388 self.as_slice().print(out)
389 }
390
391 pub fn print_term<T: Terminal + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
394 self.as_slice().print_term(out)
395 }
396
397 pub fn print_tty(&self, force_colorize: bool) -> Result<usize, Error> {
406 self.as_slice().print_tty(force_colorize)
407 }
408
409 pub fn printstd(&self) {
416 self.as_slice().printstd()
417 }
418
419 pub fn print_html<T: Write + ?Sized>(&self, out: &mut T) -> Result<(), Error> {
421 self.as_slice().print_html(out)
422 }
423}
424
425pub trait AsTableSlice {
427 fn as_slice(&self) -> TableSlice<'_>;
429}
430
431impl AsTableSlice for Table {
432 fn as_slice(&self) -> TableSlice<'_> {
433 TableSlice {
434 format: &self.format,
435 titles: &self.titles,
436 rows: &self.rows,
437 }
438 }
439}
440
441impl<T> AsTableSlice for T
442where
443 T: AsRef<Table>,
444{
445 fn as_slice(&self) -> TableSlice<'_> {
446 self.as_ref().as_slice()
447 }
448}
449
450impl Index<usize> for Table {
451 type Output = Row;
452 fn index(&self, idx: usize) -> &Self::Output {
453 &self.rows[idx]
454 }
455}
456
457impl Index<usize> for TableSlice<'_> {
458 type Output = Row;
459 fn index(&self, idx: usize) -> &Self::Output {
460 &self.rows[idx]
461 }
462}
463
464impl IndexMut<usize> for Table {
465 fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
466 &mut self.rows[idx]
467 }
468}
469
470impl fmt::Display for Table {
471 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
472 self.as_slice().fmt(fmt)
473 }
474}
475
476impl fmt::Display for TableSlice<'_> {
477 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
478 let mut writer = StringWriter::new();
479 if self.print(&mut writer).is_err() {
480 return Err(fmt::Error);
481 }
482 fmt.write_str(writer.as_string())
483 }
484}
485
486impl<B: ToString, A: IntoIterator<Item = B>> FromIterator<A> for Table {
487 fn from_iter<T>(iterator: T) -> Table
488 where
489 T: IntoIterator<Item = A>,
490 {
491 Self::init(iterator.into_iter().map(Row::from).collect())
492 }
493}
494
495impl FromIterator<Row> for Table {
496 fn from_iter<T>(iterator: T) -> Table
497 where
498 T: IntoIterator<Item = Row>,
499 {
500 Self::init(iterator.into_iter().collect())
501 }
502}
503
504impl<T, A, B> From<T> for Table
505where
506 B: ToString,
507 A: IntoIterator<Item = B>,
508 T: IntoIterator<Item = A>,
509{
510 fn from(it: T) -> Table {
511 Self::from_iter(it)
512 }
513}
514
515impl<'a> IntoIterator for &'a Table {
516 type Item = &'a Row;
517 type IntoIter = Iter<'a, Row>;
518 fn into_iter(self) -> Self::IntoIter {
519 self.row_iter()
520 }
521}
522
523impl<'a> IntoIterator for &'a mut Table {
524 type Item = &'a mut Row;
525 type IntoIter = IterMut<'a, Row>;
526 fn into_iter(self) -> Self::IntoIter {
527 self.row_iter_mut()
528 }
529}
530
531impl<A: Into<Row>> Extend<A> for Table {
540 fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
541 self.rows.extend(iter.into_iter().map(|r| r.into()));
542 }
543}
544
545pub struct ColumnIter<'a>(Iter<'a, Row>, usize);
547
548impl<'a> Iterator for ColumnIter<'a> {
549 type Item = &'a Cell;
550 fn next(&mut self) -> Option<&'a Cell> {
551 self.0.next().and_then(|row| row.get_cell(self.1))
552 }
553}
554
555pub struct ColumnIterMut<'a>(IterMut<'a, Row>, usize);
557
558impl<'a> Iterator for ColumnIterMut<'a> {
559 type Item = &'a mut Cell;
560 fn next(&mut self) -> Option<&'a mut Cell> {
561 self.0.next().and_then(|row| row.get_mut_cell(self.1))
562 }
563}
564
565impl AsTableSlice for TableSlice<'_> {
566 fn as_slice(&self) -> TableSlice<'_> {
567 *self
568 }
569}
570
571impl<'a> AsRef<TableSlice<'a>> for TableSlice<'a> {
572 fn as_ref(&self) -> &TableSlice<'a> {
573 self
574 }
575}
576
577pub trait Slice<'a, E> {
579 type Output: 'a;
581 fn slice(&'a self, arg: E) -> Self::Output;
583}
584
585impl<'a, T, E> Slice<'a, E> for T
586where
587 T: AsTableSlice,
588 [Row]: Index<E, Output = [Row]>,
589{
590 type Output = TableSlice<'a>;
591 fn slice(&'a self, arg: E) -> Self::Output {
592 let mut sl = self.as_slice();
593 sl.rows = sl.rows.index(arg);
594 sl
595 }
596}
597
598#[macro_export]
634macro_rules! table {
635 ($([$($content:tt)*]), *) => (
636 $crate::Table::init(vec![$($crate::row![$($content)*]), *])
637 );
638}
639
640#[macro_export]
644macro_rules! ptable {
645 ($($content:tt)*) => (
646 {
647 let tab = $crate::table!($($content)*);
648 tab.printstd();
649 tab
650 }
651 );
652}
653
654#[cfg(test)]
655mod tests {
656 use crate::utils::StringWriter;
657 use crate::{
658 format,
659 AsTableSlice,
660 Cell,
661 Row,
662 Slice,
663 Table,
664 };
665 use format::consts::{
666 FORMAT_BOX_CHARS,
667 FORMAT_CLEAN,
668 FORMAT_DEFAULT,
669 FORMAT_NO_COLSEP,
670 FORMAT_NO_LINESEP,
671 };
672
673 #[test]
674 fn table() {
675 let mut table = Table::new();
676 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
677 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
678 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
679 let out = "\
680+-----+----+-----+
681| t1 | t2 | t3 |
682+=====+====+=====+
683| a | bc | def |
684+-----+----+-----+
685| def | bc | a |
686+-----+----+-----+
687";
688 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
689 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
690 table.unset_titles();
691 let out = "\
692+-----+----+-----+
693| a | bc | def |
694+-----+----+-----+
695| def | bc | a |
696+-----+----+-----+
697";
698 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
699 assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
700 }
701
702 #[test]
703 fn index() {
704 let mut table = Table::new();
705 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
706 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
707 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
708 assert_eq!(table[1][1].get_content(), "bc");
709
710 table[1][1] = Cell::new("newval");
711 assert_eq!(table[1][1].get_content(), "newval");
712
713 let out = "\
714+-----+--------+-----+
715| t1 | t2 | t3 |
716+=====+========+=====+
717| a | bc | def |
718+-----+--------+-----+
719| def | newval | a |
720+-----+--------+-----+
721";
722 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
723 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
724 }
725
726 #[test]
727 fn table_size() {
728 let mut table = Table::new();
729 assert!(table.is_empty());
730 assert!(table.as_slice().is_empty());
731 assert_eq!(table.len(), 0);
732 assert_eq!(table.as_slice().len(), 0);
733 assert_eq!(table.get_column_num(), 0);
734 assert_eq!(table.as_slice().get_column_num(), 0);
735 table.add_empty_row();
736 assert!(!table.is_empty());
737 assert!(!table.as_slice().is_empty());
738 assert_eq!(table.len(), 1);
739 assert_eq!(table.as_slice().len(), 1);
740 assert_eq!(table.get_column_num(), 0);
741 assert_eq!(table.as_slice().get_column_num(), 0);
742 table[0].add_cell(Cell::default());
743 assert_eq!(table.get_column_num(), 1);
744 assert_eq!(table.as_slice().get_column_num(), 1);
745 }
746
747 #[test]
748 fn get_row() {
749 let mut table = Table::new();
750 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
751 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
752 assert!(table.get_row(12).is_none());
753 assert!(table.get_row(1).is_some());
754 assert_eq!(table.get_row(1).unwrap()[0].get_content(), "def");
755 assert!(table.get_mut_row(12).is_none());
756 assert!(table.get_mut_row(1).is_some());
757 table.get_mut_row(1).unwrap().add_cell(Cell::new("z"));
758 assert_eq!(table.get_row(1).unwrap()[3].get_content(), "z");
759 }
760
761 #[test]
762 fn add_empty_row() {
763 let mut table = Table::new();
764 assert_eq!(table.len(), 0);
765 table.add_empty_row();
766 assert_eq!(table.len(), 1);
767 assert_eq!(table[0].len(), 0);
768 }
769
770 #[test]
771 fn remove_row() {
772 let mut table = Table::new();
773 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
774 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
775 table.remove_row(12);
776 assert_eq!(table.len(), 2);
777 table.remove_row(0);
778 assert_eq!(table.len(), 1);
779 assert_eq!(table[0][0].get_content(), "def");
780 }
781
782 #[test]
783 fn insert_row() {
784 let mut table = Table::new();
785 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
786 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
787 table.insert_row(12, Row::new(vec![Cell::new("1"), Cell::new("2"), Cell::new("3")]));
788 assert_eq!(table.len(), 3);
789 assert_eq!(table[2][1].get_content(), "2");
790 table.insert_row(1, Row::new(vec![Cell::new("3"), Cell::new("4"), Cell::new("5")]));
791 assert_eq!(table.len(), 4);
792 assert_eq!(table[1][1].get_content(), "4");
793 assert_eq!(table[2][1].get_content(), "bc");
794 }
795
796 #[test]
797 fn set_element() {
798 let mut table = Table::new();
799 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
800 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
801 assert!(table.set_element("foo", 12, 12).is_err());
802 assert!(table.set_element("foo", 1, 1).is_ok());
803 assert_eq!(table[1][1].get_content(), "foo");
804 }
805
806 #[test]
807 fn no_linesep() {
808 let mut table = Table::new();
809 table.set_format(*FORMAT_NO_LINESEP);
810 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
811 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
812 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
813 assert_eq!(table[1][1].get_content(), "bc");
814
815 table[1][1] = Cell::new("newval");
816 assert_eq!(table[1][1].get_content(), "newval");
817
818 let out = "\
819+-----+--------+-----+
820| t1 | t2 | t3 |
821| a | bc | def |
822| def | newval | a |
823+-----+--------+-----+
824";
825 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
826 assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
827 }
828
829 #[test]
830 fn no_colsep() {
831 let mut table = Table::new();
832 table.set_format(*FORMAT_NO_COLSEP);
833 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
834 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
835 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
836 assert_eq!(table[1][1].get_content(), "bc");
837
838 table[1][1] = Cell::new("newval");
839 assert_eq!(table[1][1].get_content(), "newval");
840
841 let out = "\
842------------------
843 t1 t2 t3 \n\
844==================
845 a bc def \n\
846------------------
847 def newval a \n\
848------------------
849";
850 println!("{}", out);
851 println!("____");
852 println!("{}", table.to_string().replace("\r\n", "\n"));
853 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
854 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
855 }
856
857 #[test]
858 fn clean() {
859 let mut table = Table::new();
860 table.set_format(*FORMAT_CLEAN);
861 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
862 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
863 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
864 assert_eq!(table[1][1].get_content(), "bc");
865
866 table[1][1] = Cell::new("newval");
867 assert_eq!(table[1][1].get_content(), "newval");
868
869 let out = "\
870\u{0020}t1 t2 t3 \n\
871\u{0020}a bc def \n\
872\u{0020}def newval a \n\
873";
874 println!("{}", out);
875 println!("____");
876 println!("{}", table.to_string().replace("\r\n", "\n"));
877 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
878 assert_eq!(3, table.print(&mut StringWriter::new()).unwrap());
879 }
880
881 #[test]
882 fn padding() {
883 let mut table = Table::new();
884 let mut format = *FORMAT_DEFAULT;
885 format.padding(2, 2);
886 table.set_format(format);
887 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
888 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
889 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
890 assert_eq!(table[1][1].get_content(), "bc");
891
892 table[1][1] = Cell::new("newval");
893 assert_eq!(table[1][1].get_content(), "newval");
894
895 let out = "\
896+-------+----------+-------+
897| t1 | t2 | t3 |
898+=======+==========+=======+
899| a | bc | def |
900+-------+----------+-------+
901| def | newval | a |
902+-------+----------+-------+
903";
904 println!("{}", out);
905 println!("____");
906 println!("{}", table.to_string().replace("\r\n", "\n"));
907 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
908 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
909 }
910
911 #[test]
912 fn indent() {
913 let mut table = Table::new();
914 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
915 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
916 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
917 table.get_format().indent(8);
918 let out = " +-----+----+-----+
919 | t1 | t2 | t3 |
920 +=====+====+=====+
921 | a | bc | def |
922 +-----+----+-----+
923 | def | bc | a |
924 +-----+----+-----+
925";
926 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
927 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
928 }
929
930 #[test]
931 fn slices() {
932 let mut table = Table::new();
933 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
934 table.add_row(Row::new(vec![Cell::new("0"), Cell::new("0"), Cell::new("0")]));
935 table.add_row(Row::new(vec![Cell::new("1"), Cell::new("1"), Cell::new("1")]));
936 table.add_row(Row::new(vec![Cell::new("2"), Cell::new("2"), Cell::new("2")]));
937 table.add_row(Row::new(vec![Cell::new("3"), Cell::new("3"), Cell::new("3")]));
938 table.add_row(Row::new(vec![Cell::new("4"), Cell::new("4"), Cell::new("4")]));
939 table.add_row(Row::new(vec![Cell::new("5"), Cell::new("5"), Cell::new("5")]));
940 let out = "\
941+----+----+----+
942| t1 | t2 | t3 |
943+====+====+====+
944| 1 | 1 | 1 |
945+----+----+----+
946| 2 | 2 | 2 |
947+----+----+----+
948| 3 | 3 | 3 |
949+----+----+----+
950";
951 let slice = table.slice(..);
952 let slice = slice.slice(1..);
953 let slice = slice.slice(..3);
954 assert_eq!(out, slice.to_string().replace("\r\n", "\n"));
955 assert_eq!(9, slice.print(&mut StringWriter::new()).unwrap());
956 assert_eq!(out, table.slice(1..4).to_string().replace("\r\n", "\n"));
957 assert_eq!(9, table.slice(1..4).print(&mut StringWriter::new()).unwrap());
958 }
959
960 #[test]
961 fn test_unicode_separators() {
962 let mut table = Table::new();
963 table.set_format(*FORMAT_BOX_CHARS);
964 table.add_row(Row::new(vec![Cell::new("1"), Cell::new("1"), Cell::new("1")]));
965 table.add_row(Row::new(vec![Cell::new("2"), Cell::new("2"), Cell::new("2")]));
966 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
967 let out = "\
968┌────┬────┬────┐
969│ t1 │ t2 │ t3 │
970├────┼────┼────┤
971│ 1 │ 1 │ 1 │
972├────┼────┼────┤
973│ 2 │ 2 │ 2 │
974└────┴────┴────┘
975";
976 println!("{}", out);
977 println!("____");
978 println!("{}", table.to_string().replace("\r\n", "\n"));
979 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
980 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
981 }
982
983 #[test]
984 fn test_readme_format() {
985 let mut table = Table::new();
988 let format = format::FormatBuilder::new()
989 .column_separator('|')
990 .borders('|')
991 .separators(
992 &[format::LinePosition::Top, format::LinePosition::Bottom],
993 format::LineSeparator::new('-', '+', '+', '+'),
994 )
995 .padding(1, 1)
996 .build();
997 table.set_format(format);
998
999 table.set_titles(Row::new(vec![Cell::new("Title 1"), Cell::new("Title 2")]));
1000 table.add_row(Row::new(vec![Cell::new("Value 1"), Cell::new("Value 2")]));
1001 table.add_row(Row::new(vec![Cell::new("Value three"), Cell::new("Value four")]));
1002
1003 let out = "\
1004+-------------+------------+
1005| Title 1 | Title 2 |
1006| Value 1 | Value 2 |
1007| Value three | Value four |
1008+-------------+------------+
1009";
1010
1011 println!("{}", out);
1012 println!("____");
1013 println!("{}", table.to_string().replace("\r\n", "\n"));
1014 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1015 assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
1016 }
1017
1018 #[test]
1019 fn test_readme_format_with_title() {
1020 let mut table = Table::new();
1021 table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
1022
1023 table.set_titles(Row::new(vec![Cell::new("Title 1"), Cell::new("Title 2")]));
1024 table.add_row(Row::new(vec![Cell::new("Value 1"), Cell::new("Value 2")]));
1025 table.add_row(Row::new(vec![Cell::new("Value three"), Cell::new("Value four")]));
1026
1027 let out = "\
1028+-------------+------------+
1029| Title 1 | Title 2 |
1030+-------------+------------+
1031| Value 1 | Value 2 |
1032| Value three | Value four |
1033+-------------+------------+
1034";
1035 println!("{}", out);
1036 println!("____");
1037 println!("{}", table.to_string().replace("\r\n", "\n"));
1038 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1039 assert_eq!(6, table.print(&mut StringWriter::new()).unwrap());
1040 }
1041
1042 #[test]
1043 fn test_empty_table_with_title() {
1044 let mut table = Table::new();
1045 table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
1046
1047 table.set_titles(Row::new(vec![Cell::new("Title 1"), Cell::new("Title 2")]));
1048
1049 let out = "\
1050+---------+---------+
1051| Title 1 | Title 2 |
1052+---------+---------+
1053+---------+---------+
1054";
1055 println!("{}", out);
1056 println!("____");
1057 println!("{}", table.to_string().replace("\r\n", "\n"));
1058 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1059 assert_eq!(4, table.print(&mut StringWriter::new()).unwrap());
1060 }
1061
1062 #[test]
1063 fn test_horizontal_span() {
1064 let mut table = Table::new();
1065 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2").with_hspan(2)]));
1066 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
1067 table.add_row(Row::new(vec![
1068 Cell::new("def").style_spec("H02c"),
1069 Cell::new("a"),
1070 ]));
1071 let out = "\
1072+----+----+-----+
1073| t1 | t2 |
1074+====+====+=====+
1075| a | bc | def |
1076+----+----+-----+
1077| def | a |
1078+----+----+-----+
1079";
1080 println!("{}", out);
1081 println!("____");
1082 println!("{}", table.to_string().replace("\r\n", "\n"));
1083 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1084 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
1085 }
1086
1087 #[test]
1088 fn table_html() {
1089 let mut table = Table::new();
1090 table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
1091 table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
1092 table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
1093 let out = "\
1094<table>\
1095<th><td style=\"text-align: left;\">t1</td><td style=\"text-align: left;\">t2</td><td style=\"text-align: left;\">t3</td></th>\
1096<tr><td style=\"text-align: left;\">a</td><td style=\"text-align: left;\">bc</td><td style=\"text-align: left;\">def</td></tr>\
1097<tr><td style=\"text-align: left;\">def</td><td style=\"text-align: left;\">bc</td><td style=\"text-align: left;\">a</td></tr>\
1098</table>";
1099 let mut writer = StringWriter::new();
1100 assert!(table.print_html(&mut writer).is_ok());
1101 assert_eq!(writer.as_string().replace("\r\n", "\n"), out);
1102 table.unset_titles();
1103 let out = "\
1104<table>\
1105<tr><td style=\"text-align: left;\">a</td><td style=\"text-align: left;\">bc</td><td style=\"text-align: left;\">def</td></tr>\
1106<tr><td style=\"text-align: left;\">def</td><td style=\"text-align: left;\">bc</td><td style=\"text-align: left;\">a</td></tr>\
1107</table>";
1108 let mut writer = StringWriter::new();
1109 assert!(table.print_html(&mut writer).is_ok());
1110 assert_eq!(writer.as_string().replace("\r\n", "\n"), out);
1111 }
1112
1113 #[test]
1114 fn table_html_colors() {
1115 let mut table = Table::new();
1116 table.add_row(Row::new(vec![
1117 Cell::new("bold").style_spec("b"),
1118 Cell::new("italic").style_spec("i"),
1119 Cell::new("underline").style_spec("u"),
1120 ]));
1121 table.add_row(Row::new(vec![
1122 Cell::new("left").style_spec("l"),
1123 Cell::new("center").style_spec("c"),
1124 Cell::new("right").style_spec("r"),
1125 ]));
1126 table.add_row(Row::new(vec![
1127 Cell::new("red").style_spec("Fr"),
1128 Cell::new("black").style_spec("Fd"),
1129 Cell::new("yellow").style_spec("Fy"),
1130 ]));
1131 table.add_row(Row::new(vec![
1132 Cell::new("bright magenta on cyan").style_spec("FMBc"),
1133 Cell::new("white on bright green").style_spec("FwBG"),
1134 Cell::new("default on blue").style_spec("Bb"),
1135 ]));
1136 table.set_titles(Row::new(vec![Cell::new("span horizontal").style_spec("H3")]));
1137 let out = "\
1138<table>\
1139<th><td colspan=\"3\" style=\"text-align: left;\">span horizontal</td></th>\
1140<tr><td style=\"font-weight: bold;text-align: left;\">bold</td><td style=\"font-style: italic;text-align: left;\">italic</td><td style=\"text-decoration: underline;text-align: left;\">underline</td></tr>\
1141<tr><td style=\"text-align: left;\">left</td><td style=\"text-align: center;\">center</td><td style=\"text-align: right;\">right</td></tr>\
1142<tr><td style=\"color: #aa0000;text-align: left;\">red</td><td style=\"color: #000000;text-align: left;\">black</td><td style=\"color: #aa5500;text-align: left;\">yellow</td></tr>\
1143<tr><td style=\"color: #ff55ff;background-color: #00aaaa;text-align: left;\">bright magenta on cyan</td><td style=\"color: #aaaaaa;background-color: #55ff55;text-align: left;\">white on bright green</td><td style=\"background-color: #0000aa;text-align: left;\">default on blue</td></tr>\
1144</table>";
1145 let mut writer = StringWriter::new();
1146 assert!(table.print_html(&mut writer).is_ok());
1147 assert_eq!(writer.as_string().replace("\r\n", "\n"), out);
1148 }
1149
1150 #[test]
1151 fn test_panic() {
1152 let mut table = Table::new();
1153
1154 table.add_row(Row::new(vec![Cell::new("\u{1b}[\u{1b}\u{0}\u{0}")]));
1155
1156 let out = "+------+
1157| \u{1b}[\u{1b}\u{0}\u{0} |
1158+------+
1159";
1160
1161 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
1162 assert_eq!(3, table.print(&mut StringWriter::new()).unwrap());
1163 }
1164}