use crate::cli::Command;
use crate::data::{InputMode, WebSharing};
use clap::{Args, ValueEnum};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::str::FromStr;
use std::net::IpAddr;
pub const DEFAULT_WORD_SEPARATORS: &str = "[]{}<>()";
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize, ValueEnum)]
pub enum OnForceClose {
#[serde(alias = "quit")]
Quit,
#[serde(alias = "detach")]
Detach,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ValueEnum)]
pub enum NestedSessionHandling {
#[serde(alias = "ask")]
Ask,
#[serde(alias = "fullscreen")]
Fullscreen,
#[serde(alias = "descend")]
Descend,
#[serde(alias = "never")]
Never,
}
impl Default for NestedSessionHandling {
fn default() -> Self {
Self::Ask
}
}
impl FromStr for NestedSessionHandling {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Ask" | "ask" => Ok(Self::Ask),
"Fullscreen" | "fullscreen" => Ok(Self::Fullscreen),
"Descend" | "descend" => Ok(Self::Descend),
"Never" | "never" => Ok(Self::Never),
_ => Err(format!("No such nested_session_handling: {}", s)),
}
}
}
impl Default for OnForceClose {
fn default() -> Self {
Self::Detach
}
}
impl FromStr for OnForceClose {
type Err = Box<dyn std::error::Error>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"quit" => Ok(Self::Quit),
"detach" => Ok(Self::Detach),
e => Err(e.to_string().into()),
}
}
}
#[derive(ValueEnum, Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum PaneFrameStyle {
Full,
Titles,
None,
}
impl Default for PaneFrameStyle {
fn default() -> Self {
PaneFrameStyle::Titles
}
}
impl PaneFrameStyle {
pub fn draws_full_frames(&self) -> bool {
matches!(self, PaneFrameStyle::Full)
}
pub fn draws_titles(&self) -> bool {
matches!(self, PaneFrameStyle::Titles)
}
pub fn from_options(options: &Options) -> Self {
if options.pane_frames == Some(false) {
return PaneFrameStyle::None;
}
match options.pane_frame_style {
Some(PaneFrameStyle::Full) => PaneFrameStyle::Full,
_ => PaneFrameStyle::Titles,
}
}
}
impl FromStr for PaneFrameStyle {
type Err = Box<dyn std::error::Error>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.trim().to_lowercase().as_str() {
"full" => Ok(PaneFrameStyle::Full),
"titles" => Ok(PaneFrameStyle::Titles),
"none" => Ok(PaneFrameStyle::None),
e => Err(format!(
"Unknown pane frame style: '{}' (expected 'full', 'titles' or 'none')",
e
)
.into()),
}
}
}
#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, Args)]
pub struct Options {
#[clap(long, value_parser)]
#[serde(default)]
pub simplified_ui: Option<bool>,
#[clap(long, value_parser)]
pub theme: Option<String>,
#[clap(long, value_parser)]
pub theme_dark: Option<String>,
#[clap(long, value_parser)]
pub theme_light: Option<String>,
#[clap(long, value_enum, hide_possible_values = true, value_parser)]
pub default_mode: Option<InputMode>,
#[clap(long, value_parser)]
pub default_shell: Option<PathBuf>,
#[clap(long, value_parser)]
pub default_cwd: Option<PathBuf>,
#[clap(long, value_parser)]
pub default_layout: Option<PathBuf>,
#[clap(long, value_parser)]
pub layout_dir: Option<PathBuf>,
#[clap(long, value_parser)]
pub theme_dir: Option<PathBuf>,
#[clap(long, value_parser)]
#[serde(default)]
pub mouse_mode: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub pane_frames: Option<bool>,
#[clap(long, value_enum, hide_possible_values = true, value_parser)]
#[serde(default)]
pub pane_frame_style: Option<PaneFrameStyle>,
#[clap(long, value_parser)]
#[serde(default)]
pub mirror_session: Option<bool>,
#[clap(long, value_enum, hide_possible_values = true, value_parser)]
pub on_force_close: Option<OnForceClose>,
#[clap(long, value_parser)]
pub scroll_buffer_size: Option<usize>,
#[clap(long, value_parser)]
#[serde(default)]
pub copy_command: Option<String>,
#[clap(
long,
value_enum,
ignore_case = true,
conflicts_with = "copy_command",
value_parser
)]
#[serde(default)]
pub copy_clipboard: Option<Clipboard>,
#[clap(long, value_parser)]
#[serde(default)]
pub copy_on_select: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub osc8_hyperlinks: Option<bool>,
#[clap(long, value_parser)]
pub scrollback_editor: Option<PathBuf>,
#[clap(long, value_parser)]
#[serde(default)]
pub session_name: Option<String>,
#[clap(long, value_parser)]
#[serde(default)]
pub attach_to_session: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub auto_layout: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub session_serialization: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub serialize_pane_viewport: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub scrollback_lines_to_serialize: Option<usize>,
#[clap(long, value_parser)]
#[serde(default)]
pub styled_underlines: Option<bool>,
#[clap(long, value_parser)]
pub serialization_interval: Option<u64>,
#[clap(long, value_parser)]
pub disable_session_metadata: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub support_kitty_keyboard_protocol: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub support_kitty_graphics_protocol: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub web_server: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub web_sharing: Option<WebSharing>,
#[clap(long, value_parser)]
#[serde(default)]
pub stacked_resize: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub stacked_pane_list: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub show_startup_tips: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub show_release_notes: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub advanced_mouse_actions: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub mouse_scroll_resize: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub mouse_hover_effects: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub mouse_hover_tips: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub visual_bell: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub focus_follows_mouse: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub mouse_click_through: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub osc133_command_selection: Option<bool>,
#[clap(long, value_parser)]
#[serde(default)]
pub word_separators: Option<String>,
#[clap(long, value_parser)]
#[serde(default)]
pub host_notification_protocol: Option<HostNotificationProtocol>,
pub web_server_ip: Option<IpAddr>,
pub web_server_port: Option<u16>,
pub web_server_cert: Option<PathBuf>,
pub web_server_key: Option<PathBuf>,
pub enforce_https_for_localhost: Option<bool>,
#[clap(long, value_parser)]
pub post_command_discovery_hook: Option<String>,
#[clap(long)]
pub client_async_worker_tasks: Option<usize>,
#[clap(long, value_enum, hide_possible_values = true, value_parser)]
#[serde(default)]
pub nested_session_handling: Option<NestedSessionHandling>,
#[clap(long, value_parser)]
#[serde(default)]
pub dangerously_enable_paste_buffer_read: Option<bool>,
}
#[derive(ValueEnum, Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
pub enum Clipboard {
#[serde(alias = "system")]
System,
#[serde(alias = "primary")]
Primary,
}
impl Default for Clipboard {
fn default() -> Self {
Self::System
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ValueEnum)]
pub enum HostNotificationProtocol {
#[serde(alias = "auto")]
Auto,
#[serde(alias = "osc9")]
Osc9,
#[serde(alias = "osc99")]
Osc99,
#[serde(alias = "bell")]
Bell,
#[serde(alias = "off")]
Off,
}
impl Default for HostNotificationProtocol {
fn default() -> Self {
Self::Auto
}
}
impl HostNotificationProtocol {
pub fn as_str(&self) -> &'static str {
match self {
Self::Auto => "auto",
Self::Osc9 => "osc9",
Self::Osc99 => "osc99",
Self::Bell => "bell",
Self::Off => "off",
}
}
}
impl FromStr for HostNotificationProtocol {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Auto" | "auto" => Ok(Self::Auto),
"Osc9" | "osc9" => Ok(Self::Osc9),
"Osc99" | "osc99" => Ok(Self::Osc99),
"Bell" | "bell" => Ok(Self::Bell),
"Off" | "off" => Ok(Self::Off),
_ => Err(format!("No such host_notification_protocol: {}", s)),
}
}
}
impl FromStr for Clipboard {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"System" | "system" => Ok(Self::System),
"Primary" | "primary" => Ok(Self::Primary),
_ => Err(format!("No such clipboard: {}", s)),
}
}
}
impl Options {
pub fn from_yaml(from_yaml: Option<Options>) -> Options {
if let Some(opts) = from_yaml {
opts
} else {
Options::default()
}
}
pub fn merge(&self, other: Options) -> Options {
let mouse_mode = other.mouse_mode.or(self.mouse_mode);
let pane_frames = other.pane_frames.or(self.pane_frames);
let pane_frame_style = other.pane_frame_style.or(self.pane_frame_style);
let auto_layout = other.auto_layout.or(self.auto_layout);
let mirror_session = other.mirror_session.or(self.mirror_session);
let simplified_ui = other.simplified_ui.or(self.simplified_ui);
let default_mode = other.default_mode.or(self.default_mode);
let default_shell = other.default_shell.or_else(|| self.default_shell.clone());
let default_cwd = other.default_cwd.or_else(|| self.default_cwd.clone());
let default_layout = other.default_layout.or_else(|| self.default_layout.clone());
let layout_dir = other.layout_dir.or_else(|| self.layout_dir.clone());
let theme_dir = other.theme_dir.or_else(|| self.theme_dir.clone());
let theme = other.theme.or_else(|| self.theme.clone());
let theme_dark = other.theme_dark.or_else(|| self.theme_dark.clone());
let theme_light = other.theme_light.or_else(|| self.theme_light.clone());
let on_force_close = other.on_force_close.or(self.on_force_close);
let scroll_buffer_size = other.scroll_buffer_size.or(self.scroll_buffer_size);
let copy_command = other.copy_command.or_else(|| self.copy_command.clone());
let copy_clipboard = other.copy_clipboard.or(self.copy_clipboard);
let copy_on_select = other.copy_on_select.or(self.copy_on_select);
let osc8_hyperlinks = other.osc8_hyperlinks.or(self.osc8_hyperlinks);
let scrollback_editor = other
.scrollback_editor
.or_else(|| self.scrollback_editor.clone());
let session_name = other.session_name.or_else(|| self.session_name.clone());
let attach_to_session = other
.attach_to_session
.or_else(|| self.attach_to_session.clone());
let session_serialization = other.session_serialization.or(self.session_serialization);
let serialize_pane_viewport = other
.serialize_pane_viewport
.or(self.serialize_pane_viewport);
let scrollback_lines_to_serialize = other
.scrollback_lines_to_serialize
.or(self.scrollback_lines_to_serialize);
let styled_underlines = other.styled_underlines.or(self.styled_underlines);
let serialization_interval = other.serialization_interval.or(self.serialization_interval);
let disable_session_metadata = other
.disable_session_metadata
.or(self.disable_session_metadata);
let support_kitty_keyboard_protocol = other
.support_kitty_keyboard_protocol
.or(self.support_kitty_keyboard_protocol);
let support_kitty_graphics_protocol = other
.support_kitty_graphics_protocol
.or(self.support_kitty_graphics_protocol);
let web_server = other.web_server.or(self.web_server);
let web_sharing = other.web_sharing.or(self.web_sharing);
let stacked_resize = other.stacked_resize.or(self.stacked_resize);
let stacked_pane_list = other.stacked_pane_list.or(self.stacked_pane_list);
let show_startup_tips = other.show_startup_tips.or(self.show_startup_tips);
let show_release_notes = other.show_release_notes.or(self.show_release_notes);
let advanced_mouse_actions = other.advanced_mouse_actions.or(self.advanced_mouse_actions);
let mouse_scroll_resize = other.mouse_scroll_resize.or(self.mouse_scroll_resize);
let mouse_hover_effects = other.mouse_hover_effects.or(self.mouse_hover_effects);
let mouse_hover_tips = other.mouse_hover_tips.or(self.mouse_hover_tips);
let visual_bell = other.visual_bell.or(self.visual_bell);
let focus_follows_mouse = other.focus_follows_mouse.or(self.focus_follows_mouse);
let mouse_click_through = other.mouse_click_through.or(self.mouse_click_through);
let osc133_command_selection = other
.osc133_command_selection
.or(self.osc133_command_selection);
let word_separators = other
.word_separators
.or_else(|| self.word_separators.clone());
let host_notification_protocol = other
.host_notification_protocol
.or(self.host_notification_protocol);
let web_server_ip = other.web_server_ip.or(self.web_server_ip);
let web_server_port = other.web_server_port.or(self.web_server_port);
let web_server_cert = other
.web_server_cert
.or_else(|| self.web_server_cert.clone());
let web_server_key = other.web_server_key.or_else(|| self.web_server_key.clone());
let enforce_https_for_localhost = other
.enforce_https_for_localhost
.or(self.enforce_https_for_localhost);
let post_command_discovery_hook = other
.post_command_discovery_hook
.or(self.post_command_discovery_hook.clone());
let client_async_worker_tasks = other
.client_async_worker_tasks
.or(self.client_async_worker_tasks);
let nested_session_handling = other
.nested_session_handling
.or(self.nested_session_handling);
let dangerously_enable_paste_buffer_read = other
.dangerously_enable_paste_buffer_read
.or(self.dangerously_enable_paste_buffer_read);
Options {
simplified_ui,
theme,
theme_dark,
theme_light,
default_mode,
default_shell,
default_cwd,
default_layout,
layout_dir,
theme_dir,
mouse_mode,
pane_frames,
pane_frame_style,
mirror_session,
on_force_close,
scroll_buffer_size,
copy_command,
copy_clipboard,
copy_on_select,
osc8_hyperlinks,
scrollback_editor,
session_name,
attach_to_session,
auto_layout,
session_serialization,
serialize_pane_viewport,
scrollback_lines_to_serialize,
styled_underlines,
serialization_interval,
disable_session_metadata,
support_kitty_keyboard_protocol,
support_kitty_graphics_protocol,
web_server,
web_sharing,
stacked_resize,
stacked_pane_list,
show_startup_tips,
show_release_notes,
advanced_mouse_actions,
mouse_scroll_resize,
mouse_hover_effects,
mouse_hover_tips,
visual_bell,
focus_follows_mouse,
mouse_click_through,
osc133_command_selection,
word_separators,
host_notification_protocol,
web_server_ip,
web_server_port,
web_server_cert,
web_server_key,
enforce_https_for_localhost,
post_command_discovery_hook,
client_async_worker_tasks,
nested_session_handling,
dangerously_enable_paste_buffer_read,
}
}
pub fn merge_from_cli(&self, other: Options) -> Options {
let merge_bool = |opt_other: Option<bool>, opt_self: Option<bool>| {
if opt_other.is_some() ^ opt_self.is_some() {
opt_other.or(opt_self)
} else if opt_other.is_some() && opt_self.is_some() {
Some(opt_other.unwrap() ^ opt_self.unwrap())
} else {
None
}
};
let simplified_ui = merge_bool(other.simplified_ui, self.simplified_ui);
let mouse_mode = merge_bool(other.mouse_mode, self.mouse_mode);
let pane_frames = merge_bool(other.pane_frames, self.pane_frames);
let pane_frame_style = other.pane_frame_style.or(self.pane_frame_style);
let auto_layout = merge_bool(other.auto_layout, self.auto_layout);
let mirror_session = merge_bool(other.mirror_session, self.mirror_session);
let session_serialization =
merge_bool(other.session_serialization, self.session_serialization);
let serialize_pane_viewport =
merge_bool(other.serialize_pane_viewport, self.serialize_pane_viewport);
let default_mode = other.default_mode.or(self.default_mode);
let default_shell = other.default_shell.or_else(|| self.default_shell.clone());
let default_cwd = other.default_cwd.or_else(|| self.default_cwd.clone());
let default_layout = other.default_layout.or_else(|| self.default_layout.clone());
let layout_dir = other.layout_dir.or_else(|| self.layout_dir.clone());
let theme_dir = other.theme_dir.or_else(|| self.theme_dir.clone());
let theme = other.theme.or_else(|| self.theme.clone());
let theme_dark = other.theme_dark.or_else(|| self.theme_dark.clone());
let theme_light = other.theme_light.or_else(|| self.theme_light.clone());
let on_force_close = other.on_force_close.or(self.on_force_close);
let scroll_buffer_size = other.scroll_buffer_size.or(self.scroll_buffer_size);
let copy_command = other.copy_command.or_else(|| self.copy_command.clone());
let copy_clipboard = other.copy_clipboard.or(self.copy_clipboard);
let copy_on_select = other.copy_on_select.or(self.copy_on_select);
let osc8_hyperlinks = other.osc8_hyperlinks.or(self.osc8_hyperlinks);
let scrollback_editor = other
.scrollback_editor
.or_else(|| self.scrollback_editor.clone());
let session_name = other.session_name.or_else(|| self.session_name.clone());
let attach_to_session = other
.attach_to_session
.or_else(|| self.attach_to_session.clone());
let scrollback_lines_to_serialize = other
.scrollback_lines_to_serialize
.or_else(|| self.scrollback_lines_to_serialize.clone());
let styled_underlines = other.styled_underlines.or(self.styled_underlines);
let serialization_interval = other.serialization_interval.or(self.serialization_interval);
let disable_session_metadata = other
.disable_session_metadata
.or(self.disable_session_metadata);
let support_kitty_keyboard_protocol = other
.support_kitty_keyboard_protocol
.or(self.support_kitty_keyboard_protocol);
let support_kitty_graphics_protocol = other
.support_kitty_graphics_protocol
.or(self.support_kitty_graphics_protocol);
let web_server = other.web_server.or(self.web_server);
let web_sharing = other.web_sharing.or(self.web_sharing);
let stacked_resize = other.stacked_resize.or(self.stacked_resize);
let stacked_pane_list = other.stacked_pane_list.or(self.stacked_pane_list);
let show_startup_tips = other.show_startup_tips.or(self.show_startup_tips);
let show_release_notes = other.show_release_notes.or(self.show_release_notes);
let advanced_mouse_actions = other.advanced_mouse_actions.or(self.advanced_mouse_actions);
let mouse_scroll_resize = other.mouse_scroll_resize.or(self.mouse_scroll_resize);
let mouse_hover_effects = other.mouse_hover_effects.or(self.mouse_hover_effects);
let mouse_hover_tips = other.mouse_hover_tips.or(self.mouse_hover_tips);
let visual_bell = other.visual_bell.or(self.visual_bell);
let focus_follows_mouse = merge_bool(other.focus_follows_mouse, self.focus_follows_mouse);
let mouse_click_through = merge_bool(other.mouse_click_through, self.mouse_click_through);
let osc133_command_selection = other
.osc133_command_selection
.or(self.osc133_command_selection);
let word_separators = other
.word_separators
.or_else(|| self.word_separators.clone());
let host_notification_protocol = other
.host_notification_protocol
.or(self.host_notification_protocol);
let web_server_ip = other.web_server_ip.or(self.web_server_ip);
let web_server_port = other.web_server_port.or(self.web_server_port);
let web_server_cert = other
.web_server_cert
.or_else(|| self.web_server_cert.clone());
let web_server_key = other.web_server_key.or_else(|| self.web_server_key.clone());
let enforce_https_for_localhost = other
.enforce_https_for_localhost
.or(self.enforce_https_for_localhost);
let post_command_discovery_hook = other
.post_command_discovery_hook
.or_else(|| self.post_command_discovery_hook.clone());
let client_async_worker_tasks = other
.client_async_worker_tasks
.or(self.client_async_worker_tasks);
let nested_session_handling = other
.nested_session_handling
.or(self.nested_session_handling);
let dangerously_enable_paste_buffer_read = other
.dangerously_enable_paste_buffer_read
.or(self.dangerously_enable_paste_buffer_read);
Options {
simplified_ui,
theme,
theme_dark,
theme_light,
default_mode,
default_shell,
default_cwd,
default_layout,
layout_dir,
theme_dir,
mouse_mode,
pane_frames,
pane_frame_style,
mirror_session,
on_force_close,
scroll_buffer_size,
copy_command,
copy_clipboard,
copy_on_select,
osc8_hyperlinks,
scrollback_editor,
session_name,
attach_to_session,
auto_layout,
session_serialization,
serialize_pane_viewport,
scrollback_lines_to_serialize,
styled_underlines,
serialization_interval,
disable_session_metadata,
support_kitty_keyboard_protocol,
support_kitty_graphics_protocol,
web_server,
web_sharing,
stacked_resize,
stacked_pane_list,
show_startup_tips,
show_release_notes,
advanced_mouse_actions,
mouse_scroll_resize,
mouse_hover_effects,
mouse_hover_tips,
visual_bell,
focus_follows_mouse,
mouse_click_through,
osc133_command_selection,
word_separators,
host_notification_protocol,
web_server_ip,
web_server_port,
web_server_cert,
web_server_key,
enforce_https_for_localhost,
post_command_discovery_hook,
client_async_worker_tasks,
nested_session_handling,
dangerously_enable_paste_buffer_read,
}
}
pub fn from_cli(&self, other: Option<Command>) -> Options {
if let Some(Command::Options(options)) = other {
Options::merge_from_cli(self, options.into())
} else {
self.to_owned()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pane_frame_style_from_str_accepts_all_variants() {
assert_eq!(
"full".parse::<PaneFrameStyle>().unwrap(),
PaneFrameStyle::Full
);
assert_eq!(
"titles".parse::<PaneFrameStyle>().unwrap(),
PaneFrameStyle::Titles
);
assert_eq!(
"none".parse::<PaneFrameStyle>().unwrap(),
PaneFrameStyle::None
);
assert_eq!(
"NONE".parse::<PaneFrameStyle>().unwrap(),
PaneFrameStyle::None
);
assert!("bogus".parse::<PaneFrameStyle>().is_err());
}
#[test]
fn host_notification_protocol_from_str_accepts_all_variants() {
assert_eq!(
"auto".parse::<HostNotificationProtocol>().unwrap(),
HostNotificationProtocol::Auto
);
assert_eq!(
"osc9".parse::<HostNotificationProtocol>().unwrap(),
HostNotificationProtocol::Osc9
);
assert_eq!(
"osc99".parse::<HostNotificationProtocol>().unwrap(),
HostNotificationProtocol::Osc99
);
assert_eq!(
"bell".parse::<HostNotificationProtocol>().unwrap(),
HostNotificationProtocol::Bell
);
assert_eq!(
"off".parse::<HostNotificationProtocol>().unwrap(),
HostNotificationProtocol::Off
);
assert!("bogus".parse::<HostNotificationProtocol>().is_err());
}
#[test]
fn every_host_notification_protocol_variant_stringifies_back_to_itself() {
for variant in [
HostNotificationProtocol::Auto,
HostNotificationProtocol::Osc9,
HostNotificationProtocol::Osc99,
HostNotificationProtocol::Bell,
HostNotificationProtocol::Off,
] {
assert_eq!(
variant
.as_str()
.parse::<HostNotificationProtocol>()
.unwrap(),
variant
);
}
}
#[test]
fn the_host_notification_protocol_defaults_to_auto() {
assert_eq!(
HostNotificationProtocol::default(),
HostNotificationProtocol::Auto
);
}
#[test]
fn a_configured_host_notification_protocol_is_overridden_by_the_merged_in_one() {
let config = Options {
host_notification_protocol: Some(HostNotificationProtocol::Osc9),
..Default::default()
};
let layout = Options {
host_notification_protocol: Some(HostNotificationProtocol::Bell),
..Default::default()
};
assert_eq!(
config.merge(layout).host_notification_protocol,
Some(HostNotificationProtocol::Bell)
);
}
#[test]
fn an_unset_host_notification_protocol_does_not_clobber_the_configured_one() {
let config = Options {
host_notification_protocol: Some(HostNotificationProtocol::Osc9),
..Default::default()
};
assert_eq!(
config.merge(Options::default()).host_notification_protocol,
Some(HostNotificationProtocol::Osc9)
);
}
#[test]
fn a_host_notification_protocol_unset_everywhere_stays_unset() {
assert_eq!(
Options::default()
.merge(Options::default())
.host_notification_protocol,
None
);
assert_eq!(
Options::default()
.merge_from_cli(Options::default())
.host_notification_protocol,
None
);
}
#[test]
fn a_host_notification_protocol_given_on_the_command_line_wins() {
let config = Options {
host_notification_protocol: Some(HostNotificationProtocol::Osc9),
..Default::default()
};
let cli = Options {
host_notification_protocol: Some(HostNotificationProtocol::Off),
..Default::default()
};
assert_eq!(
config.merge_from_cli(cli).host_notification_protocol,
Some(HostNotificationProtocol::Off)
);
}
#[test]
fn a_host_notification_protocol_absent_from_the_command_line_keeps_the_configured_one() {
let config = Options {
host_notification_protocol: Some(HostNotificationProtocol::Osc99),
..Default::default()
};
assert_eq!(
config
.merge_from_cli(Options::default())
.host_notification_protocol,
Some(HostNotificationProtocol::Osc99),
"the option is carried over verbatim, not toggled like the boolean options are"
);
}
}