mirror of
https://github.com/nyakang/nyaterm.git
synced 2026-10-03 08:00:54 +00:00
refactor(desktop): encapsulate settings compatibility state
This commit is contained in:
@@ -624,7 +624,7 @@ impl NyaTermApp {
|
||||
let observation_message = build_observation_message(
|
||||
&observation,
|
||||
&state.command,
|
||||
&self.settings.summary.language,
|
||||
&self.settings.summary().language,
|
||||
);
|
||||
let settings = self.ai.settings.config.clone();
|
||||
let terminal_session_id = state.terminal_session_id.clone();
|
||||
|
||||
@@ -199,13 +199,13 @@ impl NyaTermApp {
|
||||
{
|
||||
return;
|
||||
}
|
||||
if self.settings.summary.terminal_low_latency_mode {
|
||||
if self.settings.summary().terminal_low_latency_mode {
|
||||
self.clear_command_suggestion_draft(cx);
|
||||
finish!("low_latency_mode", 0);
|
||||
}
|
||||
if !self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestions_enabled
|
||||
{
|
||||
self.clear_command_suggestion_draft(cx);
|
||||
@@ -294,7 +294,7 @@ impl NyaTermApp {
|
||||
let min_chars_started_at = Instant::now();
|
||||
let min_chars = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestion_min_chars
|
||||
.max(1) as usize;
|
||||
let below_min_chars = terminal_input_tracker_below_min_chars(
|
||||
@@ -421,7 +421,7 @@ impl NyaTermApp {
|
||||
if this.terminal.assist.command_suggestion_search_gen != request_id {
|
||||
return None;
|
||||
}
|
||||
if this.settings.summary.terminal_low_latency_mode {
|
||||
if this.settings.summary().terminal_low_latency_mode {
|
||||
this.hide_command_suggestions_if_present(cx);
|
||||
return None;
|
||||
}
|
||||
@@ -528,7 +528,7 @@ impl NyaTermApp {
|
||||
}
|
||||
if !self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestions_enabled
|
||||
{
|
||||
let hide_started_at = Instant::now();
|
||||
@@ -538,12 +538,12 @@ impl NyaTermApp {
|
||||
}
|
||||
let min_chars = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestion_min_chars
|
||||
.max(1) as usize;
|
||||
let max_chars = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestion_max_chars
|
||||
.max(min_chars as u32) as usize;
|
||||
let pattern_started_at = Instant::now();
|
||||
@@ -599,7 +599,7 @@ impl NyaTermApp {
|
||||
|| self.terminal.assist.command_suggestions_suppressed
|
||||
|| !self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestions_enabled
|
||||
|| get_tracked_command(&self.terminal.assist.command_input_tracker) != request.pattern
|
||||
{
|
||||
|
||||
@@ -36,8 +36,8 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.commands.set_quick_view_mode(mode);
|
||||
self.settings.summary.ui_quick_cmd_view_mode =
|
||||
quick_command_view_mode_setting(mode).to_string();
|
||||
self.settings
|
||||
.set_quick_command_view_mode(quick_command_view_mode_setting(mode).to_string());
|
||||
self.save_quick_command_ui_settings(cx);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.commands.set_quick_sort_mode(mode);
|
||||
self.settings.summary.ui_quick_cmd_sort_mode =
|
||||
quick_command_sort_mode_setting(mode).to_string();
|
||||
self.settings
|
||||
.set_quick_command_sort_mode(quick_command_sort_mode_setting(mode).to_string());
|
||||
self.save_quick_command_ui_settings(cx);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ impl NyaTermApp {
|
||||
self.runtime.config_dir(),
|
||||
self.runtime.portable_key_path().map(ToOwned::to_owned),
|
||||
)
|
||||
.and_then(|store| store.save_quick_command_ui_settings(&self.settings.summary))
|
||||
.and_then(|store| store.save_quick_command_ui_settings(self.settings.summary()))
|
||||
{
|
||||
Ok(settings) => {
|
||||
self.apply_gpui_settings(settings);
|
||||
|
||||
@@ -40,7 +40,7 @@ impl Render for ConnectionEditorWindow {
|
||||
(
|
||||
app.theme_palette(),
|
||||
app.gpui_ui_font_family(),
|
||||
app.settings.summary.ui_font_size.clamp(12, 24) as f32,
|
||||
app.settings.summary().ui_font_size.clamp(12, 24) as f32,
|
||||
app.connection_editor_title().to_string(),
|
||||
)
|
||||
});
|
||||
|
||||
@@ -168,8 +168,8 @@ impl NyaTermApp {
|
||||
|
||||
pub(in crate::features) fn cycle_connection_sort_mode(&mut self, cx: &mut Context<Self>) {
|
||||
let sort_mode = self.connection_state.cycle_list_sort_mode();
|
||||
self.settings.summary.ui_saved_connections_sort_mode =
|
||||
sort_mode.persistence_id().to_string();
|
||||
self.settings
|
||||
.set_saved_connections_sort_mode(sort_mode.persistence_id().to_string());
|
||||
self.persist_ui_layout();
|
||||
self.terminal.view.status = format!("connections sorted by {}", sort_mode.label());
|
||||
cx.notify();
|
||||
|
||||
@@ -25,6 +25,6 @@ pub(in crate::features) use markdown::{
|
||||
|
||||
impl NyaTermApp {
|
||||
pub(in crate::features) fn tr(&self, key: &'static str) -> &'static str {
|
||||
crate::i18n::text(&self.settings.summary.language, key)
|
||||
crate::i18n::text(&self.settings.summary().language, key)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let unlocked =
|
||||
self.settings.summary.has_master_password && self.security.secrets_unlocked();
|
||||
self.settings.summary().has_master_password && self.security.secrets_unlocked();
|
||||
let palette = self.theme_palette();
|
||||
div()
|
||||
.id(SharedString::from("security-secrets-toggle"))
|
||||
@@ -81,7 +81,7 @@ impl NyaTermApp {
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
if this.security_secrets_locked() {
|
||||
this.open_security_unlock_prompt(window, cx);
|
||||
} else if this.settings.summary.has_master_password {
|
||||
} else if this.settings.summary().has_master_password {
|
||||
this.lock_security_secrets(cx);
|
||||
} else {
|
||||
this.open_security_unlock_prompt(window, cx);
|
||||
|
||||
@@ -50,7 +50,7 @@ impl NyaTermApp {
|
||||
NavItem::AiAssistant => self.ai_assistant_panel(cx).into_any_element(),
|
||||
NavItem::ActiveSessions => self.active_sessions_panel(cx).into_any_element(),
|
||||
NavItem::CommandHistory => self.command_history_panel(cx).into_any_element(),
|
||||
NavItem::Stats if self.settings.summary.ui_show_remote_stats => {
|
||||
NavItem::Stats if self.settings.summary().ui_show_remote_stats => {
|
||||
self.stats_view(cx).into_any_element()
|
||||
}
|
||||
NavItem::Stats => crate::features::inspector::disabled_inspector_panel(
|
||||
@@ -58,7 +58,7 @@ impl NyaTermApp {
|
||||
self.tr("panel.resourceMonitorDisabled"),
|
||||
)
|
||||
.into_any_element(),
|
||||
NavItem::Processes if self.settings.summary.ui_show_process_manager => {
|
||||
NavItem::Processes if self.settings.summary().ui_show_process_manager => {
|
||||
self.processes_view(cx).into_any_element()
|
||||
}
|
||||
NavItem::Processes => crate::features::inspector::disabled_inspector_panel(
|
||||
@@ -66,7 +66,7 @@ impl NyaTermApp {
|
||||
self.tr("processManager.disabled"),
|
||||
)
|
||||
.into_any_element(),
|
||||
NavItem::Docker if self.settings.summary.ui_show_docker_manager => {
|
||||
NavItem::Docker if self.settings.summary().ui_show_docker_manager => {
|
||||
self.docker_view(cx).into_any_element()
|
||||
}
|
||||
NavItem::Docker => crate::features::inspector::disabled_inspector_panel(
|
||||
|
||||
@@ -30,7 +30,7 @@ impl NyaTermApp {
|
||||
let compact_layout = !cfg!(target_os = "macos");
|
||||
let narrow_left = compact_layout && self.shell.viewport_size().0 < 1024.;
|
||||
let narrow_right = compact_layout && self.shell.viewport_size().0 < 768.;
|
||||
let header_status_visible = self.settings.summary.ui_header_status_visible;
|
||||
let header_status_visible = self.settings.summary().ui_header_status_visible;
|
||||
let header_status = self.header_status_content();
|
||||
// Match Tauri Header: h-10.
|
||||
div()
|
||||
@@ -279,7 +279,8 @@ impl NyaTermApp {
|
||||
|
||||
fn header_status_dropdown(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let selected = HeaderStatusMode::from_setting(&self.settings.summary.ui_header_status_mode);
|
||||
let selected =
|
||||
HeaderStatusMode::from_setting(&self.settings.summary().ui_header_status_mode);
|
||||
let mut menu = div()
|
||||
.id("header-status-menu")
|
||||
.absolute()
|
||||
@@ -328,7 +329,7 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
fn header_status_content(&self) -> HeaderStatusContent {
|
||||
let mode = HeaderStatusMode::from_setting(&self.settings.summary.ui_header_status_mode);
|
||||
let mode = HeaderStatusMode::from_setting(&self.settings.summary().ui_header_status_mode);
|
||||
match mode {
|
||||
HeaderStatusMode::Session => HeaderStatusContent {
|
||||
icon_path: self.title_context_icon().unwrap_or(mode.icon_path()),
|
||||
@@ -336,7 +337,7 @@ impl NyaTermApp {
|
||||
},
|
||||
HeaderStatusMode::DateTime => HeaderStatusContent {
|
||||
icon_path: mode.icon_path(),
|
||||
label: format_header_datetime(local_now(), &self.settings.summary.language),
|
||||
label: format_header_datetime(local_now(), &self.settings.summary().language),
|
||||
},
|
||||
HeaderStatusMode::Resources | HeaderStatusMode::Host => {
|
||||
let label = self
|
||||
@@ -351,7 +352,8 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
fn remote_stats_header_label(&self, mode: HeaderStatusMode) -> Option<String> {
|
||||
if self.session.active_ssh_config().is_none() || !self.settings.summary.ui_show_remote_stats
|
||||
if self.session.active_ssh_config().is_none()
|
||||
|| !self.settings.summary().ui_show_remote_stats
|
||||
{
|
||||
return None;
|
||||
}
|
||||
@@ -396,7 +398,7 @@ impl NyaTermApp {
|
||||
fn remote_stats_header_fallback(&self) -> String {
|
||||
if self.session.active_ssh_config().is_none() {
|
||||
self.tr("panel.resourceMonitorNoSession").to_string()
|
||||
} else if !self.settings.summary.ui_show_remote_stats {
|
||||
} else if !self.settings.summary().ui_show_remote_stats {
|
||||
self.tr("panel.resourceMonitorDisabled").to_string()
|
||||
} else {
|
||||
let stats = self.remote_ops.stats_presentation();
|
||||
@@ -418,8 +420,8 @@ impl NyaTermApp {
|
||||
mode: HeaderStatusMode,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.settings.summary.ui_header_status_mode = mode.persistence_id().to_string();
|
||||
self.settings.summary.ui_header_status_visible = true;
|
||||
self.settings
|
||||
.set_header_status_mode(mode.persistence_id().to_string());
|
||||
self.shell.close_header_status_menu();
|
||||
self.shell
|
||||
.set_header_status_rendered_minute(current_unix_minute());
|
||||
@@ -432,7 +434,7 @@ impl NyaTermApp {
|
||||
visible: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.settings.summary.ui_header_status_visible = visible;
|
||||
self.settings.set_header_status_visible(visible);
|
||||
self.shell.close_header_status_menu();
|
||||
self.persist_header_status_settings();
|
||||
cx.notify();
|
||||
@@ -448,14 +450,14 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn header_status_needs_remote_stats(&self) -> bool {
|
||||
self.settings.summary.ui_header_status_visible
|
||||
&& HeaderStatusMode::from_setting(&self.settings.summary.ui_header_status_mode)
|
||||
self.settings.summary().ui_header_status_visible
|
||||
&& HeaderStatusMode::from_setting(&self.settings.summary().ui_header_status_mode)
|
||||
.needs_remote_stats()
|
||||
}
|
||||
|
||||
pub(in crate::features) fn header_status_clock_refresh_due(&self) -> bool {
|
||||
self.settings.summary.ui_header_status_visible
|
||||
&& HeaderStatusMode::from_setting(&self.settings.summary.ui_header_status_mode)
|
||||
self.settings.summary().ui_header_status_visible
|
||||
&& HeaderStatusMode::from_setting(&self.settings.summary().ui_header_status_mode)
|
||||
== HeaderStatusMode::DateTime
|
||||
&& self.shell.header_status_rendered_minute() != current_unix_minute()
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ impl NyaTermApp {
|
||||
match submenu {
|
||||
TitleMenuSubmenu::Theme => {
|
||||
for &theme in crate::theme::APPEARANCE_THEME_IDS {
|
||||
let current = self.settings.summary.theme.as_str();
|
||||
let current = self.settings.summary().theme.as_str();
|
||||
let selected = current == theme
|
||||
|| (current == "catppuccin" && theme == "catppuccin-mocha");
|
||||
let label = crate::theme::appearance_theme_label(theme);
|
||||
@@ -346,8 +346,8 @@ impl NyaTermApp {
|
||||
}
|
||||
}
|
||||
TitleMenuSubmenu::Language => {
|
||||
let english = matches!(self.settings.summary.language.as_str(), "en" | "en-US");
|
||||
let chinese = matches!(self.settings.summary.language.as_str(), "zh" | "zh-CN");
|
||||
let english = matches!(self.settings.summary().language.as_str(), "en" | "en-US");
|
||||
let chinese = matches!(self.settings.summary().language.as_str(), "zh" | "zh-CN");
|
||||
menu = menu
|
||||
.child(title_menu_item(
|
||||
palette,
|
||||
|
||||
@@ -53,7 +53,7 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> AnyElement {
|
||||
let palette = self.theme_palette();
|
||||
let language = self.settings.summary.language.clone();
|
||||
let language = self.settings.summary().language.clone();
|
||||
let fields = ConnectionEditorFields::new(
|
||||
self.connection_state.editor_fields().clone(),
|
||||
self.connection_state.editor_menu_focus_handle(),
|
||||
|
||||
@@ -14,19 +14,21 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let master_password = self.settings.master_password();
|
||||
let master_password_draft = master_password.draft.to_string();
|
||||
let master_password_enabled = master_password.enabled;
|
||||
let master_password_input = self
|
||||
.text_input_box(
|
||||
"settings.security.master-password",
|
||||
&self.settings.master_password.draft.clone(),
|
||||
&master_password_draft,
|
||||
TextInputSetup::masked(),
|
||||
cx,
|
||||
)
|
||||
.into_any_element();
|
||||
let master_password_enabled = self.settings.master_password.enabled;
|
||||
let master_password_switch_enabled = !self.cloud_sync.settings().enabled;
|
||||
let has_stored_master_password = self.settings.summary.has_master_password;
|
||||
let idle_minutes = self.settings.summary.idle_lock_minutes;
|
||||
let host_key_policy = match self.settings.summary.host_key_policy.as_str() {
|
||||
let has_stored_master_password = self.settings.summary().has_master_password;
|
||||
let idle_minutes = self.settings.summary().idle_lock_minutes;
|
||||
let host_key_policy = match self.settings.summary().host_key_policy.as_str() {
|
||||
"strict" | "reject" => "strict",
|
||||
"accept" | "accept_new" => "accept",
|
||||
_ => "prompt",
|
||||
@@ -91,8 +93,7 @@ impl NyaTermApp {
|
||||
)),
|
||||
))
|
||||
.when(
|
||||
has_stored_master_password
|
||||
&& self.settings.master_password.draft.is_empty(),
|
||||
has_stored_master_password && master_password_draft.is_empty(),
|
||||
|this| {
|
||||
this.child(
|
||||
div()
|
||||
@@ -130,13 +131,13 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"settings-screen-lock-enabled",
|
||||
self.settings.summary.enable_screen_lock,
|
||||
self.settings.summary().enable_screen_lock,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_screen_lock_enabled(cx);
|
||||
}),
|
||||
),
|
||||
))
|
||||
.when(self.settings.summary.enable_screen_lock, |this| {
|
||||
.when(self.settings.summary().enable_screen_lock, |this| {
|
||||
this.child(settings_form_row(
|
||||
palette,
|
||||
idle_lock_label,
|
||||
|
||||
@@ -20,12 +20,12 @@ impl NyaTermApp {
|
||||
let x11_display_input = self
|
||||
.text_input_box(
|
||||
"settings.terminal.x11-display",
|
||||
&self.settings.summary.x11_display.clone(),
|
||||
&self.settings.summary().x11_display.clone(),
|
||||
TextInputSetup::placeholder(self.tr("settings.x11DisplayPlaceholder")),
|
||||
cx,
|
||||
)
|
||||
.into_any_element();
|
||||
let action_links_enabled = self.settings.summary.terminal_action_links_enabled;
|
||||
let action_links_enabled = self.settings.summary().terminal_action_links_enabled;
|
||||
|
||||
div()
|
||||
.flex()
|
||||
@@ -47,7 +47,10 @@ impl NyaTermApp {
|
||||
palette,
|
||||
"terminal-scrollback-minus",
|
||||
"terminal-scrollback-plus",
|
||||
self.settings.summary.terminal_scrollback_lines.to_string(),
|
||||
self.settings
|
||||
.summary()
|
||||
.terminal_scrollback_lines
|
||||
.to_string(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.adjust_terminal_scrollback_lines(-100, cx);
|
||||
}),
|
||||
@@ -67,7 +70,7 @@ impl NyaTermApp {
|
||||
"terminal-keepalive-minus",
|
||||
"terminal-keepalive-plus",
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.terminal_keep_alive_interval
|
||||
.to_string(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
@@ -99,7 +102,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-hardware-acceleration",
|
||||
self.settings.summary.terminal_hardware_acceleration,
|
||||
self.settings.summary().terminal_hardware_acceleration,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_terminal_hardware_acceleration(cx);
|
||||
}),
|
||||
@@ -112,7 +115,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-low-latency-mode",
|
||||
self.settings.summary.terminal_low_latency_mode,
|
||||
self.settings.summary().terminal_low_latency_mode,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_terminal_low_latency_mode(cx);
|
||||
}),
|
||||
@@ -127,7 +130,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-workspace-padding",
|
||||
self.settings.summary.terminal_show_workspace_padding,
|
||||
self.settings.summary().terminal_show_workspace_padding,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_terminal_workspace_padding(cx);
|
||||
}),
|
||||
@@ -140,7 +143,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-line-numbers",
|
||||
self.settings.summary.terminal_show_line_numbers,
|
||||
self.settings.summary().terminal_show_line_numbers,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_terminal_line_numbers(cx);
|
||||
}),
|
||||
@@ -153,13 +156,13 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-timestamps",
|
||||
self.settings.summary.terminal_show_timestamps,
|
||||
self.settings.summary().terminal_show_timestamps,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_terminal_timestamps(cx);
|
||||
}),
|
||||
),
|
||||
))
|
||||
.when(self.settings.summary.terminal_show_timestamps, |this| {
|
||||
.when(self.settings.summary().terminal_show_timestamps, |this| {
|
||||
this.child(settings_form_row(
|
||||
palette,
|
||||
self.tr("settings.showTimestampMilliseconds"),
|
||||
@@ -169,7 +172,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-timestamp-ms",
|
||||
self.settings.summary.terminal_show_timestamp_milliseconds,
|
||||
self.settings.summary().terminal_show_timestamp_milliseconds,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_terminal_timestamp_milliseconds(cx);
|
||||
}),
|
||||
@@ -185,7 +188,9 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-multi-line-paste",
|
||||
self.settings.summary.terminal_show_multi_line_paste_dialog,
|
||||
self.settings
|
||||
.summary()
|
||||
.terminal_show_multi_line_paste_dialog,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_multi_line_paste_dialog(cx);
|
||||
}),
|
||||
@@ -198,7 +203,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-paste-image-path",
|
||||
self.settings.summary.terminal_paste_image_as_path,
|
||||
self.settings.summary().terminal_paste_image_as_path,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_paste_image_as_path(cx);
|
||||
}),
|
||||
@@ -211,13 +216,13 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-remote-stats",
|
||||
self.settings.summary.ui_show_remote_stats,
|
||||
self.settings.summary().ui_show_remote_stats,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_remote_stats_panel(cx);
|
||||
}),
|
||||
),
|
||||
))
|
||||
.when(self.settings.summary.ui_show_remote_stats, |this| {
|
||||
.when(self.settings.summary().ui_show_remote_stats, |this| {
|
||||
this.child(settings_form_row(
|
||||
palette,
|
||||
self.tr("settings.remoteStatsInterval"),
|
||||
@@ -228,7 +233,7 @@ impl NyaTermApp {
|
||||
palette,
|
||||
"terminal-remote-stats-interval-minus",
|
||||
"terminal-remote-stats-interval-plus",
|
||||
self.settings.summary.ui_remote_stats_interval.to_string(),
|
||||
self.settings.summary().ui_remote_stats_interval.to_string(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.adjust_remote_stats_interval(-1, cx);
|
||||
}),
|
||||
@@ -247,13 +252,13 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-process-manager",
|
||||
self.settings.summary.ui_show_process_manager,
|
||||
self.settings.summary().ui_show_process_manager,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_process_manager_panel(cx);
|
||||
}),
|
||||
),
|
||||
))
|
||||
.when(self.settings.summary.ui_show_process_manager, |this| {
|
||||
.when(self.settings.summary().ui_show_process_manager, |this| {
|
||||
this.child(settings_form_row(
|
||||
palette,
|
||||
self.tr("settings.processManagerInterval"),
|
||||
@@ -265,7 +270,7 @@ impl NyaTermApp {
|
||||
"terminal-process-interval-minus",
|
||||
"terminal-process-interval-plus",
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.ui_process_manager_interval
|
||||
.to_string(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
@@ -286,13 +291,13 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"terminal-docker-manager",
|
||||
self.settings.summary.ui_show_docker_manager,
|
||||
self.settings.summary().ui_show_docker_manager,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_docker_manager_panel(cx);
|
||||
}),
|
||||
),
|
||||
))
|
||||
.when(self.settings.summary.ui_show_docker_manager, |this| {
|
||||
.when(self.settings.summary().ui_show_docker_manager, |this| {
|
||||
this.child(settings_form_row(
|
||||
palette,
|
||||
self.tr("settings.dockerManagerInterval"),
|
||||
@@ -303,7 +308,10 @@ impl NyaTermApp {
|
||||
palette,
|
||||
"terminal-docker-interval-minus",
|
||||
"terminal-docker-interval-plus",
|
||||
self.settings.summary.ui_docker_manager_interval.to_string(),
|
||||
self.settings
|
||||
.summary()
|
||||
.ui_docker_manager_interval
|
||||
.to_string(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.adjust_docker_manager_interval(-1, cx);
|
||||
}),
|
||||
@@ -353,7 +361,7 @@ impl NyaTermApp {
|
||||
self.tr("settings.actionLinksMatcherIpv4"),
|
||||
"192.168.1.1",
|
||||
self.tr("settings.actionLinksMatcherIpv4Desc"),
|
||||
self.settings.summary.terminal_action_links_matchers.ipv4,
|
||||
self.settings.summary().terminal_action_links_matchers.ipv4,
|
||||
action_links_enabled,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_terminal_action_links_matcher("ipv4", cx);
|
||||
@@ -366,7 +374,7 @@ impl NyaTermApp {
|
||||
"localhost:8080",
|
||||
self.tr("settings.actionLinksMatcherHostPortDesc"),
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.terminal_action_links_matchers
|
||||
.host_port,
|
||||
action_links_enabled,
|
||||
@@ -380,7 +388,10 @@ impl NyaTermApp {
|
||||
self.tr("settings.actionLinksMatcherArchive"),
|
||||
"backup.tar.gz",
|
||||
self.tr("settings.actionLinksMatcherArchiveDesc"),
|
||||
self.settings.summary.terminal_action_links_matchers.archive,
|
||||
self.settings
|
||||
.summary()
|
||||
.terminal_action_links_matchers
|
||||
.archive,
|
||||
action_links_enabled,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_terminal_action_links_matcher("archive", cx);
|
||||
|
||||
@@ -19,8 +19,8 @@ impl NyaTermApp {
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let is_dark = self.terminal_theme_is_dark();
|
||||
let rules = self.settings.keyword_config.rules.clone();
|
||||
let keyword_highlighting_enabled = self.settings.keyword_config.enabled;
|
||||
let rules = self.settings.keyword_config().rules.clone();
|
||||
let keyword_highlighting_enabled = self.settings.keyword_config().enabled;
|
||||
let expanded = self.settings.keyword_highlight_presentation().expanded_id;
|
||||
let builtin_ids = nyaterm_core::builtin_keyword_rule_ids();
|
||||
let pattern_count_template = self.tr("settings.keywordHighlightPatternCount");
|
||||
@@ -63,7 +63,7 @@ impl NyaTermApp {
|
||||
settings_switch_with_enabled(
|
||||
palette,
|
||||
"settings-keyword-highlights-wrap",
|
||||
self.settings.keyword_config.across_wrapped_lines,
|
||||
self.settings.keyword_config().across_wrapped_lines,
|
||||
keyword_highlighting_enabled,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_keyword_highlights_wrapped(cx);
|
||||
@@ -106,7 +106,7 @@ impl NyaTermApp {
|
||||
&id, is_dark,
|
||||
);
|
||||
let enabled = self
|
||||
.settings.keyword_config
|
||||
.settings.keyword_config()
|
||||
.builtin_rules
|
||||
.get(&id)
|
||||
.copied()
|
||||
|
||||
@@ -26,7 +26,7 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let engines = self.settings.summary.search_custom_engines.clone();
|
||||
let engines = self.settings.summary().search_custom_engines.clone();
|
||||
let interaction = self.settings.search_engine_presentation();
|
||||
let expanded_index = interaction.expanded_index;
|
||||
let icon_picker_index = interaction.icon_picker_index;
|
||||
|
||||
@@ -15,7 +15,7 @@ impl NyaTermApp {
|
||||
let palette = self.theme_palette();
|
||||
let permissions = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.transfer_default_file_permissions
|
||||
.clone();
|
||||
|
||||
@@ -53,7 +53,12 @@ impl NyaTermApp {
|
||||
.text_size(px(12.))
|
||||
.font_weight(FontWeight(700.))
|
||||
.text_color(rgb(palette.text))
|
||||
.child(self.settings.summary.transfer_download_threads.to_string()),
|
||||
.child(
|
||||
self.settings
|
||||
.summary()
|
||||
.transfer_download_threads
|
||||
.to_string(),
|
||||
),
|
||||
)
|
||||
.child(small_button(
|
||||
palette,
|
||||
@@ -90,7 +95,7 @@ impl NyaTermApp {
|
||||
.text_size(px(12.))
|
||||
.font_weight(FontWeight(700.))
|
||||
.text_color(rgb(palette.text))
|
||||
.child(self.settings.summary.transfer_upload_threads.to_string()),
|
||||
.child(self.settings.summary().transfer_upload_threads.to_string()),
|
||||
)
|
||||
.child(small_button(
|
||||
palette,
|
||||
@@ -127,7 +132,7 @@ impl NyaTermApp {
|
||||
.text_size(px(12.))
|
||||
.font_weight(FontWeight(700.))
|
||||
.text_color(rgb(palette.text))
|
||||
.child(self.settings.summary.transfer_max_retries.to_string()),
|
||||
.child(self.settings.summary().transfer_max_retries.to_string()),
|
||||
)
|
||||
.child(small_button(
|
||||
palette,
|
||||
@@ -164,7 +169,7 @@ impl NyaTermApp {
|
||||
.text_size(px(12.))
|
||||
.font_weight(FontWeight(700.))
|
||||
.text_color(rgb(palette.text))
|
||||
.child(self.settings.summary.transfer_buffer_size.to_string()),
|
||||
.child(self.settings.summary().transfer_buffer_size.to_string()),
|
||||
)
|
||||
.child(small_button(
|
||||
palette,
|
||||
@@ -184,7 +189,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"settings-transfer-preserve-timestamps",
|
||||
self.settings.summary.transfer_preserve_timestamps,
|
||||
self.settings.summary().transfer_preserve_timestamps,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_transfer_preserve_timestamps(cx);
|
||||
}),
|
||||
@@ -199,7 +204,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"settings-transfer-resume-broken",
|
||||
self.settings.summary.transfer_resume_broken_transfer,
|
||||
self.settings.summary().transfer_resume_broken_transfer,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_transfer_resume_broken(cx);
|
||||
}),
|
||||
|
||||
@@ -11,11 +11,11 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let editor_type = self.settings.summary.transfer_editor_type.clone();
|
||||
let editor_type = self.settings.summary().transfer_editor_type.clone();
|
||||
let default_editor_input = self
|
||||
.text_input_box(
|
||||
"settings.transfer.default-editor",
|
||||
&self.settings.summary.transfer_default_editor.clone(),
|
||||
&self.settings.summary().transfer_default_editor.clone(),
|
||||
TextInputSetup::placeholder(self.tr("settings.defaultEditor")),
|
||||
cx,
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ impl NyaTermApp {
|
||||
let download_path_input = self
|
||||
.text_input_box(
|
||||
"settings.transfer.download-path",
|
||||
&self.settings.summary.transfer_download_path.clone(),
|
||||
&self.settings.summary().transfer_download_path.clone(),
|
||||
TextInputSetup::placeholder(self.tr("settings.downloadPath")),
|
||||
cx,
|
||||
)
|
||||
@@ -63,7 +63,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"transfer-ask-save",
|
||||
self.settings.summary.transfer_ask_save_location,
|
||||
self.settings.summary().transfer_ask_save_location,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_transfer_ask_save_location(cx);
|
||||
}),
|
||||
|
||||
@@ -16,13 +16,13 @@ impl NyaTermApp {
|
||||
let recording_path_input = self
|
||||
.text_input_box(
|
||||
"settings.recording.path",
|
||||
&self.settings.summary.recording_path.clone(),
|
||||
&self.settings.summary().recording_path.clone(),
|
||||
TextInputSetup::placeholder(self.tr("settings.recordingPath")),
|
||||
cx,
|
||||
)
|
||||
.into_any_element();
|
||||
let memory_mib =
|
||||
(self.settings.summary.recording_memory_limit_bytes / (1024 * 1024)).max(1);
|
||||
(self.settings.summary().recording_memory_limit_bytes / (1024 * 1024)).max(1);
|
||||
|
||||
div().flex().flex_col().gap_3().child(settings_form_section(
|
||||
palette,
|
||||
@@ -61,7 +61,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"settings-recording-auto",
|
||||
self.settings.summary.recording_auto_start,
|
||||
self.settings.summary().recording_auto_start,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_recording_auto_start(cx);
|
||||
}),
|
||||
@@ -76,7 +76,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"settings-recording-labels",
|
||||
self.settings.summary.recording_include_io_labels,
|
||||
self.settings.summary().recording_include_io_labels,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_recording_io_labels(cx);
|
||||
}),
|
||||
@@ -91,7 +91,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"settings-recording-timestamps",
|
||||
self.settings.summary.recording_include_timestamps,
|
||||
self.settings.summary().recording_include_timestamps,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_recording_timestamps(cx);
|
||||
}),
|
||||
|
||||
@@ -15,8 +15,8 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let font_size_label = self.settings.summary.terminal_font_size.to_string();
|
||||
let ui_font_size_label = self.settings.summary.ui_font_size.to_string();
|
||||
let font_size_label = self.settings.summary().terminal_font_size.to_string();
|
||||
let ui_font_size_label = self.settings.summary().ui_font_size.to_string();
|
||||
|
||||
div()
|
||||
.flex()
|
||||
@@ -71,7 +71,7 @@ impl NyaTermApp {
|
||||
{
|
||||
let path_label = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.background_image_path
|
||||
.as_deref()
|
||||
.map(|p| {
|
||||
@@ -91,7 +91,7 @@ impl NyaTermApp {
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| self.tr("settings.backgroundImageEmpty").to_string());
|
||||
let has_image = self.settings.summary.background_image_path.is_some();
|
||||
let has_image = self.settings.summary().background_image_path.is_some();
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
@@ -228,7 +228,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"appearance-cursor-blink",
|
||||
self.settings.summary.cursor_blink,
|
||||
self.settings.summary().cursor_blink,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_cursor_blink(cx);
|
||||
}),
|
||||
@@ -247,7 +247,7 @@ impl NyaTermApp {
|
||||
(
|
||||
self.tr("settings.terminalFontFamily"),
|
||||
self.tr("settings.terminalFontFamilyDesc"),
|
||||
self.settings.summary.terminal_font_family.clone(),
|
||||
self.settings.summary().terminal_font_family.clone(),
|
||||
"JetBrains Mono",
|
||||
self.settings.terminal_font_options().to_vec(),
|
||||
)
|
||||
@@ -255,7 +255,7 @@ impl NyaTermApp {
|
||||
(
|
||||
self.tr("settings.uiFontFamily"),
|
||||
self.tr("settings.uiFontFamilyDesc"),
|
||||
self.settings.summary.ui_font_family.clone(),
|
||||
self.settings.summary().ui_font_family.clone(),
|
||||
"Inter",
|
||||
self.settings.ui_font_options().to_vec(),
|
||||
)
|
||||
@@ -408,9 +408,9 @@ impl NyaTermApp {
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let value = if content {
|
||||
self.settings.summary.background_content_opacity
|
||||
self.settings.summary().background_content_opacity
|
||||
} else {
|
||||
self.settings.summary.background_image_opacity
|
||||
self.settings.summary().background_image_opacity
|
||||
};
|
||||
let label = if content {
|
||||
self.tr("settings.backgroundContentOpacity")
|
||||
@@ -523,12 +523,12 @@ impl NyaTermApp {
|
||||
};
|
||||
let current = if terminal {
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.terminal_theme
|
||||
.as_deref()
|
||||
.filter(|theme| !theme.trim().is_empty())
|
||||
} else {
|
||||
Some(self.settings.summary.theme.as_str())
|
||||
Some(self.settings.summary().theme.as_str())
|
||||
};
|
||||
let value = current
|
||||
.map(appearance_theme_label)
|
||||
@@ -582,7 +582,7 @@ impl NyaTermApp {
|
||||
fn appearance_contrast_select(&mut self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let id = "appearance-minimum-contrast";
|
||||
let current = self.settings.summary.minimum_contrast_ratio.clone();
|
||||
let current = self.settings.summary().minimum_contrast_ratio.clone();
|
||||
let label_for = |ratio: &str| match ratio {
|
||||
"3" => self.tr("settings.minimumContrastRatio_3"),
|
||||
"4.5" => self.tr("settings.minimumContrastRatio_4_5"),
|
||||
@@ -623,7 +623,7 @@ impl NyaTermApp {
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let id = "appearance-background-fit";
|
||||
let current = match self.settings.summary.background_image_fit.as_str() {
|
||||
let current = match self.settings.summary().background_image_fit.as_str() {
|
||||
"contain" => "contain",
|
||||
"stretch" | "fill" => "stretch",
|
||||
"tile" => "tile",
|
||||
@@ -673,9 +673,9 @@ impl NyaTermApp {
|
||||
"appearance-font-weight"
|
||||
};
|
||||
let current = if bold {
|
||||
self.settings.summary.terminal_font_weight_bold
|
||||
self.settings.summary().terminal_font_weight_bold
|
||||
} else {
|
||||
self.settings.summary.terminal_font_weight
|
||||
self.settings.summary().terminal_font_weight
|
||||
};
|
||||
let label_for = |weight| match weight {
|
||||
300 => self.tr("settings.fontWeight_300"),
|
||||
@@ -720,7 +720,7 @@ impl NyaTermApp {
|
||||
fn appearance_cursor_style_select(&mut self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let id = "appearance-cursor-style";
|
||||
let current = self.settings.summary.cursor_style.clone();
|
||||
let current = self.settings.summary().cursor_style.clone();
|
||||
let label_for = |style: &str| match style {
|
||||
"underline" => self.tr("settings.cursorUnderline"),
|
||||
"bar" => self.tr("settings.cursorBar"),
|
||||
|
||||
@@ -15,7 +15,7 @@ impl NyaTermApp {
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
// Tauri GeneralTab: language, nested startup layout, tray, confirm, diagnostics.
|
||||
let language = self.settings.summary.language.clone();
|
||||
let language = self.settings.summary().language.clone();
|
||||
let language_label = match language.as_str() {
|
||||
"zh-CN" | "zh" => "简体中文",
|
||||
"zh-TW" => "繁體中文",
|
||||
@@ -23,12 +23,12 @@ impl NyaTermApp {
|
||||
"ja" => "日本語",
|
||||
other => other,
|
||||
};
|
||||
let diagnostics_level = self.settings.summary.diagnostics_level.clone();
|
||||
let retention = self.settings.summary.diagnostics_retention_days;
|
||||
let diagnostics_level = self.settings.summary().diagnostics_level.clone();
|
||||
let retention = self.settings.summary().diagnostics_retention_days;
|
||||
let days_unit = self.tr("common.days");
|
||||
let header_status_mode =
|
||||
HeaderStatusMode::from_setting(&self.settings.summary.ui_header_status_mode);
|
||||
let header_status_visible = self.settings.summary.ui_header_status_visible;
|
||||
HeaderStatusMode::from_setting(&self.settings.summary().ui_header_status_mode);
|
||||
let header_status_visible = self.settings.summary().ui_header_status_visible;
|
||||
|
||||
div()
|
||||
.flex()
|
||||
@@ -121,13 +121,13 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"general-startup-restore",
|
||||
self.settings.summary.startup_restore,
|
||||
self.settings.summary().startup_restore,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_startup_restore(cx);
|
||||
}),
|
||||
),
|
||||
))
|
||||
.when(self.settings.summary.startup_restore, |this| {
|
||||
.when(self.settings.summary().startup_restore, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.pl_3()
|
||||
@@ -143,7 +143,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"general-startup-restore-window-layout",
|
||||
self.settings.summary.startup_restore_window_layout,
|
||||
self.settings.summary().startup_restore_window_layout,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_startup_restore_window_layout(cx);
|
||||
}),
|
||||
@@ -158,7 +158,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"general-minimize-to-tray",
|
||||
self.settings.summary.minimize_to_tray,
|
||||
self.settings.summary().minimize_to_tray,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_minimize_to_tray(cx);
|
||||
}),
|
||||
@@ -171,7 +171,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"general-confirm-close",
|
||||
self.settings.summary.confirm_on_close,
|
||||
self.settings.summary().confirm_on_close,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_confirm_on_close(cx);
|
||||
}),
|
||||
|
||||
@@ -19,47 +19,47 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let encoding = self.settings.summary.interaction_default_encoding.clone();
|
||||
let encoding = self.settings.summary().interaction_default_encoding.clone();
|
||||
// Built before the form, which reads `self` throughout: creating the
|
||||
// box needs it mutably.
|
||||
let word_separators_input = self
|
||||
.text_input_box(
|
||||
"settings.interaction.word-separators",
|
||||
&self.settings.summary.interaction_word_separators.clone(),
|
||||
&self.settings.summary().interaction_word_separators.clone(),
|
||||
TextInputSetup::default(),
|
||||
cx,
|
||||
)
|
||||
.into_any_element();
|
||||
let double_action = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_tab_double_click_action
|
||||
.clone();
|
||||
let middle_action = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_tab_middle_click_action
|
||||
.clone();
|
||||
let right_action = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_tab_right_click_action
|
||||
.clone();
|
||||
let delay_ms = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_duplicate_session_command_delay_ms;
|
||||
let min_chars = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestion_min_chars;
|
||||
let max_chars = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestion_max_chars;
|
||||
let suggestions_enabled = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestions_enabled;
|
||||
|
||||
div()
|
||||
@@ -81,7 +81,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"interaction-copy-select",
|
||||
self.settings.summary.interaction_copy_on_select,
|
||||
self.settings.summary().interaction_copy_on_select,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_interaction_copy_on_select(cx);
|
||||
}),
|
||||
@@ -94,7 +94,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"interaction-right-paste",
|
||||
self.settings.summary.interaction_right_click_paste,
|
||||
self.settings.summary().interaction_right_click_paste,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_interaction_right_click_paste(cx);
|
||||
}),
|
||||
@@ -219,7 +219,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"interaction-alt-meta",
|
||||
self.settings.summary.interaction_alt_as_meta,
|
||||
self.settings.summary().interaction_alt_as_meta,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_alt_as_meta(cx);
|
||||
}),
|
||||
@@ -234,7 +234,7 @@ impl NyaTermApp {
|
||||
settings_switch(
|
||||
palette,
|
||||
"interaction-mac-ime",
|
||||
self.settings.summary.interaction_mac_ime_compatibility,
|
||||
self.settings.summary().interaction_mac_ime_compatibility,
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_mac_ime_compatibility(cx);
|
||||
}),
|
||||
|
||||
@@ -15,7 +15,7 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let palette = self.theme_palette();
|
||||
let overrides = self.settings.summary.keybindings.len();
|
||||
let overrides = self.settings.summary().keybindings.len();
|
||||
let search = self.settings.keybinding_presentation().search_draft;
|
||||
let search_field = self.text_input(
|
||||
"settings.keybindings.search",
|
||||
@@ -106,7 +106,7 @@ impl NyaTermApp {
|
||||
if needle.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let keys = shortcut_keys_for(shortcut.id, &self.settings.summary.keybindings)
|
||||
let keys = shortcut_keys_for(shortcut.id, &self.settings.summary().keybindings)
|
||||
.unwrap_or_else(|| shortcut.default_keys.to_string());
|
||||
let display = format_hotkey_for_display(&keys).to_ascii_lowercase();
|
||||
shortcut.label.to_ascii_lowercase().contains(&needle)
|
||||
@@ -140,10 +140,14 @@ impl NyaTermApp {
|
||||
ShortcutNativeStatus::Contextual => "contextual",
|
||||
},
|
||||
);
|
||||
let is_custom = self.settings.summary.keybindings.contains_key(shortcut.id);
|
||||
let is_custom = self
|
||||
.settings
|
||||
.summary()
|
||||
.keybindings
|
||||
.contains_key(shortcut.id);
|
||||
let interaction = self.settings.keybinding_presentation();
|
||||
let is_recording = interaction.recording_id.as_deref() == Some(shortcut.id);
|
||||
let effective_keys = shortcut_keys_for(shortcut.id, &self.settings.summary.keybindings)
|
||||
let effective_keys = shortcut_keys_for(shortcut.id, &self.settings.summary().keybindings)
|
||||
.unwrap_or_else(|| shortcut.default_keys.to_string());
|
||||
let conflict = if is_recording {
|
||||
interaction
|
||||
|
||||
@@ -144,7 +144,7 @@ impl NyaTermApp {
|
||||
.sum();
|
||||
let search_active = !self.transfer.browser_view().search.trim().is_empty();
|
||||
let search_expanded = self.transfer.browser_view().search_expanded || search_active;
|
||||
let show_hidden_files = self.settings.summary.ui_file_explorer_show_hidden_files;
|
||||
let show_hidden_files = self.settings.summary().ui_file_explorer_show_hidden_files;
|
||||
let search_input = search_expanded.then(|| {
|
||||
let field = self.text_input(
|
||||
"transfer.browser.search",
|
||||
|
||||
@@ -19,7 +19,7 @@ impl NyaTermApp {
|
||||
transfer_browser_entry_is_visible(
|
||||
entry,
|
||||
&query,
|
||||
self.settings.summary.ui_file_explorer_show_hidden_files,
|
||||
self.settings.summary().ui_file_explorer_show_hidden_files,
|
||||
)
|
||||
})
|
||||
.cloned()
|
||||
|
||||
@@ -76,7 +76,7 @@ impl NyaTermApp {
|
||||
if shortcut_matches(
|
||||
event,
|
||||
"fileExplorer.rename",
|
||||
&self.settings.summary.keybindings,
|
||||
&self.settings.summary().keybindings,
|
||||
) && self.selected_transfer_entries().len() == 1
|
||||
&& self.session.active_ssh_config().is_some()
|
||||
&& !self.transfer.rename_dialog_is_open()
|
||||
|
||||
@@ -209,32 +209,17 @@ impl NyaTermApp {
|
||||
};
|
||||
let enabled = self
|
||||
.settings
|
||||
.summary
|
||||
.ui_file_explorer_auto_sync_cwd_connection_ids
|
||||
.iter()
|
||||
.any(|id| id == &connection_id);
|
||||
.toggle_file_explorer_auto_sync_cwd(connection_id);
|
||||
if enabled {
|
||||
self.settings
|
||||
.summary
|
||||
.ui_file_explorer_auto_sync_cwd_connection_ids
|
||||
.retain(|id| id != &connection_id);
|
||||
self.transfer
|
||||
.set_browser_status("Auto CWD disabled for this connection");
|
||||
} else {
|
||||
self.settings
|
||||
.summary
|
||||
.ui_file_explorer_auto_sync_cwd_connection_ids
|
||||
.retain(|id| id != &connection_id);
|
||||
self.settings
|
||||
.summary
|
||||
.ui_file_explorer_auto_sync_cwd_connection_ids
|
||||
.push(connection_id);
|
||||
self.transfer
|
||||
.set_browser_status("Auto CWD enabled for this connection");
|
||||
} else {
|
||||
self.transfer
|
||||
.set_browser_status("Auto CWD disabled for this connection");
|
||||
}
|
||||
self.transfer.reset_browser_auto_sync_cwd();
|
||||
self.persist_transfer_browser_ui_settings();
|
||||
if !enabled {
|
||||
if enabled {
|
||||
self.start_transfer_sync_cwd_job(window, cx);
|
||||
} else {
|
||||
cx.notify();
|
||||
@@ -245,14 +230,13 @@ impl NyaTermApp {
|
||||
&mut self,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.settings.summary.ui_file_explorer_show_hidden_files =
|
||||
!self.settings.summary.ui_file_explorer_show_hidden_files;
|
||||
if !self.settings.summary.ui_file_explorer_show_hidden_files {
|
||||
let show_hidden_files = self.settings.toggle_file_explorer_hidden_files();
|
||||
if !show_hidden_files {
|
||||
self.transfer
|
||||
.retain_browser_selection(|path| !remote_file_name(path).starts_with('.'));
|
||||
}
|
||||
self.transfer.set_browser_list_offset(0);
|
||||
let status = if self.settings.summary.ui_file_explorer_show_hidden_files {
|
||||
let status = if show_hidden_files {
|
||||
"hidden files shown".to_string()
|
||||
} else {
|
||||
"hidden files hidden".to_string()
|
||||
@@ -267,7 +251,7 @@ impl NyaTermApp {
|
||||
return false;
|
||||
};
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.ui_file_explorer_auto_sync_cwd_connection_ids
|
||||
.iter()
|
||||
.any(|id| id == &connection_id)
|
||||
@@ -280,7 +264,7 @@ impl NyaTermApp {
|
||||
};
|
||||
let favorites = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.ui_file_explorer_favorite_dirs_by_connection_id
|
||||
.get(&connection_id)
|
||||
.cloned()
|
||||
@@ -307,17 +291,8 @@ impl NyaTermApp {
|
||||
return;
|
||||
};
|
||||
let favorites = self.transfer.browser_favorites_owned();
|
||||
if favorites.is_empty() {
|
||||
self.settings
|
||||
.summary
|
||||
.ui_file_explorer_favorite_dirs_by_connection_id
|
||||
.remove(&connection_id);
|
||||
} else {
|
||||
self.settings
|
||||
.summary
|
||||
.ui_file_explorer_favorite_dirs_by_connection_id
|
||||
.insert(connection_id, favorites);
|
||||
}
|
||||
self.settings
|
||||
.set_file_explorer_favorites(connection_id, favorites);
|
||||
self.persist_transfer_browser_ui_settings();
|
||||
cx.notify();
|
||||
}
|
||||
@@ -327,7 +302,7 @@ impl NyaTermApp {
|
||||
self.runtime.config_dir(),
|
||||
self.runtime.portable_key_path().map(ToOwned::to_owned),
|
||||
)
|
||||
.and_then(|store| store.save_file_explorer_favorite_dirs(&self.settings.summary))
|
||||
.and_then(|store| store.save_file_explorer_favorite_dirs(self.settings.summary()))
|
||||
{
|
||||
Ok(settings) => {
|
||||
self.apply_gpui_settings(settings);
|
||||
|
||||
@@ -499,7 +499,7 @@ impl NyaTermApp {
|
||||
cx.notify();
|
||||
return;
|
||||
}
|
||||
if self.settings.summary.transfer_ask_save_location {
|
||||
if self.settings.summary().transfer_ask_save_location {
|
||||
let remote_paths = entries
|
||||
.into_iter()
|
||||
.map(|entry| entry.path)
|
||||
|
||||
@@ -170,7 +170,7 @@ impl NyaTermApp {
|
||||
entry: &SftpFileEntry,
|
||||
) -> bool {
|
||||
entry.file_type != SftpFileType::Directory
|
||||
&& self.settings.summary.transfer_editor_type == "external"
|
||||
&& self.settings.summary().transfer_editor_type == "external"
|
||||
&& !is_known_binary_file(&entry.name)
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ impl NyaTermApp {
|
||||
entry: &SftpFileEntry,
|
||||
) -> bool {
|
||||
entry.file_type != SftpFileType::Directory
|
||||
&& self.settings.summary.transfer_editor_type == "internal"
|
||||
&& self.settings.summary().transfer_editor_type == "internal"
|
||||
}
|
||||
|
||||
pub(in crate::features) fn open_transfer_default(
|
||||
@@ -188,7 +188,7 @@ impl NyaTermApp {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.settings.summary.transfer_editor_type == "internal" {
|
||||
if self.settings.summary().transfer_editor_type == "internal" {
|
||||
self.open_transfer_editor(entry, window, cx);
|
||||
} else {
|
||||
self.open_transfer_external(entry, window, cx);
|
||||
@@ -374,7 +374,7 @@ impl NyaTermApp {
|
||||
self.transfer.set_remote_path(entry.path.clone());
|
||||
let remote_path = entry.path.clone();
|
||||
let local_path = self.transfer_external_open_path(&entry, session_id.as_deref());
|
||||
let default_editor = self.settings.summary.transfer_default_editor.clone();
|
||||
let default_editor = self.settings.summary().transfer_default_editor.clone();
|
||||
let transfer_options = self.sftp_transfer_options();
|
||||
let id = self.next_transfer_id("sftp-open-external");
|
||||
let control = SftpTransferControl::new();
|
||||
|
||||
@@ -246,7 +246,7 @@ impl NyaTermApp {
|
||||
let status = if path == current_path {
|
||||
TransferBrowserChildrenMenuStatus::Ready(transfer_browser_child_directories(
|
||||
&self.transfer.browser_view().entries,
|
||||
self.settings.summary.ui_file_explorer_show_hidden_files,
|
||||
self.settings.summary().ui_file_explorer_show_hidden_files,
|
||||
))
|
||||
} else {
|
||||
TransferBrowserChildrenMenuStatus::Loading
|
||||
|
||||
@@ -17,7 +17,7 @@ impl NyaTermApp {
|
||||
let width = (self.shell.viewport_size().0 - 32.).clamp(280., 480.);
|
||||
let docs_url = if self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.language
|
||||
.to_ascii_lowercase()
|
||||
.starts_with("zh")
|
||||
|
||||
@@ -22,13 +22,13 @@ impl NyaTermApp {
|
||||
cx,
|
||||
);
|
||||
let password_focus = password_input.read(cx).focus_handle();
|
||||
let overlay_focus = if self.settings.summary.has_master_password {
|
||||
let overlay_focus = if self.settings.summary().has_master_password {
|
||||
password_focus.clone()
|
||||
} else {
|
||||
self.security.screen_lock_focus().clone()
|
||||
};
|
||||
let lock_status = if self.security.screen_lock_status().trim().is_empty() {
|
||||
if self.settings.summary.has_master_password {
|
||||
if self.settings.summary().has_master_password {
|
||||
self.tr("lockScreen.passwordPlaceholder").to_string()
|
||||
} else {
|
||||
self.tr("settings.masterPasswordRequired").to_string()
|
||||
@@ -168,7 +168,7 @@ impl NyaTermApp {
|
||||
.text_color(rgb(palette.text_muted))
|
||||
.child(self.tr("lockScreen.message")),
|
||||
)
|
||||
.when(self.settings.summary.has_master_password, |this| {
|
||||
.when(self.settings.summary().has_master_password, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.w(px(280.))
|
||||
@@ -224,7 +224,7 @@ impl NyaTermApp {
|
||||
),
|
||||
)
|
||||
})
|
||||
.when(!self.settings.summary.has_master_password, |this| {
|
||||
.when(!self.settings.summary().has_master_password, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.text_center()
|
||||
|
||||
@@ -15,7 +15,7 @@ impl NyaTermApp {
|
||||
let palette = self.theme_palette();
|
||||
let docs_url = if self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.language
|
||||
.to_ascii_lowercase()
|
||||
.starts_with("zh")
|
||||
|
||||
@@ -36,7 +36,7 @@ impl Render for QuickCommandWindow {
|
||||
(
|
||||
app.theme_palette(),
|
||||
app.gpui_ui_font_family(),
|
||||
app.settings.summary.ui_font_size.clamp(12, 24) as f32,
|
||||
app.settings.summary().ui_font_size.clamp(12, 24) as f32,
|
||||
app.quick_command_editor_title().to_string(),
|
||||
)
|
||||
});
|
||||
|
||||
@@ -54,7 +54,7 @@ impl Render for RemoteFileEditorWindow {
|
||||
(
|
||||
app.theme_palette(),
|
||||
app.gpui_ui_font_family(),
|
||||
app.settings.summary.ui_font_size.clamp(12, 24) as f32,
|
||||
app.settings.summary().ui_font_size.clamp(12, 24) as f32,
|
||||
format!(
|
||||
"{}{}",
|
||||
if workspace.tabs.iter().any(|tab| tab.dirty) {
|
||||
|
||||
@@ -59,7 +59,7 @@ impl NyaTermApp {
|
||||
let palette = self.theme_palette();
|
||||
let wallpaper_path = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.background_image_path
|
||||
.as_ref()
|
||||
.map(|p| p.trim())
|
||||
@@ -67,8 +67,8 @@ impl NyaTermApp {
|
||||
.filter(|p| std::path::Path::new(p).is_file())
|
||||
.map(|p| p.to_string());
|
||||
let wallpaper_opacity =
|
||||
(self.settings.summary.background_image_opacity.min(100) as f32) / 100.0;
|
||||
let wallpaper_fit = self.settings.summary.background_image_fit.clone();
|
||||
(self.settings.summary().background_image_opacity.min(100) as f32) / 100.0;
|
||||
let wallpaper_fit = self.settings.summary().background_image_fit.clone();
|
||||
let wallpaper_tile_size = wallpaper_path
|
||||
.as_deref()
|
||||
.filter(|_| wallpaper_fit == "tile")
|
||||
@@ -80,7 +80,7 @@ impl NyaTermApp {
|
||||
.bg(self.shell_transparent_color(palette.bg))
|
||||
.text_color(rgb(palette.text))
|
||||
.font_family(self.gpui_ui_font_family())
|
||||
.text_size(px(self.settings.summary.ui_font_size.clamp(12, 24) as f32))
|
||||
.text_size(px(self.settings.summary().ui_font_size.clamp(12, 24) as f32))
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.mark_user_activity();
|
||||
}))
|
||||
|
||||
@@ -29,7 +29,7 @@ impl NyaTermApp {
|
||||
return;
|
||||
}
|
||||
let target = recording_file_path(
|
||||
&self.settings.summary,
|
||||
self.settings.summary(),
|
||||
self.runtime.config_dir(),
|
||||
&session_name,
|
||||
);
|
||||
@@ -107,9 +107,9 @@ impl NyaTermApp {
|
||||
let manager = self.recording.manager_for_job();
|
||||
let writer = self.recording.writer();
|
||||
let job_session_id = session_id.to_string();
|
||||
let memory_limit = self.settings.summary.recording_memory_limit_bytes as usize;
|
||||
let include_io_labels = self.settings.summary.recording_include_io_labels;
|
||||
let include_timestamps = self.settings.summary.recording_include_timestamps;
|
||||
let memory_limit = self.settings.summary().recording_memory_limit_bytes as usize;
|
||||
let include_io_labels = self.settings.summary().recording_include_io_labels;
|
||||
let include_timestamps = self.settings.summary().recording_include_timestamps;
|
||||
let task = cx.background_spawn(async move {
|
||||
writer.flush();
|
||||
manager.set_memory_limit(memory_limit);
|
||||
@@ -207,9 +207,9 @@ impl NyaTermApp {
|
||||
let manager = self.recording.manager_for_job();
|
||||
let writer = self.recording.writer();
|
||||
let job_session_id = session_id.to_string();
|
||||
let memory_limit = self.settings.summary.recording_memory_limit_bytes as usize;
|
||||
let include_io_labels = self.settings.summary.recording_include_io_labels;
|
||||
let include_timestamps = self.settings.summary.recording_include_timestamps;
|
||||
let memory_limit = self.settings.summary().recording_memory_limit_bytes as usize;
|
||||
let include_io_labels = self.settings.summary().recording_include_io_labels;
|
||||
let include_timestamps = self.settings.summary().recording_include_timestamps;
|
||||
let task = cx.background_spawn(async move {
|
||||
writer.flush();
|
||||
manager.set_memory_limit(memory_limit);
|
||||
@@ -249,11 +249,11 @@ impl NyaTermApp {
|
||||
session_name: &str,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if !self.settings.summary.recording_auto_start {
|
||||
if !self.settings.summary().recording_auto_start {
|
||||
return;
|
||||
}
|
||||
let path = recording_file_path(
|
||||
&self.settings.summary,
|
||||
self.settings.summary(),
|
||||
self.runtime.config_dir(),
|
||||
session_name,
|
||||
);
|
||||
|
||||
@@ -119,7 +119,7 @@ impl NyaTermApp {
|
||||
}
|
||||
let delay_ms = u64::from(
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_duplicate_session_command_delay_ms,
|
||||
);
|
||||
self.session.dialogs.open_startup_command(action, delay_ms);
|
||||
|
||||
@@ -239,7 +239,7 @@ impl NyaTermApp {
|
||||
view.append_text(banner);
|
||||
} else {
|
||||
let mut view = TerminalViewState::new();
|
||||
view.set_encoding(&self.settings.summary.interaction_default_encoding);
|
||||
view.set_encoding(&self.settings.summary().interaction_default_encoding);
|
||||
view.append_text(banner);
|
||||
self.terminal
|
||||
.view
|
||||
|
||||
@@ -10,7 +10,7 @@ impl NyaTermApp {
|
||||
metadata: SessionRuntimeMetadata,
|
||||
) {
|
||||
self.session.register_session_metadata(session_id, metadata);
|
||||
let encoding = self.settings.summary.interaction_default_encoding.clone();
|
||||
let encoding = self.settings.summary().interaction_default_encoding.clone();
|
||||
let view = self
|
||||
.terminal
|
||||
.view
|
||||
|
||||
@@ -547,7 +547,7 @@ impl NyaTermApp {
|
||||
session_id.clone(),
|
||||
TerminalViewState::from_output_with_encoding(
|
||||
seed_output,
|
||||
&self.settings.summary.interaction_default_encoding,
|
||||
&self.settings.summary().interaction_default_encoding,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -595,7 +595,7 @@ impl NyaTermApp {
|
||||
// Do not append local log text through the full terminal decode path
|
||||
// on connect success — that competes with the first SSH/PTY frames.
|
||||
// Auto-recording file open is deferred to the idle plane.
|
||||
if self.settings.summary.recording_auto_start {
|
||||
if self.settings.summary().recording_auto_start {
|
||||
self.recording
|
||||
.schedule_auto_start(session_id.clone(), session_info.name.clone());
|
||||
}
|
||||
|
||||
@@ -316,9 +316,9 @@ impl NyaTermApp {
|
||||
SshSessionConfigBuildContext {
|
||||
config_dir: self.runtime.config_dir().to_path_buf(),
|
||||
portable_key_path: self.runtime.portable_key_path().map(ToOwned::to_owned),
|
||||
host_key_policy: self.settings.summary.host_key_policy.clone(),
|
||||
x11_display: self.settings.summary.x11_display.clone(),
|
||||
keep_alive_interval_secs: self.settings.summary.terminal_keep_alive_interval,
|
||||
host_key_policy: self.settings.summary().host_key_policy.clone(),
|
||||
x11_display: self.settings.summary().x11_display.clone(),
|
||||
keep_alive_interval_secs: self.settings.summary().terminal_keep_alive_interval,
|
||||
host_key_prompts: self.session.prompts.host_key_broker(),
|
||||
credential_prompts: self.session.prompts.credential_broker(),
|
||||
otp_provider: self.session.prompts.otp_provider(),
|
||||
|
||||
@@ -18,7 +18,7 @@ impl NyaTermApp {
|
||||
/// Connect/register must not open the config database or rewrite settings on
|
||||
/// the UI thread — that path was a major connect-time freeze source.
|
||||
pub(in crate::features) fn persist_open_tabs(&mut self) {
|
||||
if !self.settings.summary.startup_restore {
|
||||
if !self.settings.summary().startup_restore {
|
||||
return;
|
||||
}
|
||||
self.terminal.view.runtime.open_tabs_persist_dirty = true;
|
||||
@@ -28,7 +28,7 @@ impl NyaTermApp {
|
||||
|
||||
/// Force a durable open-tabs write (window close / explicit quit paths).
|
||||
pub(in crate::features) fn flush_open_tabs_now(&mut self) {
|
||||
if !self.settings.summary.startup_restore {
|
||||
if !self.settings.summary().startup_restore {
|
||||
self.terminal.view.runtime.open_tabs_persist_dirty = false;
|
||||
self.terminal.view.runtime.window_layout_persist_dirty = false;
|
||||
return;
|
||||
@@ -44,14 +44,14 @@ impl NyaTermApp {
|
||||
/// rewriting settings is never done on the UI tick — that freezes connect
|
||||
/// and the first idle frame after connect.
|
||||
pub(in crate::features) fn flush_pending_session_persistence(&mut self) {
|
||||
if !self.settings.summary.startup_restore {
|
||||
if !self.settings.summary().startup_restore {
|
||||
self.terminal.view.runtime.open_tabs_persist_dirty = false;
|
||||
self.terminal.view.runtime.window_layout_persist_dirty = false;
|
||||
return;
|
||||
}
|
||||
let need_tabs = self.terminal.view.runtime.open_tabs_persist_dirty;
|
||||
let need_layout = self.terminal.view.runtime.window_layout_persist_dirty
|
||||
&& self.settings.summary.startup_restore_window_layout;
|
||||
&& self.settings.summary().startup_restore_window_layout;
|
||||
if !need_tabs && !need_layout {
|
||||
return;
|
||||
}
|
||||
@@ -122,14 +122,14 @@ impl NyaTermApp {
|
||||
|
||||
/// Synchronous durable write used by window-close / quit (must not race exit).
|
||||
fn flush_pending_session_persistence_sync(&mut self) {
|
||||
if !self.settings.summary.startup_restore {
|
||||
if !self.settings.summary().startup_restore {
|
||||
self.terminal.view.runtime.open_tabs_persist_dirty = false;
|
||||
self.terminal.view.runtime.window_layout_persist_dirty = false;
|
||||
return;
|
||||
}
|
||||
let need_tabs = self.terminal.view.runtime.open_tabs_persist_dirty;
|
||||
let need_layout = self.terminal.view.runtime.window_layout_persist_dirty
|
||||
&& self.settings.summary.startup_restore_window_layout;
|
||||
&& self.settings.summary().startup_restore_window_layout;
|
||||
if !need_tabs && !need_layout {
|
||||
return;
|
||||
}
|
||||
@@ -339,7 +339,7 @@ impl NyaTermApp {
|
||||
if !should_restore {
|
||||
return;
|
||||
}
|
||||
if !self.settings.summary.startup_restore {
|
||||
if !self.settings.summary().startup_restore {
|
||||
self.mark_startup_restore_complete();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ impl NyaTermApp {
|
||||
x11_forwarding: false,
|
||||
x11_display: String::new(),
|
||||
deferred_pty: true,
|
||||
keep_alive_interval_secs: self.settings.summary.terminal_keep_alive_interval,
|
||||
keep_alive_interval_secs: self.settings.summary().terminal_keep_alive_interval,
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
pixel_width: 0,
|
||||
@@ -136,7 +136,7 @@ impl NyaTermApp {
|
||||
host_key_verifier: Some(Arc::new(NativeHostKeyVerifier {
|
||||
config_dir: self.runtime.config_dir().to_path_buf(),
|
||||
portable_key_path: self.runtime.portable_key_path().map(ToOwned::to_owned),
|
||||
policy: self.settings.summary.host_key_policy.clone(),
|
||||
policy: self.settings.summary().host_key_policy.clone(),
|
||||
prompt_broker: self.session.prompts.host_key_broker(),
|
||||
})),
|
||||
credential_provider: Some(self.session.prompts.credential_broker()),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Compatibility-sensitive settings state shared by the settings feature owner.
|
||||
|
||||
pub(in crate::features) struct SettingsMasterPasswordState {
|
||||
pub enabled: bool,
|
||||
pub draft: String,
|
||||
pub(super) struct SettingsMasterPasswordState {
|
||||
pub(super) enabled: bool,
|
||||
pub(super) draft: String,
|
||||
}
|
||||
|
||||
impl SettingsMasterPasswordState {
|
||||
|
||||
@@ -11,4 +11,6 @@ mod state;
|
||||
pub(in crate::features) use security_state::{
|
||||
SecurityCatalogState, SecurityFeatureFocus, SecurityFeatureState,
|
||||
};
|
||||
pub(in crate::features) use state::{SearchEngineMenu, SettingsFeatureFocus, SettingsFeatureState};
|
||||
pub(in crate::features) use state::{
|
||||
SearchEngineMenu, SettingsFeatureFocus, SettingsFeatureState, UiLayoutSettingsUpdate,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ impl NyaTermApp {
|
||||
self.cloud_sync.settings_draft_snapshot();
|
||||
let (ai_settings, ai_model_draft, ai_base_url_draft, ai_secret_draft) =
|
||||
self.ai.settings_draft_snapshot();
|
||||
let master_password = self.settings.master_password();
|
||||
self.shell
|
||||
.set_settings_draft_snapshot(SettingsDraftSnapshot {
|
||||
settings: self.settings.summary.clone(),
|
||||
@@ -29,8 +30,8 @@ impl NyaTermApp {
|
||||
translation_settings,
|
||||
translation_secret_draft,
|
||||
keyword_highlights: self.settings.keyword_config.clone(),
|
||||
master_password_enabled: self.settings.master_password.enabled,
|
||||
master_password_draft: self.settings.master_password.draft.clone(),
|
||||
master_password_enabled: master_password.enabled,
|
||||
master_password_draft: master_password.draft.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,7 +39,8 @@ impl NyaTermApp {
|
||||
let Some(snapshot) = self.shell.settings_draft_snapshot() else {
|
||||
return false;
|
||||
};
|
||||
snapshot.settings != self.settings.summary
|
||||
let master_password = self.settings.master_password();
|
||||
snapshot.settings != *self.settings.summary()
|
||||
|| !self.ai.settings_draft_matches(
|
||||
&snapshot.ai_settings,
|
||||
&snapshot.ai_model_draft,
|
||||
@@ -53,9 +55,9 @@ impl NyaTermApp {
|
||||
&snapshot.translation_settings,
|
||||
&snapshot.translation_secret_draft,
|
||||
)
|
||||
|| snapshot.keyword_highlights != self.settings.keyword_config
|
||||
|| snapshot.master_password_enabled != self.settings.master_password.enabled
|
||||
|| snapshot.master_password_draft != self.settings.master_password.draft
|
||||
|| snapshot.keyword_highlights != *self.settings.keyword_config()
|
||||
|| snapshot.master_password_enabled != master_password.enabled
|
||||
|| snapshot.master_password_draft != master_password.draft
|
||||
}
|
||||
|
||||
/// Returns true when a settings save should stay in the in-memory draft.
|
||||
@@ -78,12 +80,11 @@ impl NyaTermApp {
|
||||
if !settings.enabled {
|
||||
return None;
|
||||
}
|
||||
if !self.settings.master_password.enabled {
|
||||
let master_password = self.settings.master_password();
|
||||
if !master_password.enabled {
|
||||
return Some("Enable a master password before enabling cloud sync".to_string());
|
||||
}
|
||||
if !self.settings.summary.has_master_password
|
||||
&& self.settings.master_password.draft.is_empty()
|
||||
{
|
||||
if !self.settings.summary().has_master_password && master_password.draft.is_empty() {
|
||||
return Some("Enter a master password before enabling cloud sync".to_string());
|
||||
}
|
||||
let missing = match settings.provider.as_str() {
|
||||
@@ -216,16 +217,17 @@ impl NyaTermApp {
|
||||
return;
|
||||
}
|
||||
|
||||
let settings = self.settings.summary.clone();
|
||||
let settings = self.settings.summary().clone();
|
||||
let ai_settings = self.pending_ai_settings();
|
||||
let cloud_sync_settings = self.cloud_sync.pending_settings();
|
||||
let translation_settings = self.translation.pending_settings();
|
||||
let keyword_highlights = self.settings.keyword_config.clone();
|
||||
let master_password_update = if self.settings.master_password.draft.is_empty() {
|
||||
(self.settings.summary.has_master_password && !self.settings.master_password.enabled)
|
||||
let keyword_highlights = self.settings.keyword_config().clone();
|
||||
let master_password = self.settings.master_password();
|
||||
let master_password_update = if master_password.draft.is_empty() {
|
||||
(self.settings.summary().has_master_password && !master_password.enabled)
|
||||
.then_some(None)
|
||||
} else {
|
||||
Some(Some(self.settings.master_password.draft.clone()))
|
||||
Some(Some(master_password.draft.to_string()))
|
||||
};
|
||||
let result = ConnectionStore::open_with_portable_key_path(
|
||||
self.runtime.config_dir(),
|
||||
@@ -343,14 +345,17 @@ impl NyaTermApp {
|
||||
snapshot.translation_settings,
|
||||
snapshot.translation_secret_draft,
|
||||
);
|
||||
self.settings.keyword_config = snapshot.keyword_highlights;
|
||||
self.settings.master_password.enabled = snapshot.master_password_enabled;
|
||||
self.settings.master_password.draft = snapshot.master_password_draft;
|
||||
self.settings
|
||||
.replace_keyword_config(snapshot.keyword_highlights);
|
||||
self.settings.restore_master_password_draft(
|
||||
snapshot.master_password_enabled,
|
||||
snapshot.master_password_draft,
|
||||
);
|
||||
self.recording
|
||||
.set_memory_limit(self.settings.summary.recording_memory_limit_bytes as usize);
|
||||
.set_memory_limit(self.settings.summary().recording_memory_limit_bytes as usize);
|
||||
self.transfer
|
||||
.set_duplicate_policy(SftpDuplicatePolicy::from_legacy_value(
|
||||
&self.settings.summary.transfer_duplicate_strategy,
|
||||
&self.settings.summary().transfer_duplicate_strategy,
|
||||
));
|
||||
self.sync_terminal_encodings_from_settings();
|
||||
self.invalidate_terminal_cell_metrics(cx);
|
||||
@@ -373,8 +378,7 @@ impl NyaTermApp {
|
||||
pub(in crate::features) fn toggle_settings_master_password(&mut self, cx: &mut Context<Self>) {
|
||||
self.terminal.view.status = match self
|
||||
.settings
|
||||
.master_password
|
||||
.toggle(self.cloud_sync.settings().enabled)
|
||||
.toggle_master_password(self.cloud_sync.settings().enabled)
|
||||
{
|
||||
Ok(true) => "master password enabled; enter a password".to_string(),
|
||||
Ok(false) => "master password removal staged".to_string(),
|
||||
@@ -389,7 +393,7 @@ impl NyaTermApp {
|
||||
text: String,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if !self.settings.master_password.edit_draft(text) {
|
||||
if !self.settings.edit_master_password_draft(text) {
|
||||
return;
|
||||
}
|
||||
self.terminal.view.status = "master password edited; apply to persist".to_string();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
//! Authoritative application settings and grouped state for the settings experience.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use gpui::FocusHandle;
|
||||
use nyaterm_core::{
|
||||
AppSettingsSummary, KeywordHighlightConfig, KeywordHighlightRule, SearchEngineConfig,
|
||||
@@ -14,9 +16,9 @@ use super::catalog::{SettingsMasterPasswordState, StoreStatus};
|
||||
|
||||
pub(in crate::features) struct SettingsFeatureState {
|
||||
/// Compatibility-sensitive values loaded and persisted through `nyaterm-core`.
|
||||
pub summary: AppSettingsSummary,
|
||||
pub keyword_config: KeywordHighlightConfig,
|
||||
pub master_password: SettingsMasterPasswordState,
|
||||
pub(super) summary: AppSettingsSummary,
|
||||
pub(super) keyword_config: KeywordHighlightConfig,
|
||||
pub(super) master_password: SettingsMasterPasswordState,
|
||||
pub(super) store_status: StoreStatus,
|
||||
search_engines: SearchEngineSettingsState,
|
||||
keyword_highlights: KeywordHighlightSettingsState,
|
||||
@@ -45,6 +47,37 @@ pub(in crate::features) struct StoreStatusView<'a> {
|
||||
pub ready: bool,
|
||||
}
|
||||
|
||||
/// Borrowed staged master-password state. Deliberately does not implement
|
||||
/// `Debug` so the secret draft cannot be exposed through aggregate logging.
|
||||
pub(in crate::features) struct MasterPasswordView<'a> {
|
||||
pub enabled: bool,
|
||||
pub draft: &'a str,
|
||||
}
|
||||
|
||||
pub(in crate::features) struct UiLayoutSettingsUpdate {
|
||||
pub left_panel_width: u32,
|
||||
pub right_panel_width: u32,
|
||||
pub transfer_height: u32,
|
||||
pub quick_command_height: u32,
|
||||
pub quick_command_visible: bool,
|
||||
pub serial_send_height: u32,
|
||||
pub serial_send_visible: bool,
|
||||
pub active_left_panel: Option<String>,
|
||||
pub active_right_panel: Option<String>,
|
||||
pub left_panel_collapsed: bool,
|
||||
pub right_panel_collapsed: bool,
|
||||
pub saved_connections_sort_mode: String,
|
||||
pub activity_bar_left_top: Vec<String>,
|
||||
pub activity_bar_left_bottom: Vec<String>,
|
||||
pub activity_bar_right_top: Vec<String>,
|
||||
pub activity_bar_right_bottom: Vec<String>,
|
||||
pub activity_bar_show_labels: bool,
|
||||
pub panel_multi_open: bool,
|
||||
pub left_open_panels: Vec<String>,
|
||||
pub right_open_panels: Vec<String>,
|
||||
pub panel_stack_sizes: HashMap<String, u32>,
|
||||
}
|
||||
|
||||
struct SearchEngineSettingsState {
|
||||
expanded_index: Option<usize>,
|
||||
icon_picker_index: Option<usize>,
|
||||
@@ -147,10 +180,338 @@ impl SettingsFeatureState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rebase_master_password(&mut self) {
|
||||
pub(in crate::features) fn rebase_master_password(&mut self) {
|
||||
self.master_password.reset(self.summary.has_master_password);
|
||||
}
|
||||
|
||||
pub(in crate::features) fn summary(&self) -> &AppSettingsSummary {
|
||||
&self.summary
|
||||
}
|
||||
|
||||
pub(in crate::features) fn replace_summary(&mut self, summary: AppSettingsSummary) {
|
||||
self.summary = summary;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn keyword_config(&self) -> &KeywordHighlightConfig {
|
||||
&self.keyword_config
|
||||
}
|
||||
|
||||
pub(in crate::features) fn replace_keyword_config(&mut self, config: KeywordHighlightConfig) {
|
||||
self.keyword_config = config;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_keyword_highlights(&mut self) -> bool {
|
||||
self.keyword_config.enabled = !self.keyword_config.enabled;
|
||||
self.keyword_config.enabled
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_keyword_highlights_wrapped(&mut self) -> bool {
|
||||
self.keyword_config.across_wrapped_lines = !self.keyword_config.across_wrapped_lines;
|
||||
self.keyword_config.across_wrapped_lines
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_keyword_highlight_builtin(&mut self, rule_id: String) {
|
||||
let enabled = self
|
||||
.keyword_config
|
||||
.builtin_rules
|
||||
.get(&rule_id)
|
||||
.copied()
|
||||
.unwrap_or(true);
|
||||
self.keyword_config.builtin_rules.insert(rule_id, !enabled);
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_keyword_highlight_rule(&mut self, rule_id: &str) -> bool {
|
||||
let Some(rule) = self
|
||||
.keyword_config
|
||||
.rules
|
||||
.iter_mut()
|
||||
.find(|rule| rule.id == rule_id)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
rule.enabled = !rule.enabled;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_keyword_highlight_rule_color(
|
||||
&mut self,
|
||||
rule_id: &str,
|
||||
dark: bool,
|
||||
color: String,
|
||||
) -> bool {
|
||||
let Some(rule) = self
|
||||
.keyword_config
|
||||
.rules
|
||||
.iter_mut()
|
||||
.find(|rule| rule.id == rule_id)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if dark {
|
||||
rule.color_dark = color;
|
||||
} else {
|
||||
rule.color_light = color;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn apply_keyword_highlight_rule_input(
|
||||
&mut self,
|
||||
rule_id: &str,
|
||||
field: KeywordHighlightEditorField,
|
||||
text: String,
|
||||
) -> bool {
|
||||
let Some(rule) = self
|
||||
.keyword_config
|
||||
.rules
|
||||
.iter_mut()
|
||||
.find(|rule| rule.id == rule_id)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
match field {
|
||||
KeywordHighlightEditorField::Name => rule.name = text,
|
||||
KeywordHighlightEditorField::Patterns => {
|
||||
rule.patterns = text.split('\n').map(ToOwned::to_owned).collect();
|
||||
}
|
||||
KeywordHighlightEditorField::ColorDark => rule.color_dark = text,
|
||||
KeywordHighlightEditorField::ColorLight => rule.color_light = text,
|
||||
}
|
||||
self.begin_keyword_highlight_edit(rule_id.to_string(), field);
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn master_password(&self) -> MasterPasswordView<'_> {
|
||||
MasterPasswordView {
|
||||
enabled: self.master_password.enabled,
|
||||
draft: &self.master_password.draft,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::features) fn restore_master_password_draft(
|
||||
&mut self,
|
||||
enabled: bool,
|
||||
draft: String,
|
||||
) {
|
||||
self.master_password.enabled = enabled;
|
||||
self.master_password.draft = draft;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_master_password(
|
||||
&mut self,
|
||||
cloud_sync_enabled: bool,
|
||||
) -> Result<bool, &'static str> {
|
||||
self.master_password.toggle(cloud_sync_enabled)
|
||||
}
|
||||
|
||||
pub(in crate::features) fn edit_master_password_draft(&mut self, text: String) -> bool {
|
||||
self.master_password.edit_draft(text)
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_quick_command_view_mode(&mut self, mode: String) {
|
||||
self.summary.ui_quick_cmd_view_mode = mode;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_quick_command_sort_mode(&mut self, mode: String) {
|
||||
self.summary.ui_quick_cmd_sort_mode = mode;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_saved_connections_sort_mode(&mut self, mode: String) {
|
||||
self.summary.ui_saved_connections_sort_mode = mode;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_header_status_mode(&mut self, mode: String) {
|
||||
self.summary.ui_header_status_mode = mode;
|
||||
self.summary.ui_header_status_visible = true;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_header_status_visible(&mut self, visible: bool) {
|
||||
self.summary.ui_header_status_visible = visible;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_keybindings(&mut self, keybindings: HashMap<String, String>) {
|
||||
self.summary.keybindings = keybindings;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_transfer_download_path(&mut self, path: String) {
|
||||
self.summary.transfer_download_path = path;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_recording_path(&mut self, path: String) {
|
||||
self.summary.recording_path = path;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_transfer_default_editor(&mut self, path: String) {
|
||||
self.summary.transfer_default_editor = path;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_tab_double_click_action(&mut self, action: String) {
|
||||
self.summary.interaction_tab_double_click_action = action;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_tab_middle_click_action(&mut self, action: String) {
|
||||
self.summary.interaction_tab_middle_click_action = action;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_tab_right_click_action(&mut self, action: String) {
|
||||
self.summary.interaction_tab_right_click_action = action;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn apply_ui_layout(&mut self, update: UiLayoutSettingsUpdate) {
|
||||
self.summary.ui_left_panel_width = update.left_panel_width;
|
||||
self.summary.ui_right_panel_width = update.right_panel_width;
|
||||
self.summary.ui_transfer_height = update.transfer_height;
|
||||
self.summary.ui_quick_cmd_height = update.quick_command_height;
|
||||
self.summary.ui_quick_cmd_visible = update.quick_command_visible;
|
||||
self.summary.ui_serial_send_height = update.serial_send_height;
|
||||
self.summary.ui_serial_send_visible = update.serial_send_visible;
|
||||
self.summary.ui_active_left_panel = update.active_left_panel;
|
||||
self.summary.ui_active_right_panel = update.active_right_panel;
|
||||
self.summary.ui_left_panel_collapsed = update.left_panel_collapsed;
|
||||
self.summary.ui_right_panel_collapsed = update.right_panel_collapsed;
|
||||
self.summary.ui_saved_connections_sort_mode = update.saved_connections_sort_mode;
|
||||
self.summary.ui_activity_bar_left_top = update.activity_bar_left_top;
|
||||
self.summary.ui_activity_bar_left_bottom = update.activity_bar_left_bottom;
|
||||
self.summary.ui_activity_bar_right_top = update.activity_bar_right_top;
|
||||
self.summary.ui_activity_bar_right_bottom = update.activity_bar_right_bottom;
|
||||
self.summary.ui_activity_bar_show_labels = update.activity_bar_show_labels;
|
||||
self.summary.ui_panel_multi_open = update.panel_multi_open;
|
||||
self.summary.ui_left_open_panels = update.left_open_panels;
|
||||
self.summary.ui_right_open_panels = update.right_open_panels;
|
||||
self.summary.ui_panel_stack_sizes = update.panel_stack_sizes;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_appearance_theme(&mut self, theme: String) {
|
||||
self.summary.theme = theme;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_terminal_font_family(&mut self, family: String) -> bool {
|
||||
if self.summary.terminal_font_family == family {
|
||||
return false;
|
||||
}
|
||||
self.summary.terminal_font_family = family;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_terminal_font_size(&mut self, size: u16) -> bool {
|
||||
if self.summary.terminal_font_size == size {
|
||||
return false;
|
||||
}
|
||||
self.summary.terminal_font_size = size;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_cursor_style(&mut self, style: String) {
|
||||
self.summary.cursor_style = style;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_cursor_blink(&mut self) -> bool {
|
||||
self.summary.cursor_blink = !self.summary.cursor_blink;
|
||||
self.summary.cursor_blink
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_terminal_theme(&mut self, theme: Option<String>) {
|
||||
self.summary.terminal_theme = theme;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_minimum_contrast_ratio(&mut self, ratio: String) -> bool {
|
||||
if self.summary.minimum_contrast_ratio == ratio {
|
||||
return false;
|
||||
}
|
||||
self.summary.minimum_contrast_ratio = ratio;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_ui_font_family(&mut self, family: String) {
|
||||
self.summary.ui_font_family = family;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_ui_font_size(&mut self, size: u16) {
|
||||
self.summary.ui_font_size = size;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_terminal_font_weight(&mut self, weight: u16) -> bool {
|
||||
if self.summary.terminal_font_weight == weight {
|
||||
return false;
|
||||
}
|
||||
self.summary.terminal_font_weight = weight;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_terminal_font_weight_bold(&mut self, weight: u16) -> bool {
|
||||
if self.summary.terminal_font_weight_bold == weight {
|
||||
return false;
|
||||
}
|
||||
self.summary.terminal_font_weight_bold = weight;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn select_background_image(&mut self, path: String) {
|
||||
self.summary.background_image_path = Some(path);
|
||||
if self.summary.background_image_fit.trim().is_empty() {
|
||||
self.summary.background_image_fit = "cover".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::features) fn clear_background_image(&mut self) {
|
||||
self.summary.background_image_path = None;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_background_image_fit(&mut self, fit: String) {
|
||||
self.summary.background_image_fit = fit;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_background_image_opacity(&mut self, opacity: u8) -> bool {
|
||||
if self.summary.background_image_opacity == opacity {
|
||||
return false;
|
||||
}
|
||||
self.summary.background_image_opacity = opacity;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_background_content_opacity(&mut self, opacity: u8) -> bool {
|
||||
if self.summary.background_content_opacity == opacity {
|
||||
return false;
|
||||
}
|
||||
self.summary.background_content_opacity = opacity;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_file_explorer_auto_sync_cwd(
|
||||
&mut self,
|
||||
connection_id: String,
|
||||
) -> bool {
|
||||
let ids = &mut self.summary.ui_file_explorer_auto_sync_cwd_connection_ids;
|
||||
let was_enabled = ids.iter().any(|id| id == &connection_id);
|
||||
ids.retain(|id| id != &connection_id);
|
||||
if !was_enabled {
|
||||
ids.push(connection_id);
|
||||
}
|
||||
!was_enabled
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_file_explorer_hidden_files(&mut self) -> bool {
|
||||
self.summary.ui_file_explorer_show_hidden_files =
|
||||
!self.summary.ui_file_explorer_show_hidden_files;
|
||||
self.summary.ui_file_explorer_show_hidden_files
|
||||
}
|
||||
|
||||
pub(in crate::features) fn set_file_explorer_favorites(
|
||||
&mut self,
|
||||
connection_id: String,
|
||||
favorites: Vec<String>,
|
||||
) {
|
||||
if favorites.is_empty() {
|
||||
self.summary
|
||||
.ui_file_explorer_favorite_dirs_by_connection_id
|
||||
.remove(&connection_id);
|
||||
} else {
|
||||
self.summary
|
||||
.ui_file_explorer_favorite_dirs_by_connection_id
|
||||
.insert(connection_id, favorites);
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::features) fn store_status(&self) -> StoreStatusView<'_> {
|
||||
StoreStatusView {
|
||||
path: &self.store_status.path,
|
||||
@@ -570,12 +931,16 @@ fn adjusted_index_after_remove(value: Option<usize>, removed: usize) -> Option<u
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use gpui::TestAppContext;
|
||||
use nyaterm_core::{
|
||||
AppSettingsSummary, KeywordHighlightConfig, KeywordHighlightRule, SearchEngineConfig,
|
||||
};
|
||||
|
||||
use super::{SearchEngineMenu, SettingsFeatureFocus, SettingsFeatureState};
|
||||
use super::{
|
||||
SearchEngineMenu, SettingsFeatureFocus, SettingsFeatureState, UiLayoutSettingsUpdate,
|
||||
};
|
||||
use crate::models::{
|
||||
ConfigPathPromptKind, KeywordHighlightEditorField, SnapshotPasswordPromptKind,
|
||||
};
|
||||
@@ -717,4 +1082,96 @@ mod tests {
|
||||
assert_eq!(status.message, "store reopened");
|
||||
assert!(status.ready);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_owner_applies_ui_layout_as_one_transition() {
|
||||
let mut state = settings_state();
|
||||
|
||||
state.apply_ui_layout(UiLayoutSettingsUpdate {
|
||||
left_panel_width: 320,
|
||||
right_panel_width: 360,
|
||||
transfer_height: 240,
|
||||
quick_command_height: 180,
|
||||
quick_command_visible: false,
|
||||
serial_send_height: 160,
|
||||
serial_send_visible: true,
|
||||
active_left_panel: Some("connections".to_string()),
|
||||
active_right_panel: Some("sftp".to_string()),
|
||||
left_panel_collapsed: false,
|
||||
right_panel_collapsed: true,
|
||||
saved_connections_sort_mode: "recent".to_string(),
|
||||
activity_bar_left_top: vec!["connections".to_string()],
|
||||
activity_bar_left_bottom: vec!["settings".to_string()],
|
||||
activity_bar_right_top: vec!["sftp".to_string()],
|
||||
activity_bar_right_bottom: vec!["ai".to_string()],
|
||||
activity_bar_show_labels: true,
|
||||
panel_multi_open: true,
|
||||
left_open_panels: vec!["connections".to_string()],
|
||||
right_open_panels: vec!["sftp".to_string()],
|
||||
panel_stack_sizes: HashMap::from([("left:connections".to_string(), 600)]),
|
||||
});
|
||||
|
||||
let summary = state.summary();
|
||||
assert_eq!(summary.ui_left_panel_width, 320);
|
||||
assert_eq!(summary.ui_right_panel_width, 360);
|
||||
assert!(!summary.ui_quick_cmd_visible);
|
||||
assert!(summary.ui_serial_send_visible);
|
||||
assert_eq!(summary.ui_active_left_panel.as_deref(), Some("connections"));
|
||||
assert!(summary.ui_right_panel_collapsed);
|
||||
assert_eq!(summary.ui_activity_bar_right_bottom, ["ai"]);
|
||||
assert_eq!(summary.ui_panel_stack_sizes["left:connections"], 600);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_owner_controls_keyword_catalog_transitions() {
|
||||
let mut state = settings_state();
|
||||
state.add_keyword_highlight_rule(KeywordHighlightRule {
|
||||
id: "warning".to_string(),
|
||||
name: "warning".to_string(),
|
||||
patterns: vec!["WARN".to_string()],
|
||||
color_dark: "#ffffff".to_string(),
|
||||
color_light: "#000000".to_string(),
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
assert!(state.toggle_keyword_highlights());
|
||||
assert!(state.toggle_keyword_highlights_wrapped());
|
||||
state.toggle_keyword_highlight_builtin("builtin-error".to_string());
|
||||
assert!(state.toggle_keyword_highlight_rule("warning"));
|
||||
assert!(state.set_keyword_highlight_rule_color("warning", true, "#123456".to_string()));
|
||||
assert!(state.apply_keyword_highlight_rule_input(
|
||||
"warning",
|
||||
KeywordHighlightEditorField::Patterns,
|
||||
"WARN\nERROR".to_string(),
|
||||
));
|
||||
|
||||
let config = state.keyword_config();
|
||||
assert!(config.enabled);
|
||||
assert!(config.across_wrapped_lines);
|
||||
assert!(!config.builtin_rules["builtin-error"]);
|
||||
assert!(!config.rules[0].enabled);
|
||||
assert_eq!(config.rules[0].color_dark, "#123456");
|
||||
assert_eq!(config.rules[0].patterns, ["WARN", "ERROR"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_owner_exposes_master_password_as_a_borrowed_view() {
|
||||
let mut state = settings_state();
|
||||
assert_eq!(state.master_password.toggle(false), Ok(true));
|
||||
assert!(
|
||||
state
|
||||
.master_password
|
||||
.edit_draft("replacement secret".to_string())
|
||||
);
|
||||
|
||||
let view = state.master_password();
|
||||
assert!(view.enabled);
|
||||
assert_eq!(view.draft, "replacement secret");
|
||||
|
||||
state.summary.has_master_password = false;
|
||||
state.rebase_master_password();
|
||||
let view = state.master_password();
|
||||
assert!(!view.enabled);
|
||||
assert!(view.draft.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ impl Render for SettingsWindow {
|
||||
(
|
||||
app.theme_palette(),
|
||||
app.gpui_ui_font_family(),
|
||||
app.settings.summary.ui_font_size.clamp(12, 24) as f32,
|
||||
app.settings.summary().ui_font_size.clamp(12, 24) as f32,
|
||||
app.tr("settings.title").to_string(),
|
||||
)
|
||||
});
|
||||
|
||||
@@ -89,26 +89,13 @@ impl NyaTermApp {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(in crate::features) fn sync_activity_layout_to_settings(&mut self) {
|
||||
self.settings.summary.ui_activity_bar_left_top =
|
||||
self.shell.chrome.activity_bar_layout.left_top.clone();
|
||||
self.settings.summary.ui_activity_bar_left_bottom =
|
||||
self.shell.chrome.activity_bar_layout.left_bottom.clone();
|
||||
self.settings.summary.ui_activity_bar_right_top =
|
||||
self.shell.chrome.activity_bar_layout.right_top.clone();
|
||||
self.settings.summary.ui_activity_bar_right_bottom =
|
||||
self.shell.chrome.activity_bar_layout.right_bottom.clone();
|
||||
self.settings.summary.ui_activity_bar_show_labels =
|
||||
self.shell.chrome.activity_bar_layout.show_labels;
|
||||
}
|
||||
|
||||
pub(in crate::features) fn apply_activity_layout_from_settings(&mut self) {
|
||||
self.shell.chrome.activity_bar_layout = ActivityBarLayoutState {
|
||||
left_top: self.settings.summary.ui_activity_bar_left_top.clone(),
|
||||
left_bottom: self.settings.summary.ui_activity_bar_left_bottom.clone(),
|
||||
right_top: self.settings.summary.ui_activity_bar_right_top.clone(),
|
||||
right_bottom: self.settings.summary.ui_activity_bar_right_bottom.clone(),
|
||||
show_labels: self.settings.summary.ui_activity_bar_show_labels,
|
||||
left_top: self.settings.summary().ui_activity_bar_left_top.clone(),
|
||||
left_bottom: self.settings.summary().ui_activity_bar_left_bottom.clone(),
|
||||
right_top: self.settings.summary().ui_activity_bar_right_top.clone(),
|
||||
right_bottom: self.settings.summary().ui_activity_bar_right_bottom.clone(),
|
||||
show_labels: self.settings.summary().ui_activity_bar_show_labels,
|
||||
};
|
||||
self.normalize_activity_bar_layout();
|
||||
}
|
||||
|
||||
@@ -14,34 +14,34 @@ const TERMINAL_FONT_SIZE_MAX: i16 = 72;
|
||||
|
||||
impl NyaTermApp {
|
||||
pub(in crate::features) fn apply_gpui_settings(&mut self, settings: AppSettingsSummary) {
|
||||
self.settings.summary = settings;
|
||||
self.settings.replace_summary(settings);
|
||||
self.invalidate_paint_theme_caches();
|
||||
}
|
||||
|
||||
pub(in crate::features) fn gpui_terminal_font_family(&self) -> String {
|
||||
gpui_platform_font_family(
|
||||
&self.settings.summary.terminal_font_family,
|
||||
&self.settings.summary().terminal_font_family,
|
||||
gpui_terminal_font_fallback(),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
pub(in crate::features) fn gpui_ui_font_family(&self) -> String {
|
||||
let raw = if self.settings.summary.ui_font_family.trim().is_empty() {
|
||||
self.settings.summary.terminal_font_family.as_str()
|
||||
let raw = if self.settings.summary().ui_font_family.trim().is_empty() {
|
||||
self.settings.summary().terminal_font_family.as_str()
|
||||
} else {
|
||||
self.settings.summary.ui_font_family.as_str()
|
||||
self.settings.summary().ui_font_family.as_str()
|
||||
};
|
||||
gpui_platform_font_family(raw, gpui_ui_font_fallback(), false)
|
||||
}
|
||||
|
||||
pub(in crate::features) fn theme_palette(&self) -> ThemePalette {
|
||||
theme_palette(&self.settings.summary.theme)
|
||||
theme_palette(&self.settings.summary().theme)
|
||||
}
|
||||
|
||||
pub(in crate::features) fn wallpaper_enabled(&self) -> bool {
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.background_image_path
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
@@ -53,7 +53,7 @@ impl NyaTermApp {
|
||||
if !self.wallpaper_enabled() {
|
||||
return rgb(color);
|
||||
}
|
||||
let alpha = ((self.settings.summary.background_content_opacity.min(100) as f32 / 100.0)
|
||||
let alpha = ((self.settings.summary().background_content_opacity.min(100) as f32 / 100.0)
|
||||
* 255.0)
|
||||
.round() as u32;
|
||||
rgba((color << 8) | alpha.min(0xff))
|
||||
@@ -80,19 +80,19 @@ impl NyaTermApp {
|
||||
pub(in crate::features) fn resolved_keyword_highlight_rules(
|
||||
&self,
|
||||
) -> Arc<Vec<ResolvedKeywordHighlightRule>> {
|
||||
if self.settings.summary.terminal_low_latency_mode {
|
||||
if self.settings.summary().terminal_low_latency_mode {
|
||||
return Arc::new(Vec::new());
|
||||
}
|
||||
if let Some(cached) = self.terminal.paint.cached_keyword_highlight_rules.as_ref() {
|
||||
return cached.clone();
|
||||
}
|
||||
// Cache miss (settings path / first call without ensure): build once without storing.
|
||||
if !self.settings.keyword_config.enabled {
|
||||
if !self.settings.keyword_config().enabled {
|
||||
return Arc::new(Vec::new());
|
||||
}
|
||||
Arc::new(merge_keyword_highlight_rules_for_paint(
|
||||
&self.settings.keyword_config.rules,
|
||||
&self.settings.keyword_config.builtin_rules,
|
||||
&self.settings.keyword_config().rules,
|
||||
&self.settings.keyword_config().builtin_rules,
|
||||
self.terminal_theme_is_dark(),
|
||||
))
|
||||
}
|
||||
@@ -104,21 +104,21 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
fn ensure_keyword_highlight_rules_cache(&mut self) {
|
||||
if self.settings.summary.terminal_low_latency_mode {
|
||||
if self.settings.summary().terminal_low_latency_mode {
|
||||
self.terminal.paint.cached_keyword_highlight_rules = Some(Arc::new(Vec::new()));
|
||||
return;
|
||||
}
|
||||
if self.terminal.paint.cached_keyword_highlight_rules.is_some() {
|
||||
return;
|
||||
}
|
||||
let rules = if !self.settings.keyword_config.enabled {
|
||||
let rules = if !self.settings.keyword_config().enabled {
|
||||
Arc::new(Vec::new())
|
||||
} else {
|
||||
// terminal_theme_is_dark uses palette; ensure palette first.
|
||||
self.ensure_terminal_theme_palette_cache();
|
||||
Arc::new(merge_keyword_highlight_rules_for_paint(
|
||||
&self.settings.keyword_config.rules,
|
||||
&self.settings.keyword_config.builtin_rules,
|
||||
&self.settings.keyword_config().rules,
|
||||
&self.settings.keyword_config().builtin_rules,
|
||||
self.terminal_theme_is_dark(),
|
||||
))
|
||||
};
|
||||
@@ -127,16 +127,16 @@ impl NyaTermApp {
|
||||
|
||||
/// Terminal surface palette: follows optional `terminal_theme`, else UI theme.
|
||||
pub(in crate::features) fn terminal_theme_palette(&self) -> ThemePalette {
|
||||
let ui_theme = self.settings.summary.theme.as_str();
|
||||
let ui_theme = self.settings.summary().theme.as_str();
|
||||
let terminal_theme = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.terminal_theme
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or("");
|
||||
let contrast = self.settings.summary.minimum_contrast_ratio.as_str();
|
||||
let contrast = self.settings.summary().minimum_contrast_ratio.as_str();
|
||||
if let Some((cached_ui, cached_term, cached_contrast, palette)) =
|
||||
self.terminal.paint.cached_terminal_theme_palette.as_ref()
|
||||
{
|
||||
@@ -157,17 +157,17 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
fn ensure_terminal_theme_palette_cache(&mut self) {
|
||||
let ui_theme = self.settings.summary.theme.clone();
|
||||
let ui_theme = self.settings.summary().theme.clone();
|
||||
let terminal_theme = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.terminal_theme
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
let contrast = self.settings.summary.minimum_contrast_ratio.clone();
|
||||
let contrast = self.settings.summary().minimum_contrast_ratio.clone();
|
||||
if let Some((cached_ui, cached_term, cached_contrast, _)) =
|
||||
self.terminal.paint.cached_terminal_theme_palette.as_ref()
|
||||
{
|
||||
@@ -237,7 +237,7 @@ impl NyaTermApp {
|
||||
} else {
|
||||
theme
|
||||
};
|
||||
self.settings.summary.theme = theme.to_string();
|
||||
self.settings.set_appearance_theme(theme.to_string());
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
|
||||
@@ -246,10 +246,9 @@ impl NyaTermApp {
|
||||
family: &str,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.settings.summary.terminal_font_family == family {
|
||||
if !self.settings.set_terminal_font_family(family.to_string()) {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.terminal_font_family = family.to_string();
|
||||
self.invalidate_terminal_cell_metrics(cx);
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
@@ -273,22 +272,20 @@ impl NyaTermApp {
|
||||
delta: i16,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let next = (self.settings.summary.terminal_font_size as i16 + delta)
|
||||
let next = (self.settings.summary().terminal_font_size as i16 + delta)
|
||||
.clamp(TERMINAL_FONT_SIZE_MIN, TERMINAL_FONT_SIZE_MAX);
|
||||
if self.settings.summary.terminal_font_size == next as u16 {
|
||||
if !self.settings.set_terminal_font_size(next as u16) {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.terminal_font_size = next as u16;
|
||||
self.invalidate_terminal_cell_metrics(cx);
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
|
||||
pub(in crate::features) fn reset_terminal_font_size(&mut self, cx: &mut Context<Self>) {
|
||||
let default_size = AppSettingsSummary::default().terminal_font_size;
|
||||
if self.settings.summary.terminal_font_size == default_size {
|
||||
if !self.settings.set_terminal_font_size(default_size) {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.terminal_font_size = default_size;
|
||||
self.invalidate_terminal_cell_metrics(cx);
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
@@ -302,15 +299,15 @@ impl NyaTermApp {
|
||||
"underline" | "bar" => style,
|
||||
_ => "block",
|
||||
};
|
||||
self.settings.summary.cursor_style = normalized.to_string();
|
||||
self.settings.set_cursor_style(normalized.to_string());
|
||||
self.save_appearance_settings(cx);
|
||||
self.terminal.view.status = format!("cursor style → {normalized}");
|
||||
}
|
||||
|
||||
pub(in crate::features) fn toggle_cursor_blink(&mut self, cx: &mut Context<Self>) {
|
||||
self.settings.summary.cursor_blink = !self.settings.summary.cursor_blink;
|
||||
let cursor_blink = self.settings.toggle_cursor_blink();
|
||||
self.save_appearance_settings(cx);
|
||||
self.terminal.view.status = if self.settings.summary.cursor_blink {
|
||||
self.terminal.view.status = if cursor_blink {
|
||||
"cursor blink on".to_string()
|
||||
} else {
|
||||
"cursor blink off".to_string()
|
||||
@@ -322,16 +319,16 @@ impl NyaTermApp {
|
||||
theme: Option<&str>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.settings.summary.terminal_theme =
|
||||
theme.map(str::trim).filter(|s| !s.is_empty()).map(|s| {
|
||||
if s == "catppuccin" {
|
||||
"catppuccin-mocha".to_string()
|
||||
} else {
|
||||
s.to_string()
|
||||
}
|
||||
});
|
||||
let theme = theme.map(str::trim).filter(|s| !s.is_empty()).map(|s| {
|
||||
if s == "catppuccin" {
|
||||
"catppuccin-mocha".to_string()
|
||||
} else {
|
||||
s.to_string()
|
||||
}
|
||||
});
|
||||
self.settings.set_terminal_theme(theme);
|
||||
self.save_appearance_settings(cx);
|
||||
self.terminal.view.status = match self.settings.summary.terminal_theme.as_deref() {
|
||||
self.terminal.view.status = match self.settings.summary().terminal_theme.as_deref() {
|
||||
Some(id) => format!("terminal theme → {id}"),
|
||||
None => "terminal theme → follow UI".to_string(),
|
||||
};
|
||||
@@ -346,10 +343,9 @@ impl NyaTermApp {
|
||||
"3" | "4.5" | "7" | "21" => ratio,
|
||||
_ => "1",
|
||||
};
|
||||
if self.settings.summary.minimum_contrast_ratio == ratio {
|
||||
if !self.settings.set_minimum_contrast_ratio(ratio.to_string()) {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.minimum_contrast_ratio = ratio.to_string();
|
||||
self.save_appearance_settings(cx);
|
||||
self.terminal.view.status = format!("minimum contrast → {ratio}");
|
||||
}
|
||||
@@ -359,7 +355,7 @@ impl NyaTermApp {
|
||||
family: &str,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.settings.summary.ui_font_family = family.to_string();
|
||||
self.settings.set_ui_font_family(family.to_string());
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
|
||||
@@ -371,9 +367,9 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let raw = if terminal {
|
||||
&self.settings.summary.terminal_font_family
|
||||
&self.settings.summary().terminal_font_family
|
||||
} else {
|
||||
&self.settings.summary.ui_font_family
|
||||
&self.settings.summary().ui_font_family
|
||||
};
|
||||
let fallback = if terminal { "JetBrains Mono" } else { "Inter" };
|
||||
let mut fonts = appearance_font_stack(raw, fallback);
|
||||
@@ -391,9 +387,9 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let raw = if terminal {
|
||||
&self.settings.summary.terminal_font_family
|
||||
&self.settings.summary().terminal_font_family
|
||||
} else {
|
||||
&self.settings.summary.ui_font_family
|
||||
&self.settings.summary().ui_font_family
|
||||
};
|
||||
let fallback = if terminal { "JetBrains Mono" } else { "Inter" };
|
||||
let mut fonts = appearance_font_stack(raw, fallback);
|
||||
@@ -415,9 +411,9 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let raw = if terminal {
|
||||
&self.settings.summary.terminal_font_family
|
||||
&self.settings.summary().terminal_font_family
|
||||
} else {
|
||||
&self.settings.summary.ui_font_family
|
||||
&self.settings.summary().ui_font_family
|
||||
};
|
||||
let fallback = if terminal { "JetBrains Mono" } else { "Inter" };
|
||||
let mut fonts = appearance_font_stack(raw, fallback);
|
||||
@@ -447,8 +443,8 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn adjust_ui_font_size(&mut self, delta: i16, cx: &mut Context<Self>) {
|
||||
let next = (self.settings.summary.ui_font_size as i16 + delta).clamp(12, 24) as u16;
|
||||
self.settings.summary.ui_font_size = next;
|
||||
let next = (self.settings.summary().ui_font_size as i16 + delta).clamp(12, 24) as u16;
|
||||
self.settings.set_ui_font_size(next);
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
|
||||
@@ -461,10 +457,9 @@ impl NyaTermApp {
|
||||
300 | 400 | 500 | 600 | 700 | 800 => weight,
|
||||
_ => 400,
|
||||
};
|
||||
if self.settings.summary.terminal_font_weight == weight {
|
||||
if !self.settings.set_terminal_font_weight(weight) {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.terminal_font_weight = weight;
|
||||
self.invalidate_terminal_cell_metrics(cx);
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
@@ -478,10 +473,9 @@ impl NyaTermApp {
|
||||
300 | 400 | 500 | 600 | 700 | 800 => weight,
|
||||
_ => 700,
|
||||
};
|
||||
if self.settings.summary.terminal_font_weight_bold == weight {
|
||||
if !self.settings.set_terminal_font_weight_bold(weight) {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.terminal_font_weight_bold = weight;
|
||||
self.invalidate_terminal_cell_metrics(cx);
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
@@ -495,7 +489,7 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn prompt_background_image(&mut self, cx: &mut Context<Self>) {
|
||||
if self.settings.summary.background_image_path.is_some() {
|
||||
if self.settings.summary().background_image_path.is_some() {
|
||||
// allow replace
|
||||
}
|
||||
let options = PathPromptOptions {
|
||||
@@ -515,10 +509,8 @@ impl NyaTermApp {
|
||||
};
|
||||
let _ = this.update(cx, |this, cx| {
|
||||
if let Some(path) = path {
|
||||
this.settings.summary.background_image_path = Some(path.display().to_string());
|
||||
if this.settings.summary.background_image_fit.trim().is_empty() {
|
||||
this.settings.summary.background_image_fit = "cover".to_string();
|
||||
}
|
||||
this.settings
|
||||
.select_background_image(path.display().to_string());
|
||||
this.save_appearance_settings(cx);
|
||||
this.terminal.view.status = "wallpaper image selected".to_string();
|
||||
} else {
|
||||
@@ -532,7 +524,7 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn clear_background_image(&mut self, cx: &mut Context<Self>) {
|
||||
self.settings.summary.background_image_path = None;
|
||||
self.settings.clear_background_image();
|
||||
self.settings.close_appearance_menu();
|
||||
self.save_appearance_settings(cx);
|
||||
self.terminal.view.status = "wallpaper cleared".to_string();
|
||||
@@ -549,7 +541,8 @@ impl NyaTermApp {
|
||||
"tile" => "tile",
|
||||
_ => "cover",
|
||||
};
|
||||
self.settings.summary.background_image_fit = normalized.to_string();
|
||||
self.settings
|
||||
.set_background_image_fit(normalized.to_string());
|
||||
self.save_appearance_settings(cx);
|
||||
self.terminal.view.status = format!("wallpaper fit → {normalized}");
|
||||
}
|
||||
@@ -560,10 +553,9 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let next = value.min(100);
|
||||
if self.settings.summary.background_image_opacity == next {
|
||||
if !self.settings.set_background_image_opacity(next) {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.background_image_opacity = next;
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
|
||||
@@ -573,10 +565,9 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let next = value.min(100);
|
||||
if self.settings.summary.background_content_opacity == next {
|
||||
if !self.settings.set_background_content_opacity(next) {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.background_content_opacity = next;
|
||||
self.save_appearance_settings(cx);
|
||||
}
|
||||
|
||||
@@ -589,7 +580,7 @@ impl NyaTermApp {
|
||||
self.runtime.config_dir(),
|
||||
self.runtime.portable_key_path().map(ToOwned::to_owned),
|
||||
)
|
||||
.and_then(|store| store.save_appearance_settings(&self.settings.summary))
|
||||
.and_then(|store| store.save_appearance_settings(self.settings.summary()))
|
||||
{
|
||||
Ok(settings) => {
|
||||
self.apply_gpui_settings(settings);
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::features::NyaTermApp;
|
||||
impl NyaTermApp {
|
||||
pub(in crate::features) fn sync_session_event_bridge_config(&self) {
|
||||
self.session.configure_event_bridge(
|
||||
self.settings.summary.interaction_default_encoding.clone(),
|
||||
self.settings.summary().interaction_default_encoding.clone(),
|
||||
self.terminal_scrollback_line_limit(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -256,18 +256,18 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
if self.security.screen_locked()
|
||||
|| !self.settings.summary.enable_screen_lock
|
||||
|| self.settings.summary.idle_lock_minutes == 0
|
||||
|| !self.settings.summary().enable_screen_lock
|
||||
|| self.settings.summary().idle_lock_minutes == 0
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let idle_for = self.security.screen_lock_idle_for();
|
||||
let lock_after =
|
||||
Duration::from_secs(u64::from(self.settings.summary.idle_lock_minutes) * 60);
|
||||
Duration::from_secs(u64::from(self.settings.summary().idle_lock_minutes) * 60);
|
||||
if idle_for < lock_after {
|
||||
return false;
|
||||
}
|
||||
let lock_status = if self.settings.summary.has_master_password {
|
||||
let lock_status = if self.settings.summary().has_master_password {
|
||||
"Enter the master password to unlock.".to_string()
|
||||
} else {
|
||||
"No master password is configured.".to_string()
|
||||
@@ -276,9 +276,9 @@ impl NyaTermApp {
|
||||
self.forget_text_inputs("lock-screen.password");
|
||||
self.terminal.view.status = format!(
|
||||
"screen locked after {} minute(s) idle",
|
||||
self.settings.summary.idle_lock_minutes
|
||||
self.settings.summary().idle_lock_minutes
|
||||
);
|
||||
if self.settings.summary.has_master_password {
|
||||
if self.settings.summary().has_master_password {
|
||||
let field = self.text_input("lock-screen.password", "", TextInputSetup::masked(), cx);
|
||||
window.focus(&field.read(cx).focus_handle());
|
||||
} else {
|
||||
@@ -371,7 +371,7 @@ impl NyaTermApp {
|
||||
if self.terminal.view.runtime.visual_bell_ticks > 0 {
|
||||
return true;
|
||||
}
|
||||
if self.settings.summary.cursor_blink
|
||||
if self.settings.summary().cursor_blink
|
||||
&& !self.visible_terminal_session_ids().is_empty()
|
||||
&& self
|
||||
.terminal
|
||||
@@ -538,30 +538,30 @@ impl NyaTermApp {
|
||||
let right_panel = self.current_right_panel();
|
||||
|
||||
if (right_panel == Some(NavItem::Stats) || self.header_status_needs_remote_stats())
|
||||
&& self.settings.summary.ui_show_remote_stats
|
||||
&& self.settings.summary().ui_show_remote_stats
|
||||
&& !self.remote_ops.stats_is_pending()
|
||||
&& remote_refresh_due(
|
||||
self.remote_ops.stats_last_refresh_at(),
|
||||
self.settings.summary.ui_remote_stats_interval.max(1),
|
||||
self.settings.summary().ui_remote_stats_interval.max(1),
|
||||
)
|
||||
{
|
||||
self.refresh_stats(window, cx);
|
||||
dirty = true;
|
||||
} else if right_panel == Some(NavItem::Processes)
|
||||
&& self.settings.summary.ui_show_process_manager
|
||||
&& self.settings.summary().ui_show_process_manager
|
||||
&& !self.remote_ops.process_is_pending()
|
||||
&& remote_refresh_due(
|
||||
self.remote_ops.process_last_refresh_at(),
|
||||
self.settings.summary.ui_process_manager_interval.max(3),
|
||||
self.settings.summary().ui_process_manager_interval.max(3),
|
||||
)
|
||||
{
|
||||
self.refresh_processes(window, cx);
|
||||
dirty = true;
|
||||
} else if right_panel == Some(NavItem::Docker)
|
||||
&& self.settings.summary.ui_show_docker_manager
|
||||
&& self.settings.summary().ui_show_docker_manager
|
||||
&& !self.remote_ops.docker_is_pending()
|
||||
{
|
||||
let interval = self.settings.summary.ui_docker_manager_interval.max(3);
|
||||
let interval = self.settings.summary().ui_docker_manager_interval.max(3);
|
||||
if remote_refresh_due(self.remote_ops.docker_last_refresh_at(), interval) {
|
||||
self.refresh_docker(window, cx);
|
||||
dirty = true;
|
||||
|
||||
@@ -674,7 +674,7 @@ impl NyaTermApp {
|
||||
// can stay slow without stretching cursor blink to multi-second periods.
|
||||
// Under output pressure / connect settle, keep last blink phase.
|
||||
let mut surface_visual_dirty = false;
|
||||
if runtime_cursor_blink_allowed(output_pressure, self.settings.summary.cursor_blink) {
|
||||
if runtime_cursor_blink_allowed(output_pressure, self.settings.summary().cursor_blink) {
|
||||
let next_blink_at = self
|
||||
.terminal
|
||||
.view
|
||||
@@ -689,7 +689,7 @@ impl NyaTermApp {
|
||||
} else {
|
||||
self.terminal.view.runtime.cursor_blink_next_at = Some(next_blink_at);
|
||||
}
|
||||
} else if !self.settings.summary.cursor_blink {
|
||||
} else if !self.settings.summary().cursor_blink {
|
||||
if !self.terminal.view.runtime.cursor_blink_on {
|
||||
surface_visual_dirty = true;
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ impl NyaTermApp {
|
||||
self.note_zmodem_output_discontinuity(&session_id, bytes, cx);
|
||||
self.note_ai_agent_output_discontinuity(&session_id, bytes, cx);
|
||||
self.session.route_session_events_to_ui(&session_id);
|
||||
let encoding = self.settings.summary.interaction_default_encoding.clone();
|
||||
let encoding = self.settings.summary().interaction_default_encoding.clone();
|
||||
let view = self
|
||||
.terminal
|
||||
.view
|
||||
|
||||
@@ -39,7 +39,7 @@ impl NyaTermApp {
|
||||
return true;
|
||||
}
|
||||
|
||||
let keybindings = self.settings.summary.keybindings.clone();
|
||||
let keybindings = self.settings.summary().keybindings.clone();
|
||||
if shortcut_matches(event, "terminal.copy", &keybindings) {
|
||||
self.copy_terminal_selection_or_visible(cx);
|
||||
return true;
|
||||
|
||||
@@ -10,7 +10,7 @@ impl NyaTermApp {
|
||||
/// First display chord for empty-workspace / UI labels (Tauri-style chips).
|
||||
pub(in crate::features) fn display_shortcut_for(&self, id: &str, fallback: &str) -> String {
|
||||
use crate::shortcuts::{format_hotkey_for_display, shortcut_keys_for};
|
||||
let raw = shortcut_keys_for(id, &self.settings.summary.keybindings)
|
||||
let raw = shortcut_keys_for(id, &self.settings.summary().keybindings)
|
||||
.unwrap_or_else(|| fallback.to_string());
|
||||
let display = format_hotkey_for_display(&raw);
|
||||
display
|
||||
@@ -59,7 +59,7 @@ impl NyaTermApp {
|
||||
cx.notify();
|
||||
return;
|
||||
}
|
||||
let mut keybindings = self.settings.summary.keybindings.clone();
|
||||
let mut keybindings = self.settings.summary().keybindings.clone();
|
||||
let is_default = crate::shortcuts::SHORTCUT_REGISTRY
|
||||
.iter()
|
||||
.find(|s| s.id == shortcut_id)
|
||||
@@ -77,7 +77,7 @@ impl NyaTermApp {
|
||||
shortcut_id: String,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let mut keybindings = self.settings.summary.keybindings.clone();
|
||||
let mut keybindings = self.settings.summary().keybindings.clone();
|
||||
keybindings.remove(&shortcut_id);
|
||||
self.save_keybindings(keybindings, format!("shortcut {shortcut_id} reset"), cx);
|
||||
}
|
||||
@@ -92,7 +92,7 @@ impl NyaTermApp {
|
||||
success_message: String,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.settings.summary.keybindings = keybindings.clone();
|
||||
self.settings.set_keybindings(keybindings.clone());
|
||||
if self.defer_settings_persistence(cx) {
|
||||
self.settings.finish_keybinding_recording();
|
||||
self.terminal.view.status = success_message.replace("saved", "staged");
|
||||
@@ -177,7 +177,7 @@ impl NyaTermApp {
|
||||
}
|
||||
let existing = crate::shortcuts::shortcut_keys_for(
|
||||
shortcut.id,
|
||||
&self.settings.summary.keybindings,
|
||||
&self.settings.summary().keybindings,
|
||||
)
|
||||
.unwrap_or_else(|| shortcut.default_keys.to_string());
|
||||
let normalized_existing = existing
|
||||
|
||||
+15
-57
@@ -8,8 +8,8 @@ const MAX_KEYWORD_HIGHLIGHT_IMPORT_BYTES: u64 = 4 * 1024 * 1024;
|
||||
|
||||
impl NyaTermApp {
|
||||
pub(in crate::features) fn toggle_keyword_highlights(&mut self, cx: &mut Context<Self>) {
|
||||
self.settings.keyword_config.enabled = !self.settings.keyword_config.enabled;
|
||||
if !self.settings.keyword_config.enabled {
|
||||
let enabled = self.settings.toggle_keyword_highlights();
|
||||
if !enabled {
|
||||
self.settings.clear_keyword_highlight_edit();
|
||||
self.forget_text_inputs("keyword.highlight.");
|
||||
}
|
||||
@@ -20,8 +20,7 @@ impl NyaTermApp {
|
||||
&mut self,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.settings.keyword_config.across_wrapped_lines =
|
||||
!self.settings.keyword_config.across_wrapped_lines;
|
||||
self.settings.toggle_keyword_highlights_wrapped();
|
||||
self.save_keyword_highlights(cx);
|
||||
}
|
||||
|
||||
@@ -34,10 +33,10 @@ impl NyaTermApp {
|
||||
self.runtime.config_dir(),
|
||||
self.runtime.portable_key_path().map(ToOwned::to_owned),
|
||||
)
|
||||
.and_then(|store| store.save_keyword_highlights(&self.settings.keyword_config))
|
||||
.and_then(|store| store.save_keyword_highlights(self.settings.keyword_config()))
|
||||
{
|
||||
Ok(config) => {
|
||||
self.settings.keyword_config = config;
|
||||
self.settings.replace_keyword_config(config);
|
||||
self.settings
|
||||
.set_store_message("keyword highlight settings saved".to_string());
|
||||
self.settings.set_store_ready(true);
|
||||
@@ -158,7 +157,7 @@ impl NyaTermApp {
|
||||
self.runtime.portable_key_path().map(ToOwned::to_owned),
|
||||
) {
|
||||
if let Ok(config) = store.load_keyword_highlights() {
|
||||
self.settings.keyword_config = config;
|
||||
self.settings.replace_keyword_config(config);
|
||||
self.forget_text_inputs("keyword.highlight.");
|
||||
}
|
||||
}
|
||||
@@ -169,17 +168,7 @@ impl NyaTermApp {
|
||||
rule_id: String,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let enabled = self
|
||||
.settings
|
||||
.keyword_config
|
||||
.builtin_rules
|
||||
.get(&rule_id)
|
||||
.copied()
|
||||
.unwrap_or(true);
|
||||
self.settings
|
||||
.keyword_config
|
||||
.builtin_rules
|
||||
.insert(rule_id, !enabled);
|
||||
self.settings.toggle_keyword_highlight_builtin(rule_id);
|
||||
self.save_keyword_highlights(cx);
|
||||
}
|
||||
|
||||
@@ -188,14 +177,7 @@ impl NyaTermApp {
|
||||
rule_id: String,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(rule) = self
|
||||
.settings
|
||||
.keyword_config
|
||||
.rules
|
||||
.iter_mut()
|
||||
.find(|rule| rule.id == rule_id)
|
||||
{
|
||||
rule.enabled = !rule.enabled;
|
||||
if self.settings.toggle_keyword_highlight_rule(&rule_id) {
|
||||
self.save_keyword_highlights(cx);
|
||||
}
|
||||
}
|
||||
@@ -266,18 +248,10 @@ impl NyaTermApp {
|
||||
} else {
|
||||
normalize_keyword_highlight_color(color)
|
||||
};
|
||||
if let Some(rule) = self
|
||||
if self
|
||||
.settings
|
||||
.keyword_config
|
||||
.rules
|
||||
.iter_mut()
|
||||
.find(|rule| rule.id == rule_id)
|
||||
.set_keyword_highlight_rule_color(&rule_id, dark, color.clone())
|
||||
{
|
||||
if dark {
|
||||
rule.color_dark = color.clone();
|
||||
} else {
|
||||
rule.color_light = color.clone();
|
||||
}
|
||||
let field = if dark {
|
||||
KeywordHighlightEditorField::ColorDark
|
||||
} else {
|
||||
@@ -301,7 +275,7 @@ impl NyaTermApp {
|
||||
) {
|
||||
let value = self
|
||||
.settings
|
||||
.keyword_config
|
||||
.keyword_config()
|
||||
.rules
|
||||
.iter()
|
||||
.find(|rule| rule.id == rule_id)
|
||||
@@ -389,29 +363,13 @@ impl NyaTermApp {
|
||||
KeywordHighlightEditorField::ColorDark | KeywordHighlightEditorField::ColorLight
|
||||
)
|
||||
.then(|| normalize_keyword_highlight_color(&text));
|
||||
let Some(rule) = self
|
||||
let value = normalized_color.clone().unwrap_or(text);
|
||||
if !self
|
||||
.settings
|
||||
.keyword_config
|
||||
.rules
|
||||
.iter_mut()
|
||||
.find(|rule| rule.id == rule_id)
|
||||
else {
|
||||
.apply_keyword_highlight_rule_input(rule_id, field, value)
|
||||
{
|
||||
return;
|
||||
};
|
||||
match field {
|
||||
KeywordHighlightEditorField::Name => rule.name = text,
|
||||
KeywordHighlightEditorField::Patterns => {
|
||||
rule.patterns = text.split('\n').map(ToOwned::to_owned).collect();
|
||||
}
|
||||
KeywordHighlightEditorField::ColorDark => {
|
||||
rule.color_dark = normalized_color.clone().unwrap_or_default();
|
||||
}
|
||||
KeywordHighlightEditorField::ColorLight => {
|
||||
rule.color_light = normalized_color.clone().unwrap_or_default();
|
||||
}
|
||||
}
|
||||
self.settings
|
||||
.begin_keyword_highlight_edit(rule_id.to_string(), field);
|
||||
if let Some(color) = normalized_color {
|
||||
self.reset_text_input(&keyword_highlight_text_input_id(rule_id, field), &color, cx);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use gpui::{
|
||||
};
|
||||
use nyaterm_core::ConnectionStore;
|
||||
|
||||
use crate::features::NyaTermApp;
|
||||
use crate::features::{NyaTermApp, settings::UiLayoutSettingsUpdate};
|
||||
use crate::models::{
|
||||
BottomPanelMode, NavItem, PanelResizeSide, PanelSide, panel_collapsed_from_persistence,
|
||||
};
|
||||
@@ -16,8 +16,6 @@ const BOTTOM_PANEL_HEIGHT_MAX: f32 = 520.;
|
||||
impl NyaTermApp {
|
||||
pub(in crate::features) fn set_bottom_panel_mode(&mut self, mode: BottomPanelMode) {
|
||||
self.shell.bottom_panel.mode = mode;
|
||||
self.settings.summary.ui_quick_cmd_visible = mode == BottomPanelMode::QuickCommands;
|
||||
self.settings.summary.ui_serial_send_visible = mode == BottomPanelMode::CommandSend;
|
||||
self.persist_ui_layout();
|
||||
}
|
||||
|
||||
@@ -76,90 +74,110 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn apply_ui_layout_from_settings(&mut self) {
|
||||
self.shell.panels.left_width = self.settings.summary.ui_left_panel_width as f32;
|
||||
self.shell.panels.right_width = self.settings.summary.ui_right_panel_width as f32;
|
||||
self.shell.panels.left_width = self.settings.summary().ui_left_panel_width as f32;
|
||||
self.shell.panels.right_width = self.settings.summary().ui_right_panel_width as f32;
|
||||
self.transfer
|
||||
.set_panel_height(self.settings.summary.ui_transfer_height as f32);
|
||||
.set_panel_height(self.settings.summary().ui_transfer_height as f32);
|
||||
self.shell.bottom_panel.quick_commands_height =
|
||||
self.settings.summary.ui_quick_cmd_height as f32;
|
||||
self.settings.summary().ui_quick_cmd_height as f32;
|
||||
self.shell.bottom_panel.command_send_height =
|
||||
self.settings.summary.ui_serial_send_height as f32;
|
||||
self.settings.summary().ui_serial_send_height as f32;
|
||||
self.apply_activity_layout_from_settings();
|
||||
self.shell.panels.active_left = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.ui_active_left_panel
|
||||
.as_deref()
|
||||
.and_then(NavItem::from_persistence_id)
|
||||
.filter(|item| self.panel_side_for_item(*item) == Some(PanelSide::Left));
|
||||
self.shell.panels.active_right = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.ui_active_right_panel
|
||||
.as_deref()
|
||||
.and_then(NavItem::from_persistence_id)
|
||||
.filter(|item| self.panel_side_for_item(*item) == Some(PanelSide::Right));
|
||||
self.shell.panels.left_collapsed = panel_collapsed_from_persistence(
|
||||
self.settings.summary.ui_left_panel_collapsed,
|
||||
self.settings.summary.ui_panel_multi_open,
|
||||
self.settings.summary().ui_left_panel_collapsed,
|
||||
self.settings.summary().ui_panel_multi_open,
|
||||
self.shell.panels.active_left.is_some(),
|
||||
!self.settings.summary.ui_left_open_panels.is_empty(),
|
||||
!self.settings.summary().ui_left_open_panels.is_empty(),
|
||||
);
|
||||
self.shell.panels.right_collapsed = panel_collapsed_from_persistence(
|
||||
self.settings.summary.ui_right_panel_collapsed,
|
||||
self.settings.summary.ui_panel_multi_open,
|
||||
self.settings.summary().ui_right_panel_collapsed,
|
||||
self.settings.summary().ui_panel_multi_open,
|
||||
self.shell.panels.active_right.is_some(),
|
||||
!self.settings.summary.ui_right_open_panels.is_empty(),
|
||||
!self.settings.summary().ui_right_open_panels.is_empty(),
|
||||
);
|
||||
self.apply_panel_stack_from_settings();
|
||||
if !self.settings.summary.has_master_password {
|
||||
if !self.settings.summary().has_master_password {
|
||||
self.security.unlock_without_master_password();
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::features) fn persist_ui_layout(&mut self) {
|
||||
self.settings.summary.ui_left_panel_width =
|
||||
self.shell.panels.left_width.round().clamp(160., 720.) as u32;
|
||||
self.settings.summary.ui_right_panel_width =
|
||||
self.shell.panels.right_width.round().clamp(200., 720.) as u32;
|
||||
self.settings.summary.ui_transfer_height =
|
||||
self.transfer.panel_height().round().clamp(60., 600.) as u32;
|
||||
self.settings.summary.ui_quick_cmd_height =
|
||||
self.shell
|
||||
let update = UiLayoutSettingsUpdate {
|
||||
left_panel_width: self.shell.panels.left_width.round().clamp(160., 720.) as u32,
|
||||
right_panel_width: self.shell.panels.right_width.round().clamp(200., 720.) as u32,
|
||||
transfer_height: self.transfer.panel_height().round().clamp(60., 600.) as u32,
|
||||
quick_command_height: self
|
||||
.shell
|
||||
.bottom_panel
|
||||
.quick_commands_height
|
||||
.round()
|
||||
.clamp(QUICK_CMD_HEIGHT_MIN, BOTTOM_PANEL_HEIGHT_MAX) as u32;
|
||||
self.settings.summary.ui_serial_send_height =
|
||||
self.shell
|
||||
.clamp(QUICK_CMD_HEIGHT_MIN, BOTTOM_PANEL_HEIGHT_MAX)
|
||||
as u32,
|
||||
quick_command_visible: self.shell.bottom_panel.mode == BottomPanelMode::QuickCommands,
|
||||
serial_send_height: self
|
||||
.shell
|
||||
.bottom_panel
|
||||
.command_send_height
|
||||
.round()
|
||||
.clamp(SERIAL_SEND_HEIGHT_MIN, BOTTOM_PANEL_HEIGHT_MAX) as u32;
|
||||
self.settings.summary.ui_active_left_panel = self
|
||||
.shell
|
||||
.panels
|
||||
.active_left
|
||||
.map(|item| item.persistence_id().to_string());
|
||||
self.settings.summary.ui_active_right_panel = self
|
||||
.shell
|
||||
.panels
|
||||
.active_right
|
||||
.map(|item| item.persistence_id().to_string());
|
||||
self.settings.summary.ui_left_panel_collapsed = self.shell.panels.left_collapsed;
|
||||
self.settings.summary.ui_right_panel_collapsed = self.shell.panels.right_collapsed;
|
||||
self.settings.summary.ui_saved_connections_sort_mode = self
|
||||
.connection_state
|
||||
.list_sort_mode()
|
||||
.persistence_id()
|
||||
.to_string();
|
||||
self.sync_activity_layout_to_settings();
|
||||
self.sync_panel_stack_to_settings();
|
||||
.clamp(SERIAL_SEND_HEIGHT_MIN, BOTTOM_PANEL_HEIGHT_MAX)
|
||||
as u32,
|
||||
serial_send_visible: self.shell.bottom_panel.mode == BottomPanelMode::CommandSend,
|
||||
active_left_panel: self
|
||||
.shell
|
||||
.panels
|
||||
.active_left
|
||||
.map(|item| item.persistence_id().to_string()),
|
||||
active_right_panel: self
|
||||
.shell
|
||||
.panels
|
||||
.active_right
|
||||
.map(|item| item.persistence_id().to_string()),
|
||||
left_panel_collapsed: self.shell.panels.left_collapsed,
|
||||
right_panel_collapsed: self.shell.panels.right_collapsed,
|
||||
saved_connections_sort_mode: self
|
||||
.connection_state
|
||||
.list_sort_mode()
|
||||
.persistence_id()
|
||||
.to_string(),
|
||||
activity_bar_left_top: self.shell.chrome.activity_bar_layout.left_top.clone(),
|
||||
activity_bar_left_bottom: self.shell.chrome.activity_bar_layout.left_bottom.clone(),
|
||||
activity_bar_right_top: self.shell.chrome.activity_bar_layout.right_top.clone(),
|
||||
activity_bar_right_bottom: self.shell.chrome.activity_bar_layout.right_bottom.clone(),
|
||||
activity_bar_show_labels: self.shell.chrome.activity_bar_layout.show_labels,
|
||||
panel_multi_open: self.shell.panels.multi_open,
|
||||
left_open_panels: self.shell.panels.left_open.clone(),
|
||||
right_open_panels: self.shell.panels.right_open.clone(),
|
||||
panel_stack_sizes: self
|
||||
.shell
|
||||
.panels
|
||||
.stack_sizes
|
||||
.iter()
|
||||
.filter_map(|(key, value)| {
|
||||
let scaled = (*value * 1000.).round();
|
||||
(scaled.is_finite() && scaled > 0.).then(|| (key.clone(), scaled as u32))
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
self.settings.apply_ui_layout(update);
|
||||
if let Ok(store) = ConnectionStore::open_with_portable_key_path(
|
||||
self.runtime.config_dir(),
|
||||
self.runtime.portable_key_path().map(ToOwned::to_owned),
|
||||
) {
|
||||
match store.save_ui_layout_settings(&self.settings.summary) {
|
||||
match store.save_ui_layout_settings(self.settings.summary()) {
|
||||
Ok(summary) => {
|
||||
self.apply_gpui_settings(summary);
|
||||
self.settings.set_store_ready(true);
|
||||
|
||||
@@ -366,29 +366,13 @@ impl NyaTermApp {
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::features) fn sync_panel_stack_to_settings(&mut self) {
|
||||
self.settings.summary.ui_panel_multi_open = self.shell.panels.multi_open;
|
||||
self.settings.summary.ui_left_open_panels = self.shell.panels.left_open.clone();
|
||||
self.settings.summary.ui_right_open_panels = self.shell.panels.right_open.clone();
|
||||
self.settings.summary.ui_panel_stack_sizes = self
|
||||
.shell
|
||||
.panels
|
||||
.stack_sizes
|
||||
.iter()
|
||||
.filter_map(|(key, value)| {
|
||||
let scaled = (*value * 1000.).round();
|
||||
(scaled.is_finite() && scaled > 0.).then(|| (key.clone(), scaled as u32))
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
pub(in crate::features) fn apply_panel_stack_from_settings(&mut self) {
|
||||
self.shell.panels.multi_open = self.settings.summary.ui_panel_multi_open;
|
||||
self.shell.panels.left_open = self.settings.summary.ui_left_open_panels.clone();
|
||||
self.shell.panels.right_open = self.settings.summary.ui_right_open_panels.clone();
|
||||
self.shell.panels.multi_open = self.settings.summary().ui_panel_multi_open;
|
||||
self.shell.panels.left_open = self.settings.summary().ui_left_open_panels.clone();
|
||||
self.shell.panels.right_open = self.settings.summary().ui_right_open_panels.clone();
|
||||
self.shell.panels.stack_sizes = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.ui_panel_stack_sizes
|
||||
.iter()
|
||||
.filter_map(|(key, value)| (*value > 0).then(|| (key.clone(), (*value as f32) / 1000.)))
|
||||
|
||||
@@ -225,22 +225,24 @@ impl NyaTermApp {
|
||||
let action = normalize_tab_mouse_action(action);
|
||||
match target {
|
||||
TabMouseActionTarget::Double => {
|
||||
if self.settings.summary.interaction_tab_double_click_action == action {
|
||||
if self.settings.summary().interaction_tab_double_click_action == action {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.interaction_tab_double_click_action = action.to_string();
|
||||
self.settings
|
||||
.set_tab_double_click_action(action.to_string());
|
||||
}
|
||||
TabMouseActionTarget::Middle => {
|
||||
if self.settings.summary.interaction_tab_middle_click_action == action {
|
||||
if self.settings.summary().interaction_tab_middle_click_action == action {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.interaction_tab_middle_click_action = action.to_string();
|
||||
self.settings
|
||||
.set_tab_middle_click_action(action.to_string());
|
||||
}
|
||||
TabMouseActionTarget::Right => {
|
||||
if self.settings.summary.interaction_tab_right_click_action == action {
|
||||
if self.settings.summary().interaction_tab_right_click_action == action {
|
||||
return;
|
||||
}
|
||||
self.settings.summary.interaction_tab_right_click_action = action.to_string();
|
||||
self.settings.set_tab_right_click_action(action.to_string());
|
||||
}
|
||||
}
|
||||
self.save_interaction_settings(cx);
|
||||
@@ -260,7 +262,7 @@ impl NyaTermApp {
|
||||
cx.stop_propagation();
|
||||
let action = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_tab_middle_click_action
|
||||
.clone();
|
||||
if action == "none" {
|
||||
@@ -276,7 +278,7 @@ impl NyaTermApp {
|
||||
cx.stop_propagation();
|
||||
let action = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_tab_right_click_action
|
||||
.clone();
|
||||
if action == "none" {
|
||||
@@ -301,7 +303,7 @@ impl NyaTermApp {
|
||||
if is_left_double_click {
|
||||
let action = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_tab_double_click_action
|
||||
.clone();
|
||||
if action != "none" {
|
||||
|
||||
@@ -247,8 +247,8 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn persist_terminal_window_layout(&mut self) {
|
||||
if !self.settings.summary.startup_restore
|
||||
|| !self.settings.summary.startup_restore_window_layout
|
||||
if !self.settings.summary().startup_restore
|
||||
|| !self.settings.summary().startup_restore_window_layout
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -260,8 +260,8 @@ impl NyaTermApp {
|
||||
if self.terminal.windows.restored {
|
||||
return;
|
||||
}
|
||||
if !self.settings.summary.startup_restore
|
||||
|| !self.settings.summary.startup_restore_window_layout
|
||||
if !self.settings.summary().startup_restore
|
||||
|| !self.settings.summary().startup_restore_window_layout
|
||||
{
|
||||
self.terminal.windows.restored = true;
|
||||
return;
|
||||
|
||||
@@ -452,8 +452,8 @@ impl NyaTermApp {
|
||||
}
|
||||
}
|
||||
pub(in crate::features) fn persist_workspace_pane_layout(&mut self) {
|
||||
if !self.settings.summary.startup_restore
|
||||
|| !self.settings.summary.startup_restore_window_layout
|
||||
if !self.settings.summary().startup_restore
|
||||
|| !self.settings.summary().startup_restore_window_layout
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -500,8 +500,8 @@ impl NyaTermApp {
|
||||
if self.shell.workspace.pane_layout_restored {
|
||||
return;
|
||||
}
|
||||
if !self.settings.summary.startup_restore
|
||||
|| !self.settings.summary.startup_restore_window_layout
|
||||
if !self.settings.summary().startup_restore
|
||||
|| !self.settings.summary().startup_restore_window_layout
|
||||
{
|
||||
self.shell.workspace.pane_layout_restored = true;
|
||||
return;
|
||||
|
||||
@@ -408,7 +408,7 @@ impl NyaTermApp {
|
||||
pub(in crate::features) fn refresh_cloud_sync_history(&mut self) {
|
||||
let history = read_cloud_sync_history(
|
||||
self.runtime.log_dir(),
|
||||
self.settings.summary.diagnostics_retention_days,
|
||||
self.settings.summary().diagnostics_retention_days,
|
||||
CLOUD_SYNC_HISTORY_LIMIT,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
|
||||
@@ -21,9 +21,9 @@ impl NyaTermApp {
|
||||
|
||||
pub(in crate::features) fn toggle_cloud_sync_enabled(&mut self, cx: &mut Context<Self>) {
|
||||
if !self.cloud_sync.settings().enabled
|
||||
&& (!self.settings.master_password.enabled
|
||||
|| (!self.settings.summary.has_master_password
|
||||
&& self.settings.master_password.draft.is_empty()))
|
||||
&& (!self.settings.master_password().enabled
|
||||
|| (!self.settings.summary().has_master_password
|
||||
&& self.settings.master_password().draft.is_empty()))
|
||||
{
|
||||
self.shell.set_settings_active_tab(SettingsTab::Security);
|
||||
self.cloud_sync
|
||||
@@ -91,8 +91,8 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn cloud_sync_form_enabled(&self) -> bool {
|
||||
self.settings.master_password.enabled
|
||||
&& (self.settings.summary.has_master_password
|
||||
|| !self.settings.master_password.draft.is_empty())
|
||||
self.settings.master_password().enabled
|
||||
&& (self.settings.summary().has_master_password
|
||||
|| !self.settings.master_password().draft.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ impl NyaTermApp {
|
||||
let selected_for_paste = selected.clone();
|
||||
let search_engines: Vec<(String, String, Option<String>)> = self
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.search_custom_engines
|
||||
.iter()
|
||||
.filter(|engine| {
|
||||
@@ -118,9 +118,9 @@ impl NyaTermApp {
|
||||
.collect();
|
||||
let selection_link_kind: Option<&'static str> = None;
|
||||
let selection_actions: Vec<(String, ActionLinkAction)> =
|
||||
if self.settings.summary.terminal_action_links_enabled && has_selection {
|
||||
if self.settings.summary().terminal_action_links_enabled && has_selection {
|
||||
let trimmed = selected.trim();
|
||||
let matchers = &self.settings.summary.terminal_action_links_matchers;
|
||||
let matchers = &self.settings.summary().terminal_action_links_matchers;
|
||||
let entity = find_action_links(trimmed, matchers, true)
|
||||
.into_iter()
|
||||
.find(|item| item.text == trimmed || item.value == trimmed)
|
||||
|
||||
@@ -186,7 +186,7 @@ fn terminal_scroll_snapshot_request_action_links_enabled(
|
||||
impl NyaTermApp {
|
||||
pub(in crate::features) fn terminal_scrollback_line_limit(&self) -> usize {
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.terminal_scrollback_lines
|
||||
.clamp(100, 100_000) as usize
|
||||
}
|
||||
@@ -216,7 +216,7 @@ impl NyaTermApp {
|
||||
self.terminal.view.frame_pipeline.submit_output(
|
||||
session_id.to_string(),
|
||||
data,
|
||||
self.settings.summary.interaction_default_encoding.clone(),
|
||||
self.settings.summary().interaction_default_encoding.clone(),
|
||||
self.terminal_scrollback_line_limit(),
|
||||
);
|
||||
}
|
||||
@@ -228,7 +228,7 @@ impl NyaTermApp {
|
||||
if outputs.is_empty() {
|
||||
return;
|
||||
}
|
||||
let encoding = self.settings.summary.interaction_default_encoding.clone();
|
||||
let encoding = self.settings.summary().interaction_default_encoding.clone();
|
||||
let scrollback_limit = self.terminal_scrollback_line_limit();
|
||||
let submissions = outputs
|
||||
.into_iter()
|
||||
@@ -271,9 +271,12 @@ impl NyaTermApp {
|
||||
self.terminal.view.frame_pipeline.request_snapshot(
|
||||
session_id.to_string(),
|
||||
offset,
|
||||
self.settings.summary.terminal_action_links_enabled
|
||||
&& !self.settings.summary.terminal_low_latency_mode,
|
||||
self.settings.summary.terminal_action_links_matchers.clone(),
|
||||
self.settings.summary().terminal_action_links_enabled
|
||||
&& !self.settings.summary().terminal_low_latency_mode,
|
||||
self.settings
|
||||
.summary()
|
||||
.terminal_action_links_matchers
|
||||
.clone(),
|
||||
);
|
||||
true
|
||||
}
|
||||
@@ -299,7 +302,10 @@ impl NyaTermApp {
|
||||
session_id.to_string(),
|
||||
offset,
|
||||
false,
|
||||
self.settings.summary.terminal_action_links_matchers.clone(),
|
||||
self.settings
|
||||
.summary()
|
||||
.terminal_action_links_matchers
|
||||
.clone(),
|
||||
);
|
||||
true
|
||||
}
|
||||
@@ -390,21 +396,27 @@ impl NyaTermApp {
|
||||
if priority {
|
||||
let action_links_enabled = terminal_scroll_snapshot_request_action_links_enabled(
|
||||
priority,
|
||||
self.settings.summary.terminal_action_links_enabled,
|
||||
self.settings.summary.terminal_low_latency_mode,
|
||||
self.settings.summary().terminal_action_links_enabled,
|
||||
self.settings.summary().terminal_low_latency_mode,
|
||||
);
|
||||
self.terminal.view.frame_pipeline.request_priority_snapshot(
|
||||
session_id.to_string(),
|
||||
offset,
|
||||
action_links_enabled,
|
||||
self.settings.summary.terminal_action_links_matchers.clone(),
|
||||
self.settings
|
||||
.summary()
|
||||
.terminal_action_links_matchers
|
||||
.clone(),
|
||||
);
|
||||
} else {
|
||||
self.terminal.view.frame_pipeline.request_snapshot(
|
||||
session_id.to_string(),
|
||||
offset,
|
||||
false,
|
||||
self.settings.summary.terminal_action_links_matchers.clone(),
|
||||
self.settings
|
||||
.summary()
|
||||
.terminal_action_links_matchers
|
||||
.clone(),
|
||||
);
|
||||
}
|
||||
true
|
||||
@@ -418,14 +430,14 @@ impl NyaTermApp {
|
||||
) -> bool {
|
||||
if session_id.is_empty()
|
||||
|| offset == 0
|
||||
|| !self.settings.summary.terminal_action_links_enabled
|
||||
|| self.settings.summary.terminal_low_latency_mode
|
||||
|| !self.settings.summary().terminal_action_links_enabled
|
||||
|| self.settings.summary().terminal_low_latency_mode
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let matcher_key = terminal_action_link_matcher_key(
|
||||
true,
|
||||
&self.settings.summary.terminal_action_links_matchers,
|
||||
&self.settings.summary().terminal_action_links_matchers,
|
||||
);
|
||||
let Some(view) = self.terminal.view.views.get_mut(session_id) else {
|
||||
return false;
|
||||
@@ -452,7 +464,10 @@ impl NyaTermApp {
|
||||
session_id.to_string(),
|
||||
offset,
|
||||
true,
|
||||
self.settings.summary.terminal_action_links_matchers.clone(),
|
||||
self.settings
|
||||
.summary()
|
||||
.terminal_action_links_matchers
|
||||
.clone(),
|
||||
);
|
||||
true
|
||||
}
|
||||
@@ -490,7 +505,7 @@ impl NyaTermApp {
|
||||
self.terminal.view.frame_pipeline.seed_session(
|
||||
session_id.to_string(),
|
||||
output,
|
||||
self.settings.summary.interaction_default_encoding.clone(),
|
||||
self.settings.summary().interaction_default_encoding.clone(),
|
||||
self.terminal_scrollback_line_limit(),
|
||||
);
|
||||
}
|
||||
@@ -997,14 +1012,15 @@ impl NyaTermApp {
|
||||
"terminal frame snapshot row reuse"
|
||||
);
|
||||
// Snapshot applies only dirties the surface, not chrome.
|
||||
let current_action_link_matcher_key = (self.settings.summary.terminal_action_links_enabled
|
||||
&& !self.settings.summary.terminal_low_latency_mode)
|
||||
.then(|| {
|
||||
terminal_action_link_matcher_key(
|
||||
true,
|
||||
&self.settings.summary.terminal_action_links_matchers,
|
||||
)
|
||||
});
|
||||
let current_action_link_matcher_key =
|
||||
(self.settings.summary().terminal_action_links_enabled
|
||||
&& !self.settings.summary().terminal_low_latency_mode)
|
||||
.then(|| {
|
||||
terminal_action_link_matcher_key(
|
||||
true,
|
||||
&self.settings.summary().terminal_action_links_matchers,
|
||||
)
|
||||
});
|
||||
let should_paint = self.terminal_session_has_visible_surface(&frame.session_id)
|
||||
&& self
|
||||
.terminal
|
||||
@@ -1164,7 +1180,7 @@ impl NyaTermApp {
|
||||
session_id: &str,
|
||||
data: &[u8],
|
||||
) -> String {
|
||||
let encoding = self.settings.summary.interaction_default_encoding.clone();
|
||||
let encoding = self.settings.summary().interaction_default_encoding.clone();
|
||||
let view = self
|
||||
.terminal
|
||||
.view
|
||||
@@ -1213,7 +1229,7 @@ impl NyaTermApp {
|
||||
|
||||
if let Some(session_id) = session_id {
|
||||
let is_active = self.session.active_id() == Some(session_id);
|
||||
let encoding = self.settings.summary.interaction_default_encoding.clone();
|
||||
let encoding = self.settings.summary().interaction_default_encoding.clone();
|
||||
let view = self
|
||||
.terminal
|
||||
.view
|
||||
|
||||
@@ -29,7 +29,11 @@ impl NyaTermApp {
|
||||
cx.notify();
|
||||
return;
|
||||
}
|
||||
if self.settings.summary.terminal_show_multi_line_paste_dialog && is_multi_line_paste(&text)
|
||||
if self
|
||||
.settings
|
||||
.summary()
|
||||
.terminal_show_multi_line_paste_dialog
|
||||
&& is_multi_line_paste(&text)
|
||||
{
|
||||
self.terminal.paste.open(text);
|
||||
self.terminal.view.status = "multi-line paste confirmation opened".to_string();
|
||||
|
||||
@@ -93,7 +93,7 @@ impl NyaTermApp {
|
||||
self.terminal
|
||||
.view
|
||||
.screen
|
||||
.set_encoding(&self.settings.summary.interaction_default_encoding);
|
||||
.set_encoding(&self.settings.summary().interaction_default_encoding);
|
||||
self.terminal.view.status = "session closed".to_string();
|
||||
}
|
||||
} else {
|
||||
@@ -160,7 +160,7 @@ impl NyaTermApp {
|
||||
self.terminal
|
||||
.view
|
||||
.screen
|
||||
.set_encoding(&self.settings.summary.interaction_default_encoding);
|
||||
.set_encoding(&self.settings.summary().interaction_default_encoding);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ impl NyaTermApp {
|
||||
// Tauri minimize_to_tray: hide window instead of taskbar minimize when enabled.
|
||||
// GPUI lacks a portable tray today; minimize still uses the platform minimize path,
|
||||
// and the flag is honored as a documented no-op tray intent with status feedback.
|
||||
if self.settings.summary.minimize_to_tray {
|
||||
if self.settings.summary().minimize_to_tray {
|
||||
window.minimize_window();
|
||||
self.terminal.view.status =
|
||||
"minimized (tray mode preferred; OS tray polish pending)".to_string();
|
||||
@@ -195,7 +195,7 @@ impl NyaTermApp {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let open_sessions = self.ordered_sessions().len();
|
||||
if self.settings.summary.confirm_on_close && open_sessions > 0 {
|
||||
if self.settings.summary().confirm_on_close && open_sessions > 0 {
|
||||
// Reuse close-all confirmation as quit-with-sessions gate (Tauri confirm_on_close).
|
||||
self.session.dialogs.request_quit_after_close_all();
|
||||
self.open_close_all_sessions_confirm(window, cx);
|
||||
@@ -205,7 +205,7 @@ impl NyaTermApp {
|
||||
return;
|
||||
}
|
||||
// Persist workspace before exit when startup restore is enabled.
|
||||
if self.settings.summary.startup_restore {
|
||||
if self.settings.summary().startup_restore {
|
||||
self.flush_open_tabs_now();
|
||||
}
|
||||
window.remove_window();
|
||||
@@ -244,7 +244,7 @@ impl NyaTermApp {
|
||||
let quit_after = self.session.dialogs.take_close_all_sessions_confirm();
|
||||
self.close_all_sessions(cx);
|
||||
if quit_after {
|
||||
if self.settings.summary.startup_restore {
|
||||
if self.settings.summary().startup_restore {
|
||||
self.flush_open_tabs_now();
|
||||
}
|
||||
self.terminal.view.status = "sessions closed; closing window".to_string();
|
||||
|
||||
@@ -713,9 +713,9 @@ impl NyaTermApp {
|
||||
if track_suggestions {
|
||||
if terminal_should_track_command_suggestion_input(
|
||||
track_suggestions,
|
||||
self.settings.summary.terminal_low_latency_mode,
|
||||
self.settings.summary().terminal_low_latency_mode,
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestions_enabled,
|
||||
) {
|
||||
self.note_command_suggestion_input(&bytes, cx);
|
||||
@@ -851,9 +851,9 @@ impl NyaTermApp {
|
||||
if track_suggestions {
|
||||
if terminal_should_track_command_suggestion_input(
|
||||
track_suggestions,
|
||||
self.settings.summary.terminal_low_latency_mode,
|
||||
self.settings.summary().terminal_low_latency_mode,
|
||||
self.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_command_suggestions_enabled,
|
||||
) {
|
||||
self.note_command_suggestion_input(&primary_bytes, cx);
|
||||
@@ -1392,7 +1392,7 @@ impl NyaTermApp {
|
||||
|
||||
/// Keep all live terminal screens on the current interaction encoding.
|
||||
pub(in crate::features) fn sync_terminal_encodings_from_settings(&mut self) {
|
||||
let label = self.settings.summary.interaction_default_encoding.clone();
|
||||
let label = self.settings.summary().interaction_default_encoding.clone();
|
||||
self.terminal.view.screen.set_encoding(&label);
|
||||
self.terminal.view.output_decoder.set_encoding(&label);
|
||||
for view in self.terminal.view.views.values_mut() {
|
||||
@@ -1628,7 +1628,7 @@ impl NyaTermApp {
|
||||
terminal_key_bytes_for_mode_and_settings(
|
||||
event,
|
||||
self.terminal_key_mode_for_session(session_id),
|
||||
self.settings.summary.interaction_alt_as_meta,
|
||||
self.settings.summary().interaction_alt_as_meta,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1637,7 +1637,7 @@ impl NyaTermApp {
|
||||
event: &KeyDownEvent,
|
||||
) -> bool {
|
||||
terminal_should_defer_key_text_to_input_handler_for_state(
|
||||
self.settings.summary.interaction_mac_ime_compatibility,
|
||||
self.settings.summary().interaction_mac_ime_compatibility,
|
||||
&self.terminal.input.ime_marked_text,
|
||||
event,
|
||||
)
|
||||
@@ -1716,7 +1716,7 @@ impl NyaTermApp {
|
||||
};
|
||||
let matcher_key = terminal_action_link_matcher_key(
|
||||
true,
|
||||
&self.settings.summary.terminal_action_links_matchers,
|
||||
&self.settings.summary().terminal_action_links_matchers,
|
||||
);
|
||||
if view.frame_action_links.as_ref().is_some_and(|links| {
|
||||
links.matcher_key == matcher_key && links.covers_all_snapshot_rows(snapshot.as_ref())
|
||||
@@ -1726,7 +1726,7 @@ impl NyaTermApp {
|
||||
let Some(action_links) = crate::models::prepare_terminal_frame_action_links(
|
||||
snapshot.as_ref(),
|
||||
true,
|
||||
&self.settings.summary.terminal_action_links_matchers,
|
||||
&self.settings.summary().terminal_action_links_matchers,
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
@@ -1774,8 +1774,8 @@ impl NyaTermApp {
|
||||
) else {
|
||||
return false;
|
||||
};
|
||||
let action_links_enabled = self.settings.summary.terminal_action_links_enabled
|
||||
&& !self.settings.summary.terminal_low_latency_mode;
|
||||
let action_links_enabled = self.settings.summary().terminal_action_links_enabled
|
||||
&& !self.settings.summary().terminal_low_latency_mode;
|
||||
self.ensure_terminal_live_action_links_for_snapshot(
|
||||
session_id,
|
||||
display_offset,
|
||||
@@ -1788,12 +1788,12 @@ impl NyaTermApp {
|
||||
let palette = self.terminal_theme_palette();
|
||||
let transparent_background = self.wallpaper_enabled();
|
||||
let font_family = self.gpui_terminal_font_family();
|
||||
let font_size = self.settings.summary.terminal_font_size as f32;
|
||||
let normal_weight = self.settings.summary.terminal_font_weight as f32;
|
||||
let bold_weight = self.settings.summary.terminal_font_weight_bold as f32;
|
||||
let show_line_numbers = self.settings.summary.terminal_show_line_numbers;
|
||||
let show_timestamps = self.settings.summary.terminal_show_timestamps;
|
||||
let show_timestamp_ms = self.settings.summary.terminal_show_timestamp_milliseconds;
|
||||
let font_size = self.settings.summary().terminal_font_size as f32;
|
||||
let normal_weight = self.settings.summary().terminal_font_weight as f32;
|
||||
let bold_weight = self.settings.summary().terminal_font_weight_bold as f32;
|
||||
let show_line_numbers = self.settings.summary().terminal_show_line_numbers;
|
||||
let show_timestamps = self.settings.summary().terminal_show_timestamps;
|
||||
let show_timestamp_ms = self.settings.summary().terminal_show_timestamp_milliseconds;
|
||||
let (cell_w, cell_h) = self
|
||||
.terminal
|
||||
.layout
|
||||
@@ -1803,14 +1803,14 @@ impl NyaTermApp {
|
||||
let visual_bell = is_active && self.terminal.view.runtime.visual_bell_ticks > 0;
|
||||
let layout_cache = view.render_cache.layout_cache.clone();
|
||||
let render_degraded =
|
||||
view.render_degraded || self.settings.summary.terminal_low_latency_mode;
|
||||
view.render_degraded || self.settings.summary().terminal_low_latency_mode;
|
||||
let has_new = view.has_new_while_scrolled;
|
||||
let performance_overlay = view.performance_overlay;
|
||||
let skipped = view.skipped_output_chars;
|
||||
let protocol_state = view.protocol_state;
|
||||
let search_matches = if is_active
|
||||
&& !input_latency_active
|
||||
&& !self.settings.summary.terminal_low_latency_mode
|
||||
&& !self.settings.summary().terminal_low_latency_mode
|
||||
&& self.terminal.search.open
|
||||
&& self.terminal.search.mode == TerminalSearchMode::Buffer
|
||||
{
|
||||
@@ -1820,7 +1820,7 @@ impl NyaTermApp {
|
||||
};
|
||||
let action_link_matcher_key = terminal_action_link_matcher_key(
|
||||
action_links_enabled,
|
||||
&self.settings.summary.terminal_action_links_matchers,
|
||||
&self.settings.summary().terminal_action_links_matchers,
|
||||
);
|
||||
let frame_action_links = action_links_enabled
|
||||
.then(|| {
|
||||
@@ -1845,7 +1845,9 @@ impl NyaTermApp {
|
||||
&frame_action_links,
|
||||
action_links_enabled,
|
||||
action_links_enabled,
|
||||
is_active && !input_latency_active && !self.settings.summary.terminal_low_latency_mode,
|
||||
is_active
|
||||
&& !input_latency_active
|
||||
&& !self.settings.summary().terminal_low_latency_mode,
|
||||
);
|
||||
let has_action_link_decorations =
|
||||
crate::features::terminal::terminal_surface::terminal_action_links_have_ranges_for_snapshot(
|
||||
@@ -1991,7 +1993,7 @@ impl NyaTermApp {
|
||||
|| mode == TerminalPerformanceMode::Overloaded
|
||||
|| user_scroll_active
|
||||
|| input_latency_active
|
||||
|| self.settings.summary.terminal_low_latency_mode;
|
||||
|| self.settings.summary().terminal_low_latency_mode;
|
||||
let render_degraded = render_degraded_view || render_pressure;
|
||||
let configured_keyword_rules = self.resolved_keyword_highlight_rules();
|
||||
let clear_keyword_highlights = configured_keyword_rules.is_empty();
|
||||
@@ -2036,8 +2038,8 @@ impl NyaTermApp {
|
||||
retained_surface_snapshot,
|
||||
);
|
||||
let snapshot_duration = snapshot_started_at.elapsed();
|
||||
let action_links_enabled = self.settings.summary.terminal_action_links_enabled
|
||||
&& !self.settings.summary.terminal_low_latency_mode;
|
||||
let action_links_enabled = self.settings.summary().terminal_action_links_enabled
|
||||
&& !self.settings.summary().terminal_low_latency_mode;
|
||||
if let Some(snapshot) = snapshot.as_ref() {
|
||||
self.ensure_terminal_live_action_links_for_snapshot(
|
||||
session_id,
|
||||
@@ -2050,12 +2052,12 @@ impl NyaTermApp {
|
||||
let palette = self.terminal_theme_palette();
|
||||
let transparent_background = self.wallpaper_enabled();
|
||||
let font_family = self.gpui_terminal_font_family();
|
||||
let font_size = self.settings.summary.terminal_font_size as f32;
|
||||
let normal_weight = self.settings.summary.terminal_font_weight as f32;
|
||||
let bold_weight = self.settings.summary.terminal_font_weight_bold as f32;
|
||||
let show_line_numbers = self.settings.summary.terminal_show_line_numbers;
|
||||
let show_timestamps = self.settings.summary.terminal_show_timestamps;
|
||||
let show_timestamp_ms = self.settings.summary.terminal_show_timestamp_milliseconds;
|
||||
let font_size = self.settings.summary().terminal_font_size as f32;
|
||||
let normal_weight = self.settings.summary().terminal_font_weight as f32;
|
||||
let bold_weight = self.settings.summary().terminal_font_weight_bold as f32;
|
||||
let show_line_numbers = self.settings.summary().terminal_show_line_numbers;
|
||||
let show_timestamps = self.settings.summary().terminal_show_timestamps;
|
||||
let show_timestamp_ms = self.settings.summary().terminal_show_timestamp_milliseconds;
|
||||
let (cell_w, cell_h) = self
|
||||
.terminal
|
||||
.layout
|
||||
@@ -2133,7 +2135,7 @@ impl NyaTermApp {
|
||||
let remote_cursor_visible = snapshot.cursor.visible
|
||||
&& snapshot.cursor.shape != nyaterm_terminal::CursorShape::Hidden
|
||||
&& cursor_row != usize::MAX;
|
||||
let blink_enabled = self.settings.summary.cursor_blink || snapshot.cursor.blinking;
|
||||
let blink_enabled = self.settings.summary().cursor_blink || snapshot.cursor.blinking;
|
||||
let show_cursor = terminal_cursor_visible_for_display_offset(
|
||||
is_active,
|
||||
is_disconnected,
|
||||
@@ -2145,8 +2147,8 @@ impl NyaTermApp {
|
||||
let cursor_style = match snapshot.cursor.shape {
|
||||
nyaterm_terminal::CursorShape::Underline => "underline".to_string(),
|
||||
nyaterm_terminal::CursorShape::Beam => "bar".to_string(),
|
||||
nyaterm_terminal::CursorShape::Hidden => self.settings.summary.cursor_style.clone(),
|
||||
nyaterm_terminal::CursorShape::Block => self.settings.summary.cursor_style.clone(),
|
||||
nyaterm_terminal::CursorShape::Hidden => self.settings.summary().cursor_style.clone(),
|
||||
nyaterm_terminal::CursorShape::Block => self.settings.summary().cursor_style.clone(),
|
||||
};
|
||||
|
||||
let search_mapping_started_at = Instant::now();
|
||||
@@ -2161,7 +2163,7 @@ impl NyaTermApp {
|
||||
let enhanced = paint_policy.enhanced_decorations;
|
||||
let action_link_matcher_key = terminal_action_link_matcher_key(
|
||||
action_links_enabled,
|
||||
&self.settings.summary.terminal_action_links_matchers,
|
||||
&self.settings.summary().terminal_action_links_matchers,
|
||||
);
|
||||
let frame_action_links = action_links_enabled
|
||||
.then(|| {
|
||||
|
||||
+8
-8
@@ -75,8 +75,8 @@ impl NyaTermApp {
|
||||
event: &MouseMoveEvent,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if !self.settings.summary.terminal_action_links_enabled
|
||||
|| self.settings.summary.terminal_low_latency_mode
|
||||
if !self.settings.summary().terminal_action_links_enabled
|
||||
|| self.settings.summary().terminal_low_latency_mode
|
||||
|| self.runtime_output_pressure_active()
|
||||
{
|
||||
self.clear_action_link_tooltip(cx);
|
||||
@@ -179,7 +179,7 @@ impl NyaTermApp {
|
||||
position: Point<Pixels>,
|
||||
cx: &App,
|
||||
) -> Option<(ActionLinkMatch, Vec<ActionLinkAction>)> {
|
||||
if !self.settings.summary.terminal_action_links_enabled {
|
||||
if !self.settings.summary().terminal_action_links_enabled {
|
||||
return None;
|
||||
}
|
||||
let session_id = self.terminal_session_at_point(position)?;
|
||||
@@ -203,8 +203,8 @@ impl NyaTermApp {
|
||||
}
|
||||
let cell = self.point_to_terminal_cell_for_session(session_id, position, cx)?;
|
||||
let action_link_matcher_key = terminal_action_link_matcher_key(
|
||||
self.settings.summary.terminal_action_links_enabled,
|
||||
&self.settings.summary.terminal_action_links_matchers,
|
||||
self.settings.summary().terminal_action_links_enabled,
|
||||
&self.settings.summary().terminal_action_links_matchers,
|
||||
);
|
||||
let offset = self.terminal_display_offset_for_session(session_id);
|
||||
let snapshot = self.terminal_snapshot_for_session(session_id, offset);
|
||||
@@ -245,7 +245,7 @@ impl NyaTermApp {
|
||||
.cloned()
|
||||
})
|
||||
.or_else(|| {
|
||||
let matchers = &self.settings.summary.terminal_action_links_matchers;
|
||||
let matchers = &self.settings.summary().terminal_action_links_matchers;
|
||||
match_at_offset(line, byte_offset, matchers)
|
||||
})?;
|
||||
let actions = actions_for_match(&item);
|
||||
@@ -453,8 +453,8 @@ impl NyaTermApp {
|
||||
|| view.output_burst_bytes > 0
|
||||
|| view.performance_mode == TerminalPerformanceMode::Overloaded;
|
||||
terminal_expensive_interactions_enabled(
|
||||
self.settings.summary.terminal_action_links_enabled
|
||||
&& !self.settings.summary.terminal_low_latency_mode,
|
||||
self.settings.summary().terminal_action_links_enabled
|
||||
&& !self.settings.summary().terminal_low_latency_mode,
|
||||
is_active,
|
||||
render_degraded,
|
||||
runtime_output_pressure,
|
||||
|
||||
@@ -68,7 +68,7 @@ pub(in crate::features) fn terminal_bounds_tracker(
|
||||
if input_entity
|
||||
.read(cx)
|
||||
.settings
|
||||
.summary
|
||||
.summary()
|
||||
.interaction_mac_ime_compatibility
|
||||
{
|
||||
window.handle_input(&focus, ElementInputHandler::new(bounds, input_entity), cx);
|
||||
|
||||
@@ -25,7 +25,7 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn fallback_terminal_cell_size(&self) -> (f32, f32) {
|
||||
let font_size = self.settings.summary.terminal_font_size.max(8) as f32;
|
||||
let font_size = self.settings.summary().terminal_font_size.max(8) as f32;
|
||||
// Prefer painted fixed 18px when font is near default; scale with font otherwise.
|
||||
let cell_h = if (font_size - 14.).abs() < 0.5 {
|
||||
18.
|
||||
@@ -40,7 +40,7 @@ impl NyaTermApp {
|
||||
/// Refresh monospaced cell metrics from GPUI TextSystem for the configured terminal font.
|
||||
|
||||
pub(in crate::features) fn refresh_terminal_cell_metrics(&mut self, cx: &App) {
|
||||
let font_size = self.settings.summary.terminal_font_size.max(8) as f32;
|
||||
let font_size = self.settings.summary().terminal_font_size.max(8) as f32;
|
||||
let family = self.gpui_terminal_font_family();
|
||||
let text_system = cx.text_system();
|
||||
let font_id = text_system.resolve_font(&gpui::font(SharedString::from(family)));
|
||||
@@ -68,9 +68,9 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn terminal_content_insets(&self) -> TerminalViewportInsets {
|
||||
if self.settings.summary.terminal_show_workspace_padding
|
||||
&& !self.settings.summary.terminal_show_line_numbers
|
||||
&& !self.settings.summary.terminal_show_timestamps
|
||||
if self.settings.summary().terminal_show_workspace_padding
|
||||
&& !self.settings.summary().terminal_show_line_numbers
|
||||
&& !self.settings.summary().terminal_show_timestamps
|
||||
{
|
||||
// Tauri applies workspace padding as `pl-2`; it does not add a
|
||||
// default margin or vertical padding around the terminal grid.
|
||||
@@ -98,9 +98,9 @@ impl NyaTermApp {
|
||||
let snapshot = self.terminal_snapshot_for_session(session_id, display_offset);
|
||||
terminal_gutter_metrics(
|
||||
cell_w,
|
||||
self.settings.summary.terminal_show_timestamps,
|
||||
self.settings.summary.terminal_show_timestamp_milliseconds,
|
||||
self.settings.summary.terminal_show_line_numbers,
|
||||
self.settings.summary().terminal_show_timestamps,
|
||||
self.settings.summary().terminal_show_timestamp_milliseconds,
|
||||
self.settings.summary().terminal_show_line_numbers,
|
||||
terminal_line_number_digits(snapshot.as_ref()),
|
||||
)
|
||||
.total_width()
|
||||
|
||||
+3
-3
@@ -352,12 +352,12 @@ impl NyaTermApp {
|
||||
} else {
|
||||
selected.end
|
||||
};
|
||||
if self.settings.summary.interaction_copy_on_select {
|
||||
if self.settings.summary().interaction_copy_on_select {
|
||||
let _ = self.copy_terminal_selection(cx);
|
||||
}
|
||||
let _ = self.move_smart_input_cursor(target, cx);
|
||||
self.clear_terminal_selection(cx);
|
||||
} else if self.settings.summary.interaction_copy_on_select {
|
||||
} else if self.settings.summary().interaction_copy_on_select {
|
||||
let _ = self.copy_terminal_selection(cx);
|
||||
} else if self.terminal.selection.selection.is_some() {
|
||||
// One shell notify for status after drag ends (not per mouse move).
|
||||
@@ -452,7 +452,7 @@ impl NyaTermApp {
|
||||
}
|
||||
let idx = cell.col.min(cells.len().saturating_sub(1));
|
||||
// xterm wordSeparator semantics: characters listed are separators, not word body.
|
||||
let separators = self.settings.summary.interaction_word_separators.as_str();
|
||||
let separators = self.settings.summary().interaction_word_separators.as_str();
|
||||
let is_word = |cell: &TerminalTextCell| terminal_text_cell_is_word(cell, separators);
|
||||
if !is_word(&cells[idx]) {
|
||||
return (idx, idx.saturating_add(1));
|
||||
|
||||
@@ -50,9 +50,9 @@ impl NyaTermApp {
|
||||
&& self
|
||||
.terminal_protocol_state_for_session(&session_id)
|
||||
.mouse_reporting;
|
||||
let low_latency_mode = self.settings.summary.terminal_low_latency_mode;
|
||||
let low_latency_mode = self.settings.summary().terminal_low_latency_mode;
|
||||
let action_links_enabled =
|
||||
self.settings.summary.terminal_action_links_enabled && !low_latency_mode;
|
||||
self.settings.summary().terminal_action_links_enabled && !low_latency_mode;
|
||||
let render_output_pressure = self.runtime_output_pressure_active();
|
||||
let render_pressure = self
|
||||
.terminal
|
||||
@@ -98,7 +98,7 @@ impl NyaTermApp {
|
||||
);
|
||||
let action_link_matcher_key = terminal_action_link_matcher_key(
|
||||
action_links_enabled,
|
||||
&self.settings.summary.terminal_action_links_matchers,
|
||||
&self.settings.summary().terminal_action_links_matchers,
|
||||
);
|
||||
let keyword_rules = if session_id.is_empty() {
|
||||
if render_degraded || !is_active {
|
||||
@@ -132,7 +132,7 @@ impl NyaTermApp {
|
||||
// cursor placement, or when there is no session (empty bootstrap canvas).
|
||||
let needs_shell_viewport_snapshot = session_id.is_empty()
|
||||
|| (is_active
|
||||
&& self.settings.summary.interaction_mac_ime_compatibility
|
||||
&& self.settings.summary().interaction_mac_ime_compatibility
|
||||
&& !self.terminal.input.ime_marked_text.is_empty());
|
||||
let snapshot = if needs_shell_viewport_snapshot {
|
||||
self.terminal_snapshot_for_session(
|
||||
@@ -150,16 +150,16 @@ impl NyaTermApp {
|
||||
let snapshot_rows = snapshot.row_count();
|
||||
let snapshot_cols = snapshot.cols;
|
||||
let viewport_snapshot_duration = snapshot_stage_started_at.elapsed();
|
||||
let show_line_numbers = self.settings.summary.terminal_show_line_numbers;
|
||||
let show_timestamps = self.settings.summary.terminal_show_timestamps;
|
||||
let show_timestamp_ms = self.settings.summary.terminal_show_timestamp_milliseconds;
|
||||
let show_line_numbers = self.settings.summary().terminal_show_line_numbers;
|
||||
let show_timestamps = self.settings.summary().terminal_show_timestamps;
|
||||
let show_timestamp_ms = self.settings.summary().terminal_show_timestamp_milliseconds;
|
||||
let gutter_enabled = show_line_numbers || show_timestamps;
|
||||
// Prefer remote cursor visibility/shape from the terminal model; settings
|
||||
// supply the default paint style when the model reports a block cursor.
|
||||
let remote_cursor_visible = snapshot.cursor.visible
|
||||
&& snapshot.cursor.shape != nyaterm_terminal::CursorShape::Hidden
|
||||
&& cursor_row != usize::MAX;
|
||||
let blink_enabled = self.settings.summary.cursor_blink || snapshot.cursor.blinking;
|
||||
let blink_enabled = self.settings.summary().cursor_blink || snapshot.cursor.blinking;
|
||||
let show_cursor = is_active
|
||||
&& !session_id.is_empty()
|
||||
&& !is_disconnected
|
||||
@@ -169,8 +169,8 @@ impl NyaTermApp {
|
||||
let cursor_style = match snapshot.cursor.shape {
|
||||
nyaterm_terminal::CursorShape::Underline => "underline".to_string(),
|
||||
nyaterm_terminal::CursorShape::Beam => "bar".to_string(),
|
||||
nyaterm_terminal::CursorShape::Hidden => self.settings.summary.cursor_style.clone(),
|
||||
nyaterm_terminal::CursorShape::Block => self.settings.summary.cursor_style.clone(),
|
||||
nyaterm_terminal::CursorShape::Hidden => self.settings.summary().cursor_style.clone(),
|
||||
nyaterm_terminal::CursorShape::Block => self.settings.summary().cursor_style.clone(),
|
||||
};
|
||||
let (abs_start, abs_end) = terminal_snapshot_absolute_range(&snapshot);
|
||||
let _ = abs_end;
|
||||
@@ -333,7 +333,7 @@ impl NyaTermApp {
|
||||
let terminal_font_family = self.gpui_terminal_font_family();
|
||||
let ime_preedit_text = (is_active
|
||||
&& !session_id.is_empty()
|
||||
&& self.settings.summary.interaction_mac_ime_compatibility
|
||||
&& self.settings.summary().interaction_mac_ime_compatibility
|
||||
&& !self.terminal.input.ime_marked_text.is_empty())
|
||||
.then(|| self.terminal.input.ime_marked_text.clone());
|
||||
let ime_preedit_position = ime_preedit_text.as_ref().map(|_| {
|
||||
@@ -409,7 +409,7 @@ impl NyaTermApp {
|
||||
.pr(px(8.))
|
||||
.text_color(rgb(palette.text_dimmed))
|
||||
.font_family(terminal_font_family.clone())
|
||||
.text_size(px(self.settings.summary.terminal_font_size as f32))
|
||||
.text_size(px(self.settings.summary().terminal_font_size as f32))
|
||||
.when(show_timestamps, |this| {
|
||||
this.child(div().w(px(ts_w)).flex_none().child(ts_label))
|
||||
})
|
||||
@@ -464,9 +464,9 @@ impl NyaTermApp {
|
||||
cell_h,
|
||||
palette,
|
||||
terminal_font_family.clone(),
|
||||
self.settings.summary.terminal_font_size as f32,
|
||||
self.settings.summary.terminal_font_weight as f32,
|
||||
self.settings.summary.terminal_font_weight_bold as f32,
|
||||
self.settings.summary().terminal_font_size as f32,
|
||||
self.settings.summary().terminal_font_weight as f32,
|
||||
self.settings.summary().terminal_font_weight_bold as f32,
|
||||
);
|
||||
if let Some(cache) = layout_cache {
|
||||
grid = grid.with_layout_cache(cache);
|
||||
@@ -487,9 +487,9 @@ impl NyaTermApp {
|
||||
cell_h,
|
||||
palette,
|
||||
terminal_font_family.clone(),
|
||||
self.settings.summary.terminal_font_size as f32,
|
||||
self.settings.summary.terminal_font_weight as f32,
|
||||
self.settings.summary.terminal_font_weight_bold as f32,
|
||||
self.settings.summary().terminal_font_size as f32,
|
||||
self.settings.summary().terminal_font_weight as f32,
|
||||
self.settings.summary().terminal_font_weight_bold as f32,
|
||||
);
|
||||
if let Some(cache) = layout_cache {
|
||||
grid = grid.with_layout_cache(cache);
|
||||
@@ -507,7 +507,7 @@ impl NyaTermApp {
|
||||
.unwrap_or(palette.link);
|
||||
let sync_status_label = if sync_is_paused { "Paused" } else { "Syncing" };
|
||||
let output_session_id = session_id.clone();
|
||||
let terminal_font_size = self.settings.summary.terminal_font_size as f32;
|
||||
let terminal_font_size = self.settings.summary().terminal_font_size as f32;
|
||||
let performance_overlay = self
|
||||
.terminal
|
||||
.view
|
||||
@@ -581,7 +581,7 @@ impl NyaTermApp {
|
||||
.font_family(terminal_font_family.clone())
|
||||
.text_size(px(terminal_font_size))
|
||||
.font_weight(FontWeight(
|
||||
self.settings.summary.terminal_font_weight as f32,
|
||||
self.settings.summary().terminal_font_weight as f32,
|
||||
))
|
||||
.text_color(rgb(palette.terminal_fg))
|
||||
.child(
|
||||
@@ -855,7 +855,7 @@ impl NyaTermApp {
|
||||
this.close_action_link_menu(cx);
|
||||
let mods = event.modifiers;
|
||||
let skip_selection =
|
||||
this.settings.summary.terminal_action_links_enabled
|
||||
this.settings.summary().terminal_action_links_enabled
|
||||
&& (mods.alt || mods.control || mods.platform);
|
||||
if !skip_selection {
|
||||
this.start_terminal_selection_for_session(
|
||||
@@ -893,7 +893,7 @@ impl NyaTermApp {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if this.settings.summary.interaction_right_click_paste {
|
||||
if this.settings.summary().interaction_right_click_paste {
|
||||
this.paste_from_clipboard(window, cx);
|
||||
this.clear_terminal_selection(cx);
|
||||
} else {
|
||||
@@ -947,7 +947,7 @@ impl NyaTermApp {
|
||||
}
|
||||
window.focus(&this.terminal.input.focus);
|
||||
let modifiers = event.modifiers();
|
||||
if this.settings.summary.terminal_action_links_enabled {
|
||||
if this.settings.summary().terminal_action_links_enabled {
|
||||
if modifiers.alt {
|
||||
if this.try_open_action_link_menu_at_click(event, cx) {
|
||||
cx.stop_propagation();
|
||||
@@ -1032,7 +1032,7 @@ impl NyaTermApp {
|
||||
.text_color(rgb(palette.terminal_fg))
|
||||
.font_family(terminal_font_family.clone())
|
||||
.text_size(px(
|
||||
self.settings.summary.terminal_font_size as f32
|
||||
self.settings.summary().terminal_font_size as f32,
|
||||
))
|
||||
.child(marked_text),
|
||||
)
|
||||
@@ -1260,7 +1260,7 @@ impl NyaTermApp {
|
||||
expensive_interactions_enabled,
|
||||
output_burst_bytes,
|
||||
?performance_mode,
|
||||
action_links_enabled = self.settings.summary.terminal_action_links_enabled,
|
||||
action_links_enabled = self.settings.summary().terminal_action_links_enabled,
|
||||
search_open = self.terminal.search.open,
|
||||
search_matches = search_matches_len,
|
||||
render_cache_hits,
|
||||
|
||||
@@ -44,7 +44,7 @@ impl Render for TransferExternalSyncWindow {
|
||||
(
|
||||
app.theme_palette(),
|
||||
app.gpui_ui_font_family(),
|
||||
app.settings.summary.ui_font_size.clamp(12, 24) as f32,
|
||||
app.settings.summary().ui_font_size.clamp(12, 24) as f32,
|
||||
app.tr("fileExplorer.fileModified").to_string(),
|
||||
)
|
||||
});
|
||||
|
||||
@@ -260,7 +260,7 @@ impl NyaTermApp {
|
||||
entry.file_type == SftpFileType::Directory
|
||||
&& entry.name != "."
|
||||
&& entry.name != ".."
|
||||
&& (self.settings.summary.ui_file_explorer_show_hidden_files
|
||||
&& (self.settings.summary().ui_file_explorer_show_hidden_files
|
||||
|| !entry.name.starts_with('.'))
|
||||
});
|
||||
entries.sort_by(|left, right| {
|
||||
|
||||
@@ -5,10 +5,12 @@ use crate::features::NyaTermApp;
|
||||
impl NyaTermApp {
|
||||
pub(in crate::features) fn sftp_transfer_options(&self) -> SftpTransferOptions {
|
||||
SftpTransferOptions::default()
|
||||
.with_buffer_size_bytes(self.settings.summary.transfer_buffer_size as usize * 1024)
|
||||
.with_max_retries(self.settings.summary.transfer_max_retries)
|
||||
.with_preserve_timestamps(self.settings.summary.transfer_preserve_timestamps)
|
||||
.with_default_file_permissions(&self.settings.summary.transfer_default_file_permissions)
|
||||
.with_resume_broken_transfer(self.settings.summary.transfer_resume_broken_transfer)
|
||||
.with_buffer_size_bytes(self.settings.summary().transfer_buffer_size as usize * 1024)
|
||||
.with_max_retries(self.settings.summary().transfer_max_retries)
|
||||
.with_preserve_timestamps(self.settings.summary().transfer_preserve_timestamps)
|
||||
.with_default_file_permissions(
|
||||
&self.settings.summary().transfer_default_file_permissions,
|
||||
)
|
||||
.with_resume_broken_transfer(self.settings.summary().transfer_resume_broken_transfer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ impl NyaTermApp {
|
||||
};
|
||||
let _ = this.update(cx, |this, cx| {
|
||||
if let Some(path) = path {
|
||||
this.settings.summary.transfer_download_path = path.display().to_string();
|
||||
this.settings
|
||||
.set_transfer_download_path(path.display().to_string());
|
||||
this.save_transfer_settings("transfer download path saved", cx);
|
||||
} else {
|
||||
this.terminal.view.status = "download path selection cancelled".to_string();
|
||||
@@ -64,7 +65,7 @@ impl NyaTermApp {
|
||||
};
|
||||
let _ = this.update(cx, |this, cx| {
|
||||
if let Some(path) = path {
|
||||
this.settings.summary.recording_path = path.display().to_string();
|
||||
this.settings.set_recording_path(path.display().to_string());
|
||||
this.save_recording_settings(cx);
|
||||
} else {
|
||||
this.terminal.view.status = "recording path selection cancelled".to_string();
|
||||
@@ -95,7 +96,8 @@ impl NyaTermApp {
|
||||
};
|
||||
let _ = this.update(cx, |this, cx| {
|
||||
if let Some(path) = path {
|
||||
this.settings.summary.transfer_default_editor = path.display().to_string();
|
||||
this.settings
|
||||
.set_transfer_default_editor(path.display().to_string());
|
||||
this.save_transfer_settings("transfer editor path saved", cx);
|
||||
} else {
|
||||
this.terminal.view.status = "editor path selection cancelled".to_string();
|
||||
@@ -108,7 +110,7 @@ impl NyaTermApp {
|
||||
}
|
||||
|
||||
pub(in crate::features) fn resolved_transfer_download_dir(&self) -> Option<PathBuf> {
|
||||
let configured = self.settings.summary.transfer_download_path.trim();
|
||||
let configured = self.settings.summary().transfer_download_path.trim();
|
||||
if configured.is_empty() {
|
||||
return default_transfer_download_dir();
|
||||
}
|
||||
@@ -149,7 +151,7 @@ impl NyaTermApp {
|
||||
if value.is_empty() {
|
||||
let file_name =
|
||||
download_file_name_from_remote_path(&self.transfer.normalized_remote_path());
|
||||
let download_path = self.settings.summary.transfer_download_path.trim();
|
||||
let download_path = self.settings.summary().transfer_download_path.trim();
|
||||
if download_path.is_empty() {
|
||||
PathBuf::from(file_name)
|
||||
} else {
|
||||
|
||||
@@ -236,8 +236,13 @@ these as staged extraction candidates, not as formatting-only refactor targets.
|
||||
and backing child settings-module-private. Cross-domain persistence adapters
|
||||
now update its message/readiness through owner methods, rendering receives a
|
||||
borrowed immutable view, and store reopen replaces path/message/readiness as
|
||||
one transition. Filesystem prompts, persistence and GPUI notification stay
|
||||
in their existing adapters.
|
||||
one transition. The next compatibility-catalog batch made
|
||||
`AppSettingsSummary`, `KeywordHighlightConfig` and staged master-password
|
||||
state settings-module-private as well. Cross-domain readers now use borrowed
|
||||
immutable access, appearance/keyword/browser preferences enter through
|
||||
semantic transitions, and the shell persists its complete UI layout through
|
||||
one typed owner update instead of piecemeal field writes. Filesystem prompts,
|
||||
persistence and GPUI notification stay in their existing adapters.
|
||||
- Translation and native-update background state now have authoritative
|
||||
`TranslationFeatureState` and `UpdateFeatureState` owners. Eighteen app fields
|
||||
became two feature fields; each owner constructs and retains its own job
|
||||
@@ -1491,6 +1496,7 @@ Current ownership map:
|
||||
| Command history and persistence worker | Private state in `NyaTermApp.commands` | Persisted catalog plus background runtime | History snapshots, queue admission, event polling and idle checks enter through `CommandFeatureState`; failed optimistic use-count updates roll back on the owner. |
|
||||
| Send-command composer/options/progress | Private children in `NyaTermApp.send_command` | Transient editor and send lifecycle | Views receive immutable presentation data; control edits, mutually-exclusive menus, data/mode defaults, progress counters and cancellation enter through `SendCommandFeatureState`. Session selection, terminal writes, GPUI/text-input routing and status remain in adapters. |
|
||||
| Settings interaction and prompts | Private children in `NyaTermApp.settings` | Transient settings UI and prompt lifecycle | Search-engine rows, keyword-highlight editing, appearance menus, keybinding recording/search and config/diagnostics/import/password prompt admission enter through `SettingsFeatureState`; views use immutable presentation values and read-only focus/font access. Persistence, native filesystem prompts, text inputs and GPUI notification remain in adapters. |
|
||||
| Application settings and keyword catalogs | Settings-module-private children in `NyaTermApp.settings` | Compatibility-sensitive persisted configuration plus staged master-password input | Cross-domain consumers borrow immutable summaries/configs and use semantic owner transitions. Shell UI layout is replaced through one typed update; master-password presentation is a non-`Debug` borrowed view. Serialization, encryption and persistence remain in `nyaterm-core` and existing adapters. |
|
||||
| Global storage status | Settings-module-private child in `NyaTermApp.settings` | Runtime persistence health/presentation state | Cross-domain persistence adapters update message/readiness through `SettingsFeatureState`; rendering receives a borrowed immutable view, while store reopen replaces path/message/readiness together. Database work and compatibility handling remain in existing adapters and `nyaterm-core`. |
|
||||
| AI settings/chat/history/discovery/agent/panel | AI-module-private children in `NyaTermApp.ai` | Persisted settings plus transient UI and background lifecycle | Desktop consumers use read-only slices/queries and semantic transitions; settings draft groups, menu exclusion, confirmations, request/focus preparation, detected-error throttling, picker clamping and Agent capture/reset enter through `AiFeatureState`. Persistence, terminal-context collection, GPUI focus/rendering and notification remain in adapters. |
|
||||
| Shell viewport/navigation/panels/chrome/workspace | Shell-module-private children in `NyaTermApp.shell` | Transient GPUI composition and interaction state | Other desktop modules use read-only geometry/navigation/pane queries and semantic transitions; menu exclusion, settings-window lifecycle, mobile panels, failure chrome, submenu paths and pane ownership update through `ShellFeatureState`. Persistence, rendering, GPUI windows/notification and terminal coordination remain in adapters. |
|
||||
@@ -1755,6 +1761,12 @@ honest remaining list.
|
||||
implementation type settings-module-private, moved cross-domain status
|
||||
writes behind owner transitions, and gave rendering a borrowed immutable
|
||||
view without changing storage execution or compatibility formats.
|
||||
The following settings compatibility-catalog batch completed child
|
||||
encapsulation for `SettingsFeatureState`: summary, keyword-highlight config
|
||||
and staged master-password state are now settings-module-private, all
|
||||
cross-domain reads are immutable, keyword/appearance/browser mutations use
|
||||
owner transitions, and UI layout persistence applies one typed atomic
|
||||
update. No mutable-reference accessor was introduced.
|
||||
What remains at the
|
||||
composition root is stores, runtime and focused feature owners.
|
||||
Group by cohesion where a cluster exists; do not force the count down for
|
||||
|
||||
@@ -268,6 +268,27 @@ check_no_multiline_matches_excluding \
|
||||
'(self|this|app)\.settings[[:space:]]*\.[[:space:]]*store_status[[:space:]]*(\.|=)' \
|
||||
crates/nyaterm-desktop/src/features \
|
||||
'crates/nyaterm-desktop/src/features/settings/**'
|
||||
check_no_multiline_matches \
|
||||
"SettingsFeatureState compatibility children must stay inside the settings module" \
|
||||
'struct[[:space:]]+SettingsFeatureState[[:space:]]*\{[^}]*pub([[:space:]]|\(crate\)|\(in crate\)|\(in crate::features\))[[:space:]]+(summary|keyword_config|master_password)[[:space:]]*:' \
|
||||
crates/nyaterm-desktop/src/features/settings/state.rs
|
||||
check_no_matches \
|
||||
"SettingsMasterPasswordState implementation must stay inside the settings module" \
|
||||
'pub([[:space:]]|\(crate\)|\(in crate\)|\(in crate::features\))[[:space:]]+struct[[:space:]]+SettingsMasterPasswordState' \
|
||||
crates/nyaterm-desktop/src/features/settings/catalog.rs
|
||||
check_no_matches \
|
||||
"settings compatibility implementation types must not be re-exported" \
|
||||
'pub([^;]*)use([^;]*)(SettingsMasterPasswordState|StoreStatus)' \
|
||||
crates/nyaterm-desktop/src/features/settings/mod.rs
|
||||
check_no_multiline_matches_excluding \
|
||||
"settings compatibility children must use SettingsFeatureState methods outside settings" \
|
||||
'(self|this|app)\.settings[[:space:]]*\.[[:space:]]*(summary|keyword_config|master_password)[[:space:]]*(\.|=|\[)' \
|
||||
crates/nyaterm-desktop/src/features \
|
||||
'crates/nyaterm-desktop/src/features/settings/**'
|
||||
check_no_matches \
|
||||
"settings compatibility state must not expose mutable-reference accessors" \
|
||||
'fn[[:space:]]+(summary|keyword_config|master_password)(_mut|_mutable)|->[[:space:]]*&mut[[:space:]]+(AppSettingsSummary|KeywordHighlightConfig|SettingsMasterPasswordState)' \
|
||||
crates/nyaterm-desktop/src/features/settings
|
||||
|
||||
check_no_matches \
|
||||
"translation state must stay grouped under TranslationFeatureState" \
|
||||
|
||||
Reference in New Issue
Block a user