summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorpierresy <phsym@msn.com>2016-01-03 14:14:27 +0100
committerpierresy <phsym@msn.com>2016-01-03 14:14:27 +0100
commit93495d81195cd464016612fdd2bed284ddb6a1f0 (patch)
treed65d4ce48389eb69931207252019d24978e49173 /src
parentaac360ceac297ed09e1f036381a9ebe9e4ab709d (diff)
Implemented print_align function for #12
Implemented print_align function to replace rust's std fill/align capability.
Diffstat (limited to 'src')
-rw-r--r--src/cell.rs68
-rw-r--r--src/format.rs14
-rw-r--r--src/utils.rs60
3 files changed, 104 insertions, 38 deletions
diff --git a/src/cell.rs b/src/cell.rs
index 046bc11..52e80ff 100644
--- a/src/cell.rs
+++ b/src/cell.rs
@@ -5,6 +5,7 @@ use std::string::ToString;
use unicode_width::UnicodeWidthStr;
use term::{Attr, Terminal, color};
use super::format::Align;
+use super::utils::print_align;
/// Represent a table cell containing a string.
///
@@ -37,35 +38,35 @@ impl Cell {
style: Vec::new()
};
}
-
+
/// 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;
}
-
+
/// Add a style attribute to the cell
pub fn style(&mut self, attr: Attr) {
self.style.push(attr);
}
-
+
/// Add a style attribute to the cell. Can be chained
pub fn with_style(mut self, attr: Attr) -> Cell {
self.style(attr);
return self;
}
-
+
/// Remove all style attributes and reset alignment to default (LEFT)
pub fn reset_style(&mut self) {
self.style.clear();
self.align(Align::LEFT);
}
-
+
/// Set the cell's style by applying the given specifier string
///
/// # Style spec syntax
@@ -84,7 +85,7 @@ impl Cell {
/// * **l** : Align **l**eft
/// * **r** : Align **r**ight
/// * **d** : **d**efault style
- ///
+ ///
/// ### List of color specifiers :
///
/// * **r** : Red
@@ -95,7 +96,7 @@ impl Cell {
/// * **m** : Magenta
/// * **w** : White
/// * **d** : Black
- ///
+ ///
/// And capital letters are for **bright** colors.
/// Eg :
///
@@ -153,22 +154,22 @@ impl Cell {
}
return self;
}
-
+
/// 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.join("\n");
}
-
+
/// 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.
@@ -178,13 +179,16 @@ impl Cell {
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),
- }
+ try!(write!(out, " "));
+ try!(print_align(out, self.align, c, ' ', col_width));
+ return write!(out, " ");
+ // 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),
+ // }
}
-
+
/// Apply style then call `print` to print the cell into a terminal
pub fn print_term<T: Terminal+?Sized>(&self, out: &mut T, idx: usize, col_width: usize) -> Result<(), Error> {
for a in &self.style {
@@ -221,14 +225,14 @@ impl Default for Cell {
}
/// This macro simplifies `Cell` creation
-///
+///
/// Support 2 syntax : With and without style specification.
/// # Syntax
/// ```text
/// cell!(value);
/// ```
/// or
-///
+///
/// ```text
/// cell!(spec:value);
/// ```
@@ -260,7 +264,7 @@ mod tests {
use utils::StringWriter;
use format::Align;
use term::{Attr, color};
-
+
#[test]
fn get_content() {
let cell = Cell::new("test");
@@ -286,7 +290,16 @@ mod tests {
let _ = unicode_cell.print(&mut out, 0, 10);
assert_eq!(out.as_string(), " привет ");
}
-
+
+ #[test]
+ fn print_cjk() {
+ let unicode_cell = Cell::new("由系统自动更新");
+ assert_eq!(unicode_cell.get_width(), 14);
+ let mut out = StringWriter::new();
+ let _ = unicode_cell.print(&mut out, 0, 20);
+ assert_eq!(out.as_string(), " 由系统自动更新 ");
+ }
+
#[test]
fn align_left() {
let cell = Cell::new_align("test", Align::LEFT);
@@ -294,7 +307,7 @@ mod tests {
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);
@@ -302,7 +315,7 @@ mod tests {
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);
@@ -310,7 +323,7 @@ mod tests {
let _ = cell.print(&mut out, 0, 10);
assert_eq!(out.as_string(), " test ");
}
-
+
#[test]
fn style_spec() {
let mut cell = Cell::new("test").style_spec("FrBBbuic");
@@ -321,14 +334,14 @@ mod tests {
assert!(cell.style.contains(&Attr::ForegroundColor(color::RED)));
assert!(cell.style.contains(&Attr::BackgroundColor(color::BRIGHT_BLUE)));
assert_eq!(cell.align, Align::CENTER);
-
+
cell = cell.style_spec("FDBwr");
assert_eq!(cell.style.len(), 2);
assert!(cell.style.contains(&Attr::ForegroundColor(color::BRIGHT_BLACK)));
assert!(cell.style.contains(&Attr::BackgroundColor(color::WHITE)));
assert_eq!(cell.align, Align::RIGHT)
}
-
+
#[test]
fn reset_style() {
let mut cell = Cell::new("test").style_spec("FDBwr");
@@ -338,4 +351,3 @@ mod tests {
assert_eq!(cell.align, Align::LEFT);
}
}
-
diff --git a/src/format.rs b/src/format.rs
index 8b9a32d..91d167f 100644
--- a/src/format.rs
+++ b/src/format.rs
@@ -5,7 +5,7 @@ use std::io::{Write, Error};
use super::utils::NEWLINE;
/// Alignment for cell's content
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Copy)]
pub enum Align {
LEFT,
CENTER,
@@ -20,13 +20,13 @@ pub struct LineSeparator {
}
impl LineSeparator {
-
+
/// Create a new line separator instance where `line` is the character used to separate 2 lines
/// and `cross` is the one used when column separaors and line separators cross
pub fn new(line: char, cross: char) -> LineSeparator {
return LineSeparator{line: [line as u8], cross: [cross as u8]};
}
-
+
/// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
pub fn print<T: Write+?Sized>(&self, out: &mut T, col_width: &[usize], with_colsep: bool) -> Result<(), Error> {
if with_colsep {
@@ -51,7 +51,7 @@ pub struct TableFormat {
}
impl TableFormat {
-
+
/// Create a new TableFormat.
///
/// `col_sep` is the character used for separating columns.
@@ -65,7 +65,7 @@ impl TableFormat {
};
return TableFormat{col_sep: csep, line_sep: line_sep, title_sep: title_sep};
}
-
+
/// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
pub fn print_line_separator<T: Write+?Sized>(&self, out: &mut T, col_width: &[usize]) -> Result<(), Error> {
if let Some(ref l) = self.line_sep {
@@ -73,7 +73,7 @@ impl TableFormat {
}
return Ok(());
}
-
+
/// Print a full title separator to `out`. `col_width` is a slice containing the width of each column
pub fn print_title_separator<T: Write+?Sized>(&self, out: &mut T, col_width: &[usize]) -> Result<(), Error> {
if let Some(ref l) = self.title_sep {
@@ -81,7 +81,7 @@ impl TableFormat {
}
return self.print_line_separator(out, col_width);
}
-
+
/// Print a column separator to `out`
pub fn print_column_separator<T: Write+?Sized>(&self, out: &mut T) -> Result<(), Error> {
return match self.col_sep {
diff --git a/src/utils.rs b/src/utils.rs
index cfb5619..744bf0d 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -2,6 +2,10 @@
use std::io::{Error, ErrorKind, Write};
use std::str;
+use unicode_width::UnicodeWidthStr;
+
+use super::format::Align;
+
#[cfg(not(windows))]
pub static NEWLINE: &'static [u8] = b"\n";
#[cfg(windows)]
@@ -17,7 +21,7 @@ impl StringWriter {
pub fn new() -> StringWriter {
return StringWriter{string: String::new()};
}
-
+
/// Return a reference to the internally written `String`
pub fn as_string(&self) -> &str {
return &self.string;
@@ -33,9 +37,59 @@ impl Write for StringWriter {
self.string.push_str(string);
return Ok(data.len());
}
-
+
fn flush(&mut self) -> Result<(), Error> {
// Nothing to do here
return Ok(());
}
-} \ No newline at end of file
+}
+
+/// Align/fill a string and print it to `out`
+pub fn print_align<T: Write+?Sized>(out: &mut T, align: Align, text: &str, fill: char, size: usize) -> Result<(), Error> {
+ let text_len = UnicodeWidthStr::width(text);
+ let mut nfill = if text_len < size { size - text_len } else { 0 };
+ match align {
+ Align::LEFT => {},
+ Align:: RIGHT => {try!(out.write(&vec![fill as u8; nfill])); nfill = 0;},
+ Align:: CENTER => {try!(out.write(&vec![fill as u8; nfill/2])); nfill -= nfill/2;}
+ }
+ try!(out.write(text.as_bytes()));
+ try!(out.write(&vec![fill as u8; nfill]));
+ return Ok(());
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use format::Align;
+ use std::io::Write;
+
+ #[test]
+ fn string_writer() {
+ let mut out = StringWriter::new();
+ out.write("foo".as_bytes()).unwrap();
+ out.write(" ".as_bytes()).unwrap();
+ out.write("".as_bytes()).unwrap();
+ out.write("bar".as_bytes()).unwrap();
+ assert_eq!(out.as_string(), "foo bar");
+ }
+
+ #[test]
+ fn fill_align() {
+ let mut out = StringWriter::new();
+ print_align(&mut out, Align::RIGHT, "foo", '*', 10).unwrap();
+ assert_eq!(out.as_string(), "*******foo");
+
+ let mut out = StringWriter::new();
+ print_align(&mut out, Align::LEFT, "foo", '*', 10).unwrap();
+ assert_eq!(out.as_string(), "foo*******");
+
+ let mut out = StringWriter::new();
+ print_align(&mut out, Align::CENTER, "foo", '*', 10).unwrap();
+ assert_eq!(out.as_string(), "***foo****");
+
+ let mut out = StringWriter::new();
+ print_align(&mut out, Align::CENTER, "foo", '*', 1).unwrap();
+ assert_eq!(out.as_string(), "foo");
+ }
+}