1use crate::cli::Command;
3use crate::data::{InputMode, WebSharing};
4use clap::{Args, ValueEnum};
5use serde::{Deserialize, Serialize};
6use std::path::PathBuf;
7use std::str::FromStr;
8
9use std::net::IpAddr;
10
11pub const DEFAULT_WORD_SEPARATORS: &str = "[]{}<>()";
12
13#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize, ValueEnum)]
14pub enum OnForceClose {
15 #[serde(alias = "quit")]
16 Quit,
17 #[serde(alias = "detach")]
18 Detach,
19}
20
21#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ValueEnum)]
22pub enum NestedSessionHandling {
23 #[serde(alias = "ask")]
24 Ask,
25 #[serde(alias = "fullscreen")]
26 Fullscreen,
27 #[serde(alias = "descend")]
28 Descend,
29 #[serde(alias = "never")]
30 Never,
31}
32
33impl Default for NestedSessionHandling {
34 fn default() -> Self {
35 Self::Ask
36 }
37}
38
39impl FromStr for NestedSessionHandling {
40 type Err = String;
41 fn from_str(s: &str) -> Result<Self, Self::Err> {
42 match s {
43 "Ask" | "ask" => Ok(Self::Ask),
44 "Fullscreen" | "fullscreen" => Ok(Self::Fullscreen),
45 "Descend" | "descend" => Ok(Self::Descend),
46 "Never" | "never" => Ok(Self::Never),
47 _ => Err(format!("No such nested_session_handling: {}", s)),
48 }
49 }
50}
51
52impl Default for OnForceClose {
53 fn default() -> Self {
54 Self::Detach
55 }
56}
57
58impl FromStr for OnForceClose {
59 type Err = Box<dyn std::error::Error>;
60
61 fn from_str(s: &str) -> Result<Self, Self::Err> {
62 match s {
63 "quit" => Ok(Self::Quit),
64 "detach" => Ok(Self::Detach),
65 e => Err(e.to_string().into()),
66 }
67 }
68}
69
70#[derive(ValueEnum, Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
71#[serde(rename_all = "lowercase")]
72pub enum PaneFrameStyle {
73 Full,
74 Titles,
75 None,
76}
77
78impl Default for PaneFrameStyle {
79 fn default() -> Self {
80 PaneFrameStyle::Titles
81 }
82}
83
84impl PaneFrameStyle {
85 pub fn draws_full_frames(&self) -> bool {
86 matches!(self, PaneFrameStyle::Full)
87 }
88
89 pub fn draws_titles(&self) -> bool {
90 matches!(self, PaneFrameStyle::Titles)
91 }
92
93 pub fn from_options(options: &Options) -> Self {
94 if options.pane_frames == Some(false) {
95 return PaneFrameStyle::None;
96 }
97 match options.pane_frame_style {
98 Some(PaneFrameStyle::Full) => PaneFrameStyle::Full,
99 _ => PaneFrameStyle::Titles,
100 }
101 }
102}
103
104impl FromStr for PaneFrameStyle {
105 type Err = Box<dyn std::error::Error>;
106 fn from_str(s: &str) -> Result<Self, Self::Err> {
107 match s.trim().to_lowercase().as_str() {
108 "full" => Ok(PaneFrameStyle::Full),
109 "titles" => Ok(PaneFrameStyle::Titles),
110 "none" => Ok(PaneFrameStyle::None),
111 e => Err(format!(
112 "Unknown pane frame style: '{}' (expected 'full', 'titles' or 'none')",
113 e
114 )
115 .into()),
116 }
117 }
118}
119
120#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, Args)]
121pub struct Options {
126 #[clap(long, value_parser)]
129 #[serde(default)]
130 pub simplified_ui: Option<bool>,
131 #[clap(long, value_parser)]
133 pub theme: Option<String>,
134 #[clap(long, value_parser)]
138 pub theme_dark: Option<String>,
139 #[clap(long, value_parser)]
143 pub theme_light: Option<String>,
144 #[clap(long, value_enum, hide_possible_values = true, value_parser)]
146 pub default_mode: Option<InputMode>,
147 #[clap(long, value_parser)]
149 pub default_shell: Option<PathBuf>,
150 #[clap(long, value_parser)]
152 pub default_cwd: Option<PathBuf>,
153 #[clap(long, value_parser)]
155 pub default_layout: Option<PathBuf>,
156 #[clap(long, value_parser)]
159 pub layout_dir: Option<PathBuf>,
160 #[clap(long, value_parser)]
163 pub theme_dir: Option<PathBuf>,
164 #[clap(long, value_parser)]
165 #[serde(default)]
166 pub mouse_mode: Option<bool>,
169 #[clap(long, value_parser)]
170 #[serde(default)]
171 pub pane_frames: Option<bool>,
173 #[clap(long, value_enum, hide_possible_values = true, value_parser)]
174 #[serde(default)]
175 pub pane_frame_style: Option<PaneFrameStyle>,
176 #[clap(long, value_parser)]
177 #[serde(default)]
178 pub mirror_session: Option<bool>,
180 #[clap(long, value_enum, hide_possible_values = true, value_parser)]
182 pub on_force_close: Option<OnForceClose>,
183 #[clap(long, value_parser)]
184 pub scroll_buffer_size: Option<usize>,
185
186 #[clap(long, value_parser)]
188 #[serde(default)]
189 pub copy_command: Option<String>,
190
191 #[clap(
193 long,
194 value_enum,
195 ignore_case = true,
196 conflicts_with = "copy_command",
197 value_parser
198 )]
199 #[serde(default)]
200 pub copy_clipboard: Option<Clipboard>,
201
202 #[clap(long, value_parser)]
204 #[serde(default)]
205 pub copy_on_select: Option<bool>,
206
207 #[clap(long, value_parser)]
209 #[serde(default)]
210 pub osc8_hyperlinks: Option<bool>,
211
212 #[clap(long, value_parser)]
214 pub scrollback_editor: Option<PathBuf>,
215
216 #[clap(long, value_parser)]
218 #[serde(default)]
219 pub session_name: Option<String>,
220
221 #[clap(long, value_parser)]
223 #[serde(default)]
224 pub attach_to_session: Option<bool>,
225
226 #[clap(long, value_parser)]
228 #[serde(default)]
229 pub auto_layout: Option<bool>,
230
231 #[clap(long, value_parser)]
234 #[serde(default)]
235 pub session_serialization: Option<bool>,
236
237 #[clap(long, value_parser)]
239 #[serde(default)]
240 pub serialize_pane_viewport: Option<bool>,
241
242 #[clap(long, value_parser)]
246 #[serde(default)]
247 pub scrollback_lines_to_serialize: Option<usize>,
248
249 #[clap(long, value_parser)]
251 #[serde(default)]
252 pub styled_underlines: Option<bool>,
253
254 #[clap(long, value_parser)]
256 pub serialization_interval: Option<u64>,
257
258 #[clap(long, value_parser)]
260 pub disable_session_metadata: Option<bool>,
261
262 #[clap(long, value_parser)]
265 #[serde(default)]
266 pub support_kitty_keyboard_protocol: Option<bool>,
267
268 #[clap(long, value_parser)]
271 #[serde(default)]
272 pub support_kitty_graphics_protocol: Option<bool>,
273
274 #[clap(long, value_parser)]
287 #[serde(default)]
288 pub web_server: Option<bool>,
289
290 #[clap(long, value_parser)]
303 #[serde(default)]
304 pub web_sharing: Option<WebSharing>,
305
306 #[clap(long, value_parser)]
309 #[serde(default)]
310 pub stacked_resize: Option<bool>,
311
312 #[clap(long, value_parser)]
313 #[serde(default)]
314 pub stacked_pane_list: Option<bool>,
315
316 #[clap(long, value_parser)]
319 #[serde(default)]
320 pub show_startup_tips: Option<bool>,
321
322 #[clap(long, value_parser)]
325 #[serde(default)]
326 pub show_release_notes: Option<bool>,
327
328 #[clap(long, value_parser)]
331 #[serde(default)]
332 pub advanced_mouse_actions: Option<bool>,
333
334 #[clap(long, value_parser)]
337 #[serde(default)]
338 pub mouse_scroll_resize: Option<bool>,
339
340 #[clap(long, value_parser)]
343 #[serde(default)]
344 pub mouse_hover_effects: Option<bool>,
345
346 #[clap(long, value_parser)]
349 #[serde(default)]
350 pub mouse_hover_tips: Option<bool>,
351
352 #[clap(long, value_parser)]
355 #[serde(default)]
356 pub visual_bell: Option<bool>,
357
358 #[clap(long, value_parser)]
361 #[serde(default)]
362 pub focus_follows_mouse: Option<bool>,
363
364 #[clap(long, value_parser)]
367 #[serde(default)]
368 pub mouse_click_through: Option<bool>,
369
370 #[clap(long, value_parser)]
374 #[serde(default)]
375 pub osc133_command_selection: Option<bool>,
376
377 #[clap(long, value_parser)]
381 #[serde(default)]
382 pub word_separators: Option<String>,
383
384 #[clap(long, value_parser)]
385 #[serde(default)]
386 pub host_notification_protocol: Option<HostNotificationProtocol>,
387
388 pub web_server_ip: Option<IpAddr>,
391 pub web_server_port: Option<u16>,
392 pub web_server_cert: Option<PathBuf>,
393 pub web_server_key: Option<PathBuf>,
394 pub enforce_https_for_localhost: Option<bool>,
395 #[clap(long, value_parser)]
398 pub post_command_discovery_hook: Option<String>,
399
400 #[clap(long)]
406 pub client_async_worker_tasks: Option<usize>,
407
408 #[clap(long, value_enum, hide_possible_values = true, value_parser)]
411 #[serde(default)]
412 pub nested_session_handling: Option<NestedSessionHandling>,
413
414 #[clap(long, value_parser)]
415 #[serde(default)]
416 pub dangerously_enable_paste_buffer_read: Option<bool>,
417}
418
419#[derive(ValueEnum, Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
420pub enum Clipboard {
421 #[serde(alias = "system")]
422 System,
423 #[serde(alias = "primary")]
424 Primary,
425}
426
427impl Default for Clipboard {
428 fn default() -> Self {
429 Self::System
430 }
431}
432
433#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ValueEnum)]
434pub enum HostNotificationProtocol {
435 #[serde(alias = "auto")]
436 Auto,
437 #[serde(alias = "osc9")]
438 Osc9,
439 #[serde(alias = "osc99")]
440 Osc99,
441 #[serde(alias = "bell")]
442 Bell,
443 #[serde(alias = "off")]
444 Off,
445}
446
447impl Default for HostNotificationProtocol {
448 fn default() -> Self {
449 Self::Auto
450 }
451}
452
453impl HostNotificationProtocol {
454 pub fn as_str(&self) -> &'static str {
455 match self {
456 Self::Auto => "auto",
457 Self::Osc9 => "osc9",
458 Self::Osc99 => "osc99",
459 Self::Bell => "bell",
460 Self::Off => "off",
461 }
462 }
463}
464
465impl FromStr for HostNotificationProtocol {
466 type Err = String;
467 fn from_str(s: &str) -> Result<Self, Self::Err> {
468 match s {
469 "Auto" | "auto" => Ok(Self::Auto),
470 "Osc9" | "osc9" => Ok(Self::Osc9),
471 "Osc99" | "osc99" => Ok(Self::Osc99),
472 "Bell" | "bell" => Ok(Self::Bell),
473 "Off" | "off" => Ok(Self::Off),
474 _ => Err(format!("No such host_notification_protocol: {}", s)),
475 }
476 }
477}
478
479impl FromStr for Clipboard {
480 type Err = String;
481 fn from_str(s: &str) -> Result<Self, Self::Err> {
482 match s {
483 "System" | "system" => Ok(Self::System),
484 "Primary" | "primary" => Ok(Self::Primary),
485 _ => Err(format!("No such clipboard: {}", s)),
486 }
487 }
488}
489
490impl Options {
491 pub fn from_yaml(from_yaml: Option<Options>) -> Options {
492 if let Some(opts) = from_yaml {
493 opts
494 } else {
495 Options::default()
496 }
497 }
498 pub fn merge(&self, other: Options) -> Options {
502 let mouse_mode = other.mouse_mode.or(self.mouse_mode);
503 let pane_frames = other.pane_frames.or(self.pane_frames);
504 let pane_frame_style = other.pane_frame_style.or(self.pane_frame_style);
505 let auto_layout = other.auto_layout.or(self.auto_layout);
506 let mirror_session = other.mirror_session.or(self.mirror_session);
507 let simplified_ui = other.simplified_ui.or(self.simplified_ui);
508 let default_mode = other.default_mode.or(self.default_mode);
509 let default_shell = other.default_shell.or_else(|| self.default_shell.clone());
510 let default_cwd = other.default_cwd.or_else(|| self.default_cwd.clone());
511 let default_layout = other.default_layout.or_else(|| self.default_layout.clone());
512 let layout_dir = other.layout_dir.or_else(|| self.layout_dir.clone());
513 let theme_dir = other.theme_dir.or_else(|| self.theme_dir.clone());
514 let theme = other.theme.or_else(|| self.theme.clone());
515 let theme_dark = other.theme_dark.or_else(|| self.theme_dark.clone());
516 let theme_light = other.theme_light.or_else(|| self.theme_light.clone());
517 let on_force_close = other.on_force_close.or(self.on_force_close);
518 let scroll_buffer_size = other.scroll_buffer_size.or(self.scroll_buffer_size);
519 let copy_command = other.copy_command.or_else(|| self.copy_command.clone());
520 let copy_clipboard = other.copy_clipboard.or(self.copy_clipboard);
521 let copy_on_select = other.copy_on_select.or(self.copy_on_select);
522 let osc8_hyperlinks = other.osc8_hyperlinks.or(self.osc8_hyperlinks);
523 let scrollback_editor = other
524 .scrollback_editor
525 .or_else(|| self.scrollback_editor.clone());
526 let session_name = other.session_name.or_else(|| self.session_name.clone());
527 let attach_to_session = other
528 .attach_to_session
529 .or_else(|| self.attach_to_session.clone());
530 let session_serialization = other.session_serialization.or(self.session_serialization);
531 let serialize_pane_viewport = other
532 .serialize_pane_viewport
533 .or(self.serialize_pane_viewport);
534 let scrollback_lines_to_serialize = other
535 .scrollback_lines_to_serialize
536 .or(self.scrollback_lines_to_serialize);
537 let styled_underlines = other.styled_underlines.or(self.styled_underlines);
538 let serialization_interval = other.serialization_interval.or(self.serialization_interval);
539 let disable_session_metadata = other
540 .disable_session_metadata
541 .or(self.disable_session_metadata);
542 let support_kitty_keyboard_protocol = other
543 .support_kitty_keyboard_protocol
544 .or(self.support_kitty_keyboard_protocol);
545 let support_kitty_graphics_protocol = other
546 .support_kitty_graphics_protocol
547 .or(self.support_kitty_graphics_protocol);
548 let web_server = other.web_server.or(self.web_server);
549 let web_sharing = other.web_sharing.or(self.web_sharing);
550 let stacked_resize = other.stacked_resize.or(self.stacked_resize);
551 let stacked_pane_list = other.stacked_pane_list.or(self.stacked_pane_list);
552 let show_startup_tips = other.show_startup_tips.or(self.show_startup_tips);
553 let show_release_notes = other.show_release_notes.or(self.show_release_notes);
554 let advanced_mouse_actions = other.advanced_mouse_actions.or(self.advanced_mouse_actions);
555 let mouse_scroll_resize = other.mouse_scroll_resize.or(self.mouse_scroll_resize);
556 let mouse_hover_effects = other.mouse_hover_effects.or(self.mouse_hover_effects);
557 let mouse_hover_tips = other.mouse_hover_tips.or(self.mouse_hover_tips);
558 let visual_bell = other.visual_bell.or(self.visual_bell);
559 let focus_follows_mouse = other.focus_follows_mouse.or(self.focus_follows_mouse);
560 let mouse_click_through = other.mouse_click_through.or(self.mouse_click_through);
561 let osc133_command_selection = other
562 .osc133_command_selection
563 .or(self.osc133_command_selection);
564 let word_separators = other
565 .word_separators
566 .or_else(|| self.word_separators.clone());
567 let host_notification_protocol = other
568 .host_notification_protocol
569 .or(self.host_notification_protocol);
570 let web_server_ip = other.web_server_ip.or(self.web_server_ip);
571 let web_server_port = other.web_server_port.or(self.web_server_port);
572 let web_server_cert = other
573 .web_server_cert
574 .or_else(|| self.web_server_cert.clone());
575 let web_server_key = other.web_server_key.or_else(|| self.web_server_key.clone());
576 let enforce_https_for_localhost = other
577 .enforce_https_for_localhost
578 .or(self.enforce_https_for_localhost);
579 let post_command_discovery_hook = other
580 .post_command_discovery_hook
581 .or(self.post_command_discovery_hook.clone());
582 let client_async_worker_tasks = other
583 .client_async_worker_tasks
584 .or(self.client_async_worker_tasks);
585 let nested_session_handling = other
586 .nested_session_handling
587 .or(self.nested_session_handling);
588 let dangerously_enable_paste_buffer_read = other
589 .dangerously_enable_paste_buffer_read
590 .or(self.dangerously_enable_paste_buffer_read);
591
592 Options {
593 simplified_ui,
594 theme,
595 theme_dark,
596 theme_light,
597 default_mode,
598 default_shell,
599 default_cwd,
600 default_layout,
601 layout_dir,
602 theme_dir,
603 mouse_mode,
604 pane_frames,
605 pane_frame_style,
606 mirror_session,
607 on_force_close,
608 scroll_buffer_size,
609 copy_command,
610 copy_clipboard,
611 copy_on_select,
612 osc8_hyperlinks,
613 scrollback_editor,
614 session_name,
615 attach_to_session,
616 auto_layout,
617 session_serialization,
618 serialize_pane_viewport,
619 scrollback_lines_to_serialize,
620 styled_underlines,
621 serialization_interval,
622 disable_session_metadata,
623 support_kitty_keyboard_protocol,
624 support_kitty_graphics_protocol,
625 web_server,
626 web_sharing,
627 stacked_resize,
628 stacked_pane_list,
629 show_startup_tips,
630 show_release_notes,
631 advanced_mouse_actions,
632 mouse_scroll_resize,
633 mouse_hover_effects,
634 mouse_hover_tips,
635 visual_bell,
636 focus_follows_mouse,
637 mouse_click_through,
638 osc133_command_selection,
639 word_separators,
640 host_notification_protocol,
641 web_server_ip,
642 web_server_port,
643 web_server_cert,
644 web_server_key,
645 enforce_https_for_localhost,
646 post_command_discovery_hook,
647 client_async_worker_tasks,
648 nested_session_handling,
649 dangerously_enable_paste_buffer_read,
650 }
651 }
652
653 pub fn merge_from_cli(&self, other: Options) -> Options {
658 let merge_bool = |opt_other: Option<bool>, opt_self: Option<bool>| {
659 if opt_other.is_some() ^ opt_self.is_some() {
660 opt_other.or(opt_self)
661 } else if opt_other.is_some() && opt_self.is_some() {
662 Some(opt_other.unwrap() ^ opt_self.unwrap())
663 } else {
664 None
665 }
666 };
667
668 let simplified_ui = merge_bool(other.simplified_ui, self.simplified_ui);
669 let mouse_mode = merge_bool(other.mouse_mode, self.mouse_mode);
670 let pane_frames = merge_bool(other.pane_frames, self.pane_frames);
671 let pane_frame_style = other.pane_frame_style.or(self.pane_frame_style);
672 let auto_layout = merge_bool(other.auto_layout, self.auto_layout);
673 let mirror_session = merge_bool(other.mirror_session, self.mirror_session);
674 let session_serialization =
675 merge_bool(other.session_serialization, self.session_serialization);
676 let serialize_pane_viewport =
677 merge_bool(other.serialize_pane_viewport, self.serialize_pane_viewport);
678
679 let default_mode = other.default_mode.or(self.default_mode);
680 let default_shell = other.default_shell.or_else(|| self.default_shell.clone());
681 let default_cwd = other.default_cwd.or_else(|| self.default_cwd.clone());
682 let default_layout = other.default_layout.or_else(|| self.default_layout.clone());
683 let layout_dir = other.layout_dir.or_else(|| self.layout_dir.clone());
684 let theme_dir = other.theme_dir.or_else(|| self.theme_dir.clone());
685 let theme = other.theme.or_else(|| self.theme.clone());
686 let theme_dark = other.theme_dark.or_else(|| self.theme_dark.clone());
687 let theme_light = other.theme_light.or_else(|| self.theme_light.clone());
688 let on_force_close = other.on_force_close.or(self.on_force_close);
689 let scroll_buffer_size = other.scroll_buffer_size.or(self.scroll_buffer_size);
690 let copy_command = other.copy_command.or_else(|| self.copy_command.clone());
691 let copy_clipboard = other.copy_clipboard.or(self.copy_clipboard);
692 let copy_on_select = other.copy_on_select.or(self.copy_on_select);
693 let osc8_hyperlinks = other.osc8_hyperlinks.or(self.osc8_hyperlinks);
694 let scrollback_editor = other
695 .scrollback_editor
696 .or_else(|| self.scrollback_editor.clone());
697 let session_name = other.session_name.or_else(|| self.session_name.clone());
698 let attach_to_session = other
699 .attach_to_session
700 .or_else(|| self.attach_to_session.clone());
701 let scrollback_lines_to_serialize = other
702 .scrollback_lines_to_serialize
703 .or_else(|| self.scrollback_lines_to_serialize.clone());
704 let styled_underlines = other.styled_underlines.or(self.styled_underlines);
705 let serialization_interval = other.serialization_interval.or(self.serialization_interval);
706 let disable_session_metadata = other
707 .disable_session_metadata
708 .or(self.disable_session_metadata);
709 let support_kitty_keyboard_protocol = other
710 .support_kitty_keyboard_protocol
711 .or(self.support_kitty_keyboard_protocol);
712 let support_kitty_graphics_protocol = other
713 .support_kitty_graphics_protocol
714 .or(self.support_kitty_graphics_protocol);
715 let web_server = other.web_server.or(self.web_server);
716 let web_sharing = other.web_sharing.or(self.web_sharing);
717 let stacked_resize = other.stacked_resize.or(self.stacked_resize);
718 let stacked_pane_list = other.stacked_pane_list.or(self.stacked_pane_list);
719 let show_startup_tips = other.show_startup_tips.or(self.show_startup_tips);
720 let show_release_notes = other.show_release_notes.or(self.show_release_notes);
721 let advanced_mouse_actions = other.advanced_mouse_actions.or(self.advanced_mouse_actions);
722 let mouse_scroll_resize = other.mouse_scroll_resize.or(self.mouse_scroll_resize);
723 let mouse_hover_effects = other.mouse_hover_effects.or(self.mouse_hover_effects);
724 let mouse_hover_tips = other.mouse_hover_tips.or(self.mouse_hover_tips);
725 let visual_bell = other.visual_bell.or(self.visual_bell);
726 let focus_follows_mouse = merge_bool(other.focus_follows_mouse, self.focus_follows_mouse);
727 let mouse_click_through = merge_bool(other.mouse_click_through, self.mouse_click_through);
728 let osc133_command_selection = other
729 .osc133_command_selection
730 .or(self.osc133_command_selection);
731 let word_separators = other
732 .word_separators
733 .or_else(|| self.word_separators.clone());
734 let host_notification_protocol = other
735 .host_notification_protocol
736 .or(self.host_notification_protocol);
737 let web_server_ip = other.web_server_ip.or(self.web_server_ip);
738 let web_server_port = other.web_server_port.or(self.web_server_port);
739 let web_server_cert = other
740 .web_server_cert
741 .or_else(|| self.web_server_cert.clone());
742 let web_server_key = other.web_server_key.or_else(|| self.web_server_key.clone());
743 let enforce_https_for_localhost = other
744 .enforce_https_for_localhost
745 .or(self.enforce_https_for_localhost);
746 let post_command_discovery_hook = other
747 .post_command_discovery_hook
748 .or_else(|| self.post_command_discovery_hook.clone());
749 let client_async_worker_tasks = other
750 .client_async_worker_tasks
751 .or(self.client_async_worker_tasks);
752 let nested_session_handling = other
753 .nested_session_handling
754 .or(self.nested_session_handling);
755 let dangerously_enable_paste_buffer_read = other
756 .dangerously_enable_paste_buffer_read
757 .or(self.dangerously_enable_paste_buffer_read);
758
759 Options {
760 simplified_ui,
761 theme,
762 theme_dark,
763 theme_light,
764 default_mode,
765 default_shell,
766 default_cwd,
767 default_layout,
768 layout_dir,
769 theme_dir,
770 mouse_mode,
771 pane_frames,
772 pane_frame_style,
773 mirror_session,
774 on_force_close,
775 scroll_buffer_size,
776 copy_command,
777 copy_clipboard,
778 copy_on_select,
779 osc8_hyperlinks,
780 scrollback_editor,
781 session_name,
782 attach_to_session,
783 auto_layout,
784 session_serialization,
785 serialize_pane_viewport,
786 scrollback_lines_to_serialize,
787 styled_underlines,
788 serialization_interval,
789 disable_session_metadata,
790 support_kitty_keyboard_protocol,
791 support_kitty_graphics_protocol,
792 web_server,
793 web_sharing,
794 stacked_resize,
795 stacked_pane_list,
796 show_startup_tips,
797 show_release_notes,
798 advanced_mouse_actions,
799 mouse_scroll_resize,
800 mouse_hover_effects,
801 mouse_hover_tips,
802 visual_bell,
803 focus_follows_mouse,
804 mouse_click_through,
805 osc133_command_selection,
806 word_separators,
807 host_notification_protocol,
808 web_server_ip,
809 web_server_port,
810 web_server_cert,
811 web_server_key,
812 enforce_https_for_localhost,
813 post_command_discovery_hook,
814 client_async_worker_tasks,
815 nested_session_handling,
816 dangerously_enable_paste_buffer_read,
817 }
818 }
819
820 pub fn from_cli(&self, other: Option<Command>) -> Options {
821 if let Some(Command::Options(options)) = other {
822 Options::merge_from_cli(self, options.into())
823 } else {
824 self.to_owned()
825 }
826 }
827}
828
829#[cfg(test)]
830mod tests {
831 use super::*;
832
833 #[test]
834 fn pane_frame_style_from_str_accepts_all_variants() {
835 assert_eq!(
836 "full".parse::<PaneFrameStyle>().unwrap(),
837 PaneFrameStyle::Full
838 );
839 assert_eq!(
840 "titles".parse::<PaneFrameStyle>().unwrap(),
841 PaneFrameStyle::Titles
842 );
843 assert_eq!(
844 "none".parse::<PaneFrameStyle>().unwrap(),
845 PaneFrameStyle::None
846 );
847 assert_eq!(
848 "NONE".parse::<PaneFrameStyle>().unwrap(),
849 PaneFrameStyle::None
850 );
851 assert!("bogus".parse::<PaneFrameStyle>().is_err());
852 }
853
854 #[test]
855 fn host_notification_protocol_from_str_accepts_all_variants() {
856 assert_eq!(
857 "auto".parse::<HostNotificationProtocol>().unwrap(),
858 HostNotificationProtocol::Auto
859 );
860 assert_eq!(
861 "osc9".parse::<HostNotificationProtocol>().unwrap(),
862 HostNotificationProtocol::Osc9
863 );
864 assert_eq!(
865 "osc99".parse::<HostNotificationProtocol>().unwrap(),
866 HostNotificationProtocol::Osc99
867 );
868 assert_eq!(
869 "bell".parse::<HostNotificationProtocol>().unwrap(),
870 HostNotificationProtocol::Bell
871 );
872 assert_eq!(
873 "off".parse::<HostNotificationProtocol>().unwrap(),
874 HostNotificationProtocol::Off
875 );
876 assert!("bogus".parse::<HostNotificationProtocol>().is_err());
877 }
878
879 #[test]
880 fn every_host_notification_protocol_variant_stringifies_back_to_itself() {
881 for variant in [
882 HostNotificationProtocol::Auto,
883 HostNotificationProtocol::Osc9,
884 HostNotificationProtocol::Osc99,
885 HostNotificationProtocol::Bell,
886 HostNotificationProtocol::Off,
887 ] {
888 assert_eq!(
889 variant
890 .as_str()
891 .parse::<HostNotificationProtocol>()
892 .unwrap(),
893 variant
894 );
895 }
896 }
897
898 #[test]
899 fn the_host_notification_protocol_defaults_to_auto() {
900 assert_eq!(
901 HostNotificationProtocol::default(),
902 HostNotificationProtocol::Auto
903 );
904 }
905
906 #[test]
907 fn a_configured_host_notification_protocol_is_overridden_by_the_merged_in_one() {
908 let config = Options {
909 host_notification_protocol: Some(HostNotificationProtocol::Osc9),
910 ..Default::default()
911 };
912 let layout = Options {
913 host_notification_protocol: Some(HostNotificationProtocol::Bell),
914 ..Default::default()
915 };
916 assert_eq!(
917 config.merge(layout).host_notification_protocol,
918 Some(HostNotificationProtocol::Bell)
919 );
920 }
921
922 #[test]
923 fn an_unset_host_notification_protocol_does_not_clobber_the_configured_one() {
924 let config = Options {
925 host_notification_protocol: Some(HostNotificationProtocol::Osc9),
926 ..Default::default()
927 };
928 assert_eq!(
929 config.merge(Options::default()).host_notification_protocol,
930 Some(HostNotificationProtocol::Osc9)
931 );
932 }
933
934 #[test]
935 fn a_host_notification_protocol_unset_everywhere_stays_unset() {
936 assert_eq!(
937 Options::default()
938 .merge(Options::default())
939 .host_notification_protocol,
940 None
941 );
942 assert_eq!(
943 Options::default()
944 .merge_from_cli(Options::default())
945 .host_notification_protocol,
946 None
947 );
948 }
949
950 #[test]
951 fn a_host_notification_protocol_given_on_the_command_line_wins() {
952 let config = Options {
953 host_notification_protocol: Some(HostNotificationProtocol::Osc9),
954 ..Default::default()
955 };
956 let cli = Options {
957 host_notification_protocol: Some(HostNotificationProtocol::Off),
958 ..Default::default()
959 };
960 assert_eq!(
961 config.merge_from_cli(cli).host_notification_protocol,
962 Some(HostNotificationProtocol::Off)
963 );
964 }
965
966 #[test]
967 fn a_host_notification_protocol_absent_from_the_command_line_keeps_the_configured_one() {
968 let config = Options {
969 host_notification_protocol: Some(HostNotificationProtocol::Osc99),
970 ..Default::default()
971 };
972 assert_eq!(
973 config
974 .merge_from_cli(Options::default())
975 .host_notification_protocol,
976 Some(HostNotificationProtocol::Osc99),
977 "the option is carried over verbatim, not toggled like the boolean options are"
978 );
979 }
980}