sync_rs/
config.rs

1use anyhow::{Context, Result};
2use serde::{Deserialize, Serialize};
3use std::io::{self, Write};
4
5#[derive(Debug, Serialize, Deserialize, Clone)]
6pub struct RemoteEntry {
7    pub name: String,
8    pub remote_host: String,
9    pub remote_dir: String,
10    #[serde(default)]
11    pub override_paths: Vec<String>,
12    #[serde(default)]
13    pub post_sync_command: Option<String>,
14}
15
16pub fn prompt_remote_info() -> Result<(String, String)> {
17    let mut remote_host = String::new();
18    let mut remote_dir = String::new();
19
20    print!("Enter remote host (e.g., user@host): ");
21    io::stdout().flush()?;
22    io::stdin().read_line(&mut remote_host)?;
23
24    print!("Enter remote directory (relative to remote home): ");
25    io::stdout().flush()?;
26    io::stdin().read_line(&mut remote_dir)?;
27
28    Ok((
29        remote_host.trim().to_string(),
30        remote_dir.trim().to_string(),
31    ))
32}
33
34pub fn select_remote(entries: &[RemoteEntry]) -> Result<String> {
35    println!("Multiple remote configurations found. Please select one:");
36
37    for (i, entry) in entries.iter().enumerate() {
38        println!(
39            "{}: {} ({}:{})",
40            i + 1,
41            entry.name,
42            entry.remote_host,
43            entry.remote_dir
44        );
45    }
46
47    let mut selection = String::new();
48    print!("Enter selection (1-{}): ", entries.len());
49    io::stdout().flush()?;
50    io::stdin().read_line(&mut selection)?;
51
52    let index = selection
53        .trim()
54        .parse::<usize>()
55        .context("Invalid selection")?
56        - 1;
57
58    if index >= entries.len() {
59        anyhow::bail!("Selection out of range");
60    }
61
62    Ok(entries[index].name.clone())
63}
64
65pub fn list_remotes(cache: &crate::cache::RemoteMap, current_dir: &str) -> Result<()> {
66    let empty_vec: Vec<RemoteEntry> = Vec::new();
67    let entries = cache.get(current_dir).unwrap_or(&empty_vec);
68
69    if entries.is_empty() {
70        println!("No remote configurations found for this directory.");
71        return Ok(());
72    }
73
74    println!("Remote configurations for this directory:");
75    for (i, entry) in entries.iter().enumerate() {
76        println!(
77            "{}: {} ({}:{})",
78            i + 1,
79            entry.name,
80            entry.remote_host,
81            entry.remote_dir
82        );
83    }
84
85    Ok(())
86}
87
88pub fn remove_remote(
89    cache: &mut crate::cache::RemoteMap,
90    current_dir: &str,
91    name: &str,
92) -> Result<()> {
93    let entries = cache
94        .get_mut(current_dir)
95        .context("No remotes found for this directory")?;
96
97    let initial_len = entries.len();
98    entries.retain(|e| e.name != name);
99
100    if entries.len() == initial_len {
101        anyhow::bail!("Remote with name '{}' not found", name);
102    }
103
104    println!("Removed remote configuration '{}'", name);
105    Ok(())
106}
107
108// Generate a unique name based on the host name
109pub fn generate_unique_name(
110    host: &str,
111    cache: &crate::cache::RemoteMap,
112    current_dir: &str,
113) -> String {
114    // Extract username@hostname or just hostname
115    let base_name = host.split(':').next().unwrap_or(host);
116
117    // If there are no entries for this directory or no entries with this base name, use it as is
118    if !cache.contains_key(current_dir) || !cache[current_dir].iter().any(|e| e.name == base_name) {
119        return base_name.to_string();
120    }
121
122    // Find the highest index used for this base name
123    let mut highest_index = 0;
124    for entry in &cache[current_dir] {
125        if entry.name == base_name {
126            highest_index = 1;
127        } else if entry.name.starts_with(&format!("{}_", base_name)) {
128            if let Ok(index) = entry.name[base_name.len() + 1..].parse::<usize>() {
129                highest_index = highest_index.max(index + 1);
130            }
131        }
132    }
133
134    // Return the base name with the next available index
135    format!("{}_{}", base_name, highest_index)
136}