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