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 fn calclist(_showall: i32) -> i32 { 0
}
pub fn compprintlist(_showall: i32) -> i32 { 0
}
pub fn asklistscroll(total: usize, shown: usize) -> String { let _remaining = total.saturating_sub(shown);
format!("--More--({}/{})", shown, total)
}
pub fn compprintfmt(format: &str, matches_count: usize, group: &str) -> String { format
.replace("%d", &matches_count.to_string())
.replace("%g", group)
.replace("%%", "%")
}
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 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 zcputs(s: &str, color: Option<&str>) -> String { match color {
Some(c) => format!("\x1b[{}m{}\x1b[0m", c, s),
None => s.to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compprintfmt() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(
compprintfmt("Showing %d matches in %g", 42, "files"),
"Showing 42 matches in files"
);
}
#[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());
}
}
pub fn adjust_mcol(wish: i32, tabp: &mut i32, grp: &mut i32) -> i32 { wish.max(0)
}
pub fn boot_() -> i32 { menuselect_bindings();
0
}
pub fn cleanup_() -> i32 { 0
}
#[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 clprintfmt(p: &str, ml: i32) -> i32 { crate::ported::zle::zle_tricky::printfmt(p, ml, true, true)
}
pub fn clprintm() -> i32 { 0
}
pub fn complistmatches() -> i32 { 0
}
#[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
}
#[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 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 domenuselect() -> i32 { 0
}
pub fn enables_() -> i32 { 0
}
pub fn features_() -> i32 { 0
}
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 const MMARK: u32 = 1;
pub const MAX_POS: usize = 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"),
];
#[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>>, }
pub const LC_FOLLOW_SYMLINKS: i32 = 0x0001;
#[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, }
#[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 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 fn filecol(col: &str) -> filecol { filecol { prog: None, col: col.to_string(), next: None, } }
pub fn finish_() -> i32 { 0
}
pub fn getcoldef(s: &str) -> Option<String> { s.split_once(':').map(|(_, rest)| rest.to_string())
}
pub fn getcols(_lscol: &str) -> i32 { 0
}
#[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 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 menuselect() -> i32 { crate::ported::zle::zle_tricky::menucomplete()
}
pub fn menuselect_bindings() -> i32 { 0
}
pub fn msearch() -> i32 { 0
}
pub fn msearchpop() -> i32 { 0
}
pub fn msearchpush() -> i32 { 0
}
pub fn putfilecol(group: &str, filename: &str, m: u32, special: i32) -> i32 { let _ = group;
0
}
pub fn putmatchcol(group: &str, n: &str) -> i32 { let _ = group;
0
}
pub fn setmstatus(_status: &str, _sline: i32, _scs: i32, _np: &mut i32, _nl: &mut i32, _nc: &mut i32) -> i32 { 0
}
pub fn setup_() -> i32 { 0
}
#[allow(unused_variables)]
pub fn singlecalc(cp: &mut i32, l: i32, lcp: &mut i32) -> i32 { 0
}
pub fn singledraw() -> i32 { 0
}
pub fn zcoff() { }
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
}