summaryrefslogtreecommitdiffstats
path: root/src/cell.rs
blob: 2fe6380e8774bfd38d7729aa95ac1c51ef60d6ad (plain)
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! This module contains definition of table/row cells stuff

use std::io::{Write, Error};
use std::string::ToString;
use unicode_width::UnicodeWidthStr;
use super::format::Align;

/// Represent a table cell containing a string.
///
/// Once created, a cell's content cannot be modified.
/// The cell would have to be replaced by another one
#[derive(Clone, Debug)]
pub struct Cell {
	content: Vec<String>,
	width: usize,
	align: Align
}

impl Cell {
	/// Create a new `Cell` initialized with content from `string`.
	/// Text alignment in cell is configurable with the `align` argument
	pub fn new_align(string: &str, align: Align) -> Cell {
		let content: Vec<String> = string.lines_any().map(|ref x| x.to_string()).collect();
		let mut width = 0;
		for cont in &content {
			let l = UnicodeWidthStr::width(&cont[..]);
			if l > width {
				width = l;
			}
		}
		return Cell {
			content: content,
			width: width,
			align: align
		};
	}
	
	/// Create a new `Cell` initialized with content from `string`.
	/// By default, content is align to `LEFT`
	pub fn new(string: &str) -> Cell {
		return Cell::new_align(string, Align::LEFT);
	}
	
	/// Set text alignment in the cell
	pub fn align(&mut self, align: Align) {
		self.align = align;
	}
	
	/// Return the height of the cell
	pub fn get_height(&self) -> usize {
		return self.content.len();
	}
	
	/// Return the width of the cell
	pub fn get_width(&self) -> usize {
		return self.width;
	}
	
	/// Return a copy of the full string contained in the cell
	pub fn get_content(&self) -> String {
		return self.content.iter().fold("".to_string(), (|acc, ref item| format!("{}\n{}", acc, item)));
	}
	
	/// Print a partial cell to `out`. Since the cell may be multi-lined,
	/// `idx` is the line index to print. `col_width` is the column width used to
	/// fill the cells with blanks so it fits in the table.
	/// If `ìdx` is higher than this cell's height, it will print empty content
	pub fn print<T: Write>(&self, out: &mut T, idx: usize, col_width: usize) -> Result<(), Error> {
		let c = match self.content.get(idx) {
			Some(s) => s.as_ref(),
			None => ""
		};
		return match self.align {
			Align::LEFT   => write!(out, " {: <1$} ", c, col_width),
			Align::CENTER => write!(out, " {: ^1$} ", c, col_width),
			Align::RIGHT  => write!(out, " {: >1$} ", c, col_width),
		}
	}
}

impl <'a, T: ToString> From<&'a T> for Cell {
	fn from(f: &T) -> Cell {
		return Cell::new(&f.to_string());
	}
}

impl ToString for Cell {
	fn to_string(&self) -> String {
		return self.get_content();
	}
}

impl Default for Cell {
	/// Return a cell initialized with a single empty `String`, with LEFT alignment
	fn default() -> Cell {
		return Cell {
			content: vec!["".to_string(); 1],
			width: 0,
			align: Align::LEFT
		};
	}
}

#[cfg(test)]
mod tests {
	use cell::Cell;
	use utils::StringWriter;
	use format::Align;

	#[test]
	fn ascii() {
		let ascii_cell = Cell::new("hello");
		assert_eq!(ascii_cell.get_width(), 5);

		let mut out = StringWriter::new();
		let _ = ascii_cell.print(&mut out, 0, 10);
		assert_eq!(out.as_string(), " hello      ");
	}

	#[test]
	fn unicode() {
		let unicode_cell = Cell::new("привет");
		assert_eq!(unicode_cell.get_width(), 6);

		let mut out = StringWriter::new();
		let _ = unicode_cell.print(&mut out, 0, 10);
		assert_eq!(out.as_string(), " привет     ");
	}
	
	#[test]
	fn align_left() {
		let cell = Cell::new_align("test", Align::LEFT);
		let mut out = StringWriter::new();
		let _ = cell.print(&mut out, 0, 10);
		assert_eq!(out.as_string(), " test       ");
	}
	
	#[test]
	fn align_center() {
		let cell = Cell::new_align("test", Align::CENTER);
		let mut out = StringWriter::new();
		let _ = cell.print(&mut out, 0, 10);
		assert_eq!(out.as_string(), "    test    ");
	}
	
	#[test]
	fn align_right() {
		let cell = Cell::new_align("test", Align::RIGHT);
		let mut out = StringWriter::new();
		let _ = cell.print(&mut out, 0, 10);
		assert_eq!(out.as_string(), "       test ");
	}
}