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 plugin git operation (add / update fetch / apply / remove),
187/// produced on the background thread and polled by the Plugins section.
188#[derive(Debug, Clone)]
189pub enum PluginGitOutcome {
190    /// Operation finished; the line is shown in the Plugins section.
191    Done(String),
192    /// A fetched update awaiting review: the section shows the diff and an
193    /// Apply button before anything fast-forwards.
194    UpdateReady {
195        /// Plugin id the preview belongs to.
196        id: String,
197        /// Fetched head, current head, and the diff between them.
198        preview: par_term_scripting::plugin_git::UpdatePreview,
199    },
200}
201
202/// Result of a shader installation operation.
203#[derive(Debug, Clone)]
204pub struct ShaderInstallResult {
205    /// Number of shaders installed
206    pub installed: usize,
207    /// Number of shaders skipped (unchanged)
208    pub skipped: usize,
209    /// Number of obsolete shaders removed
210    pub removed: usize,
211}
212
213/// Result of a shader uninstallation operation.
214#[derive(Debug, Clone)]
215pub struct ShaderUninstallResult {
216    /// Number of shaders removed
217    pub removed: usize,
218    /// Number of modified shaders kept
219    pub kept: usize,
220    /// Whether confirmation is needed for modified files
221    pub needs_confirmation: bool,
222}
223
224/// Result of shell integration installation.
225#[derive(Debug, Clone)]
226pub struct ShellIntegrationInstallResult {
227    /// Shell type that was configured
228    pub shell: String,
229    /// Path to the integration script
230    pub script_path: String,
231    /// RC file that was modified
232    pub rc_file: String,
233    /// Whether a shell restart is needed
234    pub needs_restart: bool,
235}
236
237/// Result of shell integration uninstallation.
238#[derive(Debug, Clone)]
239pub struct ShellIntegrationUninstallResult {
240    /// Whether rc files were cleaned
241    pub cleaned: bool,
242    /// Whether manual intervention is needed
243    pub needs_manual: bool,
244    /// Number of integration scripts removed
245    pub scripts_removed: usize,
246}
247
248/// Result of a self-update operation.
249#[derive(Debug, Clone)]
250pub struct UpdateResult {
251    /// Old version before the update
252    pub old_version: String,
253    /// New version after the update
254    pub new_version: String,
255    /// Path where the binary was installed
256    pub install_path: String,
257    /// Whether a restart is needed
258    pub needs_restart: bool,
259}
260
261/// Installation type detected for the running binary.
262#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub enum InstallationType {
264    /// Installed via Homebrew
265    Homebrew,
266    /// Installed via `cargo install`
267    CargoInstall,
268    /// Running from a macOS .app bundle
269    MacOSBundle,
270    /// Standalone binary
271    StandaloneBinary,
272}
273
274/// Result of an update check.
275#[derive(Debug, Clone)]
276pub enum UpdateCheckResult {
277    /// No update available, up to date
278    UpToDate,
279    /// An update is available
280    UpdateAvailable(UpdateCheckInfo),
281    /// Update checking is disabled
282    Disabled,
283    /// Check was skipped (cooldown not elapsed)
284    Skipped,
285    /// Error occurred during check
286    Error(String),
287}
288
289/// Information about an available update.
290#[derive(Debug, Clone)]
291pub struct UpdateCheckInfo {
292    /// Version string (e.g., "0.16.0")
293    pub version: String,
294    /// Release notes/changelog
295    pub release_notes: Option<String>,
296    /// URL to release page
297    pub release_url: String,
298    /// When the release was published
299    pub published_at: Option<String>,
300}
301
302/// Format a timestamp string for display in the UI.
303pub fn format_timestamp(timestamp: &str) -> String {
304    match chrono::DateTime::parse_from_rfc3339(timestamp) {
305        Ok(dt) => dt.format("%Y-%m-%d %H:%M").to_string(),
306        Err(_) => timestamp.to_string(),
307    }
308}
309
310/// Get the path to the debug log file.
311///
312/// Must stay in sync with the writer in the root crate (`src/debug.rs`), which
313/// resolves the same `std::env::temp_dir()` location — `$TMPDIR` on macOS
314/// (a `/var/folders/…` path), `/tmp` on Linux, `%TEMP%` on Windows.
315pub fn log_path() -> std::path::PathBuf {
316    std::env::temp_dir().join("par_term_debug.log")
317}