prompt-toolkit / prompt-toolkit/python-prompt-toolkit

Cursor drift after auto-wrap when first char of wrapped line is a space

Open
#2,071 1 comment 0 reactions 0 assignees View on GitHub

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

  1. Open a prompt_toolkit application with a TextArea that has:
    • multiline=False (single line input)
    • wrap_lines=True
    • A prompt (e.g., BeforeInput)
  2. Type a long line of text without spaces until it auto-wraps to the next
    visual line
  3. 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
  4. 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.pyWindow._copy_body wraps text at
    line 2016+ but doesn't feed wrapping info back to cursor position
  • prompt_toolkit/layout/controls.pyBufferControl._create_get_processed_line_func
    line 773: translate_rowcol returns y=row
  • prompt_toolkit/layout/processors.pyBeforeInput line 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.