use std::{iter, process::ExitStatus};
use crate::{
bridge::create_blocking_nvim_command, dimensions::Dimensions, frame::Frame, settings::*,
version::BUILD_VERSION,
};
use anyhow::{Context, Result};
use clap::{
ArgAction, Parser, ValueEnum,
builder::{FalseyValueParser, Styles, styling},
};
#[cfg(target_os = "macos")]
use clap::{CommandFactory, parser::ValueSource};
use winit::window::CursorIcon;
#[cfg(target_os = "windows")]
pub const SRGB_DEFAULT: &str = "1";
#[cfg(not(target_os = "windows"))]
pub const SRGB_DEFAULT: &str = "0";
const NEOVIM_PASSTHROUGH_FLAGS: &[&str] = &["-h", "--help", "-?", "-v", "--version", "--api-info"];
fn get_styles() -> Styles {
styling::Styles::styled()
.header(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD)
.usage(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD)
.literal(styling::AnsiColor::Blue.on_default() | styling::Effects::BOLD)
.placeholder(styling::AnsiColor::Cyan.on_default())
}
#[derive(Clone, Debug, Parser)]
#[command(version = BUILD_VERSION, about, long_about = None, styles = get_styles())]
pub struct CmdLineSettings {
#[arg(
num_args = ..,
action = ArgAction::Append,
)]
pub files_to_open: Vec<String>,
#[arg(
num_args = ..,
action = ArgAction::Append,
last = true,
allow_hyphen_values = true
)]
pub neovim_args: Vec<String>,
#[arg(long = "log")]
pub log_to_file: bool,
#[arg(long, alias = "remote-tcp", env = "NEOVIDE_SERVER", value_name = "ADDRESS")]
pub server: Option<String>,
#[cfg(target_os = "macos")]
#[arg(long = "reuse-instance", action = ArgAction::SetTrue, default_value = "0", value_parser = FalseyValueParser::new())]
pub reuse_instance: bool,
#[cfg(target_os = "macos")]
#[arg(long = "new-window", requires = "reuse_instance", action = ArgAction::SetTrue, default_value = "0", value_parser = FalseyValueParser::new())]
pub new_window: bool,
#[arg(long, env = "NEOVIDE_WSL")]
pub wsl: bool,
#[arg(long, env = "NEOVIDE_FRAME", default_value_t)]
pub frame: Frame,
#[arg(long = "no-multigrid", env = "NEOVIDE_NO_MULTIGRID", value_parser = FalseyValueParser::new())]
pub no_multi_grid: bool,
#[arg(long = "mouse-cursor-icon", env = "NEOVIDE_MOUSE_CURSOR_ICON", default_value = "arrow")]
pub mouse_cursor_icon: MouseCursorIcon,
#[arg(long = "title-hidden", env = "NEOVIDE_TITLE_HIDDEN", value_parser = FalseyValueParser::new())]
pub title_hidden: bool,
#[arg(long = "fork", env = "NEOVIDE_FORK", action = ArgAction::SetTrue, default_value = "0", value_parser = FalseyValueParser::new())]
pub fork: bool,
#[arg(long = "no-fork", action = ArgAction::SetTrue, value_parser = FalseyValueParser::new())]
_no_fork: bool,
#[arg(long = "no-idle", env = "NEOVIDE_IDLE", action = ArgAction::SetFalse, value_parser = FalseyValueParser::new())]
pub idle: bool,
#[arg(long = "tabs", env = "NEOVIDE_TABS", action = ArgAction::SetTrue, default_value = "1", value_parser = FalseyValueParser::new())]
pub tabs: bool,
#[arg(long = "no-tabs", action = ArgAction::SetTrue, value_parser = FalseyValueParser::new())]
_no_tabs: bool,
#[cfg(target_os = "macos")]
#[arg(long = "system-native-tabs", env = "NEOVIDE_SYSTEM_NATIVE_TABS", action = ArgAction::SetTrue, default_value = "0", value_parser = FalseyValueParser::new())]
pub system_native_tabs: bool,
#[cfg(target_os = "macos")]
#[arg(long = "no-system-native-tabs", action = ArgAction::SetTrue, value_parser = FalseyValueParser::new())]
_no_system_native_tabs: bool,
#[cfg(target_os = "macos")]
#[arg(
long = "system-tab-prev-hotkey",
env = "NEOVIDE_SYSTEM_TAB_PREV_HOTKEY",
default_value = "cmd+shift+["
)]
pub system_tab_prev_hotkey: String,
#[cfg(target_os = "macos")]
#[arg(
long = "system-tab-next-hotkey",
env = "NEOVIDE_SYSTEM_TAB_NEXT_HOTKEY",
default_value = "cmd+shift+]"
)]
pub system_tab_next_hotkey: String,
#[arg(long = "srgb", env = "NEOVIDE_SRGB", action = ArgAction::SetTrue, default_value = SRGB_DEFAULT, value_parser = FalseyValueParser::new())]
pub srgb: bool,
#[arg(long = "no-srgb", action = ArgAction::SetTrue, value_parser = FalseyValueParser::new())]
_no_srgb: bool,
#[arg(long = "vsync", env = "NEOVIDE_VSYNC", action = ArgAction::SetTrue, default_value = "1", value_parser = FalseyValueParser::new())]
pub vsync: bool,
#[arg(long = "no-vsync", action = ArgAction::SetTrue, value_parser = FalseyValueParser::new())]
_no_vsync: bool,
#[arg(long = "neovim-bin", env = "NEOVIM_BIN")]
pub neovim_bin: Option<String>,
#[arg(long = "wayland_app_id", env = "NEOVIDE_APP_ID", default_value = "neovide")]
pub wayland_app_id: String,
#[arg(long = "x11-wm-class", env = "NEOVIDE_WM_CLASS", default_value = "neovide")]
pub x11_wm_class: String,
#[arg(
long = "x11-wm-class-instance",
env = "NEOVIDE_WM_CLASS_INSTANCE",
default_value = "neovide"
)]
pub x11_wm_class_instance: String,
#[arg(long, env = "NEOVIDE_ICON")]
pub icon: Option<String>,
#[command(flatten)]
pub geometry: GeometryArgs,
#[cfg(any(target_os = "windows", target_os = "macos"))]
#[arg(long = "opengl", env = "NEOVIDE_OPENGL", action = ArgAction::SetTrue, value_parser = FalseyValueParser::new())]
pub opengl: bool,
#[arg(long = "chdir", env = "NEOVIDE_CHDIR")]
pub chdir: Option<String>,
}
#[derive(Clone, Debug, Args, PartialEq)]
#[group(required = false, multiple = false)]
pub struct GeometryArgs {
#[arg(long, env = "NEOVIDE_GRID")]
pub grid: Option<Option<Dimensions>>,
#[arg(long, env = "NEOVIDE_SIZE")]
pub size: Option<Dimensions>,
#[arg(long, env = "NEOVIDE_MAXIMIZED", value_parser = FalseyValueParser::new())]
pub maximized: bool,
}
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
pub enum MouseCursorIcon {
Arrow,
IBeam,
}
impl MouseCursorIcon {
pub fn from_config(value: Option<&str>) -> Result<Self, String> {
value.map_or(Ok(Self::Arrow), |value| <Self as ValueEnum>::from_str(value, false))
}
pub fn parse(&self) -> CursorIcon {
match self {
MouseCursorIcon::Arrow => CursorIcon::Default,
MouseCursorIcon::IBeam => CursorIcon::Text,
}
}
}
impl GeometryArgs {
pub fn from_config(
size: Option<&str>,
grid: Option<&str>,
maximized: Option<bool>,
) -> Result<Self, String> {
let maximized = maximized.unwrap_or(false);
let has_size = size.is_some();
let has_grid = grid.is_some();
let conflicting = (has_size && has_grid) || (maximized && (has_size || has_grid));
if conflicting {
return Err("size, grid and maximized are mutually exclusive".to_owned());
}
Ok(Self {
grid: grid.map(|grid| grid.parse::<Dimensions>().map(Some)).transpose()?,
size: size.map(str::parse::<Dimensions>).transpose()?,
maximized,
})
}
}
impl Default for CmdLineSettings {
fn default() -> Self {
Self::parse_from(iter::empty::<String>())
}
}
pub fn handle_command_line_arguments(args: Vec<String>, settings: &Settings) -> Result<()> {
let mut cmdline = CmdLineSettings::try_parse_from(args)?;
if cmdline._no_tabs {
cmdline.tabs = false;
}
#[cfg(target_os = "macos")]
if cmdline._no_system_native_tabs {
cmdline.system_native_tabs = false;
}
if cmdline._no_fork {
cmdline.fork = false;
}
if cmdline._no_srgb {
cmdline.srgb = false;
}
if cmdline._no_vsync {
cmdline.vsync = false;
}
settings.set::<CmdLineSettings>(&cmdline);
Ok(())
}
#[cfg(target_os = "macos")]
pub fn argv_chdir() -> Option<String> {
let matches = CmdLineSettings::command().try_get_matches_from(std::env::args_os()).ok()?;
(matches.value_source("chdir") == Some(ValueSource::CommandLine))
.then(|| matches.get_one::<String>("chdir").cloned())
.flatten()
}
pub fn maybe_passthrough_to_neovim(
cmdline_settings: &CmdLineSettings,
) -> Result<Option<ExitStatus>> {
if !neovim_passthrough_requested(&cmdline_settings.neovim_args) {
return Ok(None);
}
let mut command = create_blocking_nvim_command(cmdline_settings, false);
let binary = cmdline_settings.neovim_bin.clone().unwrap_or_else(|| "nvim".to_owned());
let status = command
.status()
.with_context(|| format!("Failed to run {binary} for passthrough output"))?;
Ok(Some(status))
}
pub fn exit_status_code(status: ExitStatus) -> i32 {
#[cfg(unix)]
{
use std::os::unix::process::ExitStatusExt;
status.code().unwrap_or_else(|| 128 + status.signal().unwrap_or(0))
}
#[cfg(windows)]
{
status.code().unwrap_or(1)
}
#[cfg(not(any(unix, windows)))]
{
return status.code().unwrap_or(1);
}
}
fn neovim_passthrough_requested(args: &[String]) -> bool {
args.iter().any(|arg| NEOVIM_PASSTHROUGH_FLAGS.contains(&arg.as_str()))
}
#[cfg(test)]
#[allow(clippy::bool_assert_comparison)] #[serial_test::serial]
mod tests {
use scoped_env::ScopedEnv;
use super::*;
#[test]
fn test_neovim_passthrough() {
let settings = Settings::new();
let args: Vec<String> =
["neovide", "--no-tabs", "--", "--clean"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().neovim_args, vec!["--clean"]);
}
#[test]
fn test_files_to_open() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "./foo.txt", "--no-tabs", "./bar.md"]
.iter()
.map(|s| s.to_string())
.collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().files_to_open, vec!["./foo.txt", "./bar.md"]);
assert!(settings.get::<CmdLineSettings>().neovim_args.is_empty());
}
#[test]
#[cfg(target_os = "windows")]
fn test_files_to_open_with_wsl() {
let settings = Settings::new();
let args: Vec<String> = [
"neovide",
"--wsl",
"C:\\Users\\MyUser\\foo.txt",
"--no-tabs",
"C:\\bar.md",
"C:\\Program Files (x86)\\Some Application\\Settings.ini",
]
.iter()
.map(|s| s.to_string())
.collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(
settings.get::<CmdLineSettings>().files_to_open,
vec![
"C:\\Users\\MyUser\\foo.txt",
"C:\\bar.md",
"C:\\Program Files (x86)\\Some Application\\Settings.ini"
]
);
assert!(settings.get::<CmdLineSettings>().neovim_args.is_empty());
}
#[test]
fn test_files_to_open_with_passthrough() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--no-tabs", "./foo.txt", "./bar.md", "--", "--clean"]
.iter()
.map(|s| s.to_string())
.collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().neovim_args, vec!["--clean"]);
assert_eq!(settings.get::<CmdLineSettings>().files_to_open, vec!["./foo.txt", "./bar.md"]);
}
#[test]
fn test_files_to_open_with_flag() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "./foo.txt", "./bar.md", "--grid=420x240"]
.iter()
.map(|s| s.to_string())
.collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert!(settings.get::<CmdLineSettings>().neovim_args.is_empty());
assert_eq!(settings.get::<CmdLineSettings>().files_to_open, vec!["./foo.txt", "./bar.md"]);
assert_eq!(
settings.get::<CmdLineSettings>().geometry.grid,
Some(Some(Dimensions { width: 420, height: 240 })),
);
}
#[test]
#[cfg(target_os = "macos")]
fn test_reuse_instance_flag() {
let settings = Settings::new();
let args: Vec<String> =
["neovide", "--reuse-instance", "./foo.txt"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert!(settings.get::<CmdLineSettings>().reuse_instance);
assert_eq!(settings.get::<CmdLineSettings>().files_to_open, vec!["./foo.txt"]);
}
#[test]
#[cfg(target_os = "macos")]
fn test_new_window_flag() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--reuse-instance", "--new-window", "./foo.txt"]
.iter()
.map(|s| s.to_string())
.collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert!(settings.get::<CmdLineSettings>().reuse_instance);
assert!(settings.get::<CmdLineSettings>().new_window);
assert_eq!(settings.get::<CmdLineSettings>().files_to_open, vec!["./foo.txt"]);
}
#[test]
#[cfg(target_os = "macos")]
fn test_new_window_requires_reuse_instance() {
let settings = Settings::new();
let args: Vec<String> =
["neovide", "--new-window", "./foo.txt"].iter().map(|s| s.to_string()).collect();
assert!(handle_command_line_arguments(args, &settings).is_err());
}
#[test]
fn test_grid() {
let settings = Settings::new();
let args: Vec<String> =
["neovide", "--grid=420x240"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(
settings.get::<CmdLineSettings>().geometry.grid,
Some(Some(Dimensions { width: 420, height: 240 })),
);
}
#[test]
fn test_grid_environment_variable() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_GRID", "420x240");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(
settings.get::<CmdLineSettings>().geometry.grid,
Some(Some(Dimensions { width: 420, height: 240 })),
);
}
#[test]
fn test_size() {
let settings = Settings::new();
let args: Vec<String> =
["neovide", "--size=420x240"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(
settings.get::<CmdLineSettings>().geometry.size,
Some(Dimensions { width: 420, height: 240 }),
);
}
#[test]
fn test_size_environment_variable() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_SIZE", "420x240");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(
settings.get::<CmdLineSettings>().geometry.size,
Some(Dimensions { width: 420, height: 240 }),
);
}
#[test]
fn test_geometry_args_from_config_size() {
assert_eq!(
GeometryArgs::from_config(Some("420x240"), None, None).unwrap(),
GeometryArgs {
size: Some(Dimensions { width: 420, height: 240 }),
grid: None,
maximized: false,
}
);
}
#[test]
fn test_geometry_args_from_config_grid() {
assert_eq!(
GeometryArgs::from_config(None, Some("80x24"), None).unwrap(),
GeometryArgs {
size: None,
grid: Some(Some(Dimensions { width: 80, height: 24 })),
maximized: false,
}
);
}
#[test]
fn test_geometry_args_from_config_rejects_conflicts() {
assert_eq!(
GeometryArgs::from_config(Some("420x240"), Some("80x24"), None).unwrap_err(),
"size, grid and maximized are mutually exclusive"
);
}
#[test]
fn test_server_environment_variable() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_SERVER", "127.0.0.1:7777");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().server, Some("127.0.0.1:7777".to_string()));
}
#[test]
fn test_log_to_file() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--log"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert!(settings.get::<CmdLineSettings>().log_to_file);
}
#[test]
fn test_passthrough_detection_help() {
assert!(super::neovim_passthrough_requested(&["-h".into()]));
}
#[test]
fn test_passthrough_detection_none() {
assert!(!super::neovim_passthrough_requested(&["file".into(), "--clean".into()]));
}
#[test]
fn test_frameless_flag() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--frame=full"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().frame, Frame::Full);
}
#[test]
fn test_frameless_environment_variable() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_FRAME", "none");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().frame, Frame::None);
}
#[test]
fn test_neovim_bin_arg() {
let settings = Settings::new();
let args: Vec<String> =
["neovide", "--neovim-bin", "foo"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().neovim_bin, Some("foo".to_owned()));
}
#[test]
fn test_neovim_bin_environment_variable() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIM_BIN", "foo");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().neovim_bin, Some("foo".to_owned()));
}
#[test]
fn test_srgb_default() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
#[cfg(target_os = "windows")]
let default_value = true;
#[cfg(not(target_os = "windows"))]
let default_value = false;
assert_eq!(settings.get::<CmdLineSettings>().srgb, default_value);
}
#[test]
fn test_srgb() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--srgb"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().srgb, true);
}
#[test]
fn test_nosrgb() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--no-srgb"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().srgb, false);
}
#[test]
fn test_no_srgb_environment() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_SRGB", "0");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().srgb, false);
}
#[test]
fn test_override_srgb_environment() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--no-srgb"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_SRGB", "1");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().srgb, false);
}
#[test]
fn test_override_nosrgb_environment() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--srgb"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_SRGB", "0");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().srgb, true,);
}
#[test]
fn test_vsync_default() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().vsync, true);
}
#[test]
fn test_vsync() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--vsync"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().vsync, true);
}
#[test]
fn test_novsync() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--no-vsync"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().vsync, false);
}
#[test]
fn test_no_vsync_environment() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_VSYNC", "0");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().vsync, false);
}
#[test]
fn test_override_vsync_environment() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--no-vsync"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_VSYNC", "1");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().vsync, false);
}
#[test]
fn test_override_novsync_environment() {
let settings = Settings::new();
let args: Vec<String> = ["neovide", "--vsync"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_VSYNC", "0");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert_eq!(settings.get::<CmdLineSettings>().vsync, true,);
}
#[cfg(target_os = "macos")]
#[test]
fn test_system_native_tabs_flag() {
let settings = Settings::new();
let args: Vec<String> =
["neovide", "--system-native-tabs"].iter().map(|s| s.to_string()).collect();
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert!(settings.get::<CmdLineSettings>().system_native_tabs);
}
#[cfg(target_os = "macos")]
#[test]
fn test_system_native_tabs_env() {
let settings = Settings::new();
let args: Vec<String> = ["neovide"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_SYSTEM_NATIVE_TABS", "1");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert!(settings.get::<CmdLineSettings>().system_native_tabs);
}
#[cfg(target_os = "macos")]
#[test]
fn test_system_native_tabs_override_env() {
let settings = Settings::new();
let args: Vec<String> =
["neovide", "--no-system-native-tabs"].iter().map(|s| s.to_string()).collect();
let _env = ScopedEnv::set("NEOVIDE_SYSTEM_NATIVE_TABS", "1");
handle_command_line_arguments(args, &settings).expect("Could not parse arguments");
assert!(!settings.get::<CmdLineSettings>().system_native_tabs);
}
}