use crate::compsys::ported::_wanted::_wanted;
use crate::ported::params::{getsparam, setaparam, setsparam};
use crate::ported::zle::compcore::set_compstate_str;
use crate::ported::zle::complete::bin_compset;
use crate::ported::zsh_h::{isset, options, MAGICEQUALSUBST, MAX_OPS};
use std::fs;
use std::path::Path;
use std::process::Command;
fn make_ops() -> options {
options {
ind: [0u8; MAX_OPS],
args: Vec::new(),
argscount: 0,
argsalloc: 0,
}
}
fn scan_external_zsh_cwds() -> Vec<String> {
let my_pid = std::process::id();
let mut out: Vec<String> = Vec::new();
if Path::new("/proc").is_dir() {
if let Ok(entries) = fs::read_dir("/proc") {
for ent in entries.flatten() {
let name = ent.file_name().to_string_lossy().to_string();
let pid: u32 = match name.parse() {
Ok(n) if n != my_pid => n,
_ => continue,
};
let comm_path = format!("/proc/{}/comm", pid);
let cmd = fs::read_to_string(&comm_path).unwrap_or_default();
if !cmd.trim().contains("zsh") {
continue;
}
if let Ok(cwd) = fs::read_link(format!("/proc/{}/cwd", pid)) {
out.push(cwd.to_string_lossy().into_owned());
}
}
}
return out;
}
if let Ok(output) = Command::new("lsof")
.args(["-a", "-c", "zsh", "-d", "cwd", "-F", "n", "-w"])
.output()
{
for line in String::from_utf8_lossy(&output.stdout).lines() {
if let Some(path) = line.strip_prefix('n') {
out.push(path.to_string());
}
}
}
out
}
pub fn _external_pwds() -> i32 {
let iprefix = getsparam("IPREFIX").unwrap_or_default();
let prefix = getsparam("PREFIX").unwrap_or_default();
let suffix = getsparam("SUFFIX").unwrap_or_default();
let isuffix = getsparam("ISUFFIX").unwrap_or_default();
let _ = setsparam("PREFIX", &format!("{}{}", iprefix, prefix));
let _ = setsparam("IPREFIX", "");
let _ = setsparam("SUFFIX", &format!("{}{}", suffix, isuffix));
let _ = setsparam("ISUFFIX", "");
if isset(MAGICEQUALSUBST) {
let _ = bin_compset(
"compset",
&["-P".to_string(), "*=".to_string()],
&make_ops(),
0,
);
}
let mut dirs = scan_external_zsh_cwds();
let pwd = getsparam("PWD").unwrap_or_default();
dirs.retain(|d| d != &pwd);
dirs.sort();
dirs.dedup();
if dirs.is_empty() {
return 1;
}
set_compstate_str("pattern_match", "*");
setaparam("dirs", dirs);
_wanted(&[
"directories".to_string(),
"expl".to_string(),
"current directory from other shell".to_string(),
"compadd".to_string(),
"-M".to_string(),
"r:|/=* r:|=*".to_string(),
"-f".to_string(),
"-a".to_string(),
"dirs".to_string(),
])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_one_when_dirs_empty() {
let _g = crate::test_util::global_state_lock();
let _ = setsparam("IPREFIX", "");
let _ = setsparam("PREFIX", "");
let _ = setsparam("SUFFIX", "");
let _ = setsparam("ISUFFIX", "");
let _r = _external_pwds();
}
}