Skip to content

Keep the right prompt out of the committed prompt frame - #1749

Merged
tleonhardt merged 2 commits into
mainfrom
rprompt-not-in-scrollback
Sep 6, 2026
Merged

Keep the right prompt out of the committed prompt frame#1749
tleonhardt merged 2 commits into
mainfrom
rprompt-not-in-scrollback

Conversation

@tleonhardt

Copy link
Copy Markdown
Member

Problem

With enable_rprompt=True, the right prompt was redrawn beside every accepted command line in the scrollback, not just on the live prompt line:

myapp> echo one                            cwd=/Users/you/src/cmd2
one
myapp> echo two                            cwd=/Users/you/src/cmd2
two

Cause

prompt-toolkit ends every Application.run() with a final render, and that frame is what stays on the terminal. PromptSession filters its bottom toolbar container with ~is_done so the toolbar is excluded from it, but the right prompt is a plain Float with no such filter (shortcuts/prompt.py:157-162), so it is drawn into the committed frame once per command.

Fix

Wrap that float in a ConditionalContainer with the same ~is_done filter the toolbar already gets.

The float is located by its "class:rprompt" style rather than by its private _RPrompt type, matching how cmd2 already identifies the toolbar container by "class:bottom-toolbar". A layout that does not contain it is left alone — the right prompt is cosmetic, and an upstream layout change must not stop the application from starting.

main_session.rprompt is untouched, so main_session.rprompt == get_rprompt still holds and the existing test_enable_rprompt passes unchanged.

Verification

Driving examples/getting_started.py through a real pty:

accepted command lines ...that also carry the right prompt
main 3 3
this branch 3 0

tests/test_cmd2.py::test_rprompt_is_not_drawn_into_the_committed_line asserts the right prompt is not rendered while is_done. Making the fix a no-op fails it with the right prompt was drawn into the committed final frame.

  • make check clean (ruff, prettier, typos, ty, mypy --strict)
  • make test: 1857 passed, 2 skipped
  • make docs-test clean

Provenance

Found while investigating the bottom toolbar flicker on #1748. That branch fixed this incidentally as a side effect of a much larger architecture change which does not fix the flicker and should not be merged; this extracts the one confirmed win as a standalone change against main.

prompt-toolkit ends every Application.run() with a final render, and that frame
is what stays on the terminal. Its bottom toolbar container is filtered with
~is_done so it is excluded, but the right prompt is a plain Float with no such
filter, so a copy of it was left beside every accepted command line in the
scrollback.

Wrap that float in a ConditionalContainer with the same ~is_done filter the
toolbar already gets. The float is located by its "class:rprompt" style rather
than by its private type, and a layout that does not contain it is left alone,
since the right prompt is cosmetic and must not stop the application starting.
@codecov

codecov Bot commented Sep 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.64%. Comparing base (c11a55f) to head (78f3a1f).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1749   +/-   ##
=======================================
  Coverage   99.64%   99.64%           
=======================================
  Files          23       23           
  Lines        5960     5973   +13     
=======================================
+ Hits         5939     5952   +13     
  Misses         21       21           
Flag Coverage Δ
unittests 99.64% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

_read_raw_input() calls patch_stdout(), which asks the ambient app session for
an Output. Without one bound, prompt-toolkit builds a real one on demand, and on
Windows CI that is a Win32Output with no console behind it, so the test failed
there on every Python version with NoConsoleScreenBufferError.

Wrap the session in create_app_session() with the same pipe input and dummy
output, matching how the other prompt-driving tests do it.
@tleonhardt
tleonhardt merged commit ca0ddbe into main Sep 6, 2026
31 checks passed
@tleonhardt
tleonhardt deleted the rprompt-not-in-scrollback branch September 6, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant