diff --git a/Lib/_pyrepl/unix_console.py b/Lib/_pyrepl/unix_console.py index 937b5df6ff7d4c..5817075ea7bda6 100644 --- a/Lib/_pyrepl/unix_console.py +++ b/Lib/_pyrepl/unix_console.py @@ -675,7 +675,8 @@ def __write_changed_line(self, y, oldline, newline, px_coord): self.__move(x_coord, y) self.__write_code(self.ich1) self.__write(newline[x_pos]) - self.posxy = x_coord + character_width, y + new_x = x_coord + character_width + self.posxy = min(new_x, self.width - 1), y # if it's a single character change in the middle of the line elif ( @@ -686,7 +687,8 @@ def __write_changed_line(self, y, oldline, newline, px_coord): character_width = wlen(newline[x_pos]) self.__move(x_coord, y) self.__write(newline[x_pos]) - self.posxy = x_coord + character_width, y + new_x = x_coord + character_width + self.posxy = min(new_x, self.width - 1), y # if this is the last character to fit in the line and we edit in the middle of the line elif ( @@ -713,7 +715,14 @@ def __write_changed_line(self, y, oldline, newline, px_coord): if wlen(oldline) > wlen(newline): self.__write_code(self._el) self.__write(newline[x_pos:]) - self.posxy = wlen(newline), y + # When writing reaches the last column, the terminal enters + # "pending wrap" state where the cursor physically stays at + # width-1. Record position accordingly so CUB calculations + # use the correct physical cursor position (gh-145448). + newline_width = wlen(newline) + if newline_width >= self.width: + newline_width = self.width - 1 + self.posxy = newline_width, y if "\x1b" in newline: # ANSI escape characters are present, so we can't assume diff --git a/Misc/NEWS.d/next/Library/2026-03-09-00-00-02.gh-issue-145448.repl-cursor.rst b/Misc/NEWS.d/next/Library/2026-03-09-00-00-02.gh-issue-145448.repl-cursor.rst new file mode 100644 index 00000000000000..2387b886de59c9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-09-00-00-02.gh-issue-145448.repl-cursor.rst @@ -0,0 +1,3 @@ +Fixed REPL tab completion cursor moving backward by one cell in terminals +that correctly handle CUB (Cursor Backward) in pending wrap state, such as +xterm and Ghostty.