1use line_buffer::{DeleteListener, Direction};
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5enum Action {
6 Kill,
7 Yank(usize),
8 Other,
9}
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum Mode {
13 Append,
14 Prepend,
15}
16
17pub struct KillRing {
18 slots: Vec<String>,
19 index: usize,
21 last_action: Action,
23 killing: bool,
24}
25
26impl KillRing {
27 pub fn new(size: usize) -> KillRing {
29 KillRing {
30 slots: Vec::with_capacity(size),
31 index: 0,
32 last_action: Action::Other,
33 killing: false,
34 }
35 }
36
37 pub fn reset(&mut self) {
39 self.last_action = Action::Other;
40 }
41
42 pub fn kill(&mut self, text: &str, dir: Mode) {
44 if let Action::Kill = self.last_action {
45 if self.slots.capacity() == 0 {
46 return;
48 }
49 match dir {
50 Mode::Append => self.slots[self.index].push_str(text),
51 Mode::Prepend => self.slots[self.index].insert_str(0, text),
52 };
53 } else {
54 self.last_action = Action::Kill;
55 if self.slots.capacity() == 0 {
56 return;
58 }
59 if self.index == self.slots.capacity() - 1 {
60 self.index = 0;
62 } else if !self.slots.is_empty() {
63 self.index += 1;
64 }
65 if self.index == self.slots.len() {
66 self.slots.push(String::from(text))
67 } else {
68 self.slots[self.index] = String::from(text);
69 }
70 }
71 }
72
73 pub fn yank(&mut self) -> Option<&String> {
76 if self.slots.is_empty() {
77 None
78 } else {
79 self.last_action = Action::Yank(self.slots[self.index].len());
80 Some(&self.slots[self.index])
81 }
82 }
83
84 pub fn yank_pop(&mut self) -> Option<(usize, &String)> {
87 match self.last_action {
88 Action::Yank(yank_size) => {
89 if self.slots.is_empty() {
90 return None;
91 }
92 if self.index == 0 {
93 self.index = self.slots.len() - 1;
94 } else {
95 self.index -= 1;
96 }
97 self.last_action = Action::Yank(self.slots[self.index].len());
98 Some((yank_size, &self.slots[self.index]))
99 }
100 _ => None,
101 }
102 }
103}
104
105impl DeleteListener for KillRing {
106 fn start_killing(&mut self) {
107 self.killing = true;
108 }
109
110 fn delete(&mut self, _: usize, string: &str, dir: Direction) {
111 if !self.killing {
112 return;
113 }
114 let mode = match dir {
115 Direction::Forward => Mode::Append,
116 Direction::Backward => Mode::Prepend,
117 };
118 self.kill(string, mode);
119 }
120
121 fn stop_killing(&mut self) {
122 self.killing = false;
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::{Action, KillRing, Mode};
129
130 #[test]
131 fn disabled() {
132 let mut kill_ring = KillRing::new(0);
133 kill_ring.kill("text", Mode::Append);
134 assert!(kill_ring.slots.is_empty());
135 assert_eq!(0, kill_ring.index);
136 assert_eq!(Action::Kill, kill_ring.last_action);
137
138 assert_eq!(None, kill_ring.yank());
139 assert_eq!(Action::Kill, kill_ring.last_action);
140 }
141
142 #[test]
143 fn one_kill() {
144 let mut kill_ring = KillRing::new(2);
145 kill_ring.kill("word1", Mode::Append);
146 assert_eq!(0, kill_ring.index);
147 assert_eq!(1, kill_ring.slots.len());
148 assert_eq!("word1", kill_ring.slots[0]);
149 assert_eq!(Action::Kill, kill_ring.last_action);
150 }
151
152 #[test]
153 fn kill_append() {
154 let mut kill_ring = KillRing::new(2);
155 kill_ring.kill("word1", Mode::Append);
156 kill_ring.kill(" word2", Mode::Append);
157 assert_eq!(0, kill_ring.index);
158 assert_eq!(1, kill_ring.slots.len());
159 assert_eq!("word1 word2", kill_ring.slots[0]);
160 assert_eq!(Action::Kill, kill_ring.last_action);
161 }
162
163 #[test]
164 fn kill_backward() {
165 let mut kill_ring = KillRing::new(2);
166 kill_ring.kill("word1", Mode::Prepend);
167 kill_ring.kill("word2 ", Mode::Prepend);
168 assert_eq!(0, kill_ring.index);
169 assert_eq!(1, kill_ring.slots.len());
170 assert_eq!("word2 word1", kill_ring.slots[0]);
171 assert_eq!(Action::Kill, kill_ring.last_action);
172 }
173
174 #[test]
175 fn kill_other_kill() {
176 let mut kill_ring = KillRing::new(2);
177 kill_ring.kill("word1", Mode::Append);
178 kill_ring.reset();
179 kill_ring.kill("word2", Mode::Append);
180 assert_eq!(1, kill_ring.index);
181 assert_eq!(2, kill_ring.slots.len());
182 assert_eq!("word1", kill_ring.slots[0]);
183 assert_eq!("word2", kill_ring.slots[1]);
184 assert_eq!(Action::Kill, kill_ring.last_action);
185 }
186
187 #[test]
188 fn many_kill() {
189 let mut kill_ring = KillRing::new(2);
190 kill_ring.kill("word1", Mode::Append);
191 kill_ring.reset();
192 kill_ring.kill("word2", Mode::Append);
193 kill_ring.reset();
194 kill_ring.kill("word3", Mode::Append);
195 kill_ring.reset();
196 kill_ring.kill("word4", Mode::Append);
197 assert_eq!(1, kill_ring.index);
198 assert_eq!(2, kill_ring.slots.len());
199 assert_eq!("word3", kill_ring.slots[0]);
200 assert_eq!("word4", kill_ring.slots[1]);
201 assert_eq!(Action::Kill, kill_ring.last_action);
202 }
203
204 #[test]
205 fn yank() {
206 let mut kill_ring = KillRing::new(2);
207 kill_ring.kill("word1", Mode::Append);
208 kill_ring.reset();
209 kill_ring.kill("word2", Mode::Append);
210
211 assert_eq!(Some(&"word2".to_owned()), kill_ring.yank());
212 assert_eq!(Action::Yank(5), kill_ring.last_action);
213 assert_eq!(Some(&"word2".to_owned()), kill_ring.yank());
214 assert_eq!(Action::Yank(5), kill_ring.last_action);
215 }
216
217 #[test]
218 fn yank_pop() {
219 let mut kill_ring = KillRing::new(2);
220 kill_ring.kill("word1", Mode::Append);
221 kill_ring.reset();
222 kill_ring.kill("longword2", Mode::Append);
223
224 assert_eq!(None, kill_ring.yank_pop());
225 kill_ring.yank();
226 assert_eq!(Some((9, &"word1".to_owned())), kill_ring.yank_pop());
227 assert_eq!(Some((5, &"longword2".to_owned())), kill_ring.yank_pop());
228 assert_eq!(Some((9, &"word1".to_owned())), kill_ring.yank_pop());
229 }
230}