diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-11 23:31:36 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-11 23:34:20 +0300 |
| commit | fe693f613a23452e68589a4337863f217cc57930 (patch) | |
| tree | 8d60f6c5b0d8b31426c6623cc8b0c2415d481000 /src/ui | |
| parent | 84c0d003ddb19a8e95e7ad5206771a663913605b (diff) | |
feat: add optional pane border labels
Diffstat (limited to 'src/ui')
| -rw-r--r-- | src/ui/dialogs.rs | 1 | ||||
| -rw-r--r-- | src/ui/keybind_help.rs | 1 | ||||
| -rw-r--r-- | src/ui/panes.rs | 44 | ||||
| -rw-r--r-- | src/ui/settings.rs | 11 | ||||
| -rw-r--r-- | src/ui/sidebar.rs | 1 |
5 files changed, 57 insertions, 1 deletions
diff --git a/src/ui/dialogs.rs b/src/ui/dialogs.rs index 78f1d1cb..3c481a97 100644 --- a/src/ui/dialogs.rs +++ b/src/ui/dialogs.rs @@ -42,6 +42,7 @@ pub(super) fn render_rename_overlay(app: &AppState, frame: &mut Frame, area: Rec Mode::RenameWorkspace => "rename workspace", Mode::RenameTab if app.creating_new_tab => "new tab", Mode::RenameTab => "rename tab", + Mode::RenamePane => "rename pane", _ => return, }; diff --git a/src/ui/keybind_help.rs b/src/ui/keybind_help.rs index 2bb05c50..fdc600c4 100644 --- a/src/ui/keybind_help.rs +++ b/src/ui/keybind_help.rs @@ -82,6 +82,7 @@ pub(super) fn keybind_help_groups( (kb.split_vertical_label.clone(), "split vertical"), (kb.split_horizontal_label.clone(), "split horizontal"), (kb.close_pane_label.clone(), "close pane"), + (optional_keybind_label(&kb.rename_pane_label), "rename pane"), (kb.fullscreen_label.clone(), "fullscreen"), (kb.resize_mode_label.clone(), "resize mode"), (kb.toggle_sidebar_label.clone(), "toggle sidebar"), diff --git a/src/ui/panes.rs b/src/ui/panes.rs index 818ee9fd..72a5c30c 100644 --- a/src/ui/panes.rs +++ b/src/ui/panes.rs @@ -18,6 +18,30 @@ pub(crate) fn pane_is_scrolled_back(rt: &PaneRuntime) -> bool { .is_some_and(|metrics| metrics.offset_from_bottom > 0) } +fn truncate_label(text: &str, max_width: usize) -> String { + let len = text.chars().count(); + if len <= max_width { + return text.to_string(); + } + if max_width == 0 { + return String::new(); + } + if max_width == 1 { + return "…".to_string(); + } + let prefix: String = text.chars().take(max_width.saturating_sub(1)).collect(); + format!("{prefix}…") +} + +fn pane_border_title(label: &str, pane_width: u16) -> Option<String> { + let label = label.trim(); + if label.is_empty() || pane_width <= 4 { + return None; + } + let max_label_width = pane_width.saturating_sub(4) as usize; + Some(format!(" {} ", truncate_label(label, max_label_width))) +} + fn stable_terminal_inner_rect(pane_inner: Rect) -> Rect { if pane_inner.width <= 4 { return pane_inner; @@ -174,10 +198,17 @@ pub(super) fn render_panes(app: &AppState, frame: &mut Frame, area: Rect) { ) }; - let block = Block::default() + let mut block = Block::default() .borders(Borders::ALL) .border_style(border_style) .border_set(border_set); + if let Some(title) = ws + .pane_state(info.id) + .and_then(|pane| pane.border_label(app.show_agent_labels_on_pane_borders)) + .and_then(|label| pane_border_title(label, info.rect.width)) + { + block = block.title(Line::from(Span::styled(title, border_style))); + } frame.render_widget(block, info.rect); } @@ -303,6 +334,17 @@ mod tests { use crate::pane::PaneRuntime; use crate::workspace::Workspace; + #[test] + fn pane_border_title_trims_and_truncates() { + assert_eq!( + pane_border_title(" claude ", 20).as_deref(), + Some(" claude ") + ); + assert_eq!(pane_border_title("", 20), None); + assert_eq!(pane_border_title("abcdef", 8).as_deref(), Some(" abc… ")); + assert_eq!(pane_border_title("abcdef", 4), None); + } + #[tokio::test] async fn pane_scrollbar_gutter_is_reserved_before_scrollback_exists() { let mut app = AppState::test_new(); diff --git a/src/ui/settings.rs b/src/ui/settings.rs index 5269f380..ef80d85a 100644 --- a/src/ui/settings.rs +++ b/src/ui/settings.rs @@ -106,6 +106,17 @@ pub(super) fn render_settings_overlay(app: &AppState, frame: &mut Frame, area: R 2, ); } + SettingsSection::PaneLabels => { + render_settings_toggle( + frame, + content_area, + p, + "agent border labels", + "show detected agent names in split pane borders", + app.agent_border_labels_enabled(), + app.settings.list.selected, + ); + } } if let Some(footer_area) = stack.footer { diff --git a/src/ui/sidebar.rs b/src/ui/sidebar.rs index 83ceebe0..8a104dba 100644 --- a/src/ui/sidebar.rs +++ b/src/ui/sidebar.rs @@ -70,6 +70,7 @@ fn agent_panel_current_workspace_idx(app: &AppState) -> Option<usize> { app.mode, Mode::Navigate | Mode::RenameWorkspace + | Mode::RenamePane | Mode::Resize | Mode::ConfirmClose | Mode::ContextMenu |
