use std::sync::atomic::Ordering;
use std::sync::Mutex;
use crate::ported::params::{setiparam, setsparam};
use crate::ported::zle::zle_h::{WidgetImpl, MOD_MULT, MOD_NEG, MOD_TMULT};
use crate::ported::zle::zle_hist::{ISEARCH_ACTIVE, ISEARCH_ENDPOS, ISEARCH_STARTPOS};
use crate::ported::zle::zle_keymap::{addkeybuf, freekeynode, KeyBinding};
use crate::ported::zle::zle_main::{zleaftertrap, zlebeforetrap, ZLECONTEXT};
use crate::ported::zle::zle_misc::{
POSTDISPLAY, PREDISPLAY, PREVIOUS_ABORTED_SEARCH, PREVIOUS_SEARCH, SUFFIXLEN,
};
use crate::ported::zle::zle_thingy::Thingy;
use crate::ported::zsh_h::{hashnode, param, ScanFunc, PM_READONLY, PM_SCALAR, ZLCON_LINE_CONT, ZLCON_LINE_START, ZLCON_SELECT, ZLCON_VARED};
#[allow(unused_imports)]
use crate::ported::zle::{
deltochar::*, textobjects::*, zle_h::*, zle_hist::*, zle_main::*, zle_misc::*, zle_move::*,
zle_refresh::*, zle_tricky::*, zle_utils::*, zle_vi::*, zle_word::*,
};
use crate::ported::zle::compcore::ZMULT;
#[allow(unused_imports)]
pub fn makezleparams(_ro: i32) {
let line = crate::ported::zle::compcore::ZLELINE
.get_or_init(|| Mutex::new(String::new()))
.lock()
.map(|g| g.clone())
.unwrap_or_default();
let cs = crate::ported::zle::compcore::ZLECS.load(Ordering::Relaxed) as usize;
let (lbuf, rbuf) = if cs <= line.len() {
(line[..cs].to_string(), line[cs..].to_string())
} else {
(line.clone(), String::new())
};
let _ = setsparam("BUFFER", &line); let _ = setsparam("LBUFFER", &lbuf); let _ = setsparam("RBUFFER", &rbuf); let _ = setiparam(
"CURSOR",
crate::ported::zle::compcore::ZLECS.load(Ordering::Relaxed) as i64,
); let _ = setiparam(
"NUMERIC",
ZMULT.load(Ordering::Relaxed) as i64,
); let lines = line.chars().filter(|c| *c == '\n').count() as i64 + 1;
let _ = setiparam("BUFFERLINES", lines); }
pub fn zleunsetfn(pm: &mut param, exp: i32) {
crate::ported::params::stdunsetfn(pm, exp); }
pub fn set_buffer(s: &str) {
*ZLELINE.lock().unwrap() = s.chars().collect();
ZLELL.store(
ZLELINE.lock().unwrap().len(),
Ordering::SeqCst,
);
ZLECS.store(
ZLECS
.load(Ordering::SeqCst)
.min(ZLELL.load(Ordering::SeqCst)),
Ordering::SeqCst,
);
ZLE_RESET_NEEDED.store(1, Ordering::SeqCst);
}
pub fn get_buffer() -> String {
ZLELINE
.lock()
.unwrap()
.iter()
.collect()
}
pub fn set_cursor(pos: usize) {
ZLECS.store(
pos.min(ZLELL.load(Ordering::SeqCst)),
Ordering::SeqCst,
);
ZLE_RESET_NEEDED.store(1, Ordering::SeqCst);
}
pub fn get_cursor() -> usize {
ZLECS.load(Ordering::SeqCst)
}
pub fn set_mark(pos: usize) {
MARK.store(
pos.min(ZLELL.load(Ordering::SeqCst)),
Ordering::SeqCst,
);
}
pub fn get_mark() -> usize {
MARK.load(Ordering::SeqCst)
}
pub fn set_region_active(
x: i64,
) {
REGION_ACTIVE.store(
if x != 0 { 1 } else { 0 },
Ordering::SeqCst,
);
}
pub fn get_region_active() -> i64 {
REGION_ACTIVE.load(Ordering::SeqCst) as i64
}
pub fn set_lbuffer(s: &str) {
let rbuf: String = ZLELINE.lock().unwrap()
[ZLECS.load(Ordering::SeqCst)..]
.iter()
.collect();
*ZLELINE.lock().unwrap() =
s.chars().chain(rbuf.chars()).collect();
ZLELL.store(
ZLELINE.lock().unwrap().len(),
Ordering::SeqCst,
);
ZLECS
.store(s.chars().count(), Ordering::SeqCst);
ZLE_RESET_NEEDED.store(1, Ordering::SeqCst);
}
pub fn get_lbuffer() -> String {
ZLELINE.lock().unwrap()
[..ZLECS.load(Ordering::SeqCst)]
.iter()
.collect()
}
pub fn set_rbuffer(s: &str) {
let lbuf: String = ZLELINE.lock().unwrap()
[..ZLECS.load(Ordering::SeqCst)]
.iter()
.collect();
*ZLELINE.lock().unwrap() =
lbuf.chars().chain(s.chars()).collect();
ZLELL.store(
ZLELINE.lock().unwrap().len(),
Ordering::SeqCst,
);
ZLE_RESET_NEEDED.store(1, Ordering::SeqCst);
}
pub fn get_rbuffer() -> String {
ZLELINE.lock().unwrap()
[ZLECS.load(Ordering::SeqCst)..]
.iter()
.collect()
}
pub fn get_prebuffer() -> String {
String::new()
}
pub fn get_widget() -> String {
BINDK
.lock()
.unwrap()
.as_ref()
.map(|t| t.nam.clone())
.unwrap_or_default()
}
pub fn get_widgetfunc() -> String {
let bindk_guard = BINDK.lock().unwrap();
let Some(t) = bindk_guard.as_ref() else {
return String::new();
};
let Some(w) = t.widget.as_ref() else {
return String::new();
};
if (w.flags & WIDGET_INT) != 0 {
return ".internal".to_string();
}
match &w.u {
WidgetImpl::UserFunc(name) => name.clone(),
WidgetImpl::Internal(_) => ".internal".to_string(),
_ => ".internal".to_string(),
}
}
pub fn get_widgetstyle() -> String {
let bindk_guard = BINDK.lock().unwrap();
let Some(t) = bindk_guard.as_ref() else {
return String::new();
};
let Some(w) = t.widget.as_ref() else {
return String::new();
};
if (w.flags & WIDGET_INT) != 0 {
return ".internal".to_string();
}
String::new() }
pub fn get_lwidget() -> String {
LBINDK
.lock()
.unwrap()
.as_ref()
.map(|t| t.nam.clone())
.unwrap_or_default()
}
pub fn get_keymap() -> String {
crate::ported::zle::zle_keymap::curkeymapname().clone()
}
pub fn get_keys() -> Vec<u8> {
crate::ported::zle::zle_keymap::keybuf
.lock()
.unwrap()
.clone()
}
pub fn get_keys_queued_count() -> i64 {
KUNGETBUF
.lock()
.unwrap()
.len() as i64
}
pub fn set_numeric(x: i64) {
ZMOD.lock().unwrap().mult = x as i32;
ZMOD.lock().unwrap().flags = MOD_MULT;
}
pub fn get_numeric() -> i32 {
ZMOD.lock().unwrap().mult }
pub fn unset_numeric(exp: i32) {
if exp != 0 {
ZMOD.lock().unwrap().flags = 0; ZMOD.lock().unwrap().mult = 1; }
}
pub fn set_histno(x: i64) {
let idx = x.max(0) as usize;
if idx
<= history()
.lock()
.unwrap()
.entries
.len()
{
history()
.lock()
.unwrap()
.cursor = idx;
}
}
pub fn get_histno() -> i64 {
history()
.lock()
.unwrap()
.cursor as i64
}
pub fn get_bufferlines() -> usize {
ZLELINE
.lock()
.unwrap()
.iter()
.filter(|&&c| c == '\n')
.count()
+ 1
}
pub fn get_pending() -> usize {
0 }
pub fn get_recursive() -> i64 {
ZLE_RECURSIVE.load(Ordering::SeqCst) as i64
}
pub fn get_yankstart() -> i64 {
YANKB.load(Ordering::SeqCst) as i64
}
pub fn get_yankend() -> i64 {
YANKE.load(Ordering::SeqCst) as i64
}
pub fn get_yankactive() -> i64 {
let last =
LASTCMD.load(Ordering::SeqCst) as i32;
let yank = ((last & ZLE_YANK) != 0) as i64;
let yankafter = ((last & ZLE_YANKAFTER) != 0) as i64;
yank + yankafter
}
pub fn set_yankstart(i: i64) {
YANKB
.store(i.max(0) as usize, Ordering::SeqCst);
}
pub fn set_yankend(i: i64) {
YANKE
.store(i.max(0) as usize, Ordering::SeqCst);
}
pub fn get_isearchmatchstart() -> i64 {
ISEARCH_STARTPOS.load(Ordering::Relaxed) as i64
}
pub fn get_isearchmatchend() -> i64 {
ISEARCH_ENDPOS.load(Ordering::Relaxed) as i64 }
pub fn get_isearchmatchactive() -> i64 {
ISEARCH_ACTIVE.load(Ordering::Relaxed) as i64 }
pub fn get_suffixstart() -> i64 {
let sfx_len = SUFFIXLEN.load(Ordering::Relaxed);
(ZLECS.load(Ordering::SeqCst) as i64)
- (sfx_len as i64) }
pub fn get_suffixend() -> i64 {
ZLECS.load(Ordering::SeqCst) as i64
}
pub fn get_suffixactive() -> i64 {
SUFFIXLEN.load(Ordering::Relaxed) as i64 }
pub fn get_cutbuffer() -> String {
KILLRING
.lock()
.unwrap()
.front()
.map(|v| v.iter().collect())
.unwrap_or_default()
}
pub fn set_cutbuffer(s: &str) {
let chars: Vec<char> = s.chars().collect();
if KILLRING
.lock()
.unwrap()
.is_empty()
{
KILLRING
.lock()
.unwrap()
.push_front(chars);
} else {
KILLRING.lock().unwrap()[0] = chars;
}
}
pub fn unset_cutbuffer(exp: i32) {
if exp != 0 {
KILLRING
.lock()
.unwrap()
.pop_front();
}
}
pub fn set_killring(x: Option<&[String]>) {
KILLRING
.lock()
.unwrap()
.clear();
if let Some(arr) = x {
for entry in arr {
KILLRING
.lock()
.unwrap()
.push_back(entry.chars().collect());
}
}
}
pub fn get_killring() -> Vec<String> {
KILLRING
.lock()
.unwrap()
.iter()
.map(|entry| entry.iter().collect::<String>())
.collect()
}
pub fn unset_killring(exp: i32) {
if exp != 0 {
set_killring(None);
}
}
pub fn set_register(name: char, value: &str) -> i32 {
let idx: i32 = if ('0'..='9').contains(&name) {
name as i32 - b'0' as i32 + 26
} else if ('a'..='z').contains(&name) {
name as i32 - b'a' as i32
} else {
return 1;
};
if (idx as usize) < vibuf().lock().unwrap().len() {
vibuf().lock().unwrap()[idx as usize] =
value.chars().collect();
}
0
}
pub fn unset_register(name: char, _exp: i32) {
let _ = set_register(name, "");
}
pub fn scan_registers(_ht: i32, func: Option<ScanFunc>, flags: i32) {
let func = match func {
Some(f) => f,
None => return,
};
let buf = vibuf()
.lock()
.unwrap()
.clone(); let mut ch: u8 = b'a'; for i in 0..36usize {
let val: String = buf.get(i).map(|v| v.iter().collect()).unwrap_or_default(); let pm = param {
node: hashnode {
next: None,
nam: format!("{}", ch as char), flags: (PM_SCALAR | PM_READONLY) as i32, },
u_data: 0,
u_arr: None,
u_str: Some(val), u_val: 0,
u_dval: 0.0,
u_hash: None,
gsu_s: None,
gsu_i: None,
gsu_f: None,
gsu_a: None,
gsu_h: None,
base: 0,
width: 0,
env: None,
ename: None,
old: None,
level: 0,
};
func(&Box::new(pm.node), flags); ch = if ch == b'z' { b'0' } else { ch + 1 }; }
}
pub fn get_registers(name: &str) -> Option<String> {
let bytes = name.as_bytes();
if bytes.len() != 1 {
return None;
}
let c = bytes[0];
let idx: i32 = if c.is_ascii_digit() {
(c - b'0') as i32 + 26
} else if c.is_ascii_lowercase() {
(c - b'a') as i32
} else {
return None; };
if (idx as usize) < vibuf().lock().unwrap().len() {
Some(
vibuf().lock().unwrap()[idx as usize]
.iter()
.collect::<String>(),
)
} else {
None
}
}
pub fn set_registers(
map: &std::collections::HashMap<String, String>,
) {
for (name, value) in map {
if let Some(ch) = name.chars().next() {
let _ = set_register(ch, value);
}
}
}
pub fn unset_registers(exp: i32) {
if exp != 0 {
for buf in vibuf()
.lock()
.unwrap()
.iter_mut()
{
buf.clear();
}
}
}
pub fn set_prepost(textvar: &mut String, lenvar: &mut usize, x: Option<&str>) {
if *lenvar != 0 {
textvar.clear();
*lenvar = 0;
}
if let Some(s) = x {
textvar.push_str(s);
*lenvar = s.chars().count();
}
}
pub fn get_prepost(text: &str, len: usize) -> String {
text.chars().take(len).collect()
}
pub fn set_predisplay(x: Option<&str>) {
let mut buf = PREDISPLAY
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap(); let mut len = buf.chars().count();
set_prepost(&mut buf, &mut len, x); }
pub fn get_predisplay() -> String {
PREDISPLAY
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap()
.clone()
}
pub fn set_postdisplay(x: Option<&str>) {
let mut buf = POSTDISPLAY
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap(); let mut len = buf.chars().count();
set_prepost(&mut buf, &mut len, x); }
pub fn get_postdisplay() -> String {
POSTDISPLAY
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap()
.clone()
}
pub fn free_prepostdisplay() {
PREDISPLAY
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap()
.clear();
POSTDISPLAY
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap()
.clear();
}
pub fn get_lasearch() -> String {
PREVIOUS_ABORTED_SEARCH
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap()
.clone()
}
pub fn get_lsearch() -> String {
PREVIOUS_SEARCH
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap()
.clone()
}
pub fn get_context() -> &'static str {
match ZLECONTEXT.load(Ordering::SeqCst) {
x if x == ZLCON_LINE_CONT => "cont", x if x == ZLCON_SELECT => "select", x if x == ZLCON_VARED => "vared", _ => "line", }
}
pub fn get_zle_state() -> String {
use crate::ported::zsh_h::HIST_FOREIGN;
let insmode_str = if INSMODE.load(Ordering::SeqCst) != 0 {
"insert" } else {
"overwrite" };
let hist_str = if (crate::ported::hist::hist_skip_flags
.load(Ordering::SeqCst)
& HIST_FOREIGN as i32)
!= 0
{
"localhistory" } else {
"globalhistory" };
let mut parts = vec![insmode_str.to_string(), hist_str.to_string()];
parts.sort();
parts.join(" ")
}
pub fn is_insert_mode() -> bool {
(INSMODE.load(Ordering::SeqCst) != 0)
}
pub fn is_region_active() -> bool {
REGION_ACTIVE.load(Ordering::SeqCst) != 0
}
#[cfg(test)]
mod region_active_tests {
use super::*;
#[test]
fn get_region_active_reads_field() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
REGION_ACTIVE.store(0, Ordering::SeqCst);
assert_eq!(get_region_active(), 0);
REGION_ACTIVE.store(1, Ordering::SeqCst);
assert_eq!(get_region_active(), 1);
REGION_ACTIVE.store(2, Ordering::SeqCst);
assert_eq!(get_region_active(), 2);
}
#[test]
fn set_region_active_double_bang_idiom() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
set_region_active(0);
assert_eq!(
REGION_ACTIVE.load(Ordering::SeqCst),
0
);
set_region_active(1);
assert_eq!(
REGION_ACTIVE.load(Ordering::SeqCst),
1
);
set_region_active(99);
assert_eq!(
REGION_ACTIVE.load(Ordering::SeqCst),
1
);
set_region_active(-1);
assert_eq!(
REGION_ACTIVE.load(Ordering::SeqCst),
1
);
set_region_active(0);
assert_eq!(
REGION_ACTIVE.load(Ordering::SeqCst),
0
);
}
}
#[cfg(test)]
mod trap_tests {
use crate::zle::zle_main::{zle_test_setup, zleaftertrap, zlebeforetrap};
#[test]
fn zlebeforetrap_returns_zero() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(zlebeforetrap(std::ptr::null_mut(), std::ptr::null_mut()), 0);
}
#[test]
fn zleaftertrap_returns_zero() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(zleaftertrap(std::ptr::null_mut(), std::ptr::null_mut()), 0);
}
}
#[cfg(test)]
mod numeric_tests {
use super::*;
#[test]
fn set_numeric_sets_mult_and_replaces_flags() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().flags |= MOD_TMULT | MOD_NEG;
ZMOD.lock().unwrap().mult = 99;
set_numeric(7);
assert_eq!(ZMOD.lock().unwrap().mult, 7);
assert_ne!(ZMOD.lock().unwrap().flags & MOD_MULT, 0);
assert_eq!(
ZMOD.lock().unwrap().flags & MOD_TMULT,
0
);
assert_eq!(
ZMOD.lock().unwrap().flags & MOD_NEG,
0
);
}
#[test]
fn unset_numeric_resets_when_exp_nonzero() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().flags |= MOD_MULT;
ZMOD.lock().unwrap().mult = 5;
unset_numeric(1);
assert_eq!(ZMOD.lock().unwrap().mult, 1);
assert_eq!(ZMOD.lock().unwrap().flags, 0);
}
#[test]
fn unset_numeric_noop_when_exp_zero() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().flags |= MOD_MULT;
ZMOD.lock().unwrap().mult = 5;
unset_numeric(0);
assert_eq!(ZMOD.lock().unwrap().mult, 5);
assert_ne!(ZMOD.lock().unwrap().flags & MOD_MULT, 0);
}
}
#[cfg(test)]
mod suffix_tests {
use super::*;
#[test]
fn get_suffixactive_reads_suffixlen() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
SUFFIXLEN.store(7, Ordering::SeqCst);
assert_eq!(get_suffixactive(), 7);
SUFFIXLEN.store(0, Ordering::SeqCst);
assert_eq!(get_suffixactive(), 0);
}
#[test]
fn get_suffixend_reads_zlecs() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZLECS.store(11, Ordering::SeqCst);
assert_eq!(get_suffixend(), 11);
}
#[test]
fn get_suffixstart_subtracts_suffixlen() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZLECS.store(20, Ordering::SeqCst);
SUFFIXLEN.store(5, Ordering::SeqCst);
assert_eq!(get_suffixstart(), 15);
SUFFIXLEN.store(0, Ordering::SeqCst);
assert_eq!(get_suffixstart(), 20);
}
}
#[cfg(test)]
mod widget_tests {
use super::*;
#[test]
fn get_widget_reads_bindk_nam() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
*BINDK.lock().unwrap() = Some(Thingy::new("self-insert"));
assert_eq!(get_widget(), "self-insert");
}
#[test]
fn get_widget_empty_when_no_bindk() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
assert_eq!(get_widget(), "");
}
#[test]
fn get_lwidget_reads_lbindk_nam() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
*LBINDK.lock().unwrap() = Some(Thingy::new("forward-char"));
assert_eq!(get_lwidget(), "forward-char");
}
#[test]
fn get_lwidget_empty_when_no_lbindk() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(get_lwidget(), "");
}
#[test]
fn get_recursive_reads_zle_recursive_field() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZLE_RECURSIVE.store(0, Ordering::SeqCst);
assert_eq!(get_recursive(), 0);
ZLE_RECURSIVE.store(5, Ordering::SeqCst);
assert_eq!(get_recursive(), 5);
}
}
#[cfg(test)]
mod isearch_tests {
use super::*;
#[test]
fn get_isearchmatchactive_reads_global() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
ISEARCH_ACTIVE.store(0, Ordering::SeqCst);
assert_eq!(get_isearchmatchactive(), 0);
ISEARCH_ACTIVE.store(1, Ordering::SeqCst);
assert_eq!(get_isearchmatchactive(), 1);
ISEARCH_ACTIVE.store(0, Ordering::SeqCst);
}
#[test]
fn get_isearchmatchstart_reads_global() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
ISEARCH_STARTPOS.store(7, Ordering::SeqCst);
assert_eq!(get_isearchmatchstart(), 7);
ISEARCH_STARTPOS.store(0, Ordering::SeqCst);
}
#[test]
fn get_isearchmatchend_reads_global() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
ISEARCH_ENDPOS.store(13, Ordering::SeqCst);
assert_eq!(get_isearchmatchend(), 13);
ISEARCH_ENDPOS.store(0, Ordering::SeqCst);
}
}
#[cfg(test)]
mod batch_getters_tests {
use super::*;
#[test]
fn get_histno_reads_history_cursor() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
history()
.lock()
.unwrap()
.cursor = 7;
assert_eq!(get_histno(), 7);
}
#[test]
fn get_keys_returns_keybuf_clone() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*crate::ported::zle::zle_keymap::keybuf.lock().unwrap() = vec![0x1b, b'a'];
assert_eq!(get_keys(), vec![0x1b, b'a']);
}
#[test]
fn get_keys_queued_count_returns_unget_len() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
KUNGETBUF
.lock()
.unwrap()
.push_back(b'a');
KUNGETBUF
.lock()
.unwrap()
.push_back(b'b');
KUNGETBUF
.lock()
.unwrap()
.push_back(b'c');
assert_eq!(get_keys_queued_count(), 3);
}
#[test]
fn get_yankstart_yankend_read_fields() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
YANKB.store(3, Ordering::SeqCst);
YANKE.store(8, Ordering::SeqCst);
assert_eq!(get_yankstart(), 3);
assert_eq!(get_yankend(), 8);
}
#[test]
fn set_yankstart_yankend_write_fields() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_yankstart(5);
set_yankend(11);
assert_eq!(
YANKB.load(Ordering::SeqCst),
5
);
assert_eq!(
YANKE.load(Ordering::SeqCst),
11
);
}
}
#[cfg(test)]
mod keybuf_tests {
use crate::zle::zle_keymap::{addkeybuf, freekeynode, KeyBinding};
use crate::zle::zle_main::zle_test_setup;
#[test]
fn addkeybuf_plain_byte() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let _tg = crate::ported::ztype_h::TYPTAB_TEST_LOCK
.lock()
.unwrap_or_else(|e| e.into_inner());
crate::ported::utils::inittyptab();
crate::ported::zle::zle_keymap::keybuf
.lock()
.unwrap()
.clear();
addkeybuf(b'a' as i32);
assert_eq!(
*crate::ported::zle::zle_keymap::keybuf.lock().unwrap(),
vec![b'a']
);
}
#[test]
fn addkeybuf_meta_quoted() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let _tg = crate::ported::ztype_h::TYPTAB_TEST_LOCK
.lock()
.unwrap_or_else(|e| e.into_inner());
crate::ported::utils::inittyptab();
crate::ported::zle::zle_keymap::keybuf
.lock()
.unwrap()
.clear();
addkeybuf(0xa0);
assert_eq!(
*crate::ported::zle::zle_keymap::keybuf.lock().unwrap(),
vec![0x83, 0x80]
);
}
#[test]
fn freekeynode_consumes_binding() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let kb = KeyBinding {
bind: None,
str: Some("send-string".to_string()),
prefixct: 0,
};
freekeynode(kb);
}
}
#[cfg(test)]
mod display_tests {
use super::*;
#[test]
fn get_set_predisplay_round_trip() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_predisplay(Some("[hint] "));
assert_eq!(get_predisplay(), "[hint] ");
set_predisplay(None);
assert_eq!(get_predisplay(), "");
}
#[test]
fn get_set_postdisplay_round_trip() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_postdisplay(Some("trailer"));
assert_eq!(get_postdisplay(), "trailer");
set_postdisplay(None);
assert_eq!(get_postdisplay(), "");
}
#[test]
fn free_prepostdisplay_clears_both() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_predisplay(Some("a"));
set_postdisplay(Some("b"));
free_prepostdisplay();
assert_eq!(get_predisplay(), "");
assert_eq!(get_postdisplay(), "");
}
#[test]
fn get_context_branches() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZLECONTEXT.store(ZLCON_LINE_START, Ordering::SeqCst);
assert_eq!(get_context(), "line");
ZLECONTEXT.store(ZLCON_LINE_CONT, Ordering::SeqCst);
assert_eq!(get_context(), "cont");
ZLECONTEXT.store(ZLCON_SELECT, Ordering::SeqCst);
assert_eq!(get_context(), "select");
ZLECONTEXT.store(ZLCON_VARED, Ordering::SeqCst);
assert_eq!(get_context(), "vared");
}
#[test]
fn get_lasearch_lsearch_default_empty() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
PREVIOUS_ABORTED_SEARCH
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap()
.clear();
PREVIOUS_SEARCH
.get_or_init(|| Mutex::new(String::new()))
.lock()
.unwrap()
.clear();
assert_eq!(get_lasearch(), "");
assert_eq!(get_lsearch(), "");
}
#[test]
fn get_prepost_truncates_to_len() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(get_prepost("abcdef", 3), "abc");
assert_eq!(get_prepost("xyz", 99), "xyz"); }
#[test]
fn set_prepost_writes_and_clears() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let mut text = String::new();
let mut len = 0;
set_prepost(&mut text, &mut len, Some("hello"));
assert_eq!(text, "hello");
assert_eq!(len, 5);
set_prepost(&mut text, &mut len, None);
assert_eq!(text, "");
assert_eq!(len, 0);
}
}
#[cfg(test)]
mod widget_killring_tests {
use super::*;
#[test]
fn set_get_register_round_trip() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_register('a', "hello");
let s: String = vibuf().lock().unwrap()[0]
.iter()
.collect();
assert_eq!(s, "hello");
assert_eq!(get_registers("a"), Some("hello".to_string()));
}
#[test]
fn set_register_digit_uses_offset_26() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_register('0', "zero");
let s: String = vibuf().lock().unwrap()[26]
.iter()
.collect();
assert_eq!(s, "zero");
assert_eq!(get_registers("0"), Some("zero".to_string()));
}
#[test]
fn set_register_invalid_returns_one() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(set_register('!', "x"), 1);
}
#[test]
fn unset_register_clears_buffer() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_register('a', "hi");
unset_register('a', 1);
assert_eq!(get_registers("a"), Some(String::new()));
}
#[test]
fn set_get_killring_round_trip() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let entries = vec!["first".to_string(), "second".to_string()];
set_killring(Some(&entries));
let got = get_killring();
assert_eq!(got, vec!["first".to_string(), "second".to_string()]);
}
#[test]
fn unset_killring_clears_when_exp_nonzero() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let entries = vec!["x".to_string()];
set_killring(Some(&entries));
unset_killring(1);
assert!(get_killring().is_empty());
}
#[test]
fn set_histno_clamps_to_entries_len() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
history()
.lock()
.unwrap()
.entries
.push(HistEntry {
line: "ls".to_string(),
num: 1,
time: None,
});
history()
.lock()
.unwrap()
.entries
.push(HistEntry {
line: "cd".to_string(),
num: 2,
time: None,
});
set_histno(1);
assert_eq!(
history()
.lock()
.unwrap()
.cursor,
1
);
history()
.lock()
.unwrap()
.cursor = 7;
set_histno(99);
assert_eq!(
history()
.lock()
.unwrap()
.cursor,
7
);
}
#[test]
fn zle_params_corpus_buffer_round_trip() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_buffer("hello");
assert_eq!(get_buffer(), "hello");
}
#[test]
fn zle_params_corpus_buffer_set_empty() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_buffer("anything");
set_buffer("");
assert_eq!(get_buffer(), "");
assert_eq!(ZLELL.load(Ordering::SeqCst), 0);
}
#[test]
fn zle_params_corpus_cursor_clamps_to_buffer_length() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_buffer("abc"); set_cursor(99);
assert_eq!(get_cursor(), 3, "cursor clamped to buf len");
}
#[test]
fn zle_params_corpus_cursor_within_buffer() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_buffer("abc");
set_cursor(2);
assert_eq!(get_cursor(), 2);
}
#[test]
fn zle_params_corpus_mark_round_trip() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_buffer("abcdef");
set_mark(2);
assert_eq!(get_mark(), 2);
}
#[test]
fn zle_params_corpus_region_active_round_trip() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_region_active(1);
assert_eq!(get_region_active(), 1);
set_region_active(0);
assert_eq!(get_region_active(), 0);
}
#[test]
fn zle_params_corpus_set_buffer_updates_zlell() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_buffer("ab");
assert_eq!(ZLELL.load(Ordering::SeqCst), 2);
set_buffer("abcdef");
assert_eq!(ZLELL.load(Ordering::SeqCst), 6);
}
#[test]
fn zle_params_corpus_get_buffer_empty_returns_empty() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
set_buffer("");
assert_eq!(get_buffer(), "");
}
}