aboutsummaryrefslogtreecommitdiff
path: root/src/ui/menus.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-10 04:22:10 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-10 04:22:10 +0300
commitc8850a2e3e284033142db0f8117fa5998c68bd59 (patch)
tree487530d94265c096ceeb3ded7c60a94f14a6f7fd /src/ui/menus.rs
parent0de503ccd9a8fedeeb6cbcc1446ab2bc644fdbb6 (diff)
feat: add copy mode search and tmux word motions
refs #1230
Diffstat (limited to 'src/ui/menus.rs')
-rw-r--r--src/ui/menus.rs67
1 files changed, 49 insertions, 18 deletions
diff --git a/src/ui/menus.rs b/src/ui/menus.rs
index 42b4ec70..763c0ea8 100644
--- a/src/ui/menus.rs
+++ b/src/ui/menus.rs
@@ -70,26 +70,57 @@ pub(super) fn render_copy_mode_overlay(app: &AppState, frame: &mut Frame, area:
.bg(app.palette.accent)
.add_modifier(Modifier::BOLD);
- let select = if app
- .copy_mode
- .is_some_and(|copy_mode| copy_mode.selection.is_some())
- {
- "selecting"
+ let Some(copy_mode) = app.copy_mode.as_ref() else {
+ return;
+ };
+ let line = if let Some(prompt) = copy_mode.search.prompt.as_ref() {
+ let marker = match prompt.direction {
+ crate::app::state::CopyModeSearchDirection::Forward => "/",
+ crate::app::state::CopyModeSearchDirection::Backward => "?",
+ };
+ Line::from(vec![
+ Span::styled(" COPY ", mode_style),
+ Span::raw(" "),
+ Span::styled(marker, key),
+ Span::styled(prompt.query.clone(), Style::default().fg(app.palette.text)),
+ Span::styled("█", key),
+ Span::styled(" enter search esc cancel", dim),
+ ])
} else {
- "select"
+ let select = if copy_mode.selection.is_some() {
+ "selecting"
+ } else {
+ "select"
+ };
+ let match_status = copy_mode
+ .search
+ .current
+ .map(|current| format!(" {}/{}", current + 1, copy_mode.search.matches.len()))
+ .or_else(|| (!copy_mode.search.query.is_empty()).then(|| " 0/0".to_string()))
+ .unwrap_or_default();
+ let (exit_keys, exit_label) =
+ if copy_mode.search.query.is_empty() && copy_mode.selection.is_none() {
+ ("q/esc", " exit")
+ } else {
+ ("esc", " clear q exit")
+ };
+ 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("/ ?", key),
+ Span::styled(" search ", dim),
+ Span::styled("n/N", key),
+ Span::styled(format!(" repeat{match_status} "), dim),
+ Span::styled("v/space", key),
+ Span::styled(format!(" {select} "), dim),
+ Span::styled("y/enter", key),
+ Span::styled(" copy ", dim),
+ Span::styled(exit_keys, key),
+ Span::styled(exit_label, dim),
+ ])
};
- 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);