2023-05-31 05:22:09 +08:00
|
|
|
//! The killring.
|
|
|
|
//!
|
|
|
|
//! Works like the killring in emacs and readline. The killring is cut and paste with a memory of
|
|
|
|
//! previous cuts.
|
|
|
|
|
2023-08-14 02:28:55 +08:00
|
|
|
use once_cell::sync::Lazy;
|
2023-05-31 05:22:09 +08:00
|
|
|
use std::collections::VecDeque;
|
|
|
|
use std::sync::Mutex;
|
|
|
|
|
2023-08-09 06:16:04 +08:00
|
|
|
use crate::wchar::prelude::*;
|
2023-05-31 05:22:09 +08:00
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
struct KillRing(VecDeque<WString>);
|
2023-05-31 05:22:09 +08:00
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
static KILL_RING: Lazy<Mutex<KillRing>> = Lazy::new(|| Mutex::new(KillRing::new()));
|
2023-05-31 05:22:09 +08:00
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
impl KillRing {
|
|
|
|
/// Create a new killring.
|
|
|
|
fn new() -> Self {
|
|
|
|
Self(VecDeque::new())
|
2023-05-31 05:22:09 +08:00
|
|
|
}
|
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
/// Return whether this killring is empty.
|
2024-01-13 08:59:06 +08:00
|
|
|
#[cfg(test)]
|
2023-08-14 03:25:13 +08:00
|
|
|
fn is_empty(&self) -> bool {
|
|
|
|
self.0.is_empty()
|
|
|
|
}
|
2023-05-31 05:22:09 +08:00
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
/// Add a string to the top of the killring.
|
|
|
|
fn add(&mut self, new_entry: WString) {
|
|
|
|
if !new_entry.is_empty() {
|
|
|
|
self.0.push_front(new_entry);
|
|
|
|
}
|
2023-05-31 05:22:09 +08:00
|
|
|
}
|
2023-08-14 03:25:13 +08:00
|
|
|
|
|
|
|
/// Replace the specified string in the killring.
|
|
|
|
pub fn replace(&mut self, old_entry: &wstr, new_entry: WString) {
|
|
|
|
if let Some(old_entry_idx) = self.0.iter().position(|entry| entry == old_entry) {
|
|
|
|
self.0.remove(old_entry_idx);
|
|
|
|
}
|
|
|
|
if !new_entry.is_empty() {
|
|
|
|
self.add(new_entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Paste from the killring.
|
|
|
|
pub fn yank(&mut self) -> WString {
|
|
|
|
self.0.front().cloned().unwrap_or_default()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Rotate the killring.
|
|
|
|
pub fn yank_rotate(&mut self) -> WString {
|
|
|
|
self.0.rotate_left(1);
|
|
|
|
self.yank()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return a copy of the list of entries.
|
|
|
|
pub fn entries(&self) -> Vec<WString> {
|
|
|
|
self.0.iter().cloned().collect()
|
2023-05-31 05:22:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
/// Add a string to the top of the killring.
|
|
|
|
pub fn kill_add(new_entry: WString) {
|
|
|
|
KILL_RING.lock().unwrap().add(new_entry)
|
2023-05-31 05:22:09 +08:00
|
|
|
}
|
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
/// Replace the specified string in the killring.
|
|
|
|
pub fn kill_replace(old_entry: &wstr, new_entry: WString) {
|
|
|
|
KILL_RING.lock().unwrap().replace(old_entry, new_entry)
|
2023-05-31 05:22:09 +08:00
|
|
|
}
|
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
/// Rotate the killring.
|
|
|
|
pub fn kill_yank_rotate() -> WString {
|
|
|
|
KILL_RING.lock().unwrap().yank_rotate()
|
2023-05-31 05:22:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Paste from the killring.
|
|
|
|
pub fn kill_yank() -> WString {
|
2023-08-14 03:25:13 +08:00
|
|
|
KILL_RING.lock().unwrap().yank()
|
2023-05-31 05:22:09 +08:00
|
|
|
}
|
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
pub fn kill_entries() -> Vec<WString> {
|
|
|
|
KILL_RING.lock().unwrap().entries()
|
2023-05-31 05:22:09 +08:00
|
|
|
}
|
|
|
|
|
2024-01-13 09:23:27 +08:00
|
|
|
#[test]
|
2023-08-14 02:28:55 +08:00
|
|
|
fn test_killring() {
|
2023-08-14 03:25:13 +08:00
|
|
|
let mut kr = KillRing::new();
|
2023-08-14 02:28:55 +08:00
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
assert!(kr.is_empty());
|
2023-08-14 02:28:55 +08:00
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
kr.add(WString::from_str("a"));
|
|
|
|
kr.add(WString::from_str("b"));
|
|
|
|
kr.add(WString::from_str("c"));
|
|
|
|
|
2024-01-13 09:23:27 +08:00
|
|
|
assert!(kr.entries() == [L!("c"), L!("b"), L!("a")]);
|
2023-08-14 02:28:55 +08:00
|
|
|
|
2024-01-13 15:25:12 +08:00
|
|
|
assert!(kr.yank_rotate() == "b");
|
2024-01-13 09:23:27 +08:00
|
|
|
assert!(kr.entries() == [L!("b"), L!("a"), L!("c")]);
|
2023-08-14 02:28:55 +08:00
|
|
|
|
2024-01-13 15:25:12 +08:00
|
|
|
assert!(kr.yank_rotate() == "a");
|
2024-01-13 09:23:27 +08:00
|
|
|
assert!(kr.entries() == [L!("a"), L!("c"), L!("b")]);
|
2023-08-14 02:28:55 +08:00
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
kr.add(WString::from_str("d"));
|
2023-08-14 02:28:55 +08:00
|
|
|
|
2023-08-14 03:25:13 +08:00
|
|
|
assert!((kr.entries() == [L!("d"), L!("a"), L!("c"), L!("b")]));
|
2023-08-14 02:28:55 +08:00
|
|
|
|
2024-01-13 15:25:12 +08:00
|
|
|
assert!(kr.yank_rotate() == "a");
|
2023-08-14 03:25:13 +08:00
|
|
|
assert!((kr.entries() == [L!("a"), L!("c"), L!("b"), L!("d")]));
|
2023-08-14 02:28:55 +08:00
|
|
|
}
|