Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.spongepowered.asm.util.PrettyPrinter Maven / Gradle / Ivy
Go to download
Fabric Mixin is a trait/mixin and bytecode weaving framework for Java using ASM.
/*
* This file is part of Mixin, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.spongepowered.asm.util;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.spongepowered.asm.logging.ILogger;
import org.spongepowered.asm.logging.Level;
import org.spongepowered.asm.service.MixinService;
import com.google.common.base.Strings;
/**
* Prints information in a pretty box
*/
public class PrettyPrinter {
/**
* Interface for object which supports printing to pretty printer
*/
public interface IPrettyPrintable {
/**
* Append this objec to specified pretty printer
*
* @param printer printer to append to
*/
public abstract void print(PrettyPrinter printer);
}
/**
* Interface for objects which need their width calculated prior to printing
*/
interface IVariableWidthEntry {
public abstract int getWidth();
}
/**
* Interface for objects which control their own output format
*/
interface ISpecialEntry {
}
/**
* A key/value pair for convenient printing
*/
class KeyValue implements PrettyPrinter.IVariableWidthEntry {
private final String key;
private final Object value;
public KeyValue(String key, Object value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return String.format(PrettyPrinter.this.kvFormat, this.key, this.value);
}
@Override
public int getWidth() {
return this.toString().length();
}
}
/**
* Horizontal rule
*/
class HorizontalRule implements PrettyPrinter.ISpecialEntry {
private final char[] hrChars;
public HorizontalRule(char... hrChars) {
this.hrChars = hrChars;
}
@Override
public String toString() {
return Strings.repeat(new String(this.hrChars), PrettyPrinter.this.width + 2);
}
}
/**
* Centred text
*/
class CentredText {
private final Object centred;
public CentredText(Object centred) {
this.centred = centred;
}
@Override
public String toString() {
String text = this.centred.toString();
return String.format("%" + (((PrettyPrinter.this.width - (text.length())) / 2) + text.length()) + "s", text);
}
}
/**
* Table column alignment
*/
public static enum Alignment {
LEFT,
RIGHT
}
/**
* Table information, added to output in order to print header
*/
static class Table implements PrettyPrinter.IVariableWidthEntry {
final List columns = new ArrayList();
final List rows = new ArrayList();
String format = "%s";
int colSpacing = 2;
boolean addHeader = true;
void headerAdded() {
this.addHeader = false;
}
void setColSpacing(int spacing) {
this.colSpacing = Math.max(0, spacing);
this.updateFormat();
}
Table grow(int size) {
while (this.columns.size() < size) {
this.columns.add(new Column(this));
}
this.updateFormat();
return this;
}
Column add(Column column) {
this.columns.add(column);
return column;
}
Row add(Row row) {
this.rows.add(row);
return row;
}
Column addColumn(String title) {
return this.add(new Column(this, title));
}
Column addColumn(Alignment align, int size, String title) {
return this.add(new Column(this, align, size, title));
}
Row addRow(Object... args) {
return this.add(new Row(this, args));
}
void updateFormat() {
String spacing = Strings.repeat(" ", this.colSpacing);
StringBuilder format = new StringBuilder();
boolean addSpacing = false;
for (Column column : this.columns) {
if (addSpacing) {
format.append(spacing);
}
addSpacing = true;
format.append(column.getFormat());
}
this.format = format.toString();
}
String getFormat() {
return this.format;
}
Object[] getTitles() {
List titles = new ArrayList();
for (Column column : this.columns) {
titles.add(column.getTitle());
}
return titles.toArray();
}
@Override
public String toString() {
boolean nonEmpty = false;
String[] titles = new String[this.columns.size()];
for (int col = 0; col < this.columns.size(); col++) {
titles[col] = this.columns.get(col).toString();
nonEmpty |= !titles[col].isEmpty();
}
return nonEmpty ? String.format(this.format, (Object[])titles) : null;
}
@Override
public int getWidth() {
String str = this.toString();
return str != null ? str.length() : 0;
}
}
/**
* Table column, internal
*/
static class Column {
private final Table table;
private Alignment align = Alignment.LEFT;
private int minWidth = 1;
private int maxWidth = Integer.MAX_VALUE;
private int size = 0;
private String title = "";
private String format = "%s";
Column(Table table) {
this.table = table;
}
Column(Table table, String title) {
this(table);
this.title = title;
this.minWidth = title.length();
this.updateFormat();
}
Column(Table table, Alignment align, int size, String title) {
this(table, title);
this.align = align;
this.size = size;
}
void setAlignment(Alignment align) {
this.align = align;
this.updateFormat();
}
void setWidth(int width) {
if (width > this.size) {
this.size = width;
this.updateFormat();
}
}
void setMinWidth(int width) {
if (width > this.minWidth) {
this.minWidth = width;
this.updateFormat();
}
}
void setMaxWidth(int width) {
this.size = Math.min(this.size, this.maxWidth);
this.maxWidth = Math.max(1, width);
this.updateFormat();
}
void setTitle(String title) {
this.title = title;
this.setWidth(title.length());
}
private void updateFormat() {
int width = Math.min(this.maxWidth, this.size == 0 ? this.minWidth : this.size);
this.format = "%" + (this.align == Alignment.RIGHT ? "" : "-") + width + "s";
this.table.updateFormat();
}
int getMaxWidth() {
return this.maxWidth;
}
String getTitle() {
return this.title;
}
String getFormat() {
return this.format;
}
@Override
public String toString() {
if (this.title.length() > this.maxWidth) {
return this.title.substring(0, this.maxWidth);
}
return this.title;
}
}
/**
* Table row, internal
*/
static class Row implements PrettyPrinter.IVariableWidthEntry {
final Table table;
final String[] args;
public Row(Table table, Object... args) {
this.table = table.grow(args.length);
this.args = new String[args.length];
for (int i = 0; i < args.length; i++) {
this.args[i] = args[i].toString();
this.table.columns.get(i).setMinWidth(this.args[i].length());
}
}
@Override
public String toString() {
Object[] args = new Object[this.table.columns.size()];
for (int col = 0; col < args.length; col++) {
Column column = this.table.columns.get(col);
if (col >= this.args.length) {
args[col] = "";
} else {
args[col] = (this.args[col].length() > column.getMaxWidth()) ? this.args[col].substring(0, column.getMaxWidth()) : this.args[col];
}
}
return String.format(this.table.format, args);
}
@Override
public int getWidth() {
return this.toString().length();
}
}
/**
* Minimum allowed width
*/
private static final int MIN_WIDTH = 40;
/**
* Horizontal rule
*/
private final HorizontalRule horizontalRule = new HorizontalRule('*');
/**
* Content lines
*/
private final List lines = new ArrayList();
/**
* Table
*/
private Table table;
/**
* True when a variable-width entry is added whose width must be calculated
* on print
*/
private boolean recalcWidth = false;
/**
* Box with (adapts to contents)
*/
protected int width = 100;
/**
* Wrap width used when an explicit wrap width is not specified
*/
protected int wrapWidth = 80;
/**
* Key/value key width
*/
protected int kvKeyWidth = 10;
protected String kvFormat = PrettyPrinter.makeKvFormat(this.kvKeyWidth);
public PrettyPrinter() {
this(100);
}
public PrettyPrinter(int width) {
this.width = Math.max(PrettyPrinter.MIN_WIDTH, width);
this.wrapWidth = this.width - 20;
}
/**
* Set the wrap width (default 80 columns)
*
* @param wrapWidth new width (in characters) to wrap to
* @return fluent interface
*/
public PrettyPrinter wrapTo(int wrapWidth) {
this.wrapWidth = wrapWidth;
return this;
}
/**
* Get the current wrap width
*
* @return the current wrap width
*/
public int wrapTo() {
return this.wrapWidth;
}
/**
* Begin a new table with no header and adaptive column widths
*
* @return fluent interface
*/
public PrettyPrinter table() {
this.table = new Table();
return this;
}
/**
* Begin a new table with the specified headers and adaptive column widths
*
* @param titles Column titles
* @return fluent interface
*/
public PrettyPrinter table(String... titles) {
this.table = new Table();
for (String title : titles) {
this.table.addColumn(title);
}
return this;
}
/**
* Begin a new table with the specified format. The format is specified as a
* sequence of values with {@link String}s defining column titles,
* {@link Integer}s defining column widths, and {@link Alignment}s defining
* column alignments. Widths and alignment specifiers should follow the
* relevant column title. Specify a negative value to specify the
* maximum width for a column (values will be truncated).
*
* For example, to specify a table with two columns of width 10:
*
* printer.table("Column 1", 10, "Column 2", 10);
*
* A table with a column 30 characters wide and a right-aligned column 20
* characters wide:
*
* printer.table("Column 1", 30, "Column 2", 20, Alignment.RIGHT);
*
*
* @param format format string, see description
* @return fluent interface
*/
public PrettyPrinter table(Object... format) {
this.table = new Table();
Column column = null;
for (Object entry : format) {
if (entry instanceof String) {
column = this.table.addColumn((String)entry);
} else if (entry instanceof Integer && column != null) {
int width = ((Integer)entry).intValue();
if (width > 0) {
column.setWidth(width);
} else if (width < 0) {
column.setMaxWidth(-width);
}
} else if (entry instanceof Alignment && column != null) {
column.setAlignment((Alignment)entry);
} else if (entry != null) {
column = this.table.addColumn(entry.toString());
}
}
return this;
}
/**
* Set the column spacing for the current table. Default = 2
*
* @param spacing Column spacing in characters
* @return fluent interface
*/
public PrettyPrinter spacing(int spacing) {
if (this.table == null) {
this.table = new Table();
}
this.table.setColSpacing(spacing);
return this;
}
/**
* Print the current table header. The table header is automatically printed
* before the first row if not explicitly specified by calling this method.
*
* @return fluent interface
*/
public PrettyPrinter th() {
return this.th(false);
}
private PrettyPrinter th(boolean onlyIfNeeded) {
if (this.table == null) {
this.table = new Table();
}
if (!onlyIfNeeded || this.table.addHeader) {
this.table.headerAdded();
this.addLine(this.table);
}
return this;
}
/**
* Print a table row with the specified values. If more columns are
* specified than exist in the table, then the table is automatically
* expanded.
*
* @param args column values
* @return fluent interface
*/
public PrettyPrinter tr(Object... args) {
this.th(true);
this.addLine(this.table.addRow(args));
this.recalcWidth = true;
return this;
}
/**
* Adds a blank line to the output
*
* @return fluent interface
*/
public PrettyPrinter add() {
this.addLine("");
return this;
}
/**
* Adds a string line to the output
*
* @param string format string
* @return fluent interface
*/
public PrettyPrinter add(String string) {
this.addLine(string);
this.width = Math.max(this.width, string.length());
return this;
}
/**
* Adds a formatted line to the output
*
* @param format format string
* @param args arguments
*
* @return fluent interface
*/
public PrettyPrinter add(String format, Object... args) {
String line = String.format(format, args);
this.addLine(line);
this.width = Math.max(this.width, line.length());
return this;
}
/**
* Add elements of the array to the output, one per line
*
* @param array Array of objects to print
* @return fluent interface
*/
public PrettyPrinter add(Object[] array) {
return this.add(array, "%s");
}
/**
* Add elements of the array to the output, one per line
*
* @param array Array of objects to print
* @param format Format for each row
* @return fluent interface
*/
public PrettyPrinter add(Object[] array, String format) {
for (Object element : array) {
this.add(format, element);
}
return this;
}
/**
* Add elements of the array to the output, one per line, with array indices
*
* @param array Array of objects to print
* @return fluent interface
*/
public PrettyPrinter addIndexed(Object[] array) {
int indexWidth = String.valueOf(array.length - 1).length();
String format = "[%" + indexWidth + "d] %s";
for (int index = 0; index < array.length; index++) {
this.add(format, index, array[index]);
}
return this;
}
/**
* Add elements of the collection to the output, one per line, with indices
*
* @param c Collection of objects to print
* @return fluent interface
*/
public PrettyPrinter addWithIndices(Collection> c) {
return this.addIndexed(c.toArray());
}
/**
* Adds a pretty-printable object to the output, the object is responsible
* for adding its own representation to this printer
*
* @param printable object to add
* @return fluent interface
*/
public PrettyPrinter add(IPrettyPrintable printable) {
if (printable != null) {
printable.print(this);
}
return this;
}
/**
* Print a formatted representation of the specified throwable with the
* default indent (4)
*
* @param th Throwable to print
* @return fluent interface
*/
public PrettyPrinter add(Throwable th) {
return this.add(th, 4);
}
/**
* Print a formatted representation of the specified throwable with the
* specified indent
*
* @param th Throwable to print
* @param indent Indent size for stacktrace lines
* @return fluent interface
*/
public PrettyPrinter add(Throwable th, int indent) {
while (th != null) {
this.addWrapped(" %s: %s", th.getClass().getName(), th.getMessage());
this.add(th.getStackTrace(), indent);
th = th.getCause();
}
return this;
}
/**
* Print a formatted representation of the specified stack trace with the
* specified indent
*
* @param stackTrace stack trace to print
* @param indent Indent size for stacktrace lines
* @return fluent interface
*/
public PrettyPrinter add(StackTraceElement[] stackTrace, int indent) {
String margin = Strings.repeat(" ", indent);
for (StackTraceElement st : stackTrace) {
this.add("%s%s", margin, st);
}
return this;
}
/**
* Adds the specified object to the output
*
* @param object object to add
* @return fluent interface
*/
public PrettyPrinter add(Object object) {
return this.add(object, 0);
}
/**
* Adds the specified object to the output
*
* @param object object to add
* @param indent indent amount
* @return fluent interface
*/
public PrettyPrinter add(Object object, int indent) {
String margin = Strings.repeat(" ", indent);
return this.append(object, indent, margin);
}
private PrettyPrinter append(Object object, int indent, String margin) {
if (object instanceof String) {
return this.add("%s%s", margin, object);
} else if (object instanceof Iterable) {
for (Object entry : (Iterable>)object) {
this.append(entry, indent, margin);
}
return this;
} else if (object instanceof Map) {
this.kvWidth(indent);
return this.add((Map, ?>)object);
} else if (object instanceof IPrettyPrintable) {
return this.add((IPrettyPrintable)object);
} else if (object instanceof Throwable) {
return this.add((Throwable)object, indent);
} else if (object.getClass().isArray()) {
return this.add((Object[])object, indent + "%s");
}
return this.add("%s%s", margin, object);
}
/**
* Adds a formatted line to the output, and attempts to wrap the line
* content to the current wrap width
*
* @param format format string
* @param args arguments
*
* @return fluent interface
*/
public PrettyPrinter addWrapped(String format, Object... args) {
return this.addWrapped(this.wrapWidth, format, args);
}
/**
* Adds a formatted line to the output, and attempts to wrap the line
* content to the specified width
*
* @param width wrap width to use for this content
* @param format format string
* @param args arguments
*
* @return fluent interface
*/
public PrettyPrinter addWrapped(int width, String format, Object... args) {
String indent = "";
String line = String.format(format, args).replace("\t", " ");
Matcher indentMatcher = Pattern.compile("^(\\s+)[^\\s]").matcher(line);
if (indentMatcher.find()) {
indent = indentMatcher.group(1);
}
try {
for (String wrappedLine : this.getWrapped(width, line, indent)) {
this.add(wrappedLine);
}
} catch (Exception ex) {
this.add(line);
}
return this;
}
private List getWrapped(int width, String line, String indent) {
List lines = new ArrayList();
while (line.length() > width) {
int wrapPoint = PrettyPrinter.lastBreakIndex(line, width);
if (wrapPoint < 10) {
wrapPoint = width;
}
String head = line.substring(0, wrapPoint);
lines.add(head);
line = indent + line.substring(wrapPoint + 1);
}
if (line.length() > 0) {
lines.add(line);
}
return lines;
}
private static int lastBreakIndex(String line, int width) {
int lineBreakPos = line.lastIndexOf('\n', width);
return lineBreakPos > -1 ? lineBreakPos : Math.max(line.lastIndexOf(' ', width), line.lastIndexOf('\t', width));
}
/**
* Add a formatted key/value pair to the output
*
* @param key Key
* @param format Value format
* @param args Value args
* @return fluent interface
*/
public PrettyPrinter kv(String key, String format, Object... args) {
return this.kv(key, String.format(format, args));
}
/**
* Add a key/value pair to the output
*
* @param key Key
* @param value Value
* @return fluent interface
*/
public PrettyPrinter kv(String key, Object value) {
this.addLine(new KeyValue(key, value));
return this.kvWidth(key.length());
}
/**
* Set the minimum key display width
*
* @param width width to set
* @return fluent
*/
public PrettyPrinter kvWidth(int width) {
if (width > this.kvKeyWidth) {
this.kvKeyWidth = width;
this.kvFormat = PrettyPrinter.makeKvFormat(width);
}
this.recalcWidth = true;
return this;
}
/**
* Add all values of the specified map to this printer as key/value pairs
*
* @param map Map with entries to add
* @return fluent
*/
public PrettyPrinter add(Map, ?> map) {
for (Map.Entry, ?> entry : map.entrySet()) {
String key = entry.getKey() == null ? "null" : entry.getKey().toString();
this.kv(key, entry.getValue());
}
return this;
}
/**
* Adds a horizontal rule to the output
*
* @return fluent interface
*/
public PrettyPrinter hr() {
return this.hr('*');
}
/**
* Adds a horizontal rule of the specified char to the output
*
* @param ruleChar character to use for the horizontal rule
* @return fluent interface
*/
public PrettyPrinter hr(char ruleChar) {
this.addLine(new HorizontalRule(ruleChar));
return this;
}
/**
* Centre the last line added
*
* @return fluent interface
*/
public PrettyPrinter centre() {
if (!this.lines.isEmpty()) {
Object lastLine = this.lines.get(this.lines.size() - 1);
if (lastLine instanceof String) {
this.addLine(new CentredText(this.lines.remove(this.lines.size() - 1)));
}
}
return this;
}
private void addLine(Object line) {
if (line == null) {
return;
}
this.lines.add(line);
this.recalcWidth |= line instanceof PrettyPrinter.IVariableWidthEntry;
}
/**
* Outputs this printer to stderr and to a logger decorated with the calling
* class name with level {@link Level#DEBUG}
*
* @return fluent interface
*/
public PrettyPrinter trace() {
return this.trace(PrettyPrinter.getDefaultLoggerName());
}
/**
* Outputs this printer to stderr and to a logger decorated with the calling
* class name at the specified level
*
* @param level Log level to write messages
* @return fluent interface
*/
public PrettyPrinter trace(Level level) {
return this.trace(PrettyPrinter.getDefaultLoggerName(), level);
}
/**
* Outputs this printer to stderr and to a logger decorated with specified
* name with level {@link Level#DEBUG}
*
* @param logger Logger name to write to
* @return fluent interface
*/
public PrettyPrinter trace(String logger) {
return this.trace(System.err, MixinService.getService().getLogger(logger));
}
/**
* Outputs this printer to stderr and to a logger decorated with specified
* name with the specified level
*
* @param logger Logger name to write to
* @param level Log level to write messages
* @return fluent interface
*/
public PrettyPrinter trace(String logger, Level level) {
return this.trace(System.err, MixinService.getService().getLogger(logger), level);
}
/**
* Outputs this printer to stderr and to the supplied logger with level
* {@link Level#DEBUG}
*
* @param logger Logger to write to
* @return fluent interface
*/
public PrettyPrinter trace(ILogger logger) {
return this.trace(System.err, logger);
}
/**
* Outputs this printer to stderr and to the supplied logger with the
* specified level
*
* @param logger Logger to write to
* @param level Log level to write messages
* @return fluent interface
*/
public PrettyPrinter trace(ILogger logger, Level level) {
return this.trace(System.err, logger, level);
}
/**
* Outputs this printer to the specified stream and to a logger decorated
* with the calling class name with level {@link Level#DEBUG}
*
* @param stream Output stream to print to
* @return fluent interface
*/
public PrettyPrinter trace(PrintStream stream) {
return this.trace(stream, PrettyPrinter.getDefaultLoggerName());
}
/**
* Outputs this printer to the specified stream and to a logger decorated
* with the calling class name with the specified level
*
* @param stream Output stream to print to
* @param level Log level to write messages
* @return fluent interface
*/
public PrettyPrinter trace(PrintStream stream, Level level) {
return this.trace(stream, PrettyPrinter.getDefaultLoggerName(), level);
}
/**
* Outputs this printer to the specified stream and to a logger with the
* specified name with level {@link Level#DEBUG}
*
* @param stream Output stream to print to
* @param logger Logger name to write to
* @return fluent interface
*/
public PrettyPrinter trace(PrintStream stream, String logger) {
return this.trace(stream, MixinService.getService().getLogger(logger));
}
/**
* Outputs this printer to the specified stream and to a logger with the
* specified name at the specified level
*
* @param stream Output stream to print to
* @param logger Logger name to write to
* @param level Log level to write messages
* @return fluent interface
*/
public PrettyPrinter trace(PrintStream stream, String logger, Level level) {
return this.trace(stream, MixinService.getService().getLogger(logger), level);
}
/**
* Outputs this printer to the specified stream and to the supplied logger
* with level {@link Level#DEBUG}
*
* @param stream Output stream to print to
* @param logger Logger to write to
* @return fluent interface
*/
public PrettyPrinter trace(PrintStream stream, ILogger logger) {
return this.trace(stream, logger, Level.DEBUG);
}
/**
* Outputs this printer to the specified stream and to the supplied logger
* with at the specified level
*
* @param stream Output stream to print to
* @param logger Logger to write to
* @param level Log level to write messages
* @return fluent interface
*/
public PrettyPrinter trace(PrintStream stream, ILogger logger, Level level) {
this.log(logger, level);
this.print(stream);
return this;
}
/**
* Print this printer to stderr
*
* @return fluent interface
*/
public PrettyPrinter print() {
return this.print(System.err);
}
/**
* Print this printer to the specified output
*
* @param stream stream to print to
* @return fluent interface
*/
public PrettyPrinter print(PrintStream stream) {
this.updateWidth();
this.printSpecial(stream, this.horizontalRule);
for (Object line : this.lines) {
if (line instanceof ISpecialEntry) {
this.printSpecial(stream, (ISpecialEntry)line);
} else {
this.printString(stream, line.toString());
}
}
this.printSpecial(stream, this.horizontalRule);
return this;
}
private void printSpecial(PrintStream stream, ISpecialEntry line) {
stream.printf("/*%s*/\n", line.toString());
}
private void printString(PrintStream stream, String string) {
if (string != null) {
stream.printf("/* %-" + this.width + "s */\n", string);
}
}
/**
* Write this printer to the specified logger at {@link Level#INFO}
*
* @param logger logger to log to
* @return fluent interface
*/
public PrettyPrinter log(ILogger logger) {
return this.log(logger, Level.INFO);
}
/**
* Write this printer to the specified logger at {@link Level#INFO}
*
* @param level log level
* @return fluent interface
*/
public PrettyPrinter log(Level level) {
return this.log(MixinService.getService().getLogger(PrettyPrinter.getDefaultLoggerName()), level);
}
/**
* Write this printer to the specified logger
*
* @param logger logger to log to
* @param level log level
* @return fluent interface
*/
public PrettyPrinter log(ILogger logger, Level level) {
this.updateWidth();
this.logSpecial(logger, level, this.horizontalRule);
for (Object line : this.lines) {
if (line instanceof ISpecialEntry) {
this.logSpecial(logger, level, (ISpecialEntry)line);
} else {
this.logString(logger, level, line.toString());
}
}
this.logSpecial(logger, level, this.horizontalRule);
return this;
}
private void logSpecial(ILogger logger, Level level, ISpecialEntry line) {
logger.log(level, "/*{}*/", line.toString());
}
private void logString(ILogger logger, Level level, String line) {
if (line != null) {
logger.log(level, "/* {} */", String.format("%-" + this.width + "s", line));
}
}
private void updateWidth() {
if (this.recalcWidth) {
this.recalcWidth = false;
for (Object line : this.lines) {
if (line instanceof IVariableWidthEntry) {
this.width = Math.min(4096, Math.max(this.width, ((IVariableWidthEntry)line).getWidth()));
}
}
}
}
private static String makeKvFormat(int keyWidth) {
return String.format("%%%ds : %%s", keyWidth);
}
private static String getDefaultLoggerName() {
String name = new Throwable().getStackTrace()[2].getClassName();
int pos = name.lastIndexOf('.');
return pos == -1 ? name : name.substring(pos + 1);
}
/**
* Convenience method, alternative to using Thread.dumpStack which
* prints to stderr in pretty-printed format.
*/
public static void dumpStack() {
new PrettyPrinter().add(new Exception("Stack trace")).print(System.err);
}
/**
* Convenience methods, pretty-prints the specified throwable to stderr
*
* @param th Throwable to log
*/
public static void print(Throwable th) {
new PrettyPrinter().add(th).print(System.err);
}
}