All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.stringtemplate.v4.AutoIndentWriter Maven / Gradle / Ivy

There is a newer version: 2.12.15
Show newest version
/*
 * [The "BSD license"]
 *  Copyright (c) 2011 Terence Parr
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.stringtemplate.v4;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * Essentially a char filter that knows how to auto-indent output by maintaining
 * a stack of indent levels.
 * 

* The indent stack is a stack of strings so we can repeat original indent not * just the same number of columns (don't have to worry about tabs vs spaces * then). Anchors are char positions (tabs won't work) that indicate where all * future wraps should justify to. The wrap position is actually the larger of * either the last anchor or the indentation level.

*

* This is a filter on a {@link Writer}.

*

* {@code \n} is the proper way to say newline for options and templates. * Templates can mix {@code \r\n} and {@code \n} them, but use {@code \n} in * options like {@code wrap="\n"}. This writer will render newline characters * according to {@link #newline}. The default value is taken from the * {@code line.separator} system property, and can be overridden by passing in a * {@code String} to the appropriate constructor.

*/ public class AutoIndentWriter implements STWriter { /** Stack of indents. Use {@link List} as it's much faster than {@link Stack}. Grows * from 0..n-1. */ public List indents = new ArrayList(); /** Stack of integer anchors (char positions in line); avoid {@link Integer} * creation overhead. */ public int[] anchors = new int[10]; public int anchors_sp = -1; /** {@code \n} or {@code \r\n}? */ public String newline; public Writer out = null; public boolean atStartOfLine = true; /** * Track char position in the line (later we can think about tabs). Indexed * from 0. We want to keep {@code charPosition <= }{@link #lineWidth}. * This is the position we are about to write, not the position * last written to. */ public int charPosition = 0; /** The absolute char index into the output of the next char to be written. */ public int charIndex = 0; public int lineWidth = NO_WRAP; public AutoIndentWriter(Writer out, String newline) { this.out = out; indents.add(null); // s oftart with no indent this.newline = newline; } public AutoIndentWriter(Writer out) { this(out, System.getProperty("line.separator")); } @Override public void setLineWidth(int lineWidth) { this.lineWidth = lineWidth; } @Override public void pushIndentation(String indent) { indents.add(indent); } @Override public String popIndentation() { return indents.remove(indents.size()-1); } @Override public void pushAnchorPoint() { if ( (anchors_sp +1)>=anchors.length ) { int[] a = new int[anchors.length*2]; System.arraycopy(anchors, 0, a, 0, anchors.length-1); anchors = a; } anchors_sp++; anchors[anchors_sp] = charPosition; } @Override public void popAnchorPoint() { anchors_sp--; } @Override public int index() { return charIndex; } /** Write out a string literal or attribute expression or expression element. */ @Override public int write(String str) throws IOException { int n = 0; int nll = newline.length(); int sl = str.length(); for (int i=0; i * If doing line wrap, then check {@code wrap} before emitting {@code str}. * If at or beyond desired line width then emit a {@link #newline} and any * indentation before spitting out {@code str}.

*/ @Override public int write(String str, String wrap) throws IOException { int n = writeWrap(wrap); return n + write(str); } @Override public int writeWrap(String wrap) throws IOException { int n = 0; // if want wrap and not already at start of line (last char was \n) // and we have hit or exceeded the threshold if ( lineWidth!=NO_WRAP && wrap!=null && !atStartOfLine && charPosition >= lineWidth ) { // ok to wrap // Walk wrap string and look for A\nB. Spit out A\n // then spit indent or anchor, whichever is larger // then spit out B. for (int i=0; i=0 && anchors[anchors_sp]>indentWidth ) { int remainder = anchors[anchors_sp]-indentWidth; for (int i=1; i<=remainder; i++) out.write(' '); n += remainder; } charPosition += n; charIndex += n; return n; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy