--- /dev/null 2015-04-26 06:51:08.003313989 -0700 +++ new/jdk/src/jdk.jline/share/classes/jdk/internal/jline/console/KillRing.java 2015-06-18 03:04:38.163616842 -0700 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2002-2013, 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; + +/** + * The kill ring class keeps killed text in a fixed size ring. In this + * class we also keep record of whether or not the last command was a + * kill or a yank. Depending on this, the class may behave + * different. For instance, two consecutive kill-word commands fill + * the same slot such that the next yank will return the two + * previously killed words instead that only the last one. Likewise + * yank pop requires that the previous command was either a yank or a + * yank-pop. + */ +public final class KillRing { + + /** + * Default size is 60, like in emacs. + */ + private static final int DEFAULT_SIZE = 60; + + private final String[] slots; + private int head = 0; + private boolean lastKill = false; + private boolean lastYank = false; + + /** + * Creates a new kill ring of the given size. + */ + public KillRing(int size) { + slots = new String[size]; + } + + /** + * Creates a new kill ring of the default size. {@see DEFAULT_SIZE}. + */ + public KillRing() { + this(DEFAULT_SIZE); + } + + /** + * Resets the last-yank state. + */ + public void resetLastYank() { + lastYank = false; + } + + /** + * Resets the last-kill state. + */ + public void resetLastKill() { + lastKill = false; + } + + /** + * Returns {@code true} if the last command was a yank. + */ + public boolean lastYank() { + return lastYank; + } + + /** + * Adds the string to the kill-ring. Also sets lastYank to false + * and lastKill to true. + */ + public void add(String str) { + lastYank = false; + + if (lastKill) { + if (slots[head] != null) { + slots[head] += str; + return; + } + } + + lastKill = true; + next(); + slots[head] = str; + } + + /** + * Adds the string to the kill-ring product of killing + * backwards. If the previous command was a kill text one then + * adds the text at the beginning of the previous kill to avoid + * that two consecutive backwards kills followed by a yank leaves + * things reversed. + */ + public void addBackwards(String str) { + lastYank = false; + + if (lastKill) { + if (slots[head] != null) { + slots[head] = str + slots[head]; + return; + } + } + + lastKill = true; + next(); + slots[head] = str; + } + + /** + * Yanks a previously killed text. Returns {@code null} if the + * ring is empty. + */ + public String yank() { + lastKill = false; + lastYank = true; + return slots[head]; + } + + /** + * Moves the pointer to the current slot back and returns the text + * in that position. If the previous command was not yank returns + * null. + */ + public String yankPop() { + lastKill = false; + if (lastYank) { + prev(); + return slots[head]; + } + return null; + } + + /** + * Moves the pointer to the current slot forward. If the end of + * the slots is reached then points back to the beginning. + */ + private void next() { + if (head == 0 && slots[0] == null) { + return; + } + head++; + if (head == slots.length) { + head = 0; + } + } + + /** + * Moves the pointer to the current slot backwards. If the + * beginning of the slots is reached then traverses the slot + * backwards until one with not null content is found. + */ + private void prev() { + head--; + if (head == -1) { + int x = (slots.length - 1); + for (; x >= 0; x--) { + if (slots[x] != null) { + break; + } + } + head = x; + } + } +}