jline.console.KillRing Maven / Gradle / Ivy
/*
* Copyright (c) 2002-2016, 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 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 {@link #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;
}
}
}