Skip to content

Keep the bottom toolbar visible during nested prompts - #1750

Merged
tleonhardt merged 1 commit into
consolidated_toolbarfrom
nested-prompt-toolbar
Sep 6, 2026
Merged

Keep the bottom toolbar visible during nested prompts#1750
tleonhardt merged 1 commit into
consolidated_toolbarfrom
nested-prompt-toolbar

Conversation

@tleonhardt

Copy link
Copy Markdown
Member

Problem

read_input() and read_secret() each build their own PromptSession and passed no bottom_toolbar, while _read_raw_input() is decorated @suspend_toolbar. So the main display stops and the nested prompt has no bar of its own — the toolbar vanishes entirely for as long as the nested prompt is up. For a bar documented as persistent, that is a visible inconsistency.

Driving a real app through a pty, with a toolbar that ticks once per 200ms:

BEFORE   main prompt   : bar=('TICK0024', row 23)
         nested prompt : bar=(None, None)          <- gone

Fix

Pass the toolbar to both temporary sessions when the application has one, gated on main_session.bottom_toolbar is not None so an app without a toolbar does not sprout one at a nested prompt. Also inherit refresh_interval, so a clock or status display keeps ticking rather than freezing at its first render.

Production change is 4 lines.

AFTER    nested prompt t1 : TICK0031     VISIBLE=True
         nested prompt t2 : TICK0038     UPDATING=True

Verified for both read_input() and read_secret().

select() is deliberately excluded

prompt_toolkit's choice() accepts bottom_toolbar and style but not refresh_interval, and ChoiceInput._create_application() constructs its Application without one (verified in 3.0.53). Input-driven redraws would still refresh it, so it would not freeze permanently — but it would go stale while the selection sits idle, and a clock that stops until the next keypress is worse than no clock. Left for a follow-up: either accept a stale-while-idle toolbar there, or upstream a refresh_interval parameter to choice().

Tests

Five added, TDD throughout — each of the four positive tests was watched failing for the right reason before any production code:

Test Red because
read_input session shows the toolbar bottom_toolbar was None
read_input session inherits refresh_interval was 0
read_secret session shows the toolbar bottom_toolbar was None
read_secret session inherits refresh_interval was 0

The fifth, test_nested_prompt_has_no_toolbar_when_the_app_has_none, is a guard that passes against correct code by construction. Rather than claim it was red-first, I mutation-checked it: making the assignment unconditional fails it for both methods.

The tests capture the real PromptSession cmd2 constructs and assert on its attributes, rather than asserting on mock call kwargs.

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

Docs

docs/features/prompt.md said cmd2 "temporarily hides the toolbar for its input prompts", which this makes false. Corrected, including why select() is excluded. CHANGELOG.md entry added under 4.3.0.

Scope

This is stage 1 of the bottom-toolbar work and is independent of the flicker investigation — it needs none of that machinery and changes nothing about run boundaries. It removes the toolbar's absence during nested prompts, not the repaint: _read_raw_input still genuinely suspends, so entering and leaving a nested prompt still repaints the bar.

Opened primarily to get CI coverage on all supported platforms — particularly Windows and the free-threaded 3.14t jobs — before this merges to consolidated_toolbar.

read_input() and read_secret() each build their own PromptSession and passed no
bottom_toolbar, while _read_raw_input() suspends the main display. The toolbar
therefore vanished entirely for as long as a nested prompt was up, which is a
visible inconsistency for a bar documented as persistent.

Pass the toolbar to both sessions when the application has one, gated on
main_session.bottom_toolbar being set so an app without a toolbar does not sprout
one. Also inherit refresh_interval, so a clock or status display keeps ticking
while the nested prompt waits rather than freezing at its first render.

select() is deliberately left alone: prompt-toolkit's choice() accepts a toolbar
but has no refresh_interval, so its toolbar would go stale while the selection
sits idle.
@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.67%. Comparing base (68932ec) to head (83a4b68).

Additional details and impacted files
@@                  Coverage Diff                  @@
##           consolidated_toolbar    #1750   +/-   ##
=====================================================
  Coverage                 99.67%   99.67%           
=====================================================
  Files                        25       25           
  Lines                      6464     6464           
=====================================================
  Hits                       6443     6443           
  Misses                       21       21           
Flag Coverage Δ
unittests 99.67% <ø> (ø)

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.

@tleonhardt tleonhardt self-assigned this Sep 6, 2026
@tleonhardt
tleonhardt merged commit dee4c9b into consolidated_toolbar Sep 6, 2026
29 checks passed
@tleonhardt
tleonhardt deleted the nested-prompt-toolbar branch September 6, 2026 22:26
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