prompt-toolkit / prompt-toolkit/python-prompt-toolkit
Cursor drift after auto-wrap when first char of wrapped line is a space
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 10.6k
- Forks
- 815
- PR merge metrics
- No merged PRs in 30d
Description
prompt_toolkit Bug Report: Cursor drift after auto-wrap with leading space
Summary
When typing in a TextArea (or BufferControl) with wrap_lines=True and
multiline=False, the cursor visually drifts to the right when a space
character becomes the first character of an auto-wrapped visual line. The
drift equals approximately the number of wraps (e.g., 4 wraps → 4 characters
of drift). Navigating back to the line with arrow keys corrects the cursor
position.
Environment
- prompt_toolkit version: 3.0.x (shipped with Hermes Agent, May 2026)
- Python version: 3.11
- OS: Linux (Ubuntu 24.04)
- Terminal: SSH from Windows (PowerShell, Termius)
- TERM: xterm-256color
- Application: Hermes Agent (
hermes --tui)
Steps to Reproduce
- Open a prompt_toolkit application with a
TextAreathat has:multiline=False(single line input)wrap_lines=True- A prompt (e.g.,
BeforeInput)
- Type a long line of text without spaces until it auto-wraps to the next
visual line - Continue typing — the first character typed on the new visual line, if it
is a space (because the text logically has a space at that point), causes
the cursor to visually jump ~1 character to the right per wrap - The cursor now appears 4+ characters away from where text is actually
inserted
Additional Observations
- Adding spaces BEFORE the auto-wrap point (pushing the wrap point further
right) prevents the drift - With
full_screen=False, the drift is ~1 character per wrap (4 wraps = 4
chars) - With
full_screen=True, the drift becomes a full line offset - The drift is corrected when the user navigates to the line with arrow keys
(cursor position is recalculated)
Suspected Root Cause
In BufferControl._create_get_processed_line_func, the translate_rowcol
function computes cursor position as:
Point(x=get_processed_line(row).source_to_display(col), y=row)
The y coordinate is always the buffer row (row), which is 0 for a single
line. For wrapped content, the cursor may be on a different visual row, but
y doesn't account for wrapping. The Window._copy_body renders wrapped
content correctly, but the UIContent.cursor_position uses the unadjusted Y.
Additionally, BeforeInput.apply_transformation uses fragment_list_len
for the source_to_display shift, which counts characters rather than
display width. Multi-width characters (emoji, CJK) are miscounted.
Related Code
prompt_toolkit/layout/containers.py—Window._copy_bodywraps text at
line 2016+ but doesn't feed wrapping info back to cursor positionprompt_toolkit/layout/controls.py—BufferControl._create_get_processed_line_func
line 773:translate_rowcolreturnsy=rowprompt_toolkit/layout/processors.py—BeforeInputline 507:
shift_position = fragment_list_len(fragments_before)should be
fragment_list_width(fragments_before)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the single-line, wrapped TextArea case, then read BufferControl._create_get_processed_line_func in prompt_toolkit/layout/controls.py alongside Window._copy_body in containers.py. Check BeforeInput in processors.py for the display-width behavior, and compare cursor placement for wrapping and multi-width characters. Done means the cursor stays aligned after auto-wrap without breaking existing rendering behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100