Skip to main content

nex_pkg/
nixfile.rs

1/// Describes an editable list inside a nix file.
2#[derive(Debug, Clone)]
3pub struct NixList {
4    /// Regex-free prefix of the opening line (trimmed for matching).
5    pub open_line: &'static str,
6    /// Regex-free prefix of the closing line.
7    pub close_line: &'static str,
8    /// Number of spaces before each item.
9    pub item_indent: usize,
10    /// Whether items are quoted strings (`"foo"`) or bare identifiers (`foo`).
11    pub quoted: bool,
12}
13
14impl NixList {
15    /// Format a package name as it would appear in the file (with indent + quoting).
16    pub fn format_item(&self, pkg: &str) -> String {
17        let indent = " ".repeat(self.item_indent);
18        if self.quoted {
19            format!("{indent}\"{pkg}\"")
20        } else {
21            format!("{indent}{pkg}")
22        }
23    }
24
25    /// Extract the package name from a line, if it matches the expected format.
26    pub fn parse_item(&self, line: &str) -> Option<String> {
27        let trimmed = line.trim();
28        if trimmed.is_empty() || trimmed.starts_with('#') || trimmed.starts_with("//") {
29            return None;
30        }
31        if self.quoted {
32            // Match `"package-name"` possibly followed by inline comment
33            let stripped = trimmed.strip_prefix('"')?;
34            let end = stripped.find('"')?;
35            Some(stripped[..end].to_string())
36        } else {
37            // Bare identifier — take first word (ignore inline comments)
38            let word = trimmed.split_whitespace().next()?;
39            // Skip nix keywords / structural tokens
40            if word.starts_with('[')
41                || word.starts_with(']')
42                || word.starts_with('{')
43                || word.starts_with('}')
44                || word.contains('=')
45                || word.contains('.')
46                || word.contains('/')
47            {
48                return None;
49            }
50            Some(word.to_string())
51        }
52    }
53}
54
55// Known list definitions matching the macos-nix repo structure.
56
57pub const NIX_PACKAGES: NixList = NixList {
58    open_line: "home.packages = with pkgs; [",
59    close_line: "];",
60    item_indent: 4,
61    quoted: false,
62};
63
64pub const HOMEBREW_BREWS: NixList = NixList {
65    open_line: "brews = [",
66    close_line: "];",
67    item_indent: 6,
68    quoted: true,
69};
70
71pub const HOMEBREW_CASKS: NixList = NixList {
72    open_line: "casks = [",
73    close_line: "];",
74    item_indent: 6,
75    quoted: true,
76};