Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed1ad7fa authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Add wrapping support to IndentingPrintWriter."

parents 75d880df 71cb446f
Loading
Loading
Loading
Loading
+59 −18
Original line number Diff line number Diff line
@@ -21,29 +21,47 @@ import java.io.Writer;

/**
 * Lightweight wrapper around {@link PrintWriter} that automatically indents
 * newlines based on internal state. Delays writing indent until first actual
 * write on a newline, enabling indent modification after newline.
 * newlines based on internal state. It also automatically wraps long lines
 * based on given line length.
 * <p>
 * Delays writing indent until first actual write on a newline, enabling indent
 * modification after newline.
 */
public class IndentingPrintWriter extends PrintWriter {
    private final String mIndent;
    private final String mSingleIndent;
    private final int mWrapLength;

    private StringBuilder mBuilder = new StringBuilder();
    private char[] mCurrent;
    /** Mutable version of current indent */
    private StringBuilder mIndentBuilder = new StringBuilder();
    /** Cache of current {@link #mIndentBuilder} value */
    private char[] mCurrentIndent;
    /** Length of current line being built, excluding any indent */
    private int mCurrentLength;

    /**
     * Flag indicating if we're currently sitting on an empty line, and that
     * next write should be prefixed with the current indent.
     */
    private boolean mEmptyLine = true;

    public IndentingPrintWriter(Writer writer, String indent) {
    public IndentingPrintWriter(Writer writer, String singleIndent) {
        this(writer, singleIndent, -1);
    }

    public IndentingPrintWriter(Writer writer, String singleIndent, int wrapLength) {
        super(writer);
        mIndent = indent;
        mSingleIndent = singleIndent;
        mWrapLength = wrapLength;
    }

    public void increaseIndent() {
        mBuilder.append(mIndent);
        mCurrent = null;
        mIndentBuilder.append(mSingleIndent);
        mCurrentIndent = null;
    }

    public void decreaseIndent() {
        mBuilder.delete(0, mIndent.length());
        mCurrent = null;
        mIndentBuilder.delete(0, mSingleIndent.length());
        mCurrentIndent = null;
    }

    public void printPair(String key, Object value) {
@@ -52,33 +70,56 @@ public class IndentingPrintWriter extends PrintWriter {

    @Override
    public void write(char[] buf, int offset, int count) {
        final int indentLength = mIndentBuilder.length();
        final int bufferEnd = offset + count;
        int lineStart = offset;
        int lineEnd = offset;

        // March through incoming buffer looking for newlines
        while (lineEnd < bufferEnd) {
            char ch = buf[lineEnd++];
            mCurrentLength++;
            if (ch == '\n') {
                writeIndent();
                maybeWriteIndent();
                super.write(buf, lineStart, lineEnd - lineStart);
                lineStart = lineEnd;
                mEmptyLine = true;
                mCurrentLength = 0;
            }

            // Wrap if we've pushed beyond line length
            if (mWrapLength > 0 && mCurrentLength >= mWrapLength - indentLength) {
                if (!mEmptyLine) {
                    // Give ourselves a fresh line to work with
                    super.write('\n');
                    mEmptyLine = true;
                    mCurrentLength = lineEnd - lineStart;
                } else {
                    // We need more than a dedicated line, slice it hard
                    maybeWriteIndent();
                    super.write(buf, lineStart, lineEnd - lineStart);
                    super.write('\n');
                    mEmptyLine = true;
                    lineStart = lineEnd;
                    mCurrentLength = 0;
                }
            }
        }

        if (lineStart != lineEnd) {
            writeIndent();
            maybeWriteIndent();
            super.write(buf, lineStart, lineEnd - lineStart);
        }
    }

    private void writeIndent() {
    private void maybeWriteIndent() {
        if (mEmptyLine) {
            mEmptyLine = false;
            if (mBuilder.length() != 0) {
                if (mCurrent == null) {
                    mCurrent = mBuilder.toString().toCharArray();
            if (mIndentBuilder.length() != 0) {
                if (mCurrentIndent == null) {
                    mCurrentIndent = mIndentBuilder.toString().toCharArray();
                }
                super.write(mCurrent, 0, mCurrent.length);
                super.write(mCurrentIndent, 0, mCurrentIndent.length);
            }
        }
    }
+132 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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.android.internal.util;

import junit.framework.TestCase;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;

/**
 * Tests for {@link IndentingPrintWriter}.
 */
public class IndentingPrintWriterTest extends TestCase {

    private ByteArrayOutputStream mStream;
    private PrintWriter mWriter;

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        mStream = new ByteArrayOutputStream();
        mWriter = new PrintWriter(mStream);
    }

    public void testMultipleIndents() throws Exception {
        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ");

        pw.print("Hello");
        pw.increaseIndent();
        pw.println();
        pw.print("World");
        pw.increaseIndent();
        pw.println();
        pw.print("And");
        pw.decreaseIndent();
        pw.println();
        pw.print("Goodbye");
        pw.decreaseIndent();
        pw.println();
        pw.print("World");
        pw.println();

        pw.flush();
        assertEquals("Hello\n  World\n    And\n  Goodbye\nWorld\n", mStream.toString());
    }

    public void testAdjustIndentAfterNewline() throws Exception {
        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ");

        pw.println("Hello");
        pw.increaseIndent();
        pw.println("World");

        pw.flush();
        assertEquals("Hello\n  World\n", mStream.toString());
    }

    public void testWrapping() throws Exception {
        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "", 10);

        pw.print("dog ");
        pw.print("cat ");
        pw.print("cow ");
        pw.print("meow ");

        pw.flush();
        assertEquals("dog cat \ncow meow ", mStream.toString());
    }

    public void testWrappingIndented() throws Exception {
        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "    ", 10);

        pw.increaseIndent();
        pw.print("dog ");
        pw.print("meow ");
        pw.print("a ");
        pw.print("b ");
        pw.print("cow ");

        pw.flush();
        assertEquals("    dog \n    meow \n    a b \n    cow ", mStream.toString());
    }

    public void testWrappingEmbeddedNewlines() throws Exception {
        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ", 10);

        pw.increaseIndent();
        pw.print("Lorem ipsum \ndolor sit \namet, consectetur \nadipiscing elit.");

        pw.flush();
        assertEquals("  Lorem ip\n  sum \n  dolor si\n  t \n  amet, co\n"
                + "  nsectetu\n  r \n  adipisci\n  ng elit.\n", mStream.toString());
    }

    public void testWrappingSingleGiant() throws Exception {
        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ", 10);

        pw.increaseIndent();
        pw.print("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        pw.flush();
        assertEquals("  Lorem ip\n  sum dolo\n  r sit am\n  et, cons\n"
                + "  ectetur \n  adipisci\n  ng elit.\n", mStream.toString());
    }

    public void testWrappingPrefixedGiant() throws Exception {
        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ", 10);

        pw.increaseIndent();
        pw.print("foo");
        pw.print("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        pw.flush();
        assertEquals("  foo\n  Lorem ip\n  sum dolo\n  r sit am\n  et, cons\n"
                + "  ectetur \n  adipisci\n  ng elit.\n", mStream.toString());
    }
}