Add check flag to the setup subcommand

* The check option communicates default and config options to the user
  as well as optional compile time features

* Move generate-completion from a subcommand to a flag in the setup
  subcommand
This commit is contained in:
a-kenji 2021-05-12 22:37:17 +02:00
parent a24c7f79f1
commit d667e5ed81
5 changed files with 159 additions and 51 deletions

View File

@ -1,5 +1,6 @@
use super::common::utils::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}; use super::common::utils::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV};
use crate::common::input::options::Options; use crate::common::input::options::Options;
use crate::common::setup::Setup;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::PathBuf; use std::path::PathBuf;
use structopt::StructOpt; use structopt::StructOpt;
@ -40,17 +41,7 @@ pub enum ConfigCli {
#[structopt(name = "options")] #[structopt(name = "options")]
Options(Options), Options(Options),
#[structopt(name = "generate-completion")] /// Setup zellij and check its configuration
GenerateCompletion { shell: String },
#[structopt(name = "setup")] #[structopt(name = "setup")]
Setup { 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,
},
} }

View File

@ -60,8 +60,8 @@ impl TryFrom<&CliArgs> for Config {
return Config::new(&path); return Config::new(&path);
} }
if let Some(ConfigCli::Setup { clean, .. }) = opts.option { if let Some(ConfigCli::Setup(setup)) = opts.option.clone() {
if clean { if setup.clean {
return Config::from_default_assets(); return Config::from_default_assets();
} }
} }
@ -177,11 +177,12 @@ mod config_test {
#[test] #[test]
fn try_from_cli_args_with_option_clean() { fn try_from_cli_args_with_option_clean() {
use crate::common::setup::Setup;
let mut opts = CliArgs::default(); let mut opts = CliArgs::default();
opts.option = Some(ConfigCli::Setup { opts.option = Some(ConfigCli::Setup(Setup {
clean: true, clean: true,
dump_config: false, ..Setup::default()
}); }));
let result = Config::try_from(&opts); let result = Config::try_from(&opts);
assert!(result.is_ok()); assert!(result.is_ok());
} }

View File

@ -1,12 +1,17 @@
use crate::cli::CliArgs;
use crate::common::utils::consts::{ 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 crate::os_input_output::set_permissions;
use directories_next::BaseDirs; use directories_next::BaseDirs;
use serde::{Deserialize, Serialize};
use std::io::Write; use std::io::Write;
use std::{fs, path::Path, path::PathBuf}; use std::{fs, path::Path, path::PathBuf};
use structopt::StructOpt;
const CONFIG_LOCATION: &str = ".config/zellij"; const CONFIG_LOCATION: &str = ".config/zellij";
const CONFIG_NAME: &str = "config.yaml";
static ARROW_SEPARATOR: &str = "";
#[macro_export] #[macro_export]
macro_rules! asset_map { macro_rules! asset_map {
@ -56,11 +61,7 @@ pub mod install {
/// Goes through a predefined list and checks for an already /// Goes through a predefined list and checks for an already
/// existing config directory, returns the first match /// existing config directory, returns the first match
pub fn find_default_config_dir() -> Option<PathBuf> { pub fn find_default_config_dir() -> Option<PathBuf> {
vec![ default_config_dirs()
home_config_dir(),
Some(xdg_config_dir()),
Some(Path::new(SYSTEM_DEFAULT_CONFIG_DIR).to_path_buf()),
]
.into_iter() .into_iter()
.filter(|p| p.is_some()) .filter(|p| p.is_some())
.find(|p| p.clone().unwrap().exists()) .find(|p| p.clone().unwrap().exists())
@ -72,6 +73,15 @@ pub fn find_default_config_dir() -> Option<PathBuf> {
None None
} }
/// Order in which config directories are checked
fn default_config_dirs() -> Vec<Option<PathBuf>> {
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 /// Looks for an existing dir, uses that, else returns a
/// dir matching the config spec. /// dir matching the config spec.
pub fn get_default_data_dir() -> PathBuf { 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<()> { pub fn dump_default_config() -> std::io::Result<()> {
dump_asset(DEFAULT_CONFIG) 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<String>,
}
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::<Vec<PathBuf>>();
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);
}
}

View File

@ -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_DIR: PathBuf = ZELLIJ_TMP_DIR.join("zellij-log");
pub static ref ZELLIJ_TMP_LOG_FILE: PathBuf = ZELLIJ_TMP_LOG_DIR.join("log.txt"); 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",
];

View File

@ -6,7 +6,9 @@ mod server;
mod tests; mod tests;
use client::{boundaries, layout, panes, start_client, tab}; 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 server::start_server;
use structopt::StructOpt; use structopt::StructOpt;
@ -22,6 +24,11 @@ use std::convert::TryFrom;
pub fn main() { pub fn main() {
let opts = CliArgs::from_args(); let opts = CliArgs::from_args();
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) { let config = match Config::try_from(&opts) {
Ok(config) => config, Ok(config) => config,
Err(e) => { Err(e) => {
@ -30,25 +37,6 @@ pub fn main() {
} }
}; };
let config_options = Options::from_cli(&config.options, opts.option.clone()); 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);
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 {
atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap(); atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap();
atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap(); atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap();
let server_os_input = get_server_os_input(); let server_os_input = get_server_os_input();