use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
pub static FORCE_REINIT: AtomicBool = AtomicBool::new(false);
static DISPLAY_STATE: Mutex<Option<HashMap<String, bool>>> = Mutex::new(None);
pub fn is_hidden(seg: &str) -> bool {
let g = DISPLAY_STATE.lock().unwrap();
let Some(map) = g.as_ref() else { return false };
if map.is_empty() {
return false;
}
map.iter().any(|(k, &hidden)| hidden && part_matches(k, seg))
}
fn part_matches(key: &str, seg: &str) -> bool {
key == seg
|| key.rsplit('/').next() == Some(seg)
|| (key.ends_with(seg) && key[..key.len() - seg.len()].ends_with('/'))
}
pub fn display_set(pattern: &str, states: &[&str]) -> bool {
if states.is_empty() {
return false;
}
let mut g = DISPLAY_STATE.lock().unwrap();
let map = g.get_or_insert_with(HashMap::new);
let cur_hidden = map.get(pattern).copied().unwrap_or(false);
let cur = if cur_hidden { "hide" } else { "show" };
let new = if states.len() == 1 {
states[0]
} else {
match states.iter().position(|s| *s == cur) {
Some(i) => states[(i + 1) % states.len()],
None => states[0],
}
};
let new_hidden = new == "hide";
if new_hidden == cur_hidden && map.contains_key(pattern) {
return false; }
map.insert(pattern.to_string(), new_hidden);
true
}
pub fn display_dump(patterns: &[&str]) -> Vec<String> {
let g = DISPLAY_STATE.lock().unwrap();
let Some(map) = g.as_ref() else { return Vec::new() };
let mut out = Vec::new();
for (k, &hidden) in map.iter() {
let show = patterns.is_empty()
|| patterns.iter().any(|p| *p == "*" || part_matches(k, p) || *p == k.as_str());
if show {
out.push(k.clone());
out.push(if hidden { "hide".into() } else { "show".into() });
}
}
out
}
pub fn display_reset() {
if let Some(map) = DISPLAY_STATE.lock().unwrap().as_mut() {
map.clear();
}
}
pub const USAGE: &str = "Usage: %2Fp10k%f %Bcommand%b [options]
Commands:
%Bconfigure%b run interactive configuration wizard
%Breload%b reload configuration
%Bsegment%b print a user-defined prompt segment
%Bdisplay%b show, hide or toggle prompt parts
%Bhelp%b print this help message
Print help for a specific command:
%2Fp10k%f %Bhelp%b command";
pub const SEGMENT_USAGE: &str =
"Usage: %2Fp10k%f %Bsegment%b [-h] [{+|-}re] [-s state] [-b bg] [-f fg] [-i icon] [-c cond] [-t text]
Print a user-defined prompt segment. Can be called only during prompt rendering.";
pub const CONFIGURE_USAGE: &str = "Usage: %2Fp10k%f %Bconfigure%b
Run interactive configuration wizard.";
pub const RELOAD_USAGE: &str = "Usage: %2Fp10k%f %Breload%b
Reload configuration.";
pub const FINALIZE_USAGE: &str = "Usage: %2Fp10k%f %Bfinalize%b
Perform the final stage of initialization. Must be called at the very end of zshrc.";
pub const DISPLAY_USAGE: &str = "Usage: %2Fp10k%f %Bdisplay%b part-pattern=state-list...
Show, hide or toggle prompt parts. If called from zle, the current
prompt is refreshed.
Usage: %2Fp10k%f %Bdisplay%b -a [part-pattern]...
Populate array `reply` with states of prompt parts matching the patterns.
Usage: %2Fp10k%f %Bdisplay%b -r
Redisplay prompt.";
pub fn help_usage(sub: Option<&str>) -> &'static str {
match sub {
None => USAGE,
Some("segment") => SEGMENT_USAGE,
Some("configure") => CONFIGURE_USAGE,
Some("reload") => RELOAD_USAGE,
Some("finalize") => FINALIZE_USAGE,
Some("display") => DISPLAY_USAGE,
Some("help") => USAGE,
_ => USAGE,
}
}
pub fn print_usage(s: &str, to_stderr: bool) {
let (expanded, _, _) = crate::ported::prompt::promptexpand(s, 0, None);
if to_stderr {
eprintln!("{expanded}");
} else {
println!("{expanded}");
}
}
#[cfg(test)]
mod tests {
use super::*;
fn reset() {
display_reset();
}
#[test]
fn display_hide_show_toggle() {
reset();
assert!(!is_hidden("dir"));
assert!(display_set("dir", &["hide"]));
assert!(is_hidden("dir"));
assert!(!display_set("dir", &["hide"]));
assert!(display_set("dir", &["show"]));
assert!(!is_hidden("dir"));
assert!(display_set("dir", &["hide", "show"]));
assert!(is_hidden("dir"));
reset();
assert!(!is_hidden("dir"));
}
#[test]
fn slot_name_matches_segment() {
reset();
assert!(display_set("1/left/dir", &["hide"]));
assert!(is_hidden("dir"));
assert!(!is_hidden("time"));
reset();
}
#[test]
fn dump_reports_pairs() {
reset();
display_set("dir", &["hide"]);
let d = display_dump(&["*"]);
assert_eq!(d, vec!["dir".to_string(), "hide".to_string()]);
reset();
}
}