Skip to main content

par_term_config/
defaults.rs

1//! Default value functions for configuration.
2
3pub fn cols() -> usize {
4    80
5}
6
7pub fn rows() -> usize {
8    24
9}
10
11pub fn font_size() -> f32 {
12    12.0
13}
14
15pub fn font_family() -> String {
16    "JetBrains Mono".to_string()
17}
18
19pub fn line_spacing() -> f32 {
20    1.0 // Default line height multiplier
21}
22
23pub fn char_spacing() -> f32 {
24    1.0 // Default character width multiplier
25}
26
27pub fn text_shaping() -> bool {
28    true // Enabled by default - OpenType features now properly configured via Feature::from_str()
29}
30
31pub fn minimum_contrast() -> f32 {
32    1.0 // Disabled by default (1.0 = no adjustment)
33}
34
35pub fn scrollback() -> usize {
36    10000
37}
38
39pub fn window_title() -> String {
40    "par-term".to_string()
41}
42
43pub fn theme() -> String {
44    "dark-background".to_string()
45}
46
47pub fn light_theme() -> String {
48    "light-background".to_string()
49}
50
51pub fn dark_theme() -> String {
52    "dark-background".to_string()
53}
54
55pub fn screenshot_format() -> String {
56    "png".to_string()
57}
58
59pub fn max_fps() -> u32 {
60    60
61}
62
63pub fn window_padding() -> f32 {
64    0.0
65}
66
67pub fn login_shell() -> bool {
68    true
69}
70
71pub fn initial_text() -> String {
72    String::new()
73}
74
75pub fn initial_text_delay_ms() -> u64 {
76    100
77}
78
79pub fn initial_text_send_newline() -> bool {
80    true
81}
82
83pub fn scrollbar_position() -> String {
84    "right".to_string()
85}
86
87pub fn scrollbar_width() -> f32 {
88    15.0
89}
90
91pub fn scrollbar_thumb_color() -> [f32; 4] {
92    [0.4, 0.4, 0.4, 0.95] // Medium gray, nearly opaque
93}
94
95pub fn scrollbar_track_color() -> [f32; 4] {
96    [0.15, 0.15, 0.15, 0.6] // Dark gray, semi-transparent
97}
98
99pub fn command_separator_thickness() -> f32 {
100    1.0 // 1 pixel line
101}
102
103pub fn command_separator_opacity() -> f32 {
104    0.4 // Subtle by default
105}
106
107pub fn command_separator_color() -> [u8; 3] {
108    [128, 128, 128] // Medium gray
109}
110
111pub fn link_highlight_color() -> [u8; 3] {
112    [79, 195, 247] // Bright cyan (#4FC3F7)
113}
114
115pub fn paste_delay_ms() -> u64 {
116    0 // No delay by default
117}
118
119pub fn clipboard_max_sync_events() -> usize {
120    64 // Aligned with sister project
121}
122
123pub fn clipboard_max_event_bytes() -> usize {
124    2048 // Aligned with sister project
125}
126
127pub fn activity_threshold() -> u64 {
128    10 // Aligned with sister project (10 seconds)
129}
130
131pub fn anti_idle_seconds() -> u64 {
132    60 // Default keep-alive interval: 60 seconds
133}
134
135pub fn anti_idle_code() -> u8 {
136    0 // Default keep-alive code: NUL (0x00)
137}
138
139pub fn silence_threshold() -> u64 {
140    300 // 5 minutes
141}
142
143pub fn notification_max_buffer() -> usize {
144    64 // Aligned with sister project
145}
146
147pub fn scroll_speed() -> f32 {
148    3.0 // Lines per scroll tick
149}
150
151pub fn double_click_threshold() -> u64 {
152    500 // 500 milliseconds
153}
154
155pub fn triple_click_threshold() -> u64 {
156    500 // 500 milliseconds (same as double-click)
157}
158
159pub fn cursor_blink_interval() -> u64 {
160    500 // 500 milliseconds (blink twice per second)
161}
162
163pub fn cursor_color() -> [u8; 3] {
164    [255, 255, 255] // White cursor
165}
166
167pub fn scrollbar_autohide_delay() -> u64 {
168    0 // 0 = never auto-hide (always visible when scrollback exists)
169}
170
171pub fn window_opacity() -> f32 {
172    1.0 // Fully opaque by default
173}
174
175pub fn background_image_opacity() -> f32 {
176    1.0 // Fully opaque by default
177}
178
179pub fn pane_background_darken() -> f32 {
180    0.0 // No darkening by default
181}
182
183pub fn background_color() -> [u8; 3] {
184    [30, 30, 30] // Dark gray
185}
186
187pub fn bool_false() -> bool {
188    false
189}
190
191pub fn bool_true() -> bool {
192    true
193}
194
195pub fn mdns_timeout() -> u32 {
196    3
197}
198
199pub fn text_opacity() -> f32 {
200    1.0 // Fully opaque text by default
201}
202
203pub fn custom_shader_speed() -> f32 {
204    1.0 // Normal animation speed
205}
206
207pub fn custom_shader_brightness() -> f32 {
208    0.15 // 15% brightness by default for better text readability
209}
210
211pub fn cursor_shader_color() -> [u8; 3] {
212    [255, 255, 255] // White cursor for shader effects
213}
214
215pub fn cursor_trail_duration() -> f32 {
216    0.5 // 500ms trail duration
217}
218
219pub fn cursor_glow_radius() -> f32 {
220    80.0 // 80 pixel glow radius
221}
222
223pub fn cursor_glow_intensity() -> f32 {
224    0.3 // 30% glow intensity
225}
226
227pub fn cursor_shader_disable_in_alt_screen() -> bool {
228    true // Preserve current behavior: disable cursor shader in alt screen by default
229}
230
231pub fn bell_sound() -> u8 {
232    50 // Default to 50% volume
233}
234
235pub fn tab_bar_height() -> f32 {
236    28.0 // Default tab bar height in pixels
237}
238
239pub fn tab_bar_width() -> f32 {
240    160.0 // Default tab bar width in pixels (for left position)
241}
242
243pub fn zero() -> usize {
244    0
245}
246
247pub fn unfocused_fps() -> u32 {
248    30 // Reduced FPS when window is not focused
249}
250
251pub fn inactive_tab_fps() -> u32 {
252    2 // Very low FPS for inactive (non-visible) tabs - just enough for activity detection
253}
254
255/// Default for reduce_flicker option
256pub fn reduce_flicker() -> bool {
257    true
258}
259
260/// Default delay in milliseconds for reduce_flicker
261pub fn reduce_flicker_delay_ms() -> u32 {
262    16 // ~1 frame at 60fps
263}
264
265/// Default for maximize_throughput option
266pub fn maximize_throughput() -> bool {
267    false // Off by default
268}
269
270/// Default render interval in milliseconds when maximize_throughput is enabled
271pub fn throughput_render_interval_ms() -> u32 {
272    100 // 100ms default (~10 fps during bulk output)
273}
274
275pub fn shader_hot_reload_delay() -> u64 {
276    100 // Debounce delay in milliseconds
277}
278
279// Tab bar color defaults
280pub fn tab_bar_background() -> [u8; 3] {
281    [40, 40, 40] // Dark gray background
282}
283
284pub fn tab_active_background() -> [u8; 3] {
285    [60, 60, 60] // Slightly lighter for active tab
286}
287
288pub fn tab_inactive_background() -> [u8; 3] {
289    [40, 40, 40] // Same as bar background
290}
291
292pub fn tab_hover_background() -> [u8; 3] {
293    [50, 50, 50] // Between inactive and active
294}
295
296pub fn tab_active_text() -> [u8; 3] {
297    [255, 255, 255] // White text for active tab
298}
299
300pub fn tab_inactive_text() -> [u8; 3] {
301    [180, 180, 180] // Gray text for inactive tabs
302}
303
304pub fn tab_active_indicator() -> [u8; 3] {
305    [100, 150, 255] // Blue underline for active tab
306}
307
308pub fn tab_activity_indicator() -> [u8; 3] {
309    [100, 180, 255] // Light blue activity dot
310}
311
312pub fn tab_bell_indicator() -> [u8; 3] {
313    [255, 200, 100] // Orange/yellow bell icon
314}
315
316pub fn tab_close_button() -> [u8; 3] {
317    [150, 150, 150] // Gray close button
318}
319
320pub fn tab_close_button_hover() -> [u8; 3] {
321    [255, 100, 100] // Red on hover
322}
323
324pub fn cubemap_enabled() -> bool {
325    true // Cubemap sampling enabled by default when a path is configured
326}
327
328pub fn inactive_tab_opacity() -> f32 {
329    0.6 // Default opacity for inactive tabs (60%)
330}
331
332pub fn tab_min_width() -> f32 {
333    120.0 // Minimum tab width in pixels before scrolling kicks in
334}
335
336pub fn tab_stretch_to_fill() -> bool {
337    true // Tabs stretch to share available width by default
338}
339
340pub fn tab_html_titles() -> bool {
341    false // Render tab titles as plain text unless explicitly enabled
342}
343
344pub fn tab_border_color() -> [u8; 3] {
345    [80, 80, 80] // Subtle gray border between tabs
346}
347
348pub fn tab_border_width() -> f32 {
349    1.0 // 1 pixel border
350}
351
352pub fn blur_radius() -> u32 {
353    8 // Default blur radius in points (macOS only)
354}
355
356pub fn light_tab_style() -> crate::types::TabStyle {
357    crate::types::TabStyle::Light
358}
359
360pub fn dark_tab_style() -> crate::types::TabStyle {
361    crate::types::TabStyle::Dark
362}
363
364pub fn use_background_as_channel0() -> bool {
365    false // By default, use configured channel0 texture, not background image
366}
367
368pub fn keybindings() -> Vec<crate::types::KeyBinding> {
369    // macOS: Cmd+key is safe because Cmd is separate from Ctrl (terminal control codes).
370    // Windows/Linux: Ctrl+key conflicts with terminal control codes (Ctrl+C=SIGINT, Ctrl+D=EOF, etc.)
371    // so we use Ctrl+Shift+key following standard terminal emulator conventions
372    // (WezTerm, Kitty, Alacritty, GNOME Terminal, Windows Terminal).
373    #[cfg(target_os = "macos")]
374    let bindings = vec![
375        crate::types::KeyBinding {
376            key: "CmdOrCtrl+Shift+B".to_string(),
377            action: "toggle_background_shader".to_string(),
378        },
379        crate::types::KeyBinding {
380            key: "CmdOrCtrl+Shift+U".to_string(),
381            action: "toggle_cursor_shader".to_string(),
382        },
383        crate::types::KeyBinding {
384            key: "CmdOrCtrl+Shift+V".to_string(),
385            action: "paste_special".to_string(),
386        },
387        crate::types::KeyBinding {
388            key: "CmdOrCtrl+Shift+R".to_string(),
389            action: "toggle_session_logging".to_string(),
390        },
391        // Split pane shortcuts (Cmd+D / Cmd+Shift+D matches iTerm2)
392        crate::types::KeyBinding {
393            key: "CmdOrCtrl+D".to_string(),
394            action: "split_horizontal".to_string(),
395        },
396        crate::types::KeyBinding {
397            key: "CmdOrCtrl+Shift+D".to_string(),
398            action: "split_vertical".to_string(),
399        },
400        crate::types::KeyBinding {
401            key: "CmdOrCtrl+Shift+W".to_string(),
402            action: "close_pane".to_string(),
403        },
404        // Pane navigation shortcuts
405        crate::types::KeyBinding {
406            key: "CmdOrCtrl+Alt+Left".to_string(),
407            action: "navigate_pane_left".to_string(),
408        },
409        crate::types::KeyBinding {
410            key: "CmdOrCtrl+Alt+Right".to_string(),
411            action: "navigate_pane_right".to_string(),
412        },
413        crate::types::KeyBinding {
414            key: "CmdOrCtrl+Alt+Up".to_string(),
415            action: "navigate_pane_up".to_string(),
416        },
417        crate::types::KeyBinding {
418            key: "CmdOrCtrl+Alt+Down".to_string(),
419            action: "navigate_pane_down".to_string(),
420        },
421        // Pane resize shortcuts
422        crate::types::KeyBinding {
423            key: "CmdOrCtrl+Alt+Shift+Left".to_string(),
424            action: "resize_pane_left".to_string(),
425        },
426        crate::types::KeyBinding {
427            key: "CmdOrCtrl+Alt+Shift+Right".to_string(),
428            action: "resize_pane_right".to_string(),
429        },
430        crate::types::KeyBinding {
431            key: "CmdOrCtrl+Alt+Shift+Up".to_string(),
432            action: "resize_pane_up".to_string(),
433        },
434        crate::types::KeyBinding {
435            key: "CmdOrCtrl+Alt+Shift+Down".to_string(),
436            action: "resize_pane_down".to_string(),
437        },
438        // Broadcast input mode
439        crate::types::KeyBinding {
440            key: "CmdOrCtrl+Alt+I".to_string(),
441            action: "toggle_broadcast_input".to_string(),
442        },
443        // Throughput mode toggle
444        crate::types::KeyBinding {
445            key: "CmdOrCtrl+Shift+T".to_string(),
446            action: "toggle_throughput_mode".to_string(),
447        },
448        // tmux session picker
449        crate::types::KeyBinding {
450            key: "CmdOrCtrl+Alt+T".to_string(),
451            action: "toggle_tmux_session_picker".to_string(),
452        },
453        // Copy mode (vi-style keyboard-driven selection) - matches iTerm2
454        crate::types::KeyBinding {
455            key: "CmdOrCtrl+Shift+C".to_string(),
456            action: "toggle_copy_mode".to_string(),
457        },
458        // Command history fuzzy search
459        crate::types::KeyBinding {
460            key: "CmdOrCtrl+R".to_string(),
461            action: "toggle_command_history".to_string(),
462        },
463        // Reopen recently closed tab
464        crate::types::KeyBinding {
465            key: "CmdOrCtrl+Z".to_string(),
466            action: "reopen_closed_tab".to_string(),
467        },
468        // SSH Quick Connect
469        crate::types::KeyBinding {
470            key: "CmdOrCtrl+Shift+S".to_string(),
471            action: "ssh_quick_connect".to_string(),
472        },
473    ];
474
475    #[cfg(not(target_os = "macos"))]
476    let bindings = vec![
477        crate::types::KeyBinding {
478            key: "Ctrl+Shift+B".to_string(),
479            action: "toggle_background_shader".to_string(),
480        },
481        crate::types::KeyBinding {
482            key: "Ctrl+Shift+U".to_string(),
483            action: "toggle_cursor_shader".to_string(),
484        },
485        // Ctrl+Shift+V is standard paste on Linux terminals, so use Ctrl+Alt+V for paste special
486        crate::types::KeyBinding {
487            key: "Ctrl+Alt+V".to_string(),
488            action: "paste_special".to_string(),
489        },
490        crate::types::KeyBinding {
491            key: "Ctrl+Shift+R".to_string(),
492            action: "toggle_session_logging".to_string(),
493        },
494        // Split pane shortcuts
495        // Ctrl+D is EOF/logout - use Ctrl+Shift+D for horizontal split
496        crate::types::KeyBinding {
497            key: "Ctrl+Shift+D".to_string(),
498            action: "split_horizontal".to_string(),
499        },
500        // Ctrl+Shift+E for vertical split (Tilix/Terminator convention)
501        crate::types::KeyBinding {
502            key: "Ctrl+Shift+E".to_string(),
503            action: "split_vertical".to_string(),
504        },
505        // Ctrl+Shift+W is standard close tab - use Ctrl+Shift+X for close pane
506        crate::types::KeyBinding {
507            key: "Ctrl+Shift+X".to_string(),
508            action: "close_pane".to_string(),
509        },
510        // Pane navigation shortcuts
511        crate::types::KeyBinding {
512            key: "Ctrl+Alt+Left".to_string(),
513            action: "navigate_pane_left".to_string(),
514        },
515        crate::types::KeyBinding {
516            key: "Ctrl+Alt+Right".to_string(),
517            action: "navigate_pane_right".to_string(),
518        },
519        crate::types::KeyBinding {
520            key: "Ctrl+Alt+Up".to_string(),
521            action: "navigate_pane_up".to_string(),
522        },
523        crate::types::KeyBinding {
524            key: "Ctrl+Alt+Down".to_string(),
525            action: "navigate_pane_down".to_string(),
526        },
527        // Pane resize shortcuts
528        crate::types::KeyBinding {
529            key: "Ctrl+Alt+Shift+Left".to_string(),
530            action: "resize_pane_left".to_string(),
531        },
532        crate::types::KeyBinding {
533            key: "Ctrl+Alt+Shift+Right".to_string(),
534            action: "resize_pane_right".to_string(),
535        },
536        crate::types::KeyBinding {
537            key: "Ctrl+Alt+Shift+Up".to_string(),
538            action: "resize_pane_up".to_string(),
539        },
540        crate::types::KeyBinding {
541            key: "Ctrl+Alt+Shift+Down".to_string(),
542            action: "resize_pane_down".to_string(),
543        },
544        // Broadcast input mode
545        crate::types::KeyBinding {
546            key: "Ctrl+Alt+I".to_string(),
547            action: "toggle_broadcast_input".to_string(),
548        },
549        // Ctrl+Shift+T is standard new tab - use Ctrl+Shift+M for throughput mode
550        crate::types::KeyBinding {
551            key: "Ctrl+Shift+M".to_string(),
552            action: "toggle_throughput_mode".to_string(),
553        },
554        // tmux session picker
555        crate::types::KeyBinding {
556            key: "Ctrl+Alt+T".to_string(),
557            action: "toggle_tmux_session_picker".to_string(),
558        },
559        // Copy mode (vi-style keyboard-driven selection)
560        // Ctrl+Shift+C is standard copy on Linux, so use Ctrl+Shift+Space
561        crate::types::KeyBinding {
562            key: "Ctrl+Shift+Space".to_string(),
563            action: "toggle_copy_mode".to_string(),
564        },
565        // Command history fuzzy search
566        // Ctrl+R conflicts with terminal reverse search, so use Ctrl+Shift+R
567        // Note: Ctrl+Shift+R is session logging on Linux; users can reassign
568        crate::types::KeyBinding {
569            key: "Ctrl+Alt+R".to_string(),
570            action: "toggle_command_history".to_string(),
571        },
572        // Reopen recently closed tab
573        crate::types::KeyBinding {
574            key: "Ctrl+Shift+Z".to_string(),
575            action: "reopen_closed_tab".to_string(),
576        },
577        // SSH Quick Connect
578        crate::types::KeyBinding {
579            key: "Ctrl+Shift+S".to_string(),
580            action: "ssh_quick_connect".to_string(),
581        },
582    ];
583
584    bindings
585}
586
587// Progress bar defaults
588pub fn progress_bar_height() -> f32 {
589    4.0 // Height in pixels
590}
591
592pub fn progress_bar_normal_color() -> [u8; 3] {
593    [80, 180, 255] // Blue for normal progress
594}
595
596pub fn progress_bar_warning_color() -> [u8; 3] {
597    [255, 200, 50] // Yellow for warning
598}
599
600pub fn progress_bar_error_color() -> [u8; 3] {
601    [255, 80, 80] // Red for error
602}
603
604pub fn progress_bar_indeterminate_color() -> [u8; 3] {
605    [150, 150, 150] // Gray for indeterminate
606}
607
608pub fn progress_bar_opacity() -> f32 {
609    0.8
610}
611
612// Cursor enhancement defaults
613pub fn cursor_guide_color() -> [u8; 4] {
614    [255, 255, 255, 20] // Subtle white highlight
615}
616
617pub fn cursor_shadow_color() -> [u8; 4] {
618    [0, 0, 0, 128] // Semi-transparent black
619}
620
621pub fn cursor_shadow_offset() -> [f32; 2] {
622    [2.0, 2.0] // 2 pixels offset in both directions
623}
624
625pub fn cursor_shadow_blur() -> f32 {
626    3.0 // 3 pixel blur radius
627}
628
629pub fn cursor_boost() -> f32 {
630    0.0 // Disabled by default
631}
632
633pub fn cursor_boost_color() -> [u8; 3] {
634    [255, 255, 255] // White glow
635}
636
637pub fn update_check_frequency() -> crate::types::UpdateCheckFrequency {
638    crate::types::UpdateCheckFrequency::Daily
639}
640
641// Search defaults
642pub fn search_highlight_color() -> [u8; 4] {
643    [255, 200, 0, 180] // Yellow with some transparency
644}
645
646pub fn search_current_highlight_color() -> [u8; 4] {
647    [255, 100, 0, 220] // Orange, more visible for current match
648}
649
650// Selection defaults
651pub fn word_characters() -> String {
652    // Default characters considered part of a word (in addition to alphanumeric)
653    // Matches iTerm2's default: /-+\~_.
654    "/-+\\~_.".to_string()
655}
656
657pub fn smart_selection_enabled() -> bool {
658    true // Smart selection enabled by default
659}
660
661pub fn answerback_string() -> String {
662    String::new() // Empty/disabled by default for security
663}
664
665/// Default semantic history editor command
666/// Empty string means auto-detect from $EDITOR or use system default
667pub fn semantic_history_editor() -> String {
668    String::new() // Auto-detect by default
669}
670
671/// Default list of jobs/processes to ignore when checking for running jobs
672/// These are common shells and utilities that shouldn't block tab close
673pub fn jobs_to_ignore() -> Vec<String> {
674    vec![
675        // Common shells - these are the parent process, not "jobs"
676        "bash".to_string(),
677        "zsh".to_string(),
678        "fish".to_string(),
679        "sh".to_string(),
680        "dash".to_string(),
681        "ksh".to_string(),
682        "tcsh".to_string(),
683        "csh".to_string(),
684        // Common pagers and viewers
685        "less".to_string(),
686        "more".to_string(),
687        "man".to_string(),
688        // Common utilities that are often left running
689        "cat".to_string(),
690        "sleep".to_string(),
691    ]
692}
693
694pub fn unicode_version() -> par_term_emu_core_rust::UnicodeVersion {
695    par_term_emu_core_rust::UnicodeVersion::Auto
696}
697
698pub fn ambiguous_width() -> par_term_emu_core_rust::AmbiguousWidth {
699    par_term_emu_core_rust::AmbiguousWidth::Narrow
700}
701
702pub fn normalization_form() -> par_term_emu_core_rust::NormalizationForm {
703    par_term_emu_core_rust::NormalizationForm::NFC
704}
705
706// Split pane defaults
707pub fn pane_divider_width() -> Option<f32> {
708    Some(2.0) // 2 pixel divider between panes
709}
710
711pub fn pane_divider_hit_width() -> f32 {
712    8.0 // 8 pixel hit area for drag-to-resize (larger than visual for easier grabbing)
713}
714
715pub fn pane_padding() -> f32 {
716    4.0 // 4 pixel padding inside panes (space between content and border/divider)
717}
718
719pub fn pane_min_size() -> usize {
720    10 // Minimum pane size in cells (columns or rows)
721}
722
723pub fn pane_background_opacity() -> f32 {
724    0.85 // 85% opacity allows background/shader to show through slightly
725}
726
727pub fn pane_divider_color() -> [u8; 3] {
728    [80, 80, 80] // Subtle gray divider
729}
730
731pub fn pane_divider_hover_color() -> [u8; 3] {
732    [120, 150, 200] // Brighter color on hover for resize feedback
733}
734
735pub fn inactive_pane_opacity() -> f32 {
736    0.7 // 70% opacity for inactive panes
737}
738
739pub fn max_panes() -> usize {
740    16 // Maximum panes per tab
741}
742
743pub fn pane_title_height() -> f32 {
744    20.0 // 20 pixel title bar height for panes
745}
746
747pub fn pane_title_color() -> [u8; 3] {
748    [200, 200, 200] // Light gray text for pane titles
749}
750
751pub fn pane_title_bg_color() -> [u8; 3] {
752    [40, 40, 50] // Dark background for pane title bars
753}
754
755pub fn pane_focus_color() -> [u8; 3] {
756    [100, 150, 255] // Blue highlight for focused pane
757}
758
759pub fn pane_focus_width() -> f32 {
760    2.0 // 2 pixel border around focused pane
761}
762
763// tmux integration defaults
764pub fn tmux_path() -> String {
765    // First, try to find tmux in the user's PATH environment variable
766    if let Ok(path_env) = std::env::var("PATH") {
767        let separator = if cfg!(windows) { ';' } else { ':' };
768        let executable = if cfg!(windows) { "tmux.exe" } else { "tmux" };
769
770        for dir in path_env.split(separator) {
771            let candidate = std::path::Path::new(dir).join(executable);
772            if candidate.exists() {
773                return candidate.to_string_lossy().to_string();
774            }
775        }
776    }
777
778    // Fall back to common paths for environments where PATH might be incomplete
779    // (e.g., macOS app bundles launched from Finder)
780    #[cfg(target_os = "macos")]
781    {
782        let macos_paths = [
783            "/opt/homebrew/bin/tmux", // Homebrew on Apple Silicon
784            "/usr/local/bin/tmux",    // Homebrew on Intel / MacPorts
785        ];
786        for path in macos_paths {
787            if std::path::Path::new(path).exists() {
788                return path.to_string();
789            }
790        }
791    }
792
793    #[cfg(target_os = "linux")]
794    {
795        let linux_paths = [
796            "/usr/bin/tmux",       // Most distros
797            "/usr/local/bin/tmux", // Manual install
798            "/snap/bin/tmux",      // Snap package
799        ];
800        for path in linux_paths {
801            if std::path::Path::new(path).exists() {
802                return path.to_string();
803            }
804        }
805    }
806
807    // Final fallback - let the OS try to find it
808    "tmux".to_string()
809}
810
811pub fn tmux_default_session() -> Option<String> {
812    None // No default session name
813}
814
815pub fn tmux_auto_attach_session() -> Option<String> {
816    None // No auto-attach session
817}
818
819pub fn tmux_prefix_key() -> String {
820    "C-b".to_string() // Standard tmux prefix (Ctrl+B)
821}
822
823pub fn tmux_status_bar_refresh_ms() -> u64 {
824    1000 // Default: 1 second refresh interval
825}
826
827pub fn tmux_status_bar_left() -> String {
828    "[{session}] {windows}".to_string()
829}
830
831pub fn tmux_status_bar_right() -> String {
832    "{pane} | {time:%H:%M}".to_string()
833}
834
835// Badge defaults
836pub fn badge_format() -> String {
837    "\\(session.username)@\\(session.hostname)".to_string()
838}
839
840pub fn badge_color() -> [u8; 3] {
841    [255, 0, 0] // Red text (matches iTerm2 default)
842}
843
844pub fn badge_color_alpha() -> f32 {
845    0.5 // 50% opacity (semi-transparent)
846}
847
848pub fn badge_font() -> String {
849    "Helvetica".to_string()
850}
851
852pub fn badge_top_margin() -> f32 {
853    0.0 // 0 pixels from top
854}
855
856pub fn badge_right_margin() -> f32 {
857    16.0 // 16 pixels from right
858}
859
860pub fn badge_max_width() -> f32 {
861    0.5 // 50% of terminal width
862}
863
864pub fn badge_max_height() -> f32 {
865    0.2 // 20% of terminal height
866}
867
868// Session logging defaults
869pub fn command_history_max_entries() -> usize {
870    1000 // Maximum number of commands to persist across sessions
871}
872
873pub fn session_undo_timeout_secs() -> u32 {
874    5
875}
876
877pub fn session_undo_max_entries() -> usize {
878    10
879}
880
881pub fn session_undo_preserve_shell() -> bool {
882    false
883}
884
885// Status bar defaults
886pub fn status_bar_height() -> f32 {
887    22.0
888}
889
890pub fn status_bar_bg_color() -> [u8; 3] {
891    [30, 30, 30]
892}
893
894pub fn status_bar_bg_alpha() -> f32 {
895    0.95
896}
897
898pub fn status_bar_fg_color() -> [u8; 3] {
899    [200, 200, 200]
900}
901
902pub fn status_bar_font_size() -> f32 {
903    12.0
904}
905
906pub fn status_bar_separator() -> String {
907    " \u{2502} ".to_string() // " │ "
908}
909
910pub fn status_bar_mouse_inactive_timeout() -> f32 {
911    3.0
912}
913
914pub fn status_bar_system_poll_interval() -> f32 {
915    2.0
916}
917
918pub fn status_bar_git_poll_interval() -> f32 {
919    5.0
920}
921
922pub fn status_bar_time_format() -> String {
923    "%H:%M:%S".to_string()
924}
925
926pub fn session_log_directory() -> String {
927    // XDG-compliant default: ~/.local/share/par-term/logs/
928    if let Some(home) = dirs::home_dir() {
929        home.join(".local")
930            .join("share")
931            .join("par-term")
932            .join("logs")
933            .to_string_lossy()
934            .to_string()
935    } else {
936        "logs".to_string()
937    }
938}
939
940// AI Inspector defaults
941pub fn ai_inspector_enabled() -> bool {
942    true
943}
944
945pub fn ai_inspector_width() -> f32 {
946    300.0
947}
948
949pub fn ai_inspector_open_on_startup() -> bool {
950    false
951}
952
953pub fn ai_inspector_default_scope() -> String {
954    "visible".to_string()
955}
956
957pub fn ai_inspector_view_mode() -> String {
958    "tree".to_string()
959}
960
961pub fn ai_inspector_live_update() -> bool {
962    false
963}
964
965pub fn ai_inspector_show_zones() -> bool {
966    true
967}
968
969pub fn ai_inspector_agent() -> String {
970    "claude.com".to_string()
971}
972
973pub fn ai_inspector_auto_launch() -> bool {
974    false
975}
976
977pub fn ai_inspector_auto_context() -> bool {
978    false
979}
980
981pub fn ai_inspector_context_max_lines() -> usize {
982    200
983}
984
985pub fn ai_inspector_auto_approve() -> bool {
986    false
987}
988
989pub fn ai_inspector_agent_terminal_access() -> bool {
990    false
991}
992
993pub fn ai_inspector_agent_screenshot_access() -> bool {
994    true
995}