17
17
18
18
use crate :: * ;
19
19
use crossterm:: {
20
- cursor:: { self } ,
20
+ cursor:: { self , * } ,
21
21
event:: * ,
22
- queue ,
22
+ style :: { self , * } ,
23
23
terminal:: { self , * } ,
24
+ * ,
24
25
} ;
25
- use paste:: paste;
26
26
use r3bl_rs_utils:: * ;
27
- use std:: io:: { stdout, Write } ;
27
+ use std:: {
28
+ fmt:: Display ,
29
+ io:: { stderr, stdout, Write } ,
30
+ } ;
28
31
29
32
/// Given a crossterm command, this will run it and [log!] the [Result] that is returned.
30
33
/// If [log!] fails, then it will print a message to stderr.
31
34
///
32
35
/// Paste docs: https://github.com/dtolnay/paste
33
36
#[ 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
+ } ;
47
49
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) ) ;
56
55
}
57
56
} } ;
58
57
}
59
58
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
+ ///
62
62
/// ```ignore
63
- /// queue_and_flush !(
63
+ /// let mut queue = queue !(
64
64
/// Command::EnableRawMode,
65
65
/// Command::EnableMouseCapture,
66
66
/// Command::EnterAlternateScreen,
67
67
/// Command::ResetCursorPosition,
68
68
/// Command::ClearScreen
69
69
/// );
70
70
/// ```
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
72
74
#[ macro_export]
73
- macro_rules! queue_and_flush {
74
- (
75
+ macro_rules! tw_queue {
76
+ (
75
77
// Start a repetition:
76
78
$(
77
79
// Each repeat must contain an expression...
@@ -92,14 +94,14 @@ macro_rules! queue_and_flush {
92
94
// $element replaced with the corresponding expression.
93
95
queue. add( $element) ;
94
96
) *
95
- queue. flush ( ) ;
97
+ queue
96
98
}
97
99
} ;
98
100
}
99
101
100
102
#[ derive( Debug ) ]
101
103
#[ non_exhaustive]
102
- pub enum Command {
104
+ pub enum TWCommand {
103
105
EnableRawMode ,
104
106
EnableMouseCapture ,
105
107
EnterAlternateScreen ,
@@ -108,6 +110,19 @@ pub enum Command {
108
110
DisableMouseCapture ,
109
111
MoveCursorPosition ( UnitType , UnitType ) ,
110
112
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
+ }
111
126
}
112
127
113
128
/// This works w/ [Command] items. It allows them to be added in sequence, and then
@@ -123,58 +138,78 @@ pub enum Command {
123
138
/// ```
124
139
#[ derive( Default , Debug ) ]
125
140
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
+ }
127
148
}
128
149
129
150
impl CommandQueue {
130
- pub fn add ( & mut self , cmd_wrapper : Command ) {
151
+ pub fn add ( & mut self , cmd_wrapper : TWCommand ) {
131
152
self . queue . push ( cmd_wrapper) ;
132
153
}
133
154
134
155
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
+ } ) ;
174
212
175
- try_to_run_crossterm_command_and_log_result ! {
176
- stdout( ) . flush( ) ,
177
- "flush"
178
- }
213
+ TWCommand :: flush ( ) ;
179
214
}
180
215
}
0 commit comments