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