refactor: Build prompts from intent constructors instead of a layout flag - #459
Draft
tiurin wants to merge 2 commits into
Draft
refactor: Build prompts from intent constructors instead of a layout flag#459tiurin wants to merge 2 commits into
tiurin wants to merge 2 commits into
Conversation
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WIP - the description is mostly correct however
Motivation
#457 and #458 each fixed one prompt that had shipped with the wrong layout, and the review comment on #457 wrote down the rule they were both applying:
That rule lived nowhere the code could see it.
UserInputRequestEventasked its author for aVertical bool, which is a rendering decision. It is easy to leave the field out. Labels had drifted the same way into three styles at once:[ENTER] Log in again,Update now [U], and a bareAWSadvertising no key at all.Solution
Give user input a vocabulary of intents and derive the layout from it. User promts can be built using one of the new constructors in
internal/output/prompt.go. The developer uses the appropriate prompt type which automatically applies the design rule :output.Confirm(prompt, DefaultYes|DefaultNo, ch)[y/N], capitalized answer is what ENTER picksoutput.ActionChoice(prompt, options, ch)output.Acknowledge(prompt, label, ch)UserInputRequestEventcan't be used directly, but can be easily extended with a new prompt type if needed. See technical details:Technical details
To enforce the usage of constructors,
UserInputRequestEvent's fields are unexported - this is done by renaming variables from uppercase to lowercase and read-only accessors are added. This way a struct literal built anywhere outsideinternal/outputdoes not compile:Unexporting only
Verticalwould not have worked — Go lets a keyed literal from another package omit unexported fields, so the bypass would still compile and would still default to the inline layout that caused the bug. Removing every exported field is what closes it.UserInputRequestEvent{}remains legal but inert: no prompt, nil channel, nothing settable.Also:
output.OptionLabelderives the[KEY]shortcut from each option'sKey, so labels are plain prose (Keep waiting) and can't drift into three styles again.output.KeyYes/KeyNo/KeyAnyinstead of string literals.FormatPromptEvent) — a one-line fallback of plain-prose labels would otherwise leave the user with nothing to press.internal/ui's tests used to build by hand (an explicitenteroption outranking an uppercase default, all-lowercase labels, non-letter labels) are unreachable in production now, so those rules are pinned inTestResolveOption, which feedsresolveOptionarbitrary slices directly.Applying the rule uniformly shifts a few prompts that were on the wrong side of it:
[ENTER to log in again/ESC to exit]appended to a wrapping question[R] Re-authenticate/[ESC] Exitas rows; the sentence keeps only the reasonreset,volume clear[Yes/NO][y/N]Update now [U][U] Update nowAWS/Azurerows[A] AWS/[Z] AzureDocs
Two user-visible changes worth a writer's eye, both cosmetic-adjacent but not invisible:
R([R] Re-authenticate). ENTER still works — it confirms the highlighted row — but any doc or screenshot that says "press ENTER to log in again" now describes a second-best path. The decline key (ESC) is unchanged.lstk reset,lstk volume clear) now render[y/N]instead of[Yes/NO]. Same keys, same default (no); only the hint changed.Everything else is internal: no command, flag, env var, or config surface changes.
Review
WIP
Validation
go test ./internal/... ./cmd/... -count=1golangci-lint run ./...— 0 issuesmake buildinternal/reset/reset.goand confirminggo build ./...rejects itFollow-up to #457 and #458.