diff --git a/src/cli.rs b/src/cli.rs index b95b5770..69496808 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,5 +1,6 @@ use super::common::utils::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}; use crate::common::input::options::Options; +use crate::common::setup::Setup; use serde::{Deserialize, Serialize}; use std::path::PathBuf; use structopt::StructOpt; @@ -40,17 +41,7 @@ pub enum ConfigCli { #[structopt(name = "options")] Options(Options), - #[structopt(name = "generate-completion")] - GenerateCompletion { shell: String }, - + /// Setup zellij and check its configuration #[structopt(name = "setup")] - Setup { - /// Dump the default configuration file to stdout - #[structopt(long)] - dump_config: bool, - /// Disables loading of configuration file at default location, - /// loads the defaults that zellij ships with - #[structopt(long)] - clean: bool, - }, + Setup(Setup), } diff --git a/src/common/input/config.rs b/src/common/input/config.rs index 5f2656f3..3dffe71c 100644 --- a/src/common/input/config.rs +++ b/src/common/input/config.rs @@ -60,8 +60,8 @@ impl TryFrom<&CliArgs> for Config { return Config::new(&path); } - if let Some(ConfigCli::Setup { clean, .. }) = opts.option { - if clean { + if let Some(ConfigCli::Setup(setup)) = opts.option.clone() { + if setup.clean { return Config::from_default_assets(); } } @@ -177,11 +177,12 @@ mod config_test { #[test] fn try_from_cli_args_with_option_clean() { + use crate::common::setup::Setup; let mut opts = CliArgs::default(); - opts.option = Some(ConfigCli::Setup { + opts.option = Some(ConfigCli::Setup(Setup { clean: true, - dump_config: false, - }); + ..Setup::default() + })); let result = Config::try_from(&opts); assert!(result.is_ok()); } diff --git a/src/common/setup.rs b/src/common/setup.rs index 5913211a..2e076776 100644 --- a/src/common/setup.rs +++ b/src/common/setup.rs @@ -1,12 +1,17 @@ +use crate::cli::CliArgs; use crate::common::utils::consts::{ - SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, ZELLIJ_PROJ_DIR, + FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, ZELLIJ_PROJ_DIR, }; use crate::os_input_output::set_permissions; use directories_next::BaseDirs; +use serde::{Deserialize, Serialize}; use std::io::Write; use std::{fs, path::Path, path::PathBuf}; +use structopt::StructOpt; const CONFIG_LOCATION: &str = ".config/zellij"; +const CONFIG_NAME: &str = "config.yaml"; +static ARROW_SEPARATOR: &str = ""; #[macro_export] macro_rules! asset_map { @@ -56,15 +61,11 @@ pub mod install { /// Goes through a predefined list and checks for an already /// existing config directory, returns the first match pub fn find_default_config_dir() -> Option { - vec![ - home_config_dir(), - Some(xdg_config_dir()), - Some(Path::new(SYSTEM_DEFAULT_CONFIG_DIR).to_path_buf()), - ] - .into_iter() - .filter(|p| p.is_some()) - .find(|p| p.clone().unwrap().exists()) - .flatten() + default_config_dirs() + .into_iter() + .filter(|p| p.is_some()) + .find(|p| p.clone().unwrap().exists()) + .flatten() } #[cfg(test)] @@ -72,6 +73,15 @@ pub fn find_default_config_dir() -> Option { None } +/// Order in which config directories are checked +fn default_config_dirs() -> Vec> { + vec![ + home_config_dir(), + Some(xdg_config_dir()), + Some(Path::new(SYSTEM_DEFAULT_CONFIG_DIR).to_path_buf()), + ] +} + /// Looks for an existing dir, uses that, else returns a /// dir matching the config spec. pub fn get_default_data_dir() -> PathBuf { @@ -115,3 +125,116 @@ pub const DEFAULT_CONFIG: &[u8] = include_bytes!(concat!( pub fn dump_default_config() -> std::io::Result<()> { dump_asset(DEFAULT_CONFIG) } + +#[derive(Debug, Default, Clone, StructOpt, Serialize, Deserialize)] +pub struct Setup { + /// Dump the default configuration file to stdout + #[structopt(long)] + pub dump_config: bool, + /// Disables loading of configuration file at default location, + /// loads the defaults that zellij ships with + #[structopt(long)] + pub clean: bool, + /// Checks the configuration of zellij and displays + /// currently used directories + #[structopt(long)] + pub check: bool, + + #[structopt(long)] + pub generate_completion: Option, +} + +impl Setup { + /// Entrypoint from main + pub fn from_cli(&self, opts: CliArgs) -> std::io::Result<()> { + if self.dump_config { + dump_default_config()?; + } + + if self.check { + Setup::check_defaults_config(opts)?; + } + + if let Some(shell) = &self.generate_completion { + Self::generate_completion(shell.into()); + } + + Ok(()) + } + + pub fn check_defaults_config(opts: CliArgs) -> std::io::Result<()> { + let data_dir = opts.data_dir.unwrap_or_else(get_default_data_dir); + let config_dir = opts.config_dir.or_else(find_default_config_dir); + let plugin_dir = data_dir.join("plugins"); + let layout_dir = data_dir.join("layouts"); + let system_data_dir = PathBuf::from(SYSTEM_DEFAULT_DATA_DIR_PREFIX).join("share/zellij"); + let config_file = opts + .config + .or_else(|| config_dir.clone().map(|p| p.join(CONFIG_NAME))); + + let mut message = String::new(); + + message.push_str(&format!("[Version]: {:?}\n", VERSION)); + if let Some(config_dir) = config_dir { + message.push_str(&format!("[CONFIG DIR]: {:?}\n", config_dir)); + } else { + message.push_str(&"[CONFIG DIR]: Not Found\n"); + let mut default_config_dirs = default_config_dirs() + .iter() + .filter_map(|p| p.clone()) + .collect::>(); + default_config_dirs.dedup(); + message.push_str( + &" On your system zellij looks in the following config directories by default:\n", + ); + for dir in default_config_dirs { + message.push_str(&format!(" {:?}\n", dir)); + } + } + if let Some(config_file) = config_file { + use crate::common::input::config::Config; + message.push_str(&format!("[CONFIG FILE]: {:?}\n", config_file)); + match Config::new(&config_file) { + Ok(_) => message.push_str(&"[CONFIG FILE]: Well defined.\n"), + Err(e) => message.push_str(&format!("[CONFIG ERROR]: {}\n", e)), + } + } else { + message.push_str(&"[CONFIG FILE]: Not Found\n"); + message.push_str(&format!( + " By default zellij looks for a file called [{}] in the configuration directory\n", + CONFIG_NAME + )); + } + message.push_str(&format!("[DATA DIR]: {:?}\n", data_dir)); + message.push_str(&format!("[PLUGIN DIR]: {:?}\n", plugin_dir)); + message.push_str(&format!("[LAYOUT DIR]: {:?}\n", layout_dir)); + message.push_str(&format!("[SYSTEM DATA DIR]: {:?}\n", system_data_dir)); + + message.push_str(&format!("[ARROW SEPARATOR]: {}\n", ARROW_SEPARATOR)); + message.push_str(&" Is the [ARROW_SEPARATOR] displayed correctly?\n"); + message.push_str(&" If not you may want to either start zellij with a compatible mode 'zellij options --simple-ui'\n"); + message.push_str(&" Or check the font that is in use:\n https://zellij.dev/documentation/compatibility.html#the-status-bar-fonts-dont-render-correctly\n"); + + message.push_str(&format!("[FEATURES]: {:?}\n", FEATURES)); + message.push_str(&"[DOCUMENTATION]: zellij.dev/documentation/\n"); + + std::io::stdout().write_all(message.as_bytes())?; + + Ok(()) + } + fn generate_completion(shell: String) { + let shell = match shell.as_ref() { + "bash" => structopt::clap::Shell::Bash, + "fish" => structopt::clap::Shell::Fish, + "zsh" => structopt::clap::Shell::Zsh, + "powerShell" => structopt::clap::Shell::PowerShell, + "elvish" => structopt::clap::Shell::Elvish, + other => { + eprintln!("Unsupported shell: {}", other); + std::process::exit(1); + } + }; + let mut out = std::io::stdout(); + CliArgs::clap().gen_completions_to("zellij", shell, &mut out); + } +} diff --git a/src/common/utils/consts.rs b/src/common/utils/consts.rs index c77f1c9e..479405c3 100644 --- a/src/common/utils/consts.rs +++ b/src/common/utils/consts.rs @@ -47,3 +47,8 @@ lazy_static! { pub static ref ZELLIJ_TMP_LOG_DIR: PathBuf = ZELLIJ_TMP_DIR.join("zellij-log"); pub static ref ZELLIJ_TMP_LOG_FILE: PathBuf = ZELLIJ_TMP_LOG_DIR.join("log.txt"); } + +pub const FEATURES: &[&str] = &[ + #[cfg(feature = "enable_automatic_asset_installation")] + "enable_automatic_asset_installation", +]; diff --git a/src/main.rs b/src/main.rs index cb016067..c1f0f387 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,9 @@ mod server; mod tests; use client::{boundaries, layout, panes, start_client, tab}; -use common::{command_is_executing, errors, os_input_output, pty, screen, setup, utils, wasm_vm}; +use common::{ + command_is_executing, errors, os_input_output, pty, screen, setup::Setup, utils, wasm_vm, +}; use server::start_server; use structopt::StructOpt; @@ -22,33 +24,19 @@ use std::convert::TryFrom; pub fn main() { let opts = CliArgs::from_args(); - let config = match Config::try_from(&opts) { - Ok(config) => config, - Err(e) => { - eprintln!("There was an error in the config file:\n{}", e); - std::process::exit(1); - } - }; - let config_options = Options::from_cli(&config.options, opts.option.clone()); - if let Some(crate::cli::ConfigCli::GenerateCompletion { shell }) = opts.option { - let shell = match shell.as_ref() { - "bash" => structopt::clap::Shell::Bash, - "fish" => structopt::clap::Shell::Fish, - "zsh" => structopt::clap::Shell::Zsh, - "powerShell" => structopt::clap::Shell::PowerShell, - "elvish" => structopt::clap::Shell::Elvish, - other => { - eprintln!("Unsupported shell: {}", other); + if let Some(crate::cli::ConfigCli::Setup(setup)) = opts.option.clone() { + Setup::from_cli(&setup, opts).expect("Failed to print to stdout"); + std::process::exit(0); + } else { + let config = match Config::try_from(&opts) { + Ok(config) => config, + Err(e) => { + eprintln!("There was an error in the config file:\n{}", e); std::process::exit(1); } }; - let mut out = std::io::stdout(); - CliArgs::clap().gen_completions_to("zellij", shell, &mut out); - } else if let Some(crate::cli::ConfigCli::Setup { .. }) = opts.option { - setup::dump_default_config().expect("Failed to print to stdout"); - std::process::exit(0); - } else { + let config_options = Options::from_cli(&config.options, opts.option.clone()); atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap(); atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap(); let server_os_input = get_server_os_input();