--- /dev/null 2015-04-26 06:51:08.003313989 -0700
+++ new/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java 2015-06-25 08:33:13.689391663 -0700
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Non-persistent {@link History}.
+ *
+ * @author Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @since 2.3
+ */
+public class MemoryHistory
+ implements History
+{
+ public static final int DEFAULT_MAX_SIZE = 500;
+
+ private final LinkedList items = new LinkedList();
+
+ private int maxSize = DEFAULT_MAX_SIZE;
+
+ private boolean ignoreDuplicates = true;
+
+ private boolean autoTrim = false;
+
+ // NOTE: These are all ideas from looking at the Bash man page:
+
+ // TODO: Add ignore space? (lines starting with a space are ignored)
+
+ // TODO: Add ignore patterns?
+
+ // TODO: Add history timestamp?
+
+ // TODO: Add erase dups?
+
+ private int offset = 0;
+
+ private int index = 0;
+
+ public void setMaxSize(final int maxSize) {
+ this.maxSize = maxSize;
+ maybeResize();
+ }
+
+ public int getMaxSize() {
+ return maxSize;
+ }
+
+ public boolean isIgnoreDuplicates() {
+ return ignoreDuplicates;
+ }
+
+ public void setIgnoreDuplicates(final boolean flag) {
+ this.ignoreDuplicates = flag;
+ }
+
+ public boolean isAutoTrim() {
+ return autoTrim;
+ }
+
+ public void setAutoTrim(final boolean flag) {
+ this.autoTrim = flag;
+ }
+
+ public int size() {
+ return items.size();
+ }
+
+ public boolean isEmpty() {
+ return items.isEmpty();
+ }
+
+ public int index() {
+ return offset + index;
+ }
+
+ public void clear() {
+ items.clear();
+ offset = 0;
+ index = 0;
+ }
+
+ public CharSequence get(final int index) {
+ return items.get(index - offset);
+ }
+
+ public void set(int index, CharSequence item) {
+ items.set(index - offset, item);
+ }
+
+ public void add(CharSequence item) {
+ checkNotNull(item);
+
+ if (isAutoTrim()) {
+ item = String.valueOf(item).trim();
+ }
+
+ if (isIgnoreDuplicates()) {
+ if (!items.isEmpty() && item.equals(items.getLast())) {
+ return;
+ }
+ }
+
+ internalAdd(item);
+ }
+
+ public CharSequence remove(int i) {
+ return items.remove(i);
+ }
+
+ public CharSequence removeFirst() {
+ return items.removeFirst();
+ }
+
+ public CharSequence removeLast() {
+ return items.removeLast();
+ }
+
+ protected void internalAdd(CharSequence item) {
+ items.add(item);
+
+ maybeResize();
+ }
+
+ public void replace(final CharSequence item) {
+ items.removeLast();
+ add(item);
+ }
+
+ private void maybeResize() {
+ while (size() > getMaxSize()) {
+ items.removeFirst();
+ offset++;
+ }
+
+ index = size();
+ }
+
+ public ListIterator entries(final int index) {
+ return new EntriesIterator(index - offset);
+ }
+
+ public ListIterator entries() {
+ return entries(offset);
+ }
+
+ public Iterator iterator() {
+ return entries();
+ }
+
+ private static class EntryImpl
+ implements Entry
+ {
+ private final int index;
+
+ private final CharSequence value;
+
+ public EntryImpl(int index, CharSequence value) {
+ this.index = index;
+ this.value = value;
+ }
+
+ public int index() {
+ return index;
+ }
+
+ public CharSequence value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%d: %s", index, value);
+ }
+ }
+
+ private class EntriesIterator
+ implements ListIterator
+ {
+ private final ListIterator source;
+
+ private EntriesIterator(final int index) {
+ source = items.listIterator(index);
+ }
+
+ public Entry next() {
+ if (!source.hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return new EntryImpl(offset + source.nextIndex(), source.next());
+ }
+
+ public Entry previous() {
+ if (!source.hasPrevious()) {
+ throw new NoSuchElementException();
+ }
+ return new EntryImpl(offset + source.previousIndex(), source.previous());
+ }
+
+ public int nextIndex() {
+ return offset + source.nextIndex();
+ }
+
+ public int previousIndex() {
+ return offset + source.previousIndex();
+ }
+
+ public boolean hasNext() {
+ return source.hasNext();
+ }
+
+ public boolean hasPrevious() {
+ return source.hasPrevious();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void set(final Entry entry) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void add(final Entry entry) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ //
+ // Navigation
+ //
+
+ /**
+ * This moves the history to the last entry. This entry is one position
+ * before the moveToEnd() position.
+ *
+ * @return Returns false if there were no history entries or the history
+ * index was already at the last entry.
+ */
+ public boolean moveToLast() {
+ int lastEntry = size() - 1;
+ if (lastEntry >= 0 && lastEntry != index) {
+ index = size() - 1;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move to the specified index in the history
+ * @param index
+ * @return
+ */
+ public boolean moveTo(int index) {
+ index -= offset;
+ if (index >= 0 && index < size() ) {
+ this.index = index;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Moves the history index to the first entry.
+ *
+ * @return Return false if there are no entries in the history or if the
+ * history is already at the beginning.
+ */
+ public boolean moveToFirst() {
+ if (size() > 0 && index != 0) {
+ index = 0;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move to the end of the history buffer. This will be a blank entry, after
+ * all of the other entries.
+ */
+ public void moveToEnd() {
+ index = size();
+ }
+
+ /**
+ * Return the content of the current buffer.
+ */
+ public CharSequence current() {
+ if (index >= size()) {
+ return "";
+ }
+
+ return items.get(index);
+ }
+
+ /**
+ * Move the pointer to the previous element in the buffer.
+ *
+ * @return true if we successfully went to the previous element
+ */
+ public boolean previous() {
+ if (index <= 0) {
+ return false;
+ }
+
+ index--;
+
+ return true;
+ }
+
+ /**
+ * Move the pointer to the next element in the buffer.
+ *
+ * @return true if we successfully went to the next element
+ */
+ public boolean next() {
+ if (index >= size()) {
+ return false;
+ }
+
+ index++;
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (Entry e : this) {
+ sb.append(e.toString() + "\n");
+ }
+ return sb.toString();
+ }
+}