Repository: raphamorim/rio (language: rust)

Issue:
Support dumping config via command line
I wanted to configure Rio from scratch so I deleted the config file. Intuitively I'd expect a CLI argument such as `--dump-config` to quickly create `config.toml` but I had to start Rio for the configuration file to be created automatically.

I'm interested in contributing `--dump-config` or `--init` argument if you think it is applicable 🐻 


Discussion / hints:
Go for it @orhun 👌 

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 385b840a0e..bdadb0f64c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
 
 ## Unreleased
 
+- Support writing the config to a custom/default location via `--write-config` (Ref: #605)
 - Fix scale update on transitioning between screens with different DPI.
 - Support a short variant (`-w`) for `--working-dir` argument
 
diff --git a/docs/versioned_docs/version-0.0.x/command-line-interface.md b/docs/versioned_docs/version-0.0.x/command-line-interface.md
index 20b2ec80e5..5e9f31ea79 100644
--- a/docs/versioned_docs/version-0.0.x/command-line-interface.md
+++ b/docs/versioned_docs/version-0.0.x/command-line-interface.md
@@ -14,6 +14,7 @@ Usage: rio [OPTIONS]
 Options:
   -e, --command <COMMAND>...       Command and args to execute (must be last argument)
   -w, --working-dir <WORKING_DIR>  Start the shell in the specified working directory
+  --write-config [<PATH>]          Writes the config to a given path or the default location
   -h, --help                       Print help
   -V, --version                    Print version
 ```
diff --git a/frontends/rioterm/src/cli.rs b/frontends/rioterm/src/cli.rs
index 7eb8fc5412..2aba59f146 100644
--- a/frontends/rioterm/src/cli.rs
+++ b/frontends/rioterm/src/cli.rs
@@ -4,6 +4,7 @@
 use clap::{Args, Parser, ValueHint};
 use rio_backend::config::Shell;
 use serde::{Deserialize, Serialize};
+use std::path::PathBuf;
 
 #[derive(Parser, Default, Debug)]
 #[clap(author, about, version)]
@@ -29,6 +30,10 @@ pub struct TerminalOptions {
     /// Start the shell in the specified working directory.
     #[clap(short, long, value_hint = ValueHint::FilePath)]
     pub working_dir: Option<String>,
+
+    /// Writes the config to a given path or the default location.
+    #[clap(long, value_name = "PATH", value_hint = ValueHint::FilePath)]
+    pub write_config: Option<Option<PathBuf>>,
 }
 
 impl TerminalOptions {
diff --git a/frontends/rioterm/src/main.rs b/frontends/rioterm/src/main.rs
index 7aefb0e125..3d83998d70 100644
--- a/frontends/rioterm/src/main.rs
+++ b/frontends/rioterm/src/main.rs
@@ -108,6 +108,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     // Load command line options.
     let args = cli::Cli::parse();
 
+    let write_config_path = args.window_options.terminal_options.write_config.clone();
+    if write_config_path.is_some() {
+        let _ = setup_logs_by_filter_level("TRACE");
+        rio_backend::config::create_config_file(write_config_path.unwrap());
+        return Ok(());
+    }
+
     let (mut config, config_error) = match rio_backend::config::Config::try_load() {
         Ok(config) => (config, None),
         Err(err) => (rio_backend::config::Config::default(), Some(err)),
diff --git a/frontends/rioterm/src/router/mod.rs b/frontends/rioterm/src/router/mod.rs
index b99a0e7fa9..f8c1d324f5 100644
--- a/frontends/rioterm/src/router/mod.rs
+++ b/frontends/rioterm/src/router/mod.rs
@@ -9,8 +9,6 @@ use rio_backend::config::Config as RioConfig;
 use rio_backend::error::{RioError, RioErrorLevel, RioErrorType};
 use std::collections::HashMap;
 use std::error::Error;
-use std::fs::File;
-use std::io::Write;
 use winit::event_loop::{ActiveEventLoop, EventLoop};
 use winit::keyboard::{Key, NamedKey};
 #[cfg(not(any(target_os = "macos", windows)))]
@@ -129,53 +127,13 @@ impl Route {
         }
 
         if self.path == RoutePath::Welcome && is_enter {
-            self.create_config_file();
+            rio_backend::config::create_config_file(None);
             self.path = RoutePath::Terminal;
             return true;
         }
 
         true
     }
-
-    #[inline]
-    pub fn create_config_file(&self) {
-        let default_file_path = rio_backend::config::config_file_path();
-        if default_file_path.exists() {
-            return;
-        }
-
-        let default_dir_path = rio_backend::config::config_dir_path();
-        match std::fs::create_dir_all(&default_dir_path) {
-            Ok(_) => {
-                log::info!("configuration path created {}", default_dir_path.display());
-            }
-            Err(err_message) => {
-                log::error!("could not create config directory: {err_message}");
-            }
-        }
-
-        match File::create(&default_file_path) {
-            Err(err_message) => {
-                log::error!(
-                    "could not create config file {}: {err_message}",
-                    default_file_path.display()
-                )
-            }
-            Ok(mut created_file) => {
-                log::info!("configuration file created {}", default_file_path.display());
-
-                if let Err(err_message) = writeln!(
-                    created_file,
-                    "{}",
-                    rio_backend::config::config_file_content()
-                ) {
-                    log::error!(
-                        "could not update config file with defaults: {err_message}"
-                    )
-                }
-            }
-        }
-    }
 }
 
 pub struct Router {
diff --git a/rio-backend/src/config/mod.rs b/rio-backend/src/config/mod.rs
index 082261f165..7e391a2b68 100644
--- a/rio-backend/src/config/mod.rs
+++ b/rio-backend/src/config/mod.rs
@@ -16,8 +16,9 @@ use crate::config::window::Window;
 use colors::Colors;
 use log::warn;
 use serde::{Deserialize, Serialize};
-use std::default::Default;
+use std::io::Write;
 use std::path::PathBuf;
+use std::{default::Default, fs::File};
 use sugarloaf::font::fonts::SugarloafFonts;
 use theme::{AdaptiveColors, AdaptiveTheme, Theme};
 
@@ -153,6 +154,47 @@ pub fn config_file_content() -> String {
     default_config_file_content()
 }
 
+#[inline]
+pub fn create_config_file(path: Option<PathBuf>) {
+    let default_file_path = path.clone().unwrap_or(config_file_path());
+    if default_file_path.exists() {
+        log::info!(
+            "configuration file already exists at {}",
+            default_file_path.display()
+        );
+        return;
+    }
+
+    if path.is_none() {
+        let default_dir_path = config_dir_path();
+        match std::fs::create_dir_all(&default_dir_path) {
+            Ok(_) => {
+                log::info!("configuration path created {}", default_dir_path.display());
+            }
+            Err(err_message) => {
+                log::error!("could not create config directory: {err_message}");
+            }
+        }
+    }
+
+    match File::create(&default_file_path) {
+        Err(err_message) => {
+            log::error!(
+                "could not create config file {}: {err_message}",
+                default_file_path.display()
+            )
+        }
+        Ok(mut created_file) => {
+            log::info!("configuration file created {}", default_file_path.display());
+
+            if let Err(err_message) = writeln!(created_file, "{}", config_file_content())
+            {
+                log::error!("could not update config file with defaults: {err_message}")
+            }
+        }
+    }
+}
+
 impl Config {
     #[cfg(test)]
     fn load_from_path(path: &PathBuf) -> Self {


Test patch: