1 /* 2 * Copyright (c) 2002-2013, the original author or authors. 3 * 4 * This software is distributable under the BSD license. See the terms of the 5 * BSD license in the documentation provided with this software. 6 * 7 * http://www.opensource.org/licenses/bsd-license.php 8 */ 9 package jline.console; 10 11 /** 12 * The kill ring class keeps killed text in a fixed size ring. In this 13 * class we also keep record of whether or not the last command was a 14 * kill or a yank. Depending on this, the class may behave 15 * different. For instance, two consecutive kill-word commands fill 16 * the same slot such that the next yank will return the two 17 * previously killed words instead that only the last one. Likewise 18 * yank pop requires that the previous command was either a yank or a 19 * yank-pop. 20 */ 21 public final class KillRing { 22 23 /** 24 * Default size is 60, like in emacs. 25 */ 26 private static final int DEFAULT_SIZE = 60; 27 28 private final String[] slots; 29 private int head = 0; 30 private boolean lastKill = false; 31 private boolean lastYank = false; 32 33 /** 34 * Creates a new kill ring of the given size. 35 */ 36 public KillRing(int size) { 37 slots = new String[size]; 38 } 39 40 /** 41 * Creates a new kill ring of the default size. {@see DEFAULT_SIZE}. 42 */ 43 public KillRing() { 44 this(DEFAULT_SIZE); 45 } 46 47 /** 48 * Resets the last-yank state. 49 */ 50 public void resetLastYank() { 51 lastYank = false; 52 } 53 54 /** 55 * Resets the last-kill state. 56 */ 57 public void resetLastKill() { 58 lastKill = false; 59 } 60 61 /** 62 * Returns {@code true} if the last command was a yank. 63 */ 64 public boolean lastYank() { 65 return lastYank; 66 } 67 68 /** 69 * Adds the string to the kill-ring. Also sets lastYank to false 70 * and lastKill to true. 71 */ 72 public void add(String str) { 73 lastYank = false; 74 75 if (lastKill) { 76 if (slots[head] != null) { 77 slots[head] += str; 78 return; 79 } 80 } 81 82 lastKill = true; 83 next(); 84 slots[head] = str; 85 } 86 87 /** 88 * Adds the string to the kill-ring product of killing 89 * backwards. If the previous command was a kill text one then 90 * adds the text at the beginning of the previous kill to avoid 91 * that two consecutive backwards kills followed by a yank leaves 92 * things reversed. 93 */ 94 public void addBackwards(String str) { 95 lastYank = false; 96 97 if (lastKill) { 98 if (slots[head] != null) { 99 slots[head] = str + slots[head]; 100 return; 101 } 102 } 103 104 lastKill = true; 105 next(); 106 slots[head] = str; 107 } 108 109 /** 110 * Yanks a previously killed text. Returns {@code null} if the 111 * ring is empty. 112 */ 113 public String yank() { 114 lastKill = false; 115 lastYank = true; 116 return slots[head]; 117 } 118 119 /** 120 * Moves the pointer to the current slot back and returns the text 121 * in that position. If the previous command was not yank returns 122 * null. 123 */ 124 public String yankPop() { 125 lastKill = false; 126 if (lastYank) { 127 prev(); 128 return slots[head]; 129 } 130 return null; 131 } 132 133 /** 134 * Moves the pointer to the current slot forward. If the end of 135 * the slots is reached then points back to the beginning. 136 */ 137 private void next() { 138 if (head == 0 && slots[0] == null) { 139 return; 140 } 141 head++; 142 if (head == slots.length) { 143 head = 0; 144 } 145 } 146 147 /** 148 * Moves the pointer to the current slot backwards. If the 149 * beginning of the slots is reached then traverses the slot 150 * backwards until one with not null content is found. 151 */ 152 private void prev() { 153 head--; 154 if (head == -1) { 155 int x = (slots.length - 1); 156 for (; x >= 0; x--) { 157 if (slots[x] != null) { 158 break; 159 } 160 } 161 head = x; 162 } 163 } 164 }