1+ use std:: future;
12use std:: io:: Write as _;
23use std:: marker:: PhantomData ;
34use std:: path:: PathBuf ;
5+ use std:: pin:: Pin ;
46
57use crossterm:: style:: {
68 self ,
@@ -12,6 +14,7 @@ use crossterm::{
1214 queue,
1315} ;
1416use rustyline:: EditMode ;
17+ use tokio:: signal:: ctrl_c;
1518use tracing:: error;
1619
1720use crate :: legacy_ui_util:: {
@@ -49,19 +52,36 @@ pub enum ConduitError {
4952/// - To deliver state changes from the control layer to the view layer
5053pub struct ViewEnd {
5154 /// Used by the view to send input to the control
52- // TODO: later on we will need replace this byte array with an actual event type from ACP
5355 pub sender : tokio:: sync:: mpsc:: Sender < InputEvent > ,
5456 /// To receive messages from control about state changes
5557 pub receiver : tokio:: sync:: mpsc:: UnboundedReceiver < Event > ,
5658}
5759
5860impl ViewEnd {
59- /// Method to facilitate in the interim
60- /// It takes possible messages from the old even loop and queues write to the output provided
61- /// This blocks the current thread and consumes the [ViewEnd]
61+ /// Converts the ViewEnd into legacy mode operation. This mainly serves a purpose in the
62+ /// following circumstances:
63+ /// - To preserve the UX of the current event loop while abstracting away the impl Write it
64+ /// writes to
65+ /// - To serve as an interim UI for the new event loop while preserving the UX of the current
66+ /// product while the new UI is being worked out
67+ ///
68+ /// # Parameters
69+ ///
70+ /// * `ui_managed_input` - When true, the UI layer will manage user input through readline. When
71+ /// false, input handling is delegated to the event loop (via InputSource).
72+ /// * `ui_managed_ctrl_c` - When true, the UI layer will handle Ctrl+C interrupts. When false,
73+ /// interrupt handling is delegated to the event loop (via its own ctrl c handler).
74+ /// * `theme_source` - Provider for terminal styling and theming information.
75+ /// * `stderr` - Standard error stream for error output.
76+ /// * `stdout` - Standard output stream for normal output.
77+ ///
78+ /// # Returns
79+ ///
80+ /// Returns `Ok(())` on successful initialization, or a `ConduitError` if setup fails.
6281 pub fn into_legacy_mode (
6382 mut self ,
64- managed_input : bool ,
83+ ui_managed_input : bool ,
84+ ui_managed_ctrl_c : bool ,
6585 theme_source : impl ThemeSource ,
6686 mut stderr : std:: io:: Stderr ,
6787 mut stdout : std:: io:: Stdout ,
@@ -254,7 +274,7 @@ impl ViewEnd {
254274 Ok :: < ( ) , ConduitError > ( ( ) )
255275 }
256276
257- if managed_input {
277+ if ui_managed_input {
258278 let ( incoming_events_tx, mut incoming_events_rx) = tokio:: sync:: mpsc:: unbounded_channel :: < IncomingEvent > ( ) ;
259279 let ( prompt_signal_tx, prompt_signal_rx) = std:: sync:: mpsc:: channel :: < PromptSignal > ( ) ;
260280
@@ -303,15 +323,28 @@ impl ViewEnd {
303323 let prompt_signal = PromptSignal :: default ( ) ;
304324
305325 loop {
326+ let ctrl_c_handler: Pin <
327+ Box < dyn Future < Output = Result < ( ) , std:: io:: Error > > + Send + Sync + ' static > ,
328+ > ;
329+
306330 if matches ! ( display_state, DisplayState :: Prompting ) {
307331 // TODO: fetch prompt related info from session and send it here
308332 if let Err ( e) = prompt_signal_tx. send ( prompt_signal. clone ( ) ) {
309333 error ! ( "Error sending prompt signal: {:?}" , e) ;
310334 }
311335 display_state = DisplayState :: UserInsertingText ;
336+
337+ ctrl_c_handler = Box :: pin ( future:: pending ( ) ) ;
338+ } else if ui_managed_ctrl_c {
339+ ctrl_c_handler = Box :: pin ( ctrl_c ( ) ) ;
340+ } else {
341+ ctrl_c_handler = Box :: pin ( future:: pending ( ) ) ;
312342 }
313343
314344 tokio:: select! {
345+ _ = ctrl_c_handler => {
346+ _ = self . sender. send( InputEvent :: Interrupt ) . await ;
347+ } ,
315348 Some ( incoming_event) = incoming_events_rx. recv( ) => {
316349 match display_state {
317350 DisplayState :: UserInsertingText => {
@@ -327,6 +360,7 @@ impl ViewEnd {
327360 // not need to be notified that they are hitting
328361 // control c.
329362 display_state = DisplayState :: default ( ) ;
363+ _ = self . sender. send( InputEvent :: Interrupt ) . await ;
330364 } ,
331365 }
332366 } ,
0 commit comments