@@ -9,13 +9,12 @@ use ratatui::style::Style;
9
9
use ratatui:: text:: { Line , Span } ;
10
10
use ratatui:: widgets:: { Block , Borders , Paragraph } ;
11
11
use std:: collections:: HashMap ;
12
- use std:: io:: { self , Write } ;
13
- use std:: sync:: { Arc , Mutex , RwLock } ;
12
+ use std:: io;
13
+ use std:: sync:: { Arc , Mutex } ;
14
14
use tokio:: sync:: mpsc;
15
15
use tokio:: sync:: mpsc:: UnboundedSender ;
16
16
use tracing:: { debug, trace} ;
17
17
use tui_logger:: { LevelFilter , TuiLoggerSmartWidget , TuiWidgetEvent , TuiWidgetState } ;
18
- use vt100_ctt:: Parser ;
19
18
20
19
use crate :: native:: tui:: tui:: Tui ;
21
20
use crate :: native:: {
@@ -174,22 +173,30 @@ impl App {
174
173
175
174
pub fn update_task_status ( & mut self , task_id : String , status : TaskStatus ) {
176
175
self . dispatch_action ( Action :: UpdateTaskStatus ( task_id. clone ( ) , status) ) ;
177
- if status == TaskStatus :: InProgress && self . tasks . len ( ) == 1 {
176
+ if status == TaskStatus :: InProgress && self . should_set_interactive_by_default ( & task_id ) {
178
177
self . terminal_pane_data [ 0 ] . set_interactive ( true ) ;
179
178
}
180
179
}
181
180
181
+ fn should_set_interactive_by_default ( & self , task_id : & str ) -> bool {
182
+ self . tasks . len ( ) == 1
183
+ && self
184
+ . pty_instances
185
+ . get ( task_id)
186
+ . is_some_and ( |pty| pty. can_be_interactive ( ) )
187
+ }
188
+
182
189
pub fn print_task_terminal_output ( & mut self , task_id : String , output : String ) {
183
190
// Tasks run within a pseudo-terminal always have a pty instance and do not need a new one
184
191
// Tasks not run within a pseudo-terminal need a new pty instance to print output
185
192
if !self . pty_instances . contains_key ( & task_id) {
186
- let ( parser , parser_and_writer ) = Self :: create_empty_parser_and_noop_writer ( ) ;
193
+ let pty = PtyInstance :: non_interactive ( ) ;
187
194
188
195
// Add ANSI escape sequence to hide cursor at the end of output, it would be confusing to have it visible when a task is a cache hit
189
196
let output_with_hidden_cursor = format ! ( "{}\x1b [?25l" , output) ;
190
- Self :: write_output_to_parser ( parser , output_with_hidden_cursor) ;
197
+ Self :: write_output_to_parser ( & pty , output_with_hidden_cursor) ;
191
198
192
- self . create_and_register_pty_instance ( & task_id, parser_and_writer ) ;
199
+ self . register_pty_instance ( & task_id, pty ) ;
193
200
// Ensure the pty instances get resized appropriately
194
201
let _ = self . debounce_pty_resize ( ) ;
195
202
return ;
@@ -255,23 +262,31 @@ impl App {
255
262
}
256
263
257
264
// A pseudo-terminal running task will provide the parser and writer directly
258
- pub fn register_running_task (
265
+ pub fn register_running_interactive_task (
259
266
& mut self ,
260
267
task_id : String ,
261
268
parser_and_writer : External < ( ParserArc , WriterArc ) > ,
262
269
) {
263
- self . create_and_register_pty_instance ( & task_id, parser_and_writer) ;
264
- self . update_task_status ( task_id. clone ( ) , TaskStatus :: InProgress ) ;
270
+ debug ! ( "Registering interactive task: {task_id}" ) ;
271
+ let pty =
272
+ PtyInstance :: interactive ( parser_and_writer. 0 . clone ( ) , parser_and_writer. 1 . clone ( ) ) ;
273
+ self . register_running_task ( task_id, pty)
265
274
}
266
275
267
- pub fn register_running_task_with_empty_parser ( & mut self , task_id : String ) {
268
- let ( _, parser_and_writer) = Self :: create_empty_parser_and_noop_writer ( ) ;
269
- self . create_and_register_pty_instance ( & task_id, parser_and_writer) ;
276
+ pub fn register_running_non_interactive_task ( & mut self , task_id : String ) {
277
+ debug ! ( "Registering non-interactive task: {task_id}" ) ;
278
+ let pty = PtyInstance :: non_interactive ( ) ;
279
+ self . register_pty_instance ( & task_id, pty) ;
270
280
self . update_task_status ( task_id. clone ( ) , TaskStatus :: InProgress ) ;
271
281
// Ensure the pty instances get resized appropriately
272
282
let _ = self . debounce_pty_resize ( ) ;
273
283
}
274
284
285
+ fn register_running_task ( & mut self , task_id : String , pty : PtyInstance ) {
286
+ self . register_pty_instance ( & task_id, pty) ;
287
+ self . update_task_status ( task_id. clone ( ) , TaskStatus :: InProgress ) ;
288
+ }
289
+
275
290
pub fn append_task_output ( & mut self , task_id : String , output : String ) {
276
291
let pty = self
277
292
. pty_instances
@@ -973,13 +988,14 @@ impl App {
973
988
let terminal_pane_data = & mut self . terminal_pane_data [ pane_idx] ;
974
989
terminal_pane_data. is_continuous = task. continuous ;
975
990
let in_progress = task. status == TaskStatus :: InProgress ;
976
- terminal_pane_data. can_be_interactive = in_progress;
977
991
if !in_progress {
978
992
terminal_pane_data. set_interactive ( false ) ;
979
993
}
980
994
981
995
let mut has_pty = false ;
982
996
if let Some ( pty) = self . pty_instances . get ( & relevant_pane_task) {
997
+ terminal_pane_data. can_be_interactive =
998
+ in_progress && pty. can_be_interactive ( ) ;
983
999
terminal_pane_data. pty = Some ( pty. clone ( ) ) ;
984
1000
has_pty = true ;
985
1001
}
@@ -1487,41 +1503,17 @@ impl App {
1487
1503
self . layout_manager . get_task_list_visibility ( ) == TaskListVisibility :: Hidden
1488
1504
}
1489
1505
1490
- fn create_and_register_pty_instance (
1491
- & mut self ,
1492
- task_id : & str ,
1493
- parser_and_writer : External < ( ParserArc , WriterArc ) > ,
1494
- ) {
1506
+ fn register_pty_instance ( & mut self , task_id : & str , pty : PtyInstance ) {
1495
1507
// Access the contents of the External
1496
- let pty = Arc :: new (
1497
- PtyInstance :: new (
1498
- task_id. to_string ( ) ,
1499
- parser_and_writer. 0 . clone ( ) ,
1500
- parser_and_writer. 1 . clone ( ) ,
1501
- )
1502
- . map_err ( |e| napi:: Error :: from_reason ( format ! ( "Failed to create PTY: {}" , e) ) )
1503
- . unwrap ( ) ,
1504
- ) ;
1508
+ let pty = Arc :: new ( pty) ;
1505
1509
1506
1510
self . pty_instances . insert ( task_id. to_string ( ) , pty) ;
1507
1511
}
1508
1512
1509
- fn create_empty_parser_and_noop_writer ( ) -> ( ParserArc , External < ( ParserArc , WriterArc ) > ) {
1510
- // Use sane defaults for rows, cols and scrollback buffer size. The dimensions will be adjusted dynamically later.
1511
- let parser = Arc :: new ( RwLock :: new ( Parser :: new ( 24 , 80 , 10000 ) ) ) ;
1512
- let writer: Arc < Mutex < Box < dyn Write + Send > > > =
1513
- Arc :: new ( Mutex :: new ( Box :: new ( std:: io:: sink ( ) ) ) ) ;
1514
- ( parser. clone ( ) , External :: new ( ( parser, writer) ) )
1515
- }
1516
-
1517
1513
// Writes the given output to the given parser, used for the case where a task is a cache hit, or when it is run outside of the rust pseudo-terminal
1518
- fn write_output_to_parser ( parser : ParserArc , output : String ) {
1514
+ fn write_output_to_parser ( parser : & PtyInstance , output : String ) {
1519
1515
let normalized_output = normalize_newlines ( output. as_bytes ( ) ) ;
1520
- parser
1521
- . write ( )
1522
- . unwrap ( )
1523
- . write_all ( & normalized_output)
1524
- . unwrap ( ) ;
1516
+ parser. process_output ( & normalized_output) ;
1525
1517
}
1526
1518
1527
1519
fn display_and_focus_current_task_in_terminal_pane ( & mut self , force_spacebar_mode : bool ) {
0 commit comments