Skip to content

Commit

Permalink
Added IndentedStringWriter and corresponding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sangupta committed Sep 2, 2016
1 parent 3c3a999 commit f0bb250
Show file tree
Hide file tree
Showing 2 changed files with 334 additions and 0 deletions.
222 changes: 222 additions & 0 deletions src/main/java/com/sangupta/jerry/io/IndentedStringWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/**
*
* jerry - Common Java Functionality
* Copyright (c) 2012-2016, Sandeep Gupta
*
* http://sangupta.com/projects/jerry-core
*
* 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 com.sangupta.jerry.io;

import com.sangupta.jerry.util.AssertUtils;
import com.sangupta.jerry.util.StringUtils;

/**
* This class helps us write an indented string that breaks at a given length
* without the callee being concerned over the line length. The indentation level
* as well as number of characters to use for a tab are configurable.
*
* An initial space of 10240 characters is assigned as initial capacity. The
* writer can resize depending as we add more strings to it.
*
* @author sangupta
*
*/
public class IndentedStringWriter {

private final StringBuilder builder; // initialize with 10kb of character space

/**
* The line length to break at
*/
private final int lineLength;

/**
* Replace tabs to 4 spaces
*/
private final int tabLength;

/**
* The current indentation level
*/
private int indentLevel = 0;

/**
* The current pointer in the line - specifies how
* many number of characters have already been written to the line.
*/
private int currentPointer = 0;

public IndentedStringWriter() {
this(100); // default line length is 60 chars
}

public IndentedStringWriter(int lineLength) {
this(lineLength, 10 * 1024, 4);
}

public IndentedStringWriter(int lineLength, int initialCapacity, int tabLength) {
this.lineLength = lineLength;
this.tabLength = tabLength;
this.builder = new StringBuilder(initialCapacity);
}

public boolean hasContent() {
return this.builder.length() > 0;
}

public void setIndentLevel(int indentLevel) {
this.indentLevel = indentLevel;

if(this.builder.length() == 0) {
return;
}

this.newLine();
}

public void incrementIndent() {
this.indentLevel++;
this.newLine();
}

public void decrementIndent() {
this.indentLevel--;
this.newLine();
}

public void write(char ch) {
this.write(String.valueOf(ch));
}

/**
* Write the given string fragment to current line.
*
* @param str
*/
public void write(String str) {
String[] tokens = str.split("\n");
for(int index = 0; index < tokens.length; index++) {
if(index > 1) {
this.newLine();
}

this.writeInternal(tokens[index]);
}
}

private void writeInternal(String str) {
if(AssertUtils.isEmpty(str)) {
return;
}

// add indentation if needed
this.addIndentation();

// compute breakpoint
int len = str.length();
boolean breakNeeded = this.currentPointer + str.length() > this.lineLength;

// no break we can write directly
if(!breakNeeded) {
this.builder.append(str);
this.currentPointer += len;
return;
}

// add the prefix - whatever we can achieve in the remaining space
int breakPoint = this.lineLength - this.currentPointer;

// check if break point is not breaking a word
for(int index = breakPoint; index > 0; index--) {
if(Character.isWhitespace(str.charAt(index))) {
breakPoint = index;
break;
}
}

// add the prefix
String prefix = str.substring(0, breakPoint);
this.builder.append(prefix);
this.newLine();

// call recursive
if(breakPoint == 0) {
this.builder.append(str);
this.currentPointer = str.length();
return;
}
try {
this.write(StringUtils.ltrim(str.substring(breakPoint)));
} catch(StackOverflowError e) {
System.out.println("breakpoint: " + breakPoint);
System.out.println("string: " + str);
System.exit(0);
}
}

/**
* Write the given string fragment to current line and start a new line
* at the end.
*
* @param str
*/
public void writeLine(String str) {
this.write(str);
this.newLine();
}

/**
* Start a new indented line.
*
*/
public void newLine() {
this.builder.append('\n');
this.currentPointer = 0;

if(this.indentLevel == 0) {
return;
}
}

private void addIndentation() {
if(this.indentLevel <= 0 || this.currentPointer > 0) {
// no indentation needed
return;
}

int chars = this.indentLevel * this.tabLength;
if(chars == 0) {
return;
}

this.builder.append(StringUtils.repeat(' ', chars));
this.currentPointer = chars;
}

/**
* Return the current string representation.
*
*/
public String getString() {
return this.builder.toString();
}

@Override
public String toString() {
return this.getString();
}
}
112 changes: 112 additions & 0 deletions src/test/java/com/sangupta/jerry/io/TestIndentedStringWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
*
* jerry - Common Java Functionality
* Copyright (c) 2012-2016, Sandeep Gupta
*
* http://sangupta.com/projects/jerry-core
*
* 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 com.sangupta.jerry.io;

import org.junit.Assert;
import org.junit.Test;

/**
* Unit tests for {@link IndentedStringWriter}.
*
* @author sangupta
*
*/
public class TestIndentedStringWriter {

@Test
public void testSimple() {
IndentedStringWriter writer = new IndentedStringWriter();

Assert.assertNotNull(writer.getString());
Assert.assertEquals("", writer.getString());

writer.write("hello");
Assert.assertEquals("hello", writer.getString());
writer.write(" world");
Assert.assertEquals("hello world", writer.getString());
writer.newLine();
writer.write("hello");
Assert.assertEquals("hello world\nhello", writer.getString());
writer.writeLine(" world");
Assert.assertEquals("hello world\nhello world\n", writer.getString());
}

@Test
public void testIndentation() {
IndentedStringWriter writer = new IndentedStringWriter();
writer.setIndentLevel(1);

Assert.assertNotNull(writer.getString());
Assert.assertEquals("", writer.getString());

writer.write("hello");
Assert.assertEquals(" hello", writer.getString());

writer.setIndentLevel(0);
writer.write("world");
Assert.assertEquals(" hello\nworld", writer.getString());
}

@Test
public void testTabSpaces() {
IndentedStringWriter writer = new IndentedStringWriter();
writer.setIndentLevel(1);

Assert.assertNotNull(writer.getString());
Assert.assertEquals("", writer.getString());

writer.write("hello");
Assert.assertEquals(" hello", writer.getString());

writer.setIndentLevel(2);
writer.write("world");
Assert.assertEquals(" hello\n world", writer.getString());

// change tab spaces to 2
writer = new IndentedStringWriter(60, 1024, 2);
writer.setIndentLevel(1);

Assert.assertNotNull(writer.getString());
Assert.assertEquals("", writer.getString());

writer.write("hello");
Assert.assertEquals(" hello", writer.getString());

writer.setIndentLevel(2);
writer.write("world");
Assert.assertEquals(" hello\n world", writer.getString());

// change tab spaces to 0
writer = new IndentedStringWriter(60, 1024, 0);
writer.setIndentLevel(1);

Assert.assertNotNull(writer.getString());
Assert.assertEquals("", writer.getString());

writer.write("hello");
Assert.assertEquals("hello", writer.getString());

writer.setIndentLevel(2);
writer.write("world");
Assert.assertEquals("hello\nworld", writer.getString());
}
}

0 comments on commit f0bb250

Please sign in to comment.