fish-shell/fish-rust/src/kill.rs

100 lines
2.9 KiB
Rust
Raw Normal View History

2023-05-30 21:22:09 +00:00
//! The killring.
//!
//! Works like the killring in emacs and readline. The killring is cut and paste with a memory of
//! previous cuts.
use cxx::CxxWString;
use std::collections::VecDeque;
use std::pin::Pin;
use std::sync::Mutex;
use crate::ffi::wcstring_list_ffi_t;
2023-08-08 22:16:04 +00:00
use crate::wchar::prelude::*;
2023-05-30 21:22:09 +00:00
use crate::wchar_ffi::WCharFromFFI;
#[cxx::bridge]
mod kill_ffi {
extern "C++" {
include!("wutil.h");
type wcstring_list_ffi_t = super::wcstring_list_ffi_t;
}
extern "Rust" {
#[cxx_name = "kill_add"]
fn kill_add_ffi(new_entry: &CxxWString);
#[cxx_name = "kill_replace"]
fn kill_replace_ffi(old_entry: &CxxWString, new_entry: &CxxWString);
#[cxx_name = "kill_yank_rotate"]
fn kill_yank_rotate_ffi(mut out_front: Pin<&mut CxxWString>);
#[cxx_name = "kill_yank"]
fn kill_yank_ffi(mut out_front: Pin<&mut CxxWString>);
#[cxx_name = "kill_entries"]
fn kill_entries_ffi(mut out: Pin<&mut wcstring_list_ffi_t>);
}
}
static KILL_LIST: once_cell::sync::Lazy<Mutex<VecDeque<WString>>> =
once_cell::sync::Lazy::new(|| Mutex::new(VecDeque::new()));
fn kill_add_ffi(new_entry: &CxxWString) {
kill_add(new_entry.from_ffi());
}
/// Add a string to the top of the killring.
pub fn kill_add(new_entry: WString) {
if !new_entry.is_empty() {
KILL_LIST.lock().unwrap().push_front(new_entry);
}
}
fn kill_replace_ffi(old_entry: &CxxWString, new_entry: &CxxWString) {
kill_replace(old_entry.from_ffi(), new_entry.from_ffi())
}
/// Replace the specified string in the killring.
pub fn kill_replace(old_entry: WString, new_entry: WString) {
let mut kill_list = KILL_LIST.lock().unwrap();
if let Some(old_entry_idx) = kill_list.iter().position(|entry| entry == &old_entry) {
kill_list.remove(old_entry_idx);
}
if !new_entry.is_empty() {
kill_list.push_front(new_entry);
}
}
fn kill_yank_rotate_ffi(mut out_front: Pin<&mut CxxWString>) {
out_front.as_mut().clear();
out_front
.as_mut()
.push_chars(kill_yank_rotate().as_char_slice());
}
/// Rotate the killring.
pub fn kill_yank_rotate() -> WString {
let mut kill_list = KILL_LIST.lock().unwrap();
kill_list.rotate_left(1);
kill_list.front().cloned().unwrap_or_default()
}
fn kill_yank_ffi(mut out_front: Pin<&mut CxxWString>) {
out_front.as_mut().clear();
out_front.as_mut().push_chars(kill_yank().as_char_slice());
}
/// Paste from the killring.
pub fn kill_yank() -> WString {
let kill_list = KILL_LIST.lock().unwrap();
kill_list.front().cloned().unwrap_or_default()
}
fn kill_entries_ffi(mut out_entries: Pin<&mut wcstring_list_ffi_t>) {
out_entries.as_mut().clear();
for kill_entry in KILL_LIST.lock().unwrap().iter() {
out_entries.as_mut().push(kill_entry);
}
}
pub fn kill_entries() -> Vec<WString> {
KILL_LIST.lock().unwrap().iter().cloned().collect()
}