001 /* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 package org.crsh.text; 021 022 import org.crsh.io.Consumer; 023 024 import java.io.IOException; 025 import java.io.Serializable; 026 import java.util.Iterator; 027 import java.util.LinkedList; 028 029 public class ChunkBuffer implements Iterable<Chunk>, Serializable, Consumer<Chunk> { 030 031 /** . */ 032 private final LinkedList<Chunk> chunks; 033 034 /** . */ 035 private Style current; 036 037 /** . */ 038 private Style next; 039 040 /** Where we flush. */ 041 private final Consumer<Chunk> out; 042 043 public ChunkBuffer() { 044 this.chunks = new LinkedList<Chunk>(); 045 this.current = Style.style(); 046 this.next = Style.style(); 047 this.out = null; 048 } 049 050 public ChunkBuffer(Consumer<Chunk> out) { 051 this.chunks = new LinkedList<Chunk>(); 052 this.current = Style.style(); 053 this.next = Style.style(); 054 this.out = out; 055 } 056 057 public Iterator<Chunk> iterator() { 058 return chunks.iterator(); 059 } 060 061 @Deprecated 062 public void writeAnsiTo(Appendable appendable) throws IOException { 063 Iterator<Chunk> iterator = iterator(); 064 while (iterator.hasNext()) { 065 Chunk chunk = iterator.next(); 066 if (chunk instanceof Text) { 067 Text text = (Text)chunk; 068 if (text.buffer.length() > 0) { 069 appendable.append(text.buffer); 070 } 071 } else if (chunk instanceof Style) { 072 ((Style)chunk).writeAnsiTo(appendable); 073 } 074 } 075 } 076 077 public ChunkBuffer append(Iterable<?> data) throws NullPointerException { 078 for (Object o : data) { 079 append(o); 080 } 081 return this; 082 } 083 084 public ChunkBuffer append(Object... data) throws NullPointerException { 085 for (Object o : data) { 086 append(o); 087 } 088 return this; 089 } 090 091 public ChunkBuffer cls() { 092 chunks.addLast(CLS.INSTANCE); 093 return this; 094 } 095 096 public ChunkBuffer append(Style style) throws NullPointerException { 097 next = next.merge(style); 098 return this; 099 } 100 101 public ChunkBuffer append(char c) { 102 last().buffer.append(c); 103 return this; 104 } 105 106 public ChunkBuffer append(CharSequence s) { 107 return append(s, 0, s.length()); 108 } 109 110 public ChunkBuffer append(CharSequence s, int start, int end) { 111 if (end > start) { 112 last().buffer.append(s, start, end); 113 } 114 return this; 115 } 116 117 private Text last() { 118 if (!next.equals(current)) { 119 if (!Style.style().equals(next)) { 120 chunks.addLast(next); 121 } 122 current = next; 123 next = Style.style(); 124 } 125 Chunk last = chunks.peekLast(); 126 if (last instanceof Text) { 127 return (Text)last; 128 } else { 129 Text text = new Text(); 130 chunks.addLast(text); 131 return text; 132 } 133 } 134 135 public Class<Chunk> getConsumedType() { 136 return Chunk.class; 137 } 138 139 public void provide(Chunk element) throws IOException { 140 append(element); 141 } 142 143 public void flush() throws IOException { 144 if (out != null) { 145 for (Chunk chunk : chunks) { 146 out.provide(chunk); 147 } 148 } 149 chunks.clear(); 150 if (out != null) { 151 out.flush(); 152 } 153 } 154 155 public ChunkBuffer append(ChunkBuffer s) throws NullPointerException { 156 for (Chunk chunk : s.chunks) { 157 write(chunk); 158 } 159 if (s.next != null && !s.next.equals(Style.style())) { 160 write(s.next); 161 } 162 return this; 163 } 164 165 public void write(Chunk chunk) throws NullPointerException { 166 if (chunk instanceof Style) { 167 append((Style)chunk); 168 } else if (chunk instanceof Text){ 169 append(((Text)chunk).buffer); 170 } else { 171 cls(); 172 } 173 } 174 175 public ChunkBuffer append(Object o) throws NullPointerException { 176 if (o == null) { 177 throw new NullPointerException("No null accepted"); 178 } 179 if (o instanceof ChunkBuffer) { 180 append((ChunkBuffer)o); 181 } else if (o instanceof Chunk) { 182 write((Chunk)o); 183 } else { 184 CharSequence s; 185 if (o instanceof CharSequence) { 186 s = (CharSequence)o; 187 } else { 188 s = o.toString(); 189 } 190 append(s); 191 } 192 return this; 193 } 194 195 public boolean contains(Object o) { 196 return toString().contains(o.toString()); 197 } 198 199 public boolean isEmpty() { 200 return chunks.isEmpty(); 201 } 202 203 public void clear() { 204 chunks.clear(); 205 } 206 207 @Override 208 public int hashCode() { 209 return toString().hashCode(); 210 } 211 212 @Override 213 public boolean equals(Object obj) { 214 if (obj == this) { 215 return true; 216 } 217 if (obj instanceof ChunkBuffer) { 218 ChunkBuffer that = (ChunkBuffer)obj; 219 return toString().equals(that.toString()); 220 } 221 return false; 222 } 223 224 @Override 225 public String toString() { 226 StringBuilder sb = new StringBuilder(); 227 for (Chunk chunk : chunks) { 228 if (chunk instanceof Text) { 229 sb.append(((Text)chunk).buffer); 230 } 231 } 232 return sb.toString(); 233 } 234 235 public void writeTo(Consumer<Chunk> writer) throws IOException { 236 for (Chunk chunk : chunks) { 237 writer.provide(chunk); 238 } 239 } 240 }