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        private List history = new ArrayList();
019    
020        private PrintWriter output = null;
021    
022        private int maxSize = 500;
023    
024        private int currentIndex = 0;
025    
026        /**
027         * Construstor: initialize a blank history.
028         */
029        public History() {
030        }
031    
032        /**
033         * Construstor: initialize History object the the specified {@link File} for
034         * storage.
035         */
036        public History(final File historyFile) throws IOException {
037            setHistoryFile(historyFile);
038        }
039    
040        public void setHistoryFile(final File historyFile) throws IOException {
041            if (historyFile.isFile()) {
042                load(new FileInputStream(historyFile));
043            }
044    
045            setOutput(new PrintWriter(new FileWriter(historyFile), true));
046            flushBuffer();
047        }
048    
049        /**
050         * Load the history buffer from the specified InputStream.
051         */
052        public void load(final InputStream in) throws IOException {
053            load(new InputStreamReader(in));
054        }
055    
056        /**
057         * Load the history buffer from the specified Reader.
058         */
059        public void load(final Reader reader) throws IOException {
060            BufferedReader breader = new BufferedReader(reader);
061            List lines = new ArrayList();
062            String line;
063    
064            while ((line = breader.readLine()) != null) {
065                lines.add(line);
066            }
067    
068            for (Iterator i = lines.iterator(); i.hasNext();) {
069                addToHistory((String) i.next());
070            }
071        }
072    
073        public int size() {
074            return history.size();
075        }
076    
077        /**
078         * Clear the history buffer
079         */
080        public void clear() {
081            history.clear();
082            currentIndex = 0;
083        }
084    
085        /**
086         * Add the specified buffer to the end of the history. The pointer is set to
087         * the end of the history buffer.
088         */
089        public void addToHistory(final String buffer) {
090            // don't append duplicates to the end of the buffer
091            if ((history.size() != 0)
092                    && buffer.equals(history.get(history.size() - 1))) {
093                return;
094            }
095    
096            history.add(buffer);
097    
098            while (history.size() > getMaxSize()) {
099                history.remove(0);
100            }
101    
102            currentIndex = history.size();
103    
104            if (getOutput() != null) {
105                getOutput().println(buffer);
106                getOutput().flush();
107            }
108        }
109    
110        /**
111         * Flush the entire history buffer to the output PrintWriter.
112         */
113        public void flushBuffer() throws IOException {
114            if (getOutput() != null) {
115                for (Iterator i = history.iterator(); i.hasNext(); getOutput()
116                        .println((String) i.next())) {
117                    ;
118                }
119    
120                getOutput().flush();
121            }
122        }
123    
124        /**
125         * This moves the history to the last entry. This entry is one position
126         * before the moveToEnd() position.
127         *
128         * @return Returns false if there were no history entries or the history
129         *         index was already at the last entry.
130         */
131        public boolean moveToLastEntry() {
132            int lastEntry = history.size() - 1;
133            if (lastEntry >= 0 && lastEntry != currentIndex) {
134                currentIndex = history.size() - 1;
135                return true;
136            }
137    
138            return false;
139        }
140    
141        /**
142         * Move to the end of the history buffer. This will be a blank entry, after
143         * all of the other entries.
144         */
145        public void moveToEnd() {
146            currentIndex = history.size();
147        }
148    
149        /**
150         * Set the maximum size that the history buffer will store.
151         */
152        public void setMaxSize(final int maxSize) {
153            this.maxSize = maxSize;
154        }
155    
156        /**
157         * Get the maximum size that the history buffer will store.
158         */
159        public int getMaxSize() {
160            return this.maxSize;
161        }
162    
163        /**
164         * The output to which all history elements will be written (or null of
165         * history is not saved to a buffer).
166         */
167        public void setOutput(final PrintWriter output) {
168            this.output = output;
169        }
170    
171        /**
172         * Returns the PrintWriter that is used to store history elements.
173         */
174        public PrintWriter getOutput() {
175            return this.output;
176        }
177    
178        /**
179         * Returns the current history index.
180         */
181        public int getCurrentIndex() {
182            return this.currentIndex;
183        }
184    
185        /**
186         * Return the content of the current buffer.
187         */
188        public String current() {
189            if (currentIndex >= history.size()) {
190                return "";
191            }
192    
193            return (String) history.get(currentIndex);
194        }
195    
196        /**
197         * Move the pointer to the previous element in the buffer.
198         *
199         * @return true if we successfully went to the previous element
200         */
201        public boolean previous() {
202            if (currentIndex <= 0) {
203                return false;
204            }
205    
206            currentIndex--;
207    
208            return true;
209        }
210    
211        /**
212         * Move the pointer to the next element in the buffer.
213         *
214         * @return true if we successfully went to the next element
215         */
216        public boolean next() {
217            if (currentIndex >= history.size()) {
218                return false;
219            }
220    
221            currentIndex++;
222    
223            return true;
224        }
225    
226        /**
227         * Returns an immutable list of the history buffer.
228         */
229        public List getHistoryList() {
230            return Collections.unmodifiableList(history);
231        }
232    
233        /**
234         * Returns the standard {@link AbstractCollection#toString} representation
235         * of the history list.
236         */
237        public String toString() {
238            return history.toString();
239        }
240    
241        /**
242         * Moves the history index to the first entry.
243         *
244         * @return Return false if there are no entries in the history or if the
245         *         history is already at the beginning.
246         */
247        public boolean moveToFirstEntry() {
248            if (history.size() > 0 && currentIndex != 0) {
249                currentIndex = 0;
250                return true;
251            }
252    
253            return false;
254        }
255    }