Skip to content

Commit

Permalink
Merge pull request #20 from freva/freva/hide-column
Browse files Browse the repository at this point in the history
Support setting columns invisible
  • Loading branch information
freva authored Sep 18, 2022
2 parents c466fae + 6a2dfea commit 2dd24af
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 37 deletions.
24 changes: 16 additions & 8 deletions src/main/java/com/github/freva/asciitable/AsciiTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ static void writeTable(OutputStreamWriter osw, String lineSeparator, Character[]
if (border.length != NO_BORDERS.length)
throw new IllegalArgumentException("Border characters array must be exactly " + NO_BORDERS.length + " elements long");

String[][] stringData = objectArrayToString(data);
int numColumns = getNumColumns(rawColumns, stringData);
String[][] stringData = objectArrayToString(rawColumns, data);
int numColumns = getNumColumns(rawColumns, data);
Column[] columns = IntStream.range(0, numColumns)
.mapToObj(index -> index < rawColumns.length ? rawColumns[index] : new Column())
.filter(Column::isVisible)
.toArray(Column[]::new);

writeTable(osw, lineSeparator, border, columns, stringData);
Expand Down Expand Up @@ -160,7 +161,7 @@ private static int[] getColWidths(Column[] columns, String[][] data) {
}

/** Returns maximum number of columns between the header or any of the data rows */
private static int getNumColumns(Column[] columns, String[][] data) {
private static int getNumColumns(Column[] columns, Object[][] data) {
return Arrays.stream(data)
.mapToInt(cols -> cols.length)
.reduce(columns.length, Math::max);
Expand Down Expand Up @@ -233,13 +234,20 @@ private static void writeRepeated(OutputStreamWriter osw, char c, int num) throw
for (int i = 0; i < num; i++) osw.append(c);
}

private static String[][] objectArrayToString(Object[][] array) {
if (array instanceof String[][]) return (String[][]) array;
private static String[][] objectArrayToString(Column[] columns, Object[][] array) {
int[] numInvisible = new int[Math.max(1, columns.length)];
for (int i = 0; i < columns.length; i++)
numInvisible[i] = (i == 0 ? 0 : numInvisible[i - 1]) + (columns[i].isVisible() ? 0 : 1);

if (numInvisible[numInvisible.length - 1] == 0 && array instanceof String[][])
return (String[][]) array;

String[][] stringArray = new String[array.length][];
for (int i = 0; i < stringArray.length; i++) {
stringArray[i] = new String[array[i].length];
for (int j = 0; j < array[i].length; j++) {
stringArray[i][j] = array[i][j] == null ? null : array[i][j].toString();
stringArray[i] = new String[array[i].length - numInvisible[Math.min(numInvisible.length, array[i].length) - 1]];
for (int j = 0, k = 0; k < stringArray[i].length; j++) {
if (j < columns.length && !columns[j].isVisible()) continue;
stringArray[i][k++] = array[i][j] == null ? null : array[i][j].toString();
}
}
return stringArray;
Expand Down
20 changes: 16 additions & 4 deletions src/main/java/com/github/freva/asciitable/Column.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ public class Column {
private int minWidth;
private int maxWidth;
private OverflowBehaviour overflowBehaviour;
private boolean visible;

public Column() {
this(null, null, HorizontalAlign.LEFT, HorizontalAlign.RIGHT, HorizontalAlign.LEFT, 0, 80, OverflowBehaviour.NEWLINE);
this(null, null, HorizontalAlign.LEFT, HorizontalAlign.RIGHT, HorizontalAlign.LEFT, 0, 80, OverflowBehaviour.NEWLINE, true);
}

@Deprecated
public Column(String header, String footer, HorizontalAlign headerAlign, HorizontalAlign dataAlign,
HorizontalAlign footerAlign, int maxWidth) {
this(header, footer, headerAlign, dataAlign, footerAlign, 0, maxWidth, OverflowBehaviour.NEWLINE);
this(header, footer, headerAlign, dataAlign, footerAlign, 0, maxWidth, OverflowBehaviour.NEWLINE, true);
}

public Column(String header, String footer, HorizontalAlign headerAlign, HorizontalAlign dataAlign,
HorizontalAlign footerAlign, int minWidth, int maxWidth, OverflowBehaviour overflowBehaviour) {
Column(String header, String footer, HorizontalAlign headerAlign, HorizontalAlign dataAlign,
HorizontalAlign footerAlign, int minWidth, int maxWidth, OverflowBehaviour overflowBehaviour, boolean visible) {
this.header = header;
this.footer = footer;
this.headerAlign = headerAlign;
Expand All @@ -32,6 +33,7 @@ public Column(String header, String footer, HorizontalAlign headerAlign, Horizon
this.minWidth = minWidth;
this.maxWidth = maxWidth;
this.overflowBehaviour = overflowBehaviour;
this.visible = visible;
}

public String getHeader() {
Expand Down Expand Up @@ -80,6 +82,10 @@ public int getFooterWidth() {
return footer != null ? footer.length() : 0;
}

public boolean isVisible() {
return visible;
}


public Column header(String header) {
this.header = header;
Expand Down Expand Up @@ -131,6 +137,12 @@ public Column maxWidth(int maxWidth, OverflowBehaviour overflowBehaviour) {
@Deprecated
public Column maxColumnWidth(int maxWidth) { return maxWidth(maxWidth); }

/** Sets whether this column should be rendered. Default is true */
public Column visible(boolean visible) {
this.visible = visible;
return this;
}

public <T> ColumnData<T> with(Function<T, String> getter) {
return new ColumnData<T>(this, getter);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/github/freva/asciitable/ColumnData.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class ColumnData<T> extends Column {

ColumnData(Column column, Function<T, String> getter) {
super(column.getHeader(), column.getFooter(), column.getHeaderAlign(), column.getDataAlign(), column.getFooterAlign(),
column.getMinWidth(), column.getMaxWidth(), column.getOverflowBehaviour());
column.getMinWidth(), column.getMaxWidth(), column.getOverflowBehaviour(), column.isVisible());
this.getter = getter;
}

Expand Down
10 changes: 8 additions & 2 deletions src/main/java/com/github/freva/asciitable/LineUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ public static int maxLineLength(String str) {
private static class LineIterator implements Iterator<String> {
private final String str;
private int position = 0;
private boolean newlineLast = true;

private LineIterator(String str) {
this.str = str;
}

@Override
public boolean hasNext() {
return position < str.length();
return newlineLast || position < str.length();
}

@Override
Expand All @@ -44,10 +45,15 @@ public String next() {
}

public int getLineEndPositionAndAdvanceToNextLine() {
newlineLast = false;
for (; position < str.length(); position++) {
char ch = str.charAt(position);
if (ch == '\n') return position++;
if (ch == '\n') {
newlineLast = true;
return position++;
}
if (ch == '\r') {
newlineLast = true;
if (position + 1 == str.length() || str.charAt(position + 1) != '\n') return position++;
position += 2;
return position - 2;
Expand Down
41 changes: 19 additions & 22 deletions src/test/java/com/github/freva/asciitable/AsciiTableTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
import org.junit.Test;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.BiConsumer;

import static com.github.freva.asciitable.HorizontalAlign.*;
import static org.junit.Assert.assertEquals;
Expand Down Expand Up @@ -385,23 +381,6 @@ public void tableWithParagraphsClipLeftOverflow() {

@Test
public void tableWithParagraphsClipRightOverflow() throws IOException {
try (OutputStream fos = Files.newOutputStream(Paths.get("table.txt"))) {
AsciiTable.builder()
.lineSeparator("\r\n")
.border(AsciiTable.BASIC_ASCII_NO_OUTSIDE_BORDER)
.data(planets, Arrays.asList(
new Column().with(planet -> Integer.toString(planet.num)),
new Column().header("Name").footer("Average").headerAlign(CENTER).dataAlign(RIGHT).with(planet -> planet.name),
new Column().header("Diameter").headerAlign(RIGHT).dataAlign(CENTER).footerAlign(CENTER)
.footer(String.format("%.03f", planets.stream().mapToDouble(planet -> planet.diameter).average().orElse(0)))
.with(planet -> String.format("%.03f", planet.diameter)),
new Column().header("Mass").headerAlign(RIGHT).dataAlign(LEFT)
.footer(String.format("%.02f", planets.stream().mapToDouble(planet -> planet.mass).average().orElse(0)))
.with(planet -> String.format("%.02f", planet.mass)),
new Column().header("Atmosphere").headerAlign(LEFT).dataAlign(CENTER).with(planet -> planet.atmosphere)))
.writeTo(fos);
}

assertParagraphs(OverflowBehaviour.CLIP_RIGHT,
"+------------------+------------------------------+",
"| Long first heade | An even |",
Expand Down Expand Up @@ -457,6 +436,24 @@ public void tableWithParagraphsEllipsisRightOverflow() {
"+------------------+------------------------------+");
}

@Test
public void invisibleColumns() {
String[][] data = {{"11", "12", "13", "14"}, {"21", "22"}};
BiConsumer<Boolean[], String[]> asserter = (visibleColumns, expectedRows) -> {
Column[] columns = Arrays.stream(visibleColumns).map(visible -> new Column().visible(visible)).toArray(Column[]::new);
assertEquals(String.join(System.lineSeparator(), expectedRows), AsciiTable.getTable(AsciiTable.NO_BORDERS, columns, data));
};

asserter.accept(new Boolean[]{true, false}, new String[]{" 11 13 14 ", " 21 "});
asserter.accept(new Boolean[]{true, false, true}, new String[]{" 11 13 14 ", " 21 "});
asserter.accept(new Boolean[]{true, false, true, false}, new String[]{" 11 13 ", " 21 "});
asserter.accept(new Boolean[]{false, false, true, false}, new String[]{" 13 ", " "});
asserter.accept(new Boolean[]{}, new String[]{" 11 12 13 14 ", " 21 22 "});
asserter.accept(new Boolean[]{true, true, true, true}, new String[]{" 11 12 13 14 ", " 21 22 "});
asserter.accept(new Boolean[]{true, true, true, true, false}, new String[]{" 11 12 13 14 ", " 21 22 "});
asserter.accept(new Boolean[]{true, true, true, true, true}, new String[]{" 11 12 13 14 ", " 21 22 "});
}

@Test
public void validateNullInHeader() {
String[] headers = {"Lorem", null, "Dolor"};
Expand Down
9 changes: 9 additions & 0 deletions src/test/java/com/github/freva/asciitable/LineUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@

public class LineUtilsTest {

@Test
public void ensureTrailingEmptyLineIsReturned() {
assertEquals(Arrays.asList(""),
LineUtils.lines("").collect(Collectors.toList()));

assertEquals(Arrays.asList("", ""),
LineUtils.lines("\n").collect(Collectors.toList()));
}

@Test
public void linesIteratorTest() {
assertEquals(Arrays.asList("", "", "Some text", "", "more text", "text", "end"),
Expand Down

0 comments on commit 2dd24af

Please sign in to comment.