use std::sync::atomic::AtomicI32;
use crate::ported::zsh_h::{isset, GLOBCOMPLETE, MENUCOMPLETE, RECEXACT};
#[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::textobjects::*;
#[allow(unused_imports)]
use crate::ported::zle::deltochar::*;
pub static USEMENU: AtomicI32 = AtomicI32::new(0);
pub static USEGLOB: AtomicI32 = AtomicI32::new(0);
pub static WOULDINSTAB: AtomicI32 = AtomicI32::new(0);
pub static NBRBEG: AtomicI32 = AtomicI32::new(0); pub static NBREND: AtomicI32 = AtomicI32::new(0);
pub static ORIGCS: AtomicI32 = AtomicI32::new(0); pub static ORIGLL: AtomicI32 = AtomicI32::new(0);
pub static INSUBSCR: AtomicI32 = AtomicI32::new(0);
pub static INSTRING: AtomicI32 = AtomicI32::new(0); pub static INBACKT: AtomicI32 = AtomicI32::new(0);
pub static ORIGLINE: std::sync::OnceLock<std::sync::Mutex<String>> =
std::sync::OnceLock::new();
pub static LASTPREBR: std::sync::OnceLock<std::sync::Mutex<String>> =
std::sync::OnceLock::new(); pub static LASTPOSTBR: std::sync::OnceLock<std::sync::Mutex<String>> =
std::sync::OnceLock::new();
pub static COMPQUOTE: std::sync::OnceLock<std::sync::Mutex<String>> =
std::sync::OnceLock::new(); pub static AUTOQ: std::sync::OnceLock<std::sync::Mutex<String>> =
std::sync::OnceLock::new();
pub static MENUCMP: AtomicI32 = AtomicI32::new(0);
pub static COMPPREF: AtomicI32 = AtomicI32::new(0);
pub static VALIDLIST: AtomicI32 = AtomicI32::new(0);
pub static SHOWAGAIN: AtomicI32 = AtomicI32::new(0);
pub static LASTAMBIG: AtomicI32 = AtomicI32::new(0);
pub static BASHLISTFIRST: AtomicI32 = AtomicI32::new(0);
pub static AMENU: AtomicI32 = AtomicI32::new(0);
pub const META: char = '\u{83}';
pub fn metafy_line(s: &str) -> String { let mut result = String::with_capacity(s.len() * 2);
for c in s.chars() {
if c == META || (c as u32) >= 0x83 {
result.push(META);
result.push(char::from_u32((c as u32) ^ 32).unwrap_or(c));
} else {
result.push(c);
}
}
result
}
pub fn unmetafy_line(s: &str) -> String { let mut result = String::with_capacity(s.len());
let mut chars = s.chars().peekable();
while let Some(c) = chars.next() {
if c == META {
if let Some(&next) = chars.peek() {
chars.next();
result.push(char::from_u32((next as u32) ^ 32).unwrap_or(next));
}
} else {
result.push(c);
}
}
result
}
pub fn has_real_token(s: &str) -> bool {
let special = ['$', '`', '"', '\'', '\\', '{', '}', '[', ']', '*', '?', '~'];
let mut escaped = false;
for c in s.chars() {
if escaped {
escaped = false;
continue;
}
if c == '\\' {
escaped = true;
continue;
}
if special.contains(&c) {
return true;
}
}
false
}
pub fn pfxlen(s1: &str, s2: &str) -> usize { s1.chars()
.zip(s2.chars())
.take_while(|(a, b)| a == b)
.count()
}
pub fn sfxlen(s1: &str, s2: &str) -> usize { s1.chars()
.rev()
.zip(s2.chars().rev())
.take_while(|(a, b)| a == b)
.count()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pfxlen() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(pfxlen("hello", "help"), 3);
assert_eq!(pfxlen("abc", "xyz"), 0);
assert_eq!(pfxlen("test", "test"), 4);
}
#[test]
fn test_sfxlen() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(sfxlen("testing", "running"), 3);
assert_eq!(sfxlen("abc", "xyz"), 0);
}
#[test]
fn addx_skips_when_cursor_in_middle_of_word() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
use std::sync::atomic::Ordering;
use crate::ported::zle::zle_main::{ZLECS, ZLELINE, ZLELL};
use crate::ported::zle::compcore::ADDEDX;
*ZLELINE.lock().unwrap() = "hello".chars().collect();
ZLECS.store(2, Ordering::SeqCst); ZLELL.store(5, Ordering::SeqCst);
INSTRING.store(crate::ported::zsh_h::QT_NONE, Ordering::SeqCst);
COMPPREF.store(0, Ordering::SeqCst);
ADDEDX.store(99, Ordering::SeqCst);
let mut snap = String::new();
let added = addx(&mut snap);
assert_eq!(added, 0, "no insertion when cursor lands on word-char");
assert_eq!(ADDEDX.load(Ordering::SeqCst), 0);
assert!(snap.is_empty(), "ptmp must be NULL/empty when addx doesn't fire");
assert_eq!(
ZLELINE.lock().unwrap().iter().collect::<String>(),
"hello",
"buffer must be untouched"
);
}
#[test]
fn addx_inserts_at_end_of_line() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
use std::sync::atomic::Ordering;
use crate::ported::zle::zle_main::{ZLECS, ZLELINE, ZLELL};
use crate::ported::zle::compcore::ADDEDX;
*ZLELINE.lock().unwrap() = "abc".chars().collect();
ZLECS.store(3, Ordering::SeqCst); ZLELL.store(3, Ordering::SeqCst);
INSTRING.store(crate::ported::zsh_h::QT_NONE, Ordering::SeqCst);
COMPPREF.store(0, Ordering::SeqCst);
let mut snap = String::new();
let added = addx(&mut snap);
assert_eq!(added, 1, "exactly one 'x' inserted at EOL");
assert_eq!(ADDEDX.load(Ordering::SeqCst), 1);
assert_eq!(snap, "abc", "snapshot is pre-edit buffer");
assert_eq!(
ZLELINE.lock().unwrap().iter().collect::<String>(),
"abcx"
);
}
#[test]
fn addx_inserts_x_space_when_comppref_on_nonblank() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
use std::sync::atomic::Ordering;
use crate::ported::zle::zle_main::{ZLECS, ZLELINE, ZLELL};
use crate::ported::zle::compcore::ADDEDX;
*ZLELINE.lock().unwrap() = "ab".chars().collect();
ZLECS.store(1, Ordering::SeqCst); ZLELL.store(2, Ordering::SeqCst);
INSTRING.store(crate::ported::zsh_h::QT_NONE, Ordering::SeqCst);
COMPPREF.store(1, Ordering::SeqCst);
let mut snap = String::new();
let added = addx(&mut snap);
assert_eq!(added, 2, "comppref non-blank → 'x ' (2 chars)");
assert_eq!(ADDEDX.load(Ordering::SeqCst), 2);
COMPPREF.store(0, Ordering::SeqCst);
}
#[test]
fn addx_inserts_when_cursor_on_separator() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
use std::sync::atomic::Ordering;
use crate::ported::zle::zle_main::{ZLECS, ZLELINE, ZLELL};
*ZLELINE.lock().unwrap() = "echo|".chars().collect();
ZLECS.store(4, Ordering::SeqCst); ZLELL.store(5, Ordering::SeqCst);
INSTRING.store(crate::ported::zsh_h::QT_NONE, Ordering::SeqCst);
COMPPREF.store(0, Ordering::SeqCst);
let mut snap = String::new();
let added = addx(&mut snap);
assert_eq!(added, 1, "separator at cursor → insert 'x'");
}
#[test]
fn checkparams_hascompmod_gate() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
use std::sync::atomic::Ordering;
crate::ported::params::setsparam("abc", "v1");
crate::ported::params::setsparam("abcd", "v2");
MENUCMP.store(0, Ordering::SeqCst);
crate::ported::zle::zle_main::HASCOMPMOD.store(true, Ordering::SeqCst);
crate::ported::zle::zle_main::HASCOMPMOD.store(true, Ordering::SeqCst);
crate::ported::zle::zle_main::HASCOMPMOD.store(false, Ordering::SeqCst);
assert_eq!(checkparams("abc"), 1,
"with !hascompmod, exact + non-menu → return 1");
crate::ported::zle::zle_main::HASCOMPMOD.store(false, Ordering::SeqCst);
crate::ported::params::setsparam("abc", "");
crate::ported::params::setsparam("abcd", "");
}
#[test]
fn test_has_real_token() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert!(has_real_token("$HOME"));
assert!(has_real_token("*.txt"));
assert!(!has_real_token("hello"));
assert!(!has_real_token("test\\$var")); }
#[test]
fn dupstrspace_appends_space() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(dupstrspace("hello"), "hello ");
}
#[test]
fn dupstrspace_empty_input() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
assert_eq!(dupstrspace(""), " ");
}
#[test]
fn freebrinfo_drops_chain() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
use crate::ported::zle::zle_h::brinfo;
let head = Some(Box::new(brinfo {
next: Some(Box::new(brinfo {
next: None,
prev: None,
str: "second".into(),
pos: 7,
qpos: 8,
curpos: 9,
})),
prev: None,
str: "first".into(),
pos: 1,
qpos: 2,
curpos: 3,
}));
freebrinfo(head);
}
#[test]
fn dupbrinfo_clones_chain() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
use crate::ported::zle::zle_h::brinfo;
let src = Box::new(brinfo {
next: Some(Box::new(brinfo {
next: Some(Box::new(brinfo {
next: None,
prev: None,
str: "C".into(),
pos: 30,
qpos: 31,
curpos: 32,
})),
prev: None,
str: "B".into(),
pos: 20,
qpos: 21,
curpos: 22,
})),
prev: None,
str: "A".into(),
pos: 10,
qpos: 11,
curpos: 12,
});
let (head, last) = dupbrinfo(Some(&*src));
assert!(last.is_some());
let h = head.as_ref().unwrap();
assert_eq!(h.str, "A");
assert_eq!(h.pos, 10);
assert_eq!(h.qpos, 11);
assert_eq!(h.curpos, 12);
let n = h.next.as_ref().unwrap();
assert_eq!(n.str, "B");
assert_eq!(n.pos, 20);
let n = n.next.as_ref().unwrap();
assert_eq!(n.str, "C");
assert_eq!(n.pos, 30);
assert!(n.next.is_none());
}
#[test]
fn dupbrinfo_empty_returns_none() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
let (head, last) = dupbrinfo(None);
assert!(head.is_none());
assert!(last.is_none());
}
#[test]
fn spellword_zeroes_globals_returns_docomplete() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
use std::sync::atomic::Ordering;
USEMENU.store(99, Ordering::SeqCst);
USEGLOB.store(99, Ordering::SeqCst);
WOULDINSTAB.store(99, Ordering::SeqCst);
let r = spellword();
assert_eq!(r, 0);
assert_eq!(USEMENU.load(Ordering::SeqCst), 0);
assert_eq!(USEGLOB.load(Ordering::SeqCst), 0);
assert_eq!(WOULDINSTAB.load(Ordering::SeqCst), 0);
}
}
pub fn acceptandmenucomplete() -> i32 { use std::sync::atomic::Ordering;
if MENUCMP.load(Ordering::SeqCst) == 0 {
return 1;
}
MENUCMP.store(2, Ordering::SeqCst);
docomplete(crate::ported::zle::zle_h::COMP_COMPLETE)
}
pub fn addx(ptmp: &mut String) -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_main::{ZLECS, ZLELINE, ZLELL};
use crate::ported::zsh_h::QT_NONE;
use crate::ported::zle::compcore::ADDEDX;
let cs = ZLECS.load(Ordering::SeqCst) as usize;
let ll = ZLELL.load(Ordering::SeqCst) as usize;
let instring = INSTRING.load(Ordering::SeqCst);
let comppref = COMPPREF.load(Ordering::SeqCst) != 0;
let (ch_at, prev_at): (Option<char>, Option<char>) = {
let line = ZLELINE.lock().unwrap();
let at = line.get(cs).copied();
let prev = if cs > 0 { line.get(cs - 1).copied() } else { None };
(at, prev)
};
let is_iblank = matches!(ch_at, Some(' ' | '\t'));
let is_blank_unescaped = is_iblank
&& (cs == 0 || prev_at != Some('\\'));
let cs_at_end = ch_at.is_none() || cs >= ll;
let is_newline = ch_at == Some('\n'); let is_separator = matches!(ch_at,
Some(')' | '`' | '}' | ';' | '|' | '&' | '>' | '<')); let is_instring_quote = instring != QT_NONE && matches!(ch_at, Some('"' | '\''));
let addspace = comppref && ch_at.is_some()
&& !matches!(ch_at, Some(' ' | '\t'));
let fire = cs_at_end || is_newline || is_blank_unescaped
|| is_separator || is_instring_quote || addspace;
if fire {
let snap: String = ZLELINE.lock().unwrap().iter().collect();
*ptmp = snap;
let mut line = ZLELINE.lock().unwrap();
line.insert(cs, 'x');
if addspace {
line.insert(cs + 1, ' ');
}
drop(line);
let added = if addspace { 2 } else { 1 };
ADDEDX.store(added, Ordering::SeqCst);
ZLELL.fetch_add(added as usize, Ordering::SeqCst);
added
} else {
ADDEDX.store(0, Ordering::SeqCst);
ptmp.clear();
0
}
}
pub fn checkparams(p: &str) -> i32 { use std::sync::atomic::Ordering;
let l = p.len();
let mut n = 0;
let mut exact = false;
if let Ok(tab) = crate::ported::params::paramtab().read() { for name in tab.keys() { if name.starts_with(p) { n += 1; if name.len() == l { exact = true; }
if n >= 2 { break;
}
}
}
}
if n == 1 { return if crate::ported::params::getsparam(p).is_some() { 1 } else { 0 };
}
let menucmp = MENUCMP.load(Ordering::SeqCst) != 0;
let hascompmod = crate::ported::zle::zle_main::HASCOMPMOD
.load(Ordering::SeqCst);
let recexact = isset(RECEXACT);
if !menucmp && exact && (!hascompmod || recexact) { 1
} else {
0
}
}
pub fn cmphaswilds(str: &str) -> i32 { let bytes = str.as_bytes();
if bytes.len() == 1 && (bytes[0] == b'[' || bytes[0] == b']') {
return 0;
}
let mut idx = 0;
if bytes.len() >= 2 && bytes[0] == b'%' && bytes[1] == b'?' {
idx = 2;
}
let mut esc = false;
while idx < bytes.len() {
let c = bytes[idx];
if esc {
esc = false;
} else if c == b'\\' {
esc = true;
} else if c == b'*' || c == b'?' || c == b'[' {
return 1;
}
idx += 1;
}
0
}
pub fn completecall(args: &[String]) -> i32 { docomplete(crate::ported::zle::zle_h::COMP_COMPLETE)
}
pub fn completeword() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::{COMP_COMPLETE, COMP_LIST_COMPLETE};
USEMENU.store(0, Ordering::SeqCst); USEGLOB.store(1, Ordering::SeqCst); WOULDINSTAB.store(0, Ordering::SeqCst); docomplete(COMP_COMPLETE).max(COMP_LIST_COMPLETE - COMP_LIST_COMPLETE)
}
pub fn deletecharorlist() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_LIST_COMPLETE;
USEMENU.store(0, Ordering::SeqCst); USEGLOB.store(1, Ordering::SeqCst); WOULDINSTAB.store(0, Ordering::SeqCst); if crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst) == crate::ported::zle::zle_main::ZLELL.load(std::sync::atomic::Ordering::SeqCst) {
docomplete(COMP_LIST_COMPLETE)
} else {
crate::ported::zle::zle_misc::deletechar()
}
}
pub fn docomplete(lst: i32) -> i32 { let _ = lst;
0
}
pub fn docompletion() -> i32 { crate::ported::zle::compcore::do_completion(
"", 0, crate::ported::zle::zle_h::COMP_LIST_COMPLETE,
)
}
pub fn doexpandhist() -> i32 { use std::sync::atomic::Ordering;
let line = crate::ported::zle::compcore::ZLELINE
.get_or_init(|| std::sync::Mutex::new(String::new()))
.lock().map(|g| g.clone()).unwrap_or_default();
if line.is_empty() { return 0; }
if !line.contains('!') { return 0; } let expanded = line.clone(); if let Ok(mut g) = crate::ported::zle::compcore::ZLELINE
.get_or_init(|| std::sync::Mutex::new(String::new())).lock()
{
*g = expanded.clone();
crate::ported::zle::compcore::ZLELL.store(
g.len() as i32, Ordering::Relaxed,
);
crate::ported::zle::compcore::ZLECS.store(
g.len() as i32, Ordering::Relaxed,
);
}
1 }
pub fn doexpansion() -> i32 { 0
}
pub fn dupbrinfo( mut p: Option<&crate::ported::zle::zle_h::brinfo>,
) -> (
Option<crate::ported::zle::zle_h::BrinfoPtr>,
Option<*const crate::ported::zle::zle_h::brinfo>,
) {
let mut head: Option<crate::ported::zle::zle_h::BrinfoPtr> = None; let mut last_ptr: Option<*const crate::ported::zle::zle_h::brinfo> = None;
let mut tail: *mut Option<crate::ported::zle::zle_h::BrinfoPtr> = &mut head;
while let Some(node) = p { let cloned = Box::new(crate::ported::zle::zle_h::brinfo { next: None, prev: None, str: node.str.clone(), pos: node.pos, qpos: node.qpos, curpos: node.curpos, });
unsafe {
*tail = Some(cloned);
let inserted = (*tail).as_mut().unwrap();
last_ptr = Some(inserted.as_ref() as *const _);
tail = &mut inserted.next;
}
p = node.next.as_deref(); }
(head, last_ptr)
}
pub fn dupstrspace(str: &str) -> String { let len = str.len(); let mut out = String::with_capacity(len + 2); out.push_str(str); out.push(' '); out }
pub fn endoflist() -> i32 { 0
}
pub fn expandcmdpath() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_EXPAND;
USEMENU.store(0, Ordering::SeqCst);
USEGLOB.store(0, Ordering::SeqCst);
WOULDINSTAB.store(0, Ordering::SeqCst);
docomplete(COMP_EXPAND)
}
pub fn expandhistory() -> i32 { if doexpandhist() == 0 {
return 1;
}
0
}
pub fn expandorcomplete() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_EXPAND_COMPLETE;
USEMENU.store(0, Ordering::SeqCst); USEGLOB.store(1, Ordering::SeqCst); WOULDINSTAB.store(0, Ordering::SeqCst); docomplete(COMP_EXPAND_COMPLETE) }
pub fn expandorcompleteprefix() -> i32 { use std::sync::atomic::Ordering;
COMPPREF.store(1, Ordering::SeqCst); let ret = expandorcomplete(); if crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst) > 0 && crate::ported::zle::zle_main::ZLELINE.lock().unwrap()[crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst) - 1] == ' ' { crate::ported::zle::zle_misc::makesuffixstr(None, Some("\\-"), 0); }
COMPPREF.store(0, Ordering::SeqCst); ret
}
pub fn expandword() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_EXPAND;
USEMENU.store(0, Ordering::SeqCst); USEGLOB.store(0, Ordering::SeqCst); WOULDINSTAB.store(0, Ordering::SeqCst); docomplete(COMP_EXPAND) }
pub fn fixmagicspace() { crate::ported::zle::compcore::LASTCHAR.store((b' ' as crate::ported::zle::zle_main::ZleInt) as i32, std::sync::atomic::Ordering::SeqCst);
crate::ported::zle::zle_main::LASTCHAR_WIDE.store((b' ' as crate::ported::zle::zle_main::ZleInt) as i32, std::sync::atomic::Ordering::SeqCst);
crate::ported::zle::zle_main::LASTCHAR_WIDE_VALID.store(1, std::sync::atomic::Ordering::SeqCst);
}
pub fn freebrinfo(p: Option<crate::ported::zle::zle_h::BrinfoPtr>) { drop(p);
}
pub fn get_comp_string() -> Option<String> { let snap: String = crate::ported::zle::zle_main::ZLELINE.lock().unwrap().iter().collect();
let cs = crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst).min(snap.len());
let bytes = snap.as_bytes();
let mut start = cs;
while start > 0 && !bytes[start - 1].is_ascii_whitespace() {
start -= 1;
}
let mut end = cs;
while end < bytes.len() && !bytes[end].is_ascii_whitespace() {
end += 1;
}
if start == end {
return None;
}
Some(snap[start..end].to_string())
}
pub fn getcurcmd() -> Option<String> { let snap: String = crate::ported::zle::zle_main::ZLELINE.lock().unwrap().iter().collect();
let cs = crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst).min(snap.len());
let prefix = &snap[..cs];
let mut last_seg_start = 0;
for (i, b) in prefix.bytes().enumerate() {
if matches!(b, b'|' | b';' | b'&') {
last_seg_start = i + 1;
}
}
let seg = prefix[last_seg_start..].trim_start();
let cmd: String = seg
.chars()
.take_while(|c| !c.is_ascii_whitespace())
.collect();
if cmd.is_empty() {
return None;
}
Some(cmd)
}
pub fn inststr(s: &str) -> i32 { inststrlen(s, true, -1)
}
pub fn inststrlen( str: &str,
move_cursor: bool,
mut len: i32,
) -> i32 {
if len == 0 || str.is_empty() {
return 0;
}
if len == -1 {
len = str.len() as i32;
}
let n = (len as usize).min(str.len());
for (i, ch) in str.chars().take(n).enumerate() {
crate::ported::zle::zle_main::ZLELINE.lock().unwrap().insert(crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst) + i, ch);
}
if move_cursor {
crate::ported::zle::zle_main::ZLECS.fetch_add(n, std::sync::atomic::Ordering::SeqCst); }
len
}
pub fn listchoices() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_LIST_COMPLETE;
let menu = isset(MENUCOMPLETE) as i32;
USEMENU.store(menu, Ordering::SeqCst);
let glob = isset(GLOBCOMPLETE) as i32;
USEGLOB.store(glob, Ordering::SeqCst);
WOULDINSTAB.store(0, Ordering::SeqCst);
docomplete(COMP_LIST_COMPLETE)
}
pub fn listexpand() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_LIST_EXPAND;
let menu = isset(MENUCOMPLETE) as i32;
USEMENU.store(menu, Ordering::SeqCst); let glob = isset(GLOBCOMPLETE) as i32;
USEGLOB.store(glob, Ordering::SeqCst); WOULDINSTAB.store(0, Ordering::SeqCst); docomplete(COMP_LIST_EXPAND) }
pub fn listlist(items: &[String], cols: usize) -> i32 { let num = items.len(); if num == 0 {
return 0;
}
let mut lens: Vec<usize> = items.iter().map(|s| s.chars().count() + 2).collect(); let longest = *lens.iter().max().unwrap_or(&1); if longest >= cols {
return num as i32;
}
let ncols = (cols / longest).max(1);
let nlines = num.div_ceil(ncols); use std::sync::atomic::Ordering;
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
let out_fd = if fd >= 0 { fd } else { 1 };
let mut row = String::new();
for (i, s) in items.iter().enumerate() {
row.push_str(s);
let pad = longest - lens[i];
row.push_str(&" ".repeat(pad));
if (i + 1) % ncols == 0 {
let line = row.trim_end();
let _ = crate::ported::utils::write_loop(out_fd, line.as_bytes());
let _ = crate::ported::utils::write_loop(out_fd, b"\n");
row.clear();
}
}
if !row.is_empty() {
let line = row.trim_end();
let _ = crate::ported::utils::write_loop(out_fd, line.as_bytes());
let _ = crate::ported::utils::write_loop(out_fd, b"\n");
}
let _ = (lens.pop(),);
nlines as i32
}
pub fn magicspace() -> i32 { fixmagicspace(); let ret = expandhistory();
if ret != 0 {
crate::ported::zle::zle_main::ZLELINE.lock().unwrap().insert(crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst), ' ');
crate::ported::zle::zle_main::ZLECS.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
ret
}
pub fn menucomplete() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_COMPLETE;
USEMENU.store(1, Ordering::SeqCst); USEGLOB.store(1, Ordering::SeqCst); WOULDINSTAB.store(0, Ordering::SeqCst); docomplete(COMP_COMPLETE) }
pub fn menuexpandorcomplete() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_EXPAND_COMPLETE;
USEMENU.store(1, Ordering::SeqCst); USEGLOB.store(1, Ordering::SeqCst); WOULDINSTAB.store(0, Ordering::SeqCst); docomplete(COMP_EXPAND_COMPLETE) }
pub fn parambeg(s: &str, offs: usize) -> Option<usize> { let bytes = s.as_bytes();
if offs > bytes.len() || offs == 0 {
return None;
}
let mut p = offs.min(bytes.len()) - 1;
loop {
if bytes[p] == b'$' {
while p > 0 && bytes[p - 1] == b'$' {
p -= 1;
}
while p + 2 < bytes.len() && bytes[p + 1] == b'$' && bytes[p + 2] == b'$' {
p += 2;
}
return Some(p);
}
if p == 0 {
return None;
}
p -= 1;
}
}
pub fn printfmt(fmt: &str, n: i32, dopr: bool, doesc: bool) -> i32 { let bytes = fmt.as_bytes();
let mut i = 0;
let mut cc = 0i32; let mut out = String::new();
while i < bytes.len() {
let c = bytes[i];
if doesc && c == b'%' { i += 1;
while i < bytes.len() && (bytes[i]).is_ascii_digit() {
i += 1;
}
if i >= bytes.len() {
break;
}
match bytes[i] {
b'%' => { out.push('%');
cc += 1;
}
b'n' => { let s = n.to_string();
cc += s.chars().count() as i32;
out.push_str(&s);
}
b'B' | b'b' | b'S' | b's' | b'U' | b'u' | b'F' | b'f' | b'K' | b'k' => {
}
b'{' => {
i += 1;
while i < bytes.len() && bytes[i] != b'}' {
out.push(bytes[i] as char);
i += 1;
}
}
ch => {
out.push(ch as char);
cc += 1;
}
}
i += 1;
} else {
out.push(c as char);
cc += 1;
i += 1;
}
}
if dopr {
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, out.as_bytes());
let _ = crate::ported::utils::write_loop(out_fd, b"\n");
}
cc
}
pub fn processcmd() -> i32 { let s = match getcurcmd() {
Some(s) if !s.is_empty() => s,
_ => return 1, };
let m = crate::ported::zle::zle_main::ZMOD.lock().unwrap().mult; crate::ported::zle::zle_main::ZMOD.lock().unwrap().mult = 1; let _ = crate::ported::zle::zle_hist::pushline(); crate::ported::zle::zle_main::ZMOD.lock().unwrap().mult = m; let q = quotename(&s, 0);
let combined = format!("run-help {}", q);
for (i, ch) in combined.chars().enumerate() {
crate::ported::zle::zle_main::ZLELINE.lock().unwrap().insert(crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst) + i, ch);
}
crate::ported::zle::zle_main::ZLECS.fetch_add(combined.chars().count(), std::sync::atomic::Ordering::SeqCst);
0
}
pub fn quotename(s: &str, instring: i32) -> String { use crate::ported::zsh_h::{
QT_BACKSLASH, QT_DOLLARS, QT_DOUBLE, QT_NONE, QT_SINGLE,
};
let raw = if instring == QT_NONE { QT_BACKSLASH } else { instring };
let qt = if raw == QT_BACKSLASH {
crate::ported::zsh_h::QT_BACKSLASH
} else if raw == QT_SINGLE {
crate::ported::zsh_h::QT_SINGLE
} else if raw == QT_DOUBLE {
crate::ported::zsh_h::QT_DOUBLE
} else if raw == QT_DOLLARS {
crate::ported::zsh_h::QT_DOLLARS
} else {
crate::ported::zsh_h::QT_NONE
};
crate::ported::utils::quotestring(s, qt)
}
pub fn reversemenucomplete() -> i32 { use std::sync::atomic::Ordering;
WOULDINSTAB.store(0, Ordering::SeqCst); crate::ported::zle::zle_main::ZMOD.lock().unwrap().mult = -crate::ported::zle::zle_main::ZMOD.lock().unwrap().mult; menucomplete() }
pub fn spellword() -> i32 { use std::sync::atomic::Ordering;
use crate::ported::zle::zle_h::COMP_SPELL;
USEMENU.store(0, Ordering::SeqCst); USEGLOB.store(0, Ordering::SeqCst); WOULDINSTAB.store(0, Ordering::SeqCst); docomplete(COMP_SPELL) }
pub fn usetab(keybuf: &[u8]) -> i32 { use std::sync::atomic::Ordering;
if keybuf.first() != Some(&b'\t') || keybuf.len() > 1 {
return 0;
}
let mut i = crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst);
while i > 0 {
let c = crate::ported::zle::zle_main::ZLELINE.lock().unwrap()[i - 1];
if c == '\n' {
break;
}
if c != '\t' && c != ' ' {
return 0;
}
i -= 1;
}
let _ = WOULDINSTAB.load(Ordering::SeqCst);
1
}