muse2/cli/
settings.rs

1//! Code related to CLI interface for managing the settings file
2use crate::settings::{Settings, get_settings_file_path};
3use anyhow::{Context, Result, bail};
4use clap::Subcommand;
5use std::fs;
6use std::io::{self, Write};
7use std::path::Path;
8
9/// Subcommands for settings
10#[derive(Subcommand)]
11pub enum SettingsSubcommands {
12    /// Edit the program settings file
13    Edit,
14    /// Delete the settings file, if any
15    Delete,
16    /// Get the path to where the settings file is read from
17    Path,
18    /// Show the contents of the `settings.toml`, if present
19    Show,
20    /// Show the default settings for `settings.toml`
21    ShowDefault,
22}
23
24impl SettingsSubcommands {
25    /// Execute the supplied settings subcommand
26    pub fn execute(self) -> Result<()> {
27        match self {
28            Self::Edit => handle_edit_command()?,
29            Self::Delete => handle_delete_command()?,
30            Self::Path => handle_path_command(),
31            Self::Show => handle_show_command()?,
32            Self::ShowDefault => handle_show_default_command(),
33        }
34
35        Ok(())
36    }
37}
38
39/// Get the path to the settings file, creating it if it doesn't exist
40fn ensure_settings_file_exists(file_path: &Path) -> Result<()> {
41    if file_path.is_file() {
42        // File already exists
43        return Ok(());
44    }
45
46    if let Some(dir_path) = file_path.parent() {
47        // Create parent directory
48        fs::create_dir_all(dir_path)
49            .with_context(|| format!("Failed to create directory: {}", dir_path.display()))?;
50    }
51
52    // Create placeholder settings file
53    fs::write(file_path, Settings::default_file_contents())?;
54
55    Ok(())
56}
57
58/// Handle the `edit` command
59fn handle_edit_command() -> Result<()> {
60    let file_path = get_settings_file_path();
61    ensure_settings_file_exists(&file_path)?;
62
63    // Allow user to edit in text editor
64    println!("Opening settings file for editing: {}", file_path.display());
65    edit::edit_file(&file_path)?;
66
67    Ok(())
68}
69
70/// Handle the `delete` command
71fn handle_delete_command() -> Result<()> {
72    let file_path = get_settings_file_path();
73    if file_path.exists() {
74        fs::remove_file(&file_path)
75            .with_context(|| format!("Error deleting file: {}", file_path.display()))?;
76        println!("Deleted settings file: {}", file_path.display());
77    } else {
78        eprintln!("No settings file to delete");
79    }
80
81    Ok(())
82}
83
84/// Handle the `path` command
85fn handle_path_command() {
86    let file_path = get_settings_file_path();
87    if file_path.is_file() {
88        println!("{}", file_path.display());
89    } else {
90        eprintln!("Settings file not found at: {}", file_path.display());
91    }
92}
93
94/// Handle the `show` command
95fn handle_show_command() -> Result<()> {
96    let file_path = get_settings_file_path();
97
98    match fs::read(&file_path) {
99        // Write contents of file to stdout
100        Ok(ref contents) => io::stdout().write_all(contents)?,
101        Err(err) => {
102            if err.kind() == io::ErrorKind::NotFound {
103                bail!("Settings file not found at: {}", file_path.display())
104            }
105            // Some other kind of IO error occurred; just return it
106            Err(err)?;
107        }
108    }
109
110    Ok(())
111}
112
113/// Handle the `show-default` command
114fn handle_show_default_command() {
115    print!("{}", Settings::default_file_contents());
116}