@@ -23,7 +23,6 @@ use crate::native::{
2323 tasks:: types:: { Task , TaskResult } ,
2424} ;
2525
26- use super :: action:: Action ;
2726use super :: components:: Component ;
2827use super :: components:: countdown_popup:: CountdownPopup ;
2928use super :: components:: help_popup:: HelpPopup ;
@@ -39,6 +38,7 @@ use super::pty::PtyInstance;
3938use super :: theme:: THEME ;
4039use super :: tui;
4140use super :: utils:: normalize_newlines;
41+ use super :: { action:: Action , nx_console:: messaging:: NxConsoleMessageConnection } ;
4242
4343pub struct App {
4444 pub components : Vec < Box < dyn Component > > ,
@@ -69,6 +69,7 @@ pub struct App {
6969 tasks : Vec < Task > ,
7070 debug_mode : bool ,
7171 debug_state : TuiWidgetState ,
72+ console_messenger : Option < NxConsoleMessageConnection > ,
7273}
7374
7475#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
@@ -136,6 +137,7 @@ impl App {
136137 tasks,
137138 debug_mode : false ,
138139 debug_state : TuiWidgetState :: default ( ) ,
140+ console_messenger : None ,
139141 } )
140142 }
141143
@@ -208,6 +210,10 @@ impl App {
208210
209211 // Show countdown popup for the configured duration (making sure the help popup is not open first)
210212 pub fn end_command ( & mut self ) {
213+ self . console_messenger
214+ . as_ref ( )
215+ . and_then ( |c| c. end_running_tasks ( ) ) ;
216+
211217 // If the user has interacted with the app, or auto-exit is disabled, do nothing
212218 if self . user_has_interacted || !self . tui_config . auto_exit . should_exit_automatically ( ) {
213219 return ;
@@ -308,6 +314,10 @@ impl App {
308314 && !( matches ! ( self . focus, Focus :: MultipleOutput ( _) )
309315 && self . is_interactive_mode ( ) )
310316 {
317+ self . console_messenger
318+ . as_ref ( )
319+ . and_then ( |c| c. end_running_tasks ( ) ) ;
320+
311321 self . is_forced_shutdown = true ;
312322 // Quit immediately
313323 self . quit_at = Some ( std:: time:: Instant :: now ( ) ) ;
@@ -747,8 +757,25 @@ impl App {
747757 trace ! ( "{action:?}" ) ;
748758 }
749759 match & action {
760+ Action :: StartCommand ( _) => {
761+ self . console_messenger
762+ . as_ref ( )
763+ . and_then ( |c| c. start_running_tasks ( ) ) ;
764+ }
765+ Action :: Tick => {
766+ self . console_messenger . as_ref ( ) . and_then ( |messenger| {
767+ self . components
768+ . iter ( )
769+ . find_map ( |c| c. as_any ( ) . downcast_ref :: < TasksList > ( ) )
770+ . and_then ( |tasks_list| {
771+ messenger. update_running_tasks ( & tasks_list. tasks , & self . pty_instances )
772+ } )
773+ } ) ;
774+ }
750775 // Quit immediately
751- Action :: Quit => self . quit_at = Some ( std:: time:: Instant :: now ( ) ) ,
776+ Action :: Quit => {
777+ self . quit_at = Some ( std:: time:: Instant :: now ( ) ) ;
778+ }
752779 // Cancel quitting
753780 Action :: CancelQuit => {
754781 self . quit_at = None ;
@@ -958,6 +985,7 @@ impl App {
958985 is_focused,
959986 has_pty,
960987 is_next_tab_target,
988+ self . console_messenger . is_some ( ) ,
961989 ) ;
962990
963991 let terminal_pane = TerminalPane :: new ( )
@@ -984,6 +1012,13 @@ impl App {
9841012 } )
9851013 . ok ( ) ;
9861014 }
1015+ Action :: SendConsoleMessage ( msg) => {
1016+ if let Some ( connection) = & self . console_messenger {
1017+ connection. send_terminal_string ( msg) ;
1018+ } else {
1019+ trace ! ( "No console connection available" ) ;
1020+ }
1021+ }
9871022 _ => { }
9881023 }
9891024
@@ -1034,10 +1069,11 @@ impl App {
10341069
10351070 /// Dispatches an action to the action tx for other components to handle however they see fit
10361071 fn dispatch_action ( & self , action : Action ) {
1037- let tx = self . action_tx . clone ( ) . unwrap ( ) ;
1038- tokio:: spawn ( async move {
1039- let _ = tx. send ( action) ;
1040- } ) ;
1072+ if let Some ( tx) = & self . action_tx {
1073+ tx. send ( action) . unwrap_or_else ( |e| {
1074+ debug ! ( "Failed to dispatch action: {}" , e) ;
1075+ } ) ;
1076+ }
10411077 }
10421078
10431079 fn recalculate_layout_areas ( & mut self ) {
@@ -1330,7 +1366,10 @@ impl App {
13301366 fn handle_key_event ( & mut self , key : KeyEvent ) -> io:: Result < ( ) > {
13311367 if let Focus :: MultipleOutput ( pane_idx) = self . focus {
13321368 let terminal_pane_data = & mut self . terminal_pane_data [ pane_idx] ;
1333- terminal_pane_data. handle_key_event ( key)
1369+ if let Some ( action) = terminal_pane_data. handle_key_event ( key) ? {
1370+ self . dispatch_action ( action) ;
1371+ }
1372+ Ok ( ( ) )
13341373 } else {
13351374 Ok ( ( ) )
13361375 }
@@ -1423,15 +1462,17 @@ impl App {
14231462 parser_and_writer : External < ( ParserArc , WriterArc ) > ,
14241463 ) {
14251464 // Access the contents of the External
1426- let parser_and_writer_clone = parser_and_writer. clone ( ) ;
1427- let ( parser, writer) = & parser_and_writer_clone;
14281465 let pty = Arc :: new (
1429- PtyInstance :: new ( task_id. to_string ( ) , parser. clone ( ) , writer. clone ( ) )
1430- . map_err ( |e| napi:: Error :: from_reason ( format ! ( "Failed to create PTY: {}" , e) ) )
1431- . unwrap ( ) ,
1466+ PtyInstance :: new (
1467+ task_id. to_string ( ) ,
1468+ parser_and_writer. 0 . clone ( ) ,
1469+ parser_and_writer. 1 . clone ( ) ,
1470+ )
1471+ . map_err ( |e| napi:: Error :: from_reason ( format ! ( "Failed to create PTY: {}" , e) ) )
1472+ . unwrap ( ) ,
14321473 ) ;
14331474
1434- self . pty_instances . insert ( task_id. to_string ( ) , pty. clone ( ) ) ;
1475+ self . pty_instances . insert ( task_id. to_string ( ) , pty) ;
14351476 }
14361477
14371478 fn create_empty_parser_and_noop_writer ( ) -> ( ParserArc , External < ( ParserArc , WriterArc ) > ) {
@@ -1506,4 +1547,15 @@ impl App {
15061547 self . debug_state . transition ( event) ;
15071548 }
15081549 }
1550+
1551+ pub fn set_console_messenger ( & mut self , messenger : NxConsoleMessageConnection ) {
1552+ self . console_messenger = Some ( messenger) ;
1553+ if self
1554+ . console_messenger
1555+ . as_ref ( )
1556+ . is_some_and ( |c| c. is_connected ( ) )
1557+ {
1558+ self . dispatch_action ( Action :: ConsoleMessagesAvailable ( true ) ) ;
1559+ }
1560+ }
15091561}
0 commit comments