@@ -1461,51 +1461,37 @@ fn deltas_then_same_final_message_are_rendered_snapshot() {
1461
1461
fn local_bang_exec_lists_files ( ) {
1462
1462
use std:: fs;
1463
1463
1464
- // Prepare a temporary working directory with two files
1465
1464
let tmp = tempfile:: tempdir ( ) . expect ( "tempdir" ) ;
1466
1465
let f1 = tmp. path ( ) . join ( "alpha.txt" ) ;
1467
1466
let f2 = tmp. path ( ) . join ( "beta.txt" ) ;
1468
1467
fs:: write ( & f1, b"one" ) . unwrap ( ) ;
1469
1468
fs:: write ( & f2, b"two" ) . unwrap ( ) ;
1470
1469
1471
- // Set up widget and force CWD to the temp dir so the test is hermetic
1472
1470
let ( mut chat, mut rx, mut op_rx) = make_chatwidget_manual ( ) ;
1473
1471
chat. config . cwd = tmp. path ( ) . to_path_buf ( ) ;
1474
1472
1475
- // Simulate typing a local command and pressing Enter
1476
- #[ cfg( windows) ]
1477
- let typed = "!dir" . to_string ( ) ;
1478
- #[ cfg( not( windows) ) ]
1479
1473
let typed = "!ls" . to_string ( ) ;
1480
1474
// Use paste to avoid triggering burst heuristics that suppress Enter submission
1481
1475
chat. bottom_pane . handle_paste ( typed) ;
1482
1476
chat. handle_key_event ( KeyEvent :: new ( KeyCode :: Enter , KeyModifiers :: NONE ) ) ;
1483
1477
1484
- // Expect an Op::LocalExec emitted to the codex channel
1478
+
1485
1479
let op = op_rx. try_recv ( ) . expect ( "expected LocalExec op emitted" ) ;
1486
1480
let raw_cmd = match op {
1487
1481
Op :: LocalExec { raw_cmd } => raw_cmd,
1488
1482
other => panic ! ( "unexpected op: {other:?}" ) ,
1489
1483
} ;
1490
- #[ cfg( windows) ]
1491
- assert ! ( raw_cmd. to_ascii_lowercase( ) . starts_with( "dir" ) ) ;
1492
- #[ cfg( not( windows) ) ]
1493
1484
assert_eq ! ( raw_cmd, "ls" ) ;
1494
1485
1495
1486
// Feed the corresponding LocalCommand events back into the widget as if from core
1496
- #[ cfg( windows) ]
1497
- let begin_cmd = vec ! [ "cmd" . to_string( ) , "/C" . to_string( ) , raw_cmd. clone( ) ] ;
1498
- #[ cfg( not( windows) ) ]
1499
1487
let begin_cmd = vec ! [ "bash" . to_string( ) , "-lc" . to_string( ) , raw_cmd. clone( ) ] ;
1500
-
1501
1488
chat. handle_codex_event ( Event {
1502
1489
id : "sub-1" . into ( ) ,
1503
1490
msg : EventMsg :: LocalCommandBegin ( codex_core:: protocol:: LocalCommandBeginEvent {
1504
1491
command : begin_cmd,
1505
1492
} ) ,
1506
1493
} ) ;
1507
1494
1508
- // Create a deterministic stdout that includes both filenames, one per line
1509
1495
let mut stdout = String :: new ( ) ;
1510
1496
stdout. push_str ( "alpha.txt\n " ) ;
1511
1497
stdout. push_str ( "beta.txt\n " ) ;
@@ -1518,7 +1504,6 @@ fn local_bang_exec_lists_files() {
1518
1504
} ) ,
1519
1505
} ) ;
1520
1506
1521
- // Drain history insertions and assert both files are present
1522
1507
let cells = drain_insert_history ( & mut rx) ;
1523
1508
let combined = cells
1524
1509
. iter ( )
@@ -1550,21 +1535,14 @@ fn local_bang_exec_respects_max_lines() {
1550
1535
1551
1536
let ( mut chat, mut rx, mut op_rx) = make_chatwidget_manual ( ) ;
1552
1537
chat. config . cwd = tmp. path ( ) . to_path_buf ( ) ;
1553
- // Enforce a small cap to test truncation clearly
1554
1538
chat. config . tui . local_shell_max_lines = 10 ;
1555
-
1556
- #[ cfg( windows) ]
1557
- let typed = format ! ( "!type {}" , big. display( ) ) ;
1558
- #[ cfg( not( windows) ) ]
1559
1539
let typed = format ! ( "!cat {}" , big. display( ) ) ;
1560
1540
1561
1541
chat. bottom_pane . handle_paste ( typed) ;
1562
1542
chat. handle_key_event ( KeyEvent :: new ( KeyCode :: Enter , KeyModifiers :: NONE ) ) ;
1563
1543
1564
- // Expect the local exec op
1565
1544
let _ = op_rx. try_recv ( ) . expect ( "expected LocalExec op emitted" ) ;
1566
1545
1567
- // Simulate begin/end events with stdout equal to the file contents we wrote
1568
1546
let stdout = {
1569
1547
let mut s = String :: new ( ) ;
1570
1548
for i in 0 ..total_lines {
@@ -1593,7 +1571,6 @@ fn local_bang_exec_respects_max_lines() {
1593
1571
. map ( |lines| lines_to_single_string ( lines) )
1594
1572
. collect :: < String > ( ) ;
1595
1573
1596
- // Count rendered content lines that begin with our marker 'L'
1597
1574
let rendered_content_lines = combined
1598
1575
. lines ( )
1599
1576
. filter ( |l| l. trim_start ( ) . starts_with ( 'L' ) )
@@ -1613,29 +1590,28 @@ fn local_bang_exec_can_be_interrupted_with_ctrl_c() {
1613
1590
use codex_core:: protocol:: LocalCommandBeginEvent ;
1614
1591
use codex_core:: protocol:: LocalCommandEndEvent ;
1615
1592
1616
- let ( mut chat, mut rx , mut op_rx) = make_chatwidget_manual ( ) ;
1593
+ let ( mut chat, _ , mut op_rx) = make_chatwidget_manual ( ) ;
1617
1594
1618
- // Simulate a long-running local command begin (sleep)
1619
1595
chat. handle_codex_event ( Event {
1620
1596
id : "sub-ctrlc" . into ( ) ,
1621
1597
msg : EventMsg :: LocalCommandBegin ( LocalCommandBeginEvent {
1622
1598
command : vec ! [ "bash" . into( ) , "-lc" . into( ) , "sleep 10000" . into( ) ] ,
1623
1599
} ) ,
1624
1600
} ) ;
1625
1601
1626
- // Ensure UI marks a running task
1627
1602
assert ! ( chat. bottom_pane. is_task_running( ) , "task should be running" ) ;
1628
1603
1629
- // Press Ctrl-C; widget should send Op::Interrupt and clear running state
1630
- let _ = chat. on_ctrl_c ( ) ;
1604
+ // Press Ctrl-C; widget should send Op::Interrupt and running state should remain until LocalCommandEnd is received
1605
+ chat. on_ctrl_c ( ) ;
1631
1606
let op = op_rx. try_recv ( ) . expect ( "expected Interrupt op emitted" ) ;
1632
1607
match op {
1633
1608
Op :: Interrupt => { }
1634
1609
other => panic ! ( "unexpected op: {other:?}" ) ,
1635
1610
}
1611
+ // At this point, the task is still running until LocalCommandEnd is received
1636
1612
assert ! (
1637
- ! chat. bottom_pane. is_task_running( ) ,
1638
- "task running flag should be cleared after Ctrl-C"
1613
+ chat. bottom_pane. is_task_running( ) ,
1614
+ "task running flag should remain set after Ctrl-C until LocalCommandEnd "
1639
1615
) ;
1640
1616
1641
1617
// Core would reply with LocalCommandEnd after termination; simulate it
@@ -1644,10 +1620,14 @@ fn local_bang_exec_can_be_interrupted_with_ctrl_c() {
1644
1620
msg : EventMsg :: LocalCommandEnd ( LocalCommandEndEvent {
1645
1621
stdout : String :: new ( ) ,
1646
1622
stderr : String :: new ( ) ,
1647
- exit_code : 130 , // common SIGINT exit
1623
+ // Anything non-zero to signal interruption but we don't care about the value here.
1624
+ exit_code : 1 ,
1648
1625
} ) ,
1649
1626
} ) ;
1650
1627
1651
- // Drain any history updates to ensure no panics and UI progressed
1652
- let _ = drain_insert_history ( & mut rx) ;
1628
+ // Now the running state should be cleared
1629
+ assert ! (
1630
+ !chat. bottom_pane. is_task_running( ) ,
1631
+ "task running flag should be cleared after LocalCommandEnd"
1632
+ ) ;
1653
1633
}
0 commit comments