IndentingAppendable.java revision 5d3207ac2713386ed61c6ca8f0356e8f093a62e1
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 */
16package dagger.internal.codegen.writer;
17
18import com.google.common.collect.AbstractIterator;
19import java.io.IOException;
20import java.util.Iterator;
21
22final 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