public class PrettyWriter
extends java.io.Writer
This code is transcribed from pprint.lisp in Steel Bank Common Lisp, which is again based on the code in CMU Common Lisp. Modifications have been made to accommodate shared structures, as described in SRFI-38.
The pretty printer (hereafter PP) is responsible for formatting the results of evaluating expressions so that the human user can easily read them. The PP may also be responsible for choosing where to break lines so that the output looks reasonable.
Raw text that has not yet been written out is stored in the "buffer" array, while information about the structure of the text is stored in a queue of "formatting tokens" (see below) called queueInts. A circular queue is used when the PP is not dealing with shared structures, and a linear array is used when it is. This only effects how the formatting tokens are enqueued into the structure, and how the structure is dynamically expanded.
Formatting tokens are simply contiguous chunks of the queue. All tokens have
a type and a size. For example, there is a formatting token called
QITEM_NEWLINE_TYPE
whose size is specified by QITEM_NEWLINE_SIZE
. The size
includes these type and size bits. The tokens use the space allocated to them
in different ways. For example, the tab token uses two of its chunks (int
s)
to specify at which column it was entered, and to which column it should
expand to.
The tokens are buffered by a display formatter. The display formatter walks the structure to be printed emitting these tokens when it finds it has to, as well as the actual characters to be printed! Remember, the formatting tokens are distinct from the actual characters written, they just control how the characters are displayed. To accommodate this dichotomy, the character buffer holds the actual characters as they appear to the display formatter, the queue holds the formatting tokens plus a mapping that specifies which character in the buffer they end at.
Once the display formatter has finished walking the expression to be printed, the formatting queue is walked by the "destructive" methods, i.e., the ones that actually flush the buffer to the output port. As mentioned above, each token encodes the position it references in the character buffer, so we use this information to work our way through the buffer, occasionally modifying the buffer to look pretty (dictated by the formatting tokens). Examples of such modifications include changing a space character to a newline character so that the line will prettily fit on the specified line width, or more drastically, remove a shared object of the expression and replacing it will print-circle notation.
Once everything has been flushed, the initial conditions are reset ready for the next printing
Modifier and Type | Field and Description |
---|---|
char[] |
buffer
Holds all the text that has been output but not yet printed.
|
int |
bufferFillPointer
The index into BUFFER where more text should be put.
|
static ThreadLocation |
indentLoc |
static int |
initialBufferSize |
static ThreadLocation |
isSharing
Whether to resolve shared structures is dependent on the out:print-circle
command line switch being set true.
|
static ThreadLocation |
lineLengthLoc |
static ThreadLocation |
miserWidthLoc |
static int |
NEWLINE_FILL |
static int |
NEWLINE_LINEAR |
static int |
NEWLINE_LITERAL |
static int |
NEWLINE_MANDATORY |
static int |
NEWLINE_MISER |
static int |
NEWLINE_SPACE
A non-nested ' ' gets an implicit NEWLINE_SPACE.
|
protected java.io.Writer |
out |
int |
pendingBlocksCount
Number of startLogicalBlock - number of endLogicalBlock.
|
Constructor and Description |
---|
PrettyWriter(java.io.Writer out)
Construct a PrettyWriter with
prettyPrintingMode = 1 |
PrettyWriter(java.io.Writer out,
boolean prettyPrintingMode)
Construct a PrettyWriter.
|
PrettyWriter(java.io.Writer out,
int lineLength)
Construct a PrettyWriter which breaks on a given line length.
|
Modifier and Type | Method and Description |
---|---|
void |
addIndentation(int amount,
boolean current) |
void |
clearBuffer() |
void |
clearIDHash() |
void |
clearWordEnd() |
void |
close() |
void |
closeThis()
Flush and close this local Writer, but not underlying Writers.
|
void |
endLogicalBlock() |
void |
endLogicalBlock(java.lang.String suffix) |
int |
enqueue(int kind,
int size)
Enqueue a formatting token into
queueInts . |
int |
enqueueIndent(char kind,
int amount) |
void |
flush() |
void |
forcePrettyOutput() |
int |
getColumnNumber()
Get zero-origin column number, or -1 if unknown.
|
protected int |
getMiserWidth() |
int |
getPrettyPrintingMode()
Return pretty-printing mode.
|
int |
IDHashGetFromIndex(int index) |
int |
IDHashLookup(java.lang.Object obj) |
int |
IDHashPutAtIndex(java.lang.Object obj,
int value,
int index) |
int |
IDHashRemove(java.lang.Object obj) |
void |
initialiseIDHash() |
boolean |
isPrettyPrinting()
Is pretty printing enabled?
|
void |
lineAbbreviationHappened() |
void |
resolveBackReferences()
Walk through the queue, emitting print circle notation as described in
SRFI-38.
|
void |
setColumnNumber(int column) |
void |
setIndentation(int column) |
void |
setPrettyPrinting(boolean mode)
Turn pretty printing on or off.
|
void |
setPrettyPrintingMode(int mode)
Control pretty-printing mode.
|
void |
setSharing(boolean sharing) |
void |
startLogicalBlock(java.lang.String prefix,
boolean perLine,
java.lang.String suffix) |
void |
write(char[] str) |
void |
write(char[] str,
int start,
int count) |
void |
write(int ch)
Write a character to the buffer.
|
void |
write(java.lang.String str) |
void |
write(java.lang.String str,
int start,
int count)
Write a (sub)string to the output buffer.
|
void |
writeBackReference(int posn)
Enqueue a back-reference token to the formatting queue.
|
void |
writeBreak(int kind) |
void |
writeEndOfExpression() |
void |
writePairEnd(java.lang.Integer posn)
Enqueue a pair-end token to the formatting queue.
|
int |
writePositionMarker(boolean grouping)
A position marker is queued for every Scheme object that *could* refer
to itself (or other parts of the structure).
|
void |
writeWordEnd()
Note the end of a "word".
|
void |
writeWordStart()
Maybe write a word-separating space.
|
protected java.io.Writer out
public static ThreadLocation lineLengthLoc
public static ThreadLocation miserWidthLoc
public static ThreadLocation indentLoc
public static ThreadLocation isSharing
public static int initialBufferSize
public char[] buffer
public int bufferFillPointer
public int pendingBlocksCount
public static final int NEWLINE_LINEAR
public static final int NEWLINE_LITERAL
public static final int NEWLINE_FILL
public static final int NEWLINE_SPACE
public static final int NEWLINE_MISER
public static final int NEWLINE_MANDATORY
public PrettyWriter(java.io.Writer out)
prettyPrintingMode = 1
out
- The output to write toprettyPrintingMode
public PrettyWriter(java.io.Writer out, int lineLength)
lineLength
is strictly greater than one,
prettyPrintingMode
is set to 1, otherwise it's set to 0.out
- The output to write tolineLength
- The column width lines should break on#lineLength
public PrettyWriter(java.io.Writer out, boolean prettyPrintingMode)
out
- The output port to write toprettyPrintingMode
- If true
then prettyPrintingMode = 1
otherwise prettyPrintingMode = 0
public void initialiseIDHash()
public void clearIDHash()
public int IDHashLookup(java.lang.Object obj)
public int IDHashGetFromIndex(int index)
public int IDHashPutAtIndex(java.lang.Object obj, int value, int index)
public int IDHashRemove(java.lang.Object obj)
public void setPrettyPrintingMode(int mode)
mode
- the value 0 disables pretty-printing;
the value 1 enables explicit pretty-printing;
the value 2 enables pretty-printing with auto-fill, which means that
spaces are treated like enqueing NEWLINE_SPACE (essentiall a 'fill').public void setSharing(boolean sharing)
public int getPrettyPrintingMode()
setPrettyPrintingMode(int)
.public boolean isPrettyPrinting()
public void setPrettyPrinting(boolean mode)
setPrettyPrintingMode(mode?1:0)
.public void writeWordEnd()
writeWordStart()
.public void writeWordStart()
writeWordEnd()
. Otherwise, do nothing.public void clearWordEnd()
public void write(int ch)
write
in class java.io.Writer
ch
- The character to write.public void write(java.lang.String str)
write
in class java.io.Writer
public void write(java.lang.String str, int start, int count)
write
in class java.io.Writer
str
- The string to usestart
- Where to start in the stringcount
- The number of character to write from the stringpublic void write(char[] str)
write
in class java.io.Writer
public void write(char[] str, int start, int count)
write
in class java.io.Writer
public int writePositionMarker(boolean grouping)
queueInts
where this marker resides
it's used for back-reference lookup.writeBackReference(int)
public void writeBackReference(int posn)
posn
- The index in the queueInts
array of the referenced
position marker.public void writePairEnd(java.lang.Integer posn)
posn
- The index in the queueInts
array of the referenced
position marker.public void writeEndOfExpression()
public void setIndentation(int column)
public int enqueue(int kind, int size)
queueInts
.
The kind and size parameters are packed into a 32-bit integer and then stored in the
QITEM_TYPE_AND_SIZE offset of this token's computed base address. If the
queueInts
array is not big enough to hold the new token, two cases
arise. If we're not handling a shared structure, the queue is expanded, and
the old formatting tokens are moved to the high end of the queue, leaving
new space at the front. If we are handling shared structure, the queue
size is double, and we continue to enqueue items from the old queueSize.kind
- The type of formatting tokensize
- The size of this formatting tokenqueueInts
public final void writeBreak(int kind)
public int enqueueIndent(char kind, int amount)
public void addIndentation(int amount, boolean current)
public void startLogicalBlock(java.lang.String prefix, boolean perLine, java.lang.String suffix)
public void endLogicalBlock()
public void endLogicalBlock(java.lang.String suffix)
protected int getMiserWidth()
public void lineAbbreviationHappened()
public void resolveBackReferences()
public void forcePrettyOutput()
public void flush()
flush
in interface java.io.Flushable
flush
in class java.io.Writer
public void close() throws java.io.IOException
close
in interface java.io.Closeable
close
in interface java.lang.AutoCloseable
close
in class java.io.Writer
java.io.IOException
public void closeThis() throws java.io.IOException
java.io.IOException
public int getColumnNumber()
prettyPrintingMode > 0
.public void setColumnNumber(int column)
public void clearBuffer()