@@ -1825,3 +1825,86 @@ def test_detect_pip_usage_in_repl(self):
1825
1825
" outside of the Python REPL"
1826
1826
)
1827
1827
self .assertIn (hint , output )
1828
+
1829
+ class TestPyReplCtrlD (TestCase ):
1830
+ """Test Ctrl+D behavior in _pyrepl to match old pre-3.13 REPL behavior.
1831
+
1832
+ Ctrl+D should:
1833
+ - Exit on empty buffer (raises EOFError)
1834
+ - Delete character when cursor is in middle of line
1835
+ - Perform no operation when cursor is at end of line without newline
1836
+ - Exit multiline mode when cursor is at end with trailing newline
1837
+ - Run code up to that point when pressed on blank line with preceding lines
1838
+ """
1839
+ def prepare_reader (self , events ):
1840
+ console = FakeConsole (events )
1841
+ config = ReadlineConfig (readline_completer = None )
1842
+ reader = ReadlineAlikeReader (console = console , config = config )
1843
+ return reader
1844
+
1845
+ def test_ctrl_d_empty_line (self ):
1846
+ """Test that pressing Ctrl+D on empty line exits the program"""
1847
+ events = [
1848
+ Event (evt = "key" , data = "\x04 " , raw = bytearray (b"\x04 " )), # Ctrl+D
1849
+ ]
1850
+ reader = self .prepare_reader (events )
1851
+ with self .assertRaises (EOFError ):
1852
+ multiline_input (reader )
1853
+
1854
+ def test_ctrl_d_multiline_with_new_line (self ):
1855
+ """Test that pressing Ctrl+D in multiline mode with trailing newline exits multiline mode"""
1856
+ events = itertools .chain (
1857
+ code_to_events ("def f():\n pass\n " ), # Enter multiline mode with trailing newline
1858
+ [
1859
+ Event (evt = "key" , data = "\x04 " , raw = bytearray (b"\x04 " )), # Ctrl+D
1860
+ ],
1861
+ )
1862
+ reader , _ = handle_all_events (events )
1863
+ self .assertTrue (reader .finished )
1864
+ self .assertEqual ("def f():\n pass\n " , "" .join (reader .buffer ))
1865
+
1866
+ def test_ctrl_d_multiline_middle_of_line (self ):
1867
+ """Test that pressing Ctrl+D in multiline mode with cursor in middle deletes character"""
1868
+ events = itertools .chain (
1869
+ code_to_events ("def f():\n hello world" ), # Enter multiline mode
1870
+ [
1871
+ Event (evt = "key" , data = "left" , raw = bytearray (b"\x1b OD" ))
1872
+ ] * 5 , # move cursor to 'w' in "world"
1873
+ [
1874
+ Event (evt = "key" , data = "\x04 " , raw = bytearray (b"\x04 " ))
1875
+ ], # Ctrl+D should delete 'w'
1876
+ )
1877
+ reader , _ = handle_all_events (events )
1878
+ self .assertFalse (reader .finished )
1879
+ self .assertEqual ("def f():\n hello orld" , "" .join (reader .buffer ))
1880
+
1881
+ def test_ctrl_d_multiline_end_of_line_no_newline (self ):
1882
+ """Test that pressing Ctrl+D at end of line without newline performs no operation"""
1883
+ events = itertools .chain (
1884
+ code_to_events ("def f():\n hello" ), # Enter multiline mode, no trailing newline
1885
+ [
1886
+ Event (evt = "key" , data = "\x04 " , raw = bytearray (b"\x04 " ))
1887
+ ], # Ctrl+D should be no-op
1888
+ )
1889
+ reader , _ = handle_all_events (events )
1890
+ self .assertFalse (reader .finished )
1891
+ self .assertEqual ("def f():\n hello" , "" .join (reader .buffer ))
1892
+
1893
+ def test_ctrl_d_single_line_middle_of_line (self ):
1894
+ """Test that pressing Ctrl+D in single line mode deletes current character"""
1895
+ events = itertools .chain (
1896
+ code_to_events ("hello" ),
1897
+ [Event (evt = "key" , data = "left" , raw = bytearray (b"\x1b OD" ))], # move left
1898
+ [Event (evt = "key" , data = "\x04 " , raw = bytearray (b"\x04 " ))], # Ctrl+D
1899
+ )
1900
+ reader , _ = handle_all_events (events )
1901
+ self .assertEqual ("hell" , "" .join (reader .buffer ))
1902
+
1903
+ def test_ctrl_d_single_line_end_no_newline (self ):
1904
+ """Test that pressing Ctrl+D at end of single line without newline does nothing"""
1905
+ events = itertools .chain (
1906
+ code_to_events ("hello" ), # cursor at end of line
1907
+ [Event (evt = "key" , data = "\x04 " , raw = bytearray (b"\x04 " ))], # Ctrl+D
1908
+ )
1909
+ reader , _ = handle_all_events (events )
1910
+ self .assertEqual ("hello" , "" .join (reader .buffer ))
0 commit comments