prettytable/
utils.rs
1use std::io::{Error, ErrorKind, Write};
3use std::str;
4
5use unicode_width::UnicodeWidthStr;
6
7use super::format::Alignment;
8
9#[cfg(any(not(windows), not(feature="win_crlf")))]
10pub static NEWLINE: &'static [u8] = b"\n";
11#[cfg(all(windows, feature="win_crlf"))]
12pub static NEWLINE: &'static [u8] = b"\r\n";
13
14pub struct StringWriter {
16 string: String,
17}
18
19impl StringWriter {
20 pub fn new() -> StringWriter {
22 StringWriter { string: String::new() }
23 }
24
25 pub fn as_string(&self) -> &str {
27 &self.string
28 }
29}
30
31impl Write for StringWriter {
32 fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
33 let string = match str::from_utf8(data) {
34 Ok(s) => s,
35 Err(e) => {
36 return Err(Error::new(ErrorKind::Other,
37 format!("Cannot decode utf8 string : {}", e)))
38 }
39 };
40 self.string.push_str(string);
41 Ok(data.len())
42 }
43
44 fn flush(&mut self) -> Result<(), Error> {
45 Ok(())
47 }
48}
49
50pub fn print_align<T: Write + ?Sized>(out: &mut T,
54 align: Alignment,
55 text: &str,
56 fill: char,
57 size: usize,
58 skip_right_fill: bool)
59 -> Result<(), Error> {
60 let text_len = display_width(text);
61 let mut nfill = if text_len < size { size - text_len } else { 0 };
62 let n = match align {
63 Alignment::LEFT => 0,
64 Alignment::RIGHT => nfill,
65 Alignment::CENTER => nfill / 2,
66 };
67 if n > 0 {
68 out.write_all(&vec![fill as u8; n])?;
69 nfill -= n;
70 }
71 out.write_all(text.as_bytes())?;
72 if nfill > 0 && !skip_right_fill {
73 out.write_all(&vec![fill as u8; nfill])?;
74 }
75 Ok(())
76}
77
78pub fn display_width(text: &str) -> usize {
81 let width = UnicodeWidthStr::width(text);
82 let mut state = 0;
83 let mut hidden = 0;
84
85 for c in text.chars() {
86 state = match (state, c) {
87 (0, '\u{1b}') => 1,
88 (1, '[') => 2,
89 (1, _) => 0,
90 (2, 'm') => 3,
91 _ => state,
92 };
93
94 if state > 1 {
97 hidden += 1;
98 }
99
100 if state == 3 {
101 state = 0;
102 }
103 }
104
105 width - hidden
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use format::Alignment;
112 use std::io::Write;
113
114 #[test]
115 fn string_writer() {
116 let mut out = StringWriter::new();
117 out.write("foo".as_bytes()).unwrap();
118 out.write(" ".as_bytes()).unwrap();
119 out.write("".as_bytes()).unwrap();
120 out.write("bar".as_bytes()).unwrap();
121 assert_eq!(out.as_string(), "foo bar");
122 }
123
124 #[test]
125 fn fill_align() {
126 let mut out = StringWriter::new();
127 print_align(&mut out, Alignment::RIGHT, "foo", '*', 10, false).unwrap();
128 assert_eq!(out.as_string(), "*******foo");
129
130 let mut out = StringWriter::new();
131 print_align(&mut out, Alignment::LEFT, "foo", '*', 10, false).unwrap();
132 assert_eq!(out.as_string(), "foo*******");
133
134 let mut out = StringWriter::new();
135 print_align(&mut out, Alignment::CENTER, "foo", '*', 10, false).unwrap();
136 assert_eq!(out.as_string(), "***foo****");
137
138 let mut out = StringWriter::new();
139 print_align(&mut out, Alignment::CENTER, "foo", '*', 1, false).unwrap();
140 assert_eq!(out.as_string(), "foo");
141 }
142
143 #[test]
144 fn skip_right_fill() {
145 let mut out = StringWriter::new();
146 print_align(&mut out, Alignment::RIGHT, "foo", '*', 10, true).unwrap();
147 assert_eq!(out.as_string(), "*******foo");
148
149 let mut out = StringWriter::new();
150 print_align(&mut out, Alignment::LEFT, "foo", '*', 10, true).unwrap();
151 assert_eq!(out.as_string(), "foo");
152
153 let mut out = StringWriter::new();
154 print_align(&mut out, Alignment::CENTER, "foo", '*', 10, true).unwrap();
155 assert_eq!(out.as_string(), "***foo");
156
157 let mut out = StringWriter::new();
158 print_align(&mut out, Alignment::CENTER, "foo", '*', 1, false).unwrap();
159 assert_eq!(out.as_string(), "foo");
160 }
161
162 #[test]
163 fn utf8_error() {
164 let mut out = StringWriter::new();
165 let res = out.write_all(&vec![0, 255]);
166 assert!(res.is_err());
167 }
168}