1#![warn(
2 missing_docs,
3 unused_extern_crates,
4 unused_import_braces,
5 unused_qualifications
6)]
7#[macro_use]
10extern crate lazy_static;
11
12use std::fmt;
13use std::io::{self, Error, Write};
14use std::iter::{FromIterator, IntoIterator};
15use std::ops::{Index, IndexMut};
16use std::slice::{Iter, IterMut};
17
18pub use term::{color, Attr};
19pub(crate) use term::{stdout, Terminal};
20
21mod cell;
22pub mod format;
23mod row;
24mod utils;
25
26#[cfg(feature = "csv")]
27pub mod csv;
28
29#[cfg(feature = "evcxr")]
30pub mod evcxr;
31
32pub use cell::Cell;
33use format::{consts, LinePosition, TableFormat};
34pub use row::Row;
35use utils::StringWriter;
36
37#[derive(Default, Clone, Debug, Hash, PartialEq, Eq)]
39pub struct Table {
40 format: Box<TableFormat>,
41 titles: Box<Option<Row>>,
42 rows: Vec<Row>,
43}
44
45#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
65pub struct TableSlice<'a> {
66 format: &'a TableFormat,
67 titles: &'a Option<Row>,
68 rows: &'a [Row],
69}
70
71impl<'a> TableSlice<'a> {
72 fn get_column_num(&self) -> usize {
75 let mut cnum = match *self.titles {
76 Some(ref t) => t.column_count(),
77 None => 0,
78 };
79 for r in self.rows {
80 let l = r.column_count();
81 if l > cnum {
82 cnum = l;
83 }
84 }
85 cnum
86 }
87
88 pub fn len(&self) -> usize {
90 self.rows.len()
91 }
92
93 pub fn is_empty(&self) -> bool {
95 self.rows.is_empty()
96 }
97
98 pub fn get_row(&self, row: usize) -> Option<&Row> {
100 self.rows.get(row)
101 }
102
103 fn get_column_width(&self, col_idx: usize) -> usize {
106 let mut width = match *self.titles {
107 Some(ref t) => t.get_column_width(col_idx, self.format),
108 None => 0,
109 };
110 for r in self.rows {
111 let l = r.get_column_width(col_idx, self.format);
112 if l > width {
113 width = l;
114 }
115 }
116 width
117 }
118
119 fn get_all_column_width(&self) -> Vec<usize> {
122 let colnum = self.get_column_num();
123 let mut col_width = vec![0usize; colnum];
124 #[allow(clippy::needless_range_loop)]
125 for i in 0..colnum {
126 col_width[i] = self.get_column_width(i);
128 }
129 col_width
130 }
131
132 pub fn column_iter(&self, column: usize) -> ColumnIter {
134 ColumnIter(self.rows.iter(), column)
135 }
136
137 pub fn row_iter(&self) -> Iter<Row> {
139 self.rows.iter()
140 }
141
142 fn __print<T: Write + ?Sized, F>(&self, out: &mut T, f: F) -> Result<usize, Error>
144 where
145 F: Fn(&Row, &mut T, &TableFormat, &[usize]) -> Result<usize, Error>,
146 {
147 let mut height = 0;
148 let col_width = self.get_all_column_width();
150 height += self
151 .format
152 .print_line_separator(out, &col_width, LinePosition::Top)?;
153 if let Some(ref t) = *self.titles {
154 height += f(t, out, self.format, &col_width)?;
155 height += self
156 .format
157 .print_line_separator(out, &col_width, LinePosition::Title)?;
158 }
159 let mut iter = self.rows.iter().peekable();
161 while let Some(r) = iter.next() {
162 height += f(r, out, self.format, &col_width)?;
163 if iter.peek().is_some() {
164 height +=
165 self.format
166 .print_line_separator(out, &col_width, LinePosition::Intern)?;
167 }
168 }
169 height += self
170 .format
171 .print_line_separator(out, &col_width, LinePosition::Bottom)?;
172 out.flush()?;
173 Ok(height)
174 }
175
176 pub fn print<T: Write + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
179 self.__print(out, Row::print)
180 }
181
182 pub fn print_term<T: Terminal + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
185 self.__print(out, Row::print_term)
186 }
187
188 pub fn print_tty(&self, force_colorize: bool) -> Result<usize, Error> {
197 use is_terminal::IsTerminal;
198 match (stdout(), io::stdout().is_terminal() || force_colorize) {
199 (Some(mut o), true) => self.print_term(&mut *o),
200 _ => self.print(&mut io::stdout()),
201 }
202 }
203
204 pub fn printstd(&self) {
211 let _ = self.print_tty(false); }
213
214 pub fn print_html<T: Write + ?Sized>(&self, out: &mut T) -> Result<(), Error> {
216 let column_num = self.get_column_num();
218 out.write_all(b"<table>")?;
219 if let Some(ref t) = *self.titles {
221 out.write_all(b"<th>")?;
222 t.print_html(out, column_num)?;
223 out.write_all(b"</th>")?;
224 }
225 for r in self.rows {
227 out.write_all(b"<tr>")?;
228 r.print_html(out, column_num)?;
229 out.write_all(b"</tr>")?;
230 }
231 out.write_all(b"</table>")?;
232 out.flush()?;
233 Ok(())
234 }
235}
236
237impl<'a> IntoIterator for &'a TableSlice<'a> {
238 type Item = &'a Row;
239 type IntoIter = Iter<'a, Row>;
240 fn into_iter(self) -> Self::IntoIter {
241 self.row_iter()
242 }
243}
244
245impl Table {
246 pub fn new() -> Table {
248 Self::init(Vec::new())
249 }
250
251 pub fn init(rows: Vec<Row>) -> Table {
253 Table {
254 rows,
255 titles: Box::new(None),
256 format: Box::new(*consts::FORMAT_DEFAULT),
257 }
258 }
259
260 pub fn set_format(&mut self, format: TableFormat) {
262 *self.format = format;
263 }
264
265 pub fn get_format(&mut self) -> &mut TableFormat {
267 &mut self.format
268 }
269
270 #[cfg(test)] pub(crate) fn get_column_num(&self) -> usize {
274 self.as_slice().get_column_num()
275 }
276
277 pub fn len(&self) -> usize {
279 self.rows.len()
280 }
281
282 pub fn is_empty(&self) -> bool {
284 self.rows.is_empty()
285 }
286
287 pub fn set_titles(&mut self, titles: Row) {
289 *self.titles = Some(titles);
290 }
291
292 pub fn unset_titles(&mut self) {
294 *self.titles = None;
295 }
296
297 pub fn get_mut_row(&mut self, row: usize) -> Option<&mut Row> {
299 self.rows.get_mut(row)
300 }
301
302 pub fn get_row(&self, row: usize) -> Option<&Row> {
304 self.rows.get(row)
305 }
306
307 pub fn add_row(&mut self, row: Row) -> &mut Row {
310 self.rows.push(row);
311 let l = self.rows.len() - 1;
312 &mut self.rows[l]
313 }
314
315 pub fn add_empty_row(&mut self) -> &mut Row {
317 self.add_row(Row::default())
318 }
319
320 pub fn insert_row(&mut self, index: usize, row: Row) -> &mut Row {
323 if index < self.rows.len() {
324 self.rows.insert(index, row);
325 &mut self.rows[index]
326 } else {
327 self.add_row(row)
328 }
329 }
330
331 pub fn set_element(&mut self, element: &str, column: usize, row: usize) -> Result<(), &str> {
333 let rowline = self.get_mut_row(row).ok_or("Cannot find row")?;
334 rowline.set_cell(Cell::new(element), column)
336 }
337
338 pub fn remove_row(&mut self, index: usize) {
340 if index < self.rows.len() {
341 self.rows.remove(index);
342 }
343 }
344
345 pub fn column_iter(&self, column: usize) -> ColumnIter {
347 ColumnIter(self.rows.iter(), column)
348 }
349
350 pub fn column_iter_mut(&mut self, column: usize) -> ColumnIterMut {
352 ColumnIterMut(self.rows.iter_mut(), column)
353 }
354
355 pub fn row_iter(&self) -> Iter<Row> {
357 self.rows.iter()
358 }
359
360 pub fn row_iter_mut(&mut self) -> IterMut<Row> {
362 self.rows.iter_mut()
363 }
364
365 pub fn print<T: Write + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
368 self.as_slice().print(out)
369 }
370
371 pub fn print_term<T: Terminal + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
374 self.as_slice().print_term(out)
375 }
376
377 pub fn print_tty(&self, force_colorize: bool) -> Result<usize, Error> {
386 self.as_slice().print_tty(force_colorize)
387 }
388
389 pub fn printstd(&self) {
396 self.as_slice().printstd()
397 }
398
399 pub fn print_html<T: Write + ?Sized>(&self, out: &mut T) -> Result<(), Error> {
401 self.as_slice().print_html(out)
402 }
403}
404
405pub trait AsTableSlice {
407 fn as_slice(&self) -> TableSlice<'_>;
409}
410
411impl AsTableSlice for Table {
412 fn as_slice(&self) -> TableSlice<'_> {
413 TableSlice {
414 format: &self.format,
415 titles: &self.titles,
416 rows: &self.rows,
417 }
418 }
419}
420
421impl<T> AsTableSlice for T
422where
423 T: AsRef<Table>,
424{
425 fn as_slice(&self) -> TableSlice<'_> {
426 self.as_ref().as_slice()
427 }
428}
429
430impl Index<usize> for Table {
431 type Output = Row;
432 fn index(&self, idx: usize) -> &Self::Output {
433 &self.rows[idx]
434 }
435}
436
437impl<'a> Index<usize> for TableSlice<'a> {
438 type Output = Row;
439 fn index(&self, idx: usize) -> &Self::Output {
440 &self.rows[idx]
441 }
442}
443
444impl IndexMut<usize> for Table {
445 fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
446 &mut self.rows[idx]
447 }
448}
449
450impl fmt::Display for Table {
451 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
452 self.as_slice().fmt(fmt)
453 }
454}
455
456impl<'a> fmt::Display for TableSlice<'a> {
457 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
458 let mut writer = StringWriter::new();
459 if self.print(&mut writer).is_err() {
460 return Err(fmt::Error);
461 }
462 fmt.write_str(writer.as_string())
463 }
464}
465
466impl<B: ToString, A: IntoIterator<Item = B>> FromIterator<A> for Table {
467 fn from_iter<T>(iterator: T) -> Table
468 where
469 T: IntoIterator<Item = A>,
470 {
471 Self::init(iterator.into_iter().map(Row::from).collect())
472 }
473}
474
475impl FromIterator<Row> for Table {
476 fn from_iter<T>(iterator: T) -> Table
477 where
478 T: IntoIterator<Item = Row>,
479 {
480 Self::init(iterator.into_iter().collect())
481 }
482}
483
484impl<T, A, B> From<T> for Table
485where
486 B: ToString,
487 A: IntoIterator<Item = B>,
488 T: IntoIterator<Item = A>,
489{
490 fn from(it: T) -> Table {
491 Self::from_iter(it)
492 }
493}
494
495impl<'a> IntoIterator for &'a Table {
496 type Item = &'a Row;
497 type IntoIter = Iter<'a, Row>;
498 fn into_iter(self) -> Self::IntoIter {
499 self.row_iter()
500 }
501}
502
503impl<'a> IntoIterator for &'a mut Table {
504 type Item = &'a mut Row;
505 type IntoIter = IterMut<'a, Row>;
506 fn into_iter(self) -> Self::IntoIter {
507 self.row_iter_mut()
508 }
509}
510
511impl<A: Into<Row>> Extend<A> for Table {
520 fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
521 self.rows.extend(iter.into_iter().map(|r| r.into()));
522 }
523}
524
525pub struct ColumnIter<'a>(Iter<'a, Row>, usize);
527
528impl<'a> Iterator for ColumnIter<'a> {
529 type Item = &'a Cell;
530 fn next(&mut self) -> Option<&'a Cell> {
531 self.0.next().and_then(|row| row.get_cell(self.1))
532 }
533}
534
535pub struct ColumnIterMut<'a>(IterMut<'a, Row>, usize);
537
538impl<'a> Iterator for ColumnIterMut<'a> {
539 type Item = &'a mut Cell;
540 fn next(&mut self) -> Option<&'a mut Cell> {
541 self.0.next().and_then(|row| row.get_mut_cell(self.1))
542 }
543}
544
545impl<'a> AsTableSlice for TableSlice<'a> {
546 fn as_slice(&self) -> TableSlice<'_> {
547 *self
548 }
549}
550
551impl<'a> AsRef<TableSlice<'a>> for TableSlice<'a> {
552 fn as_ref(&self) -> &TableSlice<'a> {
553 self
554 }
555}
556
557pub trait Slice<'a, E> {
559 type Output: 'a;
561 fn slice(&'a self, arg: E) -> Self::Output;
563}
564
565impl<'a, T, E> Slice<'a, E> for T
566where
567 T: AsTableSlice,
568 [Row]: Index<E, Output = [Row]>,
569{
570 type Output = TableSlice<'a>;
571 fn slice(&'a self, arg: E) -> Self::Output {
572 let mut sl = self.as_slice();
573 sl.rows = sl.rows.index(arg);
574 sl
575 }
576}
577
578#[macro_export]
614macro_rules! table {
615 ($([$($content:tt)*]), *) => (
616 $crate::Table::init(vec![$($crate::row![$($content)*]), *])
617 );
618}
619
620#[macro_export]
624macro_rules! ptable {
625 ($($content:tt)*) => (
626 {
627 let tab = $crate::table!($($content)*);
628 tab.printstd();
629 tab
630 }
631 );
632}
633
634#[cfg(test)]
635mod tests {
636 use crate::utils::StringWriter;
637 use crate::{format, AsTableSlice, Cell, Row, Slice, Table};
638 use format::consts::{
639 FORMAT_BOX_CHARS, FORMAT_CLEAN, FORMAT_DEFAULT, FORMAT_NO_COLSEP, FORMAT_NO_LINESEP,
640 };
641
642 #[test]
643 fn table() {
644 let mut table = Table::new();
645 table.add_row(Row::new(vec![
646 Cell::new("a"),
647 Cell::new("bc"),
648 Cell::new("def"),
649 ]));
650 table.add_row(Row::new(vec![
651 Cell::new("def"),
652 Cell::new("bc"),
653 Cell::new("a"),
654 ]));
655 table.set_titles(Row::new(vec![
656 Cell::new("t1"),
657 Cell::new("t2"),
658 Cell::new("t3"),
659 ]));
660 let out = "\
661+-----+----+-----+
662| t1 | t2 | t3 |
663+=====+====+=====+
664| a | bc | def |
665+-----+----+-----+
666| def | bc | a |
667+-----+----+-----+
668";
669 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
670 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
671 table.unset_titles();
672 let out = "\
673+-----+----+-----+
674| a | bc | def |
675+-----+----+-----+
676| def | bc | a |
677+-----+----+-----+
678";
679 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
680 assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
681 }
682
683 #[test]
684 fn index() {
685 let mut table = Table::new();
686 table.add_row(Row::new(vec![
687 Cell::new("a"),
688 Cell::new("bc"),
689 Cell::new("def"),
690 ]));
691 table.add_row(Row::new(vec![
692 Cell::new("def"),
693 Cell::new("bc"),
694 Cell::new("a"),
695 ]));
696 table.set_titles(Row::new(vec![
697 Cell::new("t1"),
698 Cell::new("t2"),
699 Cell::new("t3"),
700 ]));
701 assert_eq!(table[1][1].get_content(), "bc");
702
703 table[1][1] = Cell::new("newval");
704 assert_eq!(table[1][1].get_content(), "newval");
705
706 let out = "\
707+-----+--------+-----+
708| t1 | t2 | t3 |
709+=====+========+=====+
710| a | bc | def |
711+-----+--------+-----+
712| def | newval | a |
713+-----+--------+-----+
714";
715 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
716 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
717 }
718
719 #[test]
720 fn table_size() {
721 let mut table = Table::new();
722 assert!(table.is_empty());
723 assert!(table.as_slice().is_empty());
724 assert_eq!(table.len(), 0);
725 assert_eq!(table.as_slice().len(), 0);
726 assert_eq!(table.get_column_num(), 0);
727 assert_eq!(table.as_slice().get_column_num(), 0);
728 table.add_empty_row();
729 assert!(!table.is_empty());
730 assert!(!table.as_slice().is_empty());
731 assert_eq!(table.len(), 1);
732 assert_eq!(table.as_slice().len(), 1);
733 assert_eq!(table.get_column_num(), 0);
734 assert_eq!(table.as_slice().get_column_num(), 0);
735 table[0].add_cell(Cell::default());
736 assert_eq!(table.get_column_num(), 1);
737 assert_eq!(table.as_slice().get_column_num(), 1);
738 }
739
740 #[test]
741 fn get_row() {
742 let mut table = Table::new();
743 table.add_row(Row::new(vec![
744 Cell::new("a"),
745 Cell::new("bc"),
746 Cell::new("def"),
747 ]));
748 table.add_row(Row::new(vec![
749 Cell::new("def"),
750 Cell::new("bc"),
751 Cell::new("a"),
752 ]));
753 assert!(table.get_row(12).is_none());
754 assert!(table.get_row(1).is_some());
755 assert_eq!(table.get_row(1).unwrap()[0].get_content(), "def");
756 assert!(table.get_mut_row(12).is_none());
757 assert!(table.get_mut_row(1).is_some());
758 table.get_mut_row(1).unwrap().add_cell(Cell::new("z"));
759 assert_eq!(table.get_row(1).unwrap()[3].get_content(), "z");
760 }
761
762 #[test]
763 fn add_empty_row() {
764 let mut table = Table::new();
765 assert_eq!(table.len(), 0);
766 table.add_empty_row();
767 assert_eq!(table.len(), 1);
768 assert_eq!(table[0].len(), 0);
769 }
770
771 #[test]
772 fn remove_row() {
773 let mut table = Table::new();
774 table.add_row(Row::new(vec![
775 Cell::new("a"),
776 Cell::new("bc"),
777 Cell::new("def"),
778 ]));
779 table.add_row(Row::new(vec![
780 Cell::new("def"),
781 Cell::new("bc"),
782 Cell::new("a"),
783 ]));
784 table.remove_row(12);
785 assert_eq!(table.len(), 2);
786 table.remove_row(0);
787 assert_eq!(table.len(), 1);
788 assert_eq!(table[0][0].get_content(), "def");
789 }
790
791 #[test]
792 fn insert_row() {
793 let mut table = Table::new();
794 table.add_row(Row::new(vec![
795 Cell::new("a"),
796 Cell::new("bc"),
797 Cell::new("def"),
798 ]));
799 table.add_row(Row::new(vec![
800 Cell::new("def"),
801 Cell::new("bc"),
802 Cell::new("a"),
803 ]));
804 table.insert_row(
805 12,
806 Row::new(vec![Cell::new("1"), Cell::new("2"), Cell::new("3")]),
807 );
808 assert_eq!(table.len(), 3);
809 assert_eq!(table[2][1].get_content(), "2");
810 table.insert_row(
811 1,
812 Row::new(vec![Cell::new("3"), Cell::new("4"), Cell::new("5")]),
813 );
814 assert_eq!(table.len(), 4);
815 assert_eq!(table[1][1].get_content(), "4");
816 assert_eq!(table[2][1].get_content(), "bc");
817 }
818
819 #[test]
820 fn set_element() {
821 let mut table = Table::new();
822 table.add_row(Row::new(vec![
823 Cell::new("a"),
824 Cell::new("bc"),
825 Cell::new("def"),
826 ]));
827 table.add_row(Row::new(vec![
828 Cell::new("def"),
829 Cell::new("bc"),
830 Cell::new("a"),
831 ]));
832 assert!(table.set_element("foo", 12, 12).is_err());
833 assert!(table.set_element("foo", 1, 1).is_ok());
834 assert_eq!(table[1][1].get_content(), "foo");
835 }
836
837 #[test]
838 fn no_linesep() {
839 let mut table = Table::new();
840 table.set_format(*FORMAT_NO_LINESEP);
841 table.add_row(Row::new(vec![
842 Cell::new("a"),
843 Cell::new("bc"),
844 Cell::new("def"),
845 ]));
846 table.add_row(Row::new(vec![
847 Cell::new("def"),
848 Cell::new("bc"),
849 Cell::new("a"),
850 ]));
851 table.set_titles(Row::new(vec![
852 Cell::new("t1"),
853 Cell::new("t2"),
854 Cell::new("t3"),
855 ]));
856 assert_eq!(table[1][1].get_content(), "bc");
857
858 table[1][1] = Cell::new("newval");
859 assert_eq!(table[1][1].get_content(), "newval");
860
861 let out = "\
862+-----+--------+-----+
863| t1 | t2 | t3 |
864| a | bc | def |
865| def | newval | a |
866+-----+--------+-----+
867";
868 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
869 assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
870 }
871
872 #[test]
873 fn no_colsep() {
874 let mut table = Table::new();
875 table.set_format(*FORMAT_NO_COLSEP);
876 table.add_row(Row::new(vec![
877 Cell::new("a"),
878 Cell::new("bc"),
879 Cell::new("def"),
880 ]));
881 table.add_row(Row::new(vec![
882 Cell::new("def"),
883 Cell::new("bc"),
884 Cell::new("a"),
885 ]));
886 table.set_titles(Row::new(vec![
887 Cell::new("t1"),
888 Cell::new("t2"),
889 Cell::new("t3"),
890 ]));
891 assert_eq!(table[1][1].get_content(), "bc");
892
893 table[1][1] = Cell::new("newval");
894 assert_eq!(table[1][1].get_content(), "newval");
895
896 let out = "\
897------------------
898 t1 t2 t3 \n\
899==================
900 a bc def \n\
901------------------
902 def newval a \n\
903------------------
904";
905 println!("{}", out);
906 println!("____");
907 println!("{}", table.to_string().replace("\r\n", "\n"));
908 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
909 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
910 }
911
912 #[test]
913 fn clean() {
914 let mut table = Table::new();
915 table.set_format(*FORMAT_CLEAN);
916 table.add_row(Row::new(vec![
917 Cell::new("a"),
918 Cell::new("bc"),
919 Cell::new("def"),
920 ]));
921 table.add_row(Row::new(vec![
922 Cell::new("def"),
923 Cell::new("bc"),
924 Cell::new("a"),
925 ]));
926 table.set_titles(Row::new(vec![
927 Cell::new("t1"),
928 Cell::new("t2"),
929 Cell::new("t3"),
930 ]));
931 assert_eq!(table[1][1].get_content(), "bc");
932
933 table[1][1] = Cell::new("newval");
934 assert_eq!(table[1][1].get_content(), "newval");
935
936 let out = "\
937\u{0020}t1 t2 t3 \n\
938\u{0020}a bc def \n\
939\u{0020}def newval a \n\
940";
941 println!("{}", out);
942 println!("____");
943 println!("{}", table.to_string().replace("\r\n", "\n"));
944 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
945 assert_eq!(3, table.print(&mut StringWriter::new()).unwrap());
946 }
947
948 #[test]
949 fn padding() {
950 let mut table = Table::new();
951 let mut format = *FORMAT_DEFAULT;
952 format.padding(2, 2);
953 table.set_format(format);
954 table.add_row(Row::new(vec![
955 Cell::new("a"),
956 Cell::new("bc"),
957 Cell::new("def"),
958 ]));
959 table.add_row(Row::new(vec![
960 Cell::new("def"),
961 Cell::new("bc"),
962 Cell::new("a"),
963 ]));
964 table.set_titles(Row::new(vec![
965 Cell::new("t1"),
966 Cell::new("t2"),
967 Cell::new("t3"),
968 ]));
969 assert_eq!(table[1][1].get_content(), "bc");
970
971 table[1][1] = Cell::new("newval");
972 assert_eq!(table[1][1].get_content(), "newval");
973
974 let out = "\
975+-------+----------+-------+
976| t1 | t2 | t3 |
977+=======+==========+=======+
978| a | bc | def |
979+-------+----------+-------+
980| def | newval | a |
981+-------+----------+-------+
982";
983 println!("{}", out);
984 println!("____");
985 println!("{}", table.to_string().replace("\r\n", "\n"));
986 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
987 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
988 }
989
990 #[test]
991 fn indent() {
992 let mut table = Table::new();
993 table.add_row(Row::new(vec![
994 Cell::new("a"),
995 Cell::new("bc"),
996 Cell::new("def"),
997 ]));
998 table.add_row(Row::new(vec![
999 Cell::new("def"),
1000 Cell::new("bc"),
1001 Cell::new("a"),
1002 ]));
1003 table.set_titles(Row::new(vec![
1004 Cell::new("t1"),
1005 Cell::new("t2"),
1006 Cell::new("t3"),
1007 ]));
1008 table.get_format().indent(8);
1009 let out = " +-----+----+-----+
1010 | t1 | t2 | t3 |
1011 +=====+====+=====+
1012 | a | bc | def |
1013 +-----+----+-----+
1014 | def | bc | a |
1015 +-----+----+-----+
1016";
1017 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
1018 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
1019 }
1020
1021 #[test]
1022 fn slices() {
1023 let mut table = Table::new();
1024 table.set_titles(Row::new(vec![
1025 Cell::new("t1"),
1026 Cell::new("t2"),
1027 Cell::new("t3"),
1028 ]));
1029 table.add_row(Row::new(vec![
1030 Cell::new("0"),
1031 Cell::new("0"),
1032 Cell::new("0"),
1033 ]));
1034 table.add_row(Row::new(vec![
1035 Cell::new("1"),
1036 Cell::new("1"),
1037 Cell::new("1"),
1038 ]));
1039 table.add_row(Row::new(vec![
1040 Cell::new("2"),
1041 Cell::new("2"),
1042 Cell::new("2"),
1043 ]));
1044 table.add_row(Row::new(vec![
1045 Cell::new("3"),
1046 Cell::new("3"),
1047 Cell::new("3"),
1048 ]));
1049 table.add_row(Row::new(vec![
1050 Cell::new("4"),
1051 Cell::new("4"),
1052 Cell::new("4"),
1053 ]));
1054 table.add_row(Row::new(vec![
1055 Cell::new("5"),
1056 Cell::new("5"),
1057 Cell::new("5"),
1058 ]));
1059 let out = "\
1060+----+----+----+
1061| t1 | t2 | t3 |
1062+====+====+====+
1063| 1 | 1 | 1 |
1064+----+----+----+
1065| 2 | 2 | 2 |
1066+----+----+----+
1067| 3 | 3 | 3 |
1068+----+----+----+
1069";
1070 let slice = table.slice(..);
1071 let slice = slice.slice(1..);
1072 let slice = slice.slice(..3);
1073 assert_eq!(out, slice.to_string().replace("\r\n", "\n"));
1074 assert_eq!(9, slice.print(&mut StringWriter::new()).unwrap());
1075 assert_eq!(out, table.slice(1..4).to_string().replace("\r\n", "\n"));
1076 assert_eq!(
1077 9,
1078 table.slice(1..4).print(&mut StringWriter::new()).unwrap()
1079 );
1080 }
1081
1082 #[test]
1083 fn test_unicode_separators() {
1084 let mut table = Table::new();
1085 table.set_format(*FORMAT_BOX_CHARS);
1086 table.add_row(Row::new(vec![
1087 Cell::new("1"),
1088 Cell::new("1"),
1089 Cell::new("1"),
1090 ]));
1091 table.add_row(Row::new(vec![
1092 Cell::new("2"),
1093 Cell::new("2"),
1094 Cell::new("2"),
1095 ]));
1096 table.set_titles(Row::new(vec![
1097 Cell::new("t1"),
1098 Cell::new("t2"),
1099 Cell::new("t3"),
1100 ]));
1101 let out = "\
1102┌────┬────┬────┐
1103│ t1 │ t2 │ t3 │
1104├────┼────┼────┤
1105│ 1 │ 1 │ 1 │
1106├────┼────┼────┤
1107│ 2 │ 2 │ 2 │
1108└────┴────┴────┘
1109";
1110 println!("{}", out);
1111 println!("____");
1112 println!("{}", table.to_string().replace("\r\n", "\n"));
1113 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1114 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
1115 }
1116
1117 #[test]
1118 fn test_readme_format() {
1119 let mut table = Table::new();
1122 let format = format::FormatBuilder::new()
1123 .column_separator('|')
1124 .borders('|')
1125 .separators(
1126 &[format::LinePosition::Top, format::LinePosition::Bottom],
1127 format::LineSeparator::new('-', '+', '+', '+'),
1128 )
1129 .padding(1, 1)
1130 .build();
1131 table.set_format(format);
1132
1133 table.set_titles(Row::new(vec![Cell::new("Title 1"), Cell::new("Title 2")]));
1134 table.add_row(Row::new(vec![Cell::new("Value 1"), Cell::new("Value 2")]));
1135 table.add_row(Row::new(vec![
1136 Cell::new("Value three"),
1137 Cell::new("Value four"),
1138 ]));
1139
1140 let out = "\
1141+-------------+------------+
1142| Title 1 | Title 2 |
1143| Value 1 | Value 2 |
1144| Value three | Value four |
1145+-------------+------------+
1146";
1147
1148 println!("{}", out);
1149 println!("____");
1150 println!("{}", table.to_string().replace("\r\n", "\n"));
1151 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1152 assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
1153 }
1154
1155 #[test]
1156 fn test_readme_format_with_title() {
1157 let mut table = Table::new();
1158 table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
1159
1160 table.set_titles(Row::new(vec![Cell::new("Title 1"), Cell::new("Title 2")]));
1161 table.add_row(Row::new(vec![Cell::new("Value 1"), Cell::new("Value 2")]));
1162 table.add_row(Row::new(vec![
1163 Cell::new("Value three"),
1164 Cell::new("Value four"),
1165 ]));
1166
1167 let out = "\
1168+-------------+------------+
1169| Title 1 | Title 2 |
1170+-------------+------------+
1171| Value 1 | Value 2 |
1172| Value three | Value four |
1173+-------------+------------+
1174";
1175 println!("{}", out);
1176 println!("____");
1177 println!("{}", table.to_string().replace("\r\n", "\n"));
1178 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1179 assert_eq!(6, table.print(&mut StringWriter::new()).unwrap());
1180 }
1181
1182 #[test]
1183 fn test_empty_table_with_title() {
1184 let mut table = Table::new();
1185 table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
1186
1187 table.set_titles(Row::new(vec![Cell::new("Title 1"), Cell::new("Title 2")]));
1188
1189 let out = "\
1190+---------+---------+
1191| Title 1 | Title 2 |
1192+---------+---------+
1193+---------+---------+
1194";
1195 println!("{}", out);
1196 println!("____");
1197 println!("{}", table.to_string().replace("\r\n", "\n"));
1198 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1199 assert_eq!(4, table.print(&mut StringWriter::new()).unwrap());
1200 }
1201
1202 #[test]
1203 fn test_horizontal_span() {
1204 let mut table = Table::new();
1205 table.set_titles(Row::new(vec![
1206 Cell::new("t1"),
1207 Cell::new("t2").with_hspan(2),
1208 ]));
1209 table.add_row(Row::new(vec![
1210 Cell::new("a"),
1211 Cell::new("bc"),
1212 Cell::new("def"),
1213 ]));
1214 table.add_row(Row::new(vec![
1215 Cell::new("def").style_spec("H02c"),
1216 Cell::new("a"),
1217 ]));
1218 let out = "\
1219+----+----+-----+
1220| t1 | t2 |
1221+====+====+=====+
1222| a | bc | def |
1223+----+----+-----+
1224| def | a |
1225+----+----+-----+
1226";
1227 println!("{}", out);
1228 println!("____");
1229 println!("{}", table.to_string().replace("\r\n", "\n"));
1230 assert_eq!(out, table.to_string().replace("\r\n", "\n"));
1231 assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
1232 }
1233
1234 #[test]
1235 fn table_html() {
1236 let mut table = Table::new();
1237 table.add_row(Row::new(vec![
1238 Cell::new("a"),
1239 Cell::new("bc"),
1240 Cell::new("def"),
1241 ]));
1242 table.add_row(Row::new(vec![
1243 Cell::new("def"),
1244 Cell::new("bc"),
1245 Cell::new("a"),
1246 ]));
1247 table.set_titles(Row::new(vec![
1248 Cell::new("t1"),
1249 Cell::new("t2"),
1250 Cell::new("t3"),
1251 ]));
1252 let out = "\
1253<table>\
1254<th><td style=\"text-align: left;\">t1</td><td style=\"text-align: left;\">t2</td><td style=\"text-align: left;\">t3</td></th>\
1255<tr><td style=\"text-align: left;\">a</td><td style=\"text-align: left;\">bc</td><td style=\"text-align: left;\">def</td></tr>\
1256<tr><td style=\"text-align: left;\">def</td><td style=\"text-align: left;\">bc</td><td style=\"text-align: left;\">a</td></tr>\
1257</table>";
1258 let mut writer = StringWriter::new();
1259 assert!(table.print_html(&mut writer).is_ok());
1260 assert_eq!(writer.as_string().replace("\r\n", "\n"), out);
1261 table.unset_titles();
1262 let out = "\
1263<table>\
1264<tr><td style=\"text-align: left;\">a</td><td style=\"text-align: left;\">bc</td><td style=\"text-align: left;\">def</td></tr>\
1265<tr><td style=\"text-align: left;\">def</td><td style=\"text-align: left;\">bc</td><td style=\"text-align: left;\">a</td></tr>\
1266</table>";
1267 let mut writer = StringWriter::new();
1268 assert!(table.print_html(&mut writer).is_ok());
1269 assert_eq!(writer.as_string().replace("\r\n", "\n"), out);
1270 }
1271
1272 #[test]
1273 fn table_html_colors() {
1274 let mut table = Table::new();
1275 table.add_row(Row::new(vec![
1276 Cell::new("bold").style_spec("b"),
1277 Cell::new("italic").style_spec("i"),
1278 Cell::new("underline").style_spec("u"),
1279 ]));
1280 table.add_row(Row::new(vec![
1281 Cell::new("left").style_spec("l"),
1282 Cell::new("center").style_spec("c"),
1283 Cell::new("right").style_spec("r"),
1284 ]));
1285 table.add_row(Row::new(vec![
1286 Cell::new("red").style_spec("Fr"),
1287 Cell::new("black").style_spec("Fd"),
1288 Cell::new("yellow").style_spec("Fy"),
1289 ]));
1290 table.add_row(Row::new(vec![
1291 Cell::new("bright magenta on cyan").style_spec("FMBc"),
1292 Cell::new("white on bright green").style_spec("FwBG"),
1293 Cell::new("default on blue").style_spec("Bb"),
1294 ]));
1295 table.set_titles(Row::new(
1296 vec![Cell::new("span horizontal").style_spec("H3")],
1297 ));
1298 let out = "\
1299<table>\
1300<th><td colspan=\"3\" style=\"text-align: left;\">span horizontal</td></th>\
1301<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>\
1302<tr><td style=\"text-align: left;\">left</td><td style=\"text-align: center;\">center</td><td style=\"text-align: right;\">right</td></tr>\
1303<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>\
1304<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>\
1305</table>";
1306 let mut writer = StringWriter::new();
1307 assert!(table.print_html(&mut writer).is_ok());
1308 assert_eq!(writer.as_string().replace("\r\n", "\n"), out);
1309 }
1310
1311 #[test]
1312 fn test_panic() {
1313 let mut table = Table::new();
1314
1315 table.add_row(Row::new(vec![Cell::new("\u{1b}[\u{1b}\u{0}\u{0}")]));
1316
1317 let out = "+--+
1318| \u{1b}[\u{1b}\u{0}\u{0} |
1319+--+
1320";
1321
1322 assert_eq!(table.to_string().replace("\r\n", "\n"), out);
1323 assert_eq!(3, table.print(&mut StringWriter::new()).unwrap());
1324 }
1325}