1- use crossterm:: {
2- execute,
3- style,
4- } ;
1+ use crossterm:: { execute, style} ;
52
6- use crate :: protocol:: Event ;
3+ use crate :: protocol:: { Event , LegacyPassThroughOutput } ;
74
85#[ derive( thiserror:: Error , Debug ) ]
96pub enum ConduitError {
@@ -33,37 +30,58 @@ impl ViewEnd {
3330 /// Method to facilitate in the interim
3431 /// It takes possible messages from the old even loop and queues write to the output provided
3532 /// This blocks the current thread and consumes the [ViewEnd]
36- pub fn into_legacy_mode ( self , mut output : impl std:: io:: Write ) -> Result < ( ) , ConduitError > {
33+ pub fn into_legacy_mode (
34+ self ,
35+ mut stderr : std:: io:: Stderr ,
36+ mut stdout : std:: io:: Stdout ,
37+ ) -> Result < ( ) , ConduitError > {
3738 while let Ok ( event) = self . receiver . recv ( ) {
38- let content = match event {
39- Event :: Custom ( custom) => custom. value . to_string ( ) ,
40- Event :: TextMessageContent ( content) => content. delta ,
41- Event :: TextMessageChunk ( chunk) => {
42- if let Some ( content) = chunk. delta {
43- content
44- } else {
45- continue ;
46- }
47- } ,
48- _ => continue ,
49- } ;
50-
51- execute ! ( & mut output, style:: Print ( content) ) ?;
39+ if let Event :: LegacyPassThrough ( content) = event {
40+ match content {
41+ LegacyPassThroughOutput :: Stderr ( content) => {
42+ let content_as_str = String :: from_utf8 ( content) ?;
43+ execute ! ( & mut stderr, style:: Print ( content_as_str) ) ?;
44+ } ,
45+ LegacyPassThroughOutput :: Stdout ( content) => {
46+ let content_as_str = String :: from_utf8 ( content) ?;
47+ execute ! ( & mut stdout, style:: Print ( content_as_str) ) ?;
48+ } ,
49+ }
50+ }
5251 }
5352
5453 Ok ( ( ) )
5554 }
5655}
5756
57+ #[ derive( Clone , Debug ) ]
58+ pub enum TargetOutput {
59+ Stdout ,
60+ Stderr ,
61+ }
62+
5863/// This compliments the [ViewEnd]. It can be thought of as the "other end" of a pipe.
5964/// The control would own this.
65+ #[ derive( Debug ) ]
6066pub struct ControlEnd {
6167 pub current_event : Option < Event > ,
6268 /// Used by the control to send state changes to the view
6369 pub sender : std:: sync:: mpsc:: Sender < Event > ,
6470 /// To receive user input from the view
6571 // TODO: later on we will need replace this byte array with an actual event type from ACP
66- pub receiver : std:: sync:: mpsc:: Receiver < Vec < u8 > > ,
72+ pub receiver : Option < std:: sync:: mpsc:: Receiver < Vec < u8 > > > ,
73+ pub target_output : TargetOutput ,
74+ }
75+
76+ impl Clone for ControlEnd {
77+ fn clone ( & self ) -> Self {
78+ Self {
79+ current_event : self . current_event . clone ( ) ,
80+ sender : self . sender . clone ( ) ,
81+ receiver : None ,
82+ target_output : self . target_output . clone ( ) ,
83+ }
84+ }
6785}
6886
6987impl ControlEnd {
@@ -79,15 +97,19 @@ impl ControlEnd {
7997 pub fn send ( & self , event : Event ) -> Result < ( ) , ConduitError > {
8098 Ok ( self . sender . send ( event) . map_err ( Box :: new) ?)
8199 }
100+
101+ pub fn as_stdout ( & self ) -> Self {
102+ let mut self_as_stdout = self . clone ( ) ;
103+ self_as_stdout. target_output = TargetOutput :: Stdout ;
104+
105+ self_as_stdout
106+ }
82107}
83108
84109impl std:: io:: Write for ControlEnd {
85110 fn write ( & mut self , buf : & [ u8 ] ) -> std:: io:: Result < usize > {
86- // We'll default to custom event
87- // This hardly matters because in legacy mode we are simply extracting the bytes and
88- // dumping it to output
89111 if self . current_event . is_none ( ) {
90- self . current_event . replace ( Event :: Custom ( Default :: default ( ) ) ) ;
112+ self . current_event . replace ( Event :: LegacyPassThrough ( Default :: default ( ) ) ) ;
91113 }
92114
93115 let current_event = self
@@ -117,11 +139,8 @@ impl std::io::Write for ControlEnd {
117139///
118140/// # Returns
119141/// A tuple containing:
120- /// - `ViewEnd<S>`: The view-side endpoint for sending input and receiving state updates
121- /// - `ControlEnd<S>`: The control-side endpoint for receiving input and sending state updates
122- ///
123- /// # Type Parameters
124- /// - `S`: The state type that implements `ViewState` trait
142+ /// - `ViewEnd`: The view-side endpoint for sending input and receiving state updates
143+ /// - `ControlEnd`: The control-side endpoint for receiving input and sending state updates
125144pub fn get_conduit_pair ( ) -> ( ViewEnd , ControlEnd ) {
126145 let ( state_tx, state_rx) = std:: sync:: mpsc:: channel :: < Event > ( ) ;
127146 let ( byte_tx, byte_rx) = std:: sync:: mpsc:: channel :: < Vec < u8 > > ( ) ;
@@ -134,7 +153,8 @@ pub fn get_conduit_pair() -> (ViewEnd, ControlEnd) {
134153 ControlEnd {
135154 current_event : None ,
136155 sender : state_tx,
137- receiver : byte_rx,
156+ receiver : Some ( byte_rx) ,
157+ target_output : TargetOutput :: Stderr ,
138158 } ,
139159 )
140160}
@@ -154,22 +174,10 @@ impl InterimEvent for Event {
154174 debug_assert ! ( self . is_compatible_with_legacy_event_loop( ) ) ;
155175
156176 match self {
157- Self :: Custom ( _custom) => {
158- // custom events are defined in this UI crate
159- // TODO: use an enum as implement AsRef for it
160- // match custom.name.as_str() {
161- // _ => {},
162- // }
163- } ,
164- Self :: TextMessageContent ( msg_content) => {
165- let str = String :: from_utf8 ( content. to_vec ( ) ) ?;
166- msg_content. delta . push_str ( & str) ;
167- } ,
168- Self :: TextMessageChunk ( chunk) => {
169- let str = String :: from_utf8 ( content. to_vec ( ) ) ?;
170- if let Some ( d) = chunk. delta . as_mut ( ) {
171- d. push_str ( & str) ;
172- }
177+ Self :: LegacyPassThrough ( buf) => match buf {
178+ LegacyPassThroughOutput :: Stdout ( buf) | LegacyPassThroughOutput :: Stderr ( buf) => {
179+ buf. extend_from_slice ( content) ;
180+ } ,
173181 } ,
174182 _ => unreachable ! ( ) ,
175183 }
0 commit comments