use std::collections::HashMap;
#[allow(unused_imports)]
#[allow(unused_imports)]
use crate::ported::zle::zle_main::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_misc::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_hist::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_move::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_word::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_params::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_vi::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_utils::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_refresh::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_tricky::*;
#[allow(unused_imports)]
use crate::ported::zle::textobjects::*;
#[allow(unused_imports)]
use crate::ported::zle::deltochar::*;
pub const MMARK: u32 = 1;
pub const MAX_POS: usize = 11;
pub const COL_NO: usize = 0; pub const COL_FI: usize = 1; pub const COL_DI: usize = 2; pub const COL_LN: usize = 3; pub const COL_PI: usize = 4; pub const COL_SO: usize = 5; pub const COL_BD: usize = 6; pub const COL_CD: usize = 7; pub const COL_OR: usize = 8; pub const COL_MI: usize = 9; pub const COL_SU: usize = 10; pub const COL_SG: usize = 11; pub const COL_TW: usize = 12; pub const COL_OW: usize = 13; pub const COL_ST: usize = 14; pub const COL_EX: usize = 15; pub const COL_LC: usize = 16; pub const COL_RC: usize = 17; pub const COL_EC: usize = 18; pub const COL_TC: usize = 19; pub const COL_SP: usize = 20; pub const COL_MA: usize = 21; pub const COL_HI: usize = 22; pub const COL_DU: usize = 23; pub const COL_SA: usize = 24; pub const NUM_COLS: usize = 25;
pub fn filecol(col: &str) -> filecol { filecol { prog: None, col: col.to_string(), next: None, } }
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct filecol { pub prog: Option<crate::ported::zsh_h::Patprog>, pub col: String, pub next: Option<Box<filecol>>, }
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct patcol { pub prog: Option<crate::ported::zsh_h::Patprog>, pub pat: Option<crate::ported::zsh_h::Patprog>, pub cols: Vec<String>, pub next: Option<Box<patcol>>, }
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct extcol { pub prog: Option<crate::ported::zsh_h::Patprog>, pub ext: String, pub col: String, pub next: Option<Box<extcol>>, }
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct listcols { pub files: Vec<filecol>, pub pats: Option<Box<patcol>>, pub exts: Option<Box<extcol>>, pub flags: i32, }
#[allow(unused_variables)]
pub fn getcolval(s: &str, multi: i32) -> &str { let trimmed = s.trim_start_matches(|c: char| c.is_ascii_digit() || c == ';');
trimmed
}
pub fn getcoldef(s: &str) -> Option<String> { s.split_once(':').map(|(_, rest)| rest.to_string())
}
pub fn getcols(_unused: &str) -> i32 { use std::sync::atomic::Ordering;
MAX_CAPLEN.store(0, Ordering::SeqCst); LR_CAPLEN.store(0, Ordering::SeqCst); {
let mut mc = MCOLORS.lock().unwrap();
mc.flags = 0; }
crate::ported::signals::queue_signals();
let s_opt = crate::ported::params::getsparam("ZLS_COLORS")
.or_else(|| crate::ported::params::getsparam("ZLS_COLOURS"));
if s_opt.is_none() { let mut mc = MCOLORS.lock().unwrap();
mc.files.clear();
for _i in 0..NUM_COLS { mc.files.push(filecol("")); }
mc.pats = None; mc.exts = None;
let tcstr_guard = crate::ported::init::tcstr.lock().unwrap();
let so_beg = tcstr_guard[crate::ported::zsh_h::TCSTANDOUTBEG as usize].clone();
let so_end = tcstr_guard[crate::ported::zsh_h::TCSTANDOUTEND as usize].clone();
drop(tcstr_guard);
if !so_beg.is_empty() { mc.files[COL_MA] = filecol(&so_beg); mc.files[COL_EC] = filecol(&so_end); } else { mc.files[COL_MA] = filecol("7"); }
let ma_len = mc.files[COL_MA].col.len() as i32;
let ec_len = mc.files[COL_EC].col.len() as i32;
let max_len = if ma_len < ec_len { ec_len } else { ma_len };
MAX_CAPLEN.store(max_len, Ordering::SeqCst); crate::ported::signals::unqueue_signals(); return 0; }
{
let mut mc = MCOLORS.lock().unwrap();
*mc = listcols::default(); }
let mut s = s_opt.unwrap(); while !s.is_empty() { if s.starts_with(':') { s = s[1..].to_string(); } else {
s = match getcoldef(&s) {
Some(rest) => rest,
None => break,
};
}
}
crate::ported::signals::unqueue_signals();
let defcols: [&str; NUM_COLS] = [
"0", "0", "01;34", "01;36", "33", "01;35", "01;33", "01;33",
"01;05;37;41", "01;05;37;41", "37;41", "30;43", "30;42", "34;42",
"37;44", "01;32", "\x1b[", "m", "0", "0", "0", "7", "0", "0", "0",
];
let mut mc = MCOLORS.lock().unwrap();
while mc.files.len() < NUM_COLS {
mc.files.push(filecol(""));
}
let mut max_len = MAX_CAPLEN.load(Ordering::SeqCst);
for i in 0..NUM_COLS { if mc.files[i].col.is_empty() { mc.files[i] = filecol(defcols[i]); }
let l = mc.files[i].col.len() as i32; if l > max_len { max_len = l; } }
MAX_CAPLEN.store(max_len, Ordering::SeqCst);
let lr_len = (mc.files[COL_LC].col.len() + mc.files[COL_RC].col.len()) as i32;
LR_CAPLEN.store(lr_len, Ordering::SeqCst);
if mc.files[COL_OR].col.is_empty() { let ln = mc.files[COL_LN].col.clone();
mc.files[COL_OR] = filecol(&ln); }
if mc.files[COL_MI].col.is_empty() { let fi = mc.files[COL_FI].col.clone();
mc.files[COL_MI] = filecol(&fi); }
0 }
pub fn zlrputs(cap: &str) -> i32 { use std::sync::atomic::Ordering;
if cap.is_empty() {
return 0;
}
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
let out = if fd >= 0 { fd } else { 1 };
let s = format!("\x1b[{}m", cap);
let _ = crate::ported::utils::write_loop(out, s.as_bytes());
0
}
pub fn zcputs(s: &str, color: Option<&str>) -> String { match color {
Some(c) => format!("\x1b[{}m{}\x1b[0m", c, s),
None => s.to_string(),
}
}
pub fn zcoff() { }
pub fn cleareol() { use std::sync::atomic::Ordering;
if MLBEG.load(Ordering::Relaxed) < 0 {
return;
}
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
let out = if fd >= 0 { fd } else { 1 };
if !LAST_CAP.lock().map(|s| s.is_empty()).unwrap_or(true) {
let _ = crate::ported::utils::write_loop(out, b"\x1b[0m");
LAST_CAP.lock().ok().map(|mut s| s.clear());
}
let _ = crate::ported::utils::write_loop(out, b"\x1b[K");
}
pub fn initiscol() -> i32 { use std::sync::atomic::Ordering;
let first_cap = PATCOLS.lock().ok()
.and_then(|p| p.first().cloned())
.unwrap_or_default();
if !first_cap.is_empty() {
let _ = zlrputs(&first_cap);
}
if let Ok(mut cs) = CURISCOLS.lock() {
if !cs.is_empty() {
cs[0] = first_cap.clone();
}
}
CURISCOL.store(0, Ordering::Relaxed);
PATCOLS_IDX.store(1, Ordering::Relaxed);
CURISBEG.store(0, Ordering::Relaxed);
CURISSEND.store(0, Ordering::Relaxed);
let nrefs = NREFS.load(Ordering::Relaxed) as usize;
if let Ok(mut sp) = SENDPOS.lock() {
for i in 0..MAX_POS {
sp[i] = 0xfffffff;
}
for i in 0..nrefs.min(MAX_POS) {
sp[i] = 0xfffffff; }
}
if let Ok(mut bp) = BEGPOS.lock() {
for i in nrefs..MAX_POS {
bp[i] = 0xfffffff; }
}
if let Ok(mut ep) = ENDPOS.lock() {
for i in nrefs..MAX_POS {
ep[i] = 0xfffffff; }
}
0
}
pub fn doiscol(pos: i32) -> i32 { use std::sync::atomic::Ordering;
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
let out = if fd >= 0 { fd } else { 1 };
loop {
let curissend = CURISSEND.load(Ordering::Relaxed) as usize;
let sp = SENDPOS.lock().ok().and_then(|s| s.get(curissend).copied())
.unwrap_or(0xfffffff);
if pos <= sp { break; }
CURISSEND.fetch_add(1, Ordering::Relaxed);
let curiscol = CURISCOL.load(Ordering::Relaxed);
if curiscol > 0 {
let _ = crate::ported::utils::write_loop(out, b"\x1b[0m");
let new_idx = curiscol - 1;
CURISCOL.store(new_idx, Ordering::Relaxed);
let restore_cap = CURISCOLS.lock().ok()
.and_then(|c| c.get(new_idx as usize).cloned())
.unwrap_or_default();
if !restore_cap.is_empty() {
let _ = zlrputs(&restore_cap);
}
}
}
loop {
let curisbeg = CURISBEG.load(Ordering::Relaxed) as usize;
if curisbeg >= MAX_POS { break; }
let (bp, ep) = {
let bp_lock = BEGPOS.lock().ok();
let ep_lock = ENDPOS.lock().ok();
match (bp_lock, ep_lock) {
(Some(b), Some(e)) => {
(b.get(curisbeg).copied().unwrap_or(0xfffffff),
e.get(curisbeg).copied().unwrap_or(0xfffffff))
}
_ => break,
}
};
let fi = ep < bp || bp == -1;
if !(fi || pos == bp) {
break;
}
let patcols_idx = PATCOLS_IDX.load(Ordering::Relaxed);
let cap_now = PATCOLS.lock().ok()
.and_then(|p| p.get(patcols_idx).cloned())
.unwrap_or_default();
if cap_now.is_empty() { break; }
if !fi {
let e = ep;
if let Ok(mut sp) = SENDPOS.lock() {
let curissend = CURISSEND.load(Ordering::Relaxed) as usize;
let mut i = curissend;
while i < MAX_POS && sp[i] <= e {
i += 1;
}
let mut j = MAX_POS - 1;
while j > i {
sp[j] = sp[j - 1];
j -= 1;
}
if i < MAX_POS {
sp[i] = e;
}
}
let _ = crate::ported::utils::write_loop(out, b"\x1b[0m");
let _ = zlrputs(&cap_now);
let new_idx = CURISCOL.fetch_add(1, Ordering::Relaxed) + 1;
if let Ok(mut cs) = CURISCOLS.lock() {
if (new_idx as usize) < cs.len() {
cs[new_idx as usize] = cap_now;
}
}
}
PATCOLS_IDX.fetch_add(1, Ordering::Relaxed);
CURISBEG.fetch_add(1, Ordering::Relaxed);
}
0
}
pub fn clprintfmt(p: &str, ml: i32) -> i32 { crate::ported::zle::zle_tricky::printfmt(p, ml, true, true)
}
#[allow(unused_variables)]
pub fn clnicezputs(do_colors: i32, s: &str, ml: i32) -> i32 { use std::sync::atomic::Ordering;
let _ = do_colors;
let bytes = s.as_bytes();
let mut out: Vec<u8> = Vec::with_capacity(bytes.len());
let mut i = 0;
while i < bytes.len() {
let c = bytes[i];
if c == 0x83 { i += 1;
if i < bytes.len() {
out.push(bytes[i] ^ 32);
}
} else if (0x80..0xa0).contains(&c) { } else {
out.push(c);
}
i += 1;
}
if out.is_empty() {
return 0;
}
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out_fd, &out);
0
}
pub fn putmatchcol(group: &str, n: &str) -> i32 { let _ = group;
0
}
pub fn putfilecol(group: &str, filename: &str, m: u32, special: i32) -> i32 { let _ = group;
0
}
pub fn asklistscroll(total: usize, shown: usize) -> String { let _remaining = total.saturating_sub(shown);
format!("--More--({}/{})", shown, total)
}
#[allow(unused_variables)]
pub fn compprintnl(ml: i32) -> i32 { use std::sync::atomic::Ordering;
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out_fd, b"\x1b[K\n");
0
}
pub fn compprintfmt( fmt: &str,
n: i32,
dopr: i32,
doesc: i32,
ml: i32,
stop: &mut i32,
) -> i32 {
use std::sync::atomic::Ordering;
let mut l = 0i32; let mut cc = 0i32;
let _ = doesc;
let _ = ml;
let _ = stop;
let owned: String;
let fmt_str: &str = if fmt.is_empty() { if MLBEG.load(Ordering::SeqCst) >= 0 { owned = MSTATUS.lock().unwrap().clone();
if owned.is_empty() {
MLPRINTED.store(0, Ordering::SeqCst); return 0; }
cc = -1; &owned
} else { owned = MLISTP.lock().unwrap().clone();
&owned
}
} else {
fmt
};
let mut chars = fmt_str.chars().peekable();
while let Some(c) = chars.next() {
if c == '%' { let mut arg = 0i32;
while let Some(&d) = chars.peek() {
if d.is_ascii_digit() {
arg = arg * 10 + (d as i32 - '0' as i32);
chars.next();
} else { break; }
}
match chars.next() { Some('%') => { if dopr == 1 { l += 1; } cc += 1; } Some('n') => { let s = n.to_string();
if dopr == 1 {
use std::sync::atomic::Ordering as O;
let fd = crate::ported::init::SHTTY.load(O::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out_fd, s.as_bytes());
}
l += s.len() as i32;
cc += s.len() as i32;
}
Some('p') => { let mlbeg = MLBEG.load(Ordering::SeqCst);
let mlines = MLINES.load(Ordering::SeqCst);
let s = if mlbeg <= 0 && mlines < MLEND.load(Ordering::SeqCst) {
"Top".to_string()
} else if mlbeg + MLEND.load(Ordering::SeqCst) - MLBEG.load(Ordering::SeqCst) >= mlines {
"Bot".to_string()
} else {
format!("{}%", mlbeg.max(0) * 100 / mlines.max(1))
};
if dopr == 1 {
use std::sync::atomic::Ordering as O;
let fd = crate::ported::init::SHTTY.load(O::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out_fd, s.as_bytes());
}
l += s.len() as i32;
cc += s.len() as i32;
}
Some(_) => { let _ = arg; } None => break,
}
} else { if dopr == 1 {
use std::sync::atomic::Ordering as O;
let fd = crate::ported::init::SHTTY.load(O::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let mut buf = [0u8; 4];
let bs = c.encode_utf8(&mut buf).as_bytes();
let _ = crate::ported::utils::write_loop(out_fd, bs);
}
l += 1;
cc += 1;
}
}
let _ = l;
cc }
pub static MSTATUS: std::sync::LazyLock<std::sync::Mutex<String>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(String::new()));
pub static MLISTP: std::sync::LazyLock<std::sync::Mutex<String>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(String::new()));
#[allow(unused_variables)]
pub fn compzputs(s: &str, ml: i32) -> i32 { use std::sync::atomic::Ordering;
let bytes = s.as_bytes();
let mut out: Vec<u8> = Vec::with_capacity(bytes.len());
let mut i = 0;
while i < bytes.len() {
let c = bytes[i];
if c == 0x83 { i += 1;
if i < bytes.len() {
out.push(bytes[i] ^ 32);
}
} else if (0x80..0xa0).contains(&c) { } else {
out.push(c);
}
i += 1;
}
if out.is_empty() {
return 0;
}
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out_fd, &out); 0
}
pub fn compprintlist(showall: i32) -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::comp_h::{CGF_HASDL, CGF_LINES, CGF_ROWS, CMF_DISPLINE, CMF_HIDE, CMF_NOLIST};
let mut pnl = 0i32; let mut cl: i32;
let mut ml: i32 = 0;
let mut mc: i32;
let mut printed = 0i32;
let mut stop = 0i32;
let _asked = 1i32;
let mut lastused = 0i32;
let mlbeg = MLBEG.load(Ordering::SeqCst);
let mlend = MLEND.load(Ordering::SeqCst);
let mnew = MNEW.load(Ordering::SeqCst);
let mhasstat = MHASSTAT.load(Ordering::SeqCst);
let zterm_lines = crate::ported::utils::adjustlines() as i32;
let nlnct = crate::ported::zle::zle_refresh::NLNCT.load(Ordering::SeqCst);
let invcount = crate::ported::zle::compresult::INVCOUNT.load(Ordering::SeqCst);
MFIRSTL.store(-1, Ordering::SeqCst);
let mut last_type = LAST_TYPE.load(Ordering::SeqCst);
let last_invcount = LAST_INVCOUNT.load(Ordering::SeqCst);
let last_beg = LAST_BEG.load(Ordering::SeqCst);
if mnew != 0 || last_invcount != invcount || last_beg != mlbeg || mlbeg < 0 {
last_type = 0; LAST_TYPE.store(0, Ordering::SeqCst);
LAST_NLNCT.store(-1, Ordering::SeqCst);
}
let listdat_nlines = crate::ported::zle::compcore::listdat
.get()
.and_then(|m| m.lock().ok().map(|g| g.nlines))
.unwrap_or(0);
cl = if listdat_nlines > zterm_lines - nlnct - mhasstat { zterm_lines - nlnct - mhasstat
} else {
listdat_nlines
} - if LAST_NLNCT.load(Ordering::SeqCst) > nlnct { 1 } else { 0 };
LAST_NLNCT.store(nlnct, Ordering::SeqCst); MRESTLINES.store(zterm_lines - 1, Ordering::SeqCst); LAST_INVCOUNT.store(invcount, Ordering::SeqCst);
let tcd_avail = crate::ported::init::tclen.lock().unwrap()
[crate::ported::zsh_h::TCCLEAREOD as usize] != 0; let tceol_avail = crate::ported::init::tclen.lock().unwrap()
[crate::ported::zsh_h::TCCLEAREOL as usize] != 0;
if cl < 2 { cl = -1; if tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD"); }
} else if mlbeg >= 0 && !tceol_avail && tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD"); }
let groups: Vec<crate::ported::zle::comp_h::Cmgroup> = {
crate::ported::zle::compcore::amatches
.get_or_init(|| std::sync::Mutex::new(Vec::new()))
.lock().ok().map(|g| g.clone()).unwrap_or_default()
};
let dolist = |x: i32| -> bool { x >= mlbeg && x < mlend }; let dolistcl = |x: i32| -> bool { x >= mlbeg && x < mlend + 1 }; let dolistnl = |x: i32| -> bool { x >= mlbeg && x < mlend - 1 };
'outer: for g in &groups { if crate::ported::utils::errflag.load(Ordering::SeqCst) != 0 { break;
}
let pp = &g.ylist;
let onlyexpl: i32 = crate::ported::zle::compcore::listdat
.get()
.and_then(|m| m.lock().ok().map(|g| g.onlyexpl))
.unwrap_or(0);
if !g.expls.is_empty() { for e in &g.expls { if crate::ported::utils::errflag.load(Ordering::SeqCst) != 0 { break 'outer; }
let valid = (e.count != 0 || e.always != 0) && (onlyexpl == 0
|| (onlyexpl & if e.always > 0 { 2 } else { 1 }) != 0);
if valid {
if pnl != 0 { if dolistnl(ml) && compprintnl(ml) != 0 { break 'outer;
}
pnl = 0; ml += 1; if dolistcl(ml) && cl >= 0 { cl -= 1;
if cl <= 1 {
cl = -1; if tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD");
}
}
}
}
if mlbeg < 0 && MFIRSTL.load(Ordering::SeqCst) < 0 { MFIRSTL.store(ml, Ordering::SeqCst); }
let n = if e.always != 0 { -1 } else { e.count };
let estr = e.str.clone().unwrap_or_default();
let _ = compprintfmt( &estr, n,
if dolist(ml) { 1 } else { 0 },
1, ml, &mut stop,
);
if stop != 0 { break 'outer; } if last_type == 0 && ml >= mlbeg { last_type = 1; LAST_TYPE.store(1, Ordering::SeqCst);
LAST_BEG.store(mlbeg, Ordering::SeqCst);
LAST_ML.store(ml, Ordering::SeqCst);
lastused = 1;
}
ml += MLPRINTED.load(Ordering::SeqCst); if dolistcl(ml) && cl >= 0 { cl -= MLPRINTED.load(Ordering::SeqCst);
if cl <= 1 {
cl = -1;
if tcd_avail {
crate::ported::zle::zle_refresh::tcout("TCCLEAREOD");
}
}
}
pnl = 1; }
if mnew == 0 && ml > mlend { break 'outer; } }
}
if onlyexpl == 0 && mlbeg < 0 && !pp.is_empty() { if pnl != 0 { if dolistnl(ml) && compprintnl(ml) != 0 { break 'outer; } pnl = 0;
ml += 1;
if cl >= 0 { cl -= 1; if cl <= 1 { cl = -1; if tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD"); } } }
}
if mlbeg < 0 && MFIRSTL.load(Ordering::SeqCst) < 0 {
MFIRSTL.store(ml, Ordering::SeqCst);
}
if (g.flags & CGF_LINES) != 0 { for s in pp { if compzputs(s, ml) != 0 { break 'outer; } if compprintnl(ml) != 0 { break 'outer; } }
} else {
for s in pp {
if compzputs(s, MSCROLL.load(Ordering::SeqCst)) != 0 { break 'outer;
}
if compprintnl(ml) != 0 { break 'outer; } ml += 1;
}
}
} else if onlyexpl == 0 && (g.lcount != 0 || (showall != 0 && g.mcount != 0)) { let n_total = g.dcount;
let _ = n_total;
let nc = g.lins;
if (g.flags & CGF_HASDL) != 0 { for m in &g.matches { let displine = m.disp.is_some() && (m.flags & CMF_DISPLINE) != 0;
let visible = showall != 0
|| (m.flags & (CMF_HIDE | CMF_NOLIST)) == 0;
if displine && visible { if pnl != 0 { if dolistnl(ml) && compprintnl(ml) != 0 {
break 'outer;
}
pnl = 0;
ml += 1;
if dolistcl(ml) && cl >= 0 {
cl -= 1;
if cl <= 1 { cl = -1; if tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD"); } }
}
}
if last_type == 0 && ml >= mlbeg { last_type = 2;
LAST_TYPE.store(2, Ordering::SeqCst);
LAST_BEG.store(mlbeg, Ordering::SeqCst);
LAST_ML.store(ml, Ordering::SeqCst);
lastused = 1;
}
if MFIRSTL.load(Ordering::SeqCst) < 0 { MFIRSTL.store(ml, Ordering::SeqCst);
}
if dolist(ml) { printed += 1; } if clprintm(Some(g), Some(m), 0, ml, 1, 0) != 0 { break 'outer;
}
ml += MLPRINTED.load(Ordering::SeqCst); if dolistcl(ml) {
cl -= MLPRINTED.load(Ordering::SeqCst);
if cl <= 1 { cl = -1; if tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD"); } }
}
pnl = 1; }
if mnew == 0 && ml > mlend { break 'outer; } }
}
if pnl != 0 { if dolistnl(ml) && compprintnl(ml) != 0 { break 'outer; }
pnl = 0; ml += 1;
if dolistcl(ml) && cl >= 0 {
cl -= 1;
if cl <= 1 { cl = -1; if tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD"); } }
}
}
let mut nl_cnt = nc;
let mut p_idx: usize = 0;
while p_idx < g.matches.len() {
let m = &g.matches[p_idx];
if (m.flags & CMF_HIDE) != 0
|| (showall == 0 && (m.flags & CMF_NOLIST) != 0)
{
p_idx += 1;
} else { break; }
}
let mut n = g.dcount;
while n > 0 && nl_cnt > 0 && crate::ported::utils::errflag.load(Ordering::SeqCst) == 0 {
if last_type == 0 && ml >= mlbeg { last_type = 3;
LAST_TYPE.store(3, Ordering::SeqCst);
LAST_BEG.store(mlbeg, Ordering::SeqCst);
LAST_ML.store(ml, Ordering::SeqCst);
lastused = 1;
}
let mut i = g.cols; mc = 0;
let mut q_idx = p_idx;
while n > 0 && i > 0 && crate::ported::utils::errflag.load(Ordering::SeqCst) == 0 {
i -= 1;
let wid = if !g.widths.is_empty() { g.widths.get(mc as usize).copied().unwrap_or(g.width)
} else { g.width };
let m_at_q = g.matches.get(q_idx); match m_at_q {
None => { if clprintm(Some(g), None, mc, ml, if i == 0 { 1 } else { 0 }, wid) != 0
{
break 'outer;
}
break;
}
Some(m) => { if clprintm(Some(g), Some(m), mc, ml,
if i == 0 { 1 } else { 0 }, wid) != 0
{
break 'outer;
}
if dolist(ml) { printed += 1; } ml += MLPRINTED.load(Ordering::SeqCst); if dolistcl(ml) {
cl -= MLPRINTED.load(Ordering::SeqCst);
if cl < 1 { cl = -1; if tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD"); } }
}
if MFIRSTL.load(Ordering::SeqCst) < 0 { MFIRSTL.store(ml, Ordering::SeqCst);
}
n -= 1; if n > 0 { let step = if (g.flags & CGF_ROWS) != 0 { 1 } else { nc as usize };
for _j in 0..step { if q_idx < g.matches.len() { q_idx += 1; }
while q_idx < g.matches.len() { let m2 = &g.matches[q_idx];
if (m2.flags & CMF_HIDE) != 0
|| (showall == 0 && (m2.flags & CMF_NOLIST) != 0)
{
q_idx += 1;
} else { break; }
}
}
}
mc += 1; }
}
}
while i > 0 {
i -= 1;
let wid = if !g.widths.is_empty() {
g.widths.get(mc as usize).copied().unwrap_or(g.width)
} else { g.width };
if clprintm(Some(g), None, mc, ml,
if i == 0 { 1 } else { 0 }, wid) != 0
{
break 'outer;
}
mc += 1;
}
if n > 0 { if dolistnl(ml) && compprintnl(ml) != 0 { break 'outer; }
ml += 1; if dolistcl(ml) && cl >= 0 { cl -= 1;
if cl <= 1 { cl = -1; if tcd_avail { crate::ported::zle::zle_refresh::tcout("TCCLEAREOD"); } }
}
if nl_cnt > 0 { let step = if (g.flags & CGF_ROWS) != 0 { g.cols as usize } else { 1 };
for _j in 0..step {
if p_idx < g.matches.len() { p_idx += 1; }
while p_idx < g.matches.len() {
let m2 = &g.matches[p_idx];
if (m2.flags & CMF_HIDE) != 0
|| (showall == 0 && (m2.flags & CMF_NOLIST) != 0)
{
p_idx += 1;
} else { break; }
}
}
}
}
if mnew == 0 && ml > mlend { break 'outer; } nl_cnt -= 1;
}
}
if g.lcount != 0 || (showall != 0 && g.mcount != 0) { pnl = 1; }
}
MSTATPRINTED.store(0, Ordering::SeqCst); crate::ported::zle::zle_refresh::LASTLISTLEN.store(0, Ordering::SeqCst); if nlnct <= 1 { MSCROLL.store(0, Ordering::SeqCst); }
let _ = lastused;
printed }
pub static LAST_TYPE: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(0);
pub static LAST_BEG: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(0);
pub static LAST_ML: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(0);
pub static LAST_INVCOUNT: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(-1);
pub static LAST_NLNCT: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(-1);
pub fn clprintm(
g: Option<&crate::ported::zle::comp_h::Cmgroup>,
m: Option<&crate::ported::zle::comp_h::Cmatch>,
mc: i32,
ml: i32,
lastc: i32,
width: i32,
) -> i32 { use std::sync::atomic::Ordering;
let mselect = MSELECT.load(Ordering::SeqCst);
let mcols = MCOLS.load(Ordering::SeqCst);
let zterm_columns = crate::ported::utils::adjustcolumns() as i32;
{
let mut lg = LAST_GROUP.lock().unwrap();
let g_name = g.and_then(|grp| grp.name.clone()).unwrap_or_default();
if *lg != g_name { *LAST_CAP.lock().unwrap() = String::new(); *lg = g_name; }
}
let m_ref = match m { Some(m_real) => m_real,
None => {
if let Some(grp) = g { let _ = grp;
let pad = (width - 2).max(0) as usize;
let pad_str = " ".repeat(pad);
use std::sync::atomic::Ordering as O;
let fd = crate::ported::init::SHTTY.load(O::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out_fd, pad_str.as_bytes());
}
MLPRINTED.store(0, Ordering::SeqCst); return 0; }
};
let _ = crate::ported::zle::comp_h::CMF_ALL;
MLASTM.store(m_ref.gnum, Ordering::SeqCst);
let displine = m_ref.disp.is_some()
&& (m_ref.flags & crate::ported::zle::comp_h::CMF_DISPLINE) != 0;
if displine { if mselect >= 0 { let mm = mcols * ml; let mut mtab_guard = MTAB.lock().unwrap();
let mut mgtab_guard = MGTAB.lock().unwrap();
for i in 0..mcols { let idx = (mm + i) as usize;
if idx < mtab_guard.len() {
mtab_guard[idx] = Some(m_ref.clone()); if let Some(grp) = g {
mgtab_guard[idx] = Some(grp.clone()); }
}
}
}
if m_ref.gnum == mselect { let mm = mcols * ml;
MLINE.store(ml, Ordering::SeqCst); MCOL.store(0, Ordering::SeqCst); MMTABP.store(mm.max(0) as usize, Ordering::SeqCst); MGTABP.store(mm.max(0) as usize, Ordering::SeqCst); }
let disp = m_ref.disp.as_deref().unwrap_or("");
let _ = compprintfmt(disp, 0, 1, 0, ml, &mut 0); } else {
let mx = if !g.is_some_and(|grp| grp.widths.is_empty()) { g.map(|grp| grp.widths.iter().take(mc as usize).sum::<i32>()).unwrap_or(0)
} else {
mc * g.map(|grp| grp.width).unwrap_or(0)
};
if mselect >= 0 { let mm = mcols * ml;
let mut mtab_guard = MTAB.lock().unwrap();
let mut mgtab_guard = MGTAB.lock().unwrap();
let n = if width != 0 { width } else { mcols };
for i in 0..n { let idx = (mx + mm + i) as usize;
if idx < mtab_guard.len() {
mtab_guard[idx] = Some(m_ref.clone()); if let Some(grp) = g {
mgtab_guard[idx] = Some(grp.clone()); }
}
}
}
if m_ref.gnum == mselect { let mm = mcols * ml;
MCOL.store(mx, Ordering::SeqCst); MLINE.store(ml, Ordering::SeqCst); MMTABP.store((mx + mm).max(0) as usize, Ordering::SeqCst); MGTABP.store((mx + mm).max(0) as usize, Ordering::SeqCst); }
let display = m_ref.disp.as_deref()
.unwrap_or_else(|| m_ref.str.as_deref().unwrap_or(""));
use std::sync::atomic::Ordering as O;
let fd = crate::ported::init::SHTTY.load(O::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out_fd, display.as_bytes());
let len_str = display.chars().count() as i32;
let lines = if len_str > 0 { (len_str - 1) / zterm_columns } else { 0 };
MLPRINTED.store(lines, Ordering::SeqCst);
let cgf_files = g.map(|grp| (grp.flags & crate::ported::zle::comp_h::CGF_FILES) != 0)
.unwrap_or(false);
let modec = m_ref.modec as u8;
let mut emitted_marker = 0i32;
if cgf_files && modec != 0 { let _ = crate::ported::utils::write_loop(out_fd, &[modec]); emitted_marker = 1; }
let total_len = len_str + emitted_marker;
let pad = (width - total_len - 2).max(0) as usize; if pad > 0 { let pad_str = " ".repeat(pad);
let _ = crate::ported::utils::write_loop(out_fd, pad_str.as_bytes()); }
}
let _ = lastc;
0 }
pub static LAST_GROUP: std::sync::LazyLock<std::sync::Mutex<String>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(String::new()));
#[allow(unused_variables)]
pub fn singlecalc(cp: &mut i32, l: i32, lcp: &mut i32) -> i32 { 0
}
pub fn singledraw() -> i32 { use std::sync::atomic::Ordering;
let mline = MLINE.load(Ordering::SeqCst);
let mcol = MCOL.load(Ordering::SeqCst);
let mlbeg = MLBEG.load(Ordering::SeqCst);
let moline = MOLINE.load(Ordering::SeqCst);
let mocol = MOCOL.load(Ordering::SeqCst);
let molbeg = MOLBEG.load(Ordering::SeqCst);
let zterm_columns = crate::ported::utils::adjustcolumns() as i32;
let t1 = mline - mlbeg; let t2 = moline - molbeg;
let (mc1, ml1, md1, mc2, ml2, md2);
if t2 < t1 { mc1 = mocol; ml1 = moline; md1 = t2; mc2 = mcol; ml2 = mline; md2 = t1; } else { mc1 = mcol; ml1 = mline; md1 = t1; mc2 = mocol; ml2 = moline; md2 = t2; }
let mcc1 = mc1; let _lc1 = 0i32;
let mcc2 = mc2; let _lc2 = 0i32;
if md1 != 0 { crate::ported::zle::zle_refresh::tc_downcurs(md1 as usize); }
if mc1 != 0 { crate::ported::zle::zle_refresh::tcmultout("TCRIGHT", mc1); }
let idx1 = (ml1 * zterm_columns + mc1) as usize;
let g_at1 = MGTAB.lock().unwrap().get(idx1).cloned().flatten();
let m_at1 = MTAB.lock().unwrap().get(idx1).cloned().flatten();
let width_at1 = g_at1.as_ref()
.map(|g| if g.widths.is_empty() { g.width } else { g.widths.get(mcc1 as usize).copied().unwrap_or(g.width) })
.unwrap_or(0);
clprintm(g_at1.as_ref(), m_at1.as_ref(), mcc1, ml1, 0, width_at1);
let mlprinted = MLPRINTED.load(Ordering::SeqCst);
if mlprinted != 0 { crate::ported::zle::zle_refresh::tcmultout("TCUP", mlprinted); }
use std::sync::atomic::Ordering as O;
let fd = crate::ported::init::SHTTY.load(O::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out_fd, b"\r");
if md2 != md1 { crate::ported::zle::zle_refresh::tc_downcurs((md2 - md1) as usize); }
if mc2 != 0 { crate::ported::zle::zle_refresh::tcmultout("TCRIGHT", mc2); }
let idx2 = (ml2 * zterm_columns + mc2) as usize;
let g_at2 = MGTAB.lock().unwrap().get(idx2).cloned().flatten();
let m_at2 = MTAB.lock().unwrap().get(idx2).cloned().flatten();
let width_at2 = g_at2.as_ref()
.map(|g| if g.widths.is_empty() { g.width } else { g.widths.get(mcc2 as usize).copied().unwrap_or(g.width) })
.unwrap_or(0);
clprintm(g_at2.as_ref(), m_at2.as_ref(), mcc2, ml2, 0, width_at2);
if mlprinted != 0 { crate::ported::zle::zle_refresh::tcmultout("TCUP", mlprinted); }
let _ = crate::ported::utils::write_loop(out_fd, b"\r");
let _ = (mcc1, mcc2);
0 }
pub fn complistmatches() -> i32 { use std::sync::atomic::Ordering;
if NOSELECT.load(Ordering::SeqCst) > 0 { NOSELECT.store(0, Ordering::SeqCst); }
let zterm_lines = crate::ported::utils::adjustlines() as i32;
let zterm_columns = crate::ported::utils::adjustcolumns() as i32;
let nlnct = crate::ported::zle::zle_refresh::NLNCT.load(Ordering::SeqCst);
let mselect = MSELECT.load(Ordering::SeqCst);
let minfo_asked = crate::ported::zle::compcore::MINFO
.get()
.and_then(|m| m.lock().ok().map(|g| g.asked))
.unwrap_or(0);
let errflag_v = crate::ported::utils::errflag.load(Ordering::SeqCst);
if (minfo_asked == 2 && mselect < 0) || nlnct >= zterm_lines
|| errflag_v != 0
{
crate::ported::zle::zle_refresh::SHOWINGLIST.store(0, Ordering::SeqCst); NOSELECT.store(1, Ordering::SeqCst); return 1;
}
crate::ported::mem::pushheap();
let extendedglob = crate::ported::zsh_h::isset(
crate::ported::zsh_h::EXTENDEDGLOB,
);
getcols("");
let calc_changed = crate::ported::zle::compresult::calclist(if mselect >= 0 { 1 } else { 0 });
let mlastcols = MLASTCOLS.load(Ordering::SeqCst);
let mlastlines = MLASTLINES.load(Ordering::SeqCst);
let listdat_nlines: i32 = crate::ported::zle::compcore::listdat
.get()
.and_then(|m| m.lock().ok().map(|g| g.nlines))
.unwrap_or(0);
let mnew = (calc_changed != 0 || mlastcols != zterm_columns
|| mlastlines != listdat_nlines) && mselect >= 0;
MNEW.store(if mnew { 1 } else { 0 }, Ordering::SeqCst);
let usezle = crate::ported::zsh_h::isset(crate::ported::zsh_h::USEZLE);
if listdat_nlines == 0
|| (mselect >= 0 && !(usezle ))
{
crate::ported::zle::zle_refresh::SHOWINGLIST.store(0, Ordering::SeqCst);
crate::ported::zle::zle_refresh::LISTSHOWN.store(0, Ordering::SeqCst);
NOSELECT.store(1, Ordering::SeqCst);
crate::ported::mem::popheap();
return 1;
}
if INSELECT.load(Ordering::SeqCst) != 0 || MLBEG.load(Ordering::SeqCst) >= 0 {
crate::ported::zle::zle_refresh::CLEARFLAG.store(0, Ordering::SeqCst);
}
MSCROLL.store(0, Ordering::SeqCst);
let listprompt = crate::ported::params::getsparam("LISTPROMPT");
if mselect >= 0 || MLBEG.load(Ordering::SeqCst) >= 0 || listprompt.is_some() {
crate::ported::zle::zle_main::trashzle();
crate::ported::zle::zle_refresh::SHOWINGLIST.store(0, Ordering::SeqCst);
crate::ported::zle::zle_refresh::LISTSHOWN.store(0, Ordering::SeqCst);
crate::ported::zle::zle_refresh::LASTLISTLEN.store(0, Ordering::SeqCst);
if listprompt.is_some() { crate::ported::zle::zle_refresh::CLEARFLAG.store(
if usezle { 1 } else { 0 }, Ordering::SeqCst);
MSCROLL.store(1, Ordering::SeqCst); } else { crate::ported::zle::zle_refresh::CLEARFLAG.store(1, Ordering::SeqCst); if let Some(m) = crate::ported::zle::compcore::MINFO.get() {
if let Ok(mut g) = m.lock() {
g.asked = if listdat_nlines + nlnct <= zterm_lines { 1 } else { 0 };
}
}
}
} else {
let r = crate::ported::zle::compresult::asklist();
if r != 0 { crate::ported::mem::popheap();
NOSELECT.store(1, Ordering::SeqCst);
return 1;
}
}
let mlbeg = MLBEG.load(Ordering::SeqCst);
if mlbeg >= 0 { let mhasstat = MHASSTAT.load(Ordering::SeqCst);
let mut new_mlend = mlbeg + zterm_lines - nlnct - mhasstat; let mline = MLINE.load(Ordering::SeqCst);
let mut adjusted_mlbeg = mlbeg;
while mline >= new_mlend { adjusted_mlbeg += 1; new_mlend += 1;
}
MLBEG.store(adjusted_mlbeg, Ordering::SeqCst);
MLEND.store(new_mlend, Ordering::SeqCst);
} else { MLEND.store(9_999_999, Ordering::SeqCst); }
if mnew { MTAB_BEEN_REALLOCATED.store(1, Ordering::SeqCst); let i = (zterm_columns * listdat_nlines) as usize; *MTAB.lock().unwrap() = vec![None; i]; *MGTAB.lock().unwrap() = vec![None; i]; MGTABSIZE.store(i as i32, Ordering::SeqCst); MLASTCOLS.store(zterm_columns, Ordering::SeqCst); MCOLS.store(zterm_columns, Ordering::SeqCst);
MLASTLINES.store(listdat_nlines, Ordering::SeqCst); MLINES.store(listdat_nlines, Ordering::SeqCst);
MMTABP.store(0, Ordering::SeqCst); }
let cap_size = (MAX_CAPLEN.load(Ordering::SeqCst) + 1).max(1) as usize;
*LAST_CAP.lock().unwrap() = String::with_capacity(cap_size);
let cur_onlnct = ONLNCT.load(Ordering::SeqCst);
let inselect = INSELECT.load(Ordering::SeqCst);
let mlbeg_cur = MLBEG.load(Ordering::SeqCst);
let molbeg = MOLBEG.load(Ordering::SeqCst);
let clearflag = crate::ported::zle::zle_refresh::CLEARFLAG
.load(Ordering::SeqCst);
if !mnew && inselect != 0 && cur_onlnct == nlnct && mlbeg_cur >= 0 && mlbeg_cur == molbeg
{
if NOSELECT.load(Ordering::SeqCst) == 0 { singledraw(); }
} else if compprintlist(if mselect >= 0 { 1 } else { 0 }) == 0 || clearflag == 0
{
NOSELECT.store(1, Ordering::SeqCst); }
ONLNCT.store(nlnct, Ordering::SeqCst); MOLBEG.store(MLBEG.load(Ordering::SeqCst), Ordering::SeqCst); MOCOL.store(MCOL.load(Ordering::SeqCst), Ordering::SeqCst); MOLINE.store(MLINE.load(Ordering::SeqCst), Ordering::SeqCst);
crate::ported::mem::popheap();
let _ = extendedglob;
NOSELECT.load(Ordering::SeqCst) }
pub static ONLNCT: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(-1);
pub fn adjust_mcol(wish: i32, tabp: &mut i32, grp: &mut i32) -> i32 { wish.max(0)
}
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct menustack { pub line: String, pub brbeg: Vec<u8>, pub brend: Vec<u8>, pub nbrbeg: i32, pub nbrend: i32, pub cs: i32, pub acc: i32, pub nmatches: i32, pub mline: i32, pub mlbeg: i32, pub nolist: i32, pub origline: String, pub origcs: i32, pub origll: i32, pub status: String, pub mode: i32, }
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct menusearch { pub str: String, pub line: i32, pub col: i32, pub back: i32, pub state: i32, pub ptr: usize, }
pub const MS_OK: i32 = 0; pub const MS_FAILED: i32 = 1; pub const MS_WRAPPED: i32 = 2;
pub const MAX_STATUS: usize = 128;
pub fn setmstatus( status: &mut String,
sline: &str,
sll: i32,
scs: i32,
csp: Option<&mut i32>,
llp: Option<&mut i32>,
lenp: Option<&mut i32>,
) -> Option<String> {
use std::sync::atomic::Ordering;
let mut ret: Option<String> = None;
let zlemetacs = crate::ported::zle::compcore::ZLEMETACS.load(Ordering::SeqCst);
let zlemetall = crate::ported::zle::compcore::ZLEMETALL.load(Ordering::SeqCst);
let lastend = crate::ported::zle::compcore::LASTEND.load(Ordering::SeqCst);
let wb = crate::ported::zle::compcore::WB.load(Ordering::SeqCst);
let mut p: String;
let mut s: String;
if let Some(csp_ref) = csp { *csp_ref = zlemetacs; if let Some(llp_ref) = llp { *llp_ref = zlemetall; } if let Some(lenp_ref) = lenp { *lenp_ref = lastend - wb; }
let zml = crate::ported::zle::compcore::ZLEMETALINE
.get()
.and_then(|m| m.lock().ok().map(|g| g.clone()))
.unwrap_or_default();
ret = Some(zml.clone());
let wb_u = wb.max(0) as usize;
let cs_u = zlemetacs.max(0) as usize;
p = zml.get(wb_u..cs_u).unwrap_or("").to_string();
if lastend < zlemetacs { s = String::new(); } else {
let le_u = lastend.max(0) as usize;
s = zml.get(cs_u..le_u).unwrap_or("").to_string(); }
crate::ported::zle::compcore::ZLEMETACS.store(0, Ordering::SeqCst); crate::ported::zle::zle_utils::foredel(zlemetall, 0); crate::ported::zle::zle_utils::spaceinline(sll); if let Some(zml_mutex) = crate::ported::zle::compcore::ZLEMETALINE.get() {
if let Ok(mut g) = zml_mutex.lock() {
if g.len() >= sll as usize {
let head: String = sline.chars().take(sll as usize).collect();
g.replace_range(..sll as usize, &head); } else {
*g = sline.chars().take(sll as usize).collect();
}
}
}
crate::ported::zle::compcore::ZLEMETACS.store(scs, Ordering::SeqCst); } else { p = crate::ported::zle::complete::COMPLASTPREFIX
.get_or_init(|| std::sync::Mutex::new(String::new()))
.lock().unwrap().clone();
s = crate::ported::zle::complete::COMPLASTSUFFIX
.get_or_init(|| std::sync::Mutex::new(String::new()))
.lock().unwrap().clone();
}
let pl = p.len() as i32; let sl = s.len() as i32; let zterm_columns = crate::ported::utils::adjustcolumns() as i32;
let max = if zterm_columns < MAX_STATUS as i32 { zterm_columns
} else {
MAX_STATUS as i32
} - 14;
if max > 12 { let h = (max - 2) >> 1;
status.clear();
status.push_str("interactive: "); if pl > h - 3 { status.push_str("..."); let skip = (pl - h - 3).max(0) as usize;
status.push_str(&p[skip..]); } else {
status.push_str(&p); }
status.push_str("[]"); if sl > h - 3 { let take = (h - 3).max(0) as usize;
status.push_str(&s.chars().take(take).collect::<String>()); status.push_str("..."); } else {
status.push_str(&s); }
}
ret }
pub fn msearchpush() -> i32 { 0
}
pub fn msearchpop() -> i32 { 0
}
pub fn msearch() -> i32 { use std::sync::atomic::Ordering;
let mut x = MCOL.load(Ordering::SeqCst);
let mut y = MLINE.load(Ordering::SeqCst);
let mcols = MCOLS.load(Ordering::SeqCst);
let listdat_nlines = crate::ported::zle::compcore::listdat
.get()
.and_then(|m| m.lock().ok().map(|g| g.nlines))
.unwrap_or(0);
let mut wrap = 0i32;
let owrap = MSEARCHSTATE.load(Ordering::SeqCst) & MS_WRAPPED;
let back = 0i32; let (mut ex, mut ey) = if back != 0 { (mcols - 1, -1i32)
} else { (0i32, listdat_nlines)
};
let mut p = (y * mcols + x).max(0) as usize;
let needle = MSEARCHSTR.lock().unwrap().clone();
let mtab_snapshot: Vec<Option<crate::ported::zle::comp_h::Cmatch>> =
MTAB.lock().unwrap().clone();
loop { if let Some(Some(m)) = mtab_snapshot.get(p) { let hay = m.disp.as_deref()
.unwrap_or_else(|| m.str.as_deref().unwrap_or(""));
if !needle.is_empty() && hay.contains(needle.as_str()) { MCOL.store(x, Ordering::SeqCst); MLINE.store(y, Ordering::SeqCst); return p as i32; }
}
if back != 0 {
if p == 0 { p = mtab_snapshot.len().saturating_sub(1); }
else { p -= 1; }
x -= 1;
if x < 0 { x = mcols - 1; y -= 1; }
} else {
p += 1; x += 1;
if x == mcols { x = 0; y += 1; }
}
if x == ex && y == ey { if back != 0 { x = mcols - 1; y = listdat_nlines - 1; p = (y * mcols + x).max(0) as usize; } else {
x = 0; y = 0; p = 0; }
ex = MCOL.load(Ordering::SeqCst); ey = MLINE.load(Ordering::SeqCst);
if wrap != 0 || (x == ex && y == ey) { MSEARCHSTATE.store(MS_FAILED | owrap, Ordering::SeqCst); break; }
MSEARCHSTATE.fetch_or(MS_WRAPPED, Ordering::SeqCst); wrap = 1; }
if p >= mtab_snapshot.len() { break; }
}
-1 }
pub static MSEARCHSTR: std::sync::LazyLock<std::sync::Mutex<String>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(String::new()));
pub static MSEARCHSTATE: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(MS_OK);
pub fn domenuselect() -> i32 { use std::sync::atomic::Ordering;
let mut _i: i32 = 0; let mut _acc: i32 = 0; let mut _wishcol: i32 = 0; let _setwish: i32 = 0; let oe = crate::ported::zle::compcore::onlyexpl.load(Ordering::SeqCst); let mut _wasnext: i32 = 0; let _space: i32 = 0; let _lbeg: i32 = 0; let mut step: i32 = 1; let _wrap: i32 = 0; let _pl = crate::ported::zle::zle_refresh::NLNCT.load(Ordering::SeqCst); let _broken: i32 = 0; let _first: i32 = 1; let mut _nolist: i32 = 0; let mut mode: i32 = 0; let _modecs: i32 = 0; let _modell: i32 = 0; let _modelen: i32 = 0; let _wasmeta: i32; let mut status = String::new();
let hasoldlist = false; if !hasoldlist {
return 2; }
*MSEARCHSTR.lock().unwrap() = String::new(); MSEARCHSTATE.store(MS_OK, Ordering::SeqCst);
crate::ported::signals::queue_signals();
_wasmeta = if crate::ported::zle::compcore::ZLEMETALINE.get().is_some() {
1
} else {
0
};
if let Some(s) = crate::ported::params::getsparam("MENUSCROLL") { let parsed: i32 = s.trim().parse().unwrap_or(0);
if parsed == 0 { let zterm_lines = crate::ported::utils::adjustlines() as i32;
let nlnct = crate::ported::zle::zle_refresh::NLNCT.load(Ordering::SeqCst);
step = (zterm_lines - nlnct) >> 1; } else if parsed < 0 { let zterm_lines = crate::ported::utils::adjustlines() as i32;
let nlnct = crate::ported::zle::zle_refresh::NLNCT.load(Ordering::SeqCst);
step = parsed + zterm_lines - nlnct;
if step < 0 { step = 1; } } else {
step = parsed;
}
}
if let Some(s) = crate::ported::params::getsparam("MENUMODE") { if s == "interactive" { mode = 1; let origline = crate::ported::zle::zle_tricky::ORIGLINE
.get()
.and_then(|m| m.lock().ok().map(|g| g.clone()))
.unwrap_or_default();
let l = origline.len() as i32;
crate::ported::zle::compcore::ZLEMETACS.store(0, Ordering::SeqCst);
crate::ported::zle::zle_utils::foredel( crate::ported::zle::compcore::ZLEMETALL.load(Ordering::SeqCst), 0);
crate::ported::zle::zle_utils::spaceinline(l); if let Some(m) = crate::ported::zle::compcore::ZLEMETALINE.get() {
if let Ok(mut g) = m.lock() {
if g.len() >= l as usize {
g.replace_range(..l as usize, &origline); } else {
*g = origline.clone();
}
}
}
crate::ported::zle::compcore::ZLEMETACS.store( crate::ported::zle::zle_tricky::ORIGCS.load(Ordering::SeqCst),
Ordering::SeqCst);
let _ = setmstatus(&mut status, "", 0, 0, None, None, None); } else if s.starts_with("search") { mode = if s.contains("back") { 3 } else { 2 }; }
}
crate::ported::signals::unqueue_signals();
let _ = (oe, step, mode, status);
0
}
pub fn menuselect() -> i32 { crate::ported::zle::zle_tricky::menucomplete()
}
pub fn setup_() -> i32 { 0
}
pub fn features_() -> i32 { 0
}
pub fn enables_() -> i32 { 0
}
pub fn menuselect_bindings() -> i32 { 0
}
pub fn boot_() -> i32 { menuselect_bindings();
0
}
pub fn cleanup_() -> i32 { 0
}
pub fn finish_() -> i32 { 0
}
pub static LAST_CAP: std::sync::LazyLock<std::sync::Mutex<String>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(String::new()));
pub static PATCOLS: std::sync::LazyLock<std::sync::Mutex<Vec<String>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(Vec::new()));
pub static PATCOLS_IDX: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(0);
pub static BEGPOS: std::sync::LazyLock<std::sync::Mutex<Vec<i32>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(vec![0xfffffff_i32; 11]));
pub static ENDPOS: std::sync::LazyLock<std::sync::Mutex<Vec<i32>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(vec![0xfffffff_i32; 11]));
pub static SENDPOS: std::sync::LazyLock<std::sync::Mutex<Vec<i32>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(vec![0xfffffff_i32; 11]));
pub static CURISCOLS: std::sync::LazyLock<std::sync::Mutex<Vec<String>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(vec![String::new(); 11]));
pub static COLNAMES: &[&str] = &[ "no", "fi", "di", "ln", "pi", "so", "bd", "cd", "or", "mi",
"su", "sg", "tw", "ow", "st", "ex",
"lc", "rc", "ec", "tc", "sp", "ma", "hi", "du", "sa",
];
pub static DEFCOLS: &[Option<&str>] = &[ Some("0"), Some("0"), Some("1;31"), Some("1;36"), Some("33"),
Some("1;35"), Some("1;33"), Some("1;33"), None, None,
Some("37;41"), Some("30;43"), Some("30;42"), Some("34;42"), Some("37;44"),
Some("1;32"), Some("\x1b["), Some("m"), None, Some("0"),
Some("0"), Some("7"), None, None, Some("0"),
];
pub const LC_FOLLOW_SYMLINKS: i32 = 0x0001;
pub static NOSELECT: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MSELECT: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(-1); pub static INSELECT: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MCOL: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MLINE: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MCOLS: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MLINES: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static SELECTED: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MLBEG: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(-1); pub static MLEND: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(9_999_999); pub static MSCROLL: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MRESTLINES:std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static MNEW: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MLASTCOLS: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MLASTLINES: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MHASSTAT: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MFIRSTL: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MLASTM: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static MLPRINTED: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MOLBEG: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(-2); pub static MOCOL: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MOLINE: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MSTATPRINTED:std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static MTAB_BEEN_REALLOCATED: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(0);
pub static MGTABSIZE: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static NREFS: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static CURISBEG: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static CURISSEND: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static CURISCOL: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static LR_CAPLEN: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0); pub static MAX_CAPLEN: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static MCOLORS: std::sync::LazyLock<std::sync::Mutex<listcols>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(listcols::default()));
pub static MTAB: std::sync::LazyLock<std::sync::Mutex<Vec<Option<crate::ported::zle::comp_h::Cmatch>>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(Vec::new()));
pub static MMTABP: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(0);
pub static MGTAB: std::sync::LazyLock<std::sync::Mutex<Vec<Option<crate::ported::zle::comp_h::Cmgroup>>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(Vec::new()));
pub static MGTABP: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(0);
pub fn calclist(showall: i32) -> i32 { let r = crate::ported::zle::compresult::calclist(showall);
let _ = showall;
r
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compprintfmt() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
let mut stop = 0i32;
let cc = compprintfmt("hello", 0, 0, 0, 0, &mut stop);
assert_eq!(cc, 5);
}
#[test]
fn col_indices_match_c() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(COL_NO, 0);
assert_eq!(COL_DI, 2);
assert_eq!(COL_EX, 15);
assert_eq!(COL_LC, 16);
assert_eq!(COL_EC, 18);
assert_eq!(COL_SA, 24);
}
#[test]
fn num_cols_matches_c() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(NUM_COLS, 25);
assert_eq!(COLNAMES.len(), 25);
assert_eq!(DEFCOLS.len(), 25);
}
#[test]
fn colnames_match_c() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(COLNAMES[COL_NO], "no");
assert_eq!(COLNAMES[COL_DI], "di");
assert_eq!(COLNAMES[COL_LN], "ln");
assert_eq!(COLNAMES[COL_EX], "ex");
assert_eq!(COLNAMES[COL_MA], "ma");
}
#[test]
fn defcols_match_c() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(DEFCOLS[COL_NO], Some("0"));
assert_eq!(DEFCOLS[COL_DI], Some("1;31"));
assert_eq!(DEFCOLS[COL_EX], Some("1;32"));
assert_eq!(DEFCOLS[COL_OR], None); assert_eq!(DEFCOLS[COL_MI], None); assert_eq!(DEFCOLS[COL_LC], Some("\x1b["));
assert_eq!(DEFCOLS[COL_RC], Some("m"));
}
#[test]
fn filecol_allocates_with_defaults() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
let fc = filecol("0;32");
assert_eq!(fc.col, "0;32");
assert!(fc.prog.is_none());
assert!(fc.next.is_none());
}
#[test]
fn filecol_empty_string() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
let fc = filecol("");
assert_eq!(fc.col, "");
assert!(fc.prog.is_none());
assert!(fc.next.is_none());
}
#[test]
fn col_indices_full_set_matches_c_layout() {
assert_eq!(COL_FI, 1);
assert_eq!(COL_LN, 3);
assert_eq!(COL_PI, 4);
assert_eq!(COL_SO, 5);
assert_eq!(COL_BD, 6);
assert_eq!(COL_CD, 7);
assert_eq!(COL_OR, 8);
assert_eq!(COL_MI, 9);
assert_eq!(COL_SU, 10);
assert_eq!(COL_SG, 11);
assert_eq!(COL_TW, 12);
assert_eq!(COL_OW, 13);
assert_eq!(COL_ST, 14);
assert_eq!(COL_RC, 17);
assert_eq!(COL_TC, 19);
assert_eq!(COL_SP, 20);
assert_eq!(COL_MA, 21); assert_eq!(COL_HI, 22); assert_eq!(COL_DU, 23); }
#[test]
fn colnames_entries_are_two_lowercase_letters() {
for (i, &name) in COLNAMES.iter().enumerate() {
assert_eq!(name.len(), 2,
"COLNAMES[{}] = {:?} must be exactly 2 chars", i, name);
for c in name.chars() {
assert!(c.is_ascii_lowercase(),
"COLNAMES[{}] = {:?} contains non-lowercase char {:?}",
i, name, c);
}
}
}
#[test]
fn colnames_has_no_duplicates() {
let unique: std::collections::HashSet<_> = COLNAMES.iter().copied().collect();
assert_eq!(unique.len(), COLNAMES.len(),
"duplicate entry in COLNAMES");
}
#[test]
fn defcols_and_colnames_have_equal_lengths() {
assert_eq!(DEFCOLS.len(), COLNAMES.len(),
"DEFCOLS and COLNAMES must have parallel indices");
assert_eq!(NUM_COLS, COLNAMES.len(),
"NUM_COLS must equal COLNAMES.len()");
}
#[test]
fn filecol_owns_its_col_string() {
let original = "0;31".to_string();
let fc = filecol(&original);
drop(original);
assert_eq!(fc.col, "0;31");
}
#[test]
fn filecol_distinct_calls_produce_independent_nodes() {
let a = filecol("red");
let b = filecol("blue");
assert_eq!(a.col, "red");
assert_eq!(b.col, "blue");
assert!(a.prog.is_none());
assert!(b.next.is_none());
}
#[test]
fn getcolval_empty_input_returns_empty() {
let r = getcolval("", 0);
assert_eq!(r, "");
}
#[test]
fn compprintnl_does_not_panic_outside_zle() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
let _ = compprintnl(0);
}
}