par_term_config/defaults/misc.rs
1//! Default values that do not belong to a single focused subsystem.
2
3// ── Primitive helpers ──────────────────────────────────────────────────────
4
5/// Serde default returning `false`.
6pub fn bool_false() -> bool {
7 false
8}
9
10/// Serde default returning `true`.
11pub fn bool_true() -> bool {
12 true
13}
14
15/// Serde default returning `0`.
16pub fn zero() -> usize {
17 0
18}
19
20/// Default mDNS service discovery timeout in seconds.
21pub fn mdns_timeout() -> u32 {
22 3
23}
24
25// ── Update ─────────────────────────────────────────────────────────────────
26
27/// Default update check frequency.
28pub fn update_check_frequency() -> crate::types::UpdateCheckFrequency {
29 crate::types::UpdateCheckFrequency::Daily
30}
31
32// ── Keybindings ────────────────────────────────────────────────────────────
33
34pub fn keybindings() -> Vec<crate::types::KeyBinding> {
35 // macOS: Cmd+key is safe because Cmd is separate from Ctrl (terminal control codes).
36 // Windows/Linux: Ctrl+key conflicts with terminal control codes (Ctrl+C=SIGINT, Ctrl+D=EOF, etc.)
37 // so we use Ctrl+Shift+key following standard terminal emulator conventions
38 // (WezTerm, Kitty, Alacritty, GNOME Terminal, Windows Terminal).
39 #[cfg(target_os = "macos")]
40 let bindings = vec![
41 crate::types::KeyBinding {
42 key: "CmdOrCtrl+Shift+B".to_string(),
43 action: "toggle_background_shader".to_string(),
44 },
45 crate::types::KeyBinding {
46 key: "CmdOrCtrl+Shift+U".to_string(),
47 action: "toggle_cursor_shader".to_string(),
48 },
49 crate::types::KeyBinding {
50 key: "CmdOrCtrl+Shift+V".to_string(),
51 action: "paste_special".to_string(),
52 },
53 crate::types::KeyBinding {
54 key: "CmdOrCtrl+Shift+R".to_string(),
55 action: "toggle_session_logging".to_string(),
56 },
57 // Split pane shortcuts (Cmd+D / Cmd+Shift+D matches iTerm2)
58 crate::types::KeyBinding {
59 key: "CmdOrCtrl+D".to_string(),
60 action: "split_horizontal".to_string(),
61 },
62 crate::types::KeyBinding {
63 key: "CmdOrCtrl+Shift+D".to_string(),
64 action: "split_vertical".to_string(),
65 },
66 crate::types::KeyBinding {
67 key: "CmdOrCtrl+Shift+W".to_string(),
68 action: "close_pane".to_string(),
69 },
70 // Pane navigation shortcuts
71 crate::types::KeyBinding {
72 key: "CmdOrCtrl+Alt+Left".to_string(),
73 action: "navigate_pane_left".to_string(),
74 },
75 crate::types::KeyBinding {
76 key: "CmdOrCtrl+Alt+Right".to_string(),
77 action: "navigate_pane_right".to_string(),
78 },
79 crate::types::KeyBinding {
80 key: "CmdOrCtrl+Alt+Up".to_string(),
81 action: "navigate_pane_up".to_string(),
82 },
83 crate::types::KeyBinding {
84 key: "CmdOrCtrl+Alt+Down".to_string(),
85 action: "navigate_pane_down".to_string(),
86 },
87 // Pane resize shortcuts
88 crate::types::KeyBinding {
89 key: "CmdOrCtrl+Alt+Shift+Left".to_string(),
90 action: "resize_pane_left".to_string(),
91 },
92 crate::types::KeyBinding {
93 key: "CmdOrCtrl+Alt+Shift+Right".to_string(),
94 action: "resize_pane_right".to_string(),
95 },
96 crate::types::KeyBinding {
97 key: "CmdOrCtrl+Alt+Shift+Up".to_string(),
98 action: "resize_pane_up".to_string(),
99 },
100 crate::types::KeyBinding {
101 key: "CmdOrCtrl+Alt+Shift+Down".to_string(),
102 action: "resize_pane_down".to_string(),
103 },
104 // Broadcast input mode
105 crate::types::KeyBinding {
106 key: "CmdOrCtrl+Alt+I".to_string(),
107 action: "toggle_broadcast_input".to_string(),
108 },
109 // Throughput mode toggle
110 crate::types::KeyBinding {
111 key: "CmdOrCtrl+Shift+T".to_string(),
112 action: "toggle_throughput_mode".to_string(),
113 },
114 // tmux session picker
115 crate::types::KeyBinding {
116 key: "CmdOrCtrl+Alt+T".to_string(),
117 action: "toggle_tmux_session_picker".to_string(),
118 },
119 // Copy mode (vi-style keyboard-driven selection) - matches iTerm2
120 crate::types::KeyBinding {
121 key: "CmdOrCtrl+Shift+C".to_string(),
122 action: "toggle_copy_mode".to_string(),
123 },
124 // Command history fuzzy search
125 crate::types::KeyBinding {
126 key: "CmdOrCtrl+R".to_string(),
127 action: "toggle_command_history".to_string(),
128 },
129 // Reopen recently closed tab
130 crate::types::KeyBinding {
131 key: "CmdOrCtrl+Z".to_string(),
132 action: "reopen_closed_tab".to_string(),
133 },
134 // SSH Quick Connect
135 crate::types::KeyBinding {
136 key: "CmdOrCtrl+Shift+S".to_string(),
137 action: "ssh_quick_connect".to_string(),
138 },
139 // Duplicate Tab. Cmd+D / Cmd+Shift+D (the natural mnemonic) are the two
140 // split actions and Cmd+Shift+T is throughput mode, so J — free in both
141 // the default keybindings and every hardcoded key layer.
142 crate::types::KeyBinding {
143 key: "CmdOrCtrl+Shift+J".to_string(),
144 action: "duplicate_tab".to_string(),
145 },
146 // Profile drawer. The chord was only ever a hardcoded key layer, so it
147 // was invisible in Settings and could not be rebound; shipping it as a
148 // default makes it a first-class binding. The Profiles menu used to
149 // give this accelerator to `Manage Profiles...`, which meant the native
150 // menu bar consumed it before this registry ever ran.
151 crate::types::KeyBinding {
152 key: "CmdOrCtrl+Shift+P".to_string(),
153 action: "toggle_profile_drawer".to_string(),
154 },
155 ];
156
157 #[cfg(not(target_os = "macos"))]
158 let bindings = vec![
159 crate::types::KeyBinding {
160 key: "Ctrl+Shift+B".to_string(),
161 action: "toggle_background_shader".to_string(),
162 },
163 crate::types::KeyBinding {
164 key: "Ctrl+Shift+U".to_string(),
165 action: "toggle_cursor_shader".to_string(),
166 },
167 // Ctrl+Shift+V is standard paste on Linux terminals, so use Ctrl+Alt+V for paste special
168 crate::types::KeyBinding {
169 key: "Ctrl+Alt+V".to_string(),
170 action: "paste_special".to_string(),
171 },
172 crate::types::KeyBinding {
173 key: "Ctrl+Shift+R".to_string(),
174 action: "toggle_session_logging".to_string(),
175 },
176 // Split pane shortcuts
177 // Ctrl+D is EOF/logout - use Ctrl+Shift+D for horizontal split
178 crate::types::KeyBinding {
179 key: "Ctrl+Shift+D".to_string(),
180 action: "split_horizontal".to_string(),
181 },
182 // Ctrl+Shift+E for vertical split (Tilix/Terminator convention)
183 crate::types::KeyBinding {
184 key: "Ctrl+Shift+E".to_string(),
185 action: "split_vertical".to_string(),
186 },
187 // Ctrl+Shift+W is standard close tab - use Ctrl+Shift+X for close pane
188 crate::types::KeyBinding {
189 key: "Ctrl+Shift+X".to_string(),
190 action: "close_pane".to_string(),
191 },
192 // Pane navigation shortcuts
193 crate::types::KeyBinding {
194 key: "Ctrl+Alt+Left".to_string(),
195 action: "navigate_pane_left".to_string(),
196 },
197 crate::types::KeyBinding {
198 key: "Ctrl+Alt+Right".to_string(),
199 action: "navigate_pane_right".to_string(),
200 },
201 crate::types::KeyBinding {
202 key: "Ctrl+Alt+Up".to_string(),
203 action: "navigate_pane_up".to_string(),
204 },
205 crate::types::KeyBinding {
206 key: "Ctrl+Alt+Down".to_string(),
207 action: "navigate_pane_down".to_string(),
208 },
209 // Pane resize shortcuts
210 crate::types::KeyBinding {
211 key: "Ctrl+Alt+Shift+Left".to_string(),
212 action: "resize_pane_left".to_string(),
213 },
214 crate::types::KeyBinding {
215 key: "Ctrl+Alt+Shift+Right".to_string(),
216 action: "resize_pane_right".to_string(),
217 },
218 crate::types::KeyBinding {
219 key: "Ctrl+Alt+Shift+Up".to_string(),
220 action: "resize_pane_up".to_string(),
221 },
222 crate::types::KeyBinding {
223 key: "Ctrl+Alt+Shift+Down".to_string(),
224 action: "resize_pane_down".to_string(),
225 },
226 // Broadcast input mode
227 crate::types::KeyBinding {
228 key: "Ctrl+Alt+I".to_string(),
229 action: "toggle_broadcast_input".to_string(),
230 },
231 // Ctrl+Shift+T is standard new tab - use Ctrl+Shift+M for throughput mode
232 crate::types::KeyBinding {
233 key: "Ctrl+Shift+M".to_string(),
234 action: "toggle_throughput_mode".to_string(),
235 },
236 // tmux session picker
237 crate::types::KeyBinding {
238 key: "Ctrl+Alt+T".to_string(),
239 action: "toggle_tmux_session_picker".to_string(),
240 },
241 // Copy mode (vi-style keyboard-driven selection)
242 // Ctrl+Shift+C is standard copy on Linux, so use Ctrl+Shift+Space
243 crate::types::KeyBinding {
244 key: "Ctrl+Shift+Space".to_string(),
245 action: "toggle_copy_mode".to_string(),
246 },
247 // Command history fuzzy search
248 // Ctrl+R conflicts with terminal reverse search, so use Ctrl+Shift+R
249 // Note: Ctrl+Shift+R is session logging on Linux; users can reassign
250 crate::types::KeyBinding {
251 key: "Ctrl+Alt+R".to_string(),
252 action: "toggle_command_history".to_string(),
253 },
254 // Reopen recently closed tab
255 crate::types::KeyBinding {
256 key: "Ctrl+Shift+Z".to_string(),
257 action: "reopen_closed_tab".to_string(),
258 },
259 // SSH Quick Connect
260 crate::types::KeyBinding {
261 key: "Ctrl+Shift+S".to_string(),
262 action: "ssh_quick_connect".to_string(),
263 },
264 // Duplicate Tab. Ctrl+Shift+D is the horizontal split here, and the menu
265 // model's `cmd_or_ctrl` is itself Ctrl+Shift off macOS, so every letter
266 // it uses (N, W, Q, T, C, V, A) is spoken for too. J is free on both.
267 crate::types::KeyBinding {
268 key: "Ctrl+Shift+J".to_string(),
269 action: "duplicate_tab".to_string(),
270 },
271 // Profile drawer — see the macOS list above. Ctrl+Shift+P already
272 // reached the drawer here through the hardcoded key layer, because
273 // Linux cannot attach a native menu bar; the menu merely mislabelled it
274 // as `Manage Profiles...`.
275 crate::types::KeyBinding {
276 key: "Ctrl+Shift+P".to_string(),
277 action: "toggle_profile_drawer".to_string(),
278 },
279 ];
280
281 bindings
282}
283
284// ── Command separator ──────────────────────────────────────────────────────
285
286/// Default command separator line thickness in pixels.
287pub fn command_separator_thickness() -> f32 {
288 1.0 // 1 pixel line
289}
290
291/// Default command separator line opacity (0.0–1.0).
292pub fn command_separator_opacity() -> f32 {
293 0.4 // Subtle by default
294}
295
296// ── Cursor shadow / boost ──────────────────────────────────────────────────
297
298/// Default cursor drop shadow pixel offset as `[x, y]`.
299pub fn cursor_shadow_offset() -> [f32; 2] {
300 [2.0, 2.0] // 2 pixels offset in both directions
301}
302
303/// Default cursor drop shadow blur radius in pixels.
304pub fn cursor_shadow_blur() -> f32 {
305 3.0 // 3 pixel blur radius
306}
307
308/// Default cursor brightness boost amount (0.0 = disabled).
309pub fn cursor_boost() -> f32 {
310 0.0 // Disabled by default
311}
312
313// ── Badge ──────────────────────────────────────────────────────────────────
314
315/// Default badge format string.
316pub fn badge_format() -> String {
317 "\\(session.username)@\\(session.hostname)".to_string()
318}
319
320/// Default badge text opacity (0.0–1.0).
321pub fn badge_color_alpha() -> f32 {
322 0.5 // 50% opacity (semi-transparent)
323}
324
325/// Default badge top margin in pixels.
326pub fn badge_top_margin() -> f32 {
327 0.0 // 0 pixels from top
328}
329
330/// Default badge right margin in pixels.
331pub fn badge_right_margin() -> f32 {
332 16.0 // 16 pixels from right
333}
334
335/// Default badge maximum width as a fraction of terminal width (0.0–1.0).
336pub fn badge_max_width() -> f32 {
337 0.5 // 50% of terminal width
338}
339
340/// Default badge maximum height as a fraction of terminal height (0.0–1.0).
341pub fn badge_max_height() -> f32 {
342 0.2 // 20% of terminal height
343}
344
345// ── Progress bar ───────────────────────────────────────────────────────────
346
347/// Default progress bar height in pixels.
348pub fn progress_bar_height() -> f32 {
349 4.0 // Height in pixels
350}
351
352/// Default progress bar opacity (0.0–1.0).
353pub fn progress_bar_opacity() -> f32 {
354 0.8
355}
356
357// ── Unicode ────────────────────────────────────────────────────────────────
358
359/// Default Unicode version for character width calculations.
360pub fn unicode_version() -> crate::types::UnicodeVersion {
361 crate::types::UnicodeVersion::Auto
362}
363
364/// Default treatment of ambiguous-width Unicode characters.
365pub fn ambiguous_width() -> crate::types::AmbiguousWidth {
366 crate::types::AmbiguousWidth::Narrow
367}
368
369/// Default Unicode normalization form applied to terminal input.
370pub fn normalization_form() -> crate::types::NormalizationForm {
371 crate::types::NormalizationForm::NFC
372}
373
374// ── Pane layout ────────────────────────────────────────────────────────────
375
376/// Default split-pane divider visual width in pixels (`None` = use theme default).
377pub fn pane_divider_width() -> Option<f32> {
378 Some(2.0) // 2 pixel divider between panes
379}
380
381/// Default split-pane divider drag hit area width in pixels.
382pub fn pane_divider_hit_width() -> f32 {
383 5.0 // 5 pixel hit area for drag-to-resize (larger than visual for easier grabbing)
384}
385
386/// Default padding in pixels inside each pane (between content and border/divider).
387pub fn pane_padding() -> f32 {
388 1.0 // 1 pixel padding inside panes (space between content and border/divider)
389}
390
391/// Default minimum pane size in terminal cells (applies to both columns and rows).
392pub fn pane_min_size() -> usize {
393 10 // Minimum pane size in cells (columns or rows)
394}
395
396/// Default pane background opacity (1.0 = fully opaque).
397pub fn pane_background_opacity() -> f32 {
398 1.0 // Fully opaque by default
399}
400
401/// Default opacity for inactive (unfocused) panes (0.0–1.0).
402pub fn inactive_pane_opacity() -> f32 {
403 0.7 // 70% opacity for inactive panes
404}
405
406/// Default maximum number of panes allowed per tab.
407pub fn max_panes() -> usize {
408 16 // Maximum panes per tab
409}
410
411/// Default pane title bar height in pixels.
412pub fn pane_title_height() -> f32 {
413 20.0 // 20 pixel title bar height for panes
414}
415
416/// Default focused pane border width in pixels.
417pub fn pane_focus_width() -> f32 {
418 1.0 // 1 pixel border around focused pane
419}
420
421// ── tmux integration ───────────────────────────────────────────────────────
422
423pub fn tmux_path() -> String {
424 // First, try to find tmux in the user's PATH environment variable
425 if let Ok(path_env) = std::env::var("PATH") {
426 let separator = if cfg!(windows) { ';' } else { ':' };
427 let executable = if cfg!(windows) { "tmux.exe" } else { "tmux" };
428
429 for dir in path_env.split(separator) {
430 let candidate = std::path::Path::new(dir).join(executable);
431 if candidate.exists() {
432 return candidate.to_string_lossy().to_string();
433 }
434 }
435 }
436
437 // Fall back to common paths for environments where PATH might be incomplete
438 // (e.g., macOS app bundles launched from Finder)
439 #[cfg(target_os = "macos")]
440 {
441 let macos_paths = [
442 "/opt/homebrew/bin/tmux", // Homebrew on Apple Silicon
443 "/usr/local/bin/tmux", // Homebrew on Intel / MacPorts
444 ];
445 for path in macos_paths {
446 if std::path::Path::new(path).exists() {
447 return path.to_string();
448 }
449 }
450 }
451
452 #[cfg(target_os = "linux")]
453 {
454 let linux_paths = [
455 "/usr/bin/tmux", // Most distros
456 "/usr/local/bin/tmux", // Manual install
457 "/snap/bin/tmux", // Snap package
458 ];
459 for path in linux_paths {
460 if std::path::Path::new(path).exists() {
461 return path.to_string();
462 }
463 }
464 }
465
466 // Final fallback - let the OS try to find it
467 "tmux".to_string()
468}
469
470/// Default tmux session name to connect to (`None` = no default).
471pub fn tmux_default_session() -> Option<String> {
472 None // No default session name
473}
474
475/// Default tmux session to auto-attach on startup (`None` = disabled).
476pub fn tmux_auto_attach_session() -> Option<String> {
477 None // No auto-attach session
478}
479
480/// Default tmux prefix key string (standard Ctrl+B).
481pub fn tmux_prefix_key() -> String {
482 "C-b".to_string() // Standard tmux prefix (Ctrl+B)
483}
484
485/// Default custom action prefix key (empty = disabled).
486pub fn custom_action_prefix_key() -> String {
487 String::new() // Disabled by default
488}
489
490/// Default tmux status bar refresh interval in milliseconds.
491pub fn tmux_status_bar_refresh_ms() -> u64 {
492 1000 // Default: 1 second refresh interval
493}
494
495/// Default tmux status bar left-side format string.
496pub fn tmux_status_bar_left() -> String {
497 "[{session}] {windows}".to_string()
498}
499
500/// Default tmux status bar right-side format string.
501pub fn tmux_status_bar_right() -> String {
502 "{pane} | {time:%H:%M}".to_string()
503}