implement help compoment

pull/32/head
Takayuki Maeda 3 years ago
parent c768ffd461
commit bf404dad55

10
Cargo.lock generated

@ -532,6 +532,7 @@ dependencies = [
"database-tree",
"easy-cast",
"futures",
"itertools",
"regex",
"serde",
"serde_json",
@ -615,6 +616,15 @@ dependencies = [
"libc",
]
[[package]]
name = "itertools"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.7"

@ -33,6 +33,8 @@ database-tree = { path = "./database-tree", version = "0.1" }
easy-cast = "0.4"
copypasta = { version = "0.7.0", default-features = false }
async-trait = "0.1.50"
itertools = "0.10.0"
[target.'cfg(any(target_os = "macos", windows))'.dependencies]
copypasta = { version = "0.7.0", default-features = false }

@ -1,14 +1,14 @@
use crate::clipboard::Clipboard;
use crate::components::Component as _;
use crate::components::DrawableComponent as _;
use crate::components::EventState;
use crate::components::{
CommandInfo, CommandText, Component as _, DrawableComponent as _, EventState,
};
use crate::event::Key;
use crate::utils::{MySqlPool, Pool};
use crate::{
components::tab::Tab,
components::{
ConnectionsComponent, DatabasesComponent, ErrorComponent, RecordTableComponent,
TabComponent, TableComponent, TableStatusComponent,
ConnectionsComponent, DatabasesComponent, ErrorComponent, HelpComponent,
RecordTableComponent, TabComponent, TableComponent, TableStatusComponent,
},
user_config::UserConfig,
};
@ -29,6 +29,7 @@ pub struct App {
structure_table: TableComponent,
focus: Focus,
tab: TabComponent,
help: HelpComponent,
databases: DatabasesComponent,
connections: ConnectionsComponent,
table_status: TableStatusComponent,
@ -45,6 +46,7 @@ impl Default for App {
structure_table: TableComponent::default(),
focus: Focus::DabataseList,
tab: TabComponent::default(),
help: HelpComponent::new(),
user_config: None,
databases: DatabasesComponent::new(),
connections: ConnectionsComponent::default(),
@ -58,7 +60,7 @@ impl Default for App {
impl App {
pub fn new(user_config: UserConfig) -> App {
App {
Self {
user_config: Some(user_config.clone()),
connections: ConnectionsComponent::new(user_config.conn),
focus: Focus::ConnectionList,
@ -110,10 +112,53 @@ impl App {
}
}
self.error.draw(f, Rect::default(), false)?;
self.help.draw(f, Rect::default(), false)?;
Ok(())
}
fn update_commands(&mut self) {
self.help.set_cmds(self.commands());
}
fn commands(&self) -> Vec<CommandInfo> {
let mut res = Vec::new();
res.push(CommandInfo::new(
crate::components::command::move_left("h"),
true,
true,
));
res.push(CommandInfo::new(
crate::components::command::move_down("j"),
true,
true,
));
res.push(CommandInfo::new(
crate::components::command::move_up("k"),
true,
true,
));
res.push(CommandInfo::new(
crate::components::command::move_right("l"),
true,
true,
));
res.push(CommandInfo::new(
crate::components::command::filter("/"),
true,
true,
));
res
}
pub async fn event(&mut self, key: Key) -> anyhow::Result<EventState> {
self.update_commands();
if let Key::Esc = key {
if self.error.error.is_some() {
self.error.error = None;
@ -284,6 +329,9 @@ impl App {
}
pub fn move_focus(&mut self, key: Key) -> anyhow::Result<EventState> {
if self.help.event(key)?.is_consumed() {
return Ok(EventState::Consumed);
}
if let Key::Char('c') = key {
self.focus = Focus::ConnectionList;
return Ok(EventState::Consumed);

@ -1,3 +1,5 @@
static CMD_GROUP_GENERAL: &str = "-- General --";
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq)]
pub struct CommandText {
pub name: String,
@ -5,6 +7,18 @@ pub struct CommandText {
pub group: &'static str,
pub hide_help: bool,
}
impl CommandText {
pub const fn new(name: String, desc: &'static str, group: &'static str) -> Self {
Self {
name,
desc,
group,
hide_help: false,
}
}
}
pub struct CommandInfo {
pub text: CommandText,
pub enabled: bool,
@ -12,3 +26,57 @@ pub struct CommandInfo {
pub available: bool,
pub order: i8,
}
impl CommandInfo {
pub const fn new(text: CommandText, enabled: bool, available: bool) -> Self {
Self {
text,
enabled,
quick_bar: true,
available,
order: 0,
}
}
pub const fn order(self, order: i8) -> Self {
let mut res = self;
res.order = order;
res
}
}
pub fn move_down(key: &str) -> CommandText {
CommandText::new(
format!("Move down [{}]", key),
"move down",
CMD_GROUP_GENERAL,
)
}
pub fn move_up(key: &str) -> CommandText {
CommandText::new(format!("Move up [{}]", key), "move up", CMD_GROUP_GENERAL)
}
pub fn move_right(key: &str) -> CommandText {
CommandText::new(
format!("Move right [{}]", key),
"move right",
CMD_GROUP_GENERAL,
)
}
pub fn move_left(key: &str) -> CommandText {
CommandText::new(
format!("Move left [{}]", key),
"move left",
CMD_GROUP_GENERAL,
)
}
pub fn filter(key: &str) -> CommandText {
CommandText::new(
format!("Filter [{}]", key),
"enter input for filter",
CMD_GROUP_GENERAL,
)
}

@ -1,4 +1,5 @@
use super::{Component, DrawableComponent, EventState};
use crate::components::command::CommandInfo;
use crate::event::Key;
use crate::user_config::Connection;
use anyhow::Result;
@ -99,6 +100,8 @@ impl DrawableComponent for ConnectionsComponent {
}
impl Component for ConnectionsComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, key: Key) -> Result<EventState> {
match key {
Key::Char('j') => {

@ -2,6 +2,7 @@ use super::{
compute_character_width, utils::scroll_vertical::VerticalScroll, Component, DrawableComponent,
EventState,
};
use crate::components::command::CommandInfo;
use crate::event::Key;
use crate::ui::common_nav;
use crate::ui::scrolllist::draw_list_block;
@ -202,6 +203,8 @@ impl DrawableComponent for DatabasesComponent {
}
impl Component for DatabasesComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, key: Key) -> Result<EventState> {
let input_str: String = self.input.iter().collect();
if tree_nav(

@ -1,4 +1,5 @@
use super::{Component, DrawableComponent, EventState};
use crate::components::command::CommandInfo;
use crate::event::Key;
use anyhow::Result;
use tui::{
@ -49,6 +50,8 @@ impl DrawableComponent for ErrorComponent {
}
impl Component for ErrorComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, _key: Key) -> Result<EventState> {
Ok(EventState::NotConsumed)
}

@ -0,0 +1,134 @@
use super::{Component, DrawableComponent, EventState};
use crate::components::command::CommandInfo;
use crate::event::Key;
use anyhow::Result;
use itertools::Itertools;
use std::convert::From;
use tui::{
backend::Backend,
layout::{Alignment, Constraint, Direction, Layout, Rect},
style::{Modifier, Style},
text::{Span, Spans},
widgets::{Block, BorderType, Borders, Clear, Paragraph},
Frame,
};
pub struct HelpComponent {
cmds: Vec<CommandInfo>,
visible: bool,
selection: u16,
}
impl DrawableComponent for HelpComponent {
fn draw<B: Backend>(&mut self, f: &mut Frame<B>, _area: Rect, _focused: bool) -> Result<()> {
if self.visible {
const SIZE: (u16, u16) = (65, 24);
let area = Rect::new(
(f.size().width.saturating_sub(SIZE.0)) / 2,
(f.size().height.saturating_sub(SIZE.1)) / 2,
SIZE.0.min(f.size().width),
SIZE.1.min(f.size().height),
);
let scroll = 0;
f.render_widget(Clear, area);
f.render_widget(
Block::default()
.title("Help")
.borders(Borders::ALL)
.border_type(BorderType::Thick),
area,
);
let chunks = Layout::default()
.vertical_margin(1)
.horizontal_margin(1)
.direction(Direction::Vertical)
.constraints([Constraint::Min(1), Constraint::Length(1)].as_ref())
.split(area);
f.render_widget(
Paragraph::new(self.get_text()).scroll((scroll, 0)),
chunks[0],
);
f.render_widget(
Paragraph::new(Spans::from(vec![Span::styled(
format!("gobang {}", "0.1.0"),
Style::default(),
)]))
.alignment(Alignment::Right),
chunks[1],
);
}
Ok(())
}
}
impl Component for HelpComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, key: Key) -> Result<EventState> {
if self.visible {
if let Key::Esc = key {
self.hide();
return Ok(EventState::Consumed);
}
return Ok(EventState::NotConsumed);
} else if let Key::Char('?') = key {
self.show()?;
return Ok(EventState::Consumed);
}
Ok(EventState::NotConsumed)
}
fn hide(&mut self) {
self.visible = false;
}
fn show(&mut self) -> Result<()> {
self.visible = true;
Ok(())
}
}
impl HelpComponent {
pub const fn new() -> Self {
Self {
cmds: vec![],
visible: false,
selection: 0,
}
}
pub fn set_cmds(&mut self, cmds: Vec<CommandInfo>) {
self.cmds = cmds
.into_iter()
.filter(|e| !e.text.hide_help)
.collect::<Vec<_>>();
}
fn get_text(&self) -> Vec<Spans> {
let mut txt: Vec<Spans> = Vec::new();
for (key, group) in &self.cmds.iter().group_by(|e| e.text.group) {
txt.push(Spans::from(Span::styled(
key.to_string(),
Style::default().add_modifier(Modifier::REVERSED),
)));
for command_info in group {
txt.push(Spans::from(Span::styled(
format!("{}", command_info.text.name),
Style::default(),
)));
}
}
txt
}
}

@ -2,6 +2,7 @@ pub mod command;
pub mod connections;
pub mod databases;
pub mod error;
pub mod help;
pub mod record_table;
pub mod tab;
pub mod table;
@ -14,6 +15,7 @@ pub use command::{CommandInfo, CommandText};
pub use connections::ConnectionsComponent;
pub use databases::DatabasesComponent;
pub use error::ErrorComponent;
pub use help::HelpComponent;
pub use record_table::RecordTableComponent;
pub use tab::TabComponent;
pub use table::TableComponent;
@ -72,6 +74,8 @@ pub trait DrawableComponent {
/// base component trait
#[async_trait]
pub trait Component {
fn commands(&self, out: &mut Vec<CommandInfo>);
fn event(&mut self, key: crate::event::Key) -> Result<EventState>;
fn focused(&self) -> bool {

@ -1,4 +1,5 @@
use super::{Component, DrawableComponent, EventState};
use crate::components::command::CommandInfo;
use crate::components::{TableComponent, TableFilterComponent};
use crate::event::Key;
use anyhow::Result;
@ -85,6 +86,8 @@ impl DrawableComponent for RecordTableComponent {
}
impl Component for RecordTableComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, key: Key) -> Result<EventState> {
match key {
Key::Char('/') => {

@ -1,4 +1,5 @@
use super::{Component, DrawableComponent, EventState};
use crate::components::command::CommandInfo;
use crate::event::Key;
use anyhow::Result;
use strum::IntoEnumIterator;
@ -62,6 +63,8 @@ impl DrawableComponent for TabComponent {
}
impl Component for TabComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, key: Key) -> Result<EventState> {
match key {
Key::Char('1') => {

@ -2,6 +2,7 @@ use super::{
utils::scroll_vertical::VerticalScroll, Component, DrawableComponent, EventState,
TableValueComponent,
};
use crate::components::command::CommandInfo;
use crate::event::Key;
use anyhow::Result;
use std::convert::From;
@ -447,6 +448,8 @@ impl DrawableComponent for TableComponent {
}
impl Component for TableComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, key: Key) -> Result<EventState> {
match key {
Key::Char('h') => {

@ -1,4 +1,5 @@
use super::{compute_character_width, Component, DrawableComponent, EventState};
use crate::components::command::CommandInfo;
use crate::event::Key;
use anyhow::Result;
use tui::{
@ -78,6 +79,8 @@ impl DrawableComponent for TableFilterComponent {
}
impl Component for TableFilterComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, key: Key) -> Result<EventState> {
let input_str: String = self.input.iter().collect();
match key {

@ -1,4 +1,5 @@
use super::{Component, DrawableComponent, EventState};
use crate::components::command::CommandInfo;
use crate::event::Key;
use anyhow::Result;
use database_tree::Table;
@ -85,6 +86,8 @@ impl DrawableComponent for TableStatusComponent {
}
impl Component for TableStatusComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, _key: Key) -> Result<EventState> {
Ok(EventState::NotConsumed)
}

@ -1,4 +1,5 @@
use super::{Component, DrawableComponent, EventState};
use crate::components::command::CommandInfo;
use crate::event::Key;
use anyhow::Result;
use tui::{
@ -45,6 +46,8 @@ impl DrawableComponent for TableValueComponent {
}
impl Component for TableValueComponent {
fn commands(&self, out: &mut Vec<CommandInfo>) {}
fn event(&mut self, _key: Key) -> Result<EventState> {
todo!("scroll");
}

Loading…
Cancel
Save