Skip to main content

zsh/
newuser.rs

1//! Newuser module - port of Modules/newuser.c
2//!
3//! Provides first-run setup for new zsh users.
4
5use std::path::Path;
6
7/// Check if user needs first-run setup
8pub fn needs_newuser_setup(home: &Path) -> bool {
9    let zshrc = home.join(".zshrc");
10    let zshenv = home.join(".zshenv");
11    let zprofile = home.join(".zprofile");
12    let zlogin = home.join(".zlogin");
13    let zlogout = home.join(".zlogout");
14
15    !zshrc.exists()
16        && !zshenv.exists()
17        && !zprofile.exists()
18        && !zlogin.exists()
19        && !zlogout.exists()
20}
21
22/// Generate default .zshrc content
23pub fn default_zshrc() -> String {
24    r#"# Lines configured by zsh-newuser-install
25
26# History configuration
27HISTFILE=~/.zsh_history
28HISTSIZE=10000
29SAVEHIST=10000
30
31# Options
32setopt HIST_IGNORE_DUPS
33setopt HIST_IGNORE_SPACE
34setopt EXTENDED_HISTORY
35setopt SHARE_HISTORY
36setopt APPEND_HISTORY
37setopt AUTO_CD
38setopt CORRECT
39
40# Key bindings - emacs style
41bindkey -e
42
43# Completion
44autoload -Uz compinit
45compinit
46
47# Prompt
48autoload -Uz promptinit
49promptinit
50prompt adam1
51
52# End of lines configured by zsh-newuser-install
53"#
54    .to_string()
55}
56
57/// Generate minimal .zshrc content
58pub fn minimal_zshrc() -> String {
59    r#"# Minimal zsh configuration
60HISTFILE=~/.zsh_history
61HISTSIZE=1000
62SAVEHIST=1000
63bindkey -e
64"#
65    .to_string()
66}
67
68/// First-run setup options
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum SetupChoice {
71    Recommended,
72    Minimal,
73    Exit,
74    Manual,
75}
76
77/// Run newuser setup
78pub fn run_newuser_setup(home: &Path, choice: SetupChoice) -> std::io::Result<()> {
79    let zshrc = home.join(".zshrc");
80
81    match choice {
82        SetupChoice::Recommended => {
83            std::fs::write(&zshrc, default_zshrc())?;
84        }
85        SetupChoice::Minimal => {
86            std::fs::write(&zshrc, minimal_zshrc())?;
87        }
88        SetupChoice::Exit | SetupChoice::Manual => {}
89    }
90
91    Ok(())
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97    use std::path::PathBuf;
98
99    #[test]
100    fn test_default_zshrc() {
101        let content = default_zshrc();
102        assert!(content.contains("HISTFILE"));
103        assert!(content.contains("compinit"));
104    }
105
106    #[test]
107    fn test_minimal_zshrc() {
108        let content = minimal_zshrc();
109        assert!(content.contains("HISTFILE"));
110        assert!(content.len() < default_zshrc().len());
111    }
112
113    #[test]
114    fn test_needs_newuser_setup_empty() {
115        let temp = std::env::temp_dir().join("zsh_test_newuser_empty");
116        std::fs::create_dir_all(&temp).ok();
117
118        for f in &[".zshrc", ".zshenv", ".zprofile", ".zlogin", ".zlogout"] {
119            let _ = std::fs::remove_file(temp.join(f));
120        }
121
122        assert!(needs_newuser_setup(&temp));
123
124        let _ = std::fs::remove_dir_all(&temp);
125    }
126
127    #[test]
128    fn test_needs_newuser_setup_has_zshrc() {
129        let temp = std::env::temp_dir().join("zsh_test_newuser_has");
130        std::fs::create_dir_all(&temp).ok();
131
132        std::fs::write(temp.join(".zshrc"), "# test").ok();
133        assert!(!needs_newuser_setup(&temp));
134
135        let _ = std::fs::remove_dir_all(&temp);
136    }
137}