use crate::ported::utils::{adjustcolumns, adjustlines};
use std::io::Write;
use std::sync::atomic::AtomicI32;
pub static try_tryflag: std::sync::atomic::AtomicI64 = std::sync::atomic::AtomicI64::new(0);
pub fn selectlist(items: &[&str], start: usize) -> usize {
let mut stderr = std::io::stderr().lock();
let ct = items.len(); if ct == 0 {
return 0;
}
let mut longest: usize = 1; for ap in items {
let aplen = ap.chars().count(); if aplen > longest {
longest = aplen; }
}
longest += 1; let mut t0 = ct; while t0 != 0 {
t0 /= 10; longest += 1; }
let zterm_columns = adjustcolumns(); let zterm_lines = adjustlines();
let mut fct: usize = (zterm_columns.saturating_sub(1)) / (longest + 3); let fw: usize;
if fct == 0 {
fct = 1; fw = 0; } else {
fw = (zterm_columns - 1) / fct; }
let colsz = (ct + fct - 1) / fct;
let mut t1 = start;
let max_lines = zterm_lines.saturating_sub(2);
while t1 < colsz && (t1.saturating_sub(start)) < max_lines {
let mut idx = t1; if idx >= ct {
let _ = stderr.write_all(b"\n");
t1 += 1;
continue;
}
loop {
let entry = items[idx];
let mut t2 = entry.chars().count() + 2;
let t3 = idx + 1;
let _ = write!(stderr, "{}) {}", t3, entry);
let mut digits = t3;
while digits != 0 {
t2 += 1;
digits /= 10;
}
while t2 < fw {
let _ = stderr.write_all(b" ");
t2 += 1;
}
let mut t0 = colsz;
while t0 != 0 && idx + 1 < ct {
t0 -= 1;
idx += 1;
if t0 == 0 {
break;
}
}
if idx + 1 >= ct {
break;
} }
let _ = stderr.write_all(b"\n"); t1 += 1;
}
let _ = stderr.flush();
if t1 < colsz {
t1
} else {
0
} }
static LOOP_DEPTH: AtomicI32 = AtomicI32::new(0);
static CONT_FLAG: AtomicI32 = AtomicI32::new(0);
static BREAK_LEVEL: AtomicI32 = AtomicI32::new(0);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_selectlist_returns_zero_when_full_fits() {
let _g = crate::test_util::global_state_lock();
let items = ["one", "two", "three"];
let r = selectlist(&items, 0);
assert!(r < items.len() || r == 0);
}
#[test]
fn selectlist_empty_returns_zero() {
let _g = crate::test_util::global_state_lock();
assert_eq!(selectlist(&[], 0), 0);
}
#[test]
fn selectlist_start_zero_returns_valid_count() {
let _g = crate::test_util::global_state_lock();
let items = ["a", "b", "c"];
let r = selectlist(&items, 0);
assert!(r <= items.len());
}
#[test]
fn selectlist_single_item_no_panic() {
let _g = crate::test_util::global_state_lock();
let r = selectlist(&["only"], 0);
let _ = r;
}
#[test]
fn selectlist_empty_string_entries_no_panic() {
let _g = crate::test_util::global_state_lock();
let items = ["", "", ""];
let _ = selectlist(&items, 0);
}
#[test]
fn selectlist_long_items_no_panic() {
let _g = crate::test_util::global_state_lock();
let long = "x".repeat(500);
let items = [long.as_str(), "short"];
let _ = selectlist(&items, 0);
}
#[test]
fn selectlist_multibyte_entries_no_panic() {
let _g = crate::test_util::global_state_lock();
let items = ["日本", "中文", "한국어"];
let _ = selectlist(&items, 0);
}
#[test]
fn selectlist_many_items_no_panic() {
let _g = crate::test_util::global_state_lock();
let items: Vec<String> = (0..100).map(|i| format!("item{}", i)).collect();
let refs: Vec<&str> = items.iter().map(|s| s.as_str()).collect();
let _ = selectlist(&refs, 0);
}
#[test]
fn selectlist_start_in_range_no_panic() {
let _g = crate::test_util::global_state_lock();
let items = ["a", "b", "c", "d", "e"];
let _ = selectlist(&items, 2);
}
#[test]
fn selectlist_is_deterministic() {
let _g = crate::test_util::global_state_lock();
let items = ["a", "b", "c"];
let first = selectlist(&items, 0);
for _ in 0..5 {
assert_eq!(selectlist(&items, 0), first);
}
}
#[test]
fn selectlist_return_bounded_by_items_len() {
let _g = crate::test_util::global_state_lock();
for sz in [1usize, 3, 5, 20] {
let items: Vec<String> = (0..sz).map(|i| format!("i{}", i)).collect();
let refs: Vec<&str> = items.iter().map(|s| s.as_str()).collect();
let r = selectlist(&refs, 0);
assert!(r <= sz, "selectlist({} items, 0) = {} > {}", sz, r, sz);
}
}
#[test]
fn selectlist_returns_usize_type() {
let _g = crate::test_util::global_state_lock();
let _: usize = selectlist(&["x"], 0);
}
#[test]
fn selectlist_two_items_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["a", "b"], 0);
}
#[test]
fn selectlist_entries_with_tabs_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["a\tb", "c\td"], 0);
}
#[test]
fn try_tryflag_is_atomic_i64() {
use std::sync::atomic::Ordering;
let v: i64 = try_tryflag.load(Ordering::SeqCst);
let _ = v;
}
#[test]
fn selectlist_ansi_escape_entries_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["\x1b[31mred\x1b[0m", "plain"], 0);
}
#[test]
fn selectlist_single_space_entry_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&[" "], 0);
}
#[test]
fn loop_depth_initial_state_is_zero() {
use std::sync::atomic::Ordering;
let v = LOOP_DEPTH.load(Ordering::SeqCst);
assert!(v >= 0, "loop depth must never be negative; got {}", v);
}
#[test]
fn cont_flag_initial_state_non_negative() {
use std::sync::atomic::Ordering;
let v = CONT_FLAG.load(Ordering::SeqCst);
assert!(v >= 0, "cont flag must be non-negative; got {}", v);
}
#[test]
fn break_level_initial_state_non_negative() {
use std::sync::atomic::Ordering;
let v = BREAK_LEVEL.load(Ordering::SeqCst);
assert!(v >= 0, "break level must be non-negative; got {}", v);
}
#[test]
fn selectlist_no_mutation_across_calls() {
let _g = crate::test_util::global_state_lock();
let items = ["alpha", "beta", "gamma"];
let first = selectlist(&items, 0);
for _ in 0..20 {
assert_eq!(
selectlist(&items, 0),
first,
"selectlist must be pure across repeated calls"
);
}
}
#[test]
fn selectlist_four_items_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["a", "b", "c", "d"], 0);
}
#[test]
fn selectlist_newline_entry_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["a\nb"], 0);
}
#[test]
fn selectlist_mixed_length_entries_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["a", "ab", "abc", "abcd", "abcde"], 0);
}
#[test]
fn selectlist_emoji_entries_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["foo", "bar"], 0);
}
#[test]
fn try_tryflag_load_idempotent() {
use std::sync::atomic::Ordering;
let first = try_tryflag.load(Ordering::SeqCst);
for _ in 0..50 {
assert_eq!(
try_tryflag.load(Ordering::SeqCst),
first,
"try_tryflag pure load must be deterministic"
);
}
}
#[test]
fn try_tryflag_address_is_stable() {
let p1 = &try_tryflag as *const _;
let p2 = &try_tryflag as *const _;
assert_eq!(p1, p2, "static must have a single, stable address");
}
#[test]
fn selectlist_whitespace_only_entries_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&[" ", "\t\t", " \t "], 0);
}
#[test]
fn loop_static_addresses_stable() {
let a1 = &LOOP_DEPTH as *const _;
let a2 = &LOOP_DEPTH as *const _;
assert_eq!(a1, a2, "LOOP_DEPTH must be a true static");
let b1 = &CONT_FLAG as *const _;
let b2 = &CONT_FLAG as *const _;
assert_eq!(b1, b2, "CONT_FLAG must be a true static");
let c1 = &BREAK_LEVEL as *const _;
let c2 = &BREAK_LEVEL as *const _;
assert_eq!(c1, c2, "BREAK_LEVEL must be a true static");
}
#[test]
fn selectlist_empty_returns_zero_alt() {
let _g = crate::test_util::global_state_lock();
assert_eq!(
selectlist(&[], 0),
0,
"empty items must produce zero-line output"
);
}
#[test]
fn selectlist_single_entry_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["one"], 0);
}
#[test]
fn selectlist_returns_usize_type_alt() {
let _g = crate::test_util::global_state_lock();
let _: usize = selectlist(&["a"], 0);
}
#[test]
fn selectlist_start_past_end_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["a", "b"], 100);
let _ = selectlist(&["a", "b"], usize::MAX / 2);
}
#[test]
fn selectlist_large_list_no_panic() {
let _g = crate::test_util::global_state_lock();
let items: Vec<String> = (0..200).map(|i| format!("item{}", i)).collect();
let refs: Vec<&str> = items.iter().map(|s| s.as_str()).collect();
let _ = selectlist(&refs, 0);
}
#[test]
fn selectlist_start_at_last_index_no_panic() {
let _g = crate::test_util::global_state_lock();
let _ = selectlist(&["a", "b", "c"], 2);
}
#[test]
fn loop_statics_are_atomic_i32() {
let _: &AtomicI32 = &LOOP_DEPTH;
let _: &AtomicI32 = &CONT_FLAG;
let _: &AtomicI32 = &BREAK_LEVEL;
}
#[test]
fn loop_depth_store_load_round_trip() {
use std::sync::atomic::Ordering;
let _g = crate::test_util::global_state_lock();
let saved = LOOP_DEPTH.load(Ordering::SeqCst);
for v in [0, 1, 5, 100, -1, i32::MAX, i32::MIN] {
LOOP_DEPTH.store(v, Ordering::SeqCst);
assert_eq!(
LOOP_DEPTH.load(Ordering::SeqCst),
v,
"LOOP_DEPTH must round-trip {}",
v
);
}
LOOP_DEPTH.store(saved, Ordering::SeqCst);
}
#[test]
fn cont_flag_store_load_round_trip() {
use std::sync::atomic::Ordering;
let _g = crate::test_util::global_state_lock();
let saved = CONT_FLAG.load(Ordering::SeqCst);
for v in [0, 1, 5, 100, -1, i32::MAX, i32::MIN] {
CONT_FLAG.store(v, Ordering::SeqCst);
assert_eq!(CONT_FLAG.load(Ordering::SeqCst), v);
}
CONT_FLAG.store(saved, Ordering::SeqCst);
}
#[test]
fn break_level_store_load_round_trip() {
use std::sync::atomic::Ordering;
let _g = crate::test_util::global_state_lock();
let saved = BREAK_LEVEL.load(Ordering::SeqCst);
for v in [0, 1, 5, 100, -1, i32::MAX, i32::MIN] {
BREAK_LEVEL.store(v, Ordering::SeqCst);
assert_eq!(BREAK_LEVEL.load(Ordering::SeqCst), v);
}
BREAK_LEVEL.store(saved, Ordering::SeqCst);
}
#[test]
fn selectlist_deterministic_on_identical_input() {
let _g = crate::test_util::global_state_lock();
let first = selectlist(&["one", "two", "three"], 0);
for _ in 0..5 {
assert_eq!(
selectlist(&["one", "two", "three"], 0),
first,
"selectlist must be deterministic"
);
}
}
}