diff --git a/Lib/curses/textpad.py b/Lib/curses/textpad.py index f6dfc990901d995..31ad37539ca4a42 100644 --- a/Lib/curses/textpad.py +++ b/Lib/curses/textpad.py @@ -200,14 +200,16 @@ def gather(self): result = "" self._update_max_yx() for y in range(self.maxy+1): - self.win.move(y, 0) - stop = self._end_of_line(y) - if stop == 0 and self.stripspaces: - continue - for x in range(self.maxx+1): - if self.stripspaces and x > stop: - break - result = result + str(self.win.in_wch(y, x)) + # The whole line: in_wstr() reads a double-width character once, + # skipping the continuation cell that holds its other half. + line = self.win.in_wstr(y, 0) + if self.stripspaces: + stripped = line.rstrip(' ') + if not stripped: + continue + # Keep the blank the cursor rests on past the last character. + line = stripped + ' ' if len(stripped) < len(line) else stripped + result = result + line if self.maxy > 0: result = result + "\n" return result diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index ea2dcd76b585a99..c94ddfc734a3df9 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -2660,6 +2660,23 @@ def test_textbox_combining(self): box.do_command(ch) self.assertEqual(box.gather(), text + ' ') + @requires_wide_build + def test_textbox_double_width(self): + # A double-width (East Asian) character occupies two cells. gather() + # reads a whole line at a time so that the second cell, which holds + # the same character, is not reported as another one. + text = '你好' + if not self._encodable(text): + self.skipTest('the locale cannot encode %r' % text) + box, win = self._make_textbox(1, 12) + for ch in text: + box.do_command(ch) + self.assertEqual(box.gather(), text + ' ') + box, win = self._make_textbox(1, 12, stripspaces=False) + for ch in text: + box.do_command(ch) + self.assertEqual(box.gather(), text + ' ' * 8) + def test_textbox_edit_wide(self): # edit() reads characters through get_wch(). Each character is pushed # with unget_wch(), which on a narrow build requires it to encode to a