use crate::ported::zle::zle_main::{
vibuf, zle_reset, INSMODE, KILLRING, KILLRINGMAX, LASTCHAR_WIDE, LASTCHAR_WIDE_VALID, MARK,
MULT, NEG_ARG, PREFIXFLAG, REGION_ACTIVE, YANKB, YANKE, ZLECS, ZLELINE, ZLELL,
ZLE_RESET_NEEDED, ZMOD,
};
use crate::ported::zle::compcore::{
LASTCHAR, ZLECS as ZLECS_C, ZLELINE as ZLELINE_C, ZLELL as ZLELL_C,
};
use std::io::Read;
use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::atomic::Ordering::SeqCst;
use crate::ported::builtins::sched::zleactive;
use crate::ported::utils::{errflag, quotestring};
use crate::ported::zle::complete::INCOMPFUNC;
use crate::ported::zle::zle_move::{deccs, decpos, inccs, incpos, vifirstnonblank};
use crate::ported::zle::zle_utils::{findbol, findeol};
use crate::ported::zle::zle_vi::startvichange;
use crate::ported::zsh_h::{isset, ERRFLAG_ERROR, ERRFLAG_INT, KSHARRAYS, QT_SINGLE_OPTIONAL};
use crate::zle::zle_h::{MOD_MULT, MOD_NEG, MOD_NULL, MOD_TMULT};
#[allow(unused_imports)]
use crate::ported::zle::{
deltochar::*, textobjects::*, zle_h::*, zle_hist::*, zle_main::*, zle_move::*, zle_params::*,
zle_refresh::*, zle_tricky::*, zle_utils::*, zle_vi::*, zle_word::*,
};
#[allow(unused_imports)]
pub fn doinsert(zstr: &[char]) {
if let Some(&c1) = zstr.first() {
iremovesuffix(c1 as i32, 0);
}
invalidatelist();
let m = ZMOD.lock().unwrap().mult.unsigned_abs() as usize;
let neg = ZMOD.lock().unwrap().mult < 0;
let zmult_val = ZMOD.lock().unwrap().mult;
let len = zstr.len();
let total = m * len;
let cs = ZLECS.load(SeqCst);
let insmode = INSMODE.load(SeqCst);
let at_newline = ZLELINE.lock().unwrap().get(cs).copied() == Some('\n');
let overwrite = insmode == 0 && !at_newline;
if overwrite {
let mut pos = cs;
let mut i = total;
let ll = ZLELL.load(SeqCst);
while pos < ll && i > 0 {
let ch = ZLELINE.lock().unwrap().get(pos).copied();
if ch == Some('\n') {
break;
}
pos += 1;
i -= 1;
}
let span = pos - cs;
if total < span {
let extra = span - total;
for _ in 0..extra {
ZLELINE.lock().unwrap().remove(cs + total);
ZLELL.fetch_sub(1, SeqCst);
}
}
for k in 0..total {
let c = zstr[k % len];
if cs + k < ll {
if let Some(slot) = ZLELINE.lock().unwrap().get_mut(cs + k) {
*slot = c;
}
} else {
ZLELINE.lock().unwrap().push(c);
ZLELL.fetch_add(1, SeqCst);
}
}
} else {
for _ in 0..m {
for (i, &c) in zstr.iter().enumerate() {
ZLELINE.lock().unwrap().insert(cs + i, c);
}
ZLELL.fetch_add(len, SeqCst);
}
}
if !neg {
ZLECS.fetch_add(total, SeqCst);
} else {
let offset = (zmult_val * len as i32) as i64;
let new_cs = (cs as i64 + offset).max(0) as usize;
ZLECS.store(new_cs, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn selfinsert() -> i32 {
if LASTCHAR_WIDE_VALID.load(SeqCst) == 0 {
LASTCHAR_WIDE.store(LASTCHAR.load(SeqCst), SeqCst);
LASTCHAR_WIDE_VALID.store(1, SeqCst);
}
if let Some(c) = char::from_u32(LASTCHAR_WIDE.load(SeqCst) as u32) {
self_insert(c);
} 0 }
pub fn fixunmeta() {
LASTCHAR
.fetch_and((0x7f) as i32, SeqCst);
if LASTCHAR.load(SeqCst)
== b'\r' as i32
{
LASTCHAR
.store((b'\n' as i32) as i32, SeqCst);
}
LASTCHAR_WIDE.store(
(LASTCHAR.load(SeqCst)) as i32,
SeqCst,
);
LASTCHAR_WIDE_VALID.store(1, SeqCst);
}
pub fn selfinsertunmeta() -> i32 {
fixunmeta();
selfinsert()
}
pub fn deletechar() -> i32 {
let mut n = ZMOD.lock().unwrap().mult;
if n < 0 {
let saved = n;
ZMOD.lock().unwrap().mult = -n;
let ret = backwarddeletechar();
ZMOD.lock().unwrap().mult = saved;
return ret;
}
n = ZMOD.lock().unwrap().mult;
while n > 0 {
if ZLECS.load(SeqCst)
== ZLELL.load(SeqCst)
{
return 1;
}
inccs();
n -= 1;
}
let count = ZMOD.lock().unwrap().mult.max(0) as usize;
for _ in 0..count {
if ZLECS.load(SeqCst) > 0 {
ZLECS.fetch_sub(1, SeqCst);
if ZLECS.load(SeqCst) < ZLELINE.lock().unwrap().len() {
ZLELINE
.lock()
.unwrap()
.remove(ZLECS.load(SeqCst));
ZLELL.fetch_sub(1, SeqCst);
}
}
}
ZLE_RESET_NEEDED.store(1, SeqCst);
0 }
pub fn backwarddeletechar() -> i32 {
let n = ZMOD.lock().unwrap().mult;
if n < 0 {
let saved = n;
ZMOD.lock().unwrap().mult = -n;
let ret = deletechar();
ZMOD.lock().unwrap().mult = saved;
return ret;
}
let count = (n as usize).min(ZLECS.load(SeqCst));
for _ in 0..count {
if ZLECS.load(SeqCst) > 0 {
ZLECS.fetch_sub(1, SeqCst);
ZLELINE
.lock()
.unwrap()
.remove(ZLECS.load(SeqCst));
ZLELL.fetch_sub(1, SeqCst);
}
}
ZLE_RESET_NEEDED.store(1, SeqCst);
0 }
pub fn killwholeline() -> i32 {
let mut n = ZMOD.lock().unwrap().mult;
if n < 0 {
return 1; }
while n > 0 {
let _fg = ZLECS.load(SeqCst) > 0
&& ZLECS.load(SeqCst)
== ZLELL.load(SeqCst);
if _fg {
ZLECS.fetch_sub(1, SeqCst);
}
while ZLECS.load(SeqCst) > 0
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst) - 1] != '\n'
{
ZLECS.fetch_sub(1, SeqCst);
}
let mut i = ZLECS.load(SeqCst);
while i != ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[i] != '\n'
{
i += 1;
}
let drop = i - ZLECS.load(SeqCst)
+ (if i != ZLELL.load(SeqCst) {
1
} else {
0
});
if drop > 0 {
let text: Vec<char> = ZLELINE
.lock()
.unwrap()
.drain(
ZLECS.load(SeqCst)
..ZLECS.load(SeqCst) + drop,
)
.collect();
KILLRING.lock().unwrap().push_front(text);
if KILLRING.lock().unwrap().len()
> KILLRINGMAX.load(SeqCst)
{
KILLRING.lock().unwrap().pop_back();
}
ZLELL.fetch_sub(drop, SeqCst);
}
n -= 1;
}
ZLE_RESET_NEEDED.store(1, SeqCst);
0 }
pub fn killbuffer() -> i32 {
ZLECS.store(0, SeqCst); let zlell = ZLELL.load(SeqCst) as i32;
forekill(zlell, CUT_RAW); CLEARLIST.store(1, SeqCst); 0 }
pub fn backwardkillline() -> i32 {
let n = ZMOD.lock().unwrap().mult;
if n < 0 {
ZMOD.lock().unwrap().mult = -n;
let ret = killline();
ZMOD.lock().unwrap().mult = n;
return ret;
}
let mut nn = n;
let mut i = 0_usize;
while nn > 0 {
if ZLECS.load(SeqCst) > 0
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst) - 1] == '\n'
{
ZLECS.fetch_sub(1, SeqCst);
i += 1;
} else {
while ZLECS.load(SeqCst) > 0
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst) - 1]
!= '\n'
{
ZLECS.fetch_sub(1, SeqCst);
i += 1;
}
}
nn -= 1;
}
if i > 0 {
let text: Vec<char> = ZLELINE
.lock()
.unwrap()
.drain(
ZLECS.load(SeqCst)
..ZLECS.load(SeqCst) + i,
)
.collect();
KILLRING.lock().unwrap().push_front(text);
if KILLRING.lock().unwrap().len() > KILLRINGMAX.load(SeqCst) {
KILLRING.lock().unwrap().pop_back();
}
ZLELL.fetch_sub(i, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
0 }
pub fn transpose_swap(start: usize, middle: usize, end: usize) {
let len1 = middle - start; let len2 = end - middle; let first: Vec<char> = ZLELINE.lock().unwrap()[start..middle].to_vec();
ZLELINE.lock().unwrap().copy_within(middle..end, start);
for (i, &ch) in first.iter().enumerate() {
ZLELINE.lock().unwrap()[start + len2 + i] = ch;
}
let _ = len1;
}
pub fn gosmacstransposechars() -> i32 {
if ZLECS.load(SeqCst) < 2
|| ZLECS.load(SeqCst)
> ZLELL.load(SeqCst)
{
let twice = ZLECS.load(SeqCst) == 0
|| ZLELINE.lock().unwrap().get(
ZLECS
.load(SeqCst)
.saturating_sub(1),
) == Some(&'\n');
if ZLECS.load(SeqCst)
>= ZLELL.load(SeqCst)
|| ZLELINE
.lock()
.unwrap()
.get(ZLECS.load(SeqCst))
== Some(&'\n')
{
return 1;
}
ZLECS.fetch_add(1, SeqCst);
if twice {
if ZLECS.load(SeqCst)
>= ZLELL.load(SeqCst)
|| ZLELINE
.lock()
.unwrap()
.get(ZLECS.load(SeqCst))
== Some(&'\n')
{
return 1;
}
ZLECS.fetch_add(1, SeqCst);
}
}
if ZLECS.load(SeqCst) >= 2
&& ZLECS.load(SeqCst) <= ZLELINE.lock().unwrap().len()
{
ZLELINE.lock().unwrap().swap(
ZLECS.load(SeqCst) - 2,
ZLECS.load(SeqCst) - 1,
);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
0
}
pub fn transposechars() -> i32 {
let mut n = ZMOD.lock().unwrap().mult;
let neg = n < 0; if neg {
n = -n; }
while n > 0 {
n -= 1;
let mut ct = ZLECS.load(SeqCst); if ct == 0
|| ZLELINE.lock().unwrap()[ZLECS.load(SeqCst) - 1] == '\n'
{
if ZLELL.load(SeqCst)
== ZLECS.load(SeqCst)
|| ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)] == '\n'
{
return 1;
}
if !neg {
inccs(); }
incpos(&mut ct); }
if neg {
if ZLECS.load(SeqCst) > 0
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst) - 1]
!= '\n'
{
deccs(); if ct > 1 && ZLELINE.lock().unwrap()[ct - 2] != '\n' {
decpos(&mut ct); }
}
} else if ZLECS.load(SeqCst)
!= ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)] != '\n'
{
inccs(); }
if ct == ZLELL.load(SeqCst)
|| ZLELINE.lock().unwrap()[ct] == '\n'
{
decpos(&mut ct); }
if ct < 1 || ZLELINE.lock().unwrap()[ct - 1] == '\n' {
return 1;
}
ZLELINE.lock().unwrap().swap(ct - 1, ct);
}
0
}
pub fn poundinsert() -> i32 {
ZLECS.store(0, SeqCst); vifirstnonblank(); let at_pound = ZLELINE
.lock()
.unwrap()
.get(ZLECS.load(SeqCst))
== Some(&'#');
if !at_pound {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst), '#');
ZLELL.fetch_add(1, SeqCst);
ZLECS.store(
findeol(),
SeqCst,
);
while ZLECS.load(SeqCst)
!= ZLELL.load(SeqCst)
{
ZLECS.fetch_add(1, SeqCst);
vifirstnonblank();
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst), '#');
ZLELL.fetch_add(1, SeqCst);
ZLECS.store(
findeol(),
SeqCst,
);
}
} else {
ZLELINE
.lock()
.unwrap()
.remove(ZLECS.load(SeqCst));
ZLELL.fetch_sub(1, SeqCst);
ZLECS.store(
findeol(),
SeqCst,
);
while ZLECS.load(SeqCst)
!= ZLELL.load(SeqCst)
{
ZLECS.fetch_add(1, SeqCst);
vifirstnonblank();
if ZLELINE
.lock()
.unwrap()
.get(ZLECS.load(SeqCst))
== Some(&'#')
{
ZLELINE
.lock()
.unwrap()
.remove(ZLECS.load(SeqCst));
ZLELL.fetch_sub(1, SeqCst);
}
ZLECS.store(
findeol(),
SeqCst,
);
}
}
DONE.store(1, SeqCst); ZLE_RESET_NEEDED.store(1, SeqCst);
0 }
pub fn acceptline() -> i32 {
DONE.store(1, SeqCst); 0 }
pub fn acceptandhold() -> i32 {
let zlell = ZLELL.load(SeqCst);
let line: String = ZLELINE.lock().unwrap().iter().take(zlell).collect();
BUFSTACK
.lock()
.unwrap()
.insert(0, line); STACKCS.store(ZLECS.load(SeqCst), SeqCst); DONE.store(1, SeqCst); 0 }
pub fn killline() -> i32 {
let n_orig = ZMOD.lock().unwrap().mult;
if n_orig < 0 {
ZMOD.lock().unwrap().mult = -n_orig;
let ret = backwardkillline();
ZMOD.lock().unwrap().mult = n_orig;
return ret;
}
let mut n = n_orig;
let start = ZLECS.load(SeqCst);
let mut i = 0_usize;
while n > 0 {
if ZLECS.load(SeqCst) < ZLELINE.lock().unwrap().len()
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)] == '\n'
{
ZLECS.fetch_add(1, SeqCst);
i += 1;
} else {
while ZLECS.load(SeqCst)
!= ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)] != '\n'
{
ZLECS.fetch_add(1, SeqCst);
i += 1;
}
}
n -= 1;
}
if i > 0 {
let text: Vec<char> = ZLELINE.lock().unwrap().drain(start..start + i).collect();
KILLRING.lock().unwrap().push_front(text);
if KILLRING.lock().unwrap().len() > KILLRINGMAX.load(SeqCst) {
KILLRING.lock().unwrap().pop_back();
}
ZLELL.fetch_sub(i, SeqCst);
ZLECS.store(start, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
0 }
pub fn regionlines() -> (usize, usize) {
let origcs = ZLECS.load(SeqCst);
let start;
let end;
if ZLECS.load(SeqCst)
< MARK.load(SeqCst)
{
start = findbol();
ZLECS.store(
if MARK.load(SeqCst)
> ZLELL.load(SeqCst)
{
ZLELL.load(SeqCst)
} else {
MARK.load(SeqCst)
},
SeqCst,
);
end = findeol();
} else {
end = findeol();
ZLECS.store(
MARK.load(SeqCst),
SeqCst,
);
start = findbol();
}
ZLECS.store(origcs, SeqCst);
(start, end)
}
pub fn killregion() -> i32 {
if MARK.load(SeqCst)
> ZLELL.load(SeqCst)
{
MARK.store(
ZLELL.load(SeqCst),
SeqCst,
);
}
let (start, end) = if MARK
.load(SeqCst)
> ZLECS.load(SeqCst)
{
(
ZLECS.load(SeqCst),
MARK.load(SeqCst),
)
} else {
(
MARK.load(SeqCst),
ZLECS.load(SeqCst),
)
};
if start < end {
let text: Vec<char> = ZLELINE.lock().unwrap().drain(start..end).collect();
KILLRING.lock().unwrap().push_front(text);
if KILLRING.lock().unwrap().len() > KILLRINGMAX.load(SeqCst) {
KILLRING.lock().unwrap().pop_back();
}
ZLELL.fetch_sub(end - start, SeqCst);
ZLECS.store(start, SeqCst);
MARK.store(start, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
0
}
pub fn copyregionaskill(args: &[String]) -> i32 {
if let Some(arg) = args.first() {
let text: Vec<char> = arg.chars().collect();
KILLRING.lock().unwrap().push_front(text);
if KILLRING.lock().unwrap().len() > KILLRINGMAX.load(SeqCst) {
KILLRING.lock().unwrap().pop_back();
}
return 0;
}
if MARK.load(SeqCst)
> ZLELL.load(SeqCst)
{
MARK.store(
ZLELL.load(SeqCst),
SeqCst,
);
}
let (start, end) = if MARK
.load(SeqCst)
> ZLECS.load(SeqCst)
{
(
ZLECS.load(SeqCst),
MARK.load(SeqCst),
)
} else {
(
MARK.load(SeqCst),
ZLECS.load(SeqCst),
)
};
let text: Vec<char> = ZLELINE.lock().unwrap()[start..end].to_vec();
KILLRING.lock().unwrap().push_front(text);
if KILLRING.lock().unwrap().len() > KILLRINGMAX.load(SeqCst) {
KILLRING.lock().unwrap().pop_back();
}
0
}
pub fn yank() {
if let Some(text) = KILLRING.lock().unwrap().front() {
MARK.store(
ZLECS.load(SeqCst),
SeqCst,
);
for &c in text {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst), c);
ZLECS.fetch_add(1, SeqCst);
}
ZLELL.store(
ZLELINE.lock().unwrap().len(),
SeqCst,
);
YANKLAST.store(true, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
}
pub fn pastebuf(buf: &[char], mult: i32, position: i32) -> i32 {
if buf.is_empty() {
return 0;
}
if position == 1
&& ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
{
ZLECS.fetch_add(1, SeqCst);
}
YANKB.store(
ZLECS.load(SeqCst),
SeqCst,
);
let mut n = mult;
while n > 0 {
for (i, &c) in buf.iter().enumerate() {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst) + i, c);
}
ZLECS.fetch_add(buf.len(), SeqCst);
ZLELL.fetch_add(buf.len(), SeqCst);
n -= 1;
}
YANKE.store(
ZLECS.load(SeqCst),
SeqCst,
);
if ZLECS.load(SeqCst) > 0
&& *crate::ported::zle::zle_keymap::curkeymapname() == "vicmd"
{
ZLECS.fetch_sub(1, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
0
}
pub fn viputbefore() -> i32 {
let n = ZMOD.lock().unwrap().mult; startvichange(-1); if n < 0 {
return 1; }
if ZMOD.lock().unwrap().flags & MOD_NULL != 0 {
return 0; }
let buf: Vec<char> = if ZMOD.lock().unwrap().flags & MOD_VIBUF != 0 {
let idx = ZMOD.lock().unwrap().vibuf as usize;
if idx >= vibuf().lock().unwrap().len() {
return 1;
}
vibuf().lock().unwrap()[idx].clone() } else {
KILLRING
.lock()
.unwrap()
.front()
.cloned()
.unwrap_or_default() };
if buf.is_empty() {
return 1; }
pastebuf(&buf, n, 0) }
pub fn viputafter() -> i32 {
let n = ZMOD.lock().unwrap().mult; startvichange(-1); if n < 0 {
return 1; }
if ZMOD.lock().unwrap().flags & MOD_NULL != 0 {
return 0; }
let buf: Vec<char> = if ZMOD.lock().unwrap().flags & MOD_VIBUF != 0 {
let idx = ZMOD.lock().unwrap().vibuf as usize;
if idx >= vibuf().lock().unwrap().len() {
return 1;
}
vibuf().lock().unwrap()[idx].clone() } else {
KILLRING
.lock()
.unwrap()
.front()
.cloned()
.unwrap_or_default() };
if buf.is_empty() {
return 1; }
pastebuf(&buf, n, 1) }
pub fn putreplaceselection() -> i32 {
let n = ZMOD.lock().unwrap().mult; let mut pos = 2; startvichange(-1); if n < 0 || ZMOD.lock().unwrap().flags & MOD_NULL != 0 {
return 1; }
let prevbuf: Vec<char> = if ZMOD.lock().unwrap().flags & MOD_VIBUF != 0 {
let idx = ZMOD.lock().unwrap().vibuf as usize;
if idx >= vibuf().lock().unwrap().len() {
return 1;
}
vibuf().lock().unwrap()[idx].clone() } else {
KILLRING
.lock()
.unwrap()
.front()
.cloned()
.unwrap_or_default() };
if prevbuf.is_empty() {
return 1; }
ZMOD.lock().unwrap().flags = 0; if REGION_ACTIVE.load(SeqCst) == 2 {
pos = if ZLELL.load(SeqCst)
== ZLECS.load(SeqCst)
{
1
} else {
0
};
}
let _ = killregion(); pastebuf(&prevbuf, n, pos) }
pub fn yankpop() -> i32 {
let last =
LASTCMD.load(SeqCst) as i32;
if (last & ZLE_YANK) == 0 || KILLRING.lock().unwrap().is_empty() {
return 1;
}
let prev_start = YANKB.load(SeqCst);
let prev_end = YANKE.load(SeqCst);
if prev_end > prev_start && prev_end <= ZLELINE.lock().unwrap().len() {
ZLELINE.lock().unwrap().drain(prev_start..prev_end);
ZLELL.fetch_sub(prev_end - prev_start, SeqCst);
ZLECS.store(prev_start, SeqCst);
}
if let Some(top) = KILLRING.lock().unwrap().pop_front() {
KILLRING.lock().unwrap().push_back(top);
}
if let Some(next) = KILLRING.lock().unwrap().front().cloned() {
for (i, &c) in next.iter().enumerate() {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst) + i, c);
}
YANKB.store(
ZLECS.load(SeqCst),
SeqCst,
);
ZLECS.fetch_add(next.len(), SeqCst);
ZLELL.fetch_add(next.len(), SeqCst);
YANKE.store(
ZLECS.load(SeqCst),
SeqCst,
);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
0
}
pub fn bracketedstring() -> String {
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
if fd < 0 {
return String::new();
}
const ENDESC: &[u8] = b"\x1b[201~"; let mut pbuf: Vec<u8> = Vec::with_capacity(64); let mut endpos: usize = 0;
let mut stdin = std::io::stdin();
let deadline_per_byte = std::time::Duration::from_secs(1);
while endpos < ENDESC.len() {
let mut buf = [0u8; 1];
let start = std::time::Instant::now();
let next: u8 = loop {
match stdin.read(&mut buf) {
Ok(1) => break buf[0], Ok(_) => return String::from_utf8_lossy(&pbuf).into_owned(), Err(_) if start.elapsed() < deadline_per_byte => {
std::thread::sleep(std::time::Duration::from_millis(10));
continue;
}
Err(_) => return String::from_utf8_lossy(&pbuf).into_owned(),
}
};
if endpos == 0 || next != ENDESC[endpos] {
endpos = if next == ENDESC[0] { 1 } else { 0 };
} else {
endpos += 1;
}
if (next & 0x80) != 0 && next != 0xff {
pbuf.push(0x83); pbuf.push(next ^ 32); } else if next == b'\r' {
pbuf.push(b'\n'); } else {
pbuf.push(next); }
}
let strip = endpos.min(pbuf.len());
pbuf.truncate(pbuf.len() - strip);
String::from_utf8_lossy(&pbuf).into_owned()
}
pub fn bracketedpaste(args: &[String]) -> i32 {
let pbuf = bracketedstring(); if let Some(name) = args.first() {
std::env::set_var(name, &pbuf);
return 0;
}
let payload = if ZMOD.lock().unwrap().mult == 1 {
pbuf.clone()
} else {
quotestring(&pbuf, QT_SINGLE_OPTIONAL) };
let wpaste: Vec<char> = payload.chars().collect();
if !ZMOD.lock().unwrap().flags & MOD_VIBUF != 0 {
ZMOD.lock().unwrap().mult = 1; if REGION_ACTIVE.load(SeqCst) != 0 {
let _ = killregion();
}
for c in wpaste.iter().copied() {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst), c);
ZLECS.fetch_add(1, SeqCst);
ZLELL.fetch_add(1, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
}
0 }
pub fn overwritemode() -> i32 {
INSMODE.fetch_xor(1, SeqCst); 0 }
pub fn whatcursorposition() -> i32 {
let bol = findbol(); let mut msg = String::with_capacity(100);
if ZLECS.load(SeqCst)
== ZLELL.load(SeqCst)
{
msg.push_str("EOF"); } else {
msg.push_str("Char: "); let c = ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)]; match c {
' ' => msg.push_str("SPC"), '\t' => msg.push_str("TAB"), '\n' => msg.push_str("LFD"), _ => msg.push(c), }
let cu = c as u32;
msg.push_str(&format!(" (0{:o}, {}, 0x{:x})", cu, cu, cu)); }
let pct = if ZLELL.load(SeqCst) > 0 {
100 * ZLECS.load(SeqCst)
/ ZLELL.load(SeqCst)
} else {
0
};
msg.push_str(&format!(
" point {} of {}({}%) column {}",
ZLECS.load(SeqCst) + 1,
ZLELL.load(SeqCst) + 1,
pct,
ZLECS.load(SeqCst) - bol,
)); showmsg(&msg);
0
}
pub fn undefinedkey() -> i32 {
1
}
pub fn quotedinsert() -> i32 {
let _ = getfullchar(false);
if LASTCHAR.load(SeqCst) < 0 {
return 1;
}
selfinsert() }
pub fn parsedigit(inkey: i32) -> i32 {
let inkey = inkey & 0x7f;
let base = ZMOD.lock().unwrap().base;
if base > 10 {
if (b'a' as i32..b'a' as i32 + base - 10).contains(&inkey) {
return inkey - b'a' as i32 + 10; }
if (b'A' as i32..b'A' as i32 + base - 10).contains(&inkey) {
return inkey - b'A' as i32 + 10; }
if (b'0' as i32..=b'9' as i32).contains(&inkey) {
return inkey - b'0' as i32;
}
return -1; }
if (b'0' as i32..b'0' as i32 + base).contains(&inkey) {
return inkey - b'0' as i32;
}
-1 }
pub fn digitargument() -> i32 {
let sign: i32 = if ZMOD.lock().unwrap().mult < 0 { -1 } else { 1 };
let newdigit = parsedigit(
LASTCHAR.load(SeqCst),
);
if newdigit < 0 {
return 1; }
if !ZMOD.lock().unwrap().flags & MOD_TMULT != 0 {
ZMOD.lock().unwrap().tmult = 0;
}
if ZMOD.lock().unwrap().flags & MOD_NEG != 0 {
ZMOD.lock().unwrap().tmult = sign * newdigit;
ZMOD.lock().unwrap().flags &= !MOD_NEG;
} else {
let mut __g_zmod = ZMOD.lock().unwrap();
__g_zmod.tmult = __g_zmod.tmult * __g_zmod.base + sign * newdigit;
}
ZMOD.lock().unwrap().flags |= MOD_TMULT; PREFIXFLAG.store(1, SeqCst); 0 }
pub fn negargument() -> i32 {
if ZMOD.lock().unwrap().flags & MOD_TMULT != 0 {
return 1; }
ZMOD.lock().unwrap().tmult = -1; ZMOD.lock().unwrap().flags |= MOD_TMULT | MOD_NEG; PREFIXFLAG.store(1, SeqCst); 0 }
pub fn universalargument(args: &[String]) -> i32 {
if let Some(a) = args.first() {
if let Ok(n) = a.parse::<i32>() {
ZMOD.lock().unwrap().mult = n;
ZMOD.lock().unwrap().flags |= MOD_MULT;
return 0;
}
}
let digcnt = 0;
if digcnt == 0 {
ZMOD.lock().unwrap().tmult = ZMOD.lock().unwrap().tmult.saturating_mul(4);
}
ZMOD.lock().unwrap().flags |= MOD_TMULT; PREFIXFLAG.store(1, SeqCst); 0
}
pub fn argumentbase(args: &[String]) -> i32 {
let multbase = if let Some(arg) = args.first() {
let s = arg.as_str();
if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
i32::from_str_radix(hex, 16).unwrap_or(0)
} else if s.starts_with('0') && s.len() > 1 {
i32::from_str_radix(&s[1..], 8).unwrap_or(0)
} else {
s.parse::<i32>().unwrap_or(0)
}
} else {
ZMOD.lock().unwrap().mult };
if multbase < 2 || multbase > 36 {
return 1;
}
ZMOD.lock().unwrap().base = multbase; ZMOD.lock().unwrap().flags = 0;
ZMOD.lock().unwrap().mult = 1;
ZMOD.lock().unwrap().tmult = 1;
ZMOD.lock().unwrap().vibuf = 0;
PREFIXFLAG.store(1, SeqCst);
0 }
pub fn copyprevword() -> i32 {
let n = ZMOD.lock().unwrap().mult;
if n <= 0 {
return 1;
}
let is_word = |c: char| c.is_alphanumeric() || c == '_';
let mut t0 = ZLECS.load(SeqCst);
for _ in 0..n {
while t0 > 0 && !is_word(ZLELINE.lock().unwrap()[t0 - 1]) {
t0 -= 1;
}
while t0 > 0 && is_word(ZLELINE.lock().unwrap()[t0 - 1]) {
t0 -= 1;
}
}
let mut t1 = t0;
while t1 < ZLECS.load(SeqCst)
&& is_word(ZLELINE.lock().unwrap()[t1])
{
t1 += 1;
}
let len = t1 - t0;
if len == 0 {
return 1;
}
let copied: Vec<char> = ZLELINE.lock().unwrap()[t0..t1].to_vec();
for (i, &c) in copied.iter().enumerate() {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst) + i, c);
}
ZLECS.fetch_add(len, SeqCst);
ZLELL.fetch_add(len, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
0
}
pub fn copyprevshellword() -> i32 {
let mut t1 = ZLECS.load(SeqCst);
while t1 > 0 && ZLELINE.lock().unwrap()[t1 - 1].is_whitespace() {
t1 -= 1;
}
let mut t0 = t1;
while t0 > 0 && !ZLELINE.lock().unwrap()[t0 - 1].is_whitespace() {
t0 -= 1;
}
if t0 == t1 {
return 1;
}
let copied: Vec<char> = ZLELINE.lock().unwrap()[t0..t1].to_vec();
for (i, &c) in copied.iter().enumerate() {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst) + i, c);
}
ZLECS.fetch_add(copied.len(), SeqCst);
ZLELL.fetch_add(copied.len(), SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
0
}
pub fn sendbreak() -> i32 {
errflag.fetch_or(
ERRFLAG_ERROR | ERRFLAG_INT,
Ordering::Relaxed,
); 1 }
pub fn quoteregion() -> i32 {
let mut extra = *crate::ported::zle::zle_keymap::curkeymapname() == "vicmd";
if MARK.load(SeqCst)
> ZLELL.load(SeqCst)
{
MARK.store(
ZLELL.load(SeqCst),
SeqCst,
);
}
if REGION_ACTIVE.load(SeqCst) == 2 {
let (a, b) = regionlines();
ZLECS.store(a, SeqCst);
MARK.store(b, SeqCst);
extra = false;
} else if MARK.load(SeqCst)
< ZLECS.load(SeqCst)
{
std::mem::swap(
&mut MARK.load(SeqCst),
&mut ZLECS.load(SeqCst),
);
}
if extra
&& MARK.load(SeqCst)
< ZLELL.load(SeqCst)
{
MARK.fetch_add(1, SeqCst);
}
let region: Vec<char> = ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)
..MARK.load(SeqCst)]
.to_vec();
let len = region.len();
let quoted = makequote(®ion);
let qlen = quoted.len();
ZLELINE.lock().unwrap().drain(
ZLECS.load(SeqCst)
..ZLECS.load(SeqCst) + len,
);
ZLELL.fetch_sub(len, SeqCst);
for (i, &c) in quoted.iter().enumerate() {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst) + i, c);
}
ZLELL.fetch_add(qlen, SeqCst);
MARK.store(
ZLECS.load(SeqCst),
SeqCst,
);
ZLECS.fetch_add(qlen, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
0
}
pub fn quoteline() -> i32 {
let quoted =
makequote(&ZLELINE.lock().unwrap()[..ZLELL.load(SeqCst)]);
let len = quoted.len();
*ZLELINE.lock().unwrap() = quoted;
ZLELL.store(len, SeqCst);
ZLECS.store(len, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
0 }
pub fn makequote(s: &[char]) -> Vec<char> {
let qtct = s.iter().filter(|&&c| c == '\'').count();
let mut out = Vec::<char>::with_capacity(s.len() + 2 + qtct * 3);
out.push('\''); for &c in s {
if c == '\'' {
out.push('\'');
out.push('\\');
out.push('\'');
out.push('\'');
} else {
out.push(c);
}
}
out.push('\''); out
}
pub static namedcmdstr: std::sync::Mutex<String> = std::sync::Mutex::new(String::new());
pub static namedcmdll: std::sync::Mutex<Vec<String>> = std::sync::Mutex::new(Vec::new());
pub static namedcmdambig: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
pub fn scancompcmd(name: &str) -> i32 {
let prefix = namedcmdstr.lock().unwrap().clone();
if !name.starts_with(&prefix) {
return 0;
}
let mut ll = namedcmdll.lock().unwrap();
let first = ll.first().cloned();
ll.push(name.to_string()); if let Some(f) = first {
let l = f
.bytes()
.zip(name.bytes())
.take_while(|(a, b)| a == b)
.count();
if l < namedcmdambig.load(Ordering::Relaxed) {
namedcmdambig.store(l, Ordering::Relaxed); }
} else {
namedcmdambig.store(name.len(), Ordering::Relaxed);
}
0
}
pub const NAMLEN: usize = 60;
pub fn executenamedcommand(prompt: &str) -> Option<String> {
let _ = prompt;
crate::ported::params::getsparam("REPLY") .filter(|s| !s.is_empty())
}
#[derive(Debug, Clone, Default)]
#[allow(non_camel_case_types)]
pub struct suffixset {
pub tp: i32,
pub flags: i32,
pub chars: Vec<char>,
pub lenstr: i32,
pub lensuf: i32,
}
pub fn addsuffix(tp: i32, flags: i32, chars: Vec<char>, lenstr: i32, lensuf: i32) {
let newsuf = suffixset {
tp, flags, chars: if lenstr != 0 { chars } else { Vec::new() }, lenstr, lensuf, };
suffixlist().lock().unwrap().insert(0, newsuf);
}
pub fn addsuffixstring(tp: i32, flags: i32, chars: &str, lensuf: i32) {
let chars_vec: Vec<char> = chars.chars().collect();
let slen = chars_vec.len() as i32;
addsuffix(tp, flags, chars_vec, slen, lensuf);
}
pub fn makesuffix(n: i32) {
let suffix_chars = crate::ported::params::getsparam("ZLE_REMOVE_SUFFIX_CHARS")
.unwrap_or_else(|| " \t\n;&|".to_string()); addsuffixstring(0, 0, &suffix_chars, n); }
pub fn makeparamsuffix(br: i32, n: i32) {
let charstr: Vec<char> = ":[#%?-+=".chars().collect();
let kshcheck = !isset(KSHARRAYS);
let lenstr = if br != 0 || kshcheck {
2
} else {
charstr.len() as i32
};
let prefix: Vec<char> = charstr.iter().take(lenstr as usize).copied().collect();
addsuffix(0, 0, prefix, lenstr, n);
}
pub static suffixfunc: std::sync::Mutex<Option<String>> =
std::sync::Mutex::new(None);
pub static suffixnoinsrem: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(0);
pub static suffixlen: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(0);
pub fn makesuffixstr(f: Option<&str>, s: Option<&str>, n: i32) {
if let Some(f_str) = f { if let Ok(mut g) = suffixfunc.lock() {
*g = Some(f_str.to_string()); }
suffixlen.store(n, std::sync::atomic::Ordering::Relaxed); } else if let Some(s_str) = s { let mut inv: i32; let _i: usize; let mut z: i32 = 0; let s_iter_start; if s_str.starts_with('^') || s_str.starts_with('!') { inv = 1; s_iter_start = &s_str[1..]; } else {
inv = 0; s_iter_start = s_str;
}
let (decoded, consumed) =
crate::ported::utils::getkeystring(s_iter_start);
if s_iter_start.contains("\\-") { z = 1;
}
let _ = consumed;
let ws = crate::ported::zle::zle_utils::stringaszleline(&decoded);
let mut i: usize = ws.len();
suffixnoinsrem.store(z ^ inv, std::sync::atomic::Ordering::Relaxed); suffixlen.store(n, std::sync::atomic::Ordering::Relaxed);
let mut lasts: usize = 0; let mut wptr: usize = 0; while i > 0 { if i >= 3 && ws.get(wptr + 1) == Some(&'-') { if wptr > lasts { let span: Vec<char> = ws[lasts..wptr].to_vec();
let lenstr = (wptr - lasts) as i32;
addsuffix(
if inv != 0 { SUFTYP_NEGSTR } else { SUFTYP_POSSTR },
0,
span,
lenstr,
n,
); }
let mut s_arr: Vec<char> = Vec::with_capacity(2); s_arr.push(ws[wptr]); s_arr.push(ws[wptr + 2]); addsuffix(
if inv != 0 { SUFTYP_NEGRNG } else { SUFTYP_POSRNG },
0,
s_arr,
2,
n,
);
wptr += 3; i -= 3; lasts = wptr; } else {
wptr += 1; i -= 1; if i == 0 && wptr == ws.len() {
}
if wptr >= ws.len() {
break;
}
}
}
if wptr > lasts { let span: Vec<char> = ws[lasts..wptr].to_vec();
let lenstr = (wptr - lasts) as i32;
addsuffix(
if inv != 0 { SUFTYP_NEGSTR } else { SUFTYP_POSSTR },
0,
span,
lenstr,
n,
); }
let _ = (lasts, wptr);
inv += 0;
let _ = inv;
} else {
makesuffix(n); }
}
pub fn iremovesuffix(c: i32, keep: i32) -> i32 {
let sf = SUFFIXFUNC
.get_or_init(|| std::sync::Mutex::new(String::new()))
.lock()
.map(|g| g.clone())
.unwrap_or_default();
if !sf.is_empty() {
let _exists = crate::ported::utils::getshfunc(&sf);
if let Ok(mut g) = SUFFIXFUNC
.get_or_init(|| std::sync::Mutex::new(String::new()))
.lock()
{
g.clear();
}
}
let list = suffixlist().lock().map(|g| g.clone()).unwrap_or_default();
let mut sl: i32 = 0;
let ch = c as u32;
for entry in list.iter() {
let matched = entry.chars.iter().any(|&x| x as u32 == ch);
if matched {
if keep == 0 {
sl = entry.lensuf;
} break;
}
}
if sl > 0 && keep == 0 {
let cs = ZLECS_C.load(Ordering::Relaxed) as usize;
let drop_n = (sl as usize).min(cs);
let new_cs = cs - drop_n;
if let Ok(mut g) = ZLELINE_C
.get_or_init(|| std::sync::Mutex::new(String::new()))
.lock()
{
if new_cs <= g.len() && drop_n <= cs {
g.drain(new_cs..cs);
}
ZLELL_C.store(g.len() as i32, Ordering::Relaxed);
}
ZLECS_C.store(new_cs as i32, Ordering::Relaxed);
}
fixsuffix();
0 }
pub fn fixsuffix() {
suffixlist().lock().unwrap().clear();
SUFFIXLEN.store(0, SeqCst);
}
pub static DONE: AtomicI32 = AtomicI32::new(0);
pub static SUFFIXLEN: AtomicI32 = AtomicI32::new(0);
pub static SUFFIXLIST: std::sync::OnceLock<std::sync::Mutex<Vec<suffixset>>> =
std::sync::OnceLock::new();
pub static SUFFIXNOINSREM: AtomicI32 = AtomicI32::new(0);
pub static VFINDCHAR: AtomicI32 = AtomicI32::new(0);
pub static VFINDDIR: AtomicI32 = AtomicI32::new(0); pub static TAILADD: AtomicI32 = AtomicI32::new(0);
pub static KCT: AtomicI32 = AtomicI32::new(-1);
pub static YANKCS: AtomicI32 = AtomicI32::new(0);
pub static NAMEDCMDAMBIG: AtomicI32 = AtomicI32::new(0);
pub static PREDISPLAY: std::sync::OnceLock<std::sync::Mutex<String>> = std::sync::OnceLock::new();
pub static POSTDISPLAY: std::sync::OnceLock<std::sync::Mutex<String>> = std::sync::OnceLock::new();
pub static PREVIOUS_SEARCH: std::sync::OnceLock<std::sync::Mutex<String>> =
std::sync::OnceLock::new();
pub static PREVIOUS_ABORTED_SEARCH: std::sync::OnceLock<std::sync::Mutex<String>> =
std::sync::OnceLock::new();
pub static SUFFIXFUNC: std::sync::OnceLock<std::sync::Mutex<String>> = std::sync::OnceLock::new();
pub fn self_insert(c: char) {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst), c);
ZLECS.fetch_add(1, SeqCst);
ZLELL.fetch_add(1, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn accept_line() -> String {
ZLELINE.lock().unwrap().iter().collect()
}
pub fn accept_and_hold() -> String {
ZLELINE.lock().unwrap().iter().collect()
}
pub fn kill_buffer() {
if !ZLELINE.lock().unwrap().is_empty() {
let text: Vec<char> = ZLELINE.lock().unwrap().drain(..).collect();
KILLRING.lock().unwrap().push_front(text);
if KILLRING.lock().unwrap().len() > KILLRINGMAX.load(SeqCst) {
KILLRING.lock().unwrap().pop_back();
}
ZLELL.store(0, SeqCst);
ZLECS.store(0, SeqCst);
MARK.store(0, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
}
pub fn kill_whole_line() {
kill_buffer();
}
pub fn exchange_point_and_mark() {
std::mem::swap(
&mut ZLECS.load(SeqCst),
&mut MARK.load(SeqCst),
);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn set_mark_here() {
MARK.store(
ZLECS.load(SeqCst),
SeqCst,
);
}
pub fn kill_region() {
let (start, end) = if ZLECS.load(SeqCst)
< MARK.load(SeqCst)
{
(
ZLECS.load(SeqCst),
MARK.load(SeqCst),
)
} else {
(
MARK.load(SeqCst),
ZLECS.load(SeqCst),
)
};
let text: Vec<char> = ZLELINE.lock().unwrap().drain(start..end).collect();
KILLRING.lock().unwrap().push_front(text);
if KILLRING.lock().unwrap().len() > KILLRINGMAX.load(SeqCst) {
KILLRING.lock().unwrap().pop_back();
}
ZLELL.fetch_sub(end - start, SeqCst);
ZLECS.store(start, SeqCst);
MARK.store(start, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn yank_pop() {
if !YANKLAST.load(SeqCst)
|| KILLRING.lock().unwrap().is_empty()
{
return;
}
let prev_len = KILLRING
.lock()
.unwrap()
.front()
.map(|v| v.len())
.unwrap_or(0);
let start = MARK.load(SeqCst);
for _ in 0..prev_len {
if start < ZLELINE.lock().unwrap().len() {
ZLELINE.lock().unwrap().remove(start);
}
}
ZLECS.store(start, SeqCst);
ZLELL.store(
ZLELINE.lock().unwrap().len(),
SeqCst,
);
if let Some(front) = KILLRING.lock().unwrap().pop_front() {
KILLRING.lock().unwrap().push_back(front);
}
if let Some(text) = KILLRING.lock().unwrap().front() {
for &c in text {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst), c);
ZLECS.fetch_add(1, SeqCst);
}
ZLELL.store(
ZLELINE.lock().unwrap().len(),
SeqCst,
);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn transpose_chars() {
if ZLECS.load(SeqCst) == 0
|| ZLELL.load(SeqCst) < 2
{
return;
}
let pos = if ZLECS.load(SeqCst)
== ZLELL.load(SeqCst)
{
ZLECS.load(SeqCst) - 1
} else {
ZLECS.load(SeqCst)
};
if pos > 0 {
ZLELINE.lock().unwrap().swap(pos - 1, pos);
ZLECS.store(pos + 1, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
}
pub fn capitalize_word() {
while ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
&& !ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)]
.is_alphanumeric()
{
ZLECS.fetch_add(1, SeqCst);
}
if ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)].is_alphabetic()
{
{
let mut __g = ZLELINE.lock().unwrap();
__g[ZLECS.load(SeqCst)] = __g
[ZLECS.load(SeqCst)]
.to_uppercase()
.next()
.unwrap_or(__g[ZLECS.load(SeqCst)]);
}
ZLECS.fetch_add(1, SeqCst);
}
while ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)]
.is_alphanumeric()
{
{
let mut __g = ZLELINE.lock().unwrap();
__g[ZLECS.load(SeqCst)] = __g
[ZLECS.load(SeqCst)]
.to_lowercase()
.next()
.unwrap_or(__g[ZLECS.load(SeqCst)]);
}
ZLECS.fetch_add(1, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn downcase_word() {
while ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
&& !ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)]
.is_alphanumeric()
{
ZLECS.fetch_add(1, SeqCst);
}
while ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)]
.is_alphanumeric()
{
{
let mut __g = ZLELINE.lock().unwrap();
__g[ZLECS.load(SeqCst)] = __g
[ZLECS.load(SeqCst)]
.to_lowercase()
.next()
.unwrap_or(__g[ZLECS.load(SeqCst)]);
}
ZLECS.fetch_add(1, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn upcase_word() {
while ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
&& !ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)]
.is_alphanumeric()
{
ZLECS.fetch_add(1, SeqCst);
}
while ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)]
.is_alphanumeric()
{
{
let mut __g = ZLELINE.lock().unwrap();
__g[ZLECS.load(SeqCst)] = __g
[ZLECS.load(SeqCst)]
.to_uppercase()
.next()
.unwrap_or(__g[ZLECS.load(SeqCst)]);
}
ZLECS.fetch_add(1, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn transpose_words() {
if ZLELL.load(SeqCst) < 3 {
return;
}
let mut end2 = ZLECS.load(SeqCst);
while end2 < ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[end2].is_alphanumeric()
{
end2 += 1;
}
while end2 < ZLELL.load(SeqCst)
&& !ZLELINE.lock().unwrap()[end2].is_alphanumeric()
{
end2 += 1;
}
while end2 < ZLELL.load(SeqCst)
&& ZLELINE.lock().unwrap()[end2].is_alphanumeric()
{
end2 += 1;
}
let mut start2 = end2;
while start2 > 0 && ZLELINE.lock().unwrap()[start2 - 1].is_alphanumeric() {
start2 -= 1;
}
let mut end1 = start2;
while end1 > 0 && !ZLELINE.lock().unwrap()[end1 - 1].is_alphanumeric() {
end1 -= 1;
}
let mut start1 = end1;
while start1 > 0 && ZLELINE.lock().unwrap()[start1 - 1].is_alphanumeric() {
start1 -= 1;
}
if start1 < end1 && start2 < end2 {
let word1: Vec<char> = ZLELINE.lock().unwrap()[start1..end1].to_vec();
let word2: Vec<char> = ZLELINE.lock().unwrap()[start2..end2].to_vec();
ZLELINE.lock().unwrap().drain(start2..end2);
for (i, c) in word1.iter().enumerate() {
ZLELINE.lock().unwrap().insert(start2 + i, *c);
}
let new_end1 = end1 - (end2 - start2) + word1.len();
let _new_start1 = start1;
ZLELINE.lock().unwrap().drain(start1..end1);
for (i, c) in word2.iter().enumerate() {
ZLELINE.lock().unwrap().insert(start1 + i, *c);
}
ZLELL.store(
ZLELINE.lock().unwrap().len(),
SeqCst,
);
ZLECS.store(new_end1, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
}
pub fn quote_line() {
ZLELINE.lock().unwrap().insert(0, '\'');
ZLELL.fetch_add(1, SeqCst);
ZLECS.fetch_add(1, SeqCst);
ZLELINE.lock().unwrap().push('\'');
ZLELL.fetch_add(1, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn quote_region() {
let (start, end) = if ZLECS.load(SeqCst)
< MARK.load(SeqCst)
{
(
ZLECS.load(SeqCst),
MARK.load(SeqCst),
)
} else {
(
MARK.load(SeqCst),
ZLECS.load(SeqCst),
)
};
ZLELINE.lock().unwrap().insert(end, '\'');
ZLELINE.lock().unwrap().insert(start, '\'');
ZLELL.fetch_add(2, SeqCst);
ZLECS.store(end + 2, SeqCst);
MARK.store(start, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn what_cursor_position() -> String {
if ZLECS.load(SeqCst)
>= ZLELL.load(SeqCst)
{
return format!(
"point={} of {} (EOL)",
ZLECS.load(SeqCst),
ZLELL.load(SeqCst)
);
}
let c = ZLELINE.lock().unwrap()[ZLECS.load(SeqCst)];
let code = c as u32;
format!(
"Char: {} (0{:o}, {:?}, 0x{:x}) point {} of {} ({}%)",
c,
code,
code,
code,
ZLECS.load(SeqCst),
ZLELL.load(SeqCst),
(ZLECS.load(SeqCst) * 100)
.checked_div(ZLELL.load(SeqCst))
.unwrap_or(0)
)
}
pub fn digit_argument(digit: u8) {
if MULT.load(SeqCst) == 1
&& !NEG_ARG.load(SeqCst)
{
MULT.store(0, SeqCst);
}
MULT.store(
MULT.load(SeqCst)
.saturating_mul(10)
.saturating_add(digit as i32),
SeqCst,
);
}
pub fn neg_argument() {
NEG_ARG.store(
!NEG_ARG.load(SeqCst),
SeqCst,
);
}
pub fn undefined_key() {
print!("\x07"); }
pub fn send_break() {
ZLELINE.lock().unwrap().clear();
ZLELL.store(0, SeqCst);
ZLECS.store(0, SeqCst);
MARK.store(0, SeqCst);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn vi_put_after() {
if ZLECS.load(SeqCst)
< ZLELL.load(SeqCst)
{
ZLECS.fetch_add(1, SeqCst);
}
yank();
if ZLECS.load(SeqCst) > 0 {
ZLECS.fetch_sub(1, SeqCst);
}
}
pub fn vi_put_before() {
yank();
}
pub fn overwrite_mode() {
INSMODE.fetch_xor(1, SeqCst);
}
pub fn copy_prev_word() {
if ZLECS.load(SeqCst) == 0 {
return;
}
let mut end = ZLECS.load(SeqCst);
while end > 0 && ZLELINE.lock().unwrap()[end - 1].is_whitespace() {
end -= 1;
}
let mut start = end;
while start > 0 && !ZLELINE.lock().unwrap()[start - 1].is_whitespace() {
start -= 1;
}
if start < end {
let word: Vec<char> = ZLELINE.lock().unwrap()[start..end].to_vec();
for c in word {
ZLELINE
.lock()
.unwrap()
.insert(ZLECS.load(SeqCst), c);
ZLECS.fetch_add(1, SeqCst);
}
ZLELL.store(
ZLELINE.lock().unwrap().len(),
SeqCst,
);
ZLE_RESET_NEEDED.store(1, SeqCst);
}
}
pub fn copy_prev_shell_word() {
copy_prev_word();
}
pub fn pound_insert() {
if !ZLELINE.lock().unwrap().is_empty() && ZLELINE.lock().unwrap()[0] == '#' {
ZLELINE.lock().unwrap().remove(0);
ZLELL.fetch_sub(1, SeqCst);
if ZLECS.load(SeqCst) > 0 {
ZLECS.fetch_sub(1, SeqCst);
}
} else {
ZLELINE.lock().unwrap().insert(0, '#');
ZLELL.fetch_add(1, SeqCst);
ZLECS.fetch_add(1, SeqCst);
}
ZLE_RESET_NEEDED.store(1, SeqCst);
}
pub fn processcmd(_args: &[String]) -> i32 {
crate::ported::zle::zle_tricky::processcmd()
}
fn suffixlist() -> &'static std::sync::Mutex<Vec<suffixset>> {
SUFFIXLIST.get_or_init(|| std::sync::Mutex::new(Vec::new()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn acceptline_sets_done() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
DONE.store(0, SeqCst);
let r = acceptline();
assert_eq!(r, 0);
assert_eq!(DONE.load(SeqCst), 1);
}
#[test]
fn undefinedkey_returns_one() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(undefinedkey(), 1);
}
#[test]
fn sendbreak_sets_errflag_and_returns_one() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
errflag.store(0, Ordering::Relaxed);
let r = sendbreak();
assert_eq!(r, 1);
let f = errflag.load(Ordering::Relaxed);
assert_ne!(f & ERRFLAG_ERROR, 0);
assert_ne!(f & ERRFLAG_INT, 0);
errflag.store(0, Ordering::Relaxed);
}
#[test]
fn sendbreak_preserves_existing_errflag_bits() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
errflag.store(0x1000, Ordering::Relaxed); sendbreak();
let f = errflag.load(Ordering::Relaxed);
assert_ne!(f & 0x1000, 0);
assert_ne!(f & ERRFLAG_ERROR, 0);
assert_ne!(f & ERRFLAG_INT, 0);
errflag.store(0, Ordering::Relaxed);
}
#[test]
fn negargument_sets_tmult_neg_prefix() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().tmult = 1;
ZMOD.lock().unwrap().flags = 0;
PREFIXFLAG.store(0, SeqCst);
let r = negargument();
assert_eq!(r, 0);
assert_eq!(ZMOD.lock().unwrap().tmult, -1);
assert_ne!(ZMOD.lock().unwrap().flags & MOD_TMULT, 0);
assert_ne!(ZMOD.lock().unwrap().flags & MOD_NEG, 0);
assert_ne!(PREFIXFLAG.load(SeqCst), 0);
}
#[test]
fn negargument_refuses_when_tmult_in_flight() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().flags |= MOD_TMULT;
ZMOD.lock().unwrap().tmult = 7; let r = negargument();
assert_eq!(r, 1);
assert_eq!(ZMOD.lock().unwrap().tmult, 7);
}
#[test]
fn overwritemode_toggles_insmode() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
INSMODE.store(1, SeqCst);
overwritemode();
assert_eq!(INSMODE.load(SeqCst), 0);
overwritemode();
assert_eq!(INSMODE.load(SeqCst), 1);
}
#[test]
fn argumentbase_with_arg_sets_base() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
let r = argumentbase(&["8".to_string()]);
assert_eq!(r, 0);
assert_eq!(ZMOD.lock().unwrap().base, 8);
assert_ne!(PREFIXFLAG.load(SeqCst), 0);
assert_eq!(ZMOD.lock().unwrap().mult, 1);
assert_eq!(ZMOD.lock().unwrap().tmult, 1);
assert_eq!(ZMOD.lock().unwrap().vibuf, 0);
}
#[test]
fn argumentbase_no_arg_uses_zmod_mult() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().mult = 16;
argumentbase(&[]);
assert_eq!(ZMOD.lock().unwrap().base, 16);
}
#[test]
fn argumentbase_rejects_below_two() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 10;
let r = argumentbase(&["1".to_string()]);
assert_eq!(r, 1);
assert_eq!(ZMOD.lock().unwrap().base, 10); }
#[test]
fn argumentbase_rejects_above_36() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 10;
let r = argumentbase(&["100".to_string()]);
assert_eq!(r, 1);
assert_eq!(ZMOD.lock().unwrap().base, 10);
}
#[test]
fn argumentbase_hex_prefix() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
argumentbase(&["0x10".to_string()]);
assert_eq!(ZMOD.lock().unwrap().base, 16);
}
#[test]
fn argumentbase_octal_prefix() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
argumentbase(&["010".to_string()]);
assert_eq!(ZMOD.lock().unwrap().base, 8);
}
#[test]
fn parsedigit_decimal_base() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 10;
assert_eq!(parsedigit(b'0' as i32), 0);
assert_eq!(parsedigit(b'5' as i32), 5);
assert_eq!(parsedigit(b'9' as i32), 9);
assert_eq!(parsedigit(b'a' as i32), -1);
}
#[test]
fn parsedigit_octal_base() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 8;
assert_eq!(parsedigit(b'7' as i32), 7);
assert_eq!(parsedigit(b'8' as i32), -1);
}
#[test]
fn parsedigit_hex_lowercase() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 16;
assert_eq!(parsedigit(b'a' as i32), 10);
assert_eq!(parsedigit(b'f' as i32), 15);
assert_eq!(parsedigit(b'g' as i32), -1);
}
#[test]
fn parsedigit_hex_uppercase() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 16;
assert_eq!(parsedigit(b'A' as i32), 10);
assert_eq!(parsedigit(b'F' as i32), 15);
}
#[test]
fn parsedigit_hex_digits_still_work() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 16;
assert_eq!(parsedigit(b'7' as i32), 7);
}
#[test]
fn parsedigit_strips_meta_bit() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 10;
assert_eq!(parsedigit(0x80 | (b'5' as i32)), 5);
}
#[test]
fn digitargument_first_digit_no_tmult() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().flags = 0;
ZMOD.lock().unwrap().base = 10;
ZMOD.lock().unwrap().mult = 1; LASTCHAR
.store((b'5' as i32) as i32, SeqCst);
let r = digitargument();
assert_eq!(r, 0);
assert_eq!(ZMOD.lock().unwrap().tmult, 5);
assert_ne!(ZMOD.lock().unwrap().flags & MOD_TMULT, 0);
assert_ne!(PREFIXFLAG.load(SeqCst), 0);
}
#[test]
fn digitargument_second_digit_accumulates() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().flags = MOD_TMULT;
ZMOD.lock().unwrap().tmult = 5;
ZMOD.lock().unwrap().base = 10;
ZMOD.lock().unwrap().mult = 1; LASTCHAR
.store((b'7' as i32) as i32, SeqCst);
digitargument();
assert_eq!(ZMOD.lock().unwrap().tmult, 57);
}
#[test]
fn digitargument_invalid_returns_one() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
ZMOD.lock().unwrap().base = 10;
LASTCHAR
.store((b'a' as i32) as i32, SeqCst); assert_eq!(digitargument(), 1);
}
#[test]
fn digitargument_neg_flag_replaces_tmult() {
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().tmult = -1; ZMOD.lock().unwrap().base = 10;
ZMOD.lock().unwrap().mult = -1; LASTCHAR
.store((b'3' as i32) as i32, SeqCst);
digitargument();
assert_eq!(ZMOD.lock().unwrap().tmult, -3);
assert_ne!(!ZMOD.lock().unwrap().flags & MOD_NEG, 0);
assert_ne!(ZMOD.lock().unwrap().flags & MOD_TMULT, 0);
}
#[test]
fn transpose_swap_equal_halves() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
*ZLELINE.lock().unwrap() = "abcdef".chars().collect();
ZLELL.store(6, SeqCst);
transpose_swap(0, 2, 4);
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "cdabef");
}
#[test]
fn transpose_swap_unequal_halves() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
*ZLELINE.lock().unwrap() = "abcdef".chars().collect();
ZLELL.store(6, SeqCst);
transpose_swap(0, 1, 4);
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "bcdaef");
}
#[test]
fn transpose_swap_first_longer() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
*ZLELINE.lock().unwrap() = "abcdef".chars().collect();
ZLELL.store(6, SeqCst);
transpose_swap(0, 3, 4);
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "dabcef");
}
#[test]
fn transpose_swap_mid_buffer() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zle_reset();
*ZLELINE.lock().unwrap() = "0123456789".chars().collect();
ZLELL.store(10, SeqCst);
transpose_swap(3, 5, 7);
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "0125634789");
}
#[test]
fn fixunmeta_strips_meta_and_normalizes_cr() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
LASTCHAR.store(
(0x80 | b'a' as i32) as i32,
SeqCst,
);
fixunmeta();
assert_eq!(
LASTCHAR.load(SeqCst),
b'a' as i32
);
LASTCHAR
.store((b'\r' as i32) as i32, SeqCst);
fixunmeta();
assert_eq!(
LASTCHAR.load(SeqCst),
b'\n' as i32
);
}
#[test]
fn selfinsert_inserts_lastchar() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "abc".chars().collect();
ZLELL.store(3, SeqCst);
ZLECS.store(1, SeqCst);
LASTCHAR
.store((b'X' as i32) as i32, SeqCst);
LASTCHAR_WIDE_VALID.store(0, SeqCst);
selfinsert();
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "aXbc");
}
#[test]
fn selfinsertunmeta_chains_fixunmeta_and_selfinsert() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "ab".chars().collect();
ZLELL.store(2, SeqCst);
ZLECS.store(1, SeqCst);
LASTCHAR.store(
(0x80 | b'X' as i32) as i32,
SeqCst,
);
LASTCHAR_WIDE_VALID.store(0, SeqCst);
selfinsertunmeta();
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "aXb");
}
#[test]
fn deletechar_removes_n_chars() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "hello".chars().collect();
ZLELL.store(5, SeqCst);
ZLECS.store(0, SeqCst);
ZMOD.lock().unwrap().mult = 2;
let r = deletechar();
assert_eq!(r, 0);
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "llo");
}
#[test]
fn deletechar_returns_one_at_eol() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "ab".chars().collect();
ZLELL.store(2, SeqCst);
ZLECS.store(2, SeqCst);
ZMOD.lock().unwrap().mult = 1;
assert_eq!(deletechar(), 1);
}
#[test]
fn backwarddeletechar_clamps_to_zlecs() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "abc".chars().collect();
ZLELL.store(3, SeqCst);
ZLECS.store(2, SeqCst);
ZMOD.lock().unwrap().mult = 99;
backwarddeletechar();
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "c");
assert_eq!(ZLECS.load(SeqCst), 0);
}
#[test]
fn killline_kills_to_eol_and_pushes_killring() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "hello world".chars().collect();
ZLELL.store(11, SeqCst);
ZLECS.store(6, SeqCst);
ZMOD.lock().unwrap().mult = 1;
killline();
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "hello ");
assert_eq!(ZLECS.load(SeqCst), 6);
assert_eq!(
KILLRING
.lock()
.unwrap()
.front()
.map(|v| v.iter().collect::<String>()),
Some("world".to_string())
);
}
#[test]
fn killbuffer_clears_and_pushes() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "abc".chars().collect();
ZLELL.store(3, SeqCst);
ZLECS.store(2, SeqCst);
killbuffer();
assert!(ZLELINE.lock().unwrap().is_empty());
assert_eq!(ZLELL.load(SeqCst), 0);
assert_eq!(ZLECS.load(SeqCst), 0);
assert_eq!(
KILLRING
.lock()
.unwrap()
.front()
.map(|v| v.iter().collect::<String>()),
Some("abc".to_string())
);
}
#[test]
fn killwholeline_drops_one_line() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "abc\ndef\nghi".chars().collect();
ZLELL.store(11, SeqCst);
ZLECS.store(5, SeqCst); ZMOD.lock().unwrap().mult = 1;
killwholeline();
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "abc\nghi");
}
#[test]
fn copyregionaskill_copies_between_point_mark() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "hello".chars().collect();
ZLELL.store(5, SeqCst);
ZLECS.store(0, SeqCst);
MARK.store(3, SeqCst);
copyregionaskill(&[]);
assert_eq!(
KILLRING
.lock()
.unwrap()
.front()
.map(|v| v.iter().collect::<String>()),
Some("hel".to_string())
);
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "hello");
}
#[test]
fn regionlines_returns_bol_eol_around_region() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "abc\ndef\nghi".chars().collect();
ZLELL.store(11, SeqCst);
ZLECS.store(1, SeqCst);
MARK.store(5, SeqCst);
let (start, end) = regionlines();
assert_eq!(start, 0);
assert_eq!(end, 7);
}
#[test]
fn killregion_drains_between_mark_and_cursor() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "abcdef".chars().collect();
ZLELL.store(6, SeqCst);
ZLECS.store(1, SeqCst);
MARK.store(4, SeqCst);
killregion();
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "aef");
assert_eq!(
KILLRING
.lock()
.unwrap()
.front()
.map(|v| v.iter().collect::<String>()),
Some("bcd".to_string())
);
}
#[test]
fn quoteline_wraps_in_single_quotes() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "abc".chars().collect();
ZLELL.store(3, SeqCst);
quoteline();
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "'abc'");
}
#[test]
fn quoteline_escapes_internal_quote() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "it's".chars().collect();
ZLELL.store(4, SeqCst);
quoteline();
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "'it'\\''s'");
}
#[test]
fn makequote_handles_no_quotes() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let s: Vec<char> = "abc".chars().collect();
let q = makequote(&s);
assert_eq!(q.iter().collect::<String>(), "'abc'");
}
#[test]
fn makequote_escapes_quotes() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let s: Vec<char> = "a'b".chars().collect();
let q = makequote(&s);
assert_eq!(q.iter().collect::<String>(), "'a'\\''b'");
}
#[test]
fn pastebuf_inserts_at_cursor_position_zero() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "foo".chars().collect();
ZLELL.store(3, SeqCst);
ZLECS.store(1, SeqCst);
let buf: Vec<char> = "XX".chars().collect();
pastebuf(&buf, 1, 0);
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "fXXoo");
}
#[test]
fn pastebuf_inserts_after_cursor_position_one() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
*ZLELINE.lock().unwrap() = "foo".chars().collect();
ZLELL.store(3, SeqCst);
ZLECS.store(1, SeqCst);
let buf: Vec<char> = "XX".chars().collect();
pastebuf(&buf, 1, 1);
let s: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(s, "foXXo");
}
#[test]
fn yankpop_returns_one_when_lastcmd_not_yank() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(yankpop(), 1);
}
#[test]
fn zle_usable_when_active_and_no_compfunc() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
zleactive.store(1, SeqCst);
INCOMPFUNC.store(0, SeqCst);
assert_eq!(super::super::zle_thingy::zle_usable(), 1);
INCOMPFUNC.store(1, SeqCst);
assert_eq!(super::super::zle_thingy::zle_usable(), 0);
INCOMPFUNC.store(0, SeqCst);
zleactive.store(0, SeqCst);
assert_eq!(super::super::zle_thingy::zle_usable(), 0);
}
#[test]
fn parsedigit_decimal_recognises_zero_through_nine() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(ZMOD.lock().unwrap().base, 10);
for d in 0..=9 {
assert_eq!(parsedigit(b'0' as i32 + d), d, "'{}' → {}", d, d);
}
}
#[test]
fn parsedigit_hex_recognises_full_alphabet() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
ZMOD.lock().unwrap().base = 16;
assert_eq!(parsedigit(b'a' as i32), 10);
assert_eq!(parsedigit(b'f' as i32), 15);
assert_eq!(parsedigit(b'A' as i32), 10);
assert_eq!(parsedigit(b'F' as i32), 15);
assert_eq!(
parsedigit(b'g' as i32),
-1,
"c:941 — past 'a'+base-10 bound"
);
assert_eq!(parsedigit(b'G' as i32), -1);
assert_eq!(parsedigit(b'9' as i32), 9);
assert_eq!(parsedigit(b'0' as i32), 0);
}
#[test]
fn parsedigit_octal_rejects_eight_and_nine() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
ZMOD.lock().unwrap().base = 8;
assert_eq!(parsedigit(b'0' as i32), 0);
assert_eq!(parsedigit(b'7' as i32), 7);
assert_eq!(parsedigit(b'8' as i32), -1, "c:945 — '8' fails '0'+8 bound");
assert_eq!(parsedigit(b'9' as i32), -1);
}
#[test]
fn parsedigit_rejects_non_digit_inputs() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(parsedigit(b' ' as i32), -1);
assert_eq!(parsedigit(b'.' as i32), -1);
assert_eq!(parsedigit(b'-' as i32), -1);
assert_eq!(
parsedigit(b'a' as i32),
-1,
"c:945 — 'a' rejected in base 10"
);
assert_eq!(parsedigit(b'\n' as i32), -1);
}
#[test]
fn parsedigit_strips_meta_bit_before_classification() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
for d in 0..=9 {
let meta = (b'0' as i32 + d) | 0x80;
assert_eq!(
parsedigit(meta),
d,
"Meta-{} (0x{:x}) must mask 0x80 and parse as {}",
d,
meta,
d
);
}
}
#[test]
fn makequote_wraps_plain_input_in_single_quotes() {
let _g = crate::test_util::global_state_lock();
let out: String = makequote(&"hello".chars().collect::<Vec<_>>())
.iter()
.collect();
assert_eq!(out, "'hello'");
}
#[test]
fn makequote_escapes_embedded_single_quote() {
let _g = crate::test_util::global_state_lock();
let out: String = makequote(&"it's".chars().collect::<Vec<_>>())
.iter()
.collect();
assert_eq!(out, r#"'it'\''s'"#);
}
#[test]
fn makequote_handles_consecutive_quotes() {
let _g = crate::test_util::global_state_lock();
let out: String = makequote(&"a''b".chars().collect::<Vec<_>>())
.iter()
.collect();
assert_eq!(out, r#"'a'\'''\''b'"#);
assert_eq!(out.len(), 12);
}
#[test]
fn makequote_empty_input_returns_pair_of_quotes() {
let _g = crate::test_util::global_state_lock();
let out: String = makequote(&[]).iter().collect();
assert_eq!(out, "''", "c:1213+c:1222 — quotes fire unconditionally");
}
#[test]
fn transpose_swap_rotates_two_adjacent_slices() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
{
let mut z = ZLELINE.lock().unwrap();
*z = "abcDEFG".chars().collect();
}
ZLELL.store(7, SeqCst);
transpose_swap(0, 3, 7);
let got: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(got, "DEFGabc");
}
#[test]
fn transpose_swap_equal_length_halves() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
{
let mut z = ZLELINE.lock().unwrap();
*z = "1234".chars().collect();
}
ZLELL.store(4, SeqCst);
transpose_swap(0, 2, 4);
let got: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(got, "3412");
}
#[test]
fn zle_misc_corpus_transpose_swap_single_chars() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
{
let mut z = ZLELINE.lock().unwrap();
*z = "ab".chars().collect();
}
ZLELL.store(2, SeqCst);
transpose_swap(0, 1, 2);
let got: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(got, "ba");
}
#[test]
fn zle_misc_corpus_transpose_swap_empty_first_half() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
{
let mut z = ZLELINE.lock().unwrap();
*z = "abcd".chars().collect();
}
ZLELL.store(4, SeqCst);
transpose_swap(0, 0, 4);
let got: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(got, "abcd",
"empty first half = identity transform");
}
#[test]
fn zle_misc_corpus_transpose_swap_empty_second_half() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
{
let mut z = ZLELINE.lock().unwrap();
*z = "abcd".chars().collect();
}
ZLELL.store(4, SeqCst);
transpose_swap(0, 4, 4);
let got: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(got, "abcd",
"empty second half = identity transform");
}
#[test]
fn zle_misc_corpus_transpose_swap_partial_buffer() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
{
let mut z = ZLELINE.lock().unwrap();
*z = "XYabcdZW".chars().collect();
}
ZLELL.store(8, SeqCst);
transpose_swap(2, 4, 6);
let got: String = ZLELINE.lock().unwrap().iter().collect();
assert_eq!(got, "XYcdabZW",
"surrounding chars XY,ZW must be preserved");
}
}