cmd help grouping and long desc

This commit is contained in:
Stephan Dilly 2020-04-03 14:48:41 +02:00
parent f2336d32e1
commit ed5668c4c8
7 changed files with 141 additions and 15 deletions

View file

@ -273,6 +273,7 @@ impl App {
res.push( res.push(
CommandInfo::new( CommandInfo::new(
strings::CMD_STATUS_FOCUS_UNSTAGED, strings::CMD_STATUS_FOCUS_UNSTAGED,
strings::CMD_GROUP_GENERAL,
true, true,
main_cmds_available main_cmds_available
&& focus_on_stage && focus_on_stage
@ -283,6 +284,7 @@ impl App {
res.push( res.push(
CommandInfo::new( CommandInfo::new(
strings::CMD_STATUS_FOCUS_STAGED, strings::CMD_STATUS_FOCUS_STAGED,
strings::CMD_GROUP_GENERAL,
true, true,
main_cmds_available main_cmds_available
&& !focus_on_stage && !focus_on_stage
@ -295,11 +297,13 @@ impl App {
let focus_on_diff = self.focus == Focus::Diff; let focus_on_diff = self.focus == Focus::Diff;
res.push(CommandInfo::new( res.push(CommandInfo::new(
strings::CMD_STATUS_LEFT, strings::CMD_STATUS_LEFT,
strings::CMD_GROUP_GENERAL,
true, true,
main_cmds_available && focus_on_diff, main_cmds_available && focus_on_diff,
)); ));
res.push(CommandInfo::new( res.push(CommandInfo::new(
strings::CMD_STATUS_RIGHT, strings::CMD_STATUS_RIGHT,
strings::CMD_GROUP_GENERAL,
true, true,
main_cmds_available && !focus_on_diff, main_cmds_available && !focus_on_diff,
)); ));
@ -308,6 +312,7 @@ impl App {
res.push( res.push(
CommandInfo::new( CommandInfo::new(
strings::CMD_STATUS_QUIT, strings::CMD_STATUS_QUIT,
strings::CMD_GROUP_GENERAL,
true, true,
main_cmds_available, main_cmds_available,
) )

View file

@ -178,17 +178,20 @@ impl Component for ChangesComponent {
if self.is_working_dir { if self.is_working_dir {
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::CMD_STATUS_STAGE, strings::CMD_STATUS_STAGE,
strings::CMD_GROUP_CHANGES,
some_selection, some_selection,
self.focused, self.focused,
)); ));
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::CMD_STATUS_RESET, strings::CMD_STATUS_RESET,
strings::CMD_GROUP_CHANGES,
some_selection, some_selection,
self.focused, self.focused,
)); ));
} else { } else {
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::CMD_STATUS_UNSTAGE, strings::CMD_STATUS_UNSTAGE,
strings::CMD_GROUP_CHANGES,
some_selection, some_selection,
self.focused, self.focused,
)); ));
@ -196,6 +199,7 @@ impl Component for ChangesComponent {
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::CMD_SCROLL, strings::CMD_SCROLL,
strings::CMD_GROUP_GENERAL,
self.items.len() > 1, self.items.len() > 1,
self.focused, self.focused,
)); ));

View file

@ -3,6 +3,10 @@ pub struct CommandInfo {
/// ///
pub name: String, pub name: String,
/// ///
pub group: String,
///
pub desc: String,
///
// pub keys: // pub keys:
/// available but not active in the context /// available but not active in the context
pub enabled: bool, pub enabled: bool,
@ -16,9 +20,16 @@ pub struct CommandInfo {
impl CommandInfo { impl CommandInfo {
/// ///
pub fn new(name: &str, enabled: bool, available: bool) -> Self { pub fn new(
name: &str,
group: &str,
enabled: bool,
available: bool,
) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
group: group.to_string(),
desc: String::default(),
enabled, enabled,
quick_bar: true, quick_bar: true,
available, available,
@ -32,6 +43,12 @@ impl CommandInfo {
res res
} }
/// ///
pub fn desc(self, txt: &str) -> Self {
let mut res = self;
res.desc = txt.to_string();
res
}
///
pub fn hidden(self) -> Self { pub fn hidden(self) -> Self {
let mut res = self; let mut res = self;
res.quick_bar = false; res.quick_bar = false;

View file

@ -55,16 +55,19 @@ impl Component for CommitComponent {
) -> CommandBlocking { ) -> CommandBlocking {
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::COMMIT_CMD_OPEN, strings::COMMIT_CMD_OPEN,
strings::CMD_GROUP_COMMIT,
!self.stage_empty, !self.stage_empty,
!self.visible, !self.visible,
)); ));
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::COMMIT_CMD_ENTER, strings::COMMIT_CMD_ENTER,
strings::CMD_GROUP_COMMIT,
self.can_commit(), self.can_commit(),
self.visible, self.visible,
)); ));
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::COMMIT_CMD_CLOSE, strings::COMMIT_CMD_CLOSE,
strings::CMD_GROUP_COMMIT,
true, true,
self.visible, self.visible,
)); ));

View file

@ -248,6 +248,7 @@ impl Component for DiffComponent {
) -> CommandBlocking { ) -> CommandBlocking {
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::CMD_SCROLL, strings::CMD_SCROLL,
strings::CMD_GROUP_DIFF,
self.can_scroll(), self.can_scroll(),
self.focused, self.focused,
)); ));

View file

@ -3,11 +3,14 @@ use super::{
DrawableComponent, EventUpdate, DrawableComponent, EventUpdate,
}; };
use crate::{keys, strings, ui}; use crate::{keys, strings, ui};
use asyncgit::hash;
use crossterm::event::Event; use crossterm::event::Event;
use std::borrow::Cow; use itertools::Itertools;
use std::{borrow::Cow, cmp, convert::TryFrom};
use tui::{ use tui::{
backend::Backend, backend::Backend,
layout::{Alignment, Rect}, layout::{Alignment, Rect},
style::{Color, Style},
widgets::{Block, Borders, Paragraph, Text, Widget}, widgets::{Block, Borders, Paragraph, Text, Widget},
Frame, Frame,
}; };
@ -16,21 +19,22 @@ use tui::{
pub struct HelpComponent { pub struct HelpComponent {
cmds: Vec<CommandInfo>, cmds: Vec<CommandInfo>,
visible: bool, visible: bool,
selection: u16,
} }
impl DrawableComponent for HelpComponent { impl DrawableComponent for HelpComponent {
fn draw<B: Backend>(&self, f: &mut Frame<B>, _rect: Rect) { fn draw<B: Backend>(&self, f: &mut Frame<B>, _rect: Rect) {
if self.visible { if self.visible {
let txt = self let (txt, selected_line) = self.get_text();
.cmds
.iter() let height = 24;
.map(|e| { let scroll_threshold = height / 3;
let mut out = String::new();
e.print(&mut out); let scroll = if selected_line > scroll_threshold {
out.push('\n'); self.selection - scroll_threshold
Text::Raw(Cow::from(out)) } else {
}) 0
.collect::<Vec<_>>(); };
ui::Clear::new( ui::Clear::new(
Paragraph::new(txt.iter()) Paragraph::new(txt.iter())
@ -39,9 +43,13 @@ impl DrawableComponent for HelpComponent {
.title(strings::HELP_TITLE) .title(strings::HELP_TITLE)
.borders(Borders::ALL), .borders(Borders::ALL),
) )
.scroll(scroll)
.alignment(Alignment::Left), .alignment(Alignment::Left),
) )
.render(f, ui::centered_rect_absolute(60, 20, f.size())); .render(
f,
ui::centered_rect_absolute(65, height, f.size()),
);
} }
} }
} }
@ -59,14 +67,24 @@ impl Component for HelpComponent {
out.push( out.push(
CommandInfo::new( CommandInfo::new(
strings::CMD_STATUS_HELP, strings::CMD_STATUS_HELP,
strings::CMD_GROUP_GENERAL,
true, true,
!self.visible, !self.visible,
) )
.desc("open this help screen")
.order(99), .order(99),
); );
out.push(CommandInfo::new(
strings::CMD_SCROLL,
strings::CMD_GROUP_GENERAL,
true,
self.visible,
));
out.push(CommandInfo::new( out.push(CommandInfo::new(
strings::COMMIT_CMD_CLOSE, strings::COMMIT_CMD_CLOSE,
strings::CMD_GROUP_GENERAL,
true, true,
self.visible, self.visible,
)); ));
@ -77,8 +95,11 @@ impl Component for HelpComponent {
fn event(&mut self, ev: Event) -> Option<EventUpdate> { fn event(&mut self, ev: Event) -> Option<EventUpdate> {
if self.visible { if self.visible {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if let keys::EXIT_POPUP = e { match e {
self.hide(); keys::EXIT_POPUP => self.hide(),
keys::MOVE_DOWN => self.move_selection(true),
keys::MOVE_UP => self.move_selection(false),
_ => (),
} }
} }
@ -108,5 +129,75 @@ impl HelpComponent {
/// ///
pub fn set_cmds(&mut self, cmds: Vec<CommandInfo>) { pub fn set_cmds(&mut self, cmds: Vec<CommandInfo>) {
self.cmds = cmds; self.cmds = cmds;
self.cmds.sort_by_key(|e| hash(&e.group));
}
fn move_selection(&mut self, inc: bool) {
let mut new_selection = self.selection;
new_selection = if inc {
new_selection.saturating_add(1)
} else {
new_selection.saturating_sub(1)
};
new_selection = cmp::max(new_selection, 0);
if let Ok(max) = u16::try_from(self.cmds.len() - 1) {
self.selection = cmp::min(new_selection, max);
}
}
fn get_text<'a>(&self) -> (Vec<Text<'a>>, u16) {
let mut txt = Vec::new();
let mut processed = 0_u16;
let mut selected_line = 0_u16;
for (key, group) in
&self.cmds.iter().group_by(|e| e.group.clone())
{
txt.push(Text::Styled(
Cow::from(format!(" {}\n", key)),
Style::default().fg(Color::Black).bg(Color::Gray),
));
txt.extend(
group
.into_iter()
.map(|e| {
let is_selected = self.selection == processed;
if is_selected {
selected_line = processed;
}
processed += 1;
let mut out = String::from(if is_selected {
">"
} else {
" "
});
e.print(&mut out);
out.push('\n');
if is_selected {
out.push_str(
format!(" {}\n", e.desc).as_str(),
);
}
let style = if is_selected {
Style::default().fg(Color::Yellow)
} else {
Style::default()
};
Text::Styled(Cow::from(out), style)
})
.collect::<Vec<_>>(),
);
}
(txt, selected_line)
} }
} }

View file

@ -5,6 +5,11 @@ pub static TITLE_INDEX: &str = "Staged Changes [2]";
pub static TAB_STATUS: &str = "Status"; pub static TAB_STATUS: &str = "Status";
pub static TAB_DIVIDER: &str = " | "; pub static TAB_DIVIDER: &str = " | ";
pub static CMD_GROUP_GENERAL: &str = "General";
pub static CMD_GROUP_DIFF: &str = "Diff";
pub static CMD_GROUP_CHANGES: &str = "Changes";
pub static CMD_GROUP_COMMIT: &str = "Commit";
pub static CMD_STATUS_FOCUS_UNSTAGED: &str = "Unstaged [1]"; pub static CMD_STATUS_FOCUS_UNSTAGED: &str = "Unstaged [1]";
pub static CMD_STATUS_FOCUS_STAGED: &str = "Staged [2]"; pub static CMD_STATUS_FOCUS_STAGED: &str = "Staged [2]";
pub static CMD_STATUS_STAGE: &str = "Stage File [enter]"; pub static CMD_STATUS_STAGE: &str = "Stage File [enter]";