001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.utils;
018    
019    import org.jetbrains.annotations.NotNull;
020    
021    import java.io.IOException;
022    import java.util.Collection;
023    import java.util.Iterator;
024    
025    public class Printer {
026        private static final String DEFAULT_INDENTATION_UNIT = "    ";
027        private static final String LINE_SEPARATOR = System.getProperty("line.separator");
028    
029        protected final Appendable out;
030        private final int maxBlankLines;
031    
032        private String indent = "";
033        private final String indentUnit;
034        private int blankLineCountIncludingCurrent = 0;
035        private boolean withholdIndentOnce = false;
036    
037        public Printer(@NotNull Appendable out) {
038            this(out, Integer.MAX_VALUE);
039        }
040    
041        public Printer(@NotNull Appendable out, @NotNull String indentUnit) {
042            this(out, Integer.MAX_VALUE, indentUnit);
043        }
044    
045        public Printer(@NotNull Appendable out, int maxBlankLines) {
046            this(out, maxBlankLines, DEFAULT_INDENTATION_UNIT);
047        }
048    
049        public Printer(@NotNull Appendable out, int maxBlankLines, @NotNull String indentUnit) {
050            this.out = out;
051            this.maxBlankLines = maxBlankLines;
052            this.indentUnit = indentUnit;
053        }
054    
055        private void append(Object o) {
056            try {
057                out.append(o.toString());
058            }
059            catch (IOException e) {
060                // Do nothing
061            }
062        }
063    
064        @NotNull
065        public Printer println(Object... objects) {
066            print(objects);
067            printLineSeparator();
068    
069            return this;
070        }
071    
072        private void printLineSeparator() {
073            if (blankLineCountIncludingCurrent <= maxBlankLines) {
074                blankLineCountIncludingCurrent++;
075                append(LINE_SEPARATOR);
076            }
077        }
078    
079        @NotNull
080        public Printer print(Object... objects) {
081            if (withholdIndentOnce) {
082                withholdIndentOnce = false;
083            }
084            else if (objects.length > 0) {
085                printIndent();
086            }
087            printWithNoIndent(objects);
088    
089            return this;
090        }
091    
092        public void printIndent() {
093            append(indent);
094        }
095    
096        @NotNull
097        public Printer printWithNoIndent(Object... objects) {
098            for (Object object : objects) {
099                blankLineCountIncludingCurrent = 0;
100                append(object);
101            }
102    
103            return this;
104        }
105    
106        @NotNull
107        public Printer withholdIndentOnce() {
108            withholdIndentOnce = true;
109            return this;
110        }
111    
112        @NotNull
113        public Printer printlnWithNoIndent(Object... objects) {
114            printWithNoIndent(objects);
115            printLineSeparator();
116    
117            return this;
118        }
119    
120        @NotNull
121        public Printer pushIndent() {
122            indent += indentUnit;
123    
124            return this;
125        }
126    
127        @NotNull
128        public Printer popIndent() {
129            if (indent.length() < indentUnit.length()) {
130                throw new IllegalStateException("No indentation to pop");
131            }
132    
133            indent = indent.substring(indentUnit.length());
134    
135            return this;
136        }
137    
138        @NotNull
139        public Printer separated(Object separator, Object... items) {
140            for (int i = 0; i < items.length; i++) {
141                if (i > 0) {
142                    printlnWithNoIndent(separator);
143                }
144                printlnWithNoIndent(items[i]);
145            }
146            return this;
147        }
148    
149        @NotNull
150        public Printer separated(Object separator, Collection<?> items) {
151            for (Iterator<?> iterator = items.iterator(); iterator.hasNext(); ) {
152                printlnWithNoIndent(iterator.next());
153                if (iterator.hasNext()) {
154                    printlnWithNoIndent(separator);
155                }
156            }
157            return this;
158        }
159    }