chore: remove experiments from settings tui
This commit is contained in:
parent
02fe7d7659
commit
8d190eddda
|
|
@ -6,6 +6,7 @@
|
|||
- Added `ui.tab_bar_position = "bottom"` to place the desktop tab row below terminal panes.
|
||||
|
||||
### Changed
|
||||
- Experimental options are no longer exposed in the Settings TUI and remain available through the config file.
|
||||
- Agent status indicators now use the same static workspace marks across the sidebar, navigator, and mobile views, eliminating continuous spinner rendering while agents work.
|
||||
- Relicensed Herdr from AGPL-3.0-or-later to Apache-2.0.
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ Herdr サーバーが停止して再起動すると、元のペインのプロ
|
|||
|
||||
ペイン画面履歴は、サーバーの完全な再起動後に直近のターミナル内容を復元します。復元されるのは Herdr が表示できるものであって、元のプロセスではありません。
|
||||
|
||||
ペイン出力にはシークレット、トークン、プロンプト、コマンド出力が含まれうるため、これはデフォルトで無効です。Settings > Experiments > pane screen history から、または次の設定で有効にします:
|
||||
ペイン出力にはシークレット、トークン、プロンプト、コマンド出力が含まれうるため、これはデフォルトで無効です。設定ファイルで有効にします:
|
||||
|
||||
```toml
|
||||
[experimental]
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ Snapshot restore does not preserve running shells, servers, tests, or arbitrary
|
|||
|
||||
Pane screen history restores recent terminal contents after a full server restart. It restores what Herdr can show, not the old process.
|
||||
|
||||
This is off by default because pane output can include secrets, tokens, prompts, and command output. Enable it from Settings > Experiments > pane screen history or with:
|
||||
This is off by default because pane output can include secrets, tokens, prompts, and command output. Enable it in the config file:
|
||||
|
||||
```toml
|
||||
[experimental]
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ herdr
|
|||
|
||||
窗格屏幕历史在服务器完全重启后恢复最近的终端内容。它恢复的是 Herdr 能展示的内容,而不是原来的进程。
|
||||
|
||||
它默认关闭,因为窗格输出可能包含密钥、令牌、提示词和命令输出。可以在 Settings > Experiments > pane screen history 中开启,或者:
|
||||
它默认关闭,因为窗格输出可能包含密钥、令牌、提示词和命令输出。可以在配置文件中开启:
|
||||
|
||||
```toml
|
||||
[experimental]
|
||||
|
|
|
|||
|
|
@ -92,27 +92,6 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn save_pane_history_persistence(&mut self, enabled: bool) {
|
||||
if self.update_config_file("pane screen history", |content| {
|
||||
crate::config::upsert_section_bool(content, "experimental", "pane_history", enabled)
|
||||
}) {
|
||||
self.apply_config_from_disk(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn save_switch_ascii_input_source_in_prefix(&mut self, enabled: bool) {
|
||||
if self.update_config_file("prefix ascii input source", |content| {
|
||||
crate::config::upsert_section_bool(
|
||||
content,
|
||||
"experimental",
|
||||
"switch_ascii_input_source_in_prefix",
|
||||
enabled,
|
||||
)
|
||||
}) {
|
||||
self.apply_config_from_disk(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn save_agent_panel_sort(&mut self, sort: crate::app::state::AgentPanelSort) {
|
||||
let value = match sort {
|
||||
crate::app::state::AgentPanelSort::Spaces => {
|
||||
|
|
|
|||
|
|
@ -344,12 +344,6 @@ impl App {
|
|||
SettingsAction::SaveAgentBorderLabels(enabled) => {
|
||||
self.save_agent_border_labels(enabled)
|
||||
}
|
||||
SettingsAction::SavePaneHistory(enabled) => {
|
||||
self.save_pane_history_persistence(enabled)
|
||||
}
|
||||
SettingsAction::SaveSwitchAsciiInputSourceInPrefix(enabled) => {
|
||||
self.save_switch_ascii_input_source_in_prefix(enabled)
|
||||
}
|
||||
SettingsAction::InstallRecommendedIntegrations => {
|
||||
self.install_recommended_integrations()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use ratatui::layout::Rect;
|
|||
|
||||
use crate::{
|
||||
app::{
|
||||
state::{AppState, ExperimentSetting, SettingsSection, THEME_NAMES},
|
||||
state::{AppState, SettingsSection, THEME_NAMES},
|
||||
App, Mode,
|
||||
},
|
||||
config::ToastDelivery,
|
||||
|
|
@ -17,25 +17,9 @@ pub(super) enum SettingsAction {
|
|||
SaveSound(bool),
|
||||
SaveToastDelivery(ToastDelivery),
|
||||
SaveAgentBorderLabels(bool),
|
||||
SavePaneHistory(bool),
|
||||
SaveSwitchAsciiInputSourceInPrefix(bool),
|
||||
InstallRecommendedIntegrations,
|
||||
}
|
||||
|
||||
/// Map an Experiments row index to the toggle action that flips it.
|
||||
fn experiment_toggle_action(state: &AppState, idx: usize) -> Option<SettingsAction> {
|
||||
match ExperimentSetting::ALL.get(idx).copied()? {
|
||||
ExperimentSetting::PaneHistory => Some(SettingsAction::SavePaneHistory(
|
||||
!ExperimentSetting::PaneHistory.enabled(state),
|
||||
)),
|
||||
ExperimentSetting::SwitchAsciiInputSourceInPrefix => {
|
||||
Some(SettingsAction::SaveSwitchAsciiInputSourceInPrefix(
|
||||
!ExperimentSetting::SwitchAsciiInputSourceInPrefix.enabled(state),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub(crate) fn handle_settings_key(&mut self, key: KeyEvent) {
|
||||
let previous_section = self.state.settings.section;
|
||||
|
|
@ -47,12 +31,6 @@ impl App {
|
|||
SettingsAction::SaveAgentBorderLabels(enabled) => {
|
||||
self.save_agent_border_labels(enabled)
|
||||
}
|
||||
SettingsAction::SavePaneHistory(enabled) => {
|
||||
self.save_pane_history_persistence(enabled)
|
||||
}
|
||||
SettingsAction::SaveSwitchAsciiInputSourceInPrefix(enabled) => {
|
||||
self.save_switch_ascii_input_source_in_prefix(enabled)
|
||||
}
|
||||
SettingsAction::InstallRecommendedIntegrations => {
|
||||
self.install_recommended_integrations()
|
||||
}
|
||||
|
|
@ -171,7 +149,7 @@ pub(super) fn update_settings_state(state: &mut AppState, key: KeyEvent) -> Opti
|
|||
state.settings.list.selected = usize::from(!state.sound_enabled());
|
||||
}
|
||||
KeyCode::BackTab | KeyCode::Left | KeyCode::Char('h') => {
|
||||
state.settings.section = SettingsSection::Experiments;
|
||||
state.settings.section = SettingsSection::Integrations;
|
||||
state.settings.list.selected = 0;
|
||||
}
|
||||
_ => match super::modal::modal_action_from_key(&key, super::modal::SETTINGS_ACTIONS) {
|
||||
|
|
@ -251,30 +229,6 @@ pub(super) fn update_settings_state(state: &mut AppState, key: KeyEvent) -> Opti
|
|||
}
|
||||
}
|
||||
},
|
||||
SettingsSection::Experiments => match key.code {
|
||||
KeyCode::Up | KeyCode::Char('k') => state.settings.list.move_prev(),
|
||||
KeyCode::Down | KeyCode::Char('j') => {
|
||||
state.settings.list.move_next(ExperimentSetting::ALL.len())
|
||||
}
|
||||
KeyCode::Enter | KeyCode::Char(' ') => {
|
||||
return experiment_toggle_action(state, state.settings.list.selected);
|
||||
}
|
||||
KeyCode::BackTab | KeyCode::Left | KeyCode::Char('h') => {
|
||||
state.settings.section = SettingsSection::Integrations;
|
||||
state.settings.list.selected = 0;
|
||||
}
|
||||
KeyCode::Tab | KeyCode::Right | KeyCode::Char('l') => {
|
||||
state.settings.section = SettingsSection::Theme;
|
||||
state.settings.list.selected = current_theme_index(&state.theme_name);
|
||||
}
|
||||
_ => {
|
||||
if let Some(super::modal::ModalAction::Close) =
|
||||
super::modal::modal_action_from_key(&key, super::modal::SETTINGS_ACTIONS)
|
||||
{
|
||||
cancel_settings(state);
|
||||
}
|
||||
}
|
||||
},
|
||||
SettingsSection::Integrations => match key.code {
|
||||
KeyCode::Enter | KeyCode::Char(' ') if integrations_need_install(state) => {
|
||||
return Some(SettingsAction::InstallRecommendedIntegrations);
|
||||
|
|
@ -284,8 +238,8 @@ pub(super) fn update_settings_state(state: &mut AppState, key: KeyEvent) -> Opti
|
|||
state.settings.list.selected = usize::from(!state.agent_border_labels_enabled());
|
||||
}
|
||||
KeyCode::Tab | KeyCode::Right | KeyCode::Char('l') => {
|
||||
state.settings.section = SettingsSection::Experiments;
|
||||
state.settings.list.selected = 0;
|
||||
state.settings.section = SettingsSection::Theme;
|
||||
state.settings.list.selected = current_theme_index(&state.theme_name);
|
||||
}
|
||||
_ => match super::modal::modal_action_from_key(&key, super::modal::SETTINGS_ACTIONS) {
|
||||
Some(super::modal::ModalAction::Apply) => return apply_settings(state),
|
||||
|
|
@ -312,7 +266,6 @@ pub(crate) fn open_settings_at(state: &mut AppState, section: SettingsSection) {
|
|||
SettingsSection::Sound => usize::from(!state.sound_enabled()),
|
||||
SettingsSection::Toast => toast_delivery_index(state.toast_delivery()),
|
||||
SettingsSection::PaneLabels => usize::from(!state.agent_border_labels_enabled()),
|
||||
SettingsSection::Experiments => 0,
|
||||
SettingsSection::Integrations => 0,
|
||||
};
|
||||
state.mode = Mode::Settings;
|
||||
|
|
@ -407,14 +360,6 @@ impl AppState {
|
|||
None
|
||||
}
|
||||
}
|
||||
SettingsSection::Experiments => {
|
||||
let list_y = area.y + 3;
|
||||
if row >= list_y && row < list_y + ExperimentSetting::ALL.len() as u16 {
|
||||
Some((row - list_y) as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
SettingsSection::Integrations => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -431,7 +376,6 @@ impl AppState {
|
|||
SettingsSection::PaneLabels => {
|
||||
usize::from(!self.agent_border_labels_enabled())
|
||||
}
|
||||
SettingsSection::Experiments => 0,
|
||||
SettingsSection::Integrations => 0,
|
||||
});
|
||||
return None;
|
||||
|
|
@ -455,7 +399,6 @@ impl AppState {
|
|||
let enabled = idx == 0;
|
||||
Some(SettingsAction::SaveAgentBorderLabels(enabled))
|
||||
}
|
||||
SettingsSection::Experiments => experiment_toggle_action(self, idx),
|
||||
SettingsSection::Integrations => None,
|
||||
};
|
||||
}
|
||||
|
|
@ -543,46 +486,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn settings_experiments_toggles_pane_history() {
|
||||
let mut state = state_with_workspaces(&["test"]);
|
||||
state.pane_history_persistence = false;
|
||||
open_settings_at(&mut state, SettingsSection::Experiments);
|
||||
|
||||
let action = update_settings_state(
|
||||
&mut state,
|
||||
KeyEvent::new(KeyCode::Enter, KeyModifiers::empty()),
|
||||
);
|
||||
|
||||
assert_eq!(action, Some(SettingsAction::SavePaneHistory(true)));
|
||||
assert_eq!(state.mode, Mode::Settings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_experiments_down_then_toggle_switches_ascii_input_source() {
|
||||
let mut state = state_with_workspaces(&["test"]);
|
||||
state.switch_ascii_input_source_in_prefix = false;
|
||||
open_settings_at(&mut state, SettingsSection::Experiments);
|
||||
|
||||
update_settings_state(
|
||||
&mut state,
|
||||
KeyEvent::new(KeyCode::Down, KeyModifiers::empty()),
|
||||
);
|
||||
assert_eq!(state.settings.list.selected, 1);
|
||||
|
||||
let action = update_settings_state(
|
||||
&mut state,
|
||||
KeyEvent::new(KeyCode::Enter, KeyModifiers::empty()),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
action,
|
||||
Some(SettingsAction::SaveSwitchAsciiInputSourceInPrefix(true))
|
||||
);
|
||||
assert_eq!(state.mode, Mode::Settings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_tab_cycle_places_experiments_last() {
|
||||
fn settings_tab_cycle_wraps_after_integrations() {
|
||||
let mut state = state_with_workspaces(&["test"]);
|
||||
open_settings_at(&mut state, SettingsSection::PaneLabels);
|
||||
|
||||
|
|
@ -592,24 +496,12 @@ mod tests {
|
|||
);
|
||||
assert_eq!(state.settings.section, SettingsSection::Integrations);
|
||||
|
||||
update_settings_state(
|
||||
&mut state,
|
||||
KeyEvent::new(KeyCode::Tab, KeyModifiers::empty()),
|
||||
);
|
||||
assert_eq!(state.settings.section, SettingsSection::Experiments);
|
||||
|
||||
update_settings_state(
|
||||
&mut state,
|
||||
KeyEvent::new(KeyCode::Tab, KeyModifiers::empty()),
|
||||
);
|
||||
assert_eq!(state.settings.section, SettingsSection::Theme);
|
||||
|
||||
update_settings_state(
|
||||
&mut state,
|
||||
KeyEvent::new(KeyCode::BackTab, KeyModifiers::empty()),
|
||||
);
|
||||
assert_eq!(state.settings.section, SettingsSection::Experiments);
|
||||
|
||||
update_settings_state(
|
||||
&mut state,
|
||||
KeyEvent::new(KeyCode::BackTab, KeyModifiers::empty()),
|
||||
|
|
@ -653,43 +545,6 @@ mod tests {
|
|||
assert_eq!(app.state.settings.list.selected, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_mouse_click_toggles_pane_history() {
|
||||
let mut app = app_for_mouse_test();
|
||||
app.state.pane_history_persistence = false;
|
||||
open_settings_at(&mut app.state, SettingsSection::Experiments);
|
||||
|
||||
let area = app.state.settings_content_rect();
|
||||
let action = app.state.handle_settings_mouse(mouse(
|
||||
MouseEventKind::Down(crossterm::event::MouseButton::Left),
|
||||
area.x + 2,
|
||||
area.y + 3,
|
||||
));
|
||||
|
||||
assert_eq!(action, Some(SettingsAction::SavePaneHistory(true)));
|
||||
assert_eq!(app.state.settings.list.selected, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_mouse_click_toggles_switch_ascii_input_source_row() {
|
||||
let mut app = app_for_mouse_test();
|
||||
app.state.switch_ascii_input_source_in_prefix = false;
|
||||
open_settings_at(&mut app.state, SettingsSection::Experiments);
|
||||
|
||||
let area = app.state.settings_content_rect();
|
||||
let action = app.state.handle_settings_mouse(mouse(
|
||||
MouseEventKind::Down(crossterm::event::MouseButton::Left),
|
||||
area.x + 2,
|
||||
area.y + 4,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
action,
|
||||
Some(SettingsAction::SaveSwitchAsciiInputSourceInPrefix(true))
|
||||
);
|
||||
assert_eq!(app.state.settings.list.selected, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integration_update_badge_only_tracks_outdated_recommendations() {
|
||||
let mut state = state_with_workspaces(&["test"]);
|
||||
|
|
|
|||
|
|
@ -3326,31 +3326,6 @@ mod tests {
|
|||
let _ = std::fs::remove_dir_all(path.parent().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_save_pane_history_persists_then_applies_live_config() {
|
||||
let _guard = config_env_lock().lock().unwrap();
|
||||
let path = temp_config_path("settings-save-pane-history");
|
||||
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||
std::fs::write(&path, "onboarding = false\n").unwrap();
|
||||
std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path);
|
||||
|
||||
let mut app = test_app();
|
||||
assert!(!app.persist_pane_history);
|
||||
assert!(!app.state.pane_history_persistence);
|
||||
|
||||
app.save_pane_history_persistence(true);
|
||||
|
||||
assert!(app.persist_pane_history);
|
||||
assert!(app.state.pane_history_persistence);
|
||||
let content = std::fs::read_to_string(&path).unwrap();
|
||||
assert!(content.contains("[experimental]"));
|
||||
assert!(content.contains("pane_history = true"));
|
||||
assert!(app.state.config_diagnostic.is_none());
|
||||
|
||||
std::env::remove_var(crate::config::CONFIG_PATH_ENV_VAR);
|
||||
let _ = std::fs::remove_dir_all(path.parent().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reload_config_keeps_current_state_on_invalid_toml() {
|
||||
let _guard = config_env_lock().lock().unwrap();
|
||||
|
|
|
|||
|
|
@ -994,7 +994,6 @@ pub enum SettingsSection {
|
|||
Sound,
|
||||
Toast,
|
||||
PaneLabels,
|
||||
Experiments,
|
||||
Integrations,
|
||||
}
|
||||
|
||||
|
|
@ -1005,7 +1004,6 @@ impl SettingsSection {
|
|||
Self::Toast,
|
||||
Self::PaneLabels,
|
||||
Self::Integrations,
|
||||
Self::Experiments,
|
||||
];
|
||||
|
||||
pub fn label(self) -> &'static str {
|
||||
|
|
@ -1014,40 +1012,11 @@ impl SettingsSection {
|
|||
Self::Sound => "sound",
|
||||
Self::Toast => "toasts",
|
||||
Self::PaneLabels => "pane labels",
|
||||
Self::Experiments => "experiments",
|
||||
Self::Integrations => "integrations",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum ExperimentSetting {
|
||||
PaneHistory,
|
||||
SwitchAsciiInputSourceInPrefix,
|
||||
}
|
||||
|
||||
impl ExperimentSetting {
|
||||
pub(crate) const ALL: [Self; 2] = [Self::PaneHistory, Self::SwitchAsciiInputSourceInPrefix];
|
||||
|
||||
pub(crate) fn label(self) -> &'static str {
|
||||
match self {
|
||||
Self::PaneHistory => "pane screen history",
|
||||
Self::SwitchAsciiInputSourceInPrefix => {
|
||||
"switch to ascii input source in prefix (macOS/Windows)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enabled(self, state: &AppState) -> bool {
|
||||
match self {
|
||||
Self::PaneHistory => state.pane_history_persistence_enabled(),
|
||||
Self::SwitchAsciiInputSourceInPrefix => {
|
||||
state.switch_ascii_input_source_in_prefix_enabled()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// All built-in theme names in display order.
|
||||
pub const THEME_NAMES: &[&str] = &[
|
||||
"catppuccin",
|
||||
|
|
@ -1624,14 +1593,6 @@ impl AppState {
|
|||
self.show_agent_labels_on_pane_borders
|
||||
}
|
||||
|
||||
pub fn pane_history_persistence_enabled(&self) -> bool {
|
||||
self.pane_history_persistence
|
||||
}
|
||||
|
||||
pub fn switch_ascii_input_source_in_prefix_enabled(&self) -> bool {
|
||||
self.switch_ascii_input_source_in_prefix
|
||||
}
|
||||
|
||||
pub(crate) fn pane_exposes_host_cursor(
|
||||
&self,
|
||||
_ws_idx: usize,
|
||||
|
|
|
|||
|
|
@ -11,10 +11,7 @@ use super::widgets::{
|
|||
render_action_button, render_modal_choice_list, render_panel_shell, ActionButtonSpec,
|
||||
};
|
||||
use crate::{
|
||||
app::{
|
||||
state::{ExperimentSetting, Palette},
|
||||
AppState,
|
||||
},
|
||||
app::{state::Palette, AppState},
|
||||
config::ToastDelivery,
|
||||
};
|
||||
|
||||
|
|
@ -149,9 +146,6 @@ pub(super) fn render_settings_overlay(app: &AppState, frame: &mut Frame, area: R
|
|||
app.settings.list.selected,
|
||||
);
|
||||
}
|
||||
SettingsSection::Experiments => {
|
||||
render_settings_experiments(app, frame, content_area);
|
||||
}
|
||||
SettingsSection::Integrations => {
|
||||
render_settings_integrations(app, frame, content_area);
|
||||
}
|
||||
|
|
@ -412,120 +406,3 @@ fn render_settings_toggle(
|
|||
1,
|
||||
);
|
||||
}
|
||||
|
||||
fn render_settings_experiments(app: &AppState, frame: &mut Frame, area: Rect) {
|
||||
let p = &app.palette;
|
||||
let [desc_area, _, list_area] = Layout::vertical([
|
||||
Constraint::Length(2),
|
||||
Constraint::Length(1),
|
||||
Constraint::Min(1),
|
||||
])
|
||||
.areas::<3>(area);
|
||||
|
||||
super::widgets::render_modal_description(
|
||||
frame,
|
||||
desc_area,
|
||||
"optional features that are off by default",
|
||||
Style::default().fg(p.overlay1),
|
||||
);
|
||||
|
||||
for (idx, setting) in ExperimentSetting::ALL.iter().copied().enumerate() {
|
||||
let marker = if setting.enabled(app) { "[✓]" } else { "[ ]" };
|
||||
let style = if app.settings.list.selected == idx {
|
||||
Style::default()
|
||||
.bg(p.surface0)
|
||||
.fg(p.text)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
} else {
|
||||
Style::default().fg(p.subtext0)
|
||||
};
|
||||
let row = Rect::new(list_area.x, list_area.y + idx as u16, list_area.width, 1);
|
||||
frame.render_widget(
|
||||
Paragraph::new(format!(" {} {marker}", setting.label())).style(style),
|
||||
row,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::app::{state::SettingsSection, Mode};
|
||||
use ratatui::{backend::TestBackend, Terminal};
|
||||
|
||||
#[test]
|
||||
fn experiments_pane_history_uses_settings_checkmark_marker() {
|
||||
let mut app = AppState::test_new();
|
||||
app.pane_history_persistence = true;
|
||||
app.settings.section = SettingsSection::Experiments;
|
||||
app.settings.list.selected = 0;
|
||||
app.mode = Mode::Settings;
|
||||
|
||||
let mut terminal =
|
||||
Terminal::new(TestBackend::new(80, 24)).expect("test terminal should initialize");
|
||||
terminal
|
||||
.draw(|frame| render_settings_overlay(&app, frame, Rect::new(0, 0, 80, 24)))
|
||||
.expect("settings overlay should render");
|
||||
|
||||
let rendered = terminal
|
||||
.backend()
|
||||
.buffer()
|
||||
.content()
|
||||
.iter()
|
||||
.map(|cell| cell.symbol())
|
||||
.collect::<String>();
|
||||
|
||||
assert!(rendered.contains("pane screen history [✓]"));
|
||||
assert!(!rendered.contains("[x]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn experiments_pane_history_keeps_empty_checkbox_marker_when_disabled() {
|
||||
let mut app = AppState::test_new();
|
||||
app.pane_history_persistence = false;
|
||||
app.settings.section = SettingsSection::Experiments;
|
||||
app.settings.list.selected = 0;
|
||||
app.mode = Mode::Settings;
|
||||
|
||||
let mut terminal =
|
||||
Terminal::new(TestBackend::new(80, 24)).expect("test terminal should initialize");
|
||||
terminal
|
||||
.draw(|frame| render_settings_overlay(&app, frame, Rect::new(0, 0, 80, 24)))
|
||||
.expect("settings overlay should render");
|
||||
|
||||
let rendered = terminal
|
||||
.backend()
|
||||
.buffer()
|
||||
.content()
|
||||
.iter()
|
||||
.map(|cell| cell.symbol())
|
||||
.collect::<String>();
|
||||
|
||||
assert!(rendered.contains("pane screen history [ ]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn experiments_renders_switch_ascii_input_source_row() {
|
||||
let mut app = AppState::test_new();
|
||||
app.switch_ascii_input_source_in_prefix = true;
|
||||
app.settings.section = SettingsSection::Experiments;
|
||||
app.settings.list.selected = 1;
|
||||
app.mode = Mode::Settings;
|
||||
|
||||
let mut terminal =
|
||||
Terminal::new(TestBackend::new(80, 24)).expect("test terminal should initialize");
|
||||
terminal
|
||||
.draw(|frame| render_settings_overlay(&app, frame, Rect::new(0, 0, 80, 24)))
|
||||
.expect("settings overlay should render");
|
||||
|
||||
let rendered = terminal
|
||||
.backend()
|
||||
.buffer()
|
||||
.content()
|
||||
.iter()
|
||||
.map(|cell| cell.symbol())
|
||||
.collect::<String>();
|
||||
|
||||
assert!(rendered.contains("switch to ascii input source in prefix (macOS/Windows) [✓]"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue