use rustc_hash::FxHashMap;
use std::fmt::Display;
use crate::{colors::Colorscheme, mode::Mode};
use ratatui::{
layout::Constraint,
style::{Color, Style},
text::{Line, Span},
widgets::{Cell, Row, Table},
};
#[derive(Debug, Clone)]
pub struct DisplayableKeybindings {
bindings: FxHashMap<DisplayableAction, Vec<String>>,
}
impl DisplayableKeybindings {
pub fn new(bindings: FxHashMap<DisplayableAction, Vec<String>>) -> Self {
Self { bindings }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum DisplayableAction {
ResultsNavigation,
PreviewNavigation,
SelectEntry,
CopyEntryToClipboard,
SendToChannel,
ToggleRemoteControl,
Cancel,
Quit,
ToggleHelpBar,
}
impl Display for DisplayableAction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let action = match self {
DisplayableAction::ResultsNavigation => "Results navigation",
DisplayableAction::PreviewNavigation => "Preview navigation",
DisplayableAction::SelectEntry => "Select entry",
DisplayableAction::CopyEntryToClipboard => {
"Copy entry to clipboard"
}
DisplayableAction::SendToChannel => "Send to channel",
DisplayableAction::ToggleRemoteControl => "Toggle Remote control",
DisplayableAction::Cancel => "Cancel",
DisplayableAction::Quit => "Quit",
DisplayableAction::ToggleHelpBar => "Toggle help bar",
};
write!(f, "{action}")
}
}
pub fn build_keybindings_table<'a>(
keybindings: &'a FxHashMap<Mode, DisplayableKeybindings>,
mode: Mode,
colorscheme: &'a Colorscheme,
) -> Table<'a> {
match mode {
Mode::Channel => build_keybindings_table_for_channel(
&keybindings[&mode],
colorscheme,
),
Mode::RemoteControl => build_keybindings_table_for_channel_selection(
&keybindings[&mode],
colorscheme,
),
Mode::SendToChannel => {
build_keybindings_table_for_channel_transitions(
&keybindings[&mode],
colorscheme,
)
}
}
}
fn build_keybindings_table_for_channel<'a>(
keybindings: &'a DisplayableKeybindings,
colorscheme: &'a Colorscheme,
) -> Table<'a> {
let results_navigation_keys = keybindings
.bindings
.get(&DisplayableAction::ResultsNavigation)
.unwrap();
let results_row = Row::new(build_cells_for_group(
"Results navigation",
results_navigation_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.channel,
));
let preview_navigation_keys = keybindings
.bindings
.get(&DisplayableAction::PreviewNavigation)
.unwrap();
let preview_row = Row::new(build_cells_for_group(
"Preview navigation",
preview_navigation_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.channel,
));
let select_entry_keys = keybindings
.bindings
.get(&DisplayableAction::SelectEntry)
.unwrap();
let select_entry_row = Row::new(build_cells_for_group(
"Select entry",
select_entry_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.channel,
));
let copy_entry_keys = keybindings
.bindings
.get(&DisplayableAction::CopyEntryToClipboard)
.unwrap();
let copy_entry_row = Row::new(build_cells_for_group(
"Copy entry to clipboard",
copy_entry_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.channel,
));
let send_to_channel_keys = keybindings
.bindings
.get(&DisplayableAction::SendToChannel)
.unwrap();
let send_to_channel_row = Row::new(build_cells_for_group(
"Send results to",
send_to_channel_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.channel,
));
let switch_channels_keys = keybindings
.bindings
.get(&DisplayableAction::ToggleRemoteControl)
.unwrap();
let switch_channels_row = Row::new(build_cells_for_group(
"Toggle Remote control",
switch_channels_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.channel,
));
let widths = vec![Constraint::Fill(1), Constraint::Fill(2)];
Table::new(
vec![
results_row,
preview_row,
select_entry_row,
copy_entry_row,
send_to_channel_row,
switch_channels_row,
],
widths,
)
}
fn build_keybindings_table_for_channel_selection<'a>(
keybindings: &'a DisplayableKeybindings,
colorscheme: &'a Colorscheme,
) -> Table<'a> {
let navigation_keys = keybindings
.bindings
.get(&DisplayableAction::ResultsNavigation)
.unwrap();
let results_row = Row::new(build_cells_for_group(
"Browse channels",
navigation_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.remote_control,
));
let select_entry_keys = keybindings
.bindings
.get(&DisplayableAction::SelectEntry)
.unwrap();
let select_entry_row = Row::new(build_cells_for_group(
"Select channel",
select_entry_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.remote_control,
));
let switch_channels_keys = keybindings
.bindings
.get(&DisplayableAction::ToggleRemoteControl)
.unwrap();
let switch_channels_row = Row::new(build_cells_for_group(
"Toggle Remote control",
switch_channels_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.remote_control,
));
Table::new(
vec![results_row, select_entry_row, switch_channels_row],
vec![Constraint::Fill(1), Constraint::Fill(2)],
)
}
fn build_keybindings_table_for_channel_transitions<'a>(
keybindings: &'a DisplayableKeybindings,
colorscheme: &'a Colorscheme,
) -> Table<'a> {
let results_navigation_keys = keybindings
.bindings
.get(&DisplayableAction::ResultsNavigation)
.unwrap();
let results_row = Row::new(build_cells_for_group(
"Browse channels",
results_navigation_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.send_to_channel,
));
let select_entry_keys = keybindings
.bindings
.get(&DisplayableAction::SelectEntry)
.unwrap();
let select_entry_row = Row::new(build_cells_for_group(
"Send to channel",
select_entry_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.send_to_channel,
));
let cancel_keys = keybindings
.bindings
.get(&DisplayableAction::Cancel)
.unwrap();
let cancel_row = Row::new(build_cells_for_group(
"Cancel",
cancel_keys,
colorscheme.help.metadata_field_name_fg,
colorscheme.mode.send_to_channel,
));
Table::new(
vec![results_row, select_entry_row, cancel_row],
vec![Constraint::Fill(1), Constraint::Fill(2)],
)
}
fn build_cells_for_group<'a>(
group_name: &str,
keys: &'a [String],
key_color: Color,
value_color: Color,
) -> Vec<Cell<'a>> {
let mut cells = vec![Cell::from(Span::styled(
group_name.to_owned() + ": ",
Style::default().fg(key_color),
))];
let spans = keys.iter().skip(1).fold(
vec![Span::styled(
keys[0].clone(),
Style::default().fg(value_color),
)],
|mut acc, key| {
acc.push(Span::raw(" / "));
acc.push(Span::styled(
key.to_owned(),
Style::default().fg(value_color),
));
acc
},
);
cells.push(Cell::from(Line::from(spans)));
cells
}