1use std::collections::VecDeque;
9
10const MAX_KILL_RING_SIZE: usize = 64;
12
13#[derive(Debug, Clone)]
15pub struct PushOptions {
16 pub prepend: bool,
18 pub accumulate: bool,
20}
21
22impl Default for PushOptions {
23 fn default() -> Self {
24 Self {
25 prepend: false,
26 accumulate: false,
27 }
28 }
29}
30
31#[derive(Debug, Clone)]
33pub struct KillRing {
34 entries: VecDeque<String>,
36 max_size: usize,
38}
39
40impl KillRing {
41 pub fn new() -> Self {
43 Self {
44 entries: VecDeque::with_capacity(MAX_KILL_RING_SIZE),
45 max_size: MAX_KILL_RING_SIZE,
46 }
47 }
48
49 pub fn with_max_size(max_size: usize) -> Self {
51 Self {
52 entries: VecDeque::with_capacity(max_size),
53 max_size,
54 }
55 }
56
57 pub fn push(&mut self, text: &str, options: PushOptions) {
59 if text.is_empty() {
60 return;
61 }
62
63 if options.accumulate && !self.entries.is_empty() {
64 if options.prepend {
66 let front = self.entries.front_mut().unwrap();
67 *front = format!("{}{}", text, front);
68 } else {
69 let front = self.entries.front_mut().unwrap();
70 *front = format!("{}{}", front, text);
71 }
72 } else {
73 if self.entries.front() != Some(&text.to_string()) {
76 self.entries.push_front(text.to_string());
77
78 while self.entries.len() > self.max_size {
80 self.entries.pop_back();
81 }
82 }
83 }
84 }
85
86 pub fn peek(&self) -> Option<&str> {
88 self.entries.front().map(|s| s.as_str())
89 }
90
91 pub fn len(&self) -> usize {
93 self.entries.len()
94 }
95
96 pub fn is_empty(&self) -> bool {
98 self.entries.is_empty()
99 }
100
101 pub fn rotate(&mut self) {
104 if self.entries.len() > 1 {
105 if let Some(front) = self.entries.pop_front() {
106 self.entries.push_back(front);
107 }
108 }
109 }
110
111 pub fn rotate_back(&mut self) {
113 if self.entries.len() > 1 {
114 if let Some(back) = self.entries.pop_back() {
115 self.entries.push_front(back);
116 }
117 }
118 }
119
120 pub fn clear(&mut self) {
122 self.entries.clear();
123 }
124
125 pub fn entries(&self) -> impl Iterator<Item = &String> {
127 self.entries.iter()
128 }
129
130 pub fn get(&self, index: usize) -> Option<&str> {
132 self.entries.get(index).map(|s| s.as_str())
133 }
134}
135
136impl Default for KillRing {
137 fn default() -> Self {
138 Self::new()
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_push_and_peek() {
148 let mut ring = KillRing::new();
149 ring.push("hello", PushOptions::default());
150 assert_eq!(ring.peek(), Some("hello"));
151 assert_eq!(ring.len(), 1);
152 }
153
154 #[test]
155 fn test_accumulate() {
156 let mut ring = KillRing::new();
157 ring.push("hello", PushOptions::default());
158 ring.push(
159 " world",
160 PushOptions {
161 prepend: false,
162 accumulate: true,
163 },
164 );
165 assert_eq!(ring.peek(), Some("hello world"));
166 assert_eq!(ring.len(), 1);
167 }
168
169 #[test]
170 fn test_accumulate_prepend() {
171 let mut ring = KillRing::new();
172 ring.push("world", PushOptions::default());
173 ring.push(
174 "hello ",
175 PushOptions {
176 prepend: true,
177 accumulate: true,
178 },
179 );
180 assert_eq!(ring.peek(), Some("hello world"));
181 }
182
183 #[test]
184 fn test_rotate() {
185 let mut ring = KillRing::new();
186 ring.push("first", PushOptions::default());
187 ring.push("second", PushOptions::default());
188 ring.push("third", PushOptions::default());
189
190 assert_eq!(ring.peek(), Some("third"));
191 ring.rotate();
192 assert_eq!(ring.peek(), Some("second"));
193 ring.rotate();
194 assert_eq!(ring.peek(), Some("first"));
195 }
196
197 #[test]
198 fn test_no_duplicate() {
199 let mut ring = KillRing::new();
200 ring.push("hello", PushOptions::default());
201 ring.push("hello", PushOptions::default());
202 assert_eq!(ring.len(), 1);
203 }
204
205 #[test]
206 fn test_max_size() {
207 let mut ring = KillRing::with_max_size(3);
208 ring.push("1", PushOptions::default());
209 ring.push("2", PushOptions::default());
210 ring.push("3", PushOptions::default());
211 ring.push("4", PushOptions::default());
212
213 assert_eq!(ring.len(), 3);
214 assert_eq!(ring.peek(), Some("4"));
215 assert_eq!(ring.get(2), Some("2")); }
217
218 #[test]
219 fn test_empty_text() {
220 let mut ring = KillRing::new();
221 ring.push("", PushOptions::default());
222 assert!(ring.is_empty());
223 }
224}