1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen.writer; 17 18 import com.google.common.collect.AbstractIterator; 19 import java.io.IOException; 20 import java.util.Iterator; 21 22 final class IndentingAppendable implements Appendable { 23 private final String indentation; 24 private final Appendable delegate; 25 private boolean requiresIndent = true; 26 27 IndentingAppendable(Appendable delegate) { 28 this(" ", delegate); 29 } 30 31 IndentingAppendable(String indentation, Appendable delegate) { 32 this.indentation = indentation; 33 this.delegate = delegate; 34 } 35 36 @Override 37 public Appendable append(CharSequence csq) throws IOException { 38 return append(csq, 0, csq.length()); 39 } 40 41 @Override 42 public Appendable append(CharSequence csq, int start, int end) throws IOException { 43 Iterator<CharSequence> lines = lines(csq, start, end); 44 while (lines.hasNext()) { 45 CharSequence line = lines.next(); 46 maybeIndent(); 47 delegate.append(line); 48 if (line.charAt(line.length() - 1) == '\n') { 49 requiresIndent = true; 50 } 51 } 52 return this; 53 } 54 55 @Override 56 public Appendable append(char c) throws IOException { 57 maybeIndent(); 58 delegate.append(c); 59 if (c == '\n') { 60 requiresIndent = true; 61 } 62 return this; 63 } 64 65 void maybeIndent() throws IOException { 66 if (requiresIndent) { 67 delegate.append(indentation); 68 } 69 requiresIndent = false; 70 } 71 72 private static Iterator<CharSequence> lines( 73 final CharSequence csq, final int start, final int end) { 74 return new AbstractIterator<CharSequence>() { 75 int index = start; 76 77 @Override protected CharSequence computeNext() { 78 int nextStart = index; 79 while (index < end && csq.charAt(index) != '\n') { 80 index++; 81 } 82 if (index < end && csq.charAt(index) == '\n') { 83 index++; 84 } 85 int nextEnd = index; 86 return nextStart >= end 87 ? endOfData() 88 : csq.subSequence(nextStart, nextEnd); 89 } 90 }; 91 } 92 } 93