1 /* |
|
2 * Copyright (c) 2002-2016, 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 jdk.internal.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 {@link #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 } |
|