Skip to content

Commit

Permalink
feat(tui): popup to list keybinds (#9545)
Browse files Browse the repository at this point in the history
  • Loading branch information
anthonyshew authored Dec 11, 2024
1 parent ecdc5b4 commit 10a57d0
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 4 deletions.
17 changes: 16 additions & 1 deletion crates/turborepo-ui/src/tui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
use ratatui::{
backend::{Backend, CrosstermBackend},
layout::{Constraint, Layout},
widgets::TableState,
widgets::{Clear, TableState},
Frame, Terminal,
};
use tokio::{
Expand All @@ -17,6 +17,8 @@ use tokio::{
};
use tracing::{debug, trace};

use crate::tui::popup::{popup, popup_area};

pub const FRAMERATE: Duration = Duration::from_millis(3);
const RESIZE_DEBOUNCE_DELAY: Duration = Duration::from_millis(10);

Expand Down Expand Up @@ -53,6 +55,7 @@ pub struct App<W> {
selected_task_index: usize,
is_task_selection_pinned: bool,
has_sidebar: bool,
showing_help_popup: bool,
done: bool,
}

Expand Down Expand Up @@ -97,6 +100,7 @@ impl<W> App<W> {
task_list_scroll: TableState::default().with_selected(selected_task_index),
selected_task_index,
has_sidebar: true,
showing_help_popup: false,
is_task_selection_pinned: has_user_interacted,
}
}
Expand All @@ -118,6 +122,7 @@ impl<W> App<W> {
Ok(InputOptions {
focus: &self.section_focus,
has_selection,
is_help_popup_open: self.showing_help_popup,
})
}

Expand Down Expand Up @@ -790,6 +795,9 @@ fn update(
Event::ToggleSidebar => {
app.has_sidebar = !app.has_sidebar;
}
Event::ToggleHelpPopup => {
app.showing_help_popup = !app.showing_help_popup;
}
Event::Input { bytes } => {
app.forward_input(&bytes)?;
}
Expand Down Expand Up @@ -862,6 +870,13 @@ fn view<W>(app: &mut App<W>, f: &mut Frame) {

f.render_stateful_widget(&table_to_render, table, &mut app.task_list_scroll);
f.render_widget(&pane_to_render, pane);

if app.showing_help_popup {
let area = popup_area(*f.buffer_mut().area());
let area = area.intersection(*f.buffer_mut().area());
f.render_widget(Clear, area); // Clears background underneath popup
f.render_widget(popup(area), area);
}
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions crates/turborepo-ui/src/tui/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub enum Event {
cols: u16,
},
ToggleSidebar,
ToggleHelpPopup,
SearchEnter,
SearchExit {
restore_scroll: bool,
Expand Down
4 changes: 4 additions & 0 deletions crates/turborepo-ui/src/tui/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use super::{
pub struct InputOptions<'a> {
pub focus: &'a LayoutSections,
pub has_selection: bool,
pub is_help_popup_open: bool,
}

pub fn start_crossterm_stream(tx: mpsc::Sender<crossterm::event::Event>) -> Option<JoinHandle<()>> {
Expand Down Expand Up @@ -80,6 +81,7 @@ fn translate_key_event(options: InputOptions, key_event: KeyEvent) -> Option<Eve
KeyCode::Char('/') if matches!(options.focus, LayoutSections::TaskList) => {
Some(Event::SearchEnter)
}
KeyCode::Esc if options.is_help_popup_open => Some(Event::ToggleHelpPopup),
KeyCode::Esc if matches!(options.focus, LayoutSections::Search { .. }) => {
Some(Event::SearchExit {
restore_scroll: true,
Expand Down Expand Up @@ -112,6 +114,7 @@ fn translate_key_event(options: InputOptions, key_event: KeyEvent) -> Option<Eve
KeyCode::Char('n') if key_event.modifiers == KeyModifiers::CONTROL => {
Some(Event::ScrollDown)
}
KeyCode::Char('m') => Some(Event::ToggleHelpPopup),
KeyCode::Up | KeyCode::Char('k') => Some(Event::Up),
KeyCode::Down | KeyCode::Char('j') => Some(Event::Down),
KeyCode::Enter | KeyCode::Char('i') => Some(Event::EnterInteractive),
Expand Down Expand Up @@ -443,6 +446,7 @@ mod test {
InputOptions {
focus: search(),
has_selection: false,
is_help_popup_open: false,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/turborepo-ui/src/tui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod event;
mod handle;
mod input;
mod pane;
mod popup;
mod search;
mod size;
mod spinner;
Expand Down
80 changes: 80 additions & 0 deletions crates/turborepo-ui/src/tui/popup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use std::cmp::min;

use ratatui::{
layout::{Constraint, Flex, Layout, Rect},
text::Line,
widgets::{Block, List, ListItem, Padding},
};

const BIND_LIST: [&str; 11] = [
"m - Toggle this help popup",
"↑ or j - Select previous task",
"↓ or k - Select next task",
"h - Toggle task list",
"/ - Filter tasks to search term",
"ESC - Clear filter",
"i - Interact with task",
"Ctrl+z - Stop interacting with task",
"c - Copy logs selection (Only when logs are selected)",
"Ctrl+n - Scroll logs up",
"Ctrl+p - Scroll logs down",
];

pub fn popup_area(area: Rect) -> Rect {
let screen_width = area.width;
let screen_height = area.height;

let popup_width = BIND_LIST
.iter()
.map(|s| s.len().saturating_add(4))
.max()
.unwrap_or(0) as u16;
let popup_height = min((BIND_LIST.len().saturating_add(4)) as u16, screen_height);

let x = screen_width.saturating_sub(popup_width) / 2;
let y = screen_height.saturating_sub(popup_height) / 2;

let vertical = Layout::vertical([Constraint::Percentage(100)]).flex(Flex::Center);
let horizontal = Layout::horizontal([Constraint::Percentage(100)]).flex(Flex::Center);

let [vertical_area] = vertical.areas(Rect {
x,
y,
width: popup_width,
height: popup_height,
});

let [area] = horizontal.areas(vertical_area);

area
}

pub fn popup(area: Rect) -> List<'static> {
let available_height = area.height.saturating_sub(4) as usize;

let items: Vec<ListItem> = BIND_LIST
.iter()
.take(available_height)
.map(|item| ListItem::new(Line::from(*item)))
.collect();

let title_bottom = if available_height < BIND_LIST.len() {
let binds_not_visible = BIND_LIST.len().saturating_sub(available_height);

let pluralize = if binds_not_visible > 1 { "s" } else { "" };
let message = format!(
" {} more bind{}. Make your terminal taller. ",
binds_not_visible, pluralize
);
Line::from(message)
} else {
Line::from("")
};

let outer = Block::bordered()
.title(" Keybinds ")
.title_bottom(title_bottom.to_string())
.padding(Padding::uniform(1));

List::new(items).block(outer)
}
6 changes: 3 additions & 3 deletions crates/turborepo-ui/src/tui/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pub struct TaskTable<'b> {
spinner: SpinnerState,
}

const TASK_NAVIGATE_INSTRUCTIONS: &str = "↑ ↓ to navigate";
const HIDE_INSTRUCTIONS: &str = "h to hide";
const TASK_NAVIGATE_INSTRUCTIONS: &str = "↑ ↓ - Select";
const MORE_BINDS_INSTRUCTIONS: &str = "m - More binds";

impl<'b> TaskTable<'b> {
/// Construct a new table with all of the planned tasks
Expand Down Expand Up @@ -122,7 +122,7 @@ impl<'a> StatefulWidget for &'a TaskTable<'a> {
)
.footer(
vec![Text::styled(
format!("{TASK_NAVIGATE_INSTRUCTIONS}\n{HIDE_INSTRUCTIONS}"),
format!("{TASK_NAVIGATE_INSTRUCTIONS}\n{MORE_BINDS_INSTRUCTIONS}"),
Style::default().add_modifier(Modifier::DIM),
)]
.into_iter()
Expand Down

0 comments on commit 10a57d0

Please sign in to comment.