PromptPlus

|Adr-Plus Fields|Values Migrated | |–|–| |ADR|Read-only answer viewport: shared buffer, resize preserves position| |Version|01| |Revision|01| |Scope|| |Domain|| |Created|Proposed (2026-07-30)| |Changed|Accepted (2026-07-30)| |Superseded||

PromptPlus # PromptPlus ## **ADR0025V01R01** [![NuGet](https://img.shields.io/badge/NuGet-PromptPlus-blue)](https://www.nuget.org/packages/PromptPlus) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![.NET](https://img.shields.io/badge/.NET-8%20%7C%209%20%7C%2010-512BD4)](https://dotnet.microsoft.com/)

↑ ADR Index


ADR0025V01R01 — Read-only answer viewport: shared buffer, resize preserves position

Context

Two independent implementations of the same guarantee — a read-only answer line that scrolls horizontally when its text overflows the console width — coexisted in the codebase:

A real bug was found in TreeControl: it rendered its live answer from its own manually-owned _answerBuffer via ViewportSlice, but its key loop forwarded the answer-scroll keys (Home/End//) to TryAnswerViewportNavigation, which moves the base class’s separate _answerViewportBuffer. Because TreeControl never called WriteAnswerViewport, that buffer was never initialized, so the navigation call always returned false and those keys did nothing — a mismatched hybrid of both patterns, not a deliberate design, confirmed by tracing BaseControlPrompt.TryAnswerViewportNavigation’s null-buffer guard.

Fixing that bug by moving TreeControl fully onto the shared WriteAnswerViewport pattern surfaced a second, unrelated gap: WriteAnswerViewport re-anchored the scroll to Home on any terminal resize, whereas the manual pattern (still used by Select/MultiSelect/Table/MultiTable/Input) deliberately preserves the scroll position across a resize — a past, tested fix (confirmed present in those five controls, and, per a pre-existing test comment, also present in TreeControl before this session by direct analogy to Select). TreeControl would have silently lost that guarantee as a side effect of the buffer-mismatch fix. MultiTreeControl never had it — it always used the shared pattern, which offered no way to opt out of the re-anchor.

An opt-in preservePositionOnResize parameter on WriteAnswerViewport was implemented first, to extend the guarantee to Tree/MultiTree without touching File/MultiFile. Once the follow-up question — should File/MultiFile also preserve position on resize, for full consistency with the other six controls — was answered yes, every caller of WriteAnswerViewport wanted the same behavior, making the opt-in dead weight; it was removed in favor of making the guarantee unconditional.

Decision

  1. BaseControlPrompt.WriteAnswerViewport / TryAnswerViewportNavigation is the canonical mechanism for any control whose answer line is read-only and needs horizontal scrolling. New controls with this need should use it rather than hand-rolling a manual buffer and wiring the key loop to it separately — the shared version couples rendering and key handling to the same buffer instance by construction, which rules out the class of bug found in TreeControl.
  2. A terminal resize never discards the user’s horizontal scroll position on a read-only answer line. WriteAnswerViewport guarantees this unconditionally for all of its callers (File, MultiFile, Tree, MultiTree), matching the resize behavior already present in the five controls that still use the manual pattern (Select, MultiSelect, Table, MultiTable, Input).
  3. Migrating Select/MultiSelect/Table/MultiTable/Input off the manual pattern is out of scope for this decision. Both patterns deliver the same resize guarantee today, so there is no user-visible inconsistency — only an internal-implementation one. A future migration, if pursued, is a separate, boundable change per control, tracked individually rather than bundled here (same convention as ADR0020’s per-control follow-ups).

Consequences