Skip to content

Commit b34dedd

Browse files
author
Stephan Dilly
committed
split commitComponent to have generic reusable textInputComponent
1 parent 37aa67f commit b34dedd

File tree

3 files changed

+146
-58
lines changed

3 files changed

+146
-58
lines changed

src/components/commit.rs

Lines changed: 25 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,27 @@
11
use super::{
2-
visibility_blocking, CommandBlocking, CommandInfo, Component,
3-
DrawableComponent,
2+
textinput::TextInputComponent, visibility_blocking,
3+
CommandBlocking, CommandInfo, Component, DrawableComponent,
44
};
55
use crate::{
6-
components::dialog_paragraph,
76
queue::{InternalEvent, NeedsUpdate, Queue},
8-
strings, ui,
7+
strings,
98
ui::style::Theme,
109
};
1110
use asyncgit::{sync, CWD};
1211
use crossterm::event::{Event, KeyCode};
1312
use log::error;
14-
use std::borrow::Cow;
1513
use strings::commands;
1614
use sync::HookResult;
17-
use tui::{
18-
backend::Backend,
19-
layout::Rect,
20-
style::Style,
21-
widgets::{Clear, Text},
22-
Frame,
23-
};
15+
use tui::{backend::Backend, layout::Rect, Frame};
2416

2517
pub struct CommitComponent {
26-
msg: String,
27-
visible: bool,
18+
input: TextInputComponent,
2819
queue: Queue,
29-
theme: Theme,
3020
}
3121

3222
impl DrawableComponent for CommitComponent {
33-
fn draw<B: Backend>(&mut self, f: &mut Frame<B>, _rect: Rect) {
34-
if self.visible {
35-
let txt = if self.msg.is_empty() {
36-
[Text::Styled(
37-
Cow::from(strings::COMMIT_MSG),
38-
self.theme.text(false, false),
39-
)]
40-
} else {
41-
[Text::Styled(
42-
Cow::from(self.msg.clone()),
43-
Style::default(),
44-
)]
45-
};
46-
47-
let area = ui::centered_rect(60, 20, f.size());
48-
f.render_widget(Clear, area);
49-
f.render_widget(
50-
dialog_paragraph(strings::COMMIT_TITLE, txt.iter()),
51-
area,
52-
);
53-
}
23+
fn draw<B: Backend>(&mut self, f: &mut Frame<B>, rect: Rect) {
24+
self.input.draw(f, rect)
5425
}
5526
}
5627

@@ -63,50 +34,47 @@ impl Component for CommitComponent {
6334
out.push(CommandInfo::new(
6435
commands::COMMIT_ENTER,
6536
self.can_commit(),
66-
self.visible,
37+
self.is_visible(),
6738
));
6839
out.push(CommandInfo::new(
6940
commands::CLOSE_POPUP,
7041
true,
71-
self.visible,
42+
self.is_visible(),
7243
));
7344
visibility_blocking(self)
7445
}
7546

7647
fn event(&mut self, ev: Event) -> bool {
77-
if self.visible {
48+
if self.is_visible() {
49+
if self.input.event(ev) {
50+
return true;
51+
}
52+
7853
if let Event::Key(e) = ev {
7954
match e.code {
80-
KeyCode::Esc => {
81-
self.hide();
82-
}
83-
KeyCode::Char(c) => {
84-
self.msg.push(c);
85-
}
8655
KeyCode::Enter if self.can_commit() => {
8756
self.commit();
8857
}
89-
KeyCode::Backspace if !self.msg.is_empty() => {
90-
self.msg.pop().unwrap();
91-
}
9258
_ => (),
9359
};
60+
61+
// stop key event propagation
9462
return true;
9563
}
9664
}
9765
false
9866
}
9967

10068
fn is_visible(&self) -> bool {
101-
self.visible
69+
self.input.is_visible()
10270
}
10371

10472
fn hide(&mut self) {
105-
self.visible = false
73+
self.input.hide()
10674
}
10775

10876
fn show(&mut self) {
109-
self.visible = true
77+
self.input.show()
11078
}
11179
}
11280

@@ -115,15 +83,14 @@ impl CommitComponent {
11583
pub fn new(queue: Queue, theme: &Theme) -> Self {
11684
Self {
11785
queue,
118-
msg: String::default(),
119-
visible: false,
120-
theme: *theme,
86+
input: TextInputComponent::new(theme),
12187
}
12288
}
12389

12490
fn commit(&mut self) {
91+
let mut msg = self.input.get_text().clone();
12592
if let HookResult::NotOk(e) =
126-
sync::hooks_commit_msg(CWD, &mut self.msg).unwrap()
93+
sync::hooks_commit_msg(CWD, &mut msg).unwrap()
12794
{
12895
error!("commit-msg hook error: {}", e);
12996
self.queue.borrow_mut().push_back(
@@ -135,7 +102,7 @@ impl CommitComponent {
135102
return;
136103
}
137104

138-
if let Err(e) = sync::commit(CWD, &self.msg) {
105+
if let Err(e) = sync::commit(CWD, &msg) {
139106
error!("commit error: {}", &e);
140107
self.queue.borrow_mut().push_back(
141108
InternalEvent::ShowErrorMsg(format!(
@@ -158,7 +125,7 @@ impl CommitComponent {
158125
);
159126
}
160127

161-
self.msg.clear();
128+
self.input.clear();
162129
self.hide();
163130

164131
self.queue
@@ -167,6 +134,6 @@ impl CommitComponent {
167134
}
168135

169136
fn can_commit(&self) -> bool {
170-
!self.msg.is_empty()
137+
!self.input.get_text().is_empty()
171138
}
172139
}

src/components/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod filetree;
66
mod help;
77
mod msg;
88
mod reset;
9+
mod textinput;
910
mod utils;
1011
pub use changes::ChangesComponent;
1112
pub use command::{CommandInfo, CommandText};

src/components/textinput.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
use super::{
2+
visibility_blocking, CommandBlocking, CommandInfo, Component,
3+
DrawableComponent,
4+
};
5+
use crate::{
6+
components::dialog_paragraph, strings, ui, ui::style::Theme,
7+
};
8+
use crossterm::event::{Event, KeyCode};
9+
use std::borrow::Cow;
10+
use strings::commands;
11+
use tui::{
12+
backend::Backend,
13+
layout::Rect,
14+
style::Style,
15+
widgets::{Clear, Text},
16+
Frame,
17+
};
18+
19+
/// primarily a subcomponet for user input of text (used in `CommitComponent`)
20+
pub struct TextInputComponent {
21+
msg: String,
22+
visible: bool,
23+
theme: Theme,
24+
}
25+
26+
impl TextInputComponent {
27+
///
28+
pub fn new(theme: &Theme) -> Self {
29+
Self {
30+
msg: String::default(),
31+
visible: false,
32+
theme: *theme,
33+
}
34+
}
35+
36+
///
37+
pub fn clear(&mut self) {
38+
self.msg.clear();
39+
}
40+
41+
///
42+
pub fn get_text(&self) -> &String {
43+
&self.msg
44+
}
45+
}
46+
47+
impl DrawableComponent for TextInputComponent {
48+
fn draw<B: Backend>(&mut self, f: &mut Frame<B>, _rect: Rect) {
49+
if self.visible {
50+
let txt = if self.msg.is_empty() {
51+
[Text::Styled(
52+
Cow::from(strings::COMMIT_MSG),
53+
self.theme.text(false, false),
54+
)]
55+
} else {
56+
[Text::Styled(
57+
Cow::from(self.msg.clone()),
58+
Style::default(),
59+
)]
60+
};
61+
62+
let area = ui::centered_rect(60, 20, f.size());
63+
f.render_widget(Clear, area);
64+
f.render_widget(
65+
dialog_paragraph(strings::COMMIT_TITLE, txt.iter()),
66+
area,
67+
);
68+
}
69+
}
70+
}
71+
72+
impl Component for TextInputComponent {
73+
fn commands(
74+
&self,
75+
out: &mut Vec<CommandInfo>,
76+
_force_all: bool,
77+
) -> CommandBlocking {
78+
out.push(CommandInfo::new(
79+
commands::CLOSE_POPUP,
80+
true,
81+
self.visible,
82+
));
83+
visibility_blocking(self)
84+
}
85+
86+
fn event(&mut self, ev: Event) -> bool {
87+
if self.visible {
88+
if let Event::Key(e) = ev {
89+
match e.code {
90+
KeyCode::Esc => {
91+
self.hide();
92+
return true;
93+
}
94+
KeyCode::Char(c) => {
95+
self.msg.push(c);
96+
return true;
97+
}
98+
KeyCode::Backspace => {
99+
self.msg.pop();
100+
return true;
101+
}
102+
_ => (),
103+
};
104+
}
105+
}
106+
false
107+
}
108+
109+
fn is_visible(&self) -> bool {
110+
self.visible
111+
}
112+
113+
fn hide(&mut self) {
114+
self.visible = false
115+
}
116+
117+
fn show(&mut self) {
118+
self.visible = true
119+
}
120+
}

0 commit comments

Comments
 (0)