parquet.tools.util.PrettyPrintWriter Maven / Gradle / Ivy
/**
* Copyright 2013 ARRIS, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package parquet.tools.util;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;
import java.util.Locale;
import parquet.tools.Main;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
public class PrettyPrintWriter extends PrintWriter {
public static final String MORE = " [more]...";
public static final String LINE_SEP = System.getProperty("line.separator");
public static final Span DEFAULT_APPEND;
public static final char DEFAULT_COLUMN_SEP = ':';
public static final int DEFAULT_MAX_COLUMNS = 1;
public static final int DEFAULT_COLUMN_PADDING = 1;
public static final int DEFAULT_TABS = 4;
public static final int DEFAULT_WIDTH;
public static final int DEFAULT_COLORS;
private static final String RESET = "\u001B[0m";
public static final String MODE_OFF = "0";
public static final String MODE_BOLD = "1";
public static final String MODE_UNDER = "4";
public static final String MODE_BLINK = "5";
public static final String MODE_REVERSE = "7";
public static final String MODE_CONCEALED = "8";
public static final String FG_COLOR_BLACK = "30";
public static final String FG_COLOR_RED = "31";
public static final String FG_COLOR_GREEN = "32";
public static final String FG_COLOR_YELLOW = "33";
public static final String FG_COLOR_BLUE = "34";
public static final String FG_COLOR_MAGENTA = "35";
public static final String FG_COLOR_CYAN = "36";
public static final String FG_COLOR_WHITE = "37";
public static final String BG_COLOR_BLACK = "40";
public static final String BG_COLOR_RED = "41";
public static final String BG_COLOR_GREEN = "42";
public static final String BG_COLOR_YELLOW = "43";
public static final String BG_COLOR_BLUE = "44";
public static final String BG_COLOR_MAGENTA = "45";
public static final String BG_COLOR_CYAN = "46";
public static final String BG_COLOR_WHITE = "47";
public enum WhiteSpaceHandler { ELIMINATE_NEWLINES, COLLAPSE_WHITESPACE }
static {
int consoleWidth = 80;
int numColors = 0;
String columns = System.getenv("COLUMNS");
if (columns != null && !columns.isEmpty()) {
try {
consoleWidth = Integer.parseInt(columns);
} catch (Throwable th) {
}
}
String colors = System.getenv("COLORS");
if (colors != null && !colors.isEmpty()) {
try {
numColors = Integer.parseInt(colors);
if (numColors < 0) numColors = 0;
} catch (Throwable th) {
}
}
String termout = System.getenv("TERMOUT");
if (termout != null && !termout.isEmpty()) {
if (!"y".equalsIgnoreCase(termout) &&
!"yes".equalsIgnoreCase(termout) &&
!"t".equalsIgnoreCase(termout) &&
!"true".equalsIgnoreCase(termout) &&
!"on".equalsIgnoreCase(termout)) {
consoleWidth = Integer.MAX_VALUE;
numColors = 0;
}
}
if (System.getProperty("DISABLE_COLORS", null) != null) {
numColors = 0;
}
DEFAULT_WIDTH = consoleWidth;
DEFAULT_COLORS = numColors;
if (numColors > 0) {
DEFAULT_APPEND = mkspan(MORE, null, FG_COLOR_RED, null);
} else {
DEFAULT_APPEND = mkspan(MORE);
}
}
private final StringBuilder formatString;
private final Formatter formatter;
private final ArrayList buffer;
private final boolean autoColumn;
private final boolean autoCrop;
private final Span appendToLongLine;
private final int consoleWidth;
private final int tabWidth;
private final char columnSeparator;
private final int maxColumns;
private final int columnPadding;
private final long maxBufferedLines;
private final boolean flushOnTab;
private final WhiteSpaceHandler whiteSpaceHandler;
private int tabLevel;
private String colorMode;
private String colorForeground;
private String colorBackground;
private String tabs;
private PrettyPrintWriter(OutputStream out, boolean autoFlush,
boolean autoColumn, boolean autoCrop, Span appendToLongLine,
int consoleWidth, int tabWidth, char columnSeparator,
int maxColumns, int columnPadding, long maxBufferedLines,
boolean flushOnTab, WhiteSpaceHandler whiteSpaceHandler) {
super(out, autoFlush && !autoColumn);
this.autoColumn = autoColumn;
this.autoCrop = autoCrop;
this.appendToLongLine = appendToLongLine;
this.consoleWidth = consoleWidth;
this.tabWidth = tabWidth;
this.columnSeparator = columnSeparator;
this.maxColumns = maxColumns;
this.maxBufferedLines = maxBufferedLines;
this.columnPadding = columnPadding;
this.flushOnTab = flushOnTab;
this.whiteSpaceHandler = whiteSpaceHandler;
this.buffer = new ArrayList();
this.formatString = new StringBuilder();
this.formatter = new Formatter(this.formatString);
this.colorMode = null;
this.colorForeground = null;
this.colorBackground = null;
this.tabLevel = 0;
this.tabs = "";
this.buffer.add(new Line());
}
public void setTabLevel(int level) {
this.tabLevel = level;
this.tabs = Strings.repeat(" ", tabWidth * level);
if (flushOnTab) flushColumns();
}
public void incrementTabLevel() {
setTabLevel(tabLevel + 1);
}
public void decrementTabLevel() {
if (tabLevel == 0) {
return;
}
setTabLevel(tabLevel - 1);
}
private int determineNumColumns() {
int max = 0;
for (Line line : buffer) {
int num = line.countCharacter(columnSeparator);
if (num > max) {
max = num;
}
}
return max > maxColumns ? maxColumns : max;
}
private int[] determineColumnWidths() {
int columns = determineNumColumns();
if (columns == 0) {
return null;
}
int[] widths = new int[columns];
for (Line line : buffer) {
for (int last = 0, idx = 0; last < line.length() && idx < columns; ++idx) {
int pos = line.indexOf(columnSeparator, last);
if (pos < 0) break;
int wid = pos - last + 1 + columnPadding;
if (wid > widths[idx]) {
widths[idx] = wid;
}
last = line.firstNonWhiteSpace(idx + 1);
}
}
return widths;
}
private Line toColumns(int[] widths, Line line) throws IOException {
int last = 0;
for (int i = 0; i < widths.length; ++i) {
int width = widths[i];
int idx = line.indexOf(columnSeparator, last);
if (idx < 0) break;
if ((idx+1) <= width) {
line.spaceOut(width - (idx+1), idx+1);
}
last = line.firstNonWhiteSpace(idx + 1);
}
return line;
}
public void flushColumns() {
flushColumns(false);
}
private void flushColumns(boolean preserveLast) {
int size = buffer.size();
int[] widths = null;
if (autoColumn) {
widths = determineColumnWidths();
}
StringBuilder builder = new StringBuilder();
try {
for (int i = 0; i < size - 1; ++i) {
Line line = buffer.get(i);
if (widths != null) {
line = toColumns(widths, line);
}
fixupLine(line);
builder.setLength(0);
line.toString(builder);
super.out.append(builder.toString());
super.out.append(LINE_SEP);
}
if (!preserveLast) {
Line line = buffer.get(size - 1);
if (widths != null) {
line = toColumns(widths, line);
}
fixupLine(line);
builder.setLength(0);
line.toString(builder);
super.out.append(builder.toString());
}
super.out.flush();
} catch (IOException ex) {
}
Line addback = null;
if (preserveLast) {
addback = buffer.get(size - 1);
}
buffer.clear();
if (addback != null) buffer.add(addback);
else buffer.add(new Line());
}
private void flushIfNeeded() {
flushIfNeeded(false);
}
private void flushIfNeeded(boolean preserveLast) {
if (!autoColumn || buffer.size() > maxBufferedLines) {
flushColumns(preserveLast);
}
}
private void appendToCurrent(String s) {
int size = buffer.size();
Line value = buffer.get(size - 1);
if (value.isEmpty()) {
value.append(tabs());
}
value.append(span(s));
}
private void fixupLine(Line line) {
if (autoCrop) {
line.trimTo(consoleWidth, appendToLongLine);
}
}
private void print(String s, boolean mayHaveNewlines) {
if (s == null) {
appendToCurrent("null");
return;
}
if (s.isEmpty()) {
return;
}
if (LINE_SEP.equals(s)) {
buffer.add(new Line());
flushIfNeeded();
return;
}
if (whiteSpaceHandler != null) {
boolean endswith = s.endsWith(LINE_SEP);
switch (whiteSpaceHandler) {
case ELIMINATE_NEWLINES:
s = s.replaceAll("\\r\\n|\\r|\\n", " ");
break;
case COLLAPSE_WHITESPACE:
s = s.replaceAll("\\s+", " ");
break;
}
mayHaveNewlines = endswith;
if (endswith) s = s + LINE_SEP;
}
if (!mayHaveNewlines) {
appendToCurrent(s);
return;
}
String lines[] = s.split("\\r?\\n", -1);
appendToCurrent(lines[0]);
for (int i = 1; i < lines.length; ++i) {
String value = lines[i];
if (value.isEmpty()) {
buffer.add(new Line());
} else {
Line line = new Line();
line.append(tabs());
line.append(span(value, true));
buffer.add(line);
}
}
resetColor();
flushIfNeeded(true);
}
@Override
public void print(String s) {
print(s, true);
}
@Override
public void println() {
print(LINE_SEP, true);
flushIfNeeded();
}
@Override
public void println(String x) {
print(x);
println();
}
@Override
public void print(boolean b) {
print(String.valueOf(b), false);
}
@Override
public void print(char c) {
print(String.valueOf(c), false);
}
@Override
public void print(int i) {
print(String.valueOf(i), false);
}
@Override
public void print(long l) {
print(String.valueOf(l), false);
}
@Override
public void print(float f) {
print(String.valueOf(f), false);
}
@Override
public void print(double d) {
print(String.valueOf(d), false);
}
@Override
public void print(char[] s) {
print(String.valueOf(s), true);
}
@Override
public void print(Object obj) {
print(String.valueOf(obj), true);
}
@Override
public PrintWriter printf(String format, Object... args) {
return printf(formatter.locale(), format, args);
}
@Override
public PrintWriter printf(Locale l, String format, Object... args) {
formatter.format(l, format, args);
String results = formatString.toString();
formatString.setLength(0);
print(results);
flushIfNeeded();
return this;
}
@Override
public PrintWriter format(String format, Object... args) {
return printf(format, args);
}
@Override
public PrintWriter format(Locale l, String format, Object... args) {
return printf(l, format, args);
}
@Override
public PrintWriter append(char c) {
print(c);
return this;
}
@Override
public PrintWriter append(CharSequence csq) {
if (csq == null) { print("null"); return this; }
return append(csq, 0, csq.length());
}
@Override
public PrintWriter append(CharSequence csq, int start, int end) {
if (csq == null) { print("null"); return this; }
print(csq.subSequence(start,end).toString());
return this;
}
@Override
public void println(boolean x) {
print(x);
println();
}
@Override
public void println(char x) {
print(x);
println();
}
@Override
public void println(int x) {
print(x);
println();
}
@Override
public void println(long x) {
print(x);
println();
}
@Override
public void println(float x) {
print(x);
println();
}
@Override
public void println(double x) {
print(x);
println();
}
@Override
public void println(char[] x) {
print(x);
println();
}
@Override
public void println(Object x) {
print(x);
println();
}
public void rule(char c) {
if (tabs.length() >= consoleWidth) return;
int width = consoleWidth;
if (width == Integer.MAX_VALUE) {
width = 100;
}
println(Strings.repeat(String.valueOf(c), width - tabs.length()));
}
public boolean acceptColorModification = true;
public PrettyPrintWriter iff(boolean predicate) {
if (!predicate && acceptColorModification) {
resetColor();
} else {
acceptColorModification = false;
}
return this;
}
public PrettyPrintWriter otherwise() {
acceptColorModification = false;
return this;
}
public PrettyPrintWriter black() {
if (!acceptColorModification) return this;
colorForeground = FG_COLOR_BLACK;
return this;
}
public PrettyPrintWriter red() {
if (!acceptColorModification) return this;
colorForeground = FG_COLOR_RED;
return this;
}
public PrettyPrintWriter green() {
if (!acceptColorModification) return this;
colorForeground = FG_COLOR_GREEN;
return this;
}
public PrettyPrintWriter yellow() {
if (!acceptColorModification) return this;
colorForeground = FG_COLOR_YELLOW;
return this;
}
public PrettyPrintWriter blue() {
if (!acceptColorModification) return this;
colorForeground = FG_COLOR_BLUE;
return this;
}
public PrettyPrintWriter magenta() {
if (!acceptColorModification) return this;
colorForeground = FG_COLOR_MAGENTA;
return this;
}
public PrettyPrintWriter cyan() {
if (!acceptColorModification) return this;
colorForeground = FG_COLOR_CYAN;
return this;
}
public PrettyPrintWriter white() {
if (!acceptColorModification) return this;
colorForeground = FG_COLOR_WHITE;
return this;
}
public PrettyPrintWriter bgblack() {
if (!acceptColorModification) return this;
colorBackground = BG_COLOR_BLACK;
return this;
}
public PrettyPrintWriter bgred() {
if (!acceptColorModification) return this;
colorBackground = BG_COLOR_RED;
return this;
}
public PrettyPrintWriter bggreen() {
if (!acceptColorModification) return this;
colorBackground = BG_COLOR_GREEN;
return this;
}
public PrettyPrintWriter bgyellow() {
if (!acceptColorModification) return this;
colorBackground = BG_COLOR_YELLOW;
return this;
}
public PrettyPrintWriter bgblue() {
if (!acceptColorModification) return this;
colorBackground = BG_COLOR_BLUE;
return this;
}
public PrettyPrintWriter bgmagenta() {
if (!acceptColorModification) return this;
colorBackground = BG_COLOR_MAGENTA;
return this;
}
public PrettyPrintWriter bgcyan() {
if (!acceptColorModification) return this;
colorBackground = BG_COLOR_CYAN;
return this;
}
public PrettyPrintWriter bgwhite() {
if (!acceptColorModification) return this;
colorBackground = BG_COLOR_WHITE;
return this;
}
public PrettyPrintWriter bold() {
if (!acceptColorModification) return this;
colorMode = MODE_BOLD;
return this;
}
public PrettyPrintWriter blink() {
if (!acceptColorModification) return this;
colorMode = MODE_BLINK;
return this;
}
public PrettyPrintWriter concealed() {
if (!acceptColorModification) return this;
colorMode = MODE_CONCEALED;
return this;
}
public PrettyPrintWriter off() {
if (!acceptColorModification) return this;
colorMode = MODE_OFF;
return this;
}
public PrettyPrintWriter underscore() {
if (!acceptColorModification) return this;
colorMode = MODE_UNDER;
return this;
}
public PrettyPrintWriter reverse() {
if (!acceptColorModification) return this;
colorMode = MODE_REVERSE;
return this;
}
public static Builder stdoutPrettyPrinter() {
return new Builder(Main.out).withAutoFlush();
}
public static Builder stderrPrettyPrinter() {
return new Builder(Main.err).withAutoFlush();
}
public static Builder newPrettyPrinter(OutputStream out) {
return new Builder(out);
}
public static final class Builder {
private final OutputStream out;
private boolean autoFlush;
private boolean autoColumn;
private char columnSeparator;
private int maxColumns;
private int columnPadding;
private long maxBufferedLines;
private boolean autoCrop;
private int consoleWidth;
private Span appendToLongLine;
private int tabWidth;
private boolean flushOnTab;
private WhiteSpaceHandler whiteSpaceHandler;
public Builder(OutputStream out) {
this.out = out;
this.autoFlush = false;
this.autoColumn = false;
this.flushOnTab = false;
this.columnSeparator = DEFAULT_COLUMN_SEP;
this.maxColumns = DEFAULT_MAX_COLUMNS;
this.columnPadding = DEFAULT_COLUMN_PADDING;
this.autoCrop = false;
this.consoleWidth = DEFAULT_WIDTH;
this.appendToLongLine = null;
this.tabWidth = DEFAULT_TABS;
this.whiteSpaceHandler = null;
this.maxBufferedLines = Long.MAX_VALUE;
}
public Builder withAutoFlush() {
this.autoFlush = true;
return this;
}
public Builder withAutoCrop() {
return withAutoCrop(DEFAULT_WIDTH);
}
public Builder withAutoCrop(int consoleWidth) {
return withAutoCrop(consoleWidth, DEFAULT_APPEND);
}
public Builder withAutoCrop(int consoleWidth, String appendToLong) {
return withAutoCrop(consoleWidth, mkspan(appendToLong));
}
public Builder withAutoCrop(int consoleWidth, Span appendToLong) {
this.consoleWidth = consoleWidth;
this.appendToLongLine = appendToLong;
this.autoCrop = true;
return this;
}
public Builder withTabSize(int tabWidth) {
this.tabWidth = tabWidth;
return this;
}
public Builder withAutoColumn() {
return withAutoColumn(DEFAULT_COLUMN_SEP);
}
public Builder withAutoColumn(char columnSeparator) {
return withAutoColumn(columnSeparator, DEFAULT_MAX_COLUMNS);
}
public Builder withAutoColumn(char columnSeparator, int maxColumns) {
this.autoColumn = true;
this.columnSeparator = columnSeparator;
this.maxColumns = maxColumns;
return this;
}
public Builder withColumnPadding(int columnPadding) {
this.columnPadding = columnPadding;
return this;
}
public Builder withWhitespaceHandler(WhiteSpaceHandler whiteSpaceHandler) {
this.whiteSpaceHandler = whiteSpaceHandler;
return this;
}
public Builder withMaxBufferedLines(long maxBufferedLines) {
this.maxBufferedLines = maxBufferedLines;
return this;
}
public Builder withFlushOnTab() {
this.flushOnTab = true;
return this;
}
public PrettyPrintWriter build() {
return new PrettyPrintWriter(out, autoFlush, autoColumn, autoCrop, appendToLongLine, consoleWidth, tabWidth, columnSeparator, maxColumns, columnPadding, maxBufferedLines, flushOnTab, whiteSpaceHandler);
}
}
private Span tabs() {
return new Span(tabs);
}
private Span span(String span) {
return span(span, false);
}
private void resetColor() {
acceptColorModification = true;
colorMode = null;
colorForeground = null;
colorBackground = null;
}
public static Span mkspan(String span) {
return new Span(span);
}
public static Span mkspan(String span, String color) {
return mkspan(span, null, color, null);
}
public static Span mkspan(String span, String colorMode, String colorForeground, String colorBackground) {
if (DEFAULT_COLORS > 0 && (colorMode != null || colorForeground != null || colorBackground != null)) {
String color = "\u001B[" + Joiner.on(';').skipNulls().join(colorMode, colorForeground, colorBackground) + "m";
return new Span(span, color);
} else {
return mkspan(span);
}
}
private Span span(String span, boolean keepColor) {
Span result;
if (DEFAULT_COLORS > 0 && (colorMode != null || colorForeground != null || colorBackground != null)) {
result = mkspan(span, colorMode, colorForeground, colorBackground);
} else {
result = mkspan(span);
}
if (!keepColor) {
resetColor();
}
return result;
}
public static final class Line {
private List spans;
private int length;
public Line() {
this.spans = new ArrayList();
}
public void append(Span span) {
length += span.length();
if (spans.isEmpty()) {
spans.add(span);
return;
}
Span last = spans.get(spans.size() - 1);
if (last.canAppend(span)) {
last.append(span);
} else {
spans.add(span);
}
}
public boolean isEmpty() {
return length == 0;
}
public int length() {
return length;
}
public int indexOf(char ch, int start) {
int offset = 0;
for (Span span : spans) {
if (start > span.length()) {
start -= span.length();
continue;
}
int idx = span.indexOf(ch, start);
if (idx >= 0) return offset + idx;
offset += span.length() - start;
start = 0;
}
return -1;
}
public void spaceOut(int width, int start) {
for (Span span : spans) {
if (start > span.length()) {
start -= span.length();
continue;
}
span.spaceOut(width, start);
return;
}
}
public int firstNonWhiteSpace(int start) {
return start;
}
public int countCharacter(char ch) {
int result = 0;
for (Span span : spans) {
result += span.countCharacter(ch);
}
return result;
}
public void trimTo(int width, Span appendToLongLine) {
int i = 0;
int remaining = width;
for (i = 0; i < spans.size(); ++i) {
Span next = spans.get(i);
if (next.length() > remaining) {
++i;
next.trimTo(remaining, appendToLongLine);
break;
}
remaining -= next.length();
}
for (; i < spans.size(); ++i) {
spans.remove(i);
}
}
public void toString(StringBuilder builder) {
for (Span span : spans) {
span.toString(builder);
}
}
}
public static final class Span {
private String span;
private final String color;
public Span(String span) {
this(span, null);
}
public Span(String span, String color) {
this.span = span;
this.color = color;
}
public int length() {
return span.length();
}
public boolean isEmpty() {
return span.isEmpty();
}
public int indexOf(char ch, int start) {
return span.indexOf(ch, start);
}
public void spaceOut(int width, int start) {
int removeTo = start;
while (removeTo < span.length() && Character.isWhitespace(span.charAt(removeTo))) {
removeTo++;
}
span = span.substring(0,start) + Strings.repeat(" ", width) + span.substring(removeTo);
}
public int countCharacter(char ch) {
int result = 0;
for (int i = 0; i < span.length(); ++i) {
if (span.charAt(i) == ch) {
result++;
}
}
return result;
}
public void trimTo(int width, Span appendToLongLine) {
if (appendToLongLine != null && !appendToLongLine.isEmpty()) {
int shortten = appendToLongLine.length();
if (shortten > width) shortten = width;
span = span.substring(0, width - shortten) + appendToLongLine;
} else {
span = span.substring(0, width+1);
}
}
public String toString() {
StringBuilder builder = new StringBuilder();
toString(builder);
return builder.toString();
}
public void toString(StringBuilder builder) {
if (color != null) builder.append(color);
builder.append(span);
if (color != null) builder.append(RESET);
}
public void append(Span other) {
span = span + other.span;
}
public boolean canAppend(Span other) {
if (color == null && other == null) return true;
if (color == null && other != null) return false;
return color.equals(other);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy