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 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 int blankLineCountIncludingCurrent = 0;
034        private boolean withholdIndentOnce = false;
035    
036        public Printer(@NotNull Appendable out) {
037            this(out, Integer.MAX_VALUE);
038        }
039    
040        public Printer(@NotNull Appendable out, int maxBlankLines) {
041            this.out = out;
042            this.maxBlankLines = maxBlankLines;
043        }
044    
045        private void append(Object o) {
046            try {
047                out.append(o.toString());
048            }
049            catch (IOException e) {
050                // Do nothing
051            }
052        }
053    
054        @NotNull
055        public Printer println(Object... objects) {
056            print(objects);
057            printLineSeparator();
058    
059            return this;
060        }
061    
062        private void printLineSeparator() {
063            if (blankLineCountIncludingCurrent <= maxBlankLines) {
064                blankLineCountIncludingCurrent++;
065                append(LINE_SEPARATOR);
066            }
067        }
068    
069        @NotNull
070        public Printer print(Object... objects) {
071            if (withholdIndentOnce) {
072                withholdIndentOnce = false;
073            }
074            else if (objects.length > 0) {
075                printIndent();
076            }
077            printWithNoIndent(objects);
078    
079            return this;
080        }
081    
082        public void printIndent() {
083            append(indent);
084        }
085    
086        @NotNull
087        public Printer printWithNoIndent(Object... objects) {
088            for (Object object : objects) {
089                blankLineCountIncludingCurrent = 0;
090                append(object);
091            }
092    
093            return this;
094        }
095    
096        @NotNull
097        public Printer withholdIndentOnce() {
098            withholdIndentOnce = true;
099            return this;
100        }
101    
102        @NotNull
103        public Printer printlnWithNoIndent(Object... objects) {
104            printWithNoIndent(objects);
105            printLineSeparator();
106    
107            return this;
108        }
109    
110        @NotNull
111        public Printer pushIndent() {
112            indent += INDENTATION_UNIT;
113    
114            return this;
115        }
116    
117        @NotNull
118        public Printer popIndent() {
119            if (indent.length() < INDENTATION_UNIT.length()) {
120                throw new IllegalStateException("No indentation to pop");
121            }
122    
123            indent = indent.substring(INDENTATION_UNIT.length());
124    
125            return this;
126        }
127    
128        @NotNull
129        public Printer separated(Object separator, Object... items) {
130            for (int i = 0; i < items.length; i++) {
131                if (i > 0) {
132                    printlnWithNoIndent(separator);
133                }
134                printlnWithNoIndent(items[i]);
135            }
136            return this;
137        }
138    
139        @NotNull
140        public Printer separated(Object separator, Collection<?> items) {
141            for (Iterator<?> iterator = items.iterator(); iterator.hasNext(); ) {
142                printlnWithNoIndent(iterator.next());
143                if (iterator.hasNext()) {
144                    printlnWithNoIndent(separator);
145                }
146            }
147            return this;
148        }
149    }