Skip to main content

par_term_settings_ui/
lib.rs

1//! Settings UI for par-term terminal emulator.
2//!
3//! This crate provides an egui-based settings interface for configuring
4//! terminal options at runtime. It is designed to be decoupled from the
5//! main terminal implementation through trait interfaces.
6//!
7//! # ARC-010 — Crate Size Note
8//!
9//! This crate is ~28,644 lines across ~100 files, making it the largest sub-crate
10//! and a compile-time bottleneck. Planned decomposition (deferred — multi-sprint effort):
11//!
12//!   1. Extract shader editor sub-crate (~5K lines): `par-term-shader-ui`
13//!      - shader_editor, shader_dialogs, shader_utils, cursor_shader_editor
14//!      - background_tab/shader_settings, background_tab/shader_channel_settings
15//!
16//!   2. Extract automation UI sub-crate (~3K lines): `par-term-automation-ui`
17//!      - automation_tab/*, scripts_tab/*
18//!
19//! Tracking: Issue ARC-010 in AUDIT.md.
20
21use par_term_config::{Config, Profile, ProfileId};
22
23/// Callback type for detecting modified bundled shaders.
24pub type ShaderDetectModifiedFn = fn() -> Result<Vec<String>, String>;
25
26/// Callback type for running shader lint/readability analysis from Settings.
27pub type ShaderLintFn = fn(&std::path::Path, Option<f32>, Option<f32>) -> Result<String, String>;
28
29// Trait interfaces for decoupling from main crate
30mod traits;
31pub use traits::*;
32
33// Window arrangements (pure data types)
34pub mod arrangements;
35pub use arrangements::{
36    ArrangementId, ArrangementManager, MonitorInfo, TabSnapshot, WindowArrangement, WindowSnapshot,
37};
38
39// Shell detection utility
40pub mod shell_detection;
41
42// Profile management modal UI
43pub mod profile_modal_ui;
44pub use profile_modal_ui::{ProfileModalAction, ProfileModalUI};
45
46// Nerd Font integration (font loading + icon presets)
47pub mod nerd_font;
48
49// Reorganized settings tabs
50pub mod actions_tab;
51pub mod advanced_tab;
52pub mod ai_inspector_tab;
53pub mod appearance_tab;
54pub mod automation_tab;
55pub mod effects_tab;
56pub mod input_tab;
57pub mod integrations_tab;
58pub mod notifications_tab;
59pub mod profiles_tab;
60pub mod quick_settings;
61pub mod scripts_tab;
62pub mod search_keywords;
63pub mod section;
64pub mod sidebar;
65pub mod snippets_tab;
66pub mod ssh_tab;
67pub mod status_bar_tab;
68pub mod terminal_tab;
69pub mod window_tab;
70
71// Internal implementation modules (no longer exposed as standalone tabs)
72mod arrangements_tab;
73pub use arrangements_tab::ArrangementsTabState;
74mod badge_tab;
75mod progress_bar_tab;
76
77// Background tab is still needed by effects_tab for delegation
78pub mod background_tab;
79
80// Shader editor components (used by background_tab)
81mod cursor_shader_editor;
82mod shader_dialogs;
83mod shader_editor;
84mod shader_utils;
85
86// SettingsUI struct and impl
87mod settings_ui;
88pub use settings_ui::SettingsUI;
89
90pub use sidebar::SettingsTab;
91
92// Re-export types that settings consumers need
93pub use par_term_config::{
94    self as config, BackgroundImageMode as BgMode, CursorShaderMetadataCache as CursorShaderCache,
95    ProfileManager, ProfileSource, ShaderMetadataCache as ShaderCache, Theme, VsyncMode,
96};
97
98/// Result of shader editor actions
99#[derive(Debug, Clone)]
100pub struct ShaderEditorResult {
101    /// New shader source code to compile and apply
102    pub source: String,
103}
104
105/// Result of cursor shader editor actions
106#[derive(Debug, Clone)]
107pub struct CursorShaderEditorResult {
108    /// New cursor shader source code to compile and apply
109    pub source: String,
110}
111
112/// Result of processing a settings window event.
113///
114/// This enum bridges the settings UI crate with the main application.
115/// The main application processes these actions after events are handled
116/// by the settings window.
117#[derive(Debug, Clone)]
118pub enum SettingsWindowAction {
119    /// No action needed
120    None,
121    /// Close the settings window
122    Close,
123    /// Apply config changes to terminal windows (live update)
124    ApplyConfig(Config),
125    /// Save config to disk
126    SaveConfig(Config),
127    /// Apply background shader from editor
128    ApplyShader(ShaderEditorResult),
129    /// Apply cursor shader from editor
130    ApplyCursorShader(CursorShaderEditorResult),
131    /// Send a test notification to verify permissions
132    TestNotification,
133    /// Save profiles from inline editor to all windows
134    SaveProfiles(Vec<Profile>),
135    /// Open a profile in the focused terminal window
136    OpenProfile(ProfileId),
137    /// Start a coprocess by config index on the active tab
138    StartCoprocess(usize),
139    /// Stop a coprocess by config index on the active tab
140    StopCoprocess(usize),
141    /// Start a script by config index on the active tab
142    StartScript(usize),
143    /// Stop a script by config index on the active tab
144    StopScript(usize),
145    /// Open the debug log file in the system's default editor/viewer
146    OpenLogFile,
147    /// Save the current window layout as an arrangement
148    SaveArrangement(String),
149    /// Restore a saved window arrangement
150    RestoreArrangement(ArrangementId),
151    /// Delete a saved window arrangement
152    DeleteArrangement(ArrangementId),
153    /// Rename a saved window arrangement
154    RenameArrangement(ArrangementId, String),
155    /// Move a saved window arrangement one position up in the list
156    MoveArrangementUp(ArrangementId),
157    /// Move a saved window arrangement one position down in the list
158    MoveArrangementDown(ArrangementId),
159    /// Replace a saved window arrangement with the current window layout
160    ReplaceArrangement(ArrangementId),
161    /// User requested an immediate update check
162    ForceUpdateCheck,
163    /// User requested to install the available update
164    InstallUpdate(String),
165    /// Flash pane indices on the terminal window
166    IdentifyPanes,
167    /// Install shell integration for the detected shell
168    InstallShellIntegration,
169    /// Uninstall shell integration from all shells
170    UninstallShellIntegration,
171    /// Assistant prompt library changed; terminal windows should reload prompt menus
172    AssistantPromptsChanged,
173}
174
175/// Lightweight information about a saved arrangement (used by trait interface).
176#[derive(Debug, Clone)]
177pub struct ArrangementInfo {
178    /// Unique identifier
179    pub id: ArrangementId,
180    /// Display name
181    pub name: String,
182    /// Number of windows in the arrangement
183    pub window_count: usize,
184}
185
186/// Result of a shader installation operation.
187#[derive(Debug, Clone)]
188pub struct ShaderInstallResult {
189    /// Number of shaders installed
190    pub installed: usize,
191    /// Number of shaders skipped (unchanged)
192    pub skipped: usize,
193    /// Number of obsolete shaders removed
194    pub removed: usize,
195}
196
197/// Result of a shader uninstallation operation.
198#[derive(Debug, Clone)]
199pub struct ShaderUninstallResult {
200    /// Number of shaders removed
201    pub removed: usize,
202    /// Number of modified shaders kept
203    pub kept: usize,
204    /// Whether confirmation is needed for modified files
205    pub needs_confirmation: bool,
206}
207
208/// Result of shell integration installation.
209#[derive(Debug, Clone)]
210pub struct ShellIntegrationInstallResult {
211    /// Shell type that was configured
212    pub shell: String,
213    /// Path to the integration script
214    pub script_path: String,
215    /// RC file that was modified
216    pub rc_file: String,
217    /// Whether a shell restart is needed
218    pub needs_restart: bool,
219}
220
221/// Result of shell integration uninstallation.
222#[derive(Debug, Clone)]
223pub struct ShellIntegrationUninstallResult {
224    /// Whether rc files were cleaned
225    pub cleaned: bool,
226    /// Whether manual intervention is needed
227    pub needs_manual: bool,
228    /// Number of integration scripts removed
229    pub scripts_removed: usize,
230}
231
232/// Result of a self-update operation.
233#[derive(Debug, Clone)]
234pub struct UpdateResult {
235    /// Old version before the update
236    pub old_version: String,
237    /// New version after the update
238    pub new_version: String,
239    /// Path where the binary was installed
240    pub install_path: String,
241    /// Whether a restart is needed
242    pub needs_restart: bool,
243}
244
245/// Installation type detected for the running binary.
246#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247pub enum InstallationType {
248    /// Installed via Homebrew
249    Homebrew,
250    /// Installed via `cargo install`
251    CargoInstall,
252    /// Running from a macOS .app bundle
253    MacOSBundle,
254    /// Standalone binary
255    StandaloneBinary,
256}
257
258/// Result of an update check.
259#[derive(Debug, Clone)]
260pub enum UpdateCheckResult {
261    /// No update available, up to date
262    UpToDate,
263    /// An update is available
264    UpdateAvailable(UpdateCheckInfo),
265    /// Update checking is disabled
266    Disabled,
267    /// Check was skipped (cooldown not elapsed)
268    Skipped,
269    /// Error occurred during check
270    Error(String),
271}
272
273/// Information about an available update.
274#[derive(Debug, Clone)]
275pub struct UpdateCheckInfo {
276    /// Version string (e.g., "0.16.0")
277    pub version: String,
278    /// Release notes/changelog
279    pub release_notes: Option<String>,
280    /// URL to release page
281    pub release_url: String,
282    /// When the release was published
283    pub published_at: Option<String>,
284}
285
286/// Format a timestamp string for display in the UI.
287pub fn format_timestamp(timestamp: &str) -> String {
288    match chrono::DateTime::parse_from_rfc3339(timestamp) {
289        Ok(dt) => dt.format("%Y-%m-%d %H:%M").to_string(),
290        Err(_) => timestamp.to_string(),
291    }
292}
293
294/// Get the path to the debug log file.
295///
296/// Must stay in sync with the writer in the root crate (`src/debug.rs`), which
297/// resolves the same `std::env::temp_dir()` location — `$TMPDIR` on macOS
298/// (a `/var/folders/…` path), `/tmp` on Linux, `%TEMP%` on Windows.
299pub fn log_path() -> std::path::PathBuf {
300    std::env::temp_dir().join("par_term_debug.log")
301}