const DEFAULT_CAPACITY: usize = 10;
pub struct KillRing {
entries: Vec<String>,
capacity: usize,
yank_index: Option<usize>,
}
impl KillRing {
pub fn with_capacity(capacity: usize) -> Self {
Self {
entries: Vec::with_capacity(capacity),
capacity: capacity.max(1),
yank_index: None,
}
}
pub fn new() -> Self {
Self::with_capacity(DEFAULT_CAPACITY)
}
pub fn push(&mut self, text: String) {
if text.is_empty() {
return;
}
if self.entries.first().map_or(false, |e| e == &text) {
return;
}
if self.entries.len() >= self.capacity {
self.entries.pop();
}
self.entries.insert(0, text);
self.yank_index = None;
}
pub fn yank(&mut self) -> Option<&str> {
if self.entries.is_empty() {
self.yank_index = None;
return None;
}
self.yank_index = Some(0);
Some(&self.entries[0])
}
pub fn yank_pop(&mut self) -> Option<&str> {
let idx = self.yank_index?;
if self.entries.is_empty() {
self.yank_index = None;
return None;
}
let next = (idx + 1) % self.entries.len();
self.yank_index = Some(next);
Some(&self.entries[next])
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn yank_index(&self) -> Option<usize> {
self.yank_index
}
pub fn clear(&mut self) {
self.entries.clear();
self.yank_index = None;
}
}
impl Default for KillRing {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_push_and_yank() {
let mut ring = KillRing::new();
assert!(ring.yank().is_none());
ring.push("first".to_string());
ring.push("second".to_string());
assert_eq!(ring.yank(), Some("second"));
assert_eq!(ring.len(), 2);
}
#[test]
fn test_yank_pop_cycles() {
let mut ring = KillRing::new();
ring.push("a".to_string());
ring.push("b".to_string());
ring.push("c".to_string());
assert_eq!(ring.yank(), Some("c"));
assert_eq!(ring.yank_pop(), Some("b"));
assert_eq!(ring.yank_pop(), Some("a"));
assert_eq!(ring.yank_pop(), Some("c"));
}
#[test]
fn test_capacity_limit() {
let mut ring = KillRing::with_capacity(3);
ring.push("1".to_string());
ring.push("2".to_string());
ring.push("3".to_string());
ring.push("4".to_string());
assert_eq!(ring.len(), 3);
assert_eq!(ring.yank(), Some("4"));
assert_eq!(ring.yank_pop(), Some("3"));
assert_eq!(ring.yank_pop(), Some("2"));
assert_eq!(ring.yank_pop(), Some("4")); }
#[test]
fn test_duplicate_consecutive_ignored() {
let mut ring = KillRing::new();
ring.push("hello".to_string());
ring.push("hello".to_string());
assert_eq!(ring.len(), 1);
}
#[test]
fn test_empty_push_ignored() {
let mut ring = KillRing::new();
ring.push(String::new());
assert!(ring.is_empty());
}
#[test]
fn test_clear() {
let mut ring = KillRing::new();
ring.push("x".to_string());
ring.yank();
ring.clear();
assert!(ring.is_empty());
assert!(ring.yank_index().is_none());
}
#[test]
fn test_yank_pop_without_yank_returns_none() {
let mut ring = KillRing::new();
ring.push("data".to_string());
assert!(ring.yank_pop().is_none());
}
#[test]
fn test_push_resets_yank_index() {
let mut ring = KillRing::new();
ring.push("a".to_string());
ring.push("b".to_string());
ring.yank();
assert!(ring.yank_index().is_some());
ring.push("c".to_string());
assert!(ring.yank_index().is_none());
}
}