Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tui): popup to list keybinds #9545

Merged
merged 14 commits into from
Dec 11, 2024
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 ratatui::{
backend::{Backend, CrosstermBackend},
layout::{Constraint, Layout},
widgets::TableState,
widgets::{Clear, TableState},
Frame, Terminal,
};
use tokio::{
Expand All @@ -17,6 +17,8 @@
};
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 @@
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,8 @@
task_list_scroll: TableState::default().with_selected(selected_task_index),
selected_task_index,
has_sidebar: true,
has_user_scrolled: has_user_interacted,

Check failure on line 103 in crates/turborepo-ui/src/tui/app.rs

View workflow job for this annotation

GitHub Actions / Rust lints

struct `tui::app::App<W>` has no field named `has_user_scrolled`

Check failure on line 103 in crates/turborepo-ui/src/tui/app.rs

View workflow job for this annotation

GitHub Actions / Turborepo Integration (ubuntu-latest)

struct `App<W>` has no field named `has_user_scrolled`

Check failure on line 103 in crates/turborepo-ui/src/tui/app.rs

View workflow job for this annotation

GitHub Actions / Turborepo Integration (macos-13)

struct `App<W>` has no field named `has_user_scrolled`

Check failure on line 103 in crates/turborepo-ui/src/tui/app.rs

View workflow job for this annotation

GitHub Actions / Turborepo Integration (windows-latest)

struct `App<W>` has no field named `has_user_scrolled`

Check failure on line 103 in crates/turborepo-ui/src/tui/app.rs

View workflow job for this annotation

GitHub Actions / Turborepo rust check

struct `App<W>` has no field named `has_user_scrolled`
anthonyshew marked this conversation as resolved.
Show resolved Hide resolved
showing_help_popup: false,
is_task_selection_pinned: has_user_interacted,
}
}
Expand All @@ -118,6 +123,7 @@
Ok(InputOptions {
focus: &self.section_focus,
has_selection,
is_help_popup_open: self.showing_help_popup,
})
}

Expand Down Expand Up @@ -790,6 +796,9 @@
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 +871,12 @@

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(app.size);
f.render_widget(Clear, area); // Clears background underneath popup
f.render_widget(popup(), 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 @@
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 @@
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,8 @@
KeyCode::Char('n') if key_event.modifiers == KeyModifiers::CONTROL => {
Some(Event::ScrollDown)
}
KeyCode::Char('h') => Some(Event::ToggleSidebar),

Check warning on line 117 in crates/turborepo-ui/src/tui/input.rs

View workflow job for this annotation

GitHub Actions / Rust lints

unreachable pattern

Check warning on line 117 in crates/turborepo-ui/src/tui/input.rs

View workflow job for this annotation

GitHub Actions / Turborepo Integration (ubuntu-latest)

unreachable pattern

Check warning on line 117 in crates/turborepo-ui/src/tui/input.rs

View workflow job for this annotation

GitHub Actions / Turborepo Integration (macos-13)

unreachable pattern

Check warning on line 117 in crates/turborepo-ui/src/tui/input.rs

View workflow job for this annotation

GitHub Actions / Turborepo Integration (windows-latest)

unreachable pattern

Check warning on line 117 in crates/turborepo-ui/src/tui/input.rs

View workflow job for this annotation

GitHub Actions / Turborepo rust check

unreachable pattern
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
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
60 changes: 60 additions & 0 deletions crates/turborepo-ui/src/tui/popup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use ratatui::{
layout::{Constraint, Flex, Layout, Rect},
text::Line,
widgets::{Block, List, ListItem, Padding},
};

use super::size::SizeInfo;

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

pub fn popup_area(area: SizeInfo) -> Rect {
let popup_width = BIND_LIST_ITEMS
.iter()
.map(|s| s.len() + 4)
.max()
.unwrap_or(0) as u16;
let popup_height = (BIND_LIST_ITEMS.len() + 4) as u16;

let screen_width = area.task_list_width() + area.pane_cols();
let screen_height = area.pane_rows();

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

let vertical = Layout::vertical([Constraint::Percentage(100)]).flex(Flex::Center);
let horizontal = Layout::horizontal([Constraint::Percentage(100)]).flex(Flex::Center);
let [area] = vertical.areas(Rect {
x,
y,
width: popup_width,
height: popup_height,
});
let [area] = horizontal.areas(area);
area
}

pub fn popup() -> List<'static> {
let outer = Block::bordered()
.title(" Keybinds ")
.padding(Padding::uniform(1));

List::new(
BIND_LIST_ITEMS
.into_iter()
.map(|item| ListItem::new(Line::from(item))),
)
.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
Loading