001    /*
002     * Copyright 2010-2013 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.jet.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        private 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 {
075                append(indent);
076            }
077            printWithNoIndent(objects);
078    
079            return this;
080        }
081    
082        @NotNull
083        public Printer printWithNoIndent(Object... objects) {
084            for (Object object : objects) {
085                blankLineCountIncludingCurrent = 0;
086                append(object);
087            }
088    
089            return this;
090        }
091    
092        @NotNull
093        public Printer withholdIndentOnce() {
094            withholdIndentOnce = true;
095            return this;
096        }
097    
098        @NotNull
099        public Printer printlnWithNoIndent(Object... objects) {
100            printWithNoIndent(objects);
101            printLineSeparator();
102    
103            return this;
104        }
105    
106        @NotNull
107        public Printer pushIndent() {
108            indent += INDENTATION_UNIT;
109    
110            return this;
111        }
112    
113        @NotNull
114        public Printer popIndent() {
115            if (indent.length() < INDENTATION_UNIT.length()) {
116                throw new IllegalStateException("No indentation to pop");
117            }
118    
119            indent = indent.substring(INDENTATION_UNIT.length());
120    
121            return this;
122        }
123    
124        @NotNull
125        public Printer separated(Object separator, Object... items) {
126            for (int i = 0; i < items.length; i++) {
127                if (i > 0) {
128                    printlnWithNoIndent(separator);
129                }
130                printlnWithNoIndent(items[i]);
131            }
132            return this;
133        }
134    
135        @NotNull
136        public Printer separated(Object separator, Collection<?> items) {
137            for (Iterator<?> iterator = items.iterator(); iterator.hasNext(); ) {
138                printlnWithNoIndent(iterator.next());
139                if (iterator.hasNext()) {
140                    printlnWithNoIndent(separator);
141                }
142            }
143            return this;
144        }
145    }