diff --git a/src/bridge/mod.rs b/src/bridge/mod.rs index 87e6605..451676a 100644 --- a/src/bridge/mod.rs +++ b/src/bridge/mod.rs @@ -123,9 +123,7 @@ pub fn build_neovide_command(channel: u64, num_args: u64, command: &str, event: pub fn create_nvim_command() -> Command { let mut cmd = build_nvim_cmd(); - cmd.arg("--embed") - .args(SETTINGS.get::().neovim_args.iter()) - .args(SETTINGS.get::().files_to_open.iter()); + cmd.arg("--embed").args(SETTINGS.get::().neovim_args.iter()); info!("Starting neovim with: {:?}", cmd); diff --git a/src/cmd_line.rs b/src/cmd_line.rs index df59afe..0a1b3b7 100644 --- a/src/cmd_line.rs +++ b/src/cmd_line.rs @@ -5,21 +5,22 @@ use clap::{App, Arg}; #[derive(Clone, Debug)] pub struct CmdLineSettings { - pub verbosity: u64, - pub log_to_file: bool, + // Pass through arguments pub neovim_args: Vec, - pub neovim_bin: Option, - pub files_to_open: Vec, - - pub no_fork: bool, - pub no_idle: bool, - pub srgb: bool, + // Command-line arguments only pub geometry: Dimensions, - pub wsl: bool, + pub log_to_file: bool, + pub no_fork: bool, pub remote_tcp: Option, - pub multi_grid: bool, - pub maximized: bool, + pub wsl: bool, + // Command-line flags with environment variable fallback pub frameless: bool, + pub maximized: bool, + pub multi_grid: bool, + pub no_idle: bool, + pub srgb: bool, + // Command-line arguments with environment variable fallback + pub neovim_bin: Option, pub wayland_app_id: String, pub x11_wm_class: String, } @@ -27,37 +28,47 @@ pub struct CmdLineSettings { impl Default for CmdLineSettings { fn default() -> Self { Self { - verbosity: 0, - log_to_file: false, - neovim_bin: None, + // Pass through arguments neovim_args: vec![], - files_to_open: vec![], - - no_fork: false, - no_idle: false, - srgb: true, + // Command-line arguments only geometry: DEFAULT_WINDOW_GEOMETRY, - wsl: false, + log_to_file: false, + no_fork: false, remote_tcp: None, - multi_grid: false, - maximized: false, + wsl: false, + // Command-line flags with environment variable fallback frameless: false, + maximized: false, + multi_grid: false, + no_idle: false, + srgb: true, + // Command-line arguments with environment variable fallback + neovim_bin: None, wayland_app_id: String::new(), x11_wm_class: String::new(), } } } -pub fn handle_command_line_arguments() -> Result<(), String> { +pub fn handle_command_line_arguments(args: Vec) -> Result<(), String> { let clapp = App::new("Neovide") .version(crate_version!()) .author(crate_authors!()) .about(crate_description!()) + // Pass through arguments .arg( - Arg::with_name("verbosity") - .short("v") + Arg::with_name("neovim_args") .multiple(true) - .help("Increase verbosity level (repeatable up to 4 times; implies --nofork)"), + .takes_value(true) + .last(true) + .help("Specify Arguments to pass down to neovim"), + ) + // Command-line arguments only + .arg( + Arg::with_name("geometry") + .long("geometry") + .takes_value(true) + .help("Specify the Geometry of the window"), ) .arg( Arg::with_name("log_to_file") @@ -70,14 +81,21 @@ pub fn handle_command_line_arguments() -> Result<(), String> { .help("Do not detach process from terminal"), ) .arg( - Arg::with_name("noidle") - .long("noidle") - .help("Render every frame. Takes more power and cpu time but possibly fixes animation issues"), + Arg::with_name("remote_tcp") + .long("remote-tcp") + .takes_value(true) + .help("Connect to Remote TCP"), ) .arg( - Arg::with_name("srgb") - .long("srgb") - .help("Use standard color space to initialize the window. Swapping this variable sometimes fixes issues on startup"), + Arg::with_name("wsl") + .long("wsl") + .help("Run in WSL") + ) + // Command-line flags with environment variable fallback + .arg( + Arg::with_name("frameless") + .long("frameless") + .help("Removes the window frame. NOTE: Window might not be resizable after this setting is enabled.") ) .arg( Arg::with_name("maximized") @@ -90,46 +108,22 @@ pub fn handle_command_line_arguments() -> Result<(), String> { .help("Enable Multigrid"), ) .arg( - Arg::with_name("frameless") - .long("frameless") - .help("Removes the window frame. NOTE: Window might not be resizable after this setting is enabled.") - ) - .arg( - Arg::with_name("wsl") - .long("wsl") - .help("Run in WSL") - ) - .arg( - Arg::with_name("remote_tcp") - .long("remote-tcp") - .takes_value(true) - .help("Connect to Remote TCP"), - ) - .arg( - Arg::with_name("geometry") - .long("geometry") - .takes_value(true) - .help("Specify the Geometry of the window"), + Arg::with_name("noidle") + .long("noidle") + .help("Render every frame. Takes more power and cpu time but possibly fixes animation issues"), ) .arg( - Arg::with_name("files") - .multiple(true) - .takes_value(true) - .help("Files to open"), + Arg::with_name("srgb") + .long("srgb") + .help("Use standard color space to initialize the window. Swapping this variable sometimes fixes issues on startup"), ) + // Command-line arguments with environment variable fallback .arg( Arg::with_name("neovim_bin") .long("neovim-bin") .takes_value(true) .help("Specify path to neovim"), ) - .arg( - Arg::with_name("neovim_args") - .multiple(true) - .takes_value(true) - .last(true) - .help("Specify Arguments to pass down to neovim"), - ) .arg( Arg::with_name("wayland_app_id") .long("wayland-app-id") @@ -141,53 +135,161 @@ pub fn handle_command_line_arguments() -> Result<(), String> { .takes_value(true) ); - let matches = clapp.get_matches(); + let matches = clapp.get_matches_from(args); /* * Integrate Environment Variables as Defaults to the command-line ones. - * - * NEOVIM_BIN - * NEOVIDE_MULTIGRID || --multigrid + * + * If the command-line argument is not set, the environment variable is used. */ SETTINGS.set::(&CmdLineSettings { - verbosity: matches.occurrences_of("verbosity"), - log_to_file: matches.is_present("log_to_file"), + // Pass through arguments neovim_args: matches .values_of("neovim_args") .map(|opt| opt.map(|v| v.to_owned()).collect()) .unwrap_or_default(), - neovim_bin: match std::env::var("NEOVIM_BIN") { - Ok(val) => Some(val), - Err(_) => matches.value_of("neovim_bin").map(|b| b.to_string()), - }, - files_to_open: matches - .values_of("files") - .map(|opt| opt.map(|v| v.to_owned()).collect()) - .unwrap_or_default(), - - no_fork: matches.is_present("nofork") || matches.is_present("verbosity"), - no_idle: matches.is_present("noidle") || std::env::var("NEOVIDE_NOIDLE").is_ok(), - srgb: matches.is_present("srgb") || std::env::var("NEOVIDE_NO_SRGB").is_err(), + // Command-line arguments only geometry: parse_window_geometry(matches.value_of("geometry").map(|i| i.to_owned()))?, - wsl: matches.is_present("wsl"), + log_to_file: matches.is_present("log_to_file"), + no_fork: matches.is_present("nofork"), remote_tcp: matches.value_of("remote_tcp").map(|i| i.to_owned()), - multi_grid: std::env::var("NEOVIDE_MULTIGRID").is_ok() || matches.is_present("multi_grid"), - maximized: matches.is_present("maximized") || std::env::var("NEOVIDE_MAXIMIZED").is_ok(), + wsl: matches.is_present("wsl"), + // Command-line flags with environment variable fallback frameless: matches.is_present("frameless") || std::env::var("NEOVIDE_FRAMELESS").is_ok(), - wayland_app_id: match std::env::var("NEOVIDE_APP_ID") { - Ok(val) => val, - Err(_) => matches - .value_of("wayland_app_id") - .unwrap_or("neovide") - .to_string(), - }, - x11_wm_class: match std::env::var("NEOVIDE_WM_CLASS") { - Ok(val) => val, - Err(_) => matches - .value_of("x11_wm_class") - .unwrap_or("neovide") - .to_string(), - }, + maximized: matches.is_present("maximized") || std::env::var("NEOVIDE_MAXIMIZED").is_ok(), + multi_grid: matches.is_present("multi_grid") || std::env::var("NEOVIDE_MULTIGRID").is_ok(), + no_idle: matches.is_present("noidle") || std::env::var("NEOVIDE_NOIDLE").is_ok(), + srgb: matches.is_present("srgb") || std::env::var("NEOVIDE_NO_SRGB").is_err(), + // Command-line arguments with environment variable fallback + neovim_bin: matches + .value_of("neovim_bin") + .map(|v| v.to_owned()) + .or_else(|| std::env::var("NEOVIM_BIN").ok()), + wayland_app_id: matches + .value_of("wayland_app_id") + .map(|v| v.to_owned()) + .or_else(|| std::env::var("NEOVIDE_APP_ID").ok()) + .unwrap_or("neovide".to_owned()), + x11_wm_class: matches + .value_of("x11_wm_class") + .map(|v| v.to_owned()) + .or_else(|| std::env::var("NEOVIDE_X11_WM_CLASS").ok()) + .unwrap_or("neovide".to_owned()), }); Ok(()) } + +#[cfg(test)] +mod tests { + use std::sync::Mutex; + use std::env::set_var; + + use lazy_static::lazy_static; + + use super::*; + + // Use a mutex to ensure that the settings are initialized and accessed in series + lazy_static! { + static ref ACCESSING_SETTINGS: Mutex = Mutex::new(false); + } + + #[test] + fn test_neovim_passthrough() { + let args: Vec = vec![ + "neovide", + "--", + "--clean", + ].iter() + .map(|s| s.to_string()) + .collect(); + + let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); + handle_command_line_arguments(args).expect("Could not parse arguments"); + assert_eq!(SETTINGS.get::().neovim_args, vec!["--clean"]); + } + + #[test] + fn test_geometry() { + let args: Vec = vec![ + "neovide", + "--geometry=42x24", + ].iter() + .map(|s| s.to_string()) + .collect(); + + let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); + handle_command_line_arguments(args).expect("Could not parse arguments"); + assert_eq!(SETTINGS.get::().geometry, Dimensions { width: 42, height: 24 }); + } + + #[test] + fn test_log_to_file() { + let args: Vec = vec![ + "neovide", + "--log", + ].iter() + .map(|s| s.to_string()) + .collect(); + + let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); + handle_command_line_arguments(args).expect("Could not parse arguments"); + assert_eq!(SETTINGS.get::().log_to_file, true); + } + + #[test] + fn test_frameless_flag() { + let args: Vec = vec![ + "neovide", + "--frameless", + ].iter() + .map(|s| s.to_string()) + .collect(); + + let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); + handle_command_line_arguments(args).expect("Could not parse arguments"); + assert_eq!(SETTINGS.get::().frameless, true); + } + + #[test] + fn test_frameless_environment_variable() { + let args: Vec = vec![ + "neovide", + ].iter() + .map(|s| s.to_string()) + .collect(); + + let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); + set_var("NEOVIDE_FRAMELESS", "true"); + handle_command_line_arguments(args).expect("Could not parse arguments"); + assert_eq!(SETTINGS.get::().frameless, true); + } + + #[test] + fn test_neovim_bin_arg() { + let args: Vec = vec![ + "neovide", + "--neovim-bin", + "foo", + ].iter() + .map(|s| s.to_string()) + .collect(); + + let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); + handle_command_line_arguments(args).expect("Could not parse arguments"); + assert_eq!(SETTINGS.get::().neovim_bin, Some("foo".to_owned())); + } + + #[test] + fn test_neovim_bin_environment_variable() { + let args: Vec = vec![ + "neovide", + ].iter() + .map(|s| s.to_string()) + .collect(); + + let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); + set_var("NEOVIM_BIN", "foo"); + handle_command_line_arguments(args).expect("Could not parse arguments"); + assert_eq!(SETTINGS.get::().neovim_bin, Some("foo".to_owned())); + } +} diff --git a/src/main.rs b/src/main.rs index 50a3fbb..2de65f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,6 +31,7 @@ extern crate derive_new; extern crate lazy_static; use std::sync::mpsc::channel; +use std::env::args; use log::trace; use tokio::sync::mpsc::unbounded_channel; @@ -117,7 +118,7 @@ fn main() { // properly or updates to the graphics are pushed to the screen. //Will exit if -h or -v - if let Err(err) = cmd_line::handle_command_line_arguments() { + if let Err(err) = cmd_line::handle_command_line_arguments(args().collect()) { eprintln!("{}", err); return; } @@ -179,12 +180,6 @@ fn main() { pub fn init_logger() { let settings = SETTINGS.get::(); - let verbosity = match settings.verbosity { - 0 => "warn", - 1 => "info", - 2 => "debug", - _ => "trace", - }; let logger = match settings.log_to_file { true => Logger::with_env_or_str("neovide") .duplicate_to_stderr(Duplicate::Error) @@ -194,7 +189,7 @@ pub fn init_logger() { Naming::Timestamps, Cleanup::KeepLogFiles(1), ), - false => Logger::with_env_or_str(format!("neovide = {}", verbosity)), + false => Logger::with_env_or_str(format!("neovide = {}", "trace")), }; logger.start().expect("Could not start logger"); }