mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#456 Avoiding to print multiple consecutive blank lines
This commit is contained in:
parent
37e5942c86
commit
1659a6e8e5
@ -184,7 +184,9 @@
|
|||||||
<!-- <module name="FinalClass"/> -->
|
<!-- <module name="FinalClass"/> -->
|
||||||
<module name="HideUtilityClassConstructor"/>
|
<module name="HideUtilityClassConstructor"/>
|
||||||
<module name="InterfaceIsType"/>
|
<module name="InterfaceIsType"/>
|
||||||
<module name="VisibilityModifier"/>
|
<module name="VisibilityModifier">
|
||||||
|
<property name="packageAllowed" value="true" />
|
||||||
|
</module>
|
||||||
|
|
||||||
|
|
||||||
<!-- Miscellaneous other checks. -->
|
<!-- Miscellaneous other checks. -->
|
||||||
|
@ -36,87 +36,55 @@ import java.util.Arrays;
|
|||||||
*/
|
*/
|
||||||
class IndentationCorrectingWriter extends Writer {
|
class IndentationCorrectingWriter extends Writer {
|
||||||
|
|
||||||
private enum State {
|
|
||||||
IN_TEXT, AFTER_LINE_BREAK;
|
|
||||||
|
|
||||||
State handleCharacter(char c) {
|
|
||||||
if ( this == State.IN_TEXT ) {
|
|
||||||
if ( c == '\n' || c == '\r' ) {
|
|
||||||
return State.AFTER_LINE_BREAK;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return State.IN_TEXT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( this == State.AFTER_LINE_BREAK ) {
|
|
||||||
if ( c == ' ' ) {
|
|
||||||
return State.AFTER_LINE_BREAK;
|
|
||||||
}
|
|
||||||
else if ( c == '\n' || c == '\r' ) {
|
|
||||||
return State.AFTER_LINE_BREAK;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return State.IN_TEXT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalStateException( "Unexpected state or character." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Writer delegate;
|
|
||||||
private State state = State.IN_TEXT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps track of the current indentation level, as implied by brace characters.
|
* Set to true to enable output of written characters on the console.
|
||||||
*/
|
*/
|
||||||
private int indentationLevel = 0;
|
private static final boolean DEBUG = false;
|
||||||
|
private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
|
||||||
|
private static final boolean IS_WINDOWS = System.getProperty( "os.name" ).startsWith( "Windows" );
|
||||||
|
|
||||||
|
private State currentState = State.IN_TEXT;
|
||||||
|
private final StateContext context;
|
||||||
|
|
||||||
IndentationCorrectingWriter(Writer out) {
|
IndentationCorrectingWriter(Writer out) {
|
||||||
super( out );
|
super( out );
|
||||||
this.delegate = out;
|
this.context = new StateContext( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||||
int start = off;
|
context.reset( cbuf, off );
|
||||||
int length = 0;
|
|
||||||
|
|
||||||
for ( int i = off; i < len; i++ ) {
|
for ( int i = off; i < len; i++ ) {
|
||||||
char c = cbuf[i];
|
char c = cbuf[i];
|
||||||
if ( c == '{' || c == '(' ) {
|
|
||||||
indentationLevel++;
|
State newState = currentState.handleCharacter( c, context );
|
||||||
}
|
|
||||||
else if ( c == '}' || c == ')' ) {
|
if ( newState != currentState ) {
|
||||||
indentationLevel--;
|
currentState.onExit( context );
|
||||||
|
newState.onEntry( context );
|
||||||
|
currentState = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
State newState = state.handleCharacter( c );
|
context.currentIndex++;
|
||||||
length++;
|
|
||||||
|
|
||||||
//write characters up to line-breaks
|
|
||||||
if ( state == State.IN_TEXT && newState == State.AFTER_LINE_BREAK ) {
|
|
||||||
delegate.write( cbuf, start, length );
|
|
||||||
}
|
|
||||||
//first non-whitespace character after a line break; write out the correct indentation, discarding any
|
|
||||||
//original leading whitespace characters
|
|
||||||
else if ( state == State.AFTER_LINE_BREAK && newState == State.IN_TEXT ) {
|
|
||||||
char[] indentation = getIndentation( indentationLevel );
|
|
||||||
delegate.write( indentation, 0, indentation.length );
|
|
||||||
start = i;
|
|
||||||
length = 1;
|
|
||||||
}
|
|
||||||
//write out line-breaks following directly to other line breaks
|
|
||||||
else if ( state == State.AFTER_LINE_BREAK && ( c == '\n' || c == '\r' ) ) {
|
|
||||||
delegate.write( c );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state = newState;
|
currentState.onBufferFinished( context );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( state == State.IN_TEXT ) {
|
@Override
|
||||||
delegate.write( cbuf, start, length );
|
public void flush() throws IOException {
|
||||||
|
context.writer.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
currentState.onExit( context );
|
||||||
|
context.writer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isWindows() {
|
||||||
|
return IS_WINDOWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static char[] getIndentation(int indentationLevel) {
|
private static char[] getIndentation(int indentationLevel) {
|
||||||
@ -125,13 +93,194 @@ class IndentationCorrectingWriter extends Writer {
|
|||||||
return indentation;
|
return indentation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A state of parsing a given character buffer.
|
||||||
|
*/
|
||||||
|
private enum State {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Within any text.
|
||||||
|
*/
|
||||||
|
IN_TEXT {
|
||||||
@Override
|
@Override
|
||||||
public void flush() throws IOException {
|
State doHandleCharacter(char c, StateContext context) {
|
||||||
delegate.flush();
|
switch ( c ) {
|
||||||
|
case '\r':
|
||||||
|
return isWindows() ? IN_LINE_BREAK : AFTER_LINE_BREAK;
|
||||||
|
case '\n':
|
||||||
|
return AFTER_LINE_BREAK;
|
||||||
|
default:
|
||||||
|
return IN_TEXT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out leading whitespace as per the current indentation level.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
void doOnEntry(StateContext context) throws IOException {
|
||||||
delegate.close();
|
context.writer.write( getIndentation( context.indentationLevel ) );
|
||||||
|
|
||||||
|
if ( DEBUG ) {
|
||||||
|
System.out.print( new String( getIndentation( context.indentationLevel ) ).replace( " ", "_" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out the current text.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void onExit(StateContext context) throws IOException {
|
||||||
|
flush( context );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out the current text.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void onBufferFinished(StateContext context) throws IOException {
|
||||||
|
flush( context );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flush(StateContext context) throws IOException {
|
||||||
|
context.writer.write(
|
||||||
|
context.characters,
|
||||||
|
context.lastStateChange,
|
||||||
|
context.currentIndex - context.lastStateChange
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( DEBUG ) {
|
||||||
|
System.out.print(
|
||||||
|
new String(
|
||||||
|
java.util.Arrays.copyOfRange(
|
||||||
|
context.characters,
|
||||||
|
context.lastStateChange,
|
||||||
|
context.currentIndex
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Between \r and \n of a Windows line-break.
|
||||||
|
*/
|
||||||
|
IN_LINE_BREAK {
|
||||||
|
@Override
|
||||||
|
State doHandleCharacter(char c, StateContext context) {
|
||||||
|
if ( c == '\n' ) {
|
||||||
|
return AFTER_LINE_BREAK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException( "Unexpected character: " + c );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directly after a line-break, or within leading whitespace following to a line-break.
|
||||||
|
*/
|
||||||
|
AFTER_LINE_BREAK {
|
||||||
|
@Override
|
||||||
|
State doHandleCharacter(char c, StateContext context) {
|
||||||
|
switch ( c ) {
|
||||||
|
case '\r':
|
||||||
|
return isWindows() ? IN_LINE_BREAK : AFTER_LINE_BREAK;
|
||||||
|
case ' ':
|
||||||
|
return AFTER_LINE_BREAK;
|
||||||
|
case '\n':
|
||||||
|
context.consecutiveLineBreaks++;
|
||||||
|
return AFTER_LINE_BREAK;
|
||||||
|
default:
|
||||||
|
return IN_TEXT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out the current line-breaks, avoiding more than one consecutive empty line
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void onExit(StateContext context) throws IOException {
|
||||||
|
context.consecutiveLineBreaks++;
|
||||||
|
int lineBreaks = Math.min( context.consecutiveLineBreaks, 2 );
|
||||||
|
|
||||||
|
for ( int i = 0; i < lineBreaks; i++ ) {
|
||||||
|
context.writer.append( LINE_SEPARATOR );
|
||||||
|
|
||||||
|
if ( DEBUG ) {
|
||||||
|
System.out.print( "\\n" + LINE_SEPARATOR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.consecutiveLineBreaks = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final State handleCharacter(char c, StateContext context) throws IOException {
|
||||||
|
if ( c == '{' || c == '(' ) {
|
||||||
|
context.indentationLevel++;
|
||||||
|
}
|
||||||
|
else if ( c == '}' || c == ')' ) {
|
||||||
|
context.indentationLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return doHandleCharacter( c, context );
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract State doHandleCharacter(char c, StateContext context) throws IOException;
|
||||||
|
|
||||||
|
final void onEntry(StateContext context) throws IOException {
|
||||||
|
context.lastStateChange = context.currentIndex;
|
||||||
|
doOnEntry( context );
|
||||||
|
}
|
||||||
|
|
||||||
|
void doOnEntry(StateContext context) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
void onExit(StateContext context) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBufferFinished(StateContext context) throws IOException {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps the current context of parsing the given character buffer.
|
||||||
|
*/
|
||||||
|
private static class StateContext {
|
||||||
|
final Writer writer;
|
||||||
|
|
||||||
|
char[] characters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position at which when the current state was entered.
|
||||||
|
*/
|
||||||
|
int lastStateChange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current position within the buffer.
|
||||||
|
*/
|
||||||
|
int currentIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of the current indentation level, as implied by brace characters.
|
||||||
|
*/
|
||||||
|
int indentationLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of consecutive line-breaks when within {@link State#AFTER_LINE_BREAK}.
|
||||||
|
*/
|
||||||
|
int consecutiveLineBreaks;
|
||||||
|
|
||||||
|
StateContext(Writer writer) {
|
||||||
|
this.writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(char[] characters, int off) {
|
||||||
|
this.characters = characters;
|
||||||
|
this.lastStateChange = off;
|
||||||
|
this.currentIndex = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user