IndentingPrintWriter.java revision 328ebf222167ee1d25a54fd34c8293e183303752
1a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley/* 2a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * Copyright (C) 2012 The Android Open Source Project 3a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * 4a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * Licensed under the Apache License, Version 2.0 (the "License"); 5a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * you may not use this file except in compliance with the License. 6a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * You may obtain a copy of the License at 7a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * 8a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * http://www.apache.org/licenses/LICENSE-2.0 9a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * 10a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * Unless required by applicable law or agreed to in writing, software 11a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * distributed under the License is distributed on an "AS IS" BASIS, 12a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * See the License for the specific language governing permissions and 14a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * limitations under the License. 15a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley */ 16a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley 17a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wileypackage com.android.internal.util; 18a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley 19a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wileyimport java.io.PrintWriter; 20a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wileyimport java.io.Writer; 21a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley 22a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley/** 2386105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley * Lightweight wrapper around {@link PrintWriter} that automatically indents 24a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * newlines based on internal state. It also automatically wraps long lines 25a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * based on given line length. 26a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * <p> 27217f61b2e8d2beed2fe7fa1124e1d4f52a042ab8Alex Vakulenko * Delays writing indent until first actual write on a newline, enabling indent 28217f61b2e8d2beed2fe7fa1124e1d4f52a042ab8Alex Vakulenko * modification after newline. 29a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley */ 30a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wileypublic class IndentingPrintWriter extends PrintWriter { 31af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley private final String mSingleIndent; 32a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley private final int mWrapLength; 33a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley 34af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley /** Mutable version of current indent */ 35a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley private StringBuilder mIndentBuilder = new StringBuilder(); 36a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley /** Cache of current {@link #mIndentBuilder} value */ 37af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley private char[] mCurrentIndent; 38a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley /** Length of current line being built, excluding any indent */ 39a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley private int mCurrentLength; 40a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley 41af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley /** 42a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * Flag indicating if we're currently sitting on an empty line, and that 43a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * next write should be prefixed with the current indent. 44af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley */ 45a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley private boolean mEmptyLine = true; 46af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley 47af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley public IndentingPrintWriter(Writer writer, String singleIndent) { 48af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley this(writer, singleIndent, -1); 49af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 50af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley 51a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley public IndentingPrintWriter(Writer writer, String singleIndent, int wrapLength) { 52a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley super(writer); 53af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mSingleIndent = singleIndent; 54af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mWrapLength = wrapLength; 55af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 56af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley 57a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley public void increaseIndent() { 58af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mIndentBuilder.append(mSingleIndent); 59af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mCurrentIndent = null; 60a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley } 61af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley 62a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley public void decreaseIndent() { 63af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mIndentBuilder.delete(0, mSingleIndent.length()); 64a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley mCurrentIndent = null; 65af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 66a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley 67a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley public void printPair(String key, Object value) { 68af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley print(key + "=" + String.valueOf(value) + " "); 69af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 70af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley 71af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley public void printHexPair(String key, int value) { 72af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley print(key + "=0x" + Integer.toHexString(value) + " "); 73af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 74af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley 75af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley @Override 76af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley public void write(char[] buf, int offset, int count) { 77af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley final int indentLength = mIndentBuilder.length(); 78af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley final int bufferEnd = offset + count; 79af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley int lineStart = offset; 80af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley int lineEnd = offset; 8186105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley 82af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley // March through incoming buffer looking for newlines 83a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley while (lineEnd < bufferEnd) { 84a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley char ch = buf[lineEnd++]; 85a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley mCurrentLength++; 86af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley if (ch == '\n') { 87af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley maybeWriteIndent(); 88af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley super.write(buf, lineStart, lineEnd - lineStart); 89af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley lineStart = lineEnd; 90af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mEmptyLine = true; 91af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mCurrentLength = 0; 92af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 93af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley 9486105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley // Wrap if we've pushed beyond line length 95af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley if (mWrapLength > 0 && mCurrentLength >= mWrapLength - indentLength) { 96af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley if (!mEmptyLine) { 97af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley // Give ourselves a fresh line to work with 98af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley super.write('\n'); 9986105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley mEmptyLine = true; 100af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mCurrentLength = lineEnd - lineStart; 101af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } else { 102af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley // We need more than a dedicated line, slice it hard 103af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley maybeWriteIndent(); 104a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley super.write(buf, lineStart, lineEnd - lineStart); 105a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley super.write('\n'); 106a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley mEmptyLine = true; 107a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley lineStart = lineEnd; 108af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mCurrentLength = 0; 109a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley } 110af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 111af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 112a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley 113a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley if (lineStart != lineEnd) { 114af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley maybeWriteIndent(); 115af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley super.write(buf, lineStart, lineEnd - lineStart); 116af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 117af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 118a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley 119af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley private void maybeWriteIndent() { 120af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley if (mEmptyLine) { 121af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mEmptyLine = false; 122af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley if (mIndentBuilder.length() != 0) { 123af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley if (mCurrentIndent == null) { 124af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley mCurrentIndent = mIndentBuilder.toString().toCharArray(); 125af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 12686105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley super.write(mCurrentIndent, 0, mCurrentIndent.length); 127a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley } 128a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley } 129af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley } 130af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley} 131af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley