Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trailing cells in right and center alignment mode #30

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 34 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub struct TabWriter<W> {
}

/// `Alignment` represents how a `TabWriter` should align text within its cell.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq)]
pub enum Alignment {
/// Text should be aligned with the left edge of the cell
Left,
Expand Down Expand Up @@ -257,7 +257,11 @@ impl<W: io::Write> io::Write for TabWriter<W> {
if self.curcell.size > 0 {
self.term_curcell();
}
let widths = cell_widths(&self.lines, self.minwidth);
let widths = cell_widths(
&self.lines,
self.minwidth,
self.alignment != Alignment::Left,
);

// This is a trick to avoid allocating padding for every cell.
// Just allocate the most we'll ever need and borrow from it.
Expand All @@ -280,7 +284,7 @@ impl<W: io::Write> io::Write for TabWriter<W> {
let bytes =
&self.buf.get_ref()[cell.start..cell.start + cell.size];
if i >= widths.len() {
// There is no width for the last column
// There may be no width for the last column
assert_eq!(i, line.len() - 1);
self.w.write_all(bytes)?;
} else {
Expand All @@ -295,9 +299,15 @@ impl<W: io::Write> io::Write for TabWriter<W> {
}
};
right_spaces += self.padding;
write!(&mut self.w, "{}", &padding[0..left_spaces])?;
// Omit initial padding if this is the last cell and its empty
if !(bytes.len() == 0 && i + 1 == line.len()) {
write!(&mut self.w, "{}", &padding[0..left_spaces])?;
}
self.w.write_all(bytes)?;
write!(&mut self.w, "{}", &padding[0..right_spaces])?;
// Omit final padding if this is the last cell.
if i + 1 < line.len() {
write!(&mut self.w, "{}", &padding[0..right_spaces])?;
}
}
}
}
Expand Down Expand Up @@ -347,7 +357,13 @@ impl<W: ::std::any::Any> error::Error for IntoInnerError<W> {
}
}

fn cell_widths(lines: &Vec<Vec<Cell>>, minwidth: usize) -> Vec<Vec<usize>> {
/// Compute the widths of all cells.
/// If `trailing_cell` is set, then a cell is placed to the right of the final tab on each line.
fn cell_widths(
lines: &Vec<Vec<Cell>>,
minwidth: usize,
trailing_cell: bool,
) -> Vec<Vec<usize>> {
// Naively, this algorithm looks like it could be O(n^2m) where `n` is
// the number of lines and `m` is the number of contiguous columns.
//
Expand All @@ -358,13 +374,21 @@ fn cell_widths(lines: &Vec<Vec<Cell>>, minwidth: usize) -> Vec<Vec<usize>> {
if iline.is_empty() {
continue;
}
for col in ws[i].len()..(iline.len() - 1) {
let n_cols = iline.len() - 1 + trailing_cell as usize;
for col in ws[i].len()..n_cols {
let mut width = minwidth;
let mut contig_count = 0;
for line in lines[i..].iter() {
if col + 1 >= line.len() {
// ignores last column
break;
if trailing_cell {
if col >= line.len() {
// does not ignore last column
break;
}
} else {
if col + 1 >= line.len() {
// ignores last column
break;
}
}
contig_count += 1;
width = cmp::max(width, line[col].width);
Expand Down
75 changes: 66 additions & 9 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,16 @@ fn test_one_cell() {
}

#[test]
fn test_one_cell_right() {
fn test_one_tab_right() {
iseq(
tabw().padding(2).minwidth(2).alignment(Alignment::Right),
"a\tb\nxx\tyy",
" a b\nxx yy",
" a b\nxx yy",
);
}

#[test]
fn test_one_cell_center() {
fn test_one_tab_center() {
iseq(
tabw().padding(2).minwidth(2).alignment(Alignment::Center),
"a\tb\nxx\tyy",
Expand Down Expand Up @@ -156,18 +156,75 @@ fn test_table_center() {
fn test_contiguous_columns_right() {
iseq(
tabw().padding(1).minwidth(0).alignment(Alignment::Right),
"x\tfoo\tx\nx\tfoofoo\tx\n\nx\tfoofoofoo\tx",
"x foo x\nx foofoo x\n\nx foofoofoo x",
);
concat!(
"x\tfoo\tx\n",
"x\tfoofoo\tx\n",
"\n",
"x\tfoofoofoo\tx\n",
"\n",
"x\tfoo\tx\n",
"x\tfoofoo\tx\n",
),
concat!(
"x foo x\n",
"x foofoo x\n",
"\n",
"x foofoofoo x\n",
"\n",
"x foo x\n",
"x foofoo x\n",
),
)
}

#[test]
fn test_empty_cell_right() {
iseq(
tabw().padding(1).minwidth(0).alignment(Alignment::Right),
concat!(
"x\tfoo\tx\n",
"x\tfoofoo\tx\n",
"\t\n",
"x\tfoofoofoo\tx\n",
"\t\n",
"x\tfoo\tx\n",
"x\tfoofoo\tx\n",
),
concat!(
"x foo x\n",
"x foofoo x\n",
" \n",
"x foofoofoo x\n",
" \n",
"x foo x\n",
"x foofoo x\n",
),
)
}

#[test]
fn test_contiguous_columns_center() {
iseq(
tabw().padding(1).minwidth(0).alignment(Alignment::Center),
"x\tfoo\tx\nx\tfoofoo\tx\n\nx\tfoofoofoo\tx",
"x foo x\nx foofoo x\n\nx foofoofoo x",
);
concat!(
"x\tfoo\txyx\n",
"x\tfoofoo\tx\n",
"\n",
"x\tfoofoofoo\tx\n",
"\n",
"x\tfoo\txyx\n",
"x\tfoofoo\tx\n",
),
concat!(
"x foo xyx\n",
"x foofoo x\n",
"\n",
"x foofoofoo x\n",
"\n",
"x foo xyx\n",
"x foofoo x\n",
),
)
}

#[test]
Expand Down