aboutsummaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-28 23:12:50 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-28 23:12:50 +0300
commit7626a9adc84d6757042670f9816a583dcd717823 (patch)
tree56095c659834727ca73b03627a1f6eddc86ac666 /src/ui
parent28222b20890a1f6cd36fd477de8e9bc6e5537ff5 (diff)
feat: add pane copy mode
refs #231
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/keybind_help.rs1
-rw-r--r--src/ui/menus.rs33
-rw-r--r--src/ui/panes.rs26
3 files changed, 60 insertions, 0 deletions
diff --git a/src/ui/keybind_help.rs b/src/ui/keybind_help.rs
index c3664dec..4fb559c6 100644
--- a/src/ui/keybind_help.rs
+++ b/src/ui/keybind_help.rs
@@ -126,6 +126,7 @@ pub(super) fn keybind_help_groups(
(keybind_label(&kb.close_pane), "close pane"),
(keybind_label(&kb.rename_pane), "rename pane"),
(keybind_label(&kb.edit_scrollback), "edit scrollback"),
+ (keybind_label(&kb.copy_mode), "copy mode"),
(keybind_label(&kb.zoom), "zoom pane"),
(keybind_label(&kb.resize_mode), "resize mode"),
(keybind_label(&kb.toggle_sidebar), "toggle sidebar"),
diff --git a/src/ui/menus.rs b/src/ui/menus.rs
index b711358e..e974d524 100644
--- a/src/ui/menus.rs
+++ b/src/ui/menus.rs
@@ -60,6 +60,39 @@ pub(super) fn render_prefix_overlay(app: &AppState, frame: &mut Frame, area: Rec
render_bottom_bar(frame, overlay_area, line, app.palette.panel_bg);
}
+pub(super) fn render_copy_mode_overlay(app: &AppState, frame: &mut Frame, area: Rect) {
+ let key = Style::default()
+ .fg(app.palette.accent)
+ .add_modifier(Modifier::BOLD);
+ let dim = Style::default().fg(app.palette.overlay0);
+ let mode_style = Style::default()
+ .fg(panel_contrast_fg(&app.palette))
+ .bg(app.palette.accent)
+ .add_modifier(Modifier::BOLD);
+
+ let select = if app.copy_mode.is_some_and(|copy_mode| copy_mode.selecting) {
+ "selecting"
+ } else {
+ "select"
+ };
+ let line = Line::from(vec![
+ Span::styled(" COPY ", mode_style),
+ Span::raw(" "),
+ Span::styled("h/j/k/l w/b/e { }", key),
+ Span::styled(" move ", dim),
+ Span::styled("v/space", key),
+ Span::styled(format!(" {select} "), dim),
+ Span::styled("y/enter", key),
+ Span::styled(" copy ", dim),
+ Span::styled("q/esc", key),
+ Span::styled(" exit", dim),
+ ]);
+
+ let overlay_y = area.y + area.height.saturating_sub(1);
+ let overlay_area = Rect::new(area.x, overlay_y, area.width, 1);
+ render_bottom_bar(frame, overlay_area, line, app.palette.panel_bg);
+}
+
pub(super) fn render_navigate_overlay(app: &AppState, frame: &mut Frame, area: Rect) {
let key = Style::default()
.fg(app.palette.accent)
diff --git a/src/ui/panes.rs b/src/ui/panes.rs
index c211ec9d..8c7d1f02 100644
--- a/src/ui/panes.rs
+++ b/src/ui/panes.rs
@@ -313,10 +313,36 @@ pub(super) fn render_panes(
rt.scroll_metrics(),
&app.palette,
);
+ render_copy_mode_cursor(app, frame, info);
}
}
}
+fn render_copy_mode_cursor(app: &AppState, frame: &mut Frame, info: &PaneInfo) {
+ if app.mode != Mode::Copy {
+ return;
+ }
+ let Some(copy_mode) = app.copy_mode else {
+ return;
+ };
+ if copy_mode.pane_id != info.id
+ || copy_mode.cursor_row >= info.inner_rect.height
+ || copy_mode.cursor_col >= info.inner_rect.width
+ {
+ return;
+ }
+
+ let x = info.inner_rect.x + copy_mode.cursor_col;
+ let y = info.inner_rect.y + copy_mode.cursor_row;
+ let cell = &mut frame.buffer_mut()[(x, y)];
+ cell.set_style(
+ Style::default()
+ .fg(panel_contrast_fg(&app.palette))
+ .bg(app.palette.accent)
+ .add_modifier(Modifier::BOLD),
+ );
+}
+
fn render_selection_highlight(
selection: &Option<crate::selection::Selection>,
frame: &mut Frame,