1use std::path::{Path, PathBuf};
9
10pub const PICK_PREFIX: &str = "ek-pick-";
12pub const PICK_SUFFIX: &str = ".list";
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum PickListErr {
18 Empty,
20 BadLine(usize, String),
22 Io(String),
24}
25
26impl std::fmt::Display for PickListErr {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 Self::Empty => write!(f, "pick list empty (select at least one plugin)"),
30 Self::BadLine(n, line) => {
31 write!(f, "pick list line {n} has unexpected whitespace: {line:?}")
32 }
33 Self::Io(e) => write!(f, "pick list io: {e}"),
34 }
35 }
36}
37
38impl std::error::Error for PickListErr {}
39
40fn unique_name() -> String {
42 let nanos = std::time::SystemTime::now()
43 .duration_since(std::time::UNIX_EPOCH)
44 .map(|d| d.as_nanos() as u64)
45 .unwrap_or(0);
46 format!("{PICK_PREFIX}{}{}{PICK_SUFFIX}", std::process::id(), nanos)
47}
48
49pub fn read(path: &Path) -> Result<Vec<String>, PickListErr> {
51 let text = std::fs::read_to_string(path).map_err(|e| PickListErr::Io(e.to_string()))?;
52 let text = text.strip_prefix('\u{feff}').unwrap_or(&text);
54 let mut names = Vec::new();
55 for (i, raw) in text.lines().enumerate() {
56 let line = raw.trim();
57 if line.is_empty() || line.starts_with('#') {
58 continue;
59 }
60 if line.chars().any(|c| c.is_whitespace()) {
61 return Err(PickListErr::BadLine(i + 1, raw.to_string()));
62 }
63 names.push(line.to_string());
64 }
65 if names.is_empty() {
66 return Err(PickListErr::Empty);
67 }
68 Ok(names)
69}
70
71pub fn write_in(dir: &Path, names: &[&str]) -> Result<PathBuf, PickListErr> {
73 if names.is_empty() {
74 return Err(PickListErr::Empty);
75 }
76 for (i, n) in names.iter().enumerate() {
77 if n.chars().any(|c| c.is_whitespace()) || n.is_empty() || n.starts_with('#') {
78 return Err(PickListErr::BadLine(i + 1, (*n).to_string()));
79 }
80 }
81 std::fs::create_dir_all(dir).map_err(|e| PickListErr::Io(e.to_string()))?;
82 let path = dir.join(unique_name());
83 let mut text = String::from("# ek launch pick\n");
84 for n in names {
85 text.push_str(n);
86 text.push('\n');
87 }
88 std::fs::write(&path, text).map_err(|e| PickListErr::Io(e.to_string()))?;
89 Ok(path)
90}