From 6f1f3667182e8aba42bb102c071f4631ed042eed Mon Sep 17 00:00:00 2001 From: "Benjamin J. Culkin" Date: Thu, 6 Sep 2018 13:19:23 -0300 Subject: Add ReportWriter Added ReportWriter, which is a writer with support for several things that make printing formal reports easier, like autoindenting support and number of lines written/current character position in the line. It also has support for automatically converting tabs to spaces. --- .../main/java/bjc/utils/ioutils/ReportWriter.java | 217 +++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 base/src/main/java/bjc/utils/ioutils/ReportWriter.java (limited to 'base/src') diff --git a/base/src/main/java/bjc/utils/ioutils/ReportWriter.java b/base/src/main/java/bjc/utils/ioutils/ReportWriter.java new file mode 100644 index 0000000..704ec10 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/ReportWriter.java @@ -0,0 +1,217 @@ +package bjc.utils.ioutils; + +import java.io.IOException; +import java.io.Writer; + +public class ReportWriter extends Writer { + private Writer contained; + + // @TODO Ben Culkin :IndentStr 9/5/18 + // + // I can think of several ways I might want to extend/change this, but + // no good ways to implement them come to mind. + // + // The main one is for things like bulleted lists, where at each level + // you want to use a different indent string. + + // # of character positions indentStr occupies + private int indentStrPos; + private int indentLevel; + private String indentStr; + // Indent string w/ tabs converted to spaces + private String indentStrSpacedTabs; + + // # of char. positions to the tab + private int tabEqv = 8; + private int linesWritten = 0; + private int linePos = 0; + + private boolean printTabsAsSpaces; + + private boolean lastCharWasNL; + private char lastChar; + + // Really wish java had public `readonly` properties. I wouldn't even + // care if that was a restriction that was only enforced by the compiler + public int getLevel() { + return indentLevel; + } + + public String getString() { + return indentStr; + } + + public int getTabEqv() { + return tabEqv; + } + + public int getLinesWritter() { + return linesWritten; + } + + public int getLinePos() { + return linePos; + } + + public char getLastChar() { + return lastChar; + } + + public boolean isLastCharNL() { + return lastCharWasNL; + } + + public boolean isPrintingTabsAsSpaces() { + return printTabsAsSpaces; + } + + public void setPrintTabsAsSpaces(boolean tabsAsSpaces) { + printTabsAsSpaces = tabsAsSpaces; + + // Recalculate indentStrSpacedTabs + setString(indentStr); + } + + public void setLevel(int level) { + indentLevel = level; + } + + public void setTabEqv(int eqv) { + tabEqv = eqv; + + // Recalculate position count of indentStr + setString(indentStr); + } + + // @NOTE 9/5/18 + // + // Weirdness may occur if the indent string has a + // newline in it, since that newline won't be considered + // to exist by the indentWriter + public void setString(String str) { + indentStr = str; + + indentStrPos = 0; + StringBuilder conv = new StringBuilder(); + + for(int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if(c == '\t') { + for(int j = 0; j < tabEqv; j++) { + conv.append(' '); + } + + indentStrPos += tabEqv; + } else { + conv.append(c); + } + + indentStrPos += 1; + } + } + + public ReportWriter(Writer write) { + this(write, 0, "\t"); + } + + public ReportWriter(Writer write, int level, String str) { + super(); + + contained = write; + + indentLevel = level; + + setString(str); + } + + public void indent(int lvl) { + indentLevel += lvl; + } + + public void indent() { + indent(1); + } + + public void dedent(int lvl) { + // @NOTE 9/5/18 + // + // Perhaps there should be an exception if we try to dedent to + // many times? + indentLevel = Math.max(0, indentLevel - lvl); + } + + public void dedent() { + dedent(1); + } + + public void write(char[] cbuf, int off, int len) throws IOException { + String actIndentStr = printTabsAsSpaces ? indentStrSpacedTabs : indentStr; + + // Skip empty writes + if(len == 0) return; + + // Last character was a new line, print the indent string + if(lastCharWasNL) { + lastCharWasNL = false; + + for(int i = 0; i < indentLevel; i++) { + contained.write(actIndentStr); + } + + linePos += indentStrPos; + } + + for(int i = 0; i < len; i++) { + int idx = i + off; + + char c = cbuf[off]; + + if(c == '\n' || c == '\r') { + // Count lines written + if(c == '\r') linesWritten++; + if(c == '\n' && lastChar != '\r') linesWritten++; + + lastCharWasNL = true; + + contained.write(c); + + linePos = 0; + } else { + // @CopyPaste from above. + // + // No real point in pulling it out to a method + // yet, but if :IndentStr happens, it might + // warrant it. + if(lastCharWasNL) { + lastCharWasNL = false; + + for(int j = 0; j < indentLevel; j++) { + contained.write(actIndentStr); + linePos += indentStrPos; + } + } + + if(c == '\t') { + linePos += tabEqv; + + for(int j = 0; j < tabEqv; j++) { + contained.write(' '); + } + } else { + linePos += 1; + contained.write(c); + } + } + + lastChar = c; + } + } + + public void flush() throws IOException { + contained.flush(); + } + + public void close() throws IOException { + contained.close(); + } +} -- cgit v1.2.3