mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 09:28:21 +00:00
cmd help grouping and long desc
This commit is contained in:
parent
f2336d32e1
commit
ed5668c4c8
7 changed files with 141 additions and 15 deletions
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue