Skip to content

Commit 2fefabd

Browse files
committed
Clean up cmd_wrapper.rs
1 parent 008d781 commit 2fefabd

File tree

9 files changed

+272
-149
lines changed

9 files changed

+272
-149
lines changed

TODO

+5-2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@
6060
✔ figure out how to create VDOM like result -> CommandQueue @done(22-06-19 18:44)
6161
✔ rename Draw -> Render @done(22-06-20 15:35)
6262
✔ accomodate Render returning CommandQueue @done(22-06-20 15:35)
63-
☐ app.rs render the state using CommandQueue (and crossterm commands)
64-
☐ main_container.rs actually flush CommandQueue in MySubscriber
63+
✔ app.rs render the state using CommandQueue (and crossterm commands) @done(22-06-21 17:51)
64+
✔ main_container.rs actually flush CommandQueue in MySubscriber @done(22-06-2118:33)
65+
✔ do initial render in event loop @done(22-06-21 19:04)
66+
✔ fix bug in app.rs that doesn't capture first input_event @done(22-06-21 18:52)
67+
✔ fix the fix above (flaky) - flush both stdin & stdout @done(22-06-22 12:45)
6568
☐ add layout from test_canvas.rs into app.rs
6669
☐ add all the crossterm commands to Command
6770
focus mgmt:

log.fish

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
#!/usr/bin/env fish
22
clear
3+
rm log.txt
4+
touch log.txt
35
tail -f log.txt | lolcat

src/crossterm_helpers/cmd_wrapper.rs

+113-78
Original file line numberDiff line numberDiff line change
@@ -17,61 +17,63 @@
1717

1818
use crate::*;
1919
use crossterm::{
20-
cursor::{self},
20+
cursor::{self, *},
2121
event::*,
22-
queue,
22+
style::{self, *},
2323
terminal::{self, *},
24+
*,
2425
};
25-
use paste::paste;
2626
use r3bl_rs_utils::*;
27-
use std::io::{stdout, Write};
27+
use std::{
28+
fmt::Display,
29+
io::{stderr, stdout, Write},
30+
};
2831

2932
/// Given a crossterm command, this will run it and [log!] the [Result] that is returned.
3033
/// If [log!] fails, then it will print a message to stderr.
3134
///
3235
/// Paste docs: https://github.com/dtolnay/paste
3336
#[macro_export]
34-
macro_rules! try_to_run_crossterm_command_and_log_result {
35-
($cmd: expr, $name: expr) => {{
36-
paste! {
37-
// Generate a new function that returns [CommonResult].
38-
let [<_ $name>] = || -> CommonResult<()> {
39-
throws!({
40-
if let Err(err) = $cmd {
41-
log!(ERROR, "crossterm: ❌ Failed to {} due to {}", $name, err);
42-
} else {
43-
log!(INFO, "crossterm: ✅ {} successfully", $name);
44-
}
45-
})
46-
};
37+
macro_rules! exec {
38+
($cmd: expr, $msg: expr) => {{
39+
// Generate a new function that returns [CommonResult].
40+
let _new_fn_name = || -> CommonResult<()> {
41+
throws!({
42+
if let Err(err) = $cmd {
43+
log!(ERROR, "crossterm: ❌ Failed to {} due to {}", $msg, err);
44+
} else {
45+
log!(INFO, "crossterm: ✅ {} successfully", $msg);
46+
}
47+
})
48+
};
4749

48-
// Call this generated function. It will fail if there are problems w/ log!().
49-
// In this case, if DEBUG is true, then it will dump the error to stderr.
50-
if let Err(err) = [<_ $name>]() {
51-
let msg = format!("❌ Failed to {}", $name);
52-
call_if_true!(DEBUG,
53-
debug!(ERROR_RAW &msg, err)
54-
);
55-
}
50+
// Call this generated function. It will fail if there are problems w/ log!().
51+
// In this case, if DEBUG is true, then it will dump the error to stderr.
52+
if let Err(err) = _new_fn_name() {
53+
let msg = format!("❌ Failed to {}", $msg);
54+
call_if_true!(DEBUG, debug!(ERROR_RAW & msg, err));
5655
}
5756
}};
5857
}
5958

60-
/// This works together w/ [Command] to enqueue commands, and then flush them at the end.
61-
/// Here's an example.
59+
/// This works together w/ [Command] to enqueue commands, but not flush them. It will
60+
/// return a [CommandQueue]. Here's an example.
61+
///
6262
/// ```ignore
63-
/// queue_and_flush!(
63+
/// let mut queue = queue!(
6464
/// Command::EnableRawMode,
6565
/// Command::EnableMouseCapture,
6666
/// Command::EnterAlternateScreen,
6767
/// Command::ResetCursorPosition,
6868
/// Command::ClearScreen
6969
/// );
7070
/// ```
71-
/// Decl macro docs: https://veykril.github.io/tlborm/decl-macros/macros-methodical.html#repetitions
71+
///
72+
/// Decl macro docs:
73+
/// - https://veykril.github.io/tlborm/decl-macros/macros-methodical.html#repetitions
7274
#[macro_export]
73-
macro_rules! queue_and_flush {
74-
(
75+
macro_rules! tw_queue {
76+
(
7577
// Start a repetition:
7678
$(
7779
// Each repeat must contain an expression...
@@ -92,14 +94,14 @@ macro_rules! queue_and_flush {
9294
// $element replaced with the corresponding expression.
9395
queue.add($element);
9496
)*
95-
queue.flush();
97+
queue
9698
}
9799
};
98100
}
99101

100102
#[derive(Debug)]
101103
#[non_exhaustive]
102-
pub enum Command {
104+
pub enum TWCommand {
103105
EnableRawMode,
104106
EnableMouseCapture,
105107
EnterAlternateScreen,
@@ -108,6 +110,19 @@ pub enum Command {
108110
DisableMouseCapture,
109111
MoveCursorPosition(UnitType, UnitType),
110112
ClearScreen,
113+
SetFgColor(Color),
114+
SetBgColor(Color),
115+
ResetColor,
116+
Print(String),
117+
CursorShow,
118+
CursorHide,
119+
}
120+
121+
impl TWCommand {
122+
pub fn flush() {
123+
exec!(stdout().flush(), "flush stdout");
124+
exec!(stderr().flush(), "flush stderr");
125+
}
111126
}
112127

113128
/// This works w/ [Command] items. It allows them to be added in sequence, and then
@@ -123,58 +138,78 @@ pub enum Command {
123138
/// ```
124139
#[derive(Default, Debug)]
125140
pub struct CommandQueue {
126-
pub queue: Vec<Command>,
141+
pub queue: Vec<TWCommand>,
142+
}
143+
144+
impl Display for CommandQueue {
145+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146+
write!(f, "{:?}", self)
147+
}
127148
}
128149

129150
impl CommandQueue {
130-
pub fn add(&mut self, cmd_wrapper: Command) {
151+
pub fn add(&mut self, cmd_wrapper: TWCommand) {
131152
self.queue.push(cmd_wrapper);
132153
}
133154

134155
pub fn flush(&mut self) {
135-
for cmd_wrapper in &mut self.queue {
136-
match cmd_wrapper {
137-
Command::EnableRawMode => try_to_run_crossterm_command_and_log_result! {
138-
terminal::enable_raw_mode(),
139-
"enable_raw_mode"
140-
},
141-
Command::EnableMouseCapture => try_to_run_crossterm_command_and_log_result! {
142-
queue!(stdout(), EnableMouseCapture),
143-
"enable_mouse_capture"
144-
},
145-
Command::EnterAlternateScreen => try_to_run_crossterm_command_and_log_result! {
146-
queue!(stdout(), EnterAlternateScreen),
147-
"enter_alternate_screen"
148-
},
149-
Command::LeaveAlternateScreen => try_to_run_crossterm_command_and_log_result! {
150-
queue!(stdout(), LeaveAlternateScreen),
151-
"leave_alternate_screen"
152-
},
153-
Command::DisableRawMode => try_to_run_crossterm_command_and_log_result! {
154-
terminal::disable_raw_mode(),
155-
"disable_raw_mode"
156-
},
157-
Command::DisableMouseCapture => try_to_run_crossterm_command_and_log_result! {
158-
queue!(stdout(), DisableMouseCapture) ,
159-
"disable_mouse_mode"
160-
},
161-
Command::MoveCursorPosition(first, second) => {
162-
let msg = format!("move_to: {}, {}", first, second);
163-
try_to_run_crossterm_command_and_log_result! {
164-
queue!(stdout(), cursor::MoveTo(*first, *second)),
165-
msg
166-
}
167-
}
168-
Command::ClearScreen => try_to_run_crossterm_command_and_log_result! {
169-
queue!(stdout(), terminal::Clear(ClearType::All)),
170-
"clear_screen"
171-
},
172-
};
173-
}
156+
self.queue.iter().for_each(|cmd_wrapper| match cmd_wrapper {
157+
TWCommand::EnableRawMode => {
158+
exec!(terminal::enable_raw_mode(), "EnableRawMode")
159+
}
160+
TWCommand::EnableMouseCapture => {
161+
exec!(queue!(stdout(), EnableMouseCapture), "EnableMouseCapture")
162+
}
163+
TWCommand::EnterAlternateScreen => {
164+
exec!(queue!(stdout(), EnterAlternateScreen), "EnterAlternateScreen")
165+
}
166+
TWCommand::LeaveAlternateScreen => {
167+
exec!(queue!(stdout(), LeaveAlternateScreen), "LeaveAlternateScreen")
168+
}
169+
TWCommand::DisableRawMode => {
170+
exec!(terminal::disable_raw_mode(), "DisableRawMode")
171+
}
172+
TWCommand::DisableMouseCapture => {
173+
exec!(queue!(stdout(), DisableMouseCapture), "DisableMouseCapture")
174+
}
175+
TWCommand::MoveCursorPosition(first, second) => {
176+
exec!(
177+
queue!(stdout(), cursor::MoveTo(*first, *second)),
178+
format!("MoveCursorPosition({}, {})", first, second)
179+
)
180+
}
181+
TWCommand::ClearScreen => {
182+
exec!(queue!(stdout(), terminal::Clear(ClearType::All)), "ClearScreen")
183+
}
184+
TWCommand::SetFgColor(color) => {
185+
exec!(
186+
queue!(stdout(), style::SetForegroundColor(*color)),
187+
format!("SetFgColor({:?})", color)
188+
)
189+
}
190+
TWCommand::SetBgColor(color) => {
191+
exec!(
192+
queue!(stdout(), style::SetBackgroundColor(*color)),
193+
format!("SetBgColor({:?})", color)
194+
)
195+
}
196+
TWCommand::ResetColor => {
197+
exec!(queue!(stdout(), style::ResetColor), "ResetColor")
198+
}
199+
TWCommand::Print(content) => {
200+
exec!(
201+
queue!(stdout(), style::Print(content.clone())),
202+
format!("Print({:?})", content)
203+
)
204+
}
205+
TWCommand::CursorShow => {
206+
exec!(queue!(stdout(), Show), "CursorShow")
207+
}
208+
TWCommand::CursorHide => {
209+
exec!(queue!(stdout(), Hide), "CursorHide")
210+
}
211+
});
174212

175-
try_to_run_crossterm_command_and_log_result! {
176-
stdout().flush(),
177-
"flush"
178-
}
213+
TWCommand::flush();
179214
}
180215
}

src/crossterm_helpers/raw_mode.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,27 @@ pub struct RawMode;
7373

7474
impl RawMode {
7575
pub fn start() -> Self {
76-
queue_and_flush!(
77-
Command::EnableRawMode,
78-
Command::EnableMouseCapture,
79-
Command::EnterAlternateScreen,
80-
Command::MoveCursorPosition(0, 0),
81-
Command::ClearScreen
82-
);
76+
tw_queue!(
77+
TWCommand::EnableRawMode,
78+
TWCommand::EnableMouseCapture,
79+
TWCommand::EnterAlternateScreen,
80+
TWCommand::MoveCursorPosition(0, 0),
81+
TWCommand::ClearScreen,
82+
TWCommand::CursorHide
83+
)
84+
.flush();
8385
RawMode
8486
}
8587
}
8688

8789
impl Drop for RawMode {
8890
fn drop(&mut self) {
89-
queue_and_flush!(
90-
Command::LeaveAlternateScreen,
91-
Command::DisableMouseCapture,
92-
Command::DisableRawMode
93-
);
91+
tw_queue!(
92+
TWCommand::CursorShow,
93+
TWCommand::LeaveAlternateScreen,
94+
TWCommand::DisableMouseCapture,
95+
TWCommand::DisableRawMode
96+
)
97+
.flush();
9498
}
9599
}

0 commit comments

Comments
 (0)