001 /* 002 * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved. 003 * 004 * This software is distributable under the BSD license. See the terms of the 005 * BSD license in the documentation provided with this software. 006 */ 007 package jline; 008 009 import java.io.*; 010 import java.util.*; 011 012 /** 013 * A command history buffer. 014 * 015 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a> 016 */ 017 public class History { 018 019 private List history = new ArrayList(); 020 private PrintWriter output = null; 021 private int maxSize = 500; 022 private int currentIndex = 0; 023 024 /** 025 * Construstor: initialize a blank history. 026 */ 027 public History() { 028 } 029 030 /** 031 * Construstor: initialize History object the the specified {@link File} for 032 * storage. 033 */ 034 public History(final File historyFile) throws IOException { 035 setHistoryFile(historyFile); 036 } 037 038 public void setHistoryFile(final File historyFile) throws IOException { 039 if (historyFile.isFile()) { 040 load(new FileInputStream(historyFile)); 041 } 042 043 setOutput(new PrintWriter(new FileWriter(historyFile), true)); 044 flushBuffer(); 045 } 046 047 /** 048 * Load the history buffer from the specified InputStream. 049 */ 050 public void load(final InputStream in) throws IOException { 051 load(new InputStreamReader(in)); 052 } 053 054 /** 055 * Load the history buffer from the specified Reader. 056 */ 057 public void load(final Reader reader) throws IOException { 058 BufferedReader breader = new BufferedReader(reader); 059 List lines = new ArrayList(); 060 String line; 061 062 while ((line = breader.readLine()) != null) { 063 lines.add(line); 064 } 065 066 for (Iterator i = lines.iterator(); i.hasNext();) { 067 addToHistory((String) i.next()); 068 } 069 } 070 071 public int size() { 072 return history.size(); 073 } 074 075 /** 076 * Clear the history buffer 077 */ 078 public void clear() { 079 history.clear(); 080 currentIndex = 0; 081 } 082 083 /** 084 * Add the specified buffer to the end of the history. The pointer is set to 085 * the end of the history buffer. 086 */ 087 public void addToHistory(final String buffer) { 088 // don't append duplicates to the end of the buffer 089 if ((history.size() != 0) && buffer.equals(history.get(history.size() - 1))) { 090 return; 091 } 092 093 history.add(buffer); 094 095 while (history.size() > getMaxSize()) { 096 history.remove(0); 097 } 098 099 currentIndex = history.size(); 100 101 if (getOutput() != null) { 102 getOutput().println(buffer); 103 getOutput().flush(); 104 } 105 } 106 107 /** 108 * Flush the entire history buffer to the output PrintWriter. 109 */ 110 public void flushBuffer() throws IOException { 111 if (getOutput() != null) { 112 for (Iterator i = history.iterator(); i.hasNext(); getOutput().println((String) i.next())) { 113 ; 114 } 115 116 getOutput().flush(); 117 } 118 } 119 120 /** 121 * This moves the history to the last entry. This entry is one position 122 * before the moveToEnd() position. 123 * 124 * @return Returns false if there were no history entries or the history 125 * index was already at the last entry. 126 */ 127 public boolean moveToLastEntry() { 128 int lastEntry = history.size() - 1; 129 if (lastEntry >= 0 && lastEntry != currentIndex) { 130 currentIndex = history.size() - 1; 131 return true; 132 } 133 134 return false; 135 } 136 137 /** 138 * Move to the end of the history buffer. This will be a blank entry, after 139 * all of the other entries. 140 */ 141 public void moveToEnd() { 142 currentIndex = history.size(); 143 } 144 145 /** 146 * Set the maximum size that the history buffer will store. 147 */ 148 public void setMaxSize(final int maxSize) { 149 this.maxSize = maxSize; 150 } 151 152 /** 153 * Get the maximum size that the history buffer will store. 154 */ 155 public int getMaxSize() { 156 return this.maxSize; 157 } 158 159 /** 160 * The output to which all history elements will be written (or null of 161 * history is not saved to a buffer). 162 */ 163 public void setOutput(final PrintWriter output) { 164 this.output = output; 165 } 166 167 /** 168 * Returns the PrintWriter that is used to store history elements. 169 */ 170 public PrintWriter getOutput() { 171 return this.output; 172 } 173 174 /** 175 * Returns the current history index. 176 */ 177 public int getCurrentIndex() { 178 return this.currentIndex; 179 } 180 181 /** 182 * Return the content of the current buffer. 183 */ 184 public String current() { 185 if (currentIndex >= history.size()) { 186 return ""; 187 } 188 189 return (String) history.get(currentIndex); 190 } 191 192 /** 193 * Move the pointer to the previous element in the buffer. 194 * 195 * @return true if we successfully went to the previous element 196 */ 197 public boolean previous() { 198 if (currentIndex <= 0) { 199 return false; 200 } 201 202 currentIndex--; 203 204 return true; 205 } 206 207 /** 208 * Move the pointer to the next element in the buffer. 209 * 210 * @return true if we successfully went to the next element 211 */ 212 public boolean next() { 213 if (currentIndex >= history.size()) { 214 return false; 215 } 216 217 currentIndex++; 218 219 return true; 220 } 221 222 /** 223 * Returns an immutable list of the history buffer. 224 */ 225 public List getHistoryList() { 226 return Collections.unmodifiableList(history); 227 } 228 229 /** 230 * Returns the standard {@link AbstractCollection#toString} representation 231 * of the history list. 232 */ 233 public String toString() { 234 return history.toString(); 235 } 236 237 /** 238 * Moves the history index to the first entry. 239 * 240 * @return Return false if there are no entries in the history or if the 241 * history is already at the beginning. 242 */ 243 public boolean moveToFirstEntry() { 244 if (history.size() > 0 && currentIndex != 0) { 245 currentIndex = 0; 246 return true; 247 } 248 249 return false; 250 } 251 252 /** 253 * Search backward in history from a given position. 254 * 255 * @param searchTerm substring to search for. 256 * @param startIndex the index from which on to search 257 * @return index where this substring has been found, or -1 else. 258 */ 259 public int searchBackwards(String searchTerm, int startIndex) { 260 for (int i = startIndex - 1; i >= 0; i--) { 261 if (i >= size()) 262 continue; 263 if (getHistory(i).indexOf(searchTerm) != -1) { 264 return i; 265 } 266 } 267 return -1; 268 } 269 270 /** 271 * Search backwards in history from the current position. 272 * 273 * @param searchTerm substring to search for. 274 * @return index where the substring has been found, or -1 else. 275 */ 276 public int searchBackwards(String s) { 277 return searchBackwards(s, getCurrentIndex()); 278 } 279 280 /** 281 * Get the history string for the given index. 282 * 283 * @param index 284 * @return 285 */ 286 public String getHistory(int index) { 287 return (String) history.get(index); 288 } 289 290 /** 291 * Set current index to given number. 292 * 293 * @param index 294 */ 295 public void setCurrentIndex(int index) { 296 if (index >= 0 && index < history.size()) 297 currentIndex = index; 298 } 299 }