1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use anyhow::Result;
use crossterm::event::{Event, KeyCode};
use tui::{
backend::Backend,
layout::Rect,
style::Style,
widgets::{Block, Borders, Paragraph},
Frame,
};
use crate::{
common::OverflowText,
model::Command,
storage::{SqliteStorage, USER_CATEGORY},
theme::Theme,
Widget, WidgetOutput,
};
pub struct SaveCommandWidget<'s> {
storage: &'s mut SqliteStorage,
command: String,
description: Option<String>,
current_description: String,
}
impl<'s> SaveCommandWidget<'s> {
pub fn new(storage: &'s mut SqliteStorage, command: String, description: Option<String>) -> Self {
Self {
storage,
command,
description,
current_description: Default::default(),
}
}
fn insert_command(
storage: &mut SqliteStorage,
command: impl Into<String>,
description: impl Into<String>,
) -> Result<WidgetOutput> {
let cmd = command.into();
let mut command = Command::new(USER_CATEGORY, &cmd, description);
Ok(match storage.insert_command(&mut command)? {
true => WidgetOutput::new("Command was saved successfully", cmd),
false => WidgetOutput::new("Command already existed, so it was updated", cmd),
})
}
}
impl<'s> Widget for SaveCommandWidget<'s> {
fn min_height(&self) -> usize {
1
}
fn peek(&mut self) -> Result<Option<WidgetOutput>> {
match &self.description {
Some(d) => Ok(Some(Self::insert_command(self.storage, &self.command, d)?)),
None => Ok(None),
}
}
fn render<B: Backend>(&mut self, frame: &mut Frame<B>, area: Rect, inline: bool, theme: Theme) {
let max_width = area.width as usize - 1 - (2 * (!inline as usize));
let text_inline = format!("Description: {}", self.current_description);
let description_text = if inline {
OverflowText::new(max_width, &text_inline)
} else {
OverflowText::new(max_width, &self.current_description)
};
let description_text_width = description_text.width() as u16;
let mut description_input = Paragraph::new(description_text).style(Style::default().fg(theme.main));
if !inline {
description_input = description_input.block(Block::default().borders(Borders::ALL).title(" Description "));
}
frame.render_widget(description_input, area);
frame.set_cursor(
area.x + description_text_width + (!inline as u16),
area.y + (!inline as u16),
);
}
fn process_event(&mut self, event: Event) -> Result<Option<WidgetOutput>> {
if let Event::Key(key) = event {
match key.code {
KeyCode::Enter | KeyCode::Tab => {
if !self.current_description.is_empty() {
return Ok(Some(Self::insert_command(
self.storage,
&self.command,
&self.current_description,
)?));
}
}
KeyCode::Char(c) => {
self.current_description.push(c);
}
KeyCode::Backspace => {
self.current_description.pop();
}
KeyCode::Esc => {
return Ok(Some(WidgetOutput::output(self.command.clone())));
}
_ => (),
}
}
Ok(None)
}
}