use super::*;
use crate::ui_scale;
use gitcomet_core::domain::HistoryMode;
use gitcomet_core::process::{
    GitExecutablePreference, GitRuntimeState, install_git_executable_path, refresh_git_runtime,
};
use gitcomet_state::model::{DefaultTagType, GitLogTagFetchMode};
use gitcomet_state::session::ExternalCodeEditorSetting;
use gpui::{
    Stateful, TitlebarOptions, WindowBackgroundAppearance, WindowBounds, WindowDecorations,
    WindowOptions,
};
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex, OnceLock};

const SETTINGS_WINDOW_MIN_WIDTH_PX: f32 = 620.0;
const SETTINGS_WINDOW_MIN_HEIGHT_PX: f32 = 460.0;
const SETTINGS_WINDOW_DEFAULT_WIDTH_PX: f32 = 720.0;
const SETTINGS_WINDOW_DEFAULT_HEIGHT_PX: f32 = 620.0;
const SETTINGS_DROPDOWN_LIST_MAX_HEIGHT_PX: f32 = 224.0;
const SETTINGS_DROPDOWN_COMPACT_ROW_HEIGHT_PX: f32 = 28.0;
const SETTINGS_DROPDOWN_COMPACT_LIST_EXTRA_HEIGHT_PX: f32 = 20.0;
const SETTINGS_DROPDOWN_DETAIL_ROW_HEIGHT_PX: f32 = 42.0;
const SETTINGS_DROPDOWN_DETAIL_LIST_EXTRA_HEIGHT_PX: f32 = 24.0;
const SETTINGS_DROPDOWN_DENSE_DETAIL_ROW_HEIGHT_PX: f32 = 28.0;
const SETTINGS_WINDOW_TITLE: &str = "Settings: GitComet";
const SETTINGS_TRAFFIC_LIGHTS_SAFE_INSET_PX: f32 = 78.0;
const MIN_GIT_MAJOR: u32 = 2;
const MIN_GIT_MINOR: u32 = 50;
const GITHUB_URL: &str = "https://github.com/Auto-Explore/GitComet";
const THEMES_GUIDE_URL: &str = "https://github.com/Auto-Explore/GitComet/blob/main/docs/themes.md";
const LICENSE_URL: &str = "https://github.com/Auto-Explore/GitComet/blob/main/LICENSE-AGPL-3.0";
const LICENSE_NAME: &str = "AGPL-3.0";

#[derive(Clone, Default)]
struct ExternalEditorPreferencePersistQueue {
    latest_sequence: Arc<AtomicU64>,
    write_lock: Arc<Mutex<()>>,
}

impl ExternalEditorPreferencePersistQueue {
    fn next_sequence(&self) -> u64 {
        self.latest_sequence
            .fetch_add(1, Ordering::AcqRel)
            .wrapping_add(1)
    }

    fn persist_if_latest(
        &self,
        sequence: u64,
        setting: Option<ExternalCodeEditorSetting>,
    ) -> std::io::Result<bool> {
        let _guard = self
            .write_lock
            .lock()
            .unwrap_or_else(|err| err.into_inner());
        if self.latest_sequence.load(Ordering::Acquire) != sequence {
            return Ok(false);
        }
        session::persist_ui_settings(external_editor_preference_settings(setting))?;
        Ok(true)
    }

    #[cfg(test)]
    fn persist_to_path_if_latest(
        &self,
        sequence: u64,
        setting: Option<ExternalCodeEditorSetting>,
        path: &std::path::Path,
    ) -> std::io::Result<bool> {
        let _guard = self
            .write_lock
            .lock()
            .unwrap_or_else(|err| err.into_inner());
        if self.latest_sequence.load(Ordering::Acquire) != sequence {
            return Ok(false);
        }
        session::persist_ui_settings_to_path(external_editor_preference_settings(setting), path)?;
        Ok(true)
    }
}

static EXTERNAL_EDITOR_PREFERENCE_PERSIST_QUEUE: OnceLock<ExternalEditorPreferencePersistQueue> =
    OnceLock::new();

fn external_editor_preference_persist_queue() -> &'static ExternalEditorPreferencePersistQueue {
    EXTERNAL_EDITOR_PREFERENCE_PERSIST_QUEUE.get_or_init(Default::default)
}

fn external_editor_preference_settings(
    setting: Option<ExternalCodeEditorSetting>,
) -> session::UiSettings {
    session::UiSettings {
        external_code_editor: Some(setting),
        ..session::UiSettings::default()
    }
}

fn custom_external_editor_path_prompt_options() -> gpui::PathPromptOptions {
    gpui::PathPromptOptions {
        files: true,
        directories: true,
        multiple: false,
        prompt: Some("Select external code editor".into()),
    }
}

const CHANGE_TRACKING_OPTIONS: &[(&str, ChangeTrackingView, &str)] = &[
    (
        "settings_window_change_tracking_combined",
        ChangeTrackingView::Combined,
        "Keep untracked files inside the Unstaged section",
    ),
    (
        "settings_window_change_tracking_split_untracked",
        ChangeTrackingView::SplitUntracked,
        "Show an Untracked block above Unstaged",
    ),
];

const DIFF_SCROLL_SYNC_OPTIONS: &[(&str, DiffScrollSync, &str)] = &[
    (
        "settings_window_diff_scroll_sync_vertical",
        DiffScrollSync::Vertical,
        "Lock vertical scrolling only.",
    ),
    (
        "settings_window_diff_scroll_sync_horizontal",
        DiffScrollSync::Horizontal,
        "Lock horizontal scrolling only.",
    ),
    (
        "settings_window_diff_scroll_sync_none",
        DiffScrollSync::None,
        "Keep split and merge panes independent.",
    ),
    (
        "settings_window_diff_scroll_sync_both",
        DiffScrollSync::Both,
        "Lock both vertical and horizontal scrolling.",
    ),
];

const DIFF_CONTENT_MODE_OPTIONS: &[(&str, DiffContentMode, &str)] = &[
    (
        "settings_window_diff_content_mode_collapsed",
        DiffContentMode::Collapsed,
        "Hide unchanged sections, with hunk controls to reveal more context.",
    ),
    (
        "settings_window_diff_content_mode_full",
        DiffContentMode::Full,
        "Show the full file using the regular file diff view.",
    ),
];

const DIFF_VIEW_MODE_OPTIONS: &[(&str, DiffViewMode, &str)] = &[
    (
        "settings_window_diff_view_mode_inline",
        DiffViewMode::Inline,
        "Show changes inline.",
    ),
    (
        "settings_window_diff_view_mode_split",
        DiffViewMode::Split,
        "Show changes in split view.",
    ),
];

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum SettingsSection {
    Theme,
    UiScale,
    UiFont,
    EditorFont,
    ExternalCodeEditor,
    DateFormat,
    Timezone,
    TerminalExternal,
    TerminalActionBar,
    ChangeTracking,
    DiffContentMode,
    Diff,
    DiffViewMode,
    GitLogDefaultMode,
    GitLogColumns,
    GitLogTagFetch,
}

impl SettingsSection {
    /// The left-nav category that owns this expandable section. Expanding a
    /// section always happens from within its owning category's page, so this
    /// mapping keeps the visible page and the expanded row in sync.
    fn category(self) -> SettingsCategory {
        match self {
            Self::Theme
            | Self::UiScale
            | Self::UiFont
            | Self::EditorFont
            | Self::ExternalCodeEditor
            | Self::DateFormat
            | Self::Timezone => SettingsCategory::General,
            Self::TerminalExternal | Self::TerminalActionBar => SettingsCategory::Terminal,
            Self::ChangeTracking => SettingsCategory::ChangeTracking,
            Self::DiffContentMode | Self::Diff | Self::DiffViewMode => SettingsCategory::Diff,
            Self::GitLogDefaultMode | Self::GitLogColumns | Self::GitLogTagFetch => {
                SettingsCategory::GitLog
            }
        }
    }
}

/// A top-level settings grouping, shown as a row in the left-hand navigation.
/// Each category maps to one of the existing settings cards.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum SettingsCategory {
    General,
    Terminal,
    ChangeTracking,
    Diff,
    FileEditing,
    GitLog,
    Tags,
    GitExecutable,
    Environment,
    Links,
}

impl SettingsCategory {
    const ALL: &'static [SettingsCategory] = &[
        SettingsCategory::General,
        SettingsCategory::Terminal,
        SettingsCategory::ChangeTracking,
        SettingsCategory::Diff,
        SettingsCategory::FileEditing,
        SettingsCategory::GitLog,
        SettingsCategory::Tags,
        SettingsCategory::GitExecutable,
        SettingsCategory::Environment,
        SettingsCategory::Links,
    ];

    fn label(self) -> &'static str {
        match self {
            Self::General => "General",
            Self::Terminal => "Terminal",
            Self::ChangeTracking => "Change tracking",
            Self::Diff => "Diff",
            Self::FileEditing => "File editing",
            Self::GitLog => "Git log",
            Self::Tags => "Tags",
            Self::GitExecutable => "Git executable",
            Self::Environment => "Environment",
            Self::Links => "Links",
        }
    }

    fn icon(self) -> &'static str {
        match self {
            Self::General => "icons/cog.svg",
            Self::Terminal => "icons/terminal.svg",
            Self::ChangeTracking => "icons/file.svg",
            Self::Diff => "icons/swap.svg",
            Self::FileEditing => "icons/pencil.svg",
            Self::GitLog => "icons/history.svg",
            Self::Tags => "icons/tag.svg",
            Self::GitExecutable => "icons/git_branch.svg",
            Self::Environment => "icons/computer.svg",
            Self::Links => "icons/link.svg",
        }
    }

    fn nav_id(self) -> &'static str {
        match self {
            Self::General => "settings_window_nav_general",
            Self::Terminal => "settings_window_nav_terminal",
            Self::ChangeTracking => "settings_window_nav_change_tracking",
            Self::Diff => "settings_window_nav_diff",
            Self::FileEditing => "settings_window_nav_file_editing",
            Self::GitLog => "settings_window_nav_git_log",
            Self::Tags => "settings_window_nav_tags",
            Self::GitExecutable => "settings_window_nav_git_executable",
            Self::Environment => "settings_window_nav_environment",
            Self::Links => "settings_window_nav_links",
        }
    }

    /// Lowercase text (title plus the labels of the settings on the page) used
    /// to decide whether a category matches the nav search query.
    fn search_haystack(self) -> &'static str {
        match self {
            Self::General => {
                "general theme date format ui scale ui font editor font ligatures \
                 external code editor date timezone appearance"
            }
            Self::Terminal => "terminal external terminal action bar terminal button opens",
            Self::ChangeTracking => "change tracking untracked files",
            Self::Diff => {
                "diff mode scroll sync show whitespace changes reveal whitespace characters \
                 word wrap show line numbers unified split"
            }
            Self::FileEditing => {
                "file editing edit file auto save autosave save automatically editor"
            }
            Self::GitLog => {
                "git log default history mode history columns relative dates show tags graph \
                 author sha"
            }
            Self::Tags => "tags automatically fetch tags",
            Self::GitExecutable => "git executable custom path system path version",
            Self::Environment => "environment build operating system app version",
            Self::Links => {
                "links theme guide github license open source licenses professional edition \
                 waitlist"
            }
        }
    }

    fn matches_query(self, query: &str) -> bool {
        let query = query.trim().to_lowercase();
        if query.is_empty() {
            return true;
        }
        self.search_haystack().contains(query.as_str())
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum SettingsView {
    Root,
    OpenSourceLicenses,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum GitExecutableMode {
    SystemPath,
    Custom,
}

impl GitExecutableMode {
    fn from_preference(preference: &GitExecutablePreference) -> Self {
        match preference {
            GitExecutablePreference::SystemPath => Self::SystemPath,
            GitExecutablePreference::Custom(_) => Self::Custom,
        }
    }
}

#[derive(Clone, Debug)]
struct SettingsRuntimeInfo {
    git: GitRuntimeInfo,
    app_version_display: SharedString,
    operating_system: SharedString,
}

#[derive(Clone, Debug)]
struct GitRuntimeInfo {
    runtime: GitRuntimeState,
    version_display: SharedString,
    compatibility: GitCompatibility,
    detail: Option<SharedString>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum GitCompatibility {
    Supported,
    TooOld,
    Unknown,
    Unavailable,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct GitVersion {
    major: u32,
    minor: u32,
}

#[derive(Clone, Debug)]
struct TerminalSettingsStatus {
    is_error: bool,
    text: SharedString,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum TerminalProgramInputTarget {
    ExternalTerminal,
}

pub(crate) struct SettingsWindowView {
    theme_mode: ThemeMode,
    theme: AppTheme,
    ui_scale_percent: u32,
    ui_font_family: String,
    editor_font_family: String,
    use_font_ligatures: bool,
    ui_font_options: Arc<[String]>,
    editor_font_options: Arc<[String]>,
    external_editor_options: Arc<[crate::external_editor::ExternalEditorOption]>,
    settings_window_scroll: ScrollHandle,
    theme_scroll: UniformListScrollHandle,
    ui_font_scroll: UniformListScrollHandle,
    editor_font_scroll: UniformListScrollHandle,
    external_editor_scroll: UniformListScrollHandle,
    date_format_scroll: UniformListScrollHandle,
    timezone_scroll: UniformListScrollHandle,
    change_tracking_scroll: UniformListScrollHandle,
    diff_content_mode_scroll: UniformListScrollHandle,
    diff_scroll_sync_scroll: UniformListScrollHandle,
    diff_view_mode_scroll: UniformListScrollHandle,
    date_time_format: DateTimeFormat,
    timezone: Timezone,
    show_timezone: bool,
    change_tracking_view: ChangeTrackingView,
    terminal_preferences: TerminalPreferences,
    terminal_external_program_input: Entity<components::TextInput>,
    terminal_external_args_input: Entity<components::TextInput>,
    terminal_status: Option<TerminalSettingsStatus>,
    diff_content_mode: DiffContentMode,
    diff_whitespace_mode: DiffWhitespaceMode,
    diff_view_mode: DiffViewMode,
    diff_reveal_whitespace_chars: bool,
    diff_word_wrap: bool,
    diff_show_line_numbers: bool,
    auto_save_file_edits: bool,
    diff_scroll_sync: DiffScrollSync,
    history_show_graph: bool,
    history_show_author: bool,
    history_show_date: bool,
    history_show_sha: bool,
    history_relative_dates: bool,
    history_highlight_commit_chain: bool,
    history_show_tags: bool,
    history_tag_fetch_mode: GitLogTagFetchMode,
    default_history_mode: HistoryMode,
    default_tag_type: DefaultTagType,
    current_view: SettingsView,
    selected_category: SettingsCategory,
    search_query: String,
    search_input: Entity<components::TextInput>,
    nav_scroll: ScrollHandle,
    open_source_licenses_scroll: UniformListScrollHandle,
    runtime_info: SettingsRuntimeInfo,
    git_executable_mode: GitExecutableMode,
    git_custom_path_draft: String,
    git_executable_input: Entity<components::TextInput>,
    external_editor_setting: Option<ExternalCodeEditorSetting>,
    external_editor_custom_path_draft: String,
    external_editor_custom_arguments_draft: String,
    external_editor_custom_path_input: Entity<components::TextInput>,
    external_editor_custom_arguments_input: Entity<components::TextInput>,
    expanded_section: Option<SettingsSection>,
    hover_resize_edge: Option<ResizeEdge>,
    title_drag_state: chrome::TitleBarDragState,
    _git_executable_input_subscription: gpui::Subscription,
    _external_editor_custom_path_input_subscription: gpui::Subscription,
    _external_editor_custom_arguments_input_subscription: gpui::Subscription,
    _appearance_subscription: gpui::Subscription,
    _search_input_subscription: gpui::Subscription,
    #[cfg(test)]
    overflow_probe: bool,
    #[cfg(test)]
    external_editor_browse_notify_count: usize,
}

pub(crate) fn open_settings_window(cx: &mut App) {
    if let Some(window) = cx
        .windows()
        .into_iter()
        .find_map(|window| window.downcast::<SettingsWindowView>())
    {
        let _ = window.update(cx, |_view, window, _cx| {
            window.activate_window();
        });
        cx.activate(true);
        return;
    }

    let ui_session = session::load();
    let ui_scale = ui_scale::current_or_initialize_from_session(&ui_session, cx);
    let bounds = Bounds::centered(
        None,
        settings_window_default_size_for_percent(ui_scale.percent),
        cx,
    );
    let ui_scale_percent = ui_scale.percent;
    cx.open_window(
        settings_window_options_for_scale(bounds, ui_scale_percent),
        move |window, cx| {
            ui_scale::apply_to_window(window, ui_scale_percent);
            window.on_window_should_close(cx, |window, cx| {
                crate::app::mark_clean_shutdown_if_last_window(cx);
                window.remove_window();
                false
            });
            cx.new(|cx| SettingsWindowView::new(window, cx))
        },
    )
    .expect("failed to open settings window");

    cx.activate(true);
}

fn settings_window_min_size_for_percent(percent: u32) -> gpui::Size<Pixels> {
    ui_scale::design_size_from_percent(
        SETTINGS_WINDOW_MIN_WIDTH_PX,
        SETTINGS_WINDOW_MIN_HEIGHT_PX,
        percent,
    )
}

fn settings_window_default_size_for_percent(percent: u32) -> gpui::Size<Pixels> {
    ui_scale::design_size_from_percent(
        SETTINGS_WINDOW_DEFAULT_WIDTH_PX,
        SETTINGS_WINDOW_DEFAULT_HEIGHT_PX,
        percent,
    )
}

fn settings_window_traffic_light_position(_percent: u32) -> Point<Pixels> {
    point(px(9.0), px(9.0))
}

fn settings_window_traffic_lights_safe_inset(_percent: u32) -> Pixels {
    px(SETTINGS_TRAFFIC_LIGHTS_SAFE_INSET_PX)
}

#[cfg(test)]
fn settings_window_options(bounds: Bounds<Pixels>) -> WindowOptions {
    settings_window_options_for_scale(bounds, ui_scale::DEFAULT_UI_SCALE_PERCENT)
}

fn settings_window_options_for_scale(
    bounds: Bounds<Pixels>,
    ui_scale_percent: u32,
) -> WindowOptions {
    WindowOptions {
        window_bounds: Some(WindowBounds::Windowed(bounds)),
        window_min_size: Some(settings_window_min_size_for_percent(ui_scale_percent)),
        titlebar: Some(settings_window_titlebar_options_for_scale(ui_scale_percent)),
        app_id: Some("gitcomet-settings".into()),
        window_decorations: Some(WindowDecorations::Client),
        // Match the main window: the area outside the rounded client frame
        // must be see-through.
        window_background: if cfg!(target_os = "macos") {
            WindowBackgroundAppearance::Opaque
        } else {
            WindowBackgroundAppearance::Transparent
        },
        is_movable: true,
        is_resizable: true,
        ..Default::default()
    }
}

#[cfg(test)]
fn settings_window_titlebar_options() -> TitlebarOptions {
    settings_window_titlebar_options_for_scale(ui_scale::DEFAULT_UI_SCALE_PERCENT)
}

fn settings_window_titlebar_options_for_scale(ui_scale_percent: u32) -> TitlebarOptions {
    TitlebarOptions {
        title: Some(SETTINGS_WINDOW_TITLE.into()),
        // Windows needs a transparent native titlebar to avoid rendering its own
        // caption on top of the custom settings header.
        appears_transparent: cfg!(any(target_os = "macos", target_os = "windows")),
        traffic_light_position: cfg!(target_os = "macos")
            .then_some(settings_window_traffic_light_position(ui_scale_percent)),
    }
}

#[cfg(test)]
fn settings_window_client_inset() -> Pixels {
    settings_window_client_inset_for_scale(ui_scale::DEFAULT_UI_SCALE_PERCENT)
}

fn settings_window_client_inset_for_scale(ui_scale_percent: u32) -> Pixels {
    if cfg!(target_os = "windows") {
        px(0.0)
    } else {
        chrome::client_side_decoration_inset(ui_scale_percent)
    }
}

fn settings_window_frame(
    theme: AppTheme,
    decorations: Decorations,
    content: AnyElement,
    ui_scale_percent: u32,
) -> AnyElement {
    if cfg!(target_os = "windows") {
        content
    } else {
        chrome::window_frame(theme, decorations, content, None, ui_scale_percent)
    }
}

fn uniform_list_vertical_wheel_delta(event: &gpui::ScrollWheelEvent, window: &Window) -> Pixels {
    event.delta.pixel_delta(window.line_height()).y
}

fn normalize_scroll_offset(raw_offset: Pixels, max_offset: Pixels) -> Pixels {
    if max_offset <= px(0.0) {
        return px(0.0);
    }

    if raw_offset < px(0.0) {
        (-raw_offset).max(px(0.0)).min(max_offset)
    } else {
        raw_offset.max(px(0.0)).min(max_offset)
    }
}

fn uniform_list_vertical_scroll_metrics(
    handle: &UniformListScrollHandle,
) -> (Pixels, Pixels, Pixels) {
    let state = handle.0.borrow();
    let max_offset = state
        .last_item_size
        .map(|size| (size.contents.height - size.item.height).max(px(0.0)))
        .unwrap_or_else(|| state.base_handle.max_offset().y.max(px(0.0)));
    let raw_offset = state.base_handle.offset().y;
    let scroll_offset = normalize_scroll_offset(raw_offset, max_offset);
    (raw_offset, scroll_offset, max_offset)
}

fn uniform_list_should_stop_scroll_propagation(
    handle: &UniformListScrollHandle,
    event: &gpui::ScrollWheelEvent,
    window: &Window,
) -> bool {
    let delta_y = uniform_list_vertical_wheel_delta(event, window);
    if delta_y.is_zero() {
        return false;
    }

    let (raw_offset_after, _scroll_offset_after, max_offset) =
        uniform_list_vertical_scroll_metrics(handle);
    if max_offset <= px(0.0) {
        return false;
    }

    // This runs after the list's built-in wheel scroll listener, so reconstruct the pre-scroll
    // position before deciding whether to keep the event inside the dropdown.
    let raw_offset_before = raw_offset_after - delta_y;
    let scroll_offset_before = normalize_scroll_offset(raw_offset_before, max_offset);
    if delta_y < px(0.0) {
        scroll_offset_before < max_offset
    } else {
        scroll_offset_before > px(0.0)
    }
}

fn mix_color(a: gpui::Rgba, b: gpui::Rgba, t: f32) -> gpui::Rgba {
    let t = t.clamp(0.0, 1.0);
    gpui::Rgba::new(
        a.red + (b.red - a.red) * t,
        a.green + (b.green - a.green) * t,
        a.blue + (b.blue - a.blue) * t,
        a.alpha + (b.alpha - a.alpha) * t,
    )
}

fn settings_row_separator_color(theme: AppTheme) -> gpui::Rgba {
    mix_color(
        theme.colors.surface.canvas,
        theme.colors.stroke.subtle,
        if theme.is_dark { 0.14 } else { 0.10 },
    )
}

fn settings_dropdown_background(theme: AppTheme) -> gpui::Rgba {
    if theme.is_dark {
        mix_color(
            theme.colors.surface.raised,
            theme.colors.surface.canvas,
            0.58,
        )
    } else {
        mix_color(
            theme.colors.surface.raised,
            theme.colors.stroke.default,
            0.55,
        )
    }
}

fn settings_dropdown_border_color(theme: AppTheme) -> gpui::Rgba {
    if theme.is_dark {
        with_alpha(theme.colors.stroke.default, 0.98)
    } else {
        theme.colors.stroke.default
    }
}

fn settings_dropdown_height(
    item_count: usize,
    estimated_row_height_px: f32,
    extra_height_px: f32,
    ui_scale_percent: u32,
) -> Pixels {
    ui_scale::design_px_from_percent(
        (((item_count.max(1) as f32) * estimated_row_height_px) + extra_height_px)
            .min(SETTINGS_DROPDOWN_LIST_MAX_HEIGHT_PX),
        ui_scale_percent,
    )
}

/// The theme rows, labels included, from a single pass over the theme list.
///
/// `ThemeMode::label` resolves a key by re-reading the user theme directory --
/// a `create_dir_all`, a `read_dir`, and a `metadata` per file, all of it ahead
/// of the memo that is supposed to make it cheap -- and the row processor below
/// runs on every layout pass while the dropdown is open. Taking the label off
/// the same `ThemeOption` the mode is built from spends that once per render
/// instead of once per visible row per frame.
fn settings_theme_mode_options() -> Vec<(ThemeMode, SharedString)> {
    let themes = crate::theme::available_themes();
    let mut options = Vec::with_capacity(themes.len() + 1);
    options.push((
        ThemeMode::Automatic,
        SharedString::from(ThemeMode::Automatic.label()),
    ));
    options.extend(
        themes
            .into_iter()
            .map(|theme| (ThemeMode::Named(theme.key), SharedString::from(theme.label))),
    );
    options
}

fn settings_theme_modes() -> Vec<ThemeMode> {
    settings_theme_mode_options()
        .into_iter()
        .map(|(mode, _)| mode)
        .collect()
}

fn history_columns_settings_label(
    show_graph: bool,
    show_author: bool,
    show_date: bool,
    show_sha: bool,
) -> SharedString {
    let mut columns = Vec::new();
    if show_graph {
        columns.push("Graph");
    }
    if show_author {
        columns.push("Author");
    }
    if show_date {
        columns.push("Commit date");
    }
    if show_sha {
        columns.push("SHA");
    }

    if columns.is_empty() {
        "None".into()
    } else {
        columns.join(", ").into()
    }
}

fn git_log_tag_fetch_mode_label(mode: GitLogTagFetchMode) -> &'static str {
    match mode {
        GitLogTagFetchMode::OnRepositoryActivation => "On repository activation",
        GitLogTagFetchMode::Disabled => "Disabled",
    }
}

fn applied_git_executable_path(runtime: &GitRuntimeState) -> Option<PathBuf> {
    match &runtime.preference {
        GitExecutablePreference::SystemPath => None,
        GitExecutablePreference::Custom(path) => Some(path.clone()),
    }
}

fn git_executable_scope_note() -> &'static str {
    "Applies to the main GitComet browser window. Git-invoked command modes keep using git from System PATH. Helper tools such as gpg are resolved by Git from the app environment unless configured in Git."
}

fn initial_external_editor_setting(
    ui_session: &session::UiSession,
) -> Option<ExternalCodeEditorSetting> {
    crate::external_editor::configured_setting_preference_override()
        .unwrap_or_else(|| ui_session.external_code_editor.clone())
}

impl SettingsWindowView {
    fn new(window: &mut Window, cx: &mut gpui::Context<Self>) -> Self {
        window.set_window_title(SETTINGS_WINDOW_TITLE);

        let ui_session = session::load();
        let ui_scale = ui_scale::current_or_initialize_from_session(&ui_session, cx);
        let font_preferences =
            crate::font_preferences::current_or_initialize_from_session(window, &ui_session, cx);
        let theme_mode = ui_session
            .theme_mode
            .as_deref()
            .and_then(ThemeMode::from_key)
            .unwrap_or_default();
        let date_time_format = ui_session
            .date_time_format
            .as_deref()
            .and_then(DateTimeFormat::from_key)
            .unwrap_or(DateTimeFormat::YmdHm);
        let timezone = ui_session
            .timezone
            .as_deref()
            .and_then(Timezone::from_key)
            .unwrap_or_default();
        let show_timezone = ui_session.show_timezone.unwrap_or(true);
        let change_tracking_view = ui_session
            .change_tracking_view
            .as_deref()
            .and_then(ChangeTrackingView::from_key)
            .unwrap_or_default();
        let terminal_preferences = TerminalPreferences::from_ui_session(&ui_session);
        let diff_scroll_sync = ui_session
            .diff_scroll_sync
            .as_deref()
            .and_then(DiffScrollSync::from_key)
            .unwrap_or_default();
        let diff_content_mode = ui_session
            .diff_content_mode
            .as_deref()
            .and_then(DiffContentMode::from_key)
            .unwrap_or_default();
        let diff_whitespace_mode = ui_session
            .diff_whitespace_mode
            .as_deref()
            .and_then(DiffWhitespaceMode::from_key)
            .unwrap_or_default();
        let diff_view_mode = ui_session
            .diff_view_mode
            .as_deref()
            .and_then(DiffViewMode::from_key)
            .unwrap_or(DiffViewMode::Split);
        let diff_reveal_whitespace_chars = ui_session.diff_reveal_whitespace_chars.unwrap_or(false);
        let diff_word_wrap = ui_session.diff_word_wrap.unwrap_or(false);
        let diff_show_line_numbers = ui_session.diff_show_line_numbers.unwrap_or(true);
        let auto_save_file_edits = ui_session.auto_save_file_edits.unwrap_or(false);
        let history_show_graph = ui_session.history_show_graph.unwrap_or(true);
        let history_show_author = ui_session.history_show_author.unwrap_or(true);
        let history_show_date = ui_session.history_show_date.unwrap_or(true);
        let history_show_sha = ui_session.history_show_sha.unwrap_or(false);
        let history_relative_dates = ui_session.history_relative_dates.unwrap_or(true);
        let history_highlight_commit_chain =
            ui_session.history_highlight_commit_chain.unwrap_or(true);
        let history_show_tags = ui_session.history_show_tags.unwrap_or(true);
        let history_tag_fetch_mode = ui_session.history_tag_fetch_mode.unwrap_or_default();
        let default_history_mode = ui_session.default_history_mode.unwrap_or_default();
        let default_tag_type = ui_session.default_tag_type.unwrap_or_default();
        let external_editor_setting = initial_external_editor_setting(&ui_session);
        let external_editor_options: Arc<[crate::external_editor::ExternalEditorOption]> =
            crate::external_editor::external_editor_options(external_editor_setting.as_ref())
                .into();
        let (external_editor_custom_path_draft, external_editor_custom_arguments_draft) =
            match &external_editor_setting {
                Some(ExternalCodeEditorSetting::Custom {
                    executable,
                    arguments,
                }) => (
                    executable.display().to_string(),
                    arguments.clone().unwrap_or_default(),
                ),
                _ => (String::new(), String::new()),
            };
        let theme = theme_mode.resolve_theme(window.appearance());
        let runtime_info = SettingsRuntimeInfo::detect();
        let git_executable_mode =
            GitExecutableMode::from_preference(&runtime_info.git.runtime.preference);
        let git_custom_path_draft = match &runtime_info.git.runtime.preference {
            GitExecutablePreference::Custom(path) if !path.as_os_str().is_empty() => {
                path.display().to_string()
            }
            _ => String::new(),
        };

        let appearance_subscription = {
            let view = cx.weak_entity();
            let mut first = true;
            window.observe_window_appearance(move |window, app| {
                if first {
                    first = false;
                    return;
                }

                let _ = view.update(app, |this, cx| {
                    if !this.theme_mode.is_automatic() {
                        return;
                    }
                    this.theme = this.theme_mode.resolve_theme(window.appearance());
                    cx.notify();
                });
            })
        };

        let terminal_external_program_input = cx.new(|cx| {
            let mut input = components::TextInput::new(
                components::TextInputOptions {
                    placeholder: "wezterm".into(),
                    ..Default::default()
                },
                window,
                cx,
            );
            input.set_theme(theme, cx);
            input.set_text(terminal_preferences.external_terminal_program.clone(), cx);
            input
        });

        let terminal_external_args_input = cx.new(|cx| {
            let mut input = components::TextInput::new(
                components::TextInputOptions {
                    placeholder: "One argument per line".into(),
                    multiline: true,
                    ..Default::default()
                },
                window,
                cx,
            );
            input.set_theme(theme, cx);
            input.set_line_height(Some(px(20.0)), cx);
            input.set_text(terminal_preferences.external_args_multiline(), cx);
            input
        });

        let git_executable_input = cx.new(|cx| {
            components::TextInput::new(
                components::TextInputOptions {
                    placeholder: "/path/to/git".into(),
                    ..Default::default()
                },
                window,
                cx,
            )
        });
        git_executable_input.update(cx, |input, cx| {
            input.set_text(git_custom_path_draft.clone(), cx);
        });
        let git_executable_input_subscription =
            cx.observe(&git_executable_input, |this, input, cx| {
                let enter_pressed = input.update(cx, |input, _| input.take_enter_pressed());
                let next = input.read(cx).text().to_string();
                if this.git_custom_path_draft != next {
                    this.git_custom_path_draft = next;
                    cx.notify();
                }
                if enter_pressed && this.git_executable_mode == GitExecutableMode::Custom {
                    this.apply_git_executable_settings(cx);
                }
            });

        let external_editor_custom_path_input = cx.new(|cx| {
            components::TextInput::new(
                components::TextInputOptions {
                    placeholder: "/path/to/editor".into(),
                    ..Default::default()
                },
                window,
                cx,
            )
        });
        external_editor_custom_path_input.update(cx, |input, cx| {
            input.set_text(external_editor_custom_path_draft.clone(), cx);
        });
        let external_editor_custom_arguments_input = cx.new(|cx| {
            components::TextInput::new(
                components::TextInputOptions {
                    placeholder: "--reuse-window {path}".into(),
                    ..Default::default()
                },
                window,
                cx,
            )
        });
        external_editor_custom_arguments_input.update(cx, |input, cx| {
            input.set_text(external_editor_custom_arguments_draft.clone(), cx);
        });
        let external_editor_custom_path_input_subscription =
            cx.observe(&external_editor_custom_path_input, |this, input, cx| {
                let next = input.read(cx).text().to_string();
                if this.external_editor_custom_path_draft == next {
                    return;
                }
                this.external_editor_custom_path_draft = next;
                if this.external_editor_is_custom() {
                    this.persist_external_editor_from_custom_drafts(cx);
                }
                cx.notify();
            });
        let search_input = cx.new(|cx| {
            let mut input = components::TextInput::new(
                components::TextInputOptions {
                    placeholder: "Search".into(),
                    leading_icon: Some("icons/zoom.svg"),
                    ..Default::default()
                },
                window,
                cx,
            );
            input.set_theme(theme, cx);
            input
        });
        let search_input_subscription = cx.observe(&search_input, |this, input, cx| {
            let next = input.read(cx).text().to_string();
            if this.search_query == next {
                return;
            }
            this.search_query = next;
            // Keep the visible page in the filtered set: if the current
            // category no longer matches, jump to the first one that does.
            if !this.selected_category.matches_query(&this.search_query)
                && let Some(first) = SettingsCategory::ALL
                    .iter()
                    .copied()
                    .find(|category| category.matches_query(&this.search_query))
            {
                this.selected_category = first;
                this.expanded_section = None;
            }
            cx.notify();
        });

        let external_editor_custom_arguments_input_subscription = cx.observe(
            &external_editor_custom_arguments_input,
            |this, input, cx| {
                let next = input.read(cx).text().to_string();
                if this.external_editor_custom_arguments_draft == next {
                    return;
                }
                this.external_editor_custom_arguments_draft = next;
                if this.external_editor_is_custom() {
                    this.persist_external_editor_from_custom_drafts(cx);
                }
                cx.notify();
            },
        );

        Self {
            theme_mode,
            theme,
            ui_scale_percent: ui_scale.percent,
            ui_font_family: font_preferences.ui_font_family,
            editor_font_family: font_preferences.editor_font_family,
            use_font_ligatures: font_preferences.use_font_ligatures,
            ui_font_options: crate::font_preferences::ui_font_options(window),
            editor_font_options: crate::font_preferences::editor_font_options(window),
            external_editor_options,
            settings_window_scroll: ScrollHandle::default(),
            theme_scroll: UniformListScrollHandle::default(),
            ui_font_scroll: UniformListScrollHandle::default(),
            editor_font_scroll: UniformListScrollHandle::default(),
            external_editor_scroll: UniformListScrollHandle::default(),
            date_format_scroll: UniformListScrollHandle::default(),
            timezone_scroll: UniformListScrollHandle::default(),
            change_tracking_scroll: UniformListScrollHandle::default(),
            diff_content_mode_scroll: UniformListScrollHandle::default(),
            diff_scroll_sync_scroll: UniformListScrollHandle::default(),
            diff_view_mode_scroll: UniformListScrollHandle::default(),
            date_time_format,
            timezone,
            show_timezone,
            change_tracking_view,
            terminal_preferences,
            terminal_external_program_input,
            terminal_external_args_input,
            terminal_status: None,
            diff_content_mode,
            diff_whitespace_mode,
            diff_view_mode,
            diff_reveal_whitespace_chars,
            diff_word_wrap,
            diff_show_line_numbers,
            auto_save_file_edits,
            diff_scroll_sync,
            history_show_graph,
            history_show_author,
            history_show_date,
            history_show_sha,
            history_relative_dates,
            history_highlight_commit_chain,
            history_show_tags,
            history_tag_fetch_mode,
            default_history_mode,
            default_tag_type,
            current_view: SettingsView::Root,
            selected_category: SettingsCategory::General,
            search_query: String::new(),
            search_input,
            nav_scroll: ScrollHandle::default(),
            open_source_licenses_scroll: UniformListScrollHandle::default(),
            runtime_info,
            git_executable_mode,
            git_custom_path_draft,
            git_executable_input,
            external_editor_setting,
            external_editor_custom_path_draft,
            external_editor_custom_arguments_draft,
            external_editor_custom_path_input,
            external_editor_custom_arguments_input,
            expanded_section: None,
            hover_resize_edge: None,
            title_drag_state: chrome::TitleBarDragState::default(),
            _git_executable_input_subscription: git_executable_input_subscription,
            _external_editor_custom_path_input_subscription:
                external_editor_custom_path_input_subscription,
            _external_editor_custom_arguments_input_subscription:
                external_editor_custom_arguments_input_subscription,
            _appearance_subscription: appearance_subscription,
            _search_input_subscription: search_input_subscription,
            #[cfg(test)]
            overflow_probe: false,
            #[cfg(test)]
            external_editor_browse_notify_count: 0,
        }
    }

    fn select_category(&mut self, category: SettingsCategory, cx: &mut gpui::Context<Self>) {
        if self.selected_category == category {
            return;
        }
        self.selected_category = category;
        // Collapse any expanded row so the new page starts clean, and scroll
        // the content pane back to the top.
        self.expanded_section = None;
        self.settings_window_scroll
            .set_offset(gpui::point(px(0.0), px(0.0)));
        cx.notify();
    }

    fn toggle_section(&mut self, section: SettingsSection, cx: &mut gpui::Context<Self>) {
        self.expanded_section = if self.expanded_section == Some(section) {
            None
        } else {
            Some(section)
        };
        cx.notify();
    }

    fn persist_preferences(&self, cx: &mut gpui::Context<Self>) {
        let settings = self.preference_settings();

        cx.background_spawn(async move {
            let _ = session::persist_ui_settings(settings);
        })
        .detach();
    }

    fn preference_settings(&self) -> session::UiSettings {
        let mut settings = session::UiSettings {
            repo_picker_sort: None,
            repo_picker_collapsed_sections: None,
            window_width: None,
            window_height: None,
            sidebar_width: None,
            details_width: None,
            sidebar_collapsed: None,
            repo_sidebar_collapsed_items: None,
            repo_sidebar_pinned_branches: None,
            theme_mode: Some(self.theme_mode.key().to_string()),
            ui_scale_percent: Some(self.ui_scale_percent),
            ui_font_family: Some(self.ui_font_family.clone()),
            editor_font_family: Some(self.editor_font_family.clone()),
            use_font_ligatures: Some(self.use_font_ligatures),
            date_time_format: Some(self.date_time_format.key().to_string()),
            timezone: Some(self.timezone.key()),
            show_timezone: Some(self.show_timezone),
            change_tracking_view: Some(self.change_tracking_view.key().to_string()),
            diff_scroll_sync: Some(self.diff_scroll_sync.key().to_string()),
            diff_content_mode: Some(self.diff_content_mode.key().to_string()),
            diff_whitespace_mode: Some(self.diff_whitespace_mode.key().to_string()),
            diff_view_mode: Some(self.diff_view_mode.key().to_string()),
            // Annotate is toggled from the diff toolbar, not the settings window,
            // so leave it untouched here (None never overwrites the stored value).
            annotate_enabled: None,
            diff_reveal_whitespace_chars: Some(self.diff_reveal_whitespace_chars),
            diff_word_wrap: Some(self.diff_word_wrap),
            diff_show_line_numbers: Some(self.diff_show_line_numbers),
            auto_save_file_edits: Some(self.auto_save_file_edits),
            // Merge tool settings are managed from the resolver's cog menu;
            // None never overwrites the stored values.
            mergetool_auto_advance: None,
            mergetool_collapse_unchanged: None,
            mergetool_output_scroll_sync: None,
            mergetool_show_line_numbers: None,
            mergetool_view_three_way: None,
            change_tracking_height: None,
            untracked_height: None,
            history_show_graph: Some(self.history_show_graph),
            history_show_author: Some(self.history_show_author),
            history_show_date: Some(self.history_show_date),
            history_show_sha: Some(self.history_show_sha),
            history_relative_dates: Some(self.history_relative_dates),
            history_highlight_commit_chain: Some(self.history_highlight_commit_chain),
            history_show_tags: Some(self.history_show_tags),
            history_tag_fetch_mode: Some(self.history_tag_fetch_mode),
            default_history_mode: Some(self.default_history_mode),
            default_tag_type: Some(self.default_tag_type),
            commit_push_after_enabled: None,
            git_executable_path: Some(applied_git_executable_path(&self.runtime_info.git.runtime)),
            terminal_external_mode: None,
            terminal_external_program: None,
            terminal_external_args: None,
            terminal_action_bar_target: None,
            external_code_editor: None,
        };
        self.terminal_preferences
            .apply_to_ui_settings(&mut settings);
        settings
    }

    fn apply_terminal_preferences_change(
        &mut self,
        next: TerminalPreferences,
        cx: &mut gpui::Context<Self>,
    ) {
        if self.terminal_preferences == next {
            return;
        }

        self.terminal_preferences = next.clone();
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.apply_terminal_preferences(next.clone(), cx);
        });
        cx.notify();
    }

    fn set_terminal_status(
        &mut self,
        is_error: bool,
        text: impl Into<SharedString>,
        cx: &mut gpui::Context<Self>,
    ) {
        self.terminal_status = Some(TerminalSettingsStatus {
            is_error,
            text: text.into(),
        });
        cx.notify();
    }

    fn external_terminal_preferences_with_drafts(
        &self,
        cx: &gpui::Context<Self>,
    ) -> TerminalPreferences {
        let mut preferences = self.terminal_preferences.clone();
        preferences.external_terminal_program = self
            .terminal_external_program_input
            .read_with(cx, |input, _| input.text().trim().to_string());
        let args_raw = self
            .terminal_external_args_input
            .read_with(cx, |input, _| input.text().to_string());
        preferences.external_terminal_args = parse_terminal_args_multiline(&args_raw);
        preferences
    }

    fn set_external_terminal_mode(
        &mut self,
        mode: ExternalTerminalMode,
        cx: &mut gpui::Context<Self>,
    ) {
        if self.terminal_preferences.external_terminal_mode == mode {
            return;
        }

        let mut next = self.terminal_preferences.clone();
        next.external_terminal_mode = mode;
        self.terminal_status = None;
        self.apply_terminal_preferences_change(next, cx);
    }

    fn set_action_bar_terminal_target(
        &mut self,
        target: ActionBarTerminalTarget,
        cx: &mut gpui::Context<Self>,
    ) {
        if self.terminal_preferences.action_bar_terminal_target == target {
            return;
        }

        let mut next = self.terminal_preferences.clone();
        next.action_bar_terminal_target = target;
        self.terminal_status = None;
        self.apply_terminal_preferences_change(next, cx);
    }

    fn save_terminal_external_draft(&mut self, cx: &mut gpui::Context<Self>) {
        let next = self.external_terminal_preferences_with_drafts(cx);
        self.apply_terminal_preferences_change(next, cx);
        self.set_terminal_status(false, "External terminal settings saved.", cx);
    }

    fn reset_terminal_external_draft(&mut self, cx: &mut gpui::Context<Self>) {
        let program = self.terminal_preferences.external_terminal_program.clone();
        self.terminal_external_program_input
            .update(cx, |input, cx| input.set_text(program, cx));
        let args = self.terminal_preferences.external_args_multiline();
        self.terminal_external_args_input
            .update(cx, |input, cx| input.set_text(args, cx));
        self.set_terminal_status(false, "External terminal draft reset.", cx);
    }

    fn browse_terminal_program_input(
        &mut self,
        target: TerminalProgramInputTarget,
        window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) {
        let prompt = match target {
            TerminalProgramInputTarget::ExternalTerminal => "Select terminal launcher",
        };
        let allow_directories = cfg!(target_os = "macos");
        let rx = cx.prompt_for_paths(gpui::PathPromptOptions {
            files: true,
            directories: allow_directories,
            multiple: false,
            prompt: Some(prompt.into()),
        });
        let view = cx.weak_entity();

        window
            .spawn(cx, async move |cx| {
                let result = rx.await;
                let paths = match result {
                    Ok(Ok(Some(paths))) => paths,
                    Ok(Ok(None)) => return,
                    Ok(Err(_)) | Err(_) => return,
                };
                let Some(path) = paths.into_iter().next() else {
                    return;
                };
                let rendered = path.display().to_string();
                let _ = view.update(cx, |this, cx| {
                    match target {
                        TerminalProgramInputTarget::ExternalTerminal => {
                            this.terminal_external_program_input
                                .update(cx, |input, cx| input.set_text(rendered.clone(), cx));
                        }
                    }
                    this.terminal_status = None;
                    cx.notify();
                });
            })
            .detach();
    }

    fn preferred_terminal_launch_context(
        &self,
        cx: &gpui::Context<Self>,
    ) -> ExternalTerminalLaunchContext {
        for handle in cx
            .windows()
            .into_iter()
            .filter_map(|window| window.downcast::<GitCometView>())
        {
            if let Ok(Some(context)) = handle.read_with(cx, |view, _cx| {
                view.terminal_launch_context_for_active_repo()
            }) {
                return context;
            }
        }

        ExternalTerminalLaunchContext {
            cwd: std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
            repo_name: None,
        }
    }

    fn test_terminal_launch_from_draft(&mut self, cx: &mut gpui::Context<Self>) {
        let preferences = self.external_terminal_preferences_with_drafts(cx);
        let context = self.preferred_terminal_launch_context(cx);
        match launch_external_terminal_from_preferences(&preferences, &context) {
            Ok(()) => self.set_terminal_status(false, "Launch request sent.", cx),
            Err(err) => self.set_terminal_status(true, format!("Test launch failed: {err}"), cx),
        }
    }

    fn show_root(&mut self, cx: &mut gpui::Context<Self>) {
        if self.current_view == SettingsView::Root {
            return;
        }

        self.current_view = SettingsView::Root;
        cx.notify();
    }

    fn show_open_source_licenses(&mut self, cx: &mut gpui::Context<Self>) {
        if self.current_view == SettingsView::OpenSourceLicenses {
            return;
        }

        self.current_view = SettingsView::OpenSourceLicenses;
        self.expanded_section = None;
        cx.notify();
    }

    fn custom_theme_folder_detail(&self) -> SharedString {
        session::user_themes_dir()
            .map(|path| path.display().to_string().into())
            .unwrap_or_else(|| "Unavailable".into())
    }

    fn push_main_window_toast(
        &self,
        kind: components::ToastKind,
        message: String,
        cx: &mut gpui::Context<Self>,
    ) {
        self.update_main_windows(cx, move |view, _window, cx| {
            view.push_toast(kind, message.clone(), cx);
        });
    }

    fn open_custom_theme_folder(&mut self, cx: &mut gpui::Context<Self>) {
        let Some(path) = crate::theme::ensure_user_themes_dir_exists() else {
            self.push_main_window_toast(
                components::ToastKind::Error,
                "Custom theme folder is unavailable.".to_string(),
                cx,
            );
            return;
        };

        if let Err(err) = super::platform_open::open_path(&path) {
            self.push_main_window_toast(
                components::ToastKind::Error,
                format!("Failed to open custom theme folder: {err}"),
                cx,
            );
        }
    }

    pub(crate) fn apply_ui_scale_percent(
        &mut self,
        percent: u32,
        window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) {
        let percent = ui_scale::sanitize_percent(Some(percent));
        if self.ui_scale_percent == percent {
            return;
        }

        self.ui_scale_percent = percent;
        ui_scale::apply_to_window(window, percent);
        crate::app::ensure_window_respects_min_size(
            window,
            settings_window_min_size_for_percent(percent),
        );
        cx.notify();
    }

    fn update_main_windows(
        &self,
        cx: &mut gpui::Context<Self>,
        f: impl FnMut(&mut GitCometView, &mut Window, &mut gpui::Context<GitCometView>) + 'static,
    ) {
        let handles: Vec<_> = cx
            .windows()
            .into_iter()
            .filter_map(|window| window.downcast::<GitCometView>())
            .collect();
        cx.spawn(
            async move |_view: WeakEntity<Self>, cx: &mut gpui::AsyncApp| {
                cx.update(move |cx| {
                    let mut f = f;
                    for handle in handles {
                        let _ = handle.update(cx, |view, window, cx| f(view, window, cx));
                    }
                });
            },
        )
        .detach();
    }

    fn selected_git_executable_path(&self) -> Option<std::path::PathBuf> {
        match self.git_executable_mode {
            GitExecutableMode::SystemPath => None,
            GitExecutableMode::Custom => {
                let trimmed = self.git_custom_path_draft.trim();
                Some(if trimmed.is_empty() {
                    std::path::PathBuf::new()
                } else {
                    std::path::PathBuf::from(trimmed)
                })
            }
        }
    }

    fn sync_git_runtime_state(&mut self, runtime: GitRuntimeState, cx: &mut gpui::Context<Self>) {
        self.git_executable_mode = GitExecutableMode::from_preference(&runtime.preference);
        if let GitExecutablePreference::Custom(path) = &runtime.preference {
            let next_draft = if path.as_os_str().is_empty() {
                String::new()
            } else {
                path.display().to_string()
            };
            if self.git_custom_path_draft != next_draft {
                self.git_custom_path_draft = next_draft.clone();
                self.git_executable_input
                    .update(cx, |input, cx| input.set_text(next_draft, cx));
            }
        }

        self.runtime_info = SettingsRuntimeInfo::from_runtime(runtime.clone());
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, _cx| {
            view.store
                .dispatch(Msg::SetGitRuntimeState(runtime.clone()));
        });
        cx.notify();
    }

    fn apply_git_executable_settings(&mut self, cx: &mut gpui::Context<Self>) {
        let runtime = install_git_executable_path(self.selected_git_executable_path());
        self.sync_git_runtime_state(runtime, cx);
    }

    fn set_git_executable_mode(&mut self, mode: GitExecutableMode, cx: &mut gpui::Context<Self>) {
        if self.git_executable_mode == mode {
            return;
        }

        self.git_executable_mode = mode;
        self.apply_git_executable_settings(cx);
    }

    fn external_editor_is_custom(&self) -> bool {
        matches!(
            self.external_editor_setting,
            Some(ExternalCodeEditorSetting::Custom { .. })
        )
    }

    fn custom_external_editor_setting_from_drafts(&self) -> ExternalCodeEditorSetting {
        let executable = self.external_editor_custom_path_draft.trim();
        let arguments = self.external_editor_custom_arguments_draft.trim();
        ExternalCodeEditorSetting::Custom {
            executable: if executable.is_empty() {
                PathBuf::new()
            } else {
                PathBuf::from(executable)
            },
            arguments: (!arguments.is_empty()).then(|| arguments.to_string()),
        }
    }

    fn persist_external_editor_preference(&self, cx: &mut gpui::Context<Self>) {
        let setting = self.external_editor_setting.clone();
        crate::external_editor::set_configured_setting_override(setting.clone());
        let persist_queue = external_editor_preference_persist_queue().clone();
        let sequence = persist_queue.next_sequence();
        let setting_for_persist = setting.clone();
        cx.background_spawn(async move {
            let _ = persist_queue.persist_if_latest(sequence, setting_for_persist);
        })
        .detach();
        cx.defer(move |cx| {
            crate::app::refresh_external_editor_app_surfaces_for_setting(setting.as_ref(), cx);
        });
    }

    fn apply_browsed_external_editor_path(&mut self, path: PathBuf, cx: &mut gpui::Context<Self>) {
        let next = path.display().to_string();
        self.external_editor_custom_path_draft = next.clone();
        self.external_editor_custom_path_input
            .update(cx, |input, cx| input.set_text(next, cx));
        self.persist_external_editor_from_custom_drafts(cx);
        self.notify_after_external_editor_browse(cx);
    }

    fn notify_after_external_editor_browse(&mut self, cx: &mut gpui::Context<Self>) {
        #[cfg(test)]
        {
            self.external_editor_browse_notify_count += 1;
        }
        cx.notify();
    }

    fn persist_external_editor_from_custom_drafts(&mut self, cx: &mut gpui::Context<Self>) {
        let next = self.custom_external_editor_setting_from_drafts();
        if self.external_editor_setting.as_ref() == Some(&next) {
            return;
        }
        self.external_editor_setting = Some(next);
        self.persist_external_editor_preference(cx);
    }

    fn set_external_editor_setting(
        &mut self,
        next: Option<ExternalCodeEditorSetting>,
        cx: &mut gpui::Context<Self>,
    ) {
        if self.external_editor_setting == next {
            self.expanded_section = None;
            cx.notify();
            return;
        }

        self.external_editor_setting = next;
        self.expanded_section = None;
        self.persist_external_editor_preference(cx);
        cx.notify();
    }

    fn select_custom_external_editor(&mut self, cx: &mut gpui::Context<Self>) {
        self.set_external_editor_setting(
            Some(self.custom_external_editor_setting_from_drafts()),
            cx,
        );
    }

    fn font_option_detail(&self, family: &str) -> Option<SharedString> {
        match family {
            crate::font_preferences::UI_SYSTEM_FONT_FAMILY => {
                Some("Use GitComet's best match for the operating system UI font stack".into())
            }
            _ => None,
        }
    }

    fn font_options_hint(&self, family: &str) -> SharedString {
        self.font_option_detail(family)
            .unwrap_or_else(|| "Choose from installed system fonts".into())
    }

    fn font_option_row_for_family(
        &self,
        id_prefix: &'static str,
        ix: usize,
        family: &str,
        selected: bool,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        self.option_row(
            format!("{id_prefix}_{ix}"),
            crate::font_preferences::display_label(family),
            None,
            selected,
            theme,
        )
    }

    fn set_ui_scale_percent(
        &mut self,
        percent: u32,
        window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) {
        let percent = ui_scale::set_current(cx, percent).percent;
        if self.ui_scale_percent == percent {
            return;
        }

        self.expanded_section = None;
        self.apply_ui_scale_percent(percent, window, cx);
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, root_window, cx| {
            view.apply_ui_scale_percent(percent, root_window, cx);
        });
        cx.notify();
    }

    fn set_theme_mode(
        &mut self,
        mode: ThemeMode,
        window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) {
        if self.theme_mode == mode {
            return;
        }

        self.theme_mode = mode.clone();
        self.theme = mode.resolve_theme(window.appearance());
        self.expanded_section = None;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, root_window, cx| {
            view.popover_host.update(cx, |host, cx| {
                host.set_theme_mode(mode.clone(), root_window.appearance(), cx);
            });
        });
        cx.notify();
    }

    fn set_ui_font_family(&mut self, family: String, cx: &mut gpui::Context<Self>) {
        if self.ui_font_family == family {
            return;
        }

        self.ui_font_family = family;
        self.expanded_section = None;
        crate::font_preferences::set_current(
            cx,
            self.ui_font_family.clone(),
            self.editor_font_family.clone(),
            self.use_font_ligatures,
        );
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.notify_font_preferences_changed(cx);
        });
        cx.notify();
    }

    fn set_editor_font_family(&mut self, family: String, cx: &mut gpui::Context<Self>) {
        if self.editor_font_family == family {
            return;
        }

        self.editor_font_family = family;
        self.expanded_section = None;
        crate::font_preferences::set_current(
            cx,
            self.ui_font_family.clone(),
            self.editor_font_family.clone(),
            self.use_font_ligatures,
        );
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.notify_font_preferences_changed(cx);
        });
        cx.notify();
    }

    fn set_use_font_ligatures(&mut self, enabled: bool, cx: &mut gpui::Context<Self>) {
        if self.use_font_ligatures == enabled {
            return;
        }

        self.use_font_ligatures = enabled;
        crate::font_preferences::set_current(
            cx,
            self.ui_font_family.clone(),
            self.editor_font_family.clone(),
            self.use_font_ligatures,
        );
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.notify_font_preferences_changed(cx);
        });
        cx.notify();
    }

    fn set_date_time_format(&mut self, format: DateTimeFormat, cx: &mut gpui::Context<Self>) {
        if self.date_time_format == format {
            return;
        }

        self.date_time_format = format;
        self.expanded_section = None;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.popover_host.update(cx, |host, cx| {
                host.set_date_time_format(format, cx);
            });
        });
        cx.notify();
    }

    fn set_timezone(&mut self, timezone: Timezone, cx: &mut gpui::Context<Self>) {
        if self.timezone == timezone {
            return;
        }

        self.timezone = timezone;
        self.expanded_section = None;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.popover_host.update(cx, |host, cx| {
                host.set_timezone(timezone, cx);
            });
        });
        cx.notify();
    }

    fn set_show_timezone(&mut self, enabled: bool, cx: &mut gpui::Context<Self>) {
        if self.show_timezone == enabled {
            return;
        }

        self.show_timezone = enabled;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.popover_host.update(cx, |host, cx| {
                host.set_show_timezone(enabled, cx);
            });
        });
        cx.notify();
    }

    fn set_change_tracking_view(&mut self, next: ChangeTrackingView, cx: &mut gpui::Context<Self>) {
        if self.change_tracking_view == next {
            return;
        }

        self.change_tracking_view = next;
        self.expanded_section = None;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_change_tracking_view(next, cx);
        });
        cx.notify();
    }

    fn set_diff_scroll_sync(&mut self, next: DiffScrollSync, cx: &mut gpui::Context<Self>) {
        if self.diff_scroll_sync == next {
            return;
        }

        self.diff_scroll_sync = next;
        self.expanded_section = None;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_diff_scroll_sync(next, cx);
        });
        cx.notify();
    }

    fn set_diff_content_mode(&mut self, next: DiffContentMode, cx: &mut gpui::Context<Self>) {
        if self.diff_content_mode == next {
            return;
        }

        self.diff_content_mode = next;
        self.expanded_section = None;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_diff_content_mode(next, cx);
        });
        cx.notify();
    }

    fn set_diff_whitespace_mode(&mut self, next: DiffWhitespaceMode, cx: &mut gpui::Context<Self>) {
        if self.diff_whitespace_mode == next {
            return;
        }

        self.diff_whitespace_mode = next;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_diff_whitespace_mode(next, cx);
        });
        cx.notify();
    }

    fn set_diff_view_mode(&mut self, next: DiffViewMode, cx: &mut gpui::Context<Self>) {
        if self.diff_view_mode == next {
            return;
        }

        self.diff_view_mode = next;
        self.expanded_section = None;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_diff_view_mode(next, cx);
        });
        cx.notify();
    }

    fn set_diff_reveal_whitespace_chars(&mut self, next: bool, cx: &mut gpui::Context<Self>) {
        if self.diff_reveal_whitespace_chars == next {
            return;
        }

        self.diff_reveal_whitespace_chars = next;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_diff_reveal_whitespace_chars(next, cx);
        });
        cx.notify();
    }

    fn set_diff_word_wrap(&mut self, next: bool, cx: &mut gpui::Context<Self>) {
        if self.diff_word_wrap == next {
            return;
        }

        self.diff_word_wrap = next;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_diff_word_wrap(next, cx);
        });
        cx.notify();
    }

    fn set_diff_show_line_numbers(&mut self, next: bool, cx: &mut gpui::Context<Self>) {
        if self.diff_show_line_numbers == next {
            return;
        }

        self.diff_show_line_numbers = next;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_diff_show_line_numbers(next, cx);
        });
        cx.notify();
    }

    fn set_auto_save_file_edits(&mut self, next: bool, cx: &mut gpui::Context<Self>) {
        if self.auto_save_file_edits == next {
            return;
        }

        self.auto_save_file_edits = next;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_auto_save_file_edits(next, cx);
        });
        cx.notify();
    }

    fn set_history_column_preferences(
        &mut self,
        show_graph: bool,
        show_author: bool,
        show_date: bool,
        show_sha: bool,
        cx: &mut gpui::Context<Self>,
    ) {
        if self.history_show_graph == show_graph
            && self.history_show_author == show_author
            && self.history_show_date == show_date
            && self.history_show_sha == show_sha
        {
            return;
        }

        self.history_show_graph = show_graph;
        self.history_show_author = show_author;
        self.history_show_date = show_date;
        self.history_show_sha = show_sha;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_history_column_preferences(show_graph, show_author, show_date, show_sha, cx);
        });
        cx.notify();
    }

    fn set_history_highlight_commit_chain(&mut self, enabled: bool, cx: &mut gpui::Context<Self>) {
        if self.history_highlight_commit_chain == enabled {
            return;
        }
        self.history_highlight_commit_chain = enabled;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_history_highlight_commit_chain(enabled, cx);
        });
        cx.notify();
    }

    fn set_history_relative_dates(&mut self, enabled: bool, cx: &mut gpui::Context<Self>) {
        if self.history_relative_dates == enabled {
            return;
        }

        self.history_relative_dates = enabled;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_history_relative_dates(enabled, cx);
        });
        cx.notify();
    }

    fn set_history_show_tags(&mut self, enabled: bool, cx: &mut gpui::Context<Self>) {
        if self.history_show_tags == enabled {
            return;
        }

        self.history_show_tags = enabled;
        if !enabled && self.expanded_section == Some(SettingsSection::GitLogTagFetch) {
            self.expanded_section = None;
        }
        let tag_fetch_mode = self.history_tag_fetch_mode;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_history_tag_preferences(enabled, tag_fetch_mode, cx);
        });
        cx.notify();
    }

    fn set_history_tag_fetch_mode(
        &mut self,
        mode: GitLogTagFetchMode,
        cx: &mut gpui::Context<Self>,
    ) {
        if self.history_tag_fetch_mode == mode {
            return;
        }

        self.history_tag_fetch_mode = mode;
        self.expanded_section = None;
        let show_tags = self.history_show_tags;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_history_tag_preferences(show_tags, mode, cx);
        });
        cx.notify();
    }

    fn set_default_history_mode(&mut self, mode: HistoryMode, cx: &mut gpui::Context<Self>) {
        if self.default_history_mode == mode {
            return;
        }

        self.default_history_mode = mode;
        self.expanded_section = None;
        self.persist_preferences(cx);
        cx.notify();
    }

    fn set_default_tag_type(&mut self, tag_type: DefaultTagType, cx: &mut gpui::Context<Self>) {
        if self.default_tag_type == tag_type {
            return;
        }

        self.default_tag_type = tag_type;
        self.persist_preferences(cx);
        self.update_main_windows(cx, move |view, _window, cx| {
            view.set_default_tag_type_preference(tag_type, cx);
        });
        cx.notify();
    }

    fn option_row(
        &self,
        id: impl Into<SharedString>,
        label: impl Into<SharedString>,
        detail: Option<SharedString>,
        selected: bool,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        let id: SharedString = id.into();
        let debug_id = id.clone();
        let text_color = if selected {
            theme.colors.foreground.primary
        } else {
            theme.colors.foreground.secondary
        };
        let selected_bg = with_alpha(
            theme.colors.accent.foreground,
            if theme.is_dark { 0.16 } else { 0.10 },
        );
        let hover_bg = theme.hover_overlay();
        let active_bg = theme.active_overlay();

        div()
            .id(id)
            .debug_selector(move || debug_id.to_string())
            .w_full()
            .px_2()
            .py_1()
            .flex()
            .items_start()
            .gap_2()
            .rounded(px(theme.radii.row))
            .cursor(CursorStyle::PointingHand)
            .bg(if selected {
                selected_bg
            } else {
                gpui::rgba(0x00000000)
            })
            .hover(move |s| {
                if selected {
                    s.bg(selected_bg)
                } else {
                    s.bg(hover_bg)
                }
            })
            .active(move |s| {
                if selected {
                    s.bg(selected_bg)
                } else {
                    s.bg(active_bg)
                }
            })
            .child(
                div()
                    .w(px(16.0))
                    // Match the label's line box so the check mark centers on
                    // the first text line instead of hugging the row's top.
                    .h(px(20.0))
                    .flex_none()
                    .flex()
                    .items_center()
                    .justify_center()
                    .when(selected, |d| {
                        d.child(svg_icon(
                            "icons/check.svg",
                            theme.colors.accent.foreground,
                            px(12.0),
                        ))
                    }),
            )
            .child(
                div()
                    .flex_1()
                    .min_w(px(0.0))
                    .flex()
                    .flex_col()
                    .gap_0p5()
                    .child(
                        div()
                            .text_sm()
                            .line_height(px(20.0))
                            .text_color(text_color)
                            .child(label.into()),
                    )
                    .when_some(detail, |this, detail| {
                        this.child(
                            div()
                                .text_xs()
                                .text_color(theme.colors.foreground.secondary)
                                .line_clamp(1)
                                .whitespace_nowrap()
                                .overflow_hidden()
                                .child(detail),
                        )
                    }),
            )
    }

    fn setting_option_row(
        &self,
        id: impl Into<SharedString>,
        label: impl Into<SharedString>,
        detail: Option<SharedString>,
        selected: bool,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        self.option_row(id, label, detail, selected, theme)
            .rounded(px(0.0))
            .pb_3()
            .border_b_1()
            .border_color(settings_row_separator_color(theme))
    }

    fn dense_detail_option_row(
        &self,
        id: impl Into<SharedString>,
        label: impl Into<SharedString>,
        detail: impl Into<SharedString>,
        selected: bool,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        let id: SharedString = id.into();
        let debug_id = id.clone();
        let text_color = if selected {
            theme.colors.foreground.primary
        } else {
            theme.colors.foreground.secondary
        };
        let selected_bg = with_alpha(
            theme.colors.accent.foreground,
            if theme.is_dark { 0.16 } else { 0.10 },
        );
        let hover_bg = theme.hover_overlay();
        let active_bg = theme.active_overlay();

        div()
            .id(id)
            .debug_selector(move || debug_id.to_string())
            .w_full()
            .min_h(px(SETTINGS_DROPDOWN_DENSE_DETAIL_ROW_HEIGHT_PX))
            .px_2()
            .py(px(2.0))
            .flex()
            .items_center()
            .gap_2()
            .rounded(px(theme.radii.row))
            .cursor(CursorStyle::PointingHand)
            .bg(if selected {
                selected_bg
            } else {
                gpui::rgba(0x00000000)
            })
            .hover(move |s| {
                if selected {
                    s.bg(selected_bg)
                } else {
                    s.bg(hover_bg)
                }
            })
            .active(move |s| {
                if selected {
                    s.bg(selected_bg)
                } else {
                    s.bg(active_bg)
                }
            })
            .child(
                div()
                    .w(px(16.0))
                    .flex()
                    .items_center()
                    .justify_center()
                    .when(selected, |d| {
                        d.child(svg_icon(
                            "icons/check.svg",
                            theme.colors.accent.foreground,
                            px(12.0),
                        ))
                    }),
            )
            .child(
                div()
                    .flex()
                    .flex_1()
                    .min_w(px(0.0))
                    .items_center()
                    .gap_2()
                    .child(
                        div()
                            .text_sm()
                            .text_color(text_color)
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(label.into()),
                    )
                    .child(
                        div()
                            .flex_1()
                            .min_w(px(0.0))
                            .text_xs()
                            .text_color(theme.colors.foreground.secondary)
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(detail.into()),
                    ),
            )
    }

    fn empty_dropdown_list(&self, message: &'static str, theme: AppTheme) -> AnyElement {
        div()
            .w_full()
            .h_full()
            .min_w(px(0.0))
            .min_h(px(0.0))
            .px_2()
            .py_1()
            .text_sm()
            .text_color(theme.colors.foreground.secondary)
            .child(message)
            .into_any_element()
    }

    fn dropdown_list_container(
        &self,
        container_id: &'static str,
        scrollbar_id: &'static str,
        scroll: UniformListScrollHandle,
        item_count: usize,
        estimated_row_height_px: f32,
        extra_height_px: f32,
        list: AnyElement,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        let height = settings_dropdown_height(
            item_count,
            estimated_row_height_px,
            extra_height_px,
            self.ui_scale_percent,
        );
        // `h` includes the 1px border on each edge, so keep the requested
        // dropdown height available to the inner list viewport.
        let outer_height = height + px(2.0);

        div()
            .id(container_id)
            .debug_selector(move || container_id.to_string())
            .w_full()
            .min_w(px(0.0))
            .relative()
            .h(outer_height)
            .min_h(outer_height)
            .rounded(px(theme.radii.row))
            .border_1()
            .border_color(settings_dropdown_border_color(theme))
            .bg(settings_dropdown_background(theme))
            .overflow_hidden()
            .child(
                div()
                    .w_full()
                    .h_full()
                    .min_w(px(0.0))
                    .min_h(px(0.0))
                    .pr(components::Scrollbar::visible_gutter(
                        scroll.clone(),
                        components::ScrollbarAxis::Vertical,
                    ))
                    .child(list),
            )
            .child(
                components::Scrollbar::new(scrollbar_id, scroll)
                    .always_visible()
                    .render(theme),
            )
    }

    fn detail_container(&self, container_id: &'static str, theme: AppTheme) -> Stateful<gpui::Div> {
        div()
            .id(container_id)
            .debug_selector(move || container_id.to_string())
            .w_full()
            .min_w(px(0.0))
            .flex()
            .flex_col()
            .rounded(px(theme.radii.row))
            .border_1()
            .border_color(settings_dropdown_border_color(theme))
            .bg(settings_dropdown_background(theme))
            .overflow_hidden()
    }

    fn summary_row(
        &self,
        id: &'static str,
        label: &'static str,
        value: SharedString,
        expanded: bool,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        let label_debug_id = format!("{id}_label");
        let value_debug_id = format!("{id}_value");
        div()
            .id(id)
            .debug_selector(move || id.to_string())
            .w_full()
            .px_2()
            .pt_1()
            .pb_3()
            .flex()
            .items_center()
            .gap_2()
            .rounded(px(theme.radii.row))
            .border_b_1()
            .border_color(settings_row_separator_color(theme))
            .cursor(CursorStyle::PointingHand)
            .overflow_hidden()
            .hover(move |s| s.bg(theme.colors.interaction.hover_background))
            .active(move |s| s.bg(theme.colors.interaction.pressed_background))
            .child(
                div()
                    .debug_selector(move || label_debug_id.clone())
                    .flex_1()
                    .min_w(px(0.0))
                    .overflow_hidden()
                    .child(
                        div()
                            .text_sm()
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(label),
                    ),
            )
            .child(
                div()
                    .debug_selector(move || value_debug_id.clone())
                    .min_w(px(0.0))
                    .flex()
                    .items_center()
                    .justify_end()
                    .gap_2()
                    .text_sm()
                    .text_color(theme.colors.foreground.secondary)
                    .overflow_hidden()
                    .child(
                        div()
                            .min_w(px(0.0))
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(value),
                    )
                    .child(div().flex_shrink_0().child(svg_icon(
                        if expanded {
                            "icons/chevron_down.svg"
                        } else {
                            "icons/arrow_right.svg"
                        },
                        theme.colors.foreground.secondary,
                        px(12.0),
                    ))),
            )
    }

    fn toggle_row(
        &self,
        id: &'static str,
        label: &'static str,
        enabled: bool,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        let label_debug_id = format!("{id}_label");
        let value_debug_id = format!("{id}_value");
        div()
            .id(id)
            .debug_selector(move || id.to_string())
            .w_full()
            .px_2()
            .pt_1()
            .pb_3()
            .flex()
            .items_center()
            .gap_2()
            .rounded(px(theme.radii.row))
            .border_b_1()
            .border_color(settings_row_separator_color(theme))
            .cursor(CursorStyle::PointingHand)
            .overflow_hidden()
            .hover(move |s| s.bg(theme.colors.interaction.hover_background))
            .active(move |s| s.bg(theme.colors.interaction.pressed_background))
            .child(
                div()
                    .debug_selector(move || label_debug_id.clone())
                    .flex_1()
                    .min_w(px(0.0))
                    .overflow_hidden()
                    .child(
                        div()
                            .text_sm()
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(label),
                    ),
            )
            .child(
                div()
                    .debug_selector(move || value_debug_id.clone())
                    .flex_none()
                    .flex()
                    .items_center()
                    .child(
                        // Toggle-switch visual; the whole row stays the click
                        // target, so this carries no handlers of its own.
                        div()
                            .w(px(28.0))
                            .h(px(16.0))
                            .rounded(px(theme.radii.pill))
                            .flex()
                            .items_center()
                            .p(px(2.0))
                            .when(enabled, |track| {
                                track.justify_end().bg(theme.colors.accent.foreground)
                            })
                            .when(!enabled, |track| {
                                track.justify_start().bg(with_alpha(
                                    theme.colors.foreground.secondary,
                                    if theme.is_dark { 0.35 } else { 0.30 },
                                ))
                            })
                            .child(
                                div()
                                    .size(px(12.0))
                                    .rounded(px(theme.radii.pill))
                                    .bg(gpui::rgba(0xFFFFFFF2)),
                            ),
                    ),
            )
    }

    fn info_row(
        &self,
        id: &'static str,
        label: &'static str,
        value: SharedString,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        let label_debug_id = format!("{id}_label");
        let value_debug_id = format!("{id}_value");
        div()
            .id(id)
            .debug_selector(move || id.to_string())
            .w_full()
            .px_2()
            .pt_1()
            .pb_3()
            .flex()
            .items_center()
            .gap_2()
            .border_b_1()
            .border_color(settings_row_separator_color(theme))
            .overflow_hidden()
            .child(
                div()
                    .debug_selector(move || label_debug_id.clone())
                    .flex_1()
                    .min_w(px(0.0))
                    .overflow_hidden()
                    .child(
                        div()
                            .text_sm()
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(label),
                    ),
            )
            .child(
                div()
                    .debug_selector(move || value_debug_id.clone())
                    .min_w(px(0.0))
                    .flex()
                    .items_center()
                    .justify_end()
                    .overflow_hidden()
                    .child(
                        div()
                            .min_w(px(0.0))
                            .text_sm()
                            .font_family(UI_MONOSPACE_FONT_FAMILY)
                            .text_color(theme.colors.foreground.secondary)
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(value),
                    ),
            )
    }

    fn link_row(
        &self,
        id: &'static str,
        label: &'static str,
        value: SharedString,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        let label_debug_id = format!("{id}_label");
        let value_debug_id = format!("{id}_value");
        div()
            .id(id)
            .debug_selector(move || id.to_string())
            .w_full()
            .px_2()
            .pt_1()
            .pb_3()
            .flex()
            .flex_col()
            .items_stretch()
            .gap_0p5()
            .rounded(px(theme.radii.row))
            .border_b_1()
            .border_color(settings_row_separator_color(theme))
            .cursor(CursorStyle::PointingHand)
            .hover(move |s| s.bg(theme.colors.interaction.hover_background))
            .active(move |s| s.bg(theme.colors.interaction.pressed_background))
            .child(
                div()
                    .debug_selector(move || label_debug_id.clone())
                    .min_w(px(0.0))
                    .text_sm()
                    .child(label),
            )
            .child(
                div()
                    .debug_selector(move || value_debug_id.clone())
                    .w_full()
                    .min_w(px(0.0))
                    .flex()
                    .items_start()
                    .gap_2()
                    .text_sm()
                    .text_color(theme.colors.accent.foreground)
                    .child(div().flex_1().min_w(px(0.0)).child(value))
                    .child(div().flex_shrink_0().child(svg_icon(
                        "icons/open_external.svg",
                        theme.colors.accent.foreground,
                        px(13.0),
                    ))),
            )
    }

    /// One row per theme file the loader refused, named and with its reason.
    ///
    /// A rejected file is otherwise silent: it simply is not in the picker, the
    /// app falls back to a bundled theme, and the account of why only ever
    /// reaches stderr. After a schema break every custom theme in the folder is
    /// rejected at once, and "my theme is gone" has to be answerable from here.
    fn rejected_theme_rows(&self, theme: AppTheme) -> Vec<AnyElement> {
        crate::theme::runtime_theme_issues()
            .iter()
            .enumerate()
            .map(|(ix, issue)| {
                let name: SharedString = issue
                    .path
                    .file_name()
                    .map(|name| name.to_string_lossy().into_owned())
                    .unwrap_or_else(|| issue.path.display().to_string())
                    .into();
                let message: SharedString = issue.message.clone().into();
                div()
                    .debug_selector(move || format!("settings_window_theme_rejected_{ix}"))
                    .w_full()
                    .min_w(px(0.0))
                    .px_2()
                    .pt_1()
                    .pb_3()
                    .flex()
                    .flex_col()
                    .items_stretch()
                    .gap_0p5()
                    .border_b_1()
                    .border_color(settings_row_separator_color(theme))
                    .child(
                        div()
                            .w_full()
                            .min_w(px(0.0))
                            .flex()
                            .items_center()
                            .gap_2()
                            .text_sm()
                            .child(svg_icon(
                                "icons/warning.svg",
                                theme.colors.status.warning.foreground,
                                px(13.0),
                            ))
                            .child(div().flex_1().min_w(px(0.0)).child(name)),
                    )
                    .child(
                        div()
                            .w_full()
                            .min_w(px(0.0))
                            .text_sm()
                            .text_color(theme.colors.foreground.secondary)
                            .child(message),
                    )
                    .into_any_element()
            })
            .collect()
    }

    fn git_runtime_row(&self, theme: AppTheme) -> Stateful<gpui::Div> {
        let min_git_version = format!("{MIN_GIT_MAJOR}.{MIN_GIT_MINOR}");
        let (git_icon_path, git_icon_color, git_status_text): (
            &'static str,
            gpui::Rgba,
            SharedString,
        ) = match self.runtime_info.git.compatibility {
            GitCompatibility::Supported => (
                "icons/check.svg",
                theme.colors.status.success.foreground,
                format!("Git >= {min_git_version}").into(),
            ),
            GitCompatibility::TooOld => (
                "icons/warning.svg",
                theme.colors.status.warning.foreground,
                format!("Git < {min_git_version}").into(),
            ),
            GitCompatibility::Unknown => (
                "icons/warning.svg",
                theme.colors.status.warning.foreground,
                "Git version unknown".into(),
            ),
            GitCompatibility::Unavailable => (
                "icons/warning.svg",
                theme.colors.status.danger.foreground,
                "Unavailable".into(),
            ),
        };

        div()
            .id("settings_window_git_runtime")
            .debug_selector(|| "settings_window_git_runtime".to_string())
            .w_full()
            .px_2()
            .pt_1()
            .pb_3()
            .flex()
            .items_center()
            .gap_2()
            .overflow_hidden()
            .child(
                div()
                    .debug_selector(|| "settings_window_git_runtime_label".to_string())
                    .flex_1()
                    .min_w(px(0.0))
                    .overflow_hidden()
                    .child(
                        div()
                            .text_sm()
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child("Detected runtime"),
                    ),
            )
            .child(
                div()
                    .debug_selector(|| "settings_window_git_runtime_value".to_string())
                    .min_w(px(0.0))
                    .flex()
                    .items_center()
                    .justify_end()
                    .gap_2()
                    .overflow_hidden()
                    .child(svg_icon(git_icon_path, git_icon_color, px(14.0)))
                    .child(
                        div()
                            .min_w(px(0.0))
                            .text_sm()
                            .font_family(UI_MONOSPACE_FONT_FAMILY)
                            .text_color(theme.colors.foreground.secondary)
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(self.runtime_info.git.version_display.clone()),
                    )
                    .child(
                        div()
                            .min_w(px(0.0))
                            .text_xs()
                            .text_color(git_icon_color)
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .flex_shrink_0()
                            .child(git_status_text),
                    ),
            )
    }

    fn overflow_probe_content(&self, theme: AppTheme) -> Stateful<gpui::Div> {
        div()
            .id("settings_window_overflow_probe_view")
            .w_full()
            .flex_1()
            .min_w(px(0.0))
            .min_h(px(0.0))
            .flex()
            .flex_col()
            .gap_3()
            .p_3()
            .child(
                self.card("settings_window_overflow_probe_card", "Overflow probe", theme)
                    .child(self.summary_row(
                        "settings_window_overflow_summary",
                        "Deliberately long summary label for overflow coverage",
                        "Extraordinarily long monospace-friendly summary value used to verify clipping"
                            .into(),
                        false,
                        theme,
                    ))
                    .child(self.toggle_row(
                        "settings_window_overflow_toggle",
                        "Deliberately long toggle label for overflow coverage",
                        true,
                        theme,
                    ))
                    .child(self.info_row(
                        "settings_window_overflow_info",
                        "Deliberately long info label for overflow coverage",
                        self.runtime_info.operating_system.clone(),
                        theme,
                    ))
                    .child(self.link_row(
                        "settings_window_overflow_link",
                        "Deliberately long link label for overflow coverage",
                        "https://github.com/Auto-Explore/GitComet/releases/tag/settings-overflow-regression"
                            .into(),
                        theme,
                    ))
                    .child(self.git_runtime_row(theme)),
            )
    }

    fn open_source_license_row(
        &self,
        ix: usize,
        row: crate::view::open_source_licenses_data::OpenSourceLicenseRow,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        div()
            .id(("settings_window_open_source_license_row", ix))
            .w_full()
            .px_2()
            .py_1()
            .h(px(24.0))
            .flex()
            .items_center()
            .rounded(px(theme.radii.row))
            .hover(move |s| s.bg(theme.colors.interaction.hover_background))
            .child(
                div()
                    .flex()
                    .items_center()
                    .gap_2()
                    .child(
                        div()
                            .w(px(200.0))
                            .text_sm()
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(row.crate_name),
                    )
                    .child(
                        div()
                            .w(px(90.0))
                            .text_xs()
                            .font_family(UI_MONOSPACE_FONT_FAMILY)
                            .text_color(theme.colors.foreground.secondary)
                            .whitespace_nowrap()
                            .child(row.version),
                    )
                    .child(
                        div()
                            .flex_1()
                            .min_w(px(0.0))
                            .text_xs()
                            .font_family(UI_MONOSPACE_FONT_FAMILY)
                            .text_color(theme.colors.foreground.secondary)
                            .line_clamp(1)
                            .whitespace_nowrap()
                            .overflow_hidden()
                            .child(row.license),
                    ),
            )
    }

    fn render_open_source_license_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        _cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let rows = crate::view::open_source_licenses_data::open_source_license_rows();
        let theme = this.theme;

        range
            .filter_map(|ix| rows.get(ix).copied().map(|row| (ix, row)))
            .map(|(ix, row)| {
                this.open_source_license_row(ix, row, theme)
                    .into_any_element()
            })
            .collect()
    }

    fn render_ui_font_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| {
                this.ui_font_options
                    .get(ix)
                    .cloned()
                    .map(|family| (ix, family))
            })
            .map(|(ix, family)| {
                this.font_option_row_for_family(
                    "settings_window_ui_font",
                    ix,
                    family.as_str(),
                    this.ui_font_family == family,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                    this.set_ui_font_family(family.clone(), cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn render_theme_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        let modes = settings_theme_mode_options();
        range
            .filter_map(|ix| modes.get(ix).cloned())
            .map(|(mode, label)| {
                this.option_row(
                    format!("settings_window_theme_{}", mode.key()),
                    label,
                    None,
                    this.theme_mode == mode,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, window, cx| {
                    this.set_theme_mode(mode.clone(), window, cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn render_editor_font_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| {
                this.editor_font_options
                    .get(ix)
                    .cloned()
                    .map(|family| (ix, family))
            })
            .map(|(ix, family)| {
                this.font_option_row_for_family(
                    "settings_window_editor_font",
                    ix,
                    family.as_str(),
                    this.editor_font_family == family,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                    this.set_editor_font_family(family.clone(), cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn render_external_editor_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| this.external_editor_options.get(ix).cloned())
            .map(|option| {
                let selected = match &option.kind {
                    crate::external_editor::ExternalEditorOptionKind::None => {
                        this.external_editor_setting.is_none()
                    }
                    crate::external_editor::ExternalEditorOptionKind::Detected(setting) => {
                        this.external_editor_setting.as_ref() == Some(setting)
                    }
                    crate::external_editor::ExternalEditorOptionKind::Custom => {
                        this.external_editor_is_custom()
                    }
                };
                let row = this.option_row(
                    option.id.clone(),
                    option.label.clone(),
                    option.detail.clone().map(Into::into),
                    selected,
                    theme,
                );
                match option.kind {
                    crate::external_editor::ExternalEditorOptionKind::None => row
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_external_editor_setting(None, cx);
                        }))
                        .into_any_element(),
                    crate::external_editor::ExternalEditorOptionKind::Detected(setting) => row
                        .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                            this.set_external_editor_setting(Some(setting.clone()), cx);
                        }))
                        .into_any_element(),
                    crate::external_editor::ExternalEditorOptionKind::Custom => row
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.select_custom_external_editor(cx);
                        }))
                        .into_any_element(),
                }
            })
            .collect()
    }

    fn render_date_format_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| {
                DateTimeFormat::all()
                    .get(ix)
                    .copied()
                    .map(|format| (ix, format))
            })
            .map(|(_ix, format)| {
                this.option_row(
                    match format {
                        DateTimeFormat::YmdHm => "settings_window_date_format_ymd_hm",
                        DateTimeFormat::YmdHms => "settings_window_date_format_ymd_hms",
                        DateTimeFormat::DmyHm => "settings_window_date_format_dmy_hm",
                        DateTimeFormat::MdyHm => "settings_window_date_format_mdy_hm",
                    },
                    format.label(),
                    None,
                    this.date_time_format == format,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                    this.set_date_time_format(format, cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn render_timezone_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| {
                Timezone::all()
                    .get(ix)
                    .copied()
                    .map(|timezone| (ix, timezone))
            })
            .map(|(_ix, timezone)| {
                this.dense_detail_option_row(
                    format!("settings_window_timezone_{}", timezone.key()),
                    timezone.label(),
                    timezone.cities(),
                    this.timezone == timezone,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                    this.set_timezone(timezone, cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn render_change_tracking_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| CHANGE_TRACKING_OPTIONS.get(ix).copied())
            .map(|(id, option, detail)| {
                this.option_row(
                    id,
                    option.label(),
                    Some(detail.into()),
                    this.change_tracking_view == option,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                    this.set_change_tracking_view(option, cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn render_diff_scroll_sync_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| DIFF_SCROLL_SYNC_OPTIONS.get(ix).copied())
            .map(|(id, option, detail)| {
                this.option_row(
                    id,
                    option.label(),
                    Some(detail.into()),
                    this.diff_scroll_sync == option,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                    this.set_diff_scroll_sync(option, cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn render_diff_view_mode_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| DIFF_VIEW_MODE_OPTIONS.get(ix).copied())
            .map(|(id, option, detail)| {
                this.option_row(
                    id,
                    option.settings_label(),
                    Some(detail.into()),
                    this.diff_view_mode == option,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                    this.set_diff_view_mode(option, cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn render_diff_content_mode_option_rows(
        this: &mut Self,
        range: Range<usize>,
        _window: &mut Window,
        cx: &mut gpui::Context<Self>,
    ) -> Vec<AnyElement> {
        let theme = this.theme;
        range
            .filter_map(|ix| DIFF_CONTENT_MODE_OPTIONS.get(ix).copied())
            .map(|(id, option, detail)| {
                this.option_row(
                    id,
                    option.label(),
                    Some(detail.into()),
                    this.diff_content_mode == option,
                    theme,
                )
                .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                    this.set_diff_content_mode(option, cx);
                }))
                .into_any_element()
            })
            .collect()
    }

    fn card(&self, id: &'static str, title: &'static str, theme: AppTheme) -> Stateful<gpui::Div> {
        div()
            .id(id)
            .debug_selector(move || id.to_string())
            .w_full()
            .min_w(px(0.0))
            .flex()
            .flex_col()
            .gap_2()
            .child(
                div()
                    .px_2()
                    .pb_2()
                    .text_lg()
                    .font_weight(FontWeight::BOLD)
                    .text_color(theme.colors.foreground.primary)
                    .child(title),
            )
    }

    fn subsection_heading(
        &self,
        id: &'static str,
        title: &'static str,
        theme: AppTheme,
    ) -> Stateful<gpui::Div> {
        div()
            .id(id)
            .debug_selector(move || id.to_string())
            .w_full()
            .px_2()
            .pt(px(24.0))
            .pb_2()
            .text_sm()
            .font_weight(FontWeight::BOLD)
            .text_color(theme.colors.foreground.primary)
            .child(title)
    }

    fn settings_nav_item(
        &self,
        category: SettingsCategory,
        selected: bool,
        theme: AppTheme,
        cx: &mut gpui::Context<Self>,
    ) -> Stateful<gpui::Div> {
        let icon_color = if selected {
            theme.colors.accent.foreground
        } else {
            theme.colors.foreground.secondary
        };
        div()
            .id(category.nav_id())
            .debug_selector(move || category.nav_id().to_string())
            .w_full()
            .px_2()
            .py_1()
            .flex()
            .items_center()
            .gap_2()
            .rounded(px(theme.radii.row))
            .cursor(CursorStyle::PointingHand)
            .overflow_hidden()
            .when(selected, |d| {
                d.bg(theme.colors.interaction.pressed_background)
            })
            .when(!selected, |d| {
                d.hover(move |s| s.bg(theme.colors.interaction.hover_background))
            })
            .child(
                div()
                    .flex_shrink_0()
                    .child(svg_icon(category.icon(), icon_color, px(15.0))),
            )
            .child(
                div()
                    .flex_1()
                    .min_w(px(0.0))
                    .text_sm()
                    .when(selected, |d| d.font_weight(FontWeight::MEDIUM))
                    .text_color(theme.colors.foreground.primary)
                    .line_clamp(1)
                    .whitespace_nowrap()
                    .overflow_hidden()
                    .child(category.label()),
            )
            .on_click(cx.listener(move |this, _e: &ClickEvent, _window, cx| {
                this.select_category(category, cx);
            }))
    }

    fn render_settings_nav(
        &self,
        active: SettingsCategory,
        theme: AppTheme,
        cx: &mut gpui::Context<Self>,
    ) -> impl IntoElement {
        let query = self.search_query.clone();

        let mut list = div()
            .id("settings_window_nav_list")
            .debug_selector(|| "settings_window_nav_list".to_string())
            .flex_1()
            .min_h(px(0.0))
            .w_full()
            .overflow_y_scroll()
            .track_scroll(&self.nav_scroll)
            .flex()
            .flex_col()
            .gap(px(1.0));

        let mut any_match = false;
        for category in SettingsCategory::ALL.iter().copied() {
            if !category.matches_query(&query) {
                continue;
            }
            any_match = true;
            list = list.child(self.settings_nav_item(category, category == active, theme, cx));
        }

        if !any_match {
            list = list.child(
                div()
                    .px_2()
                    .py_1()
                    .text_sm()
                    .text_color(theme.colors.foreground.secondary)
                    .child("No matching settings"),
            );
        }

        div()
            .id("settings_window_nav")
            .debug_selector(|| "settings_window_nav".to_string())
            .flex_none()
            .w(px(200.0))
            .h_full()
            .min_h(px(0.0))
            .flex()
            .flex_col()
            .gap_2()
            .p_2()
            .bg(theme.colors.surface.chrome)
            .child(
                div()
                    .id("settings_window_nav_search")
                    .flex_none()
                    .w_full()
                    .child(self.search_input.clone()),
            )
            .child(list)
    }
}

impl Render for SettingsWindowView {
    fn render(&mut self, window: &mut Window, cx: &mut gpui::Context<Self>) -> impl IntoElement {
        let theme = self.theme;
        self.terminal_external_program_input
            .update(cx, |input, cx| input.set_theme(theme, cx));
        self.terminal_external_args_input
            .update(cx, |input, cx| input.set_theme(theme, cx));
        let decorations = window.window_decorations();
        let show_custom_window_chrome =
            crate::linux_gui_env::LinuxGuiEnvironment::should_render_custom_window_chrome(
                decorations,
            );
        let (tiling, client_inset) = match decorations {
            Decorations::Client { tiling } => (
                Some(tiling),
                settings_window_client_inset_for_scale(self.ui_scale_percent),
            ),
            Decorations::Server => (None, px(0.0)),
        };
        window.set_client_inset(client_inset);

        let cursor = self
            .hover_resize_edge
            .map(chrome::cursor_style_for_resize_edge)
            .unwrap_or(CursorStyle::Arrow);
        let is_macos = cfg!(target_os = "macos");
        let header_bg = if window.is_window_active() {
            with_alpha(
                theme.colors.surface.panel,
                if theme.is_dark { 0.98 } else { 0.94 },
            )
        } else {
            theme.colors.surface.panel
        };
        let header_border = if window.is_window_active() {
            theme.colors.stroke.default
        } else {
            with_alpha(theme.colors.stroke.default, 0.7)
        };

        let drag_region = div()
            .id("settings_window_header_drag")
            .debug_selector(|| "settings_window_header_drag".to_string())
            .flex_1()
            .h_full()
            .flex()
            .items_center()
            .min_w(px(0.0))
            .px(px(12.0))
            .window_control_area(WindowControlArea::Drag)
            .when(is_macos, |this| {
                this.pl(settings_window_traffic_lights_safe_inset(
                    self.ui_scale_percent,
                ))
            })
            .on_click(cx.listener(|this, e: &ClickEvent, window, cx| {
                if !chrome::should_handle_titlebar_double_click(e.click_count(), e.standard_click())
                {
                    return;
                }

                this.title_drag_state.clear();
                cx.stop_propagation();
                chrome::handle_titlebar_double_click(window);
                cx.notify();
            }))
            .on_mouse_up(
                MouseButton::Right,
                cx.listener(|_this, e: &MouseUpEvent, window, cx| {
                    chrome::show_titlebar_secondary_menu(e.position, window, cx);
                }),
            )
            .on_mouse_down(
                MouseButton::Left,
                cx.listener(|this, e: &MouseDownEvent, _window, cx| {
                    this.title_drag_state.on_left_mouse_down(e.click_count);
                    cx.notify();
                }),
            )
            .on_mouse_up(
                MouseButton::Left,
                cx.listener(|this, _e, _window, cx| {
                    this.title_drag_state.clear();
                    cx.notify();
                }),
            )
            .on_mouse_up_out(
                MouseButton::Left,
                cx.listener(|this, _e, _window, cx| {
                    this.title_drag_state.clear();
                    cx.notify();
                }),
            )
            .on_mouse_move(cx.listener(|this, _e, window, _cx| {
                if this.title_drag_state.take_move_request() {
                    crate::app::begin_window_move(window);
                }
            }))
            .child(
                div()
                    .overflow_hidden()
                    .text_size(px(13.0))
                    .line_height(px(16.0))
                    .font_weight(FontWeight::BOLD)
                    .whitespace_nowrap()
                    .child(SETTINGS_WINDOW_TITLE),
            );

        let min = chrome::titlebar_control_button(
            self.ui_scale_percent,
            "settings_window_min_btn",
            "icons/generic_minimize.svg",
            theme.colors.foreground.secondary,
            theme.colors.foreground.primary,
        )
        .id("settings_window_min")
        .debug_selector(|| "settings_window_min".to_string())
        .window_control_area(WindowControlArea::Min)
        .on_click(cx.listener(|_this, _e: &ClickEvent, window, cx| {
            cx.stop_propagation();
            window.minimize_window();
        }));

        let max_icon = if window.is_maximized() {
            "icons/generic_restore.svg"
        } else {
            "icons/generic_maximize.svg"
        };
        let max = chrome::titlebar_control_button(
            self.ui_scale_percent,
            "settings_window_max_btn",
            max_icon,
            theme.colors.foreground.secondary,
            theme.colors.foreground.primary,
        )
        .id("settings_window_max")
        .debug_selector(|| "settings_window_max".to_string())
        .window_control_area(WindowControlArea::Max)
        .on_click(cx.listener(|_this, _e: &ClickEvent, window, cx| {
            cx.stop_propagation();
            crate::app::toggle_window_zoom(window);
            cx.notify();
        }));

        let close = chrome::titlebar_control_button(
            self.ui_scale_percent,
            "settings_window_close_btn",
            "icons/generic_close.svg",
            theme.colors.foreground.secondary,
            theme.colors.status.danger.foreground,
        )
        .id("settings_window_close_btn")
        .debug_selector(|| "settings_window_close".to_string())
        .window_control_area(WindowControlArea::Close)
        .on_click(cx.listener(|_this, _e: &ClickEvent, window, cx| {
            cx.stop_propagation();
            crate::app::mark_clean_shutdown_if_last_window_from_view(cx);
            window.remove_window();
        }));

        let frame_rounding = chrome::client_frame_corner_rounding(theme, window);
        let header = div()
            .id("settings_window_header")
            .h(chrome::title_bar_height(self.ui_scale_percent))
            .w_full()
            .flex()
            .items_center()
            .border_b_1()
            .border_color(header_border)
            .bg(header_bg)
            .when_some(
                chrome::client_frame_corner_rounding(theme, window),
                |d, rounding| {
                    d.when(rounding.top_left, |d| d.rounded_tl(rounding.radius))
                        .when(rounding.top_right, |d| d.rounded_tr(rounding.radius))
                },
            )
            .child(drag_region)
            .when(!is_macos, |this| {
                this.child(
                    div()
                        .flex()
                        .items_center()
                        .gap_1()
                        .pr_2()
                        .child(min)
                        .child(max)
                        .child(close),
                )
            });

        self.git_executable_input
            .update(cx, |input, cx| input.set_theme(theme, cx));
        self.external_editor_custom_path_input
            .update(cx, |input, cx| input.set_theme(theme, cx));
        self.external_editor_custom_arguments_input
            .update(cx, |input, cx| input.set_theme(theme, cx));
        self.search_input
            .update(cx, |input, cx| input.set_theme(theme, cx));

        #[cfg(test)]
        let show_overflow_probe =
            self.overflow_probe && matches!(self.current_view, SettingsView::Root);
        #[cfg(not(test))]
        let show_overflow_probe = false;

        let content = if show_overflow_probe {
            self.overflow_probe_content(theme).into_any_element()
        } else {
            match self.current_view {
                SettingsView::Root => {
                    let no_separator = gpui::rgba(0x00000000);
                    let theme_row = self
                        .summary_row(
                            "settings_window_theme",
                            "Theme",
                            self.theme_mode.label().into(),
                            self.expanded_section == Some(SettingsSection::Theme),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::Theme, cx);
                        }));

                    let date_format_row = self
                        .summary_row(
                            "settings_window_date_format",
                            "Date format",
                            self.date_time_format.label().into(),
                            self.expanded_section == Some(SettingsSection::DateFormat),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::DateFormat, cx);
                        }));

                    let ui_scale_row = self
                        .summary_row(
                            "settings_window_ui_scale",
                            "UI scale",
                            ui_scale::label(self.ui_scale_percent).into(),
                            self.expanded_section == Some(SettingsSection::UiScale),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::UiScale, cx);
                        }));

                    let ui_font_row = self
                        .summary_row(
                            "settings_window_ui_font",
                            "UI Font",
                            crate::font_preferences::display_label(&self.ui_font_family).into(),
                            self.expanded_section == Some(SettingsSection::UiFont),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::UiFont, cx);
                        }));

                    let editor_font_row = self
                        .summary_row(
                            "settings_window_editor_font",
                            "Editor Font",
                            crate::font_preferences::display_label(&self.editor_font_family).into(),
                            self.expanded_section == Some(SettingsSection::EditorFont),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::EditorFont, cx);
                        }));

                    let font_ligatures_row = self
                        .toggle_row(
                            "settings_window_use_font_ligatures",
                            "Use font ligatures",
                            self.use_font_ligatures,
                            theme,
                        )
                        .border_color(no_separator)
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_use_font_ligatures(!this.use_font_ligatures, cx);
                        }));

                    let external_editor_row = self
                        .summary_row(
                            "settings_window_external_code_editor",
                            "External code editor",
                            crate::external_editor::label_for_setting(
                                self.external_editor_setting.as_ref(),
                            )
                            .into(),
                            self.expanded_section == Some(SettingsSection::ExternalCodeEditor),
                            theme,
                        )
                        .border_color(no_separator)
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::ExternalCodeEditor, cx);
                        }));

                    let timezone_row = self
                        .summary_row(
                            "settings_window_timezone",
                            "Date timezone",
                            self.timezone.label().into(),
                            self.expanded_section == Some(SettingsSection::Timezone),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::Timezone, cx);
                        }));

                    let show_timezone_row = self
                        .toggle_row(
                            "settings_window_show_timezone",
                            "Show timezone",
                            self.show_timezone,
                            theme,
                        )
                        .border_color(no_separator)
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_show_timezone(!this.show_timezone, cx);
                        }));

                    let terminal_external_row = self
                        .summary_row(
                            "settings_window_terminal_external",
                            "External terminal",
                            self.terminal_preferences.external_summary().into(),
                            self.expanded_section == Some(SettingsSection::TerminalExternal),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::TerminalExternal, cx);
                        }));

                    let terminal_action_bar_row = self
                        .summary_row(
                            "settings_window_terminal_action_bar",
                            "Action bar terminal button opens",
                            self.terminal_preferences
                                .action_bar_terminal_target
                                .label()
                                .into(),
                            self.expanded_section == Some(SettingsSection::TerminalActionBar),
                            theme,
                        )
                        .border_color(no_separator)
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::TerminalActionBar, cx);
                        }));

                    let change_tracking_row = self
                        .summary_row(
                            "settings_window_change_tracking",
                            "Untracked files",
                            self.change_tracking_view.settings_label().into(),
                            self.expanded_section == Some(SettingsSection::ChangeTracking),
                            theme,
                        )
                        .border_color(no_separator)
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::ChangeTracking, cx);
                        }));

                    let diff_scroll_sync_row = self
                        .summary_row(
                            "settings_window_diff_scroll_sync",
                            "Scroll sync",
                            self.diff_scroll_sync.label().into(),
                            self.expanded_section == Some(SettingsSection::Diff),
                            theme,
                        )
                        .border_color(no_separator)
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::Diff, cx);
                        }));

                    let diff_content_mode_row = self
                        .summary_row(
                            "settings_window_diff_content_mode",
                            "Diff mode",
                            self.diff_content_mode.settings_label().into(),
                            self.expanded_section == Some(SettingsSection::DiffContentMode),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::DiffContentMode, cx);
                        }));

                    let diff_whitespace_mode_row = self
                        .toggle_row(
                            "settings_window_diff_whitespace_mode",
                            "Show whitespace changes",
                            self.diff_whitespace_mode == DiffWhitespaceMode::Show,
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_diff_whitespace_mode(this.diff_whitespace_mode.toggled(), cx);
                        }));

                    let diff_reveal_whitespace_chars_row = self
                        .toggle_row(
                            "settings_window_diff_reveal_whitespace_chars",
                            "Reveal whitespace characters",
                            self.diff_reveal_whitespace_chars,
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_diff_reveal_whitespace_chars(
                                !this.diff_reveal_whitespace_chars,
                                cx,
                            );
                        }));

                    let diff_word_wrap_row = self
                        .toggle_row(
                            "settings_window_diff_word_wrap",
                            "Word wrap",
                            self.diff_word_wrap,
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_diff_word_wrap(!this.diff_word_wrap, cx);
                        }));

                    let diff_show_line_numbers_row = self
                        .toggle_row(
                            "settings_window_diff_show_line_numbers",
                            "Show line numbers",
                            self.diff_show_line_numbers,
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_diff_show_line_numbers(!this.diff_show_line_numbers, cx);
                        }));

                    let history_default_mode_row = self
                        .summary_row(
                            "settings_window_git_log_default_mode",
                            "Default history mode",
                            crate::view::history_mode::history_mode_label(
                                self.default_history_mode,
                            )
                            .into(),
                            self.expanded_section == Some(SettingsSection::GitLogDefaultMode),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::GitLogDefaultMode, cx);
                        }));

                    let history_columns_row = self
                        .summary_row(
                            "settings_window_git_log_columns",
                            "History columns",
                            history_columns_settings_label(
                                self.history_show_graph,
                                self.history_show_author,
                                self.history_show_date,
                                self.history_show_sha,
                            ),
                            self.expanded_section == Some(SettingsSection::GitLogColumns),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::GitLogColumns, cx);
                        }));

                    // "Lane", not "chain": what this dims is every lane but the
                    // selected commit's own. A merge's second parent sits on a
                    // lane of its own and washes out with the rest, so the old
                    // label promised an ancestry walk the graph no longer does.
                    let highlight_commit_chain_row = self
                        .toggle_row(
                            "settings_window_git_log_highlight_commit_chain",
                            "Highlight selected commit lane",
                            self.history_highlight_commit_chain,
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_history_highlight_commit_chain(
                                !this.history_highlight_commit_chain,
                                cx,
                            );
                        }));

                    let relative_dates_row = self
                        .toggle_row(
                            "settings_window_git_log_relative_dates",
                            "Relative dates in history view",
                            self.history_relative_dates,
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_history_relative_dates(!this.history_relative_dates, cx);
                        }));

                    let show_history_tags_row = self
                        .toggle_row(
                            "settings_window_git_log_show_tags",
                            "Show tags in history view",
                            self.history_show_tags,
                            theme,
                        )
                        .border_color(if self.history_show_tags {
                            settings_row_separator_color(theme)
                        } else {
                            no_separator
                        })
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_history_show_tags(!this.history_show_tags, cx);
                        }));

                    let auto_fetch_tags_row = self
                        .summary_row(
                            "settings_window_git_log_tag_fetch_mode",
                            "Automatically fetch tags",
                            git_log_tag_fetch_mode_label(self.history_tag_fetch_mode).into(),
                            self.expanded_section == Some(SettingsSection::GitLogTagFetch),
                            theme,
                        )
                        .border_color(no_separator)
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            if this.history_show_tags {
                                this.toggle_section(SettingsSection::GitLogTagFetch, cx);
                            }
                        }));

                    let mut general_card = self
                        .card("settings_window_general", "General", theme)
                        .child(self.subsection_heading(
                            "settings_window_general_appearance",
                            "Appearance",
                            theme,
                        ))
                        .child(theme_row);

                    if self.expanded_section == Some(SettingsSection::Theme) {
                        let theme_mode_count = settings_theme_modes().len();
                        let list = uniform_list(
                            "settings_window_theme_list",
                            theme_mode_count,
                            cx.processor(Self::render_theme_option_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.theme_scroll)
                        .on_scroll_wheel({
                            let scroll = self.theme_scroll.clone();
                            move |event, window, cx| {
                                if uniform_list_should_stop_scroll_propagation(
                                    &scroll, event, window,
                                ) {
                                    cx.stop_propagation();
                                }
                            }
                        });
                        let list = restrict_scroll_to_vertical_axis(list).into_any_element();
                        general_card = general_card.child(self.dropdown_list_container(
                            "settings_window_theme_list_container",
                            "settings_window_theme_scrollbar",
                            self.theme_scroll.clone(),
                            theme_mode_count,
                            SETTINGS_DROPDOWN_COMPACT_ROW_HEIGHT_PX,
                            SETTINGS_DROPDOWN_COMPACT_LIST_EXTRA_HEIGHT_PX,
                            list,
                            theme,
                        ));
                        general_card = general_card.child(
                            self.detail_container("settings_window_theme_links_container", theme)
                                // Above the folder link, so a theme that is
                                // missing from the list above is explained right
                                // next to the way to go and fix it.
                                .children(self.rejected_theme_rows(theme))
                                .child(
                                    self.link_row(
                                        "settings_window_theme_custom_folder",
                                        "Open custom theme folder",
                                        self.custom_theme_folder_detail(),
                                        theme,
                                    )
                                    .on_click(cx.listener(
                                        |this, _e: &ClickEvent, _window, cx| {
                                            this.open_custom_theme_folder(cx);
                                        },
                                    )),
                                )
                                .child(
                                    self.link_row(
                                        "settings_window_theme_guide",
                                        "Theme guide",
                                        THEMES_GUIDE_URL.into(),
                                        theme,
                                    )
                                    .border_color(no_separator)
                                    .on_click(|_, _, cx| {
                                        cx.open_url(THEMES_GUIDE_URL);
                                    }),
                                ),
                        );
                    }

                    general_card = general_card.child(ui_scale_row);
                    if self.expanded_section == Some(SettingsSection::UiScale) {
                        let mut detail =
                            self.detail_container("settings_window_ui_scale_container", theme);
                        for percent in ui_scale::UI_SCALE_PRESETS.iter().copied() {
                            let detail_text = match percent {
                                ui_scale::DEFAULT_UI_SCALE_PERCENT => Some("Default scale".into()),
                                80 | 90 => Some("Fit more on screen".into()),
                                110 | 125 | 150 => Some("Larger controls and text".into()),
                                _ => None,
                            };
                            detail = detail.child(
                                self.option_row(
                                    format!("settings_window_ui_scale_{percent}"),
                                    ui_scale::label(percent),
                                    detail_text,
                                    self.ui_scale_percent == percent,
                                    theme,
                                )
                                .on_click(cx.listener(
                                    move |this, _e: &ClickEvent, window, cx| {
                                        this.set_ui_scale_percent(percent, window, cx);
                                    },
                                )),
                            );
                        }
                        general_card = general_card.child(
                            detail.child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child("Shortcut: Ctrl/Cmd +, -, and 0."),
                            ),
                        );
                    }

                    general_card = general_card.child(ui_font_row);
                    if self.expanded_section == Some(SettingsSection::UiFont) {
                        let list = if self.ui_font_options.is_empty() {
                            self.empty_dropdown_list("No fonts available.", theme)
                        } else {
                            restrict_scroll_to_vertical_axis(uniform_list(
                                "settings_window_ui_font_list",
                                self.ui_font_options.len(),
                                cx.processor(Self::render_ui_font_option_rows),
                            )
                            .w_full()
                            .min_w(px(0.0))
                            .h_full()
                            .min_h(px(0.0))
                            .track_scroll(&self.ui_font_scroll)
                            .on_scroll_wheel({
                                let scroll = self.ui_font_scroll.clone();
                                move |event, window, cx| {
                                    if uniform_list_should_stop_scroll_propagation(
                                        &scroll, event, window,
                                    ) {
                                        cx.stop_propagation();
                                    }
                                }
                            })
                            )
                            .into_any_element()
                        };
                        general_card = general_card
                            .child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child(self.font_options_hint(self.ui_font_family.as_str())),
                            )
                            .child(self.dropdown_list_container(
                                "settings_window_ui_font_list_container",
                                "settings_window_ui_font_scrollbar",
                                self.ui_font_scroll.clone(),
                                self.ui_font_options.len(),
                                SETTINGS_DROPDOWN_COMPACT_ROW_HEIGHT_PX,
                                0.0,
                                list,
                                theme,
                            ));
                    }

                    general_card = general_card.child(editor_font_row);
                    if self.expanded_section == Some(SettingsSection::EditorFont) {
                        let list = if self.editor_font_options.is_empty() {
                            self.empty_dropdown_list("No fonts available.", theme)
                        } else {
                            restrict_scroll_to_vertical_axis(uniform_list(
                                "settings_window_editor_font_list",
                                self.editor_font_options.len(),
                                cx.processor(Self::render_editor_font_option_rows),
                            )
                            .w_full()
                            .min_w(px(0.0))
                            .h_full()
                            .min_h(px(0.0))
                            .track_scroll(&self.editor_font_scroll)
                            .on_scroll_wheel({
                                let scroll = self.editor_font_scroll.clone();
                                move |event, window, cx| {
                                    if uniform_list_should_stop_scroll_propagation(
                                        &scroll, event, window,
                                    ) {
                                        cx.stop_propagation();
                                    }
                                }
                            })
                            )
                            .into_any_element()
                        };
                        general_card = general_card
                            .child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child(
                                        self.font_options_hint(self.editor_font_family.as_str()),
                                    ),
                            )
                            .child(self.dropdown_list_container(
                                "settings_window_editor_font_list_container",
                                "settings_window_editor_font_scrollbar",
                                self.editor_font_scroll.clone(),
                                self.editor_font_options.len(),
                                SETTINGS_DROPDOWN_COMPACT_ROW_HEIGHT_PX,
                                0.0,
                                list,
                                theme,
                            ));
                    }

                    general_card = general_card.child(font_ligatures_row);

                    general_card = general_card
                        .child(self.subsection_heading(
                            "settings_window_general_integrations",
                            "Integrations",
                            theme,
                        ))
                        .child(external_editor_row);
                    if self.expanded_section == Some(SettingsSection::ExternalCodeEditor) {
                        let list = uniform_list(
                            "settings_window_external_code_editor_list",
                            self.external_editor_options.len(),
                            cx.processor(Self::render_external_editor_option_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.external_editor_scroll)
                        .on_scroll_wheel({
                            let scroll = self.external_editor_scroll.clone();
                            move |event, window, cx| {
                                if uniform_list_should_stop_scroll_propagation(
                                    &scroll, event, window,
                                ) {
                                    cx.stop_propagation();
                                }
                            }
                        })
                        .into_any_element();
                        general_card = general_card.child(self.dropdown_list_container(
                            "settings_window_external_code_editor_list_container",
                            "settings_window_external_code_editor_scrollbar",
                            self.external_editor_scroll.clone(),
                            self.external_editor_options.len(),
                            SETTINGS_DROPDOWN_DETAIL_ROW_HEIGHT_PX,
                            SETTINGS_DROPDOWN_DETAIL_LIST_EXTRA_HEIGHT_PX,
                            list,
                            theme,
                        ));
                    }

                    if self.external_editor_is_custom() {
                        let browse_button = components::Button::new(
                            "settings_window_external_code_editor_browse",
                            "Browse",
                        )
                        .style(components::ButtonStyle::Outlined)
                        .on_click(theme, cx, |_this, _e, window, cx| {
                            let view = cx.weak_entity();
                            let rx = cx.prompt_for_paths(custom_external_editor_path_prompt_options());

                            window
                                .spawn(cx, async move |cx| {
                                    let result = rx.await;
                                    let paths = match result {
                                        Ok(Ok(Some(paths))) => paths,
                                        Ok(Ok(None)) => return,
                                        Ok(Err(_)) | Err(_) => return,
                                    };
                                    let Some(path) = paths.into_iter().next() else {
                                        return;
                                    };
                                    let _ = view.update(cx, |this, cx| {
                                        this.apply_browsed_external_editor_path(path, cx);
                                    });
                                })
                                .detach();
                        });

                        general_card = general_card.child(
                            self.detail_container(
                                "settings_window_external_code_editor_custom_container",
                                theme,
                            )
                            .child(
                                div()
                                    .px_2()
                                    .pt_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child("Custom editor executable"),
                            )
                            .child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .w_full()
                                    .min_w(px(0.0))
                                    .flex()
                                    .items_center()
                                    .gap_2()
                                    .child(
                                        div()
                                            .flex_1()
                                            .min_w(px(0.0))
                                            .child(self.external_editor_custom_path_input.clone()),
                                    )
                                    .child(browse_button),
                            )
                            .child(
                                div()
                                    .px_2()
                                    .pt_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child("Arguments"),
                            )
                            .child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .w_full()
                                    .min_w(px(0.0))
                                    .child(
                                        self.external_editor_custom_arguments_input.clone(),
                                    ),
                            ),
                        );
                    }

                    general_card = general_card
                        .child(self.subsection_heading(
                            "settings_window_general_date_time",
                            "Date & Time",
                            theme,
                        ))
                        .child(date_format_row);
                    if self.expanded_section == Some(SettingsSection::DateFormat) {
                        let list = uniform_list(
                            "settings_window_date_format_list",
                            DateTimeFormat::all().len(),
                            cx.processor(Self::render_date_format_option_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.date_format_scroll)
                        .on_scroll_wheel({
                            let scroll = self.date_format_scroll.clone();
                            move |event, window, cx| {
                                if uniform_list_should_stop_scroll_propagation(
                                    &scroll, event, window,
                                ) {
                                    cx.stop_propagation();
                                }
                            }
                        });
                        let list = restrict_scroll_to_vertical_axis(list).into_any_element();
                        general_card = general_card.child(self.dropdown_list_container(
                            "settings_window_date_format_list_container",
                            "settings_window_date_format_scrollbar",
                            self.date_format_scroll.clone(),
                            DateTimeFormat::all().len(),
                            SETTINGS_DROPDOWN_COMPACT_ROW_HEIGHT_PX,
                            SETTINGS_DROPDOWN_COMPACT_LIST_EXTRA_HEIGHT_PX,
                            list,
                            theme,
                        ));
                    }

                    general_card = general_card.child(timezone_row);
                    if self.expanded_section == Some(SettingsSection::Timezone) {
                        let list = uniform_list(
                            "settings_window_timezone_list",
                            Timezone::all().len(),
                            cx.processor(Self::render_timezone_option_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.timezone_scroll)
                        .on_scroll_wheel({
                            let scroll = self.timezone_scroll.clone();
                            move |event, window, cx| {
                                if uniform_list_should_stop_scroll_propagation(
                                    &scroll, event, window,
                                ) {
                                    cx.stop_propagation();
                                }
                            }
                        });
                        let list = restrict_scroll_to_vertical_axis(list).into_any_element();
                        general_card = general_card.child(self.dropdown_list_container(
                            "settings_window_timezone_list_container",
                            "settings_window_timezone_scrollbar",
                            self.timezone_scroll.clone(),
                            Timezone::all().len(),
                            SETTINGS_DROPDOWN_DENSE_DETAIL_ROW_HEIGHT_PX,
                            0.0,
                            list,
                            theme,
                        ));
                    }

                    general_card = general_card.child(show_timezone_row);

                    let mut terminal_card =
                        self.card("settings_window_terminal_card", "Terminal", theme);

                    terminal_card = terminal_card.child(terminal_external_row);
                    if self.expanded_section == Some(SettingsSection::TerminalExternal) {
                        terminal_card = terminal_card
                            .child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child(
                                        "System default is best effort. Use a custom launcher for predictable cross-platform behavior.",
                                    ),
                            )
                            .child(
                                div()
                                    .px_2()
                                    .flex()
                                    .flex_col()
                                    .gap_1()
                                    .child(
                                        self.option_row(
                                            "settings_window_terminal_external_default",
                                            ExternalTerminalMode::SystemDefault.label(),
                                            Some("Use the platform default when possible".into()),
                                            self.terminal_preferences.external_terminal_mode
                                                == ExternalTerminalMode::SystemDefault,
                                            theme,
                                        )
                                        .on_click(cx.listener(
                                            |this, _e: &ClickEvent, _window, cx| {
                                                this.set_external_terminal_mode(
                                                    ExternalTerminalMode::SystemDefault,
                                                    cx,
                                                );
                                            },
                                        )),
                                    )
                                    .child(
                                        self.option_row(
                                            "settings_window_terminal_external_custom",
                                            ExternalTerminalMode::CustomProgram.label(),
                                            Some("Choose a launcher and explicit arguments".into()),
                                            self.terminal_preferences.external_terminal_mode
                                                == ExternalTerminalMode::CustomProgram,
                                            theme,
                                        )
                                        .on_click(cx.listener(
                                            |this, _e: &ClickEvent, _window, cx| {
                                                this.set_external_terminal_mode(
                                                    ExternalTerminalMode::CustomProgram,
                                                    cx,
                                                );
                                            },
                                        )),
                                    ),
                            );

                        if self.terminal_preferences.external_terminal_mode
                            == ExternalTerminalMode::CustomProgram
                        {
                            terminal_card = terminal_card
                                .child(
                                    div()
                                        .px_2()
                                        .pt_1()
                                        .text_xs()
                                        .text_color(theme.colors.foreground.secondary)
                                        .child("Program"),
                                )
                                .child(
                                    div()
                                        .px_2()
                                        .pb_1()
                                        .w_full()
                                        .min_w(px(0.0))
                                        .flex()
                                        .items_center()
                                        .gap_2()
                                        .child(
                                            div().flex_1().min_w(px(0.0)).child(
                                                self.terminal_external_program_input.clone(),
                                            ),
                                        )
                                        .child(
                                            components::Button::new(
                                                "settings_window_terminal_external_browse",
                                                "Browse",
                                            )
                                            .style(components::ButtonStyle::Outlined)
                                            .on_click(theme, cx, |this, _e, window, cx| {
                                                this.browse_terminal_program_input(
                                                    TerminalProgramInputTarget::ExternalTerminal,
                                                    window,
                                                    cx,
                                                );
                                            }),
                                        ),
                                )
                                .child(
                                    div()
                                        .px_2()
                                        .pt_1()
                                        .text_xs()
                                        .text_color(theme.colors.foreground.secondary)
                                        .child("Arguments"),
                                )
                                .child(
                                    div()
                                        .px_2()
                                        .pb_1()
                                        .w_full()
                                        .min_w(px(0.0))
                                        .child(self.terminal_external_args_input.clone()),
                                )
                                .child(
                                    div()
                                        .px_2()
                                        .pb_1()
                                        .text_xs()
                                        .text_color(theme.colors.foreground.secondary)
                                        .child("One argument per line. Use {cwd} and {repo_name} placeholders."),
                                )
                                .child(
                                    div()
                                        .px_2()
                                        .pb_1()
                                        .flex()
                                        .items_center()
                                        .gap_1()
                                        .child(
                                            components::Button::new(
                                                "settings_window_terminal_external_save",
                                                "Save",
                                            )
                                            .style(components::ButtonStyle::Filled)
                                            .on_click(theme, cx, |this, _e, _w, cx| {
                                                this.save_terminal_external_draft(cx);
                                            }),
                                        )
                                        .child(
                                            components::Button::new(
                                                "settings_window_terminal_external_reset",
                                                "Reset",
                                            )
                                            .style(components::ButtonStyle::Outlined)
                                            .on_click(theme, cx, |this, _e, _w, cx| {
                                                this.reset_terminal_external_draft(cx);
                                            }),
                                        )
                                        .child(
                                            components::Button::new(
                                                "settings_window_terminal_external_test",
                                                "Test launch",
                                            )
                                            .style(components::ButtonStyle::Outlined)
                                            .on_click(theme, cx, |this, _e, _w, cx| {
                                                this.test_terminal_launch_from_draft(cx);
                                            }),
                                        ),
                                );
                        }
                    }

                    terminal_card = terminal_card.child(terminal_action_bar_row);
                    if self.expanded_section == Some(SettingsSection::TerminalActionBar) {
                        terminal_card = terminal_card
                            .child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child(
                                        "Choose what the action bar terminal button opens. Global shortcuts for each can be configured separately.",
                                    ),
                            )
                            .child(
                                div()
                                    .px_2()
                                    .flex()
                                    .flex_col()
                                    .gap_1()
                                    .child(
                                        self.option_row(
                                            "settings_window_terminal_action_bar_embedded",
                                            ActionBarTerminalTarget::Embedded.label(),
                                            Some("Toggle the embedded terminal panel".into()),
                                            self.terminal_preferences.action_bar_terminal_target
                                                == ActionBarTerminalTarget::Embedded,
                                            theme,
                                        )
                                        .on_click(cx.listener(
                                            |this, _e: &ClickEvent, _window, cx| {
                                                this.set_action_bar_terminal_target(
                                                    ActionBarTerminalTarget::Embedded,
                                                    cx,
                                                );
                                            },
                                        )),
                                    )
                                    .child(
                                        self.option_row(
                                            "settings_window_terminal_action_bar_external",
                                            ActionBarTerminalTarget::External.label(),
                                            Some("Launch the external terminal".into()),
                                            self.terminal_preferences.action_bar_terminal_target
                                                == ActionBarTerminalTarget::External,
                                            theme,
                                        )
                                        .on_click(cx.listener(
                                            |this, _e: &ClickEvent, _window, cx| {
                                                this.set_action_bar_terminal_target(
                                                    ActionBarTerminalTarget::External,
                                                    cx,
                                                );
                                            },
                                        )),
                                    ),
                            );
                    }

                    if let Some(status) = self.terminal_status.clone() {
                        terminal_card = terminal_card.child(
                            div()
                                .px_2()
                                .pt_1()
                                .text_xs()
                                .text_color(if status.is_error {
                                    theme.colors.status.danger.foreground
                                } else {
                                    theme.colors.status.success.foreground
                                })
                                .child(status.text),
                        );
                    }

                    let mut change_tracking_card = self
                        .card(
                            "settings_window_change_tracking_card",
                            "Change tracking",
                            theme,
                        )
                        .child(change_tracking_row);

                    if self.expanded_section == Some(SettingsSection::ChangeTracking) {
                        let list = uniform_list(
                            "settings_window_change_tracking_list",
                            CHANGE_TRACKING_OPTIONS.len(),
                            cx.processor(Self::render_change_tracking_option_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.change_tracking_scroll)
                        .on_scroll_wheel({
                            let scroll = self.change_tracking_scroll.clone();
                            move |event, window, cx| {
                                if uniform_list_should_stop_scroll_propagation(
                                    &scroll, event, window,
                                ) {
                                    cx.stop_propagation();
                                }
                            }
                        });
                        let list = restrict_scroll_to_vertical_axis(list).into_any_element();
                        change_tracking_card =
                            change_tracking_card.child(self.dropdown_list_container(
                                "settings_window_change_tracking_list_container",
                                "settings_window_change_tracking_scrollbar",
                                self.change_tracking_scroll.clone(),
                                CHANGE_TRACKING_OPTIONS.len(),
                                SETTINGS_DROPDOWN_DETAIL_ROW_HEIGHT_PX,
                                SETTINGS_DROPDOWN_DETAIL_LIST_EXTRA_HEIGHT_PX,
                                list,
                                theme,
                            ));
                    }

                    let mut diff_card = self
                        .card("settings_window_diff_card", "Diff", theme)
                        .child(diff_content_mode_row);

                    if self.expanded_section == Some(SettingsSection::DiffContentMode) {
                        let list = uniform_list(
                            "settings_window_diff_content_mode_list",
                            DIFF_CONTENT_MODE_OPTIONS.len(),
                            cx.processor(Self::render_diff_content_mode_option_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.diff_content_mode_scroll)
                        .on_scroll_wheel({
                            let scroll = self.diff_content_mode_scroll.clone();
                            move |event, window, cx| {
                                if uniform_list_should_stop_scroll_propagation(
                                    &scroll, event, window,
                                ) {
                                    cx.stop_propagation();
                                }
                            }
                        });
                        let list = restrict_scroll_to_vertical_axis(list).into_any_element();
                        diff_card = diff_card.child(self.dropdown_list_container(
                            "settings_window_diff_content_mode_list_container",
                            "settings_window_diff_content_mode_scrollbar",
                            self.diff_content_mode_scroll.clone(),
                            DIFF_CONTENT_MODE_OPTIONS.len(),
                            SETTINGS_DROPDOWN_DETAIL_ROW_HEIGHT_PX,
                            SETTINGS_DROPDOWN_DETAIL_LIST_EXTRA_HEIGHT_PX,
                            list,
                            theme,
                        ));
                    }

                    let diff_view_mode_row = self
                        .summary_row(
                            "settings_window_diff_view_mode",
                            "View mode",
                            self.diff_view_mode.settings_label().into(),
                            self.expanded_section == Some(SettingsSection::DiffViewMode),
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.toggle_section(SettingsSection::DiffViewMode, cx);
                        }));

                    diff_card = diff_card.child(diff_view_mode_row);

                    if self.expanded_section == Some(SettingsSection::DiffViewMode) {
                        let list = uniform_list(
                            "settings_window_diff_view_mode_list",
                            DIFF_VIEW_MODE_OPTIONS.len(),
                            cx.processor(Self::render_diff_view_mode_option_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.diff_view_mode_scroll)
                        .on_scroll_wheel({
                            let scroll = self.diff_view_mode_scroll.clone();
                            move |event, window, cx| {
                                if uniform_list_should_stop_scroll_propagation(
                                    &scroll, event, window,
                                ) {
                                    cx.stop_propagation();
                                }
                            }
                        });
                        let list = restrict_scroll_to_vertical_axis(list).into_any_element();
                        diff_card = diff_card.child(self.dropdown_list_container(
                            "settings_window_diff_view_mode_list_container",
                            "settings_window_diff_view_mode_scrollbar",
                            self.diff_view_mode_scroll.clone(),
                            DIFF_VIEW_MODE_OPTIONS.len(),
                            SETTINGS_DROPDOWN_DETAIL_ROW_HEIGHT_PX,
                            SETTINGS_DROPDOWN_DETAIL_LIST_EXTRA_HEIGHT_PX,
                            list,
                            theme,
                        ));
                    }

                    diff_card = diff_card
                        .child(diff_whitespace_mode_row)
                        .child(diff_reveal_whitespace_chars_row)
                        .child(diff_word_wrap_row)
                        .child(diff_show_line_numbers_row);

                    diff_card = diff_card.child(diff_scroll_sync_row);

                    if self.expanded_section == Some(SettingsSection::Diff) {
                        let list = uniform_list(
                            "settings_window_diff_scroll_sync_list",
                            DIFF_SCROLL_SYNC_OPTIONS.len(),
                            cx.processor(Self::render_diff_scroll_sync_option_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.diff_scroll_sync_scroll)
                        .on_scroll_wheel({
                            let scroll = self.diff_scroll_sync_scroll.clone();
                            move |event, window, cx| {
                                if uniform_list_should_stop_scroll_propagation(
                                    &scroll, event, window,
                                ) {
                                    cx.stop_propagation();
                                }
                            }
                        });
                        let list = restrict_scroll_to_vertical_axis(list).into_any_element();
                        diff_card = diff_card.child(self.dropdown_list_container(
                            "settings_window_diff_scroll_sync_list_container",
                            "settings_window_diff_scroll_sync_scrollbar",
                            self.diff_scroll_sync_scroll.clone(),
                            DIFF_SCROLL_SYNC_OPTIONS.len(),
                            SETTINGS_DROPDOWN_DETAIL_ROW_HEIGHT_PX,
                            SETTINGS_DROPDOWN_DETAIL_LIST_EXTRA_HEIGHT_PX + 18.0,
                            list,
                            theme,
                        ));
                    }

                    let file_editing_card = self
                        .card(
                            "settings_window_file_editing_card",
                            "File editing",
                            theme,
                        )
                        .child(
                            self.toggle_row(
                                "settings_window_auto_save_file_edits",
                                "Auto-save edits",
                                self.auto_save_file_edits,
                                theme,
                            )
                            .border_color(no_separator)
                            .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                                this.set_auto_save_file_edits(!this.auto_save_file_edits, cx);
                            })),
                        );

                    let mut git_log_card = self
                        .card("settings_window_git_log_card", "Git log", theme)
                        .child(history_default_mode_row);

                    if self.expanded_section == Some(SettingsSection::GitLogDefaultMode) {
                        let mut mode_container = self.detail_container(
                            "settings_window_git_log_default_mode_container",
                            theme,
                        );
                        for spec in crate::view::history_mode::history_mode_ui_specs() {
                            let mode = spec.mode;
                            mode_container = mode_container.child(
                                self.option_row(
                                    spec.settings_row_id,
                                    spec.label,
                                    Some(spec.settings_description.into()),
                                    self.default_history_mode == mode,
                                    theme,
                                )
                                .on_click(cx.listener(
                                    move |this, _e: &ClickEvent, _window, cx| {
                                        this.set_default_history_mode(mode, cx);
                                    },
                                )),
                            );
                        }
                        git_log_card = git_log_card.child(
                            mode_container.child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child(
                                        "Applies when opening repositories that do not already have a saved history mode.",
                                    ),
                            ),
                        );
                    }

                    git_log_card = git_log_card.child(history_columns_row);

                    if self.expanded_section == Some(SettingsSection::GitLogColumns) {
                        git_log_card = git_log_card.child(
                            self.detail_container(
                                "settings_window_git_log_columns_container",
                                theme,
                            )
                            .child(
                                self.toggle_row(
                                    "settings_window_git_log_column_graph",
                                    "Graph",
                                    self.history_show_graph,
                                    theme,
                                )
                                .on_click(cx.listener(
                                    |this, _e: &ClickEvent, _window, cx| {
                                        this.set_history_column_preferences(
                                            !this.history_show_graph,
                                            this.history_show_author,
                                            this.history_show_date,
                                            this.history_show_sha,
                                            cx,
                                        );
                                    },
                                )),
                            )
                            .child(
                                self.toggle_row(
                                    "settings_window_git_log_column_author",
                                    "Author",
                                    self.history_show_author,
                                    theme,
                                )
                                .on_click(cx.listener(
                                    |this, _e: &ClickEvent, _window, cx| {
                                        this.set_history_column_preferences(
                                            this.history_show_graph,
                                            !this.history_show_author,
                                            this.history_show_date,
                                            this.history_show_sha,
                                            cx,
                                        );
                                    },
                                )),
                            )
                            .child(
                                self.toggle_row(
                                    "settings_window_git_log_column_date",
                                    "Commit date",
                                    self.history_show_date,
                                    theme,
                                )
                                .on_click(cx.listener(
                                    |this, _e: &ClickEvent, _window, cx| {
                                        this.set_history_column_preferences(
                                            this.history_show_graph,
                                            this.history_show_author,
                                            !this.history_show_date,
                                            this.history_show_sha,
                                            cx,
                                        );
                                    },
                                )),
                            )
                            .child(
                                self.toggle_row(
                                    "settings_window_git_log_column_sha",
                                    "SHA",
                                    self.history_show_sha,
                                    theme,
                                )
                                .on_click(cx.listener(
                                    |this, _e: &ClickEvent, _window, cx| {
                                        this.set_history_column_preferences(
                                            this.history_show_graph,
                                            this.history_show_author,
                                            this.history_show_date,
                                            !this.history_show_sha,
                                            cx,
                                        );
                                    },
                                )),
                            )
                            .child(
                                div()
                                    .px_2()
                                    .pb_1()
                                    .text_xs()
                                    .text_color(theme.colors.foreground.secondary)
                                    .child("Columns may auto-hide in narrow windows."),
                            )
                            .child(
                                self.link_row(
                                    "settings_window_git_log_reset_widths",
                                    "Reset column widths",
                                    "Reset".into(),
                                    theme,
                                )
                                .border_color(no_separator)
                                .on_click(cx.listener(
                                    |this, _e: &ClickEvent, _window, cx| {
                                        this.update_main_windows(cx, |view, _window, cx| {
                                            view.reset_history_column_widths(cx);
                                        });
                                        cx.notify();
                                    },
                                )),
                            ),
                        );
                    }

                    git_log_card = git_log_card.child(highlight_commit_chain_row);
                    git_log_card = git_log_card.child(relative_dates_row);
                    git_log_card = git_log_card.child(show_history_tags_row);
                    if self.history_show_tags {
                        git_log_card = git_log_card.child(auto_fetch_tags_row);

                        if self.expanded_section == Some(SettingsSection::GitLogTagFetch) {
                            git_log_card = git_log_card.child(
                                self.detail_container(
                                    "settings_window_git_log_tag_fetch_container",
                                    theme,
                                )
                                .child(
                                    self.option_row(
                                        "settings_window_git_log_tag_fetch_mode_activation",
                                        "On repository activation",
                                        Some(
                                            "Fetch local and remote tags in the background when a repository becomes active."
                                                .into(),
                                        ),
                                        self.history_tag_fetch_mode
                                            == GitLogTagFetchMode::OnRepositoryActivation,
                                        theme,
                                    )
                                    .on_click(cx.listener(
                                        |this, _e: &ClickEvent, _window, cx| {
                                            this.set_history_tag_fetch_mode(
                                                GitLogTagFetchMode::OnRepositoryActivation,
                                                cx,
                                            );
                                        },
                                    )),
                                )
                                .child(
                                    self.option_row(
                                        "settings_window_git_log_tag_fetch_mode_disabled",
                                        "Disabled",
                                        Some(
                                            "Skip automatic tag fetching on repository activation."
                                                .into(),
                                        ),
                                        self.history_tag_fetch_mode == GitLogTagFetchMode::Disabled,
                                        theme,
                                    )
                                    .on_click(cx.listener(
                                        |this, _e: &ClickEvent, _window, cx| {
                                            this.set_history_tag_fetch_mode(
                                                GitLogTagFetchMode::Disabled,
                                                cx,
                                            );
                                        },
                                    )),
                                ),
                            );
                        }
                    }

                    let tags_card = self
                        .card("settings_window_tags_card", "Tags", theme)
                        .child(
                            self.setting_option_row(
                                "settings_window_tags_default_lightweight",
                                "Lightweight",
                                Some(
                                    "A simple tag pointing directly to a commit. No message, no GPG signing."
                                        .into(),
                                ),
                                self.default_tag_type == DefaultTagType::Lightweight,
                                theme,
                            )
                            .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                                this.set_default_tag_type(DefaultTagType::Lightweight, cx);
                            })),
                        )
                        .child(
                            self.setting_option_row(
                                "settings_window_tags_default_annotated",
                                "Annotated",
                                Some(
                                    "Stores tag author, date, and an optional message. Supports GPG signing."
                                        .into(),
                                ),
                                self.default_tag_type == DefaultTagType::Annotated,
                                theme,
                            )
                            .border_color(no_separator)
                            .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                                this.set_default_tag_type(DefaultTagType::Annotated, cx);
                            })),
                        );

                    let system_git_row = self
                        .setting_option_row(
                            "settings_window_git_executable_system",
                            "System PATH",
                            Some(
                                "Use the first `git` executable available in the current PATH."
                                    .into(),
                            ),
                            self.git_executable_mode == GitExecutableMode::SystemPath,
                            theme,
                        )
                        .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                            this.set_git_executable_mode(GitExecutableMode::SystemPath, cx);
                        }));

                    let custom_git_row = self
                    .setting_option_row(
                        "settings_window_git_executable_custom",
                        "Custom executable",
                        Some(
                            "Use a specific Git binary and add its directory when Git resolves helper tools."
                                .into(),
                        ),
                        self.git_executable_mode == GitExecutableMode::Custom,
                        theme,
                    )
                    .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                        this.set_git_executable_mode(GitExecutableMode::Custom, cx);
                    }));

                    let mut git_executable_card = self
                        .card("settings_window_git_executable", "Git executable", theme)
                        .child(
                            div()
                                .id("settings_window_git_executable_scope_note")
                                .px_2()
                                .pb_1()
                                .text_xs()
                                .text_color(theme.colors.foreground.secondary)
                                .child(git_executable_scope_note()),
                        )
                        .child(system_git_row)
                        .child(custom_git_row);

                    if self.git_executable_mode == GitExecutableMode::Custom {
                        let browse_button = components::Button::new(
                            "settings_window_git_executable_browse",
                            "Browse",
                        )
                        .style(components::ButtonStyle::Outlined)
                        .on_click(theme, cx, |_this, _e, window, cx| {
                            let view = cx.weak_entity();
                            let rx = cx.prompt_for_paths(gpui::PathPromptOptions {
                                files: true,
                                directories: false,
                                multiple: false,
                                prompt: Some("Select Git executable".into()),
                            });

                            window
                                .spawn(cx, async move |cx| {
                                    let result = rx.await;
                                    let paths = match result {
                                        Ok(Ok(Some(paths))) => paths,
                                        Ok(Ok(None)) => return,
                                        Ok(Err(_)) | Err(_) => return,
                                    };
                                    let Some(path) = paths.into_iter().next() else {
                                        return;
                                    };
                                    let _ = view.update(cx, |this, cx| {
                                        let next = path.display().to_string();
                                        this.git_custom_path_draft = next.clone();
                                        this.git_executable_input
                                            .update(cx, |input, cx| input.set_text(next, cx));
                                        this.apply_git_executable_settings(cx);
                                    });
                                })
                                .detach();
                        });

                        let use_path_button = components::Button::new(
                            "settings_window_git_executable_apply",
                            "Use Path",
                        )
                        .style(components::ButtonStyle::Filled)
                        .on_click(theme, cx, |this, _e, _window, cx| {
                            this.apply_git_executable_settings(cx);
                        });

                        git_executable_card = git_executable_card.child(
                        self.detail_container(
                            "settings_window_git_executable_custom_container",
                            theme,
                        )
                        .child(
                            div()
                                .px_2()
                                .pt_1()
                                .text_xs()
                                .text_color(theme.colors.foreground.secondary)
                                .child("Custom Git executable"),
                        )
                        .child(
                            div()
                                .px_2()
                                .pb_1()
                                .w_full()
                                .min_w(px(0.0))
                                .flex()
                                .items_center()
                                .gap_2()
                                .child(
                                    div()
                                        .flex_1()
                                        .min_w(px(0.0))
                                        .child(self.git_executable_input.clone()),
                                )
                                .child(browse_button)
                                .child(use_path_button),
                        )
                        .child(
                            div()
                                .px_2()
                                .pb_1()
                                .text_xs()
                                .text_color(theme.colors.foreground.secondary)
                                .child(
                                    "Press Enter after editing the path to apply it immediately.",
                                ),
                        ),
                    );
                    }

                    git_executable_card = git_executable_card.child(self.git_runtime_row(theme));

                    if let Some(detail) = self.runtime_info.git.detail.clone() {
                        git_executable_card = git_executable_card.child(
                            div()
                                .id("settings_window_git_runtime_detail")
                                .px_2()
                                .pb_1()
                                .text_xs()
                                .text_color(theme.colors.foreground.secondary)
                                .child(detail),
                        );
                    }

                    let environment_card = self
                        .card("settings_window_environment", "Environment", theme)
                        .child(self.info_row(
                            "settings_window_build",
                            "Build",
                            self.runtime_info.app_version_display.clone(),
                            theme,
                        ))
                        .child(self.info_row(
                            "settings_window_os",
                            "Operating system",
                            self.runtime_info.operating_system.clone(),
                            theme,
                        ).border_color(no_separator));

                    let links_card = self
                        .card("settings_window_links", "Links", theme)
                        .child(
                            self.link_row(
                                "settings_window_links_theme_guide",
                                "Theme guide",
                                "docs/themes.md".into(),
                                theme,
                            )
                            .on_click(|_, _, cx| {
                                cx.open_url(THEMES_GUIDE_URL);
                            }),
                        )
                        .child(
                            self.link_row(
                                "settings_window_github",
                                "GitHub",
                                "Auto-Explore/GitComet".into(),
                                theme,
                            )
                            .on_click(|_, _, cx| {
                                cx.open_url(GITHUB_URL);
                            }),
                        )
                        .child(
                            self.link_row(
                                "settings_window_license",
                                "License",
                                LICENSE_NAME.into(),
                                theme,
                            )
                            .on_click(|_, _, cx| {
                                cx.open_url(LICENSE_URL);
                            }),
                        )
                        .child(
                            self.link_row(
                                "settings_window_professional_edition_waitlist",
                                "Professional Edition waitlist",
                                "gitcomet.dev".into(),
                                theme,
                            )
                            .on_click(|_, _, cx| {
                                cx.open_url(EDITIONS_URL);
                            }),
                        )
                        .child(
                            self.link_row(
                                "settings_window_open_source_licenses",
                                "Open source licenses",
                                "Show".into(),
                                theme,
                            )
                            .border_color(no_separator)
                            .on_click(cx.listener(
                                |this, _e: &ClickEvent, _window, cx| {
                                    this.show_open_source_licenses(cx);
                                },
                            )),
                        );

                    // The visible page follows the selected nav category.
                    // Expanding a row can only happen from within its owning
                    // category, so deriving from an expanded section keeps the
                    // page and the expanded row consistent.
                    let active_category = self
                        .expanded_section
                        .map(SettingsSection::category)
                        .unwrap_or(self.selected_category);

                    let active_card = match active_category {
                        SettingsCategory::General => general_card,
                        SettingsCategory::Terminal => terminal_card,
                        SettingsCategory::ChangeTracking => change_tracking_card,
                        SettingsCategory::Diff => diff_card,
                        SettingsCategory::FileEditing => file_editing_card,
                        SettingsCategory::GitLog => git_log_card,
                        SettingsCategory::Tags => tags_card,
                        SettingsCategory::GitExecutable => git_executable_card,
                        SettingsCategory::Environment => environment_card,
                        SettingsCategory::Links => links_card,
                    };

                    let scroll_surface = restrict_scroll_to_vertical_axis(
                        div()
                            .id("settings_window_scroll")
                            .debug_selector(|| "settings_window_scroll".to_string())
                            .w_full()
                            .h_full()
                            .min_w(px(0.0))
                            .min_h(px(0.0))
                            .overflow_y_scroll()
                            .track_scroll(&self.settings_window_scroll),
                    )
                    .flex()
                    .flex_col()
                    .gap_3()
                    .p_3()
                    .child(active_card);

                    let content_pane = div()
                        .id("settings_window_content_pane")
                        .debug_selector(|| "settings_window_content_pane".to_string())
                        .relative()
                        .flex_1()
                        .h_full()
                        .min_w(px(0.0))
                        .min_h(px(0.0))
                        .bg(theme.colors.surface.canvas)
                        .child(
                            div()
                                .w_full()
                                .flex_1()
                                .h_full()
                                .min_w(px(0.0))
                                .min_h(px(0.0))
                                .pr(components::Scrollbar::visible_gutter(
                                    self.settings_window_scroll.clone(),
                                    components::ScrollbarAxis::Vertical,
                                ))
                                .child(scroll_surface),
                        )
                        .child(
                            {
                                let scrollbar = components::Scrollbar::new(
                                    "settings_window_scrollbar",
                                    self.settings_window_scroll.clone(),
                                )
                                .always_visible();
                                #[cfg(test)]
                                let scrollbar =
                                    scrollbar.debug_selector("settings_window_scrollbar");
                                scrollbar
                            }
                            .render(theme),
                        );

                    div()
                        .id("settings_window_root_view")
                        .debug_selector(|| "settings_window_root_view".to_string())
                        .w_full()
                        .flex_1()
                        .min_w(px(0.0))
                        .min_h(px(0.0))
                        .flex()
                        .flex_row()
                        .child(self.render_settings_nav(active_category, theme, cx))
                        .child(content_pane)
                }
                SettingsView::OpenSourceLicenses => {
                    let rows = crate::view::open_source_licenses_data::open_source_license_rows();
                    let breadcrumb = div()
                        .id("settings_window_breadcrumb")
                        .w_full()
                        .px_2()
                        .py_1()
                        .flex()
                        .items_center()
                        .gap_2()
                        .child(
                            div()
                                .id("settings_window_breadcrumb_settings")
                                .debug_selector(|| {
                                    "settings_window_breadcrumb_settings".to_string()
                                })
                                .px_2()
                                .py_1()
                                .rounded(px(theme.radii.row))
                                .cursor(CursorStyle::PointingHand)
                                .hover(move |s| s.bg(theme.colors.interaction.hover_background))
                                .active(move |s| s.bg(theme.colors.interaction.pressed_background))
                                .text_sm()
                                .text_color(theme.colors.accent.foreground)
                                .child("< Settings")
                                .on_click(cx.listener(|this, _e: &ClickEvent, _window, cx| {
                                    this.show_root(cx);
                                })),
                        )
                        .child(
                            div()
                                .text_sm()
                                .text_color(theme.colors.foreground.secondary)
                                .child("/"),
                        )
                        .child(
                            div()
                                .text_sm()
                                .font_weight(FontWeight::BOLD)
                                .child("Open source licenses"),
                        );

                    let list = if rows.is_empty() {
                        div()
                            .px_2()
                            .py_1()
                            .text_sm()
                            .text_color(theme.colors.foreground.secondary)
                            .child("No dependency licenses found.")
                            .into_any_element()
                    } else {
                        restrict_scroll_to_vertical_axis(uniform_list(
                            "settings_window_open_source_licenses_list",
                            rows.len(),
                            cx.processor(Self::render_open_source_license_rows),
                        )
                        .w_full()
                        .min_w(px(0.0))
                        .h_full()
                        .min_h(px(0.0))
                        .track_scroll(&self.open_source_licenses_scroll))
                        .into_any_element()
                    };

                    let list_container = div()
                        .id("settings_window_open_source_licenses_list_container")
                        .w_full()
                        .min_w(px(0.0))
                        .relative()
                        .flex_1()
                        .min_h(px(0.0))
                        .child(
                            div()
                                .w_full()
                                .flex_1()
                                .h_full()
                                .min_w(px(0.0))
                                .min_h(px(0.0))
                                .pr(components::Scrollbar::visible_gutter(
                                    self.open_source_licenses_scroll.clone(),
                                    components::ScrollbarAxis::Vertical,
                                ))
                                .child(list),
                        )
                        .child(
                            {
                                let scrollbar = components::Scrollbar::new(
                                    "settings_window_open_source_licenses_scrollbar",
                                    self.open_source_licenses_scroll.clone(),
                                )
                                .always_visible();
                                #[cfg(test)]
                                let scrollbar = scrollbar.debug_selector(
                                    "settings_window_open_source_licenses_scrollbar",
                                );
                                scrollbar
                            }
                            .render(theme),
                        );

                    let licenses_card = self
                        .card(
                            "settings_window_open_source_licenses_card",
                            "Open source licenses",
                            theme,
                        )
                        .flex_1()
                        .min_h(px(0.0))
                        .child(
                            div()
                                .px_2()
                                .pb_1()
                                .text_xs()
                                .text_color(theme.colors.foreground.secondary)
                                .child(format!("{} third-party crates listed", rows.len())),
                        )
                        .child(
                            div()
                                .id("settings_window_open_source_licenses_columns")
                                .debug_selector(|| {
                                    "settings_window_open_source_licenses_columns".to_string()
                                })
                                .px_2()
                                .py_1()
                                .text_xs()
                                .text_color(theme.colors.foreground.secondary)
                                .flex()
                                .items_center()
                                .gap_2()
                                .child(div().w(px(200.0)).child("Crate"))
                                .child(div().w(px(90.0)).child("Version"))
                                .child(div().flex_1().min_w(px(0.0)).child("License")),
                        )
                        .child(list_container);

                    div()
                        .id("settings_window_open_source_licenses_view")
                        .w_full()
                        .flex_1()
                        .min_w(px(0.0))
                        .min_h(px(0.0))
                        .flex()
                        .flex_col()
                        .gap_3()
                        .p_3()
                        .child(breadcrumb)
                        .child(licenses_card)
                }
            }
            .into_any_element()
        };

        let body = div()
            .id("settings_window_content")
            .size_full()
            .flex()
            .flex_col()
            .bg(theme.colors.surface.canvas)
            .when_some(frame_rounding, |d, rounding| {
                d.when(rounding.bottom_left, |d| d.rounded_bl(rounding.radius))
                    .when(rounding.bottom_right, |d| d.rounded_br(rounding.radius))
            })
            .font(gpui::Font {
                family: crate::font_preferences::applied_ui_font_family(&self.ui_font_family)
                    .into(),
                features: crate::font_preferences::applied_font_features(self.use_font_ligatures),
                fallbacks: None,
                weight: gpui::FontWeight::default(),
                style: gpui::FontStyle::default(),
            })
            .text_color(theme.colors.foreground.primary);

        let body = if show_custom_window_chrome {
            body.child(header).child(content)
        } else {
            body.child(content)
        };

        let mut root = div()
            .size_full()
            .cursor(cursor)
            .text_color(theme.colors.foreground.primary)
            .relative()
            // Any click anywhere hides visible tooltips.
            .capture_any_mouse_down(cx.listener(|_this, _e: &MouseDownEvent, _window, cx| {
                crate::view::tooltip::dismiss_tooltips_on_mouse_down(cx);
            }));

        root = root.on_mouse_move(cx.listener(|this, e: &MouseMoveEvent, window, cx| {
            let Decorations::Client { tiling } = window.window_decorations() else {
                if this.hover_resize_edge.is_some() {
                    this.hover_resize_edge = None;
                    cx.notify();
                }
                return;
            };

            let size = window.viewport_size();
            let next = chrome::resize_edge(
                e.position,
                settings_window_client_inset_for_scale(this.ui_scale_percent),
                size,
                tiling,
            );
            if next != this.hover_resize_edge {
                this.hover_resize_edge = next;
                cx.notify();
            }
        }));

        if tiling.is_some() {
            root = root.on_mouse_down(
                MouseButton::Left,
                cx.listener(|this, e: &MouseDownEvent, window, cx| {
                    let Decorations::Client { tiling } = window.window_decorations() else {
                        return;
                    };

                    let size = window.viewport_size();
                    let edge = chrome::resize_edge(
                        e.position,
                        settings_window_client_inset_for_scale(this.ui_scale_percent),
                        size,
                        tiling,
                    );
                    let Some(edge) = edge else {
                        return;
                    };

                    cx.stop_propagation();
                    crate::app::begin_window_resize(window, edge);
                }),
            );
        } else {
            self.hover_resize_edge = None;
        }

        root.child(settings_window_frame(
            theme,
            decorations,
            body.into_any_element(),
            self.ui_scale_percent,
        ))
    }
}

impl SettingsRuntimeInfo {
    fn detect() -> Self {
        Self::from_runtime(refresh_git_runtime())
    }

    fn from_runtime(runtime: GitRuntimeState) -> Self {
        Self {
            git: git_runtime_info_from_state(runtime),
            app_version_display: format!("GitComet v{}", env!("CARGO_PKG_VERSION")).into(),
            operating_system: format!(
                "{} ({})",
                os_display_name(std::env::consts::OS),
                std::env::consts::ARCH
            )
            .into(),
        }
    }
}

/// Human-readable OS name for the Environment card ("windows" reads like a
/// debug dump; "Windows" reads like a product).
fn os_display_name(os: &str) -> &str {
    match os {
        "windows" => "Windows",
        "macos" => "macOS",
        "linux" => "Linux",
        "freebsd" => "FreeBSD",
        other => other,
    }
}

fn git_runtime_info_from_state(runtime: GitRuntimeState) -> GitRuntimeInfo {
    let compatibility_message =
        format!("GitComet has been tested only with Git {MIN_GIT_MAJOR}.{MIN_GIT_MINOR} or newer.");
    let compatibility = if !runtime.is_available() {
        GitCompatibility::Unavailable
    } else {
        match runtime.version_output().and_then(parse_git_version) {
            Some(version) if is_supported_git_version(version) => GitCompatibility::Supported,
            Some(_) => GitCompatibility::TooOld,
            None => GitCompatibility::Unknown,
        }
    };

    let version_display = runtime
        .version_output()
        .unwrap_or("Unavailable")
        .to_string()
        .into();

    let detail = match compatibility {
        GitCompatibility::Supported => None,
        GitCompatibility::TooOld | GitCompatibility::Unknown => Some(compatibility_message.into()),
        GitCompatibility::Unavailable => runtime
            .unavailable_detail()
            .map(|detail| SharedString::from(detail.to_string())),
    };

    GitRuntimeInfo {
        runtime,
        version_display,
        compatibility,
        detail,
    }
}

fn parse_git_version(raw: &str) -> Option<GitVersion> {
    raw.split_whitespace().find_map(parse_git_version_token)
}

fn parse_git_version_token(token: &str) -> Option<GitVersion> {
    let mut parts = token.split('.');
    let major = parse_u32_prefix(parts.next()?)?;
    let minor = parse_u32_prefix(parts.next()?)?;
    Some(GitVersion { major, minor })
}

fn parse_u32_prefix(part: &str) -> Option<u32> {
    let end = part
        .char_indices()
        .find_map(|(ix, ch)| (!ch.is_ascii_digit()).then_some(ix))
        .unwrap_or(part.len());
    if end == 0 {
        return None;
    }
    part[..end].parse::<u32>().ok()
}

fn is_supported_git_version(version: GitVersion) -> bool {
    version.major > MIN_GIT_MAJOR
        || (version.major == MIN_GIT_MAJOR && version.minor >= MIN_GIT_MINOR)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_support::lock_visual_test;
    use gitcomet_core::error::{Error, ErrorKind};
    use gitcomet_core::process::{
        GitExecutableAvailability, GitExecutablePreference, GitRuntimeState,
    };
    use gitcomet_core::services::{GitBackend, GitRepository, Result};
    use gpui::{Modifiers, ScrollDelta, ScrollWheelEvent};
    use std::ops::Deref;
    use std::path::{Path, PathBuf};
    use std::process::Command;
    use std::time::{SystemTime, UNIX_EPOCH};

    const SESSION_FILE_ENV: &str = "GITCOMET_SESSION_FILE";
    const DIFF_DEFAULTS_SESSION_SUBTEST_ENV: &str = "GITCOMET_DIFF_DEFAULTS_SESSION_SUBTEST";

    struct TestBackend;

    impl GitBackend for TestBackend {
        fn open(&self, _workdir: &Path) -> Result<std::sync::Arc<dyn GitRepository>> {
            Err(Error::new(ErrorKind::Unsupported(
                "Test backend does not open repositories",
            )))
        }
    }

    fn unique_session_file(label: &str) -> PathBuf {
        let dir = std::env::temp_dir().join(format!(
            "gitcomet-settings-window-{label}-{}-{}",
            std::process::id(),
            SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap_or_default()
                .as_nanos()
        ));
        std::fs::create_dir_all(&dir).expect("create settings session temp dir");
        dir.join("session.json")
    }

    fn run_subtest_with_session_env(filter: &str, session_file: &Path) {
        let current_exe = std::env::current_exe().expect("locate current test binary");
        let output = Command::new(current_exe)
            .arg(filter)
            .arg("--nocapture")
            .env(SESSION_FILE_ENV, session_file)
            .env(DIFF_DEFAULTS_SESSION_SUBTEST_ENV, "1")
            .output()
            .expect("spawn settings subtest process");
        assert!(
            output.status.success(),
            "subtest {filter} failed:\nstdout:\n{}\nstderr:\n{}",
            String::from_utf8_lossy(&output.stdout),
            String::from_utf8_lossy(&output.stderr)
        );
    }

    fn assert_debug_bounds_within(
        cx: &mut gpui::VisualTestContext,
        outer_selector: &'static str,
        inner_selector: &'static str,
    ) {
        let outer_bounds = cx
            .debug_bounds(outer_selector)
            .unwrap_or_else(|| panic!("expected `{outer_selector}` bounds"));
        let inner_bounds = cx
            .debug_bounds(inner_selector)
            .unwrap_or_else(|| panic!("expected `{inner_selector}` bounds"));
        let tolerance = px(0.5);

        assert!(
            inner_bounds.left() >= outer_bounds.left() - tolerance
                && inner_bounds.right() <= outer_bounds.right() + tolerance
                && inner_bounds.top() >= outer_bounds.top() - tolerance
                && inner_bounds.bottom() <= outer_bounds.bottom() + tolerance,
            "expected `{inner_selector}` to stay within `{outer_selector}` \
             (outer={outer_bounds:?}, inner={inner_bounds:?})"
        );
    }

    fn assert_debug_matching_horizontal_insets(
        cx: &mut gpui::VisualTestContext,
        outer_selector: &'static str,
        inner_selector: &'static str,
    ) {
        let outer_bounds = cx
            .debug_bounds(outer_selector)
            .unwrap_or_else(|| panic!("expected `{outer_selector}` bounds"));
        let inner_bounds = cx
            .debug_bounds(inner_selector)
            .unwrap_or_else(|| panic!("expected `{inner_selector}` bounds"));
        let left_inset = inner_bounds.left() - outer_bounds.left();
        let right_inset = outer_bounds.right() - inner_bounds.right();
        let tolerance = px(1.0);

        assert!(
            (left_inset - right_inset).abs() <= tolerance,
            "expected `{inner_selector}` to use the full horizontal content width inside \
             `{outer_selector}` (left inset={left_inset:?}, right inset={right_inset:?}, \
             outer={outer_bounds:?}, inner={inner_bounds:?})"
        );
    }

    #[test]
    fn git_executable_mode_tracks_runtime_preference() {
        assert_eq!(
            GitExecutableMode::from_preference(&GitExecutablePreference::SystemPath),
            GitExecutableMode::SystemPath
        );
        assert_eq!(
            GitExecutableMode::from_preference(&GitExecutablePreference::Custom(PathBuf::from(
                "/opt/git/bin/git"
            ),)),
            GitExecutableMode::Custom
        );
    }

    #[test]
    fn git_runtime_info_from_state_surfaces_unavailable_detail() {
        let runtime = GitRuntimeState {
            preference: GitExecutablePreference::Custom(PathBuf::new()),
            availability: GitExecutableAvailability::Unavailable {
                detail: "Custom Git executable is not configured. Choose an executable or switch back to System PATH.".to_string(),
            },
        };

        let info = git_runtime_info_from_state(runtime.clone());
        assert_eq!(info.runtime, runtime);
        assert_eq!(info.compatibility, GitCompatibility::Unavailable);
        assert_eq!(info.version_display.as_ref(), "Unavailable");
        assert_eq!(
            info.detail.as_ref().map(|detail| detail.as_ref()),
            Some(
                "Custom Git executable is not configured. Choose an executable or switch back to System PATH."
            )
        );
    }

    #[test]
    fn applied_git_executable_path_tracks_runtime_preference() {
        assert_eq!(
            applied_git_executable_path(&GitRuntimeState {
                preference: GitExecutablePreference::SystemPath,
                availability: GitExecutableAvailability::Available {
                    version_output: "git version 2.51.0".to_string(),
                },
            }),
            None
        );
        assert_eq!(
            applied_git_executable_path(&GitRuntimeState {
                preference: GitExecutablePreference::Custom(PathBuf::from("/opt/git/bin/git")),
                availability: GitExecutableAvailability::Available {
                    version_output: "git version 2.51.0".to_string(),
                },
            }),
            Some(PathBuf::from("/opt/git/bin/git"))
        );
        assert_eq!(
            applied_git_executable_path(&GitRuntimeState {
                preference: GitExecutablePreference::Custom(PathBuf::new()),
                availability: GitExecutableAvailability::Unavailable {
                    detail: "missing".to_string(),
                },
            }),
            Some(PathBuf::new())
        );
    }

    #[test]
    fn git_executable_scope_note_mentions_browser_only_scope() {
        let note = git_executable_scope_note();
        assert!(
            note.contains("browser window"),
            "expected browser-only scope note, got: {note}"
        );
        assert!(
            note.contains("System PATH"),
            "expected command-mode fallback note, got: {note}"
        );
    }

    #[test]
    fn parse_git_version_extracts_first_version_token() {
        assert_eq!(
            parse_git_version("git version 2.50.7"),
            Some(GitVersion {
                major: 2,
                minor: 50
            })
        );
    }

    #[test]
    fn parse_git_version_token_accepts_numeric_prefixes_and_rejects_non_numeric_prefixes() {
        assert_eq!(
            parse_git_version_token("2.45.1.windows.1"),
            Some(GitVersion {
                major: 2,
                minor: 45
            })
        );
        assert_eq!(parse_git_version_token("v2.45.1"), None);
        assert_eq!(parse_u32_prefix("53rc1"), Some(53));
        assert_eq!(parse_u32_prefix("rc53"), None);
    }

    #[test]
    fn supported_version_requires_minimum_2_50() {
        assert!(is_supported_git_version(GitVersion {
            major: MIN_GIT_MAJOR,
            minor: MIN_GIT_MINOR,
        }));
        assert!(is_supported_git_version(GitVersion {
            major: MIN_GIT_MAJOR,
            minor: MIN_GIT_MINOR + 1,
        }));
        assert!(!is_supported_git_version(GitVersion {
            major: MIN_GIT_MAJOR,
            minor: MIN_GIT_MINOR - 1,
        }));
        assert!(is_supported_git_version(GitVersion {
            major: MIN_GIT_MAJOR + 1,
            minor: 0,
        }));
    }

    #[test]
    fn settings_window_titlebar_options_match_platform_chrome_strategy() {
        let options = settings_window_titlebar_options();
        assert_eq!(
            options.appears_transparent,
            cfg!(any(target_os = "macos", target_os = "windows")),
            "settings window titlebar transparency should match the platform chrome strategy"
        );
        assert_eq!(
            options.title.as_ref().map(ToString::to_string),
            Some(SETTINGS_WINDOW_TITLE.to_string()),
            "settings window titlebar should keep the OS-visible title"
        );
    }

    #[test]
    fn settings_window_frame_strategy_matches_platform_chrome() {
        #[cfg(target_os = "windows")]
        {
            assert_eq!(settings_window_client_inset(), px(0.0));
        }

        #[cfg(not(target_os = "windows"))]
        {
            assert_eq!(
                settings_window_client_inset(),
                chrome::CLIENT_SIDE_DECORATION_INSET
            );
        }
    }

    #[test]
    fn settings_window_options_request_client_chrome_and_resize_behavior() {
        let bounds = Bounds::new(
            point(px(12.0), px(24.0)),
            size(
                px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX),
                px(SETTINGS_WINDOW_DEFAULT_HEIGHT_PX),
            ),
        );
        let options = settings_window_options(bounds);

        assert_eq!(
            options.window_bounds,
            Some(WindowBounds::Windowed(bounds)),
            "settings window should open at the requested bounds"
        );
        assert_eq!(
            options.window_min_size,
            Some(size(
                px(SETTINGS_WINDOW_MIN_WIDTH_PX),
                px(SETTINGS_WINDOW_MIN_HEIGHT_PX),
            )),
            "settings window should enforce its minimum size"
        );
        assert_eq!(
            options.window_decorations,
            Some(WindowDecorations::Client),
            "settings window should request client-side decorations"
        );
        assert!(
            options.is_movable,
            "settings window should remain movable with custom chrome"
        );
        assert!(
            options.is_resizable,
            "settings window should remain resizable with custom chrome"
        );
    }

    #[test]
    fn settings_dropdown_background_is_darker_than_card_surface() {
        fn brightness(color: gpui::Rgba) -> f32 {
            color.red + color.green + color.blue
        }

        let dark = AppTheme::gitcomet_dark();
        assert!(
            brightness(settings_dropdown_background(dark)) < brightness(dark.colors.surface.raised),
            "dark dropdown surface should be darker than the card surface"
        );

        let light = AppTheme::gitcomet_light();
        assert!(
            brightness(settings_dropdown_background(light))
                < brightness(light.colors.surface.raised),
            "light dropdown surface should still read darker than the card surface"
        );
    }

    #[test]
    fn settings_theme_modes_include_automatic_and_all_available_named_themes() {
        let modes = settings_theme_modes();
        assert_eq!(modes.first(), Some(&ThemeMode::Automatic));

        let named_modes = modes.iter().skip(1).map(ThemeMode::key).collect::<Vec<_>>();
        let available_themes = crate::theme::available_themes()
            .into_iter()
            .map(|theme| theme.key.to_string())
            .collect::<Vec<_>>();

        assert_eq!(
            named_modes,
            available_themes
                .iter()
                .map(String::as_str)
                .collect::<Vec<_>>()
        );
    }

    #[gpui::test]
    fn settings_window_sets_platform_title(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();

        assert_eq!(
            settings_cx.window_title().as_deref(),
            Some(SETTINGS_WINDOW_TITLE),
            "expected settings window to expose the native OS title"
        );
    }

    #[gpui::test]
    fn expanded_settings_sections_render_scrollable_list_containers(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1800.0)));
        settings_cx.run_until_parked();

        for (section, selector) in [
            (
                SettingsSection::Theme,
                "settings_window_theme_list_container",
            ),
            (
                SettingsSection::DateFormat,
                "settings_window_date_format_list_container",
            ),
            (
                SettingsSection::UiFont,
                "settings_window_ui_font_list_container",
            ),
            (
                SettingsSection::EditorFont,
                "settings_window_editor_font_list_container",
            ),
            (
                SettingsSection::ExternalCodeEditor,
                "settings_window_external_code_editor_list_container",
            ),
            (
                SettingsSection::Timezone,
                "settings_window_timezone_list_container",
            ),
            (
                SettingsSection::ChangeTracking,
                "settings_window_change_tracking_list_container",
            ),
            (
                SettingsSection::Diff,
                "settings_window_diff_scroll_sync_list_container",
            ),
            (
                SettingsSection::DiffContentMode,
                "settings_window_diff_content_mode_list_container",
            ),
        ] {
            let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
                settings.expanded_section = Some(section);
                cx.notify();
            });
            settings_cx.run_until_parked();
            settings_cx.update(|window, app| {
                let _ = window.draw(app);
            });

            assert!(
                settings_cx.debug_bounds(selector).is_some(),
                "expected `{selector}` to be rendered for the expanded section"
            );
        }
    }

    #[gpui::test]
    fn expanded_diff_content_mode_section_renders_before_scroll_sync_row(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.expanded_section = Some(SettingsSection::DiffContentMode);
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        let diff_mode_row = settings_cx
            .debug_bounds("settings_window_diff_content_mode")
            .expect("expected diff mode row bounds");
        let diff_mode_container = settings_cx
            .debug_bounds("settings_window_diff_content_mode_list_container")
            .expect("expected diff mode list container bounds");
        let scroll_sync_row = settings_cx
            .debug_bounds("settings_window_diff_scroll_sync")
            .expect("expected scroll sync row bounds");

        assert!(
            diff_mode_row.bottom() <= diff_mode_container.top()
                && diff_mode_container.bottom() <= scroll_sync_row.top(),
            "expected the diff mode selector to expand directly below the diff mode row"
        );
    }

    #[gpui::test]
    fn expanded_theme_section_renders_theme_utilities_and_opens_theme_guide(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.expanded_section = Some(SettingsSection::Theme);
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        assert!(
            settings_cx
                .debug_bounds("settings_window_theme_links_container")
                .is_some(),
            "expected the expanded theme section to render theme utility links"
        );
        assert!(
            settings_cx
                .debug_bounds("settings_window_theme_custom_folder")
                .is_some(),
            "expected the expanded theme section to render the custom folder action"
        );

        let guide_bounds = settings_cx
            .debug_bounds("settings_window_theme_guide")
            .expect("expected theme guide row bounds");
        settings_cx.simulate_click(guide_bounds.center(), Modifiers::default());
        settings_cx.run_until_parked();

        assert_eq!(cx.opened_url(), Some(THEMES_GUIDE_URL.to_string()));
    }

    #[gpui::test]
    fn expanded_history_columns_section_renders_detail_container(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.expanded_section = Some(SettingsSection::GitLogColumns);
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        assert!(
            settings_cx
                .debug_bounds("settings_window_git_log_columns_container")
                .is_some(),
            "expected the history columns section to render its detail container when expanded"
        );
    }

    #[gpui::test]
    fn expanded_git_log_default_mode_section_renders_modes_in_order_and_updates_selection(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.expanded_section = Some(SettingsSection::GitLogDefaultMode);
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        let mut previous_top = None;
        for spec in crate::view::history_mode::history_mode_ui_specs() {
            let bounds = settings_cx
                .debug_bounds(spec.settings_row_id)
                .unwrap_or_else(|| panic!("expected `{}` bounds", spec.settings_row_id));
            if let Some(previous_top) = previous_top {
                assert!(
                    bounds.top() > previous_top,
                    "expected `{}` to appear below the previous history mode row",
                    spec.settings_row_id
                );
            }
            previous_top = Some(bounds.top());
        }

        let selected = crate::view::history_mode::history_mode_ui_specs()
            .last()
            .copied()
            .expect("history modes");
        let initial_selected_bounds = settings_cx
            .debug_bounds(selected.settings_row_id)
            .expect("expected selected row bounds");
        let scroll_bounds = settings_cx
            .debug_bounds("settings_window_scroll")
            .expect("expected settings scroll bounds");
        let selected_center = initial_selected_bounds.center();
        if selected_center.y >= scroll_bounds.bottom() {
            let scroll_delta = selected_center.y - scroll_bounds.bottom() + px(24.0);
            let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
                let current = settings.settings_window_scroll.offset();
                settings
                    .settings_window_scroll
                    .set_offset(point(current.x, current.y - scroll_delta));
                cx.notify();
            });
            settings_cx.run_until_parked();
            settings_cx.update(|window, app| {
                let _ = window.draw(app);
            });
        }
        let selected_bounds = settings_cx
            .debug_bounds(selected.settings_row_id)
            .expect("expected selected row bounds");
        settings_cx.simulate_click(selected_bounds.center(), Modifiers::default());
        settings_cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| settings.default_history_mode)
                    .expect("settings window should remain readable"),
                selected.mode
            );
        });
    }

    #[gpui::test]
    fn expanded_git_log_default_mode_section_renders_before_history_columns_row(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.expanded_section = Some(SettingsSection::GitLogDefaultMode);
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        let default_mode_container = settings_cx
            .debug_bounds("settings_window_git_log_default_mode_container")
            .expect("expected default history mode container bounds");
        let history_columns_row = settings_cx
            .debug_bounds("settings_window_git_log_columns")
            .expect("expected history columns row bounds");

        assert!(
            default_mode_container.bottom() <= history_columns_row.top(),
            "expected the default history mode container to appear before the history columns row"
        );
    }

    #[gpui::test]
    fn expanded_auto_fetch_tags_section_renders_detail_container(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.history_show_tags = true;
            settings.expanded_section = Some(SettingsSection::GitLogTagFetch);
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        assert!(
            settings_cx
                .debug_bounds("settings_window_git_log_tag_fetch_container")
                .is_some(),
            "expected the auto fetch tags section to render its detail container when expanded"
        );
    }

    #[gpui::test]
    fn custom_git_executable_mode_renders_detail_container(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.select_category(SettingsCategory::GitExecutable, cx);
            settings.git_executable_mode = GitExecutableMode::Custom;
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        assert!(
            settings_cx
                .debug_bounds("settings_window_git_executable_custom_container")
                .is_some(),
            "expected custom git executable mode to render its detail container"
        );
    }

    #[gpui::test]
    fn custom_external_editor_renders_detail_container(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        assert!(
            settings_cx
                .debug_bounds("settings_window_external_code_editor_custom_container")
                .is_none(),
            "expected external editor custom details to stay hidden for the default None setting"
        );

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.external_editor_setting = Some(ExternalCodeEditorSetting::Custom {
                executable: PathBuf::new(),
                arguments: None,
            });
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        assert!(
            settings_cx
                .debug_bounds("settings_window_external_code_editor_custom_container")
                .is_some(),
            "expected custom external editor mode to render its detail container"
        );
    }

    #[gpui::test]
    fn browsed_external_editor_path_updates_custom_setting_and_notifies(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let _external_editor_guard =
            crate::external_editor::configured_setting_override_test_guard();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();

        let editor_path = PathBuf::from("/tmp/gitcomet-custom-editor");
        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.apply_browsed_external_editor_path(editor_path.clone(), cx);

            assert_eq!(
                settings.external_editor_setting,
                Some(ExternalCodeEditorSetting::Custom {
                    executable: editor_path.clone(),
                    arguments: None,
                })
            );
            assert_eq!(
                settings.external_editor_custom_path_draft,
                editor_path.display().to_string()
            );
            assert_eq!(
                settings
                    .external_editor_custom_path_input
                    .read(cx)
                    .text()
                    .to_string(),
                editor_path.display().to_string()
            );
            assert_eq!(settings.external_editor_browse_notify_count, 1);
        });
    }

    #[test]
    fn custom_external_editor_browse_prompt_allows_app_bundle_directories() {
        let options = custom_external_editor_path_prompt_options();

        assert!(
            options.files,
            "custom external editor browsing should still allow executable files"
        );
        assert!(
            options.directories,
            "custom external editor browsing should allow macOS .app bundle directories"
        );
        assert!(
            !options.multiple,
            "custom external editor browsing should remain a single-selection prompt"
        );
        assert_eq!(
            options.prompt.as_ref().map(ToString::to_string),
            Some("Select external code editor".to_string())
        );
    }

    #[gpui::test]
    fn external_editor_setting_seeds_from_pending_override_and_can_clear(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let _external_editor_guard =
            crate::external_editor::configured_setting_override_test_guard();
        let pending_setting = ExternalCodeEditorSetting::Custom {
            executable: PathBuf::from("/tmp/gitcomet-pending-editor"),
            arguments: Some("--reuse-window {path}".to_string()),
        };
        crate::external_editor::set_configured_setting_override(Some(pending_setting.clone()));

        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        cx.update(|_window, app| {
            let _ = settings_window.update(app, |settings, _window, cx| {
                assert_eq!(
                    settings.external_editor_setting,
                    Some(pending_setting.clone()),
                    "settings should use the pending in-memory editor preference before session persistence finishes"
                );

                settings.set_external_editor_setting(None, cx);

                assert_eq!(settings.external_editor_setting, None);
                assert_eq!(
                    crate::external_editor::configured_setting_preference_override(),
                    Some(None),
                    "clearing the reopened settings window should replace the pending editor preference"
                );
            });
        });
    }

    #[test]
    fn external_editor_preference_persist_queue_skips_stale_custom_draft_writes() {
        let session_file = unique_session_file("external-editor-draft-sequence");
        let queue = ExternalEditorPreferencePersistQueue::default();
        let stale_setting = Some(ExternalCodeEditorSetting::Custom {
            executable: PathBuf::from("/tmp/editor"),
            arguments: Some("--reuse".to_string()),
        });
        let latest_setting = Some(ExternalCodeEditorSetting::Custom {
            executable: PathBuf::from("/tmp/editor-final"),
            arguments: Some("--reuse-window {path}".to_string()),
        });

        let stale_sequence = queue.next_sequence();
        let latest_sequence = queue.next_sequence();

        assert!(
            queue
                .persist_to_path_if_latest(latest_sequence, latest_setting.clone(), &session_file)
                .expect("persist latest custom editor draft")
        );
        assert!(
            !queue
                .persist_to_path_if_latest(stale_sequence, stale_setting, &session_file)
                .expect("skip stale custom editor draft")
        );

        let loaded = gitcomet_state::session::load_from_path(&session_file);
        assert_eq!(loaded.external_code_editor, latest_setting);
    }

    #[gpui::test]
    fn generic_preference_persistence_omits_external_editor_snapshot(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        cx.update(|_window, app| {
            let _ = settings_window.update(app, |settings, _window, _cx| {
                settings.external_editor_setting = Some(ExternalCodeEditorSetting::Custom {
                    executable: PathBuf::from("/tmp/editor-before-theme-change"),
                    arguments: Some("--reuse-window {path}".to_string()),
                });
                let persisted = settings.preference_settings();
                assert_eq!(persisted.external_code_editor, None);
            });
        });
    }

    #[gpui::test]
    fn settings_dropdowns_fit_without_inner_scroll(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        for (section, label) in [
            (SettingsSection::Theme, "Theme"),
            (SettingsSection::DateFormat, "Date time format"),
            (SettingsSection::ChangeTracking, "Untracked files"),
            (SettingsSection::Diff, "Diff scroll sync"),
        ] {
            let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
                settings.expanded_section = Some(section);
                cx.notify();
            });
            settings_cx.run_until_parked();
            settings_cx.update(|window, app| {
                let _ = window.draw(app);
            });

            let max_offset = settings_window
                .update(&mut settings_cx, |settings, _window, _cx| match section {
                    SettingsSection::Theme => {
                        uniform_list_vertical_scroll_metrics(&settings.theme_scroll).2
                    }
                    SettingsSection::DateFormat => {
                        uniform_list_vertical_scroll_metrics(&settings.date_format_scroll).2
                    }
                    SettingsSection::ChangeTracking => {
                        uniform_list_vertical_scroll_metrics(&settings.change_tracking_scroll).2
                    }
                    SettingsSection::Diff => {
                        uniform_list_vertical_scroll_metrics(&settings.diff_scroll_sync_scroll).2
                    }
                    _ => px(0.0),
                })
                .expect("settings window should remain readable");

            assert_eq!(
                max_offset,
                px(0.0),
                "expected the {label} dropdown to fit without inner scroll"
            );
        }
    }

    #[gpui::test]
    fn settings_window_open_source_licenses_row_switches_content(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.select_category(SettingsCategory::Links, cx);
            // Keep the interaction test resilient as rows are added to the root links card.
            let current_x = settings.settings_window_scroll.offset().x;
            let max_offset = settings.settings_window_scroll.max_offset().y.max(px(0.0));
            settings
                .settings_window_scroll
                .set_offset(point(current_x, -max_offset));
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        let row_bounds = settings_cx
            .debug_bounds("settings_window_open_source_licenses")
            .expect("expected open source licenses row bounds");
        settings_cx.simulate_click(row_bounds.center(), Modifiers::default());
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        cx.update(|_window, app| {
            assert_eq!(
                app.windows().len(),
                2,
                "expected the settings window to reuse the existing window"
            );
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| settings.current_view)
                    .expect("settings window should remain readable"),
                SettingsView::OpenSourceLicenses,
                "expected the settings window to switch to open source licenses content"
            );
        });

        assert_eq!(
            settings_cx.window_title().as_deref(),
            Some(SETTINGS_WINDOW_TITLE),
            "expected the settings window to keep its OS title"
        );
        assert!(
            settings_cx
                .debug_bounds("settings_window_breadcrumb_settings")
                .is_some(),
            "expected a breadcrumb back control in the licenses view"
        );
        assert!(
            settings_cx
                .debug_bounds("settings_window_open_source_licenses_columns")
                .is_some(),
            "expected open source licenses columns in debug bounds"
        );
        assert!(
            settings_cx
                .debug_bounds("settings_window_open_source_licenses_scrollbar")
                .is_some(),
            "expected a visible scrollbar in the open source licenses view"
        );

        let back_bounds = settings_cx
            .debug_bounds("settings_window_breadcrumb_settings")
            .expect("expected breadcrumb back control bounds");
        settings_cx.simulate_click(back_bounds.center(), Modifiers::default());
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        cx.update(|_window, app| {
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| settings.current_view)
                    .expect("settings window should remain readable"),
                SettingsView::Root,
                "expected the breadcrumb back control to return to the root settings view"
            );
        });
    }

    #[gpui::test]
    fn settings_window_professional_edition_waitlist_row_opens_editions_page(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.select_category(SettingsCategory::Links, cx);
            // Keep the interaction test resilient as sections are added above the links card.
            let current_x = settings.settings_window_scroll.offset().x;
            let max_offset = settings.settings_window_scroll.max_offset().y.max(px(0.0));
            settings
                .settings_window_scroll
                .set_offset(point(current_x, -max_offset));
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        let row_bounds = settings_cx
            .debug_bounds("settings_window_professional_edition_waitlist")
            .expect("expected professional edition waitlist row bounds");
        settings_cx.simulate_click(row_bounds.center(), Modifiers::default());
        settings_cx.run_until_parked();

        assert_eq!(cx.opened_url(), Some(EDITIONS_URL.to_string()));
    }

    #[gpui::test]
    fn settings_window_links_card_includes_theme_guide_row(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.select_category(SettingsCategory::Links, cx);
            let current_x = settings.settings_window_scroll.offset().x;
            let max_offset = settings.settings_window_scroll.max_offset().y.max(px(0.0));
            settings
                .settings_window_scroll
                .set_offset(point(current_x, -max_offset));
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        assert!(
            settings_cx
                .debug_bounds("settings_window_links_theme_guide")
                .is_some(),
            "expected the Links card to include a Theme guide row"
        );
    }

    #[gpui::test]
    fn settings_window_root_view_renders_visible_scrollbar(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let synthetic_fonts: Arc<[String]> = (0..200)
            .map(|ix| format!("Test UI Font {ix:03}"))
            .collect::<Vec<_>>()
            .into();

        cx.update(|_window, app| {
            let _ = settings_window.update(app, |settings, _window, cx| {
                settings.ui_font_options = synthetic_fonts.clone();
                settings.ui_font_family = synthetic_fonts[0].clone();
                settings.expanded_section = Some(SettingsSection::UiFont);
                settings.settings_window_scroll = ScrollHandle::default();
                settings.ui_font_scroll = UniformListScrollHandle::default();
                cx.notify();
            });
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(
            px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX),
            px(SETTINGS_WINDOW_MIN_HEIGHT_PX),
        ));
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        let max_offset = settings_window
            .update(&mut settings_cx, |settings, _window, _cx| {
                settings.settings_window_scroll.max_offset().y.max(px(0.0))
            })
            .expect("settings window should remain readable");
        assert!(
            max_offset > px(0.0),
            "expected the root settings page to be scrollable during the test"
        );
        assert!(
            settings_cx
                .debug_bounds("settings_window_scrollbar")
                .is_some(),
            "expected a visible scrollbar in the root settings view"
        );
    }

    #[gpui::test]
    fn settings_window_rows_clamp_under_lilex_at_minimum_width(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.ui_font_family = crate::bundled_fonts::LILEX_FONT_FAMILY.to_string();
            settings.runtime_info.app_version_display =
                "GitComet v0.0.0-overflow-regression-build".into();
            settings.runtime_info.operating_system =
                "linux (gnu-linux-overflow-regression-platform, x86_64-extra-build-metadata)"
                    .into();
            settings.runtime_info.git.version_display =
                "git version 2.51.0 (overflow-regression-build-with-very-long-metadata)".into();
            settings.runtime_info.git.compatibility = GitCompatibility::Supported;
            settings.overflow_probe = true;
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(
            px(SETTINGS_WINDOW_MIN_WIDTH_PX),
            px(SETTINGS_WINDOW_DEFAULT_HEIGHT_PX),
        ));
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        for (row_selector, label_selector, value_selector) in [
            (
                "settings_window_overflow_summary",
                "settings_window_overflow_summary_label",
                "settings_window_overflow_summary_value",
            ),
            (
                "settings_window_overflow_toggle",
                "settings_window_overflow_toggle_label",
                "settings_window_overflow_toggle_value",
            ),
            (
                "settings_window_overflow_info",
                "settings_window_overflow_info_label",
                "settings_window_overflow_info_value",
            ),
            (
                "settings_window_overflow_link",
                "settings_window_overflow_link_label",
                "settings_window_overflow_link_value",
            ),
            (
                "settings_window_git_runtime",
                "settings_window_git_runtime_label",
                "settings_window_git_runtime_value",
            ),
        ] {
            assert_debug_bounds_within(&mut settings_cx, row_selector, label_selector);
            assert_debug_bounds_within(&mut settings_cx, row_selector, value_selector);
        }
    }

    #[gpui::test]
    fn settings_window_containers_fill_available_width_when_content_wraps(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let synthetic_fonts: Arc<[String]> = (0..24)
            .map(|ix| format!("Overflow Regression UI Font {ix:02} With Extended Width Coverage"))
            .collect::<Vec<_>>()
            .into();

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.ui_font_options = synthetic_fonts.clone();
            settings.ui_font_family = synthetic_fonts[0].clone();
            settings.expanded_section = Some(SettingsSection::UiFont);
            settings.git_executable_mode = GitExecutableMode::Custom;
            settings.runtime_info.app_version_display =
                "GitComet v0.0.0-overflow-regression-build-with-extra-layout-metadata".into();
            settings.runtime_info.operating_system =
                "linux (gnu-linux-overflow-regression-platform with verbose wrapping metadata, x86_64)"
                    .into();
            settings.runtime_info.git.version_display =
                "git version 2.51.0 (overflow-regression-build-with-very-long-metadata)".into();
            settings.runtime_info.git.compatibility = GitCompatibility::Unknown;
            settings.runtime_info.git.detail = Some(
                "This deliberately long compatibility detail must wrap inside the Git executable card without shrinking the settings containers into narrow blocks."
                    .into(),
            );
            settings.settings_window_scroll = ScrollHandle::default();
            settings.ui_font_scroll = UniformListScrollHandle::default();
            cx.notify();
        });
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_MIN_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();

        // Each category renders its card on its own page now, so visit every
        // category and verify the visible card fills the content-pane width.
        for (category, card_selector) in [
            (SettingsCategory::General, "settings_window_general"),
            (
                SettingsCategory::ChangeTracking,
                "settings_window_change_tracking_card",
            ),
            (SettingsCategory::Diff, "settings_window_diff_card"),
            (
                SettingsCategory::FileEditing,
                "settings_window_file_editing_card",
            ),
            (SettingsCategory::GitLog, "settings_window_git_log_card"),
            (
                SettingsCategory::GitExecutable,
                "settings_window_git_executable",
            ),
            (SettingsCategory::Environment, "settings_window_environment"),
            (SettingsCategory::Links, "settings_window_links"),
        ] {
            let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
                settings.select_category(category, cx);
                // The General page keeps a dropdown expanded to exercise wrapping.
                if category == SettingsCategory::General {
                    settings.expanded_section = Some(SettingsSection::UiFont);
                }
                cx.notify();
            });
            settings_cx.run_until_parked();
            settings_cx.update(|window, app| {
                let _ = window.draw(app);
            });

            assert_debug_matching_horizontal_insets(
                &mut settings_cx,
                "settings_window_scroll",
                card_selector,
            );

            if category == SettingsCategory::General {
                assert_debug_matching_horizontal_insets(
                    &mut settings_cx,
                    "settings_window_general",
                    "settings_window_ui_font_list_container",
                );
            }
            if category == SettingsCategory::GitExecutable {
                assert_debug_matching_horizontal_insets(
                    &mut settings_cx,
                    "settings_window_git_executable",
                    "settings_window_git_executable_custom_container",
                );
            }
        }
    }

    #[gpui::test]
    fn non_macos_settings_window_renders_custom_chrome_controls(cx: &mut gpui::TestAppContext) {
        if cfg!(target_os = "macos") {
            return;
        }

        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        for selector in [
            "settings_window_header_drag",
            "settings_window_min",
            "settings_window_max",
            "settings_window_close",
        ] {
            assert!(
                settings_cx.debug_bounds(selector).is_some(),
                "expected `{selector}` in debug bounds"
            );
        }
    }

    #[gpui::test]
    fn linux_settings_window_close_button_closes_only_the_settings_window(
        cx: &mut gpui::TestAppContext,
    ) {
        if !cfg!(any(target_os = "linux", target_os = "freebsd")) {
            return;
        }

        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            assert_eq!(app.windows().len(), 2, "expected main + settings windows");
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        let close_bounds = settings_cx
            .debug_bounds("settings_window_close")
            .expect("expected settings window close control bounds");
        settings_cx.simulate_mouse_move(close_bounds.center(), None, Modifiers::default());
        settings_cx.simulate_mouse_down(
            close_bounds.center(),
            MouseButton::Left,
            Modifiers::default(),
        );
        settings_cx.simulate_mouse_up(
            close_bounds.center(),
            MouseButton::Left,
            Modifiers::default(),
        );
        settings_cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                app.windows().len(),
                1,
                "expected the settings close control to close only the settings window"
            );
            assert!(
                app.windows()
                    .into_iter()
                    .all(|window| window.downcast::<SettingsWindowView>().is_none()),
                "expected the settings window to be removed"
            );
        });
    }

    #[gpui::test]
    fn show_timezone_toggle_defers_main_window_update(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let next_show_timezone = cx.update(|_window, app| {
            !settings_window
                .read_with(app, |settings, _cx| settings.show_timezone)
                .expect("settings window should be readable")
        });

        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_show_timezone(next_show_timezone, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "settings window toggle should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                crate::view::test_support::show_timezone(main_view.read(app)),
                next_show_timezone
            );
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| settings.show_timezone)
                    .expect("settings window should remain readable"),
                next_show_timezone
            );
        });
    }

    #[gpui::test]
    fn change_tracking_setting_defers_main_window_update(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let next_view = cx.update(|_window, app| {
            let current = settings_window
                .read_with(app, |settings, _cx| settings.change_tracking_view)
                .expect("settings window should be readable");
            match current {
                ChangeTrackingView::Combined => ChangeTrackingView::SplitUntracked,
                ChangeTrackingView::SplitUntracked => ChangeTrackingView::Combined,
            }
        });

        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_change_tracking_view(next_view, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "change tracking update should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                crate::view::test_support::change_tracking_view(main_view.read(app)),
                next_view
            );
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| settings.change_tracking_view)
                    .expect("settings window should remain readable"),
                next_view
            );
        });
    }

    #[gpui::test]
    fn terminal_settings_sections_toggle_and_render_controls(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.select_category(SettingsCategory::Terminal, cx);
        });
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(1200.0)));
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        assert!(
            settings_cx
                .debug_bounds("settings_window_terminal_action_bar_embedded")
                .is_none(),
            "expected action bar terminal options to stay collapsed until opened"
        );

        let action_bar_bounds = settings_cx
            .debug_bounds("settings_window_terminal_action_bar")
            .expect("expected action bar terminal row bounds");
        settings_cx.simulate_click(action_bar_bounds.center(), Modifiers::default());
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        for selector in [
            "settings_window_terminal_action_bar_embedded",
            "settings_window_terminal_action_bar_external",
        ] {
            assert!(
                settings_cx.debug_bounds(selector).is_some(),
                "expected `{selector}` when the action bar terminal section is expanded"
            );
        }

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.toggle_section(SettingsSection::TerminalActionBar, cx);
        });
        settings_cx.run_until_parked();
        assert!(
            settings_window
                .update(&mut settings_cx, |settings, _window, _cx| {
                    settings.expanded_section
                })
                .expect("settings window should remain readable")
                != Some(SettingsSection::TerminalActionBar),
            "expected action bar terminal section state to collapse when toggled again"
        );

        let external_bounds = settings_cx
            .debug_bounds("settings_window_terminal_external")
            .expect("expected external terminal row bounds");
        settings_cx.simulate_click(external_bounds.center(), Modifiers::default());
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        for selector in [
            "settings_window_terminal_external_default",
            "settings_window_terminal_external_custom",
        ] {
            assert!(
                settings_cx.debug_bounds(selector).is_some(),
                "expected `{selector}` when the external terminal section is expanded"
            );
        }

        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            settings.toggle_section(SettingsSection::TerminalExternal, cx);
        });
        settings_cx.run_until_parked();
        assert!(
            settings_window
                .update(&mut settings_cx, |settings, _window, _cx| {
                    settings.expanded_section
                })
                .expect("settings window should remain readable")
                != Some(SettingsSection::TerminalExternal),
            "expected external terminal section state to collapse when toggled again"
        );
    }

    #[gpui::test]
    fn action_bar_terminal_target_setting_defers_main_window_update(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let next_target = cx.update(|_window, app| {
            let current = settings_window
                .read_with(app, |settings, _cx| {
                    settings.terminal_preferences.action_bar_terminal_target
                })
                .expect("settings window should be readable");
            match current {
                ActionBarTerminalTarget::Embedded => ActionBarTerminalTarget::External,
                ActionBarTerminalTarget::External => ActionBarTerminalTarget::Embedded,
            }
        });

        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_action_bar_terminal_target(next_target, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "action bar terminal target updates should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                main_view
                    .read(app)
                    .terminal_preferences_for_test()
                    .action_bar_terminal_target,
                next_target
            );
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| {
                        settings.terminal_preferences.action_bar_terminal_target
                    })
                    .expect("settings window should remain readable"),
                next_target
            );
        });
    }

    #[gpui::test]
    fn diff_scroll_sync_setting_defers_main_window_update(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let next_mode = cx.update(|_window, app| {
            let current = settings_window
                .read_with(app, |settings, _cx| settings.diff_scroll_sync)
                .expect("settings window should be readable");
            match current {
                DiffScrollSync::Both => DiffScrollSync::Vertical,
                DiffScrollSync::Vertical => DiffScrollSync::Horizontal,
                DiffScrollSync::Horizontal => DiffScrollSync::None,
                DiffScrollSync::None => DiffScrollSync::Both,
            }
        });

        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_diff_scroll_sync(next_mode, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "diff scroll sync update should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                crate::view::test_support::diff_scroll_sync(main_view.read(app)),
                next_mode
            );
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| settings.diff_scroll_sync)
                    .expect("settings window should remain readable"),
                next_mode
            );
        });
    }

    #[gpui::test]
    fn diff_content_mode_setting_defers_main_window_update(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let next_mode = cx.update(|_window, app| {
            let current = settings_window
                .read_with(app, |settings, _cx| settings.diff_content_mode)
                .expect("settings window should be readable");
            match current {
                DiffContentMode::Full => DiffContentMode::Collapsed,
                DiffContentMode::Collapsed => DiffContentMode::Full,
            }
        });

        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_diff_content_mode(next_mode, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "diff content mode update should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                crate::view::test_support::diff_content_mode(main_view.read(app)),
                next_mode
            );
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| settings.diff_content_mode)
                    .expect("settings window should remain readable"),
                next_mode
            );
        });
    }

    #[gpui::test]
    fn diff_whitespace_mode_setting_defers_main_window_update(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let next_mode = cx.update(|_window, app| {
            let current = settings_window
                .read_with(app, |settings, _cx| settings.diff_whitespace_mode)
                .expect("settings window should be readable");
            current.toggled()
        });

        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_diff_whitespace_mode(next_mode, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "diff whitespace mode update should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                crate::view::test_support::diff_whitespace_mode(main_view.read(app)),
                next_mode
            );
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| settings.diff_whitespace_mode)
                    .expect("settings window should remain readable"),
                next_mode
            );
        });
    }

    #[gpui::test]
    fn auto_save_file_edits_toggle_reaches_the_main_window(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        cx.update(|_window, app| {
            assert!(
                !main_view.read(app).main_pane.read(app).auto_save_file_edits,
                "auto-save is off until it is turned on"
            );
        });

        // Nested inside a `GitCometView` update, as the deferral regression
        // tests do: the settings window must not re-enter the main view.
        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_auto_save_file_edits(true, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "the auto-save toggle should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert!(
                main_view.read(app).main_pane.read(app).auto_save_file_edits,
                "the pane that owns the editor must see the new value"
            );
            assert!(
                settings_window
                    .read_with(app, |settings, _cx| settings.auto_save_file_edits)
                    .expect("settings window should remain readable")
            );
        });
    }

    #[gpui::test]
    fn diff_render_settings_update_main_window(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_diff_reveal_whitespace_chars(true, cx);
                        settings.set_diff_word_wrap(true, cx);
                        settings.set_diff_show_line_numbers(false, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "diff render setting updates should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert!(crate::view::test_support::diff_reveal_whitespace_chars(
                main_view.read(app)
            ));
            assert!(crate::view::test_support::diff_word_wrap(
                main_view.read(app)
            ));
            assert!(!crate::view::test_support::diff_show_line_numbers(
                main_view.read(app)
            ));
            assert!(
                settings_window
                    .read_with(app, |settings, _cx| settings.diff_reveal_whitespace_chars)
                    .expect("settings window should remain readable")
            );
            assert!(
                settings_window
                    .read_with(app, |settings, _cx| settings.diff_word_wrap)
                    .expect("settings window should remain readable")
            );
            assert!(
                !settings_window
                    .read_with(app, |settings, _cx| settings.diff_show_line_numbers)
                    .expect("settings window should remain readable")
            );
        });
    }

    #[test]
    fn diff_render_defaults_from_session_wrapper() {
        let session_file = unique_session_file("diff-defaults");
        gitcomet_state::session::persist_ui_settings_to_path(
            gitcomet_state::session::UiSettings {
                diff_reveal_whitespace_chars: Some(true),
                diff_word_wrap: Some(true),
                diff_show_line_numbers: Some(false),
                ..Default::default()
            },
            &session_file,
        )
        .expect("seed diff defaults session");

        run_subtest_with_session_env(
            "diff_render_defaults_from_session_subprocess",
            &session_file,
        );
    }

    #[gpui::test]
    fn diff_render_defaults_from_session_subprocess(cx: &mut gpui::TestAppContext) {
        if std::env::var_os(DIFF_DEFAULTS_SESSION_SUBTEST_ENV).is_none() {
            return;
        }

        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|_window, app| {
            let view = main_view.read(app);
            assert!(crate::view::test_support::diff_reveal_whitespace_chars(
                view
            ));
            assert!(crate::view::test_support::diff_word_wrap(view));
            assert!(!crate::view::test_support::diff_show_line_numbers(view));
            assert!(view.main_pane.read(app).reveal_whitespace_chars);
            assert!(view.main_pane.read(app).diff_word_wrap);
            assert!(!view.main_pane.read(app).diff_show_line_numbers);
        });

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        cx.update(|_window, app| {
            assert!(
                settings_window
                    .read_with(app, |settings, _cx| settings.diff_reveal_whitespace_chars)
                    .expect("settings window should remain readable")
            );
            assert!(
                settings_window
                    .read_with(app, |settings, _cx| settings.diff_word_wrap)
                    .expect("settings window should remain readable")
            );
            assert!(
                !settings_window
                    .read_with(app, |settings, _cx| settings.diff_show_line_numbers)
                    .expect("settings window should remain readable")
            );
        });
    }

    #[gpui::test]
    fn external_terminal_mode_setting_defers_main_window_update(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let next_mode = cx.update(|_window, app| {
            let current = settings_window
                .read_with(app, |settings, _cx| {
                    settings.terminal_preferences.external_terminal_mode
                })
                .expect("settings window should be readable");
            match current {
                ExternalTerminalMode::SystemDefault => ExternalTerminalMode::CustomProgram,
                ExternalTerminalMode::CustomProgram => ExternalTerminalMode::SystemDefault,
            }
        });

        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            cx.update(|_window, app| {
                main_view.update(app, |_view, cx| {
                    let _ = settings_window.update(cx, |settings, _window, cx| {
                        settings.set_external_terminal_mode(next_mode, cx);
                    });
                });
            });
        }));
        assert!(
            result.is_ok(),
            "external terminal mode updates should not re-enter GitCometView updates"
        );

        cx.run_until_parked();

        cx.update(|_window, app| {
            assert_eq!(
                main_view
                    .read(app)
                    .terminal_preferences_for_test()
                    .external_terminal_mode,
                next_mode
            );
            assert_eq!(
                settings_window
                    .read_with(app, |settings, _cx| {
                        settings.terminal_preferences.external_terminal_mode
                    })
                    .expect("settings window should remain readable"),
                next_mode
            );
        });
    }

    #[gpui::test]
    fn terminal_external_draft_save_trims_multiline_args_before_persistence(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        cx.update(|_window, app| {
            let _ = settings_window.update(app, |settings, _window, cx| {
                settings.set_external_terminal_mode(ExternalTerminalMode::CustomProgram, cx);
                settings
                    .terminal_external_program_input
                    .update(cx, |input, cx| input.set_text("  wezterm  ", cx));
                settings
                    .terminal_external_args_input
                    .update(cx, |input, cx| {
                        input.set_text("  start  \n\n  --cwd  \n  {cwd}  \n", cx);
                    });
                settings.save_terminal_external_draft(cx);
            });
        });
        cx.run_until_parked();

        cx.update(|_window, app| {
            let root_preferences = main_view.read(app).terminal_preferences_for_test().clone();
            assert_eq!(
                root_preferences.external_terminal_mode,
                ExternalTerminalMode::CustomProgram
            );
            assert_eq!(root_preferences.external_terminal_program, "wezterm");
            assert_eq!(
                root_preferences.external_terminal_args,
                vec![
                    "start".to_string(),
                    "--cwd".to_string(),
                    "{cwd}".to_string(),
                ]
            );

            let (program, args, program_input, args_input, status) = settings_window
                .read_with(app, |settings, cx| {
                    (
                        settings
                            .terminal_preferences
                            .external_terminal_program
                            .clone(),
                        settings.terminal_preferences.external_terminal_args.clone(),
                        settings
                            .terminal_external_program_input
                            .read_with(cx, |input, _| input.text().to_string()),
                        settings
                            .terminal_external_args_input
                            .read_with(cx, |input, _| input.text().to_string()),
                        settings
                            .terminal_status
                            .as_ref()
                            .map(|status| status.text.to_string()),
                    )
                })
                .expect("settings window should remain readable");

            assert_eq!(program, "wezterm");
            assert_eq!(
                args,
                vec![
                    "start".to_string(),
                    "--cwd".to_string(),
                    "{cwd}".to_string(),
                ]
            );
            assert_eq!(program_input, "  wezterm  ");
            assert_eq!(args_input, "  start  \n\n  --cwd  \n  {cwd}  \n");
            assert_eq!(status.as_deref(), Some("External terminal settings saved."));
        });
    }

    #[gpui::test]
    fn terminal_external_draft_save_and_reset(cx: &mut gpui::TestAppContext) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        cx.update(|_window, app| {
            let _ = settings_window.update(app, |settings, _window, cx| {
                settings.set_external_terminal_mode(ExternalTerminalMode::CustomProgram, cx);
                settings
                    .terminal_external_program_input
                    .update(cx, |input, cx| input.set_text("wezterm", cx));
                settings
                    .terminal_external_args_input
                    .update(cx, |input, cx| {
                        input.set_text("start\n--cwd\n{cwd}", cx);
                    });
                settings.save_terminal_external_draft(cx);

                settings
                    .terminal_external_program_input
                    .update(cx, |input, cx| input.set_text("kitty", cx));
                settings
                    .terminal_external_args_input
                    .update(cx, |input, cx| {
                        input.set_text("--directory\n/tmp", cx);
                    });
                settings.reset_terminal_external_draft(cx);
            });
        });
        cx.run_until_parked();

        cx.update(|_window, app| {
            let root_preferences = main_view.read(app).terminal_preferences_for_test().clone();
            assert_eq!(
                root_preferences.external_terminal_mode,
                ExternalTerminalMode::CustomProgram
            );
            assert_eq!(root_preferences.external_terminal_program, "wezterm");
            assert_eq!(
                root_preferences.external_terminal_args,
                vec![
                    "start".to_string(),
                    "--cwd".to_string(),
                    "{cwd}".to_string(),
                ]
            );

            let (
                external_program,
                external_args,
                external_program_input,
                external_args_input,
                status,
            ) = settings_window
                .read_with(app, |settings, cx| {
                    (
                        settings
                            .terminal_preferences
                            .external_terminal_program
                            .clone(),
                        settings.terminal_preferences.external_terminal_args.clone(),
                        settings
                            .terminal_external_program_input
                            .read_with(cx, |input, _| input.text().to_string()),
                        settings
                            .terminal_external_args_input
                            .read_with(cx, |input, _| input.text().to_string()),
                        settings
                            .terminal_status
                            .as_ref()
                            .map(|status| status.text.to_string()),
                    )
                })
                .expect("settings window should remain readable");

            assert_eq!(external_program, "wezterm");
            assert_eq!(
                external_args,
                vec![
                    "start".to_string(),
                    "--cwd".to_string(),
                    "{cwd}".to_string(),
                ]
            );
            assert_eq!(external_program_input, "wezterm");
            assert_eq!(external_args_input, "start\n--cwd\n{cwd}");
            assert_eq!(status.as_deref(), Some("External terminal draft reset."));
        });
    }

    #[gpui::test]
    fn ui_font_dropdown_wheel_scrolls_inner_list_before_outer_window(
        cx: &mut gpui::TestAppContext,
    ) {
        let _visual_guard = lock_visual_test();
        let (store, events) = AppStore::new(std::sync::Arc::new(TestBackend));
        let (_main_view, cx) =
            cx.add_window_view(|window, cx| GitCometView::new(store, events, None, window, cx));

        cx.update(|window, app| {
            let _ = window.draw(app);
            open_settings_window(app);
        });
        cx.run_until_parked();

        let settings_window = cx.update(|_window, app| {
            app.windows()
                .into_iter()
                .find_map(|window| window.downcast::<SettingsWindowView>())
                .expect("settings window should be open")
        });

        let synthetic_fonts: Arc<[String]> = (0..200)
            .map(|ix| format!("Test UI Font {ix:03}"))
            .collect::<Vec<_>>()
            .into();

        cx.update(|_window, app| {
            let _ = settings_window.update(app, |settings, _window, cx| {
                settings.ui_font_options = synthetic_fonts.clone();
                settings.ui_font_family = synthetic_fonts[0].clone();
                settings.expanded_section = Some(SettingsSection::UiFont);
                settings.settings_window_scroll = ScrollHandle::default();
                settings.ui_font_scroll = UniformListScrollHandle::default();
                cx.notify();
            });
        });

        let mut settings_cx = gpui::VisualTestContext::from_window(*settings_window.deref(), cx);
        settings_cx.run_until_parked();
        settings_cx.simulate_resize(size(px(SETTINGS_WINDOW_DEFAULT_WIDTH_PX), px(460.0)));
        settings_cx.run_until_parked();
        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });

        let list_bounds = settings_cx
            .debug_bounds("settings_window_ui_font_list_container")
            .expect("expected UI font list bounds");

        let (outer_before, inner_before, outer_max, inner_max) = settings_window
            .update(&mut settings_cx, |settings, _window, _cx| {
                (
                    absolute_scroll_y(&settings.settings_window_scroll),
                    uniform_list_vertical_scroll_metrics(&settings.ui_font_scroll).1,
                    settings.settings_window_scroll.max_offset().y.max(px(0.0)),
                    uniform_list_vertical_scroll_metrics(&settings.ui_font_scroll).2,
                )
            })
            .expect("settings window should remain readable");
        assert!(
            outer_max > px(0.0),
            "expected the settings page to be scrollable during the test"
        );
        assert!(
            inner_max > px(0.0),
            "expected the UI font list to be scrollable during the test"
        );

        settings_cx.simulate_mouse_move(list_bounds.center(), None, Modifiers::default());
        settings_cx.simulate_event(ScrollWheelEvent {
            position: list_bounds.center(),
            delta: ScrollDelta::Pixels(point(px(-120.0), px(0.0))),
            ..Default::default()
        });
        settings_cx.run_until_parked();

        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        let (outer_after_horizontal_scroll, inner_after_horizontal_scroll) = settings_window
            .update(&mut settings_cx, |settings, _window, _cx| {
                (
                    absolute_scroll_y(&settings.settings_window_scroll),
                    uniform_list_vertical_scroll_metrics(&settings.ui_font_scroll).1,
                )
            })
            .expect("settings window should remain readable");

        assert!(
            (inner_after_horizontal_scroll - inner_before).abs() <= px(0.5),
            "expected horizontal-only wheel scroll not to move the UI font list vertically"
        );
        assert!(
            (outer_after_horizontal_scroll - outer_before).abs() <= px(0.5),
            "expected horizontal-only wheel scroll not to move the outer settings page vertically"
        );

        settings_cx.simulate_mouse_move(list_bounds.center(), None, Modifiers::default());
        settings_cx.simulate_event(ScrollWheelEvent {
            position: list_bounds.center(),
            delta: ScrollDelta::Pixels(point(px(0.0), px(-120.0))),
            ..Default::default()
        });
        settings_cx.run_until_parked();

        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        let (outer_after_inner_scroll, inner_after_inner_scroll) = settings_window
            .update(&mut settings_cx, |settings, _window, _cx| {
                (
                    absolute_scroll_y(&settings.settings_window_scroll),
                    uniform_list_vertical_scroll_metrics(&settings.ui_font_scroll).1,
                )
            })
            .expect("settings window should remain readable");

        assert!(
            inner_after_inner_scroll > inner_before + px(0.5),
            "expected the UI font list to consume wheel scroll first"
        );
        assert!(
            (outer_after_inner_scroll - outer_before).abs() <= px(0.5),
            "expected the outer settings page to stay still while the UI font list can still scroll"
        );

        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        let _ = settings_window.update(&mut settings_cx, |settings, _window, cx| {
            let (raw_offset, _scroll_offset, max_offset) =
                uniform_list_vertical_scroll_metrics(&settings.ui_font_scroll);
            let current_x = settings.ui_font_scroll.0.borrow().base_handle.offset().x;
            let target_y = if raw_offset > px(0.0) {
                max_offset
            } else {
                -max_offset
            };
            settings
                .ui_font_scroll
                .0
                .borrow()
                .base_handle
                .set_offset(point(current_x, target_y));
            cx.notify();
        });
        settings_cx.run_until_parked();

        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        let outer_before_boundary_handoff = settings_window
            .update(&mut settings_cx, |settings, _window, _cx| {
                absolute_scroll_y(&settings.settings_window_scroll)
            })
            .expect("settings window should remain readable");

        settings_cx.simulate_mouse_move(list_bounds.center(), None, Modifiers::default());
        settings_cx.simulate_event(ScrollWheelEvent {
            position: list_bounds.center(),
            delta: ScrollDelta::Pixels(point(px(0.0), px(-120.0))),
            ..Default::default()
        });
        settings_cx.run_until_parked();

        settings_cx.update(|window, app| {
            let _ = window.draw(app);
        });
        let outer_after_boundary_handoff = settings_window
            .update(&mut settings_cx, |settings, _window, _cx| {
                absolute_scroll_y(&settings.settings_window_scroll)
            })
            .expect("settings window should remain readable");

        assert!(
            outer_after_boundary_handoff > outer_before_boundary_handoff + px(0.5),
            "expected wheel scrolling to bubble to the outer settings page once the UI font list reaches its boundary"
        );
    }
}
