1 /* 2 * Copyright 2021 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 android.app.appsearch.util; 18 19 import android.annotation.NonNull; 20 21 /** 22 * Utility for building indented strings. 23 * 24 * <p>This is a wrapper for {@link StringBuilder} for appending strings with indentation. The 25 * indentation level can be increased by calling {@link #increaseIndentLevel()} and decreased by 26 * calling {@link #decreaseIndentLevel()}. 27 * 28 * <p>Indentation is applied after each newline character for the given indent level. 29 * 30 * @hide 31 */ 32 public class IndentingStringBuilder { 33 private final StringBuilder mStringBuilder = new StringBuilder(); 34 35 // Indicates whether next non-newline character should have an indent applied before it. 36 private boolean mIndentNext = false; 37 private int mIndentLevel = 0; 38 39 /** Increases the indent level by one for appended strings. */ 40 @NonNull increaseIndentLevel()41 public IndentingStringBuilder increaseIndentLevel() { 42 mIndentLevel++; 43 return this; 44 } 45 46 /** Decreases the indent level by one for appended strings. */ 47 @NonNull decreaseIndentLevel()48 public IndentingStringBuilder decreaseIndentLevel() throws IllegalStateException { 49 if (mIndentLevel == 0) { 50 throw new IllegalStateException("Cannot set indent level below 0."); 51 } 52 mIndentLevel--; 53 return this; 54 } 55 56 /** 57 * Appends provided {@code String} at the current indentation level. 58 * 59 * <p>Indentation is applied after each newline character. 60 */ 61 @NonNull append(@onNull String str)62 public IndentingStringBuilder append(@NonNull String str) { 63 applyIndentToString(str); 64 return this; 65 } 66 67 /** 68 * Appends provided {@code Object}, represented as a {@code String}, at the current indentation 69 * level. 70 * 71 * <p>Indentation is applied after each newline character. 72 */ 73 @NonNull append(@onNull Object obj)74 public IndentingStringBuilder append(@NonNull Object obj) { 75 applyIndentToString(obj.toString()); 76 return this; 77 } 78 79 @Override 80 @NonNull toString()81 public String toString() { 82 return mStringBuilder.toString(); 83 } 84 85 /** Adds indent string to the {@link StringBuilder} instance for current indent level. */ applyIndent()86 private void applyIndent() { 87 for (int i = 0; i < mIndentLevel; i++) { 88 mStringBuilder.append(" "); 89 } 90 } 91 92 /** 93 * Applies indent, for current indent level, after each newline character. 94 * 95 * <p>Consecutive newline characters are not indented. 96 */ applyIndentToString(@onNull String str)97 private void applyIndentToString(@NonNull String str) { 98 int index = str.indexOf("\n"); 99 if (index == 0) { 100 // String begins with new line character: append newline and slide past newline. 101 mStringBuilder.append("\n"); 102 mIndentNext = true; 103 if (str.length() > 1) { 104 applyIndentToString(str.substring(index + 1)); 105 } 106 } else if (index >= 1) { 107 // String contains new line character: divide string between newline, append new line, 108 // and recurse on each string. 109 String beforeIndentString = str.substring(0, index); 110 applyIndentToString(beforeIndentString); 111 mStringBuilder.append("\n"); 112 mIndentNext = true; 113 if (str.length() > index + 1) { 114 String afterIndentString = str.substring(index + 1); 115 applyIndentToString(afterIndentString); 116 } 117 } else { 118 // String does not contain newline character: append string. 119 if (mIndentNext) { 120 applyIndent(); 121 mIndentNext = false; 122 } 123 mStringBuilder.append(str); 124 } 125 } 126 } 127