Uh oh!
There was an error while loading. Please reload this page.
feat: show the server's prompt on a row above the command line - #39
Conversation
TelnetNegotiationCore 2.11.0 made the GA boundary arrive and TelnetSession flushed it, but the prompt was still displayed nowhere: WorldSession routes an IsPrompt event to CurrentPrompt rather than to ProcessOutputLine, and grep found that property written in one place and read in none. PromptChanged had a single subscriber, `(_, _) => OnUi(UpdateStatus)`, which discards both arguments. The prompt was being received perfectly and painted by nobody. The routing is right and stays: a game ending every turn with HP:100 MP:50 > would double its own output into the scrollback and the transcript, which is what Prompt_UpdatesCurrentPrompt_WithoutScrollback pins. What was missing was a reader, so this adds one. Always exactly one row, elided rather than wrapped. Sticky rows are reserved before the workspace is measured and per-pane NAWS is derived from the pane rectangles, so a band whose height followed whatever the server last sent would re-announce a new terminal size to every connected game on every prompt — the same rule the rail's reserved badge fields already follow. Painted on the untinted idle input band, not the armed one: the armed band means "enter sends from here" and the prompt row is not somewhere you can type. The band is why MarkupFormatter takes an optional plane — the contrast floor is only meaningful against the fill the ink lands on, and the game's own colours land here rather than on a pane. Resolved through WindowSession, never _active, so a background pane's prompt is never shown above a command line aimed elsewhere. StyledText.Truncate is new and does the eliding on the styled line rather than on the markup: cutting markup by character count lands inside a [#rrggbb] or orphans a [/]. Verified on a rendered frame (--view prompt, added to FrameContrastTests so the band is measured on all three themes), not by reading the markup. 948 / 1848 / 83 / 42 / 37, all green.
A prompt is a live connection's question. CurrentPrompt was set and never cleared, so after a disconnect the row kept a dead server's question above a command line that could no longer answer it — and its own doc already said "or null if none is active", which was never true once one had arrived. Cleared before the state change, so anything repainting on StateChanged already sees no prompt and the two never disagree for a frame. Raised only when there was something to clear: a session that disconnects without ever having been prompted must not report a change it did not make. OnDisconnected is the only place it is needed — TelnetSession raises Disconnected from the finally of its read loop, so a clean close and a faulted one both arrive there.
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in:52 minutes Limit details: You’ve used the included review currently available. Your 69 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (9)
Comment |
What
Follow-on from #38. That took the TelnetNegotiationCore fix so an
IAC GAprompt boundary finally arrives, andTelnetSessionflushes the buffered prompt for it — but the prompt was still displayed nowhere.WorldSession.OnOutputReceivedroutes anIsPromptevent toCurrentPromptand returns beforeProcessOutputLine, so it never reaches a pane. And nothing read the property:grep -rn "CurrentPrompt" src/returned two hits — the declaration and the assignment.PromptChangedhad one subscriber,SharpMUTermApp.cs:session.PromptChanged += (_, _) => OnUi(UpdateStatus);— both arguments discarded.The routing is right and stays. A game ending every turn with
HP:100 MP:50 >would double its own output into the scrollback and the transcript, which is whatPrompt_UpdatesCurrentPrompt_WithoutScrollbackpins. What was missing was a reader, so this adds one.The row
PromptRowRendererplus a sticky row directly above the command line, hidden until a prompt arrives.MarkupFormattergained an optional plane for it. The contrast floor is only meaningful against the fill the ink lands on, and this is the one place the client paints the game's colours outside a pane.WindowSession, never_active, so a background pane's prompt is never shown above a command line aimed elsewhere.StateChangedsees the two disagree, and raised only when there was something to clear.StyledText.Truncateis new and does the eliding on the styled line rather than on the markup — cutting markup by character count lands inside a[#rrggbb]or orphans a[/].Verification
All five suites green: Core 950, Tui 1828, Graphics 83, Scripting 42, Web 37, zero failures.
Backed by a rendered frame rather than by reading markup: a new
--view promptsnapshot, added toFrameContrastTests' list so the band is measured on all three themes — the game's own colours land on a fill nothing else in the client uses.Both behavioural fixes were confirmed to fail without their change: deleting the
ClearPrompt()call failsPrompt_IsClearedOnDisconnect, and the first render put the text on the bare backdrop, which is what caught the band being claimed in a doc comment but not drawn.🤖 Generated with Claude Code