split commitComponent to have generic reusable textInputComponent

This commit is contained in:
Stephan Dilly 2020-05-22 14:33:44 +02:00
parent 37aa67f8a4
commit b34deddb0e
3 changed files with 146 additions and 58 deletions

View file

@ -1,56 +1,27 @@
use super::{ use super::{
visibility_blocking, CommandBlocking, CommandInfo, Component, textinput::TextInputComponent, visibility_blocking,
DrawableComponent, CommandBlocking, CommandInfo, Component, DrawableComponent,
}; };
use crate::{ use crate::{
components::dialog_paragraph,
queue::{InternalEvent, NeedsUpdate, Queue}, queue::{InternalEvent, NeedsUpdate, Queue},
strings, ui, strings,
ui::style::Theme, ui::style::Theme,
}; };
use asyncgit::{sync, CWD}; use asyncgit::{sync, CWD};
use crossterm::event::{Event, KeyCode}; use crossterm::event::{Event, KeyCode};
use log::error; use log::error;
use std::borrow::Cow;
use strings::commands; use strings::commands;
use sync::HookResult; use sync::HookResult;
use tui::{ use tui::{backend::Backend, layout::Rect, Frame};
backend::Backend,
layout::Rect,
style::Style,
widgets::{Clear, Text},
Frame,
};
pub struct CommitComponent { pub struct CommitComponent {
msg: String, input: TextInputComponent,
visible: bool,
queue: Queue, queue: Queue,
theme: Theme,
} }
impl DrawableComponent for CommitComponent { impl DrawableComponent for CommitComponent {
fn draw<B: Backend>(&mut self, f: &mut Frame<B>, _rect: Rect) { fn draw<B: Backend>(&mut self, f: &mut Frame<B>, rect: Rect) {
if self.visible { self.input.draw(f, rect)
let txt = if self.msg.is_empty() {
[Text::Styled(
Cow::from(strings::COMMIT_MSG),
self.theme.text(false, false),
)]
} else {
[Text::Styled(
Cow::from(self.msg.clone()),
Style::default(),
)]
};
let area = ui::centered_rect(60, 20, f.size());
f.render_widget(Clear, area);
f.render_widget(
dialog_paragraph(strings::COMMIT_TITLE, txt.iter()),
area,
);
}
} }
} }
@ -63,34 +34,31 @@ impl Component for CommitComponent {
out.push(CommandInfo::new( out.push(CommandInfo::new(
commands::COMMIT_ENTER, commands::COMMIT_ENTER,
self.can_commit(), self.can_commit(),
self.visible, self.is_visible(),
)); ));
out.push(CommandInfo::new( out.push(CommandInfo::new(
commands::CLOSE_POPUP, commands::CLOSE_POPUP,
true, true,
self.visible, self.is_visible(),
)); ));
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> bool { fn event(&mut self, ev: Event) -> bool {
if self.visible { if self.is_visible() {
if self.input.event(ev) {
return true;
}
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
match e.code { match e.code {
KeyCode::Esc => {
self.hide();
}
KeyCode::Char(c) => {
self.msg.push(c);
}
KeyCode::Enter if self.can_commit() => { KeyCode::Enter if self.can_commit() => {
self.commit(); self.commit();
} }
KeyCode::Backspace if !self.msg.is_empty() => {
self.msg.pop().unwrap();
}
_ => (), _ => (),
}; };
// stop key event propagation
return true; return true;
} }
} }
@ -98,15 +66,15 @@ impl Component for CommitComponent {
} }
fn is_visible(&self) -> bool { fn is_visible(&self) -> bool {
self.visible self.input.is_visible()
} }
fn hide(&mut self) { fn hide(&mut self) {
self.visible = false self.input.hide()
} }
fn show(&mut self) { fn show(&mut self) {
self.visible = true self.input.show()
} }
} }
@ -115,15 +83,14 @@ impl CommitComponent {
pub fn new(queue: Queue, theme: &Theme) -> Self { pub fn new(queue: Queue, theme: &Theme) -> Self {
Self { Self {
queue, queue,
msg: String::default(), input: TextInputComponent::new(theme),
visible: false,
theme: *theme,
} }
} }
fn commit(&mut self) { fn commit(&mut self) {
let mut msg = self.input.get_text().clone();
if let HookResult::NotOk(e) = if let HookResult::NotOk(e) =
sync::hooks_commit_msg(CWD, &mut self.msg).unwrap() sync::hooks_commit_msg(CWD, &mut msg).unwrap()
{ {
error!("commit-msg hook error: {}", e); error!("commit-msg hook error: {}", e);
self.queue.borrow_mut().push_back( self.queue.borrow_mut().push_back(
@ -135,7 +102,7 @@ impl CommitComponent {
return; return;
} }
if let Err(e) = sync::commit(CWD, &self.msg) { if let Err(e) = sync::commit(CWD, &msg) {
error!("commit error: {}", &e); error!("commit error: {}", &e);
self.queue.borrow_mut().push_back( self.queue.borrow_mut().push_back(
InternalEvent::ShowErrorMsg(format!( InternalEvent::ShowErrorMsg(format!(
@ -158,7 +125,7 @@ impl CommitComponent {
); );
} }
self.msg.clear(); self.input.clear();
self.hide(); self.hide();
self.queue self.queue
@ -167,6 +134,6 @@ impl CommitComponent {
} }
fn can_commit(&self) -> bool { fn can_commit(&self) -> bool {
!self.msg.is_empty() !self.input.get_text().is_empty()
} }
} }

View file

@ -6,6 +6,7 @@ mod filetree;
mod help; mod help;
mod msg; mod msg;
mod reset; mod reset;
mod textinput;
mod utils; mod utils;
pub use changes::ChangesComponent; pub use changes::ChangesComponent;
pub use command::{CommandInfo, CommandText}; pub use command::{CommandInfo, CommandText};

120
src/components/textinput.rs Normal file
View file

@ -0,0 +1,120 @@
use super::{
visibility_blocking, CommandBlocking, CommandInfo, Component,
DrawableComponent,
};
use crate::{
components::dialog_paragraph, strings, ui, ui::style::Theme,
};
use crossterm::event::{Event, KeyCode};
use std::borrow::Cow;
use strings::commands;
use tui::{
backend::Backend,
layout::Rect,
style::Style,
widgets::{Clear, Text},
Frame,
};
/// primarily a subcomponet for user input of text (used in `CommitComponent`)
pub struct TextInputComponent {
msg: String,
visible: bool,
theme: Theme,
}
impl TextInputComponent {
///
pub fn new(theme: &Theme) -> Self {
Self {
msg: String::default(),
visible: false,
theme: *theme,
}
}
///
pub fn clear(&mut self) {
self.msg.clear();
}
///
pub fn get_text(&self) -> &String {
&self.msg
}
}
impl DrawableComponent for TextInputComponent {
fn draw<B: Backend>(&mut self, f: &mut Frame<B>, _rect: Rect) {
if self.visible {
let txt = if self.msg.is_empty() {
[Text::Styled(
Cow::from(strings::COMMIT_MSG),
self.theme.text(false, false),
)]
} else {
[Text::Styled(
Cow::from(self.msg.clone()),
Style::default(),
)]
};
let area = ui::centered_rect(60, 20, f.size());
f.render_widget(Clear, area);
f.render_widget(
dialog_paragraph(strings::COMMIT_TITLE, txt.iter()),
area,
);
}
}
}
impl Component for TextInputComponent {
fn commands(
&self,
out: &mut Vec<CommandInfo>,
_force_all: bool,
) -> CommandBlocking {
out.push(CommandInfo::new(
commands::CLOSE_POPUP,
true,
self.visible,
));
visibility_blocking(self)
}
fn event(&mut self, ev: Event) -> bool {
if self.visible {
if let Event::Key(e) = ev {
match e.code {
KeyCode::Esc => {
self.hide();
return true;
}
KeyCode::Char(c) => {
self.msg.push(c);
return true;
}
KeyCode::Backspace => {
self.msg.pop();
return true;
}
_ => (),
};
}
}
false
}
fn is_visible(&self) -> bool {
self.visible
}
fn hide(&mut self) {
self.visible = false
}
fn show(&mut self) {
self.visible = true
}
}