Skip to content

Commit a3a5b4b

Browse files
aidanmelenambvAlexWaygoodmblahay
authored
gh-60436: fix curses textbox backspace/del (#103783)
Co-authored-by: Łukasz Langa <[email protected]> Co-authored-by: Alex Waygood <[email protected]> Co-authored-by: Michael Blahay <[email protected]>
1 parent 44010d0 commit a3a5b4b

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

Lib/curses/textpad.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ def do_command(self, ch):
102102
self._insert_printable_char(ch)
103103
elif ch == curses.ascii.SOH: # ^a
104104
self.win.move(y, 0)
105-
elif ch in (curses.ascii.STX,curses.KEY_LEFT, curses.ascii.BS,curses.KEY_BACKSPACE):
105+
elif ch in (curses.ascii.STX,curses.KEY_LEFT,
106+
curses.ascii.BS,
107+
curses.KEY_BACKSPACE,
108+
curses.ascii.DEL):
106109
if x > 0:
107110
self.win.move(y, x-1)
108111
elif y == 0:
@@ -111,7 +114,7 @@ def do_command(self, ch):
111114
self.win.move(y-1, self._end_of_line(y-1))
112115
else:
113116
self.win.move(y-1, self.maxx)
114-
if ch in (curses.ascii.BS, curses.KEY_BACKSPACE):
117+
if ch in (curses.ascii.BS, curses.KEY_BACKSPACE, curses.ascii.DEL):
115118
self.win.delch()
116119
elif ch == curses.ascii.EOT: # ^d
117120
self.win.delch()

Lib/test/test_curses.py

+71
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import sys
66
import tempfile
77
import unittest
8+
from unittest.mock import MagicMock
89

910
from test.support import (requires, verbose, SaveSignals, cpython_only,
1011
check_disallow_instantiation)
@@ -1319,5 +1320,75 @@ def lorem_ipsum(win):
13191320
for y, line in enumerate(text[:maxy]):
13201321
win.addstr(y, 0, line[:maxx - (y == maxy - 1)])
13211322

1323+
1324+
class TextboxTest(unittest.TestCase):
1325+
def setUp(self):
1326+
self.mock_win = MagicMock(spec=curses.window)
1327+
self.mock_win.getyx.return_value = (1, 1)
1328+
self.mock_win.getmaxyx.return_value = (10, 20)
1329+
self.textbox = curses.textpad.Textbox(self.mock_win)
1330+
1331+
def test_init(self):
1332+
"""Test textbox initialization."""
1333+
self.mock_win.reset_mock()
1334+
tb = curses.textpad.Textbox(self.mock_win)
1335+
self.mock_win.getmaxyx.assert_called_once_with()
1336+
self.mock_win.keypad.assert_called_once_with(1)
1337+
self.assertEqual(tb.insert_mode, False)
1338+
self.assertEqual(tb.stripspaces, 1)
1339+
self.assertIsNone(tb.lastcmd)
1340+
self.mock_win.reset_mock()
1341+
1342+
def test_insert(self):
1343+
"""Test inserting a printable character."""
1344+
self.mock_win.reset_mock()
1345+
self.textbox.do_command(ord('a'))
1346+
self.mock_win.addch.assert_called_with(ord('a'))
1347+
self.textbox.do_command(ord('b'))
1348+
self.mock_win.addch.assert_called_with(ord('b'))
1349+
self.textbox.do_command(ord('c'))
1350+
self.mock_win.addch.assert_called_with(ord('c'))
1351+
self.mock_win.reset_mock()
1352+
1353+
def test_delete(self):
1354+
"""Test deleting a character."""
1355+
self.mock_win.reset_mock()
1356+
self.textbox.do_command(curses.ascii.BS)
1357+
self.textbox.do_command(curses.KEY_BACKSPACE)
1358+
self.textbox.do_command(curses.ascii.DEL)
1359+
assert self.mock_win.delch.call_count == 3
1360+
self.mock_win.reset_mock()
1361+
1362+
def test_move_left(self):
1363+
"""Test moving the cursor left."""
1364+
self.mock_win.reset_mock()
1365+
self.textbox.do_command(curses.KEY_LEFT)
1366+
self.mock_win.move.assert_called_with(1, 0)
1367+
self.textbox.do_command(curses.KEY_RIGHT)
1368+
self.mock_win.move.assert_called_with(1, 2)
1369+
self.mock_win.reset_mock()
1370+
1371+
def test_move_left(self):
1372+
"""Test moving the cursor left."""
1373+
self.mock_win.reset_mock()
1374+
self.textbox.do_command(curses.KEY_RIGHT)
1375+
self.mock_win.move.assert_called_with(1, 2)
1376+
self.mock_win.reset_mock()
1377+
1378+
def test_move_up(self):
1379+
"""Test moving the cursor left."""
1380+
self.mock_win.reset_mock()
1381+
self.textbox.do_command(curses.KEY_UP)
1382+
self.mock_win.move.assert_called_with(0, 1)
1383+
self.mock_win.reset_mock()
1384+
1385+
def test_move_down(self):
1386+
"""Test moving the cursor left."""
1387+
self.mock_win.reset_mock()
1388+
self.textbox.do_command(curses.KEY_DOWN)
1389+
self.mock_win.move.assert_called_with(2, 1)
1390+
self.mock_win.reset_mock()
1391+
1392+
13221393
if __name__ == '__main__':
13231394
unittest.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
update curses textbox to additionally handle backspace using the ``curses.ascii.DEL`` key press.

0 commit comments

Comments
 (0)