Skip to content

Commit 7ef7cd5

Browse files
authored
feat(ui): add optional tooltip with key hints to the compact bar (#4225)
* initial implementation * some refactoring * refactor: separate some concerns and tidy up * fix: move tooltip to focused tab as needed * some ux adjustments * some refactoring * only show tooltip if we have configured a shortcut key * add plugin artifacts * fix tests * truncate tooltip if it exceeds width * change config name * remove comment * docs(changelog): add PR
1 parent a9f8bbc commit 7ef7cd5

28 files changed

+1908
-485
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
66

77
## [Unreleased]
88
* feat: multiple select and bulk pane actions (https://github.com/zellij-org/zellij/pull/4169 and https://github.com/zellij-org/zellij/pull/4171 and https://github.com/zellij-org/zellij/pull/4221)
9+
* feat: add an optional key tooltip to show the current keybindings for the compact bar (https://github.com/zellij-org/zellij/pull/4225)
910

1011
## [0.42.2] - 2025-04-15
1112
* refactor(terminal): track scroll_region as tuple rather than Option (https://github.com/zellij-org/zellij/pull/4082)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
use zellij_tile::prelude::actions::Action;
2+
use zellij_tile::prelude::*;
3+
4+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5+
pub enum ActionType {
6+
MoveFocus,
7+
MovePaneWithDirection,
8+
MovePaneWithoutDirection,
9+
ResizeIncrease,
10+
ResizeDecrease,
11+
ResizeAny,
12+
Search,
13+
NewPaneWithDirection,
14+
NewPaneWithoutDirection,
15+
BreakPaneLeftOrRight,
16+
GoToAdjacentTab,
17+
Scroll,
18+
PageScroll,
19+
HalfPageScroll,
20+
SessionManager,
21+
Configuration,
22+
PluginManager,
23+
About,
24+
SwitchToMode(InputMode),
25+
TogglePaneEmbedOrFloating,
26+
ToggleFocusFullscreen,
27+
ToggleFloatingPanes,
28+
CloseFocus,
29+
CloseTab,
30+
ToggleActiveSyncTab,
31+
ToggleTab,
32+
BreakPane,
33+
EditScrollback,
34+
NewTab,
35+
Detach,
36+
Quit,
37+
Other(String), // Fallback for unhandled actions
38+
}
39+
40+
impl ActionType {
41+
pub fn description(&self) -> String {
42+
match self {
43+
ActionType::MoveFocus => "Move focus".to_string(),
44+
ActionType::MovePaneWithDirection => "Move pane".to_string(),
45+
ActionType::MovePaneWithoutDirection => "Move pane".to_string(),
46+
ActionType::ResizeIncrease => "Increase size in direction".to_string(),
47+
ActionType::ResizeDecrease => "Decrease size in direction".to_string(),
48+
ActionType::ResizeAny => "Increase or decrease size".to_string(),
49+
ActionType::Search => "Search".to_string(),
50+
ActionType::NewPaneWithDirection => "Split right/down".to_string(),
51+
ActionType::NewPaneWithoutDirection => "New pane".to_string(),
52+
ActionType::BreakPaneLeftOrRight => "Break pane to adjacent tab".to_string(),
53+
ActionType::GoToAdjacentTab => "Move tab focus".to_string(),
54+
ActionType::Scroll => "Scroll".to_string(),
55+
ActionType::PageScroll => "Scroll page".to_string(),
56+
ActionType::HalfPageScroll => "Scroll half Page".to_string(),
57+
ActionType::SessionManager => "Session manager".to_string(),
58+
ActionType::PluginManager => "Plugin manager".to_string(),
59+
ActionType::Configuration => "Configuration".to_string(),
60+
ActionType::About => "About Zellij".to_string(),
61+
ActionType::SwitchToMode(input_mode) if input_mode == &InputMode::RenamePane => {
62+
"Rename pane".to_string()
63+
},
64+
ActionType::SwitchToMode(input_mode) if input_mode == &InputMode::RenameTab => {
65+
"Rename tab".to_string()
66+
},
67+
ActionType::SwitchToMode(input_mode) if input_mode == &InputMode::EnterSearch => {
68+
"Search".to_string()
69+
},
70+
ActionType::SwitchToMode(input_mode) if input_mode == &InputMode::Locked => {
71+
"Lock".to_string()
72+
},
73+
ActionType::SwitchToMode(input_mode) if input_mode == &InputMode::Normal => {
74+
"Unlock".to_string()
75+
},
76+
ActionType::SwitchToMode(input_mode) => format!("{:?}", input_mode),
77+
ActionType::TogglePaneEmbedOrFloating => "Float or embed".to_string(),
78+
ActionType::ToggleFocusFullscreen => "Toggle fullscreen".to_string(),
79+
ActionType::ToggleFloatingPanes => "Show/hide floating panes".to_string(),
80+
ActionType::CloseFocus => "Close pane".to_string(),
81+
ActionType::CloseTab => "Close tab".to_string(),
82+
ActionType::ToggleActiveSyncTab => "Sync panes in tab".to_string(),
83+
ActionType::ToggleTab => "Circle tab focus".to_string(),
84+
ActionType::BreakPane => "Break pane to new tab".to_string(),
85+
ActionType::EditScrollback => "Open pane scrollback in editor".to_string(),
86+
ActionType::NewTab => "New tab".to_string(),
87+
ActionType::Detach => "Detach".to_string(),
88+
ActionType::Quit => "Quit".to_string(),
89+
ActionType::Other(_) => "Other action".to_string(),
90+
}
91+
}
92+
93+
pub fn from_action(action: &Action) -> Self {
94+
match action {
95+
Action::MoveFocus(_) => ActionType::MoveFocus,
96+
Action::MovePane(Some(_)) => ActionType::MovePaneWithDirection,
97+
Action::MovePane(None) => ActionType::MovePaneWithoutDirection,
98+
Action::Resize(Resize::Increase, Some(_)) => ActionType::ResizeIncrease,
99+
Action::Resize(Resize::Decrease, Some(_)) => ActionType::ResizeDecrease,
100+
Action::Resize(_, None) => ActionType::ResizeAny,
101+
Action::Search(_) => ActionType::Search,
102+
Action::NewPane(Some(_), _, _) => ActionType::NewPaneWithDirection,
103+
Action::NewPane(None, _, _) => ActionType::NewPaneWithoutDirection,
104+
Action::BreakPaneLeft | Action::BreakPaneRight => ActionType::BreakPaneLeftOrRight,
105+
Action::GoToPreviousTab | Action::GoToNextTab => ActionType::GoToAdjacentTab,
106+
Action::ScrollUp | Action::ScrollDown => ActionType::Scroll,
107+
Action::PageScrollUp | Action::PageScrollDown => ActionType::PageScroll,
108+
Action::HalfPageScrollUp | Action::HalfPageScrollDown => ActionType::HalfPageScroll,
109+
Action::SwitchToMode(input_mode) => ActionType::SwitchToMode(*input_mode),
110+
Action::TogglePaneEmbedOrFloating => ActionType::TogglePaneEmbedOrFloating,
111+
Action::ToggleFocusFullscreen => ActionType::ToggleFocusFullscreen,
112+
Action::ToggleFloatingPanes => ActionType::ToggleFloatingPanes,
113+
Action::CloseFocus => ActionType::CloseFocus,
114+
Action::CloseTab => ActionType::CloseTab,
115+
Action::ToggleActiveSyncTab => ActionType::ToggleActiveSyncTab,
116+
Action::ToggleTab => ActionType::ToggleTab,
117+
Action::BreakPane => ActionType::BreakPane,
118+
Action::EditScrollback => ActionType::EditScrollback,
119+
Action::Detach => ActionType::Detach,
120+
Action::Quit => ActionType::Quit,
121+
action if action.launches_plugin("session-manager") => ActionType::SessionManager,
122+
action if action.launches_plugin("configuration") => ActionType::Configuration,
123+
action if action.launches_plugin("plugin-manager") => ActionType::PluginManager,
124+
action if action.launches_plugin("zellij:about") => ActionType::About,
125+
action if matches!(action, Action::NewTab(..)) => ActionType::NewTab,
126+
_ => ActionType::Other(format!("{:?}", action)),
127+
}
128+
}
129+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use crate::LinePart;
2+
use zellij_tile::prelude::*;
3+
4+
pub fn text_copied_hint(copy_destination: CopyDestination) -> LinePart {
5+
let hint = match copy_destination {
6+
CopyDestination::Command => "Text piped to external command",
7+
#[cfg(not(target_os = "macos"))]
8+
CopyDestination::Primary => "Text copied to system primary selection",
9+
#[cfg(target_os = "macos")] // primary selection does not exist on macos
10+
CopyDestination::Primary => "Text copied to system clipboard",
11+
CopyDestination::System => "Text copied to system clipboard",
12+
};
13+
LinePart {
14+
part: serialize_text(&Text::new(&hint).color_range(2, ..).opaque()),
15+
len: hint.len(),
16+
tab_index: None,
17+
}
18+
}
19+
20+
pub fn system_clipboard_error() -> LinePart {
21+
let hint = " Error using the system clipboard.";
22+
LinePart {
23+
part: serialize_text(&Text::new(&hint).color_range(2, ..).opaque()),
24+
len: hint.len(),
25+
tab_index: None,
26+
}
27+
}

0 commit comments

Comments
 (0)