| 1531 | } |
| 1532 | |
| 1533 | fn upsert_host_block(contents: &str, alias: &str, block: &str) -> String { |
| 1534 | let lines: Vec<&str> = contents.lines().collect(); |
| 1535 | let start = lines.iter().position(|line| host_line_matches(line, alias)); |
| 1536 | |
| 1537 | let mut out = Vec::new(); |
| 1538 | if let Some(start) = start { |
| 1539 | let end = lines |
| 1540 | .iter() |
| 1541 | .enumerate() |
| 1542 | .skip(start + 1) |
| 1543 | .find(|(_, line)| line.trim_start().starts_with("Host ")) |
| 1544 | .map_or(lines.len(), |(idx, _)| idx); |
| 1545 | |
| 1546 | out.extend_from_slice(&lines[..start]); |
| 1547 | if !out.is_empty() && !out.last().is_some_and(|line| line.is_empty()) { |
| 1548 | out.push(""); |
| 1549 | } |
| 1550 | out.extend(block.lines()); |
| 1551 | if end < lines.len() && !lines[end..].first().is_some_and(|line| line.is_empty()) { |
| 1552 | out.push(""); |
| 1553 | } |
| 1554 | out.extend_from_slice(&lines[end..]); |
| 1555 | } else { |
| 1556 | out.extend_from_slice(&lines); |
| 1557 | if !out.is_empty() && !out.last().is_some_and(|line| line.is_empty()) { |
| 1558 | out.push(""); |
| 1559 | } |
| 1560 | out.extend(block.lines()); |
| 1561 | } |
| 1562 | |
| 1563 | let mut rendered = out.join("\n"); |
| 1564 | if !rendered.is_empty() { |
| 1565 | rendered.push('\n'); |
| 1566 | } |
| 1567 | rendered |
| 1568 | } |
| 1569 | |
| 1570 | pub fn install_ssh_config(gateway: &str, name: &str) -> Result<PathBuf> { |
| 1571 | let managed_config = openshell_ssh_config_path()?; |