fix: address verified review findings (terminal-forms-1)

Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
bircni committed 2026-10-18 17:42:24 +02:00
1 parent caeed59bc6
commit 0910cf307a
21 files changed
+329 -53

No files matched your search

+37 -2
View File
@@ -3,7 +3,14 @@
package terminal
import "charm.land/huh/v2"
import (
"errors"
"strings"
"unicode"
"unicode/utf8"
"charm.land/huh/v2"
)
// BodyTitle labels the markdown body of issues, pull requests and comments.
const BodyTitle = "Body (markdown):"
@@ -11,9 +18,17 @@ const BodyTitle = "Body (markdown):"
// maxVisibleOptions bounds how many options a multi-select shows before it scrolls.
const maxVisibleOptions = 8
// notBlank rejects empty and whitespace-only answers, which huh.ValidateNotEmpty accepts.
func notBlank(s string) error {
if strings.TrimSpace(s) == "" {
return errors.New("input cannot be empty")
}
return nil
}
// titleField is the required one-line title of an issue, pull request or similar resource.
func titleField(value *string) *huh.Input {
return huh.NewInput().Title("Title (required):").Value(value).Validate(huh.ValidateNotEmpty())
return huh.NewInput().Title("Title (required):").Value(value).Validate(notBlank)
}
// bodyField is an inline multi-line markdown field. It has no external editor: forms run the
@@ -22,6 +37,26 @@ func bodyField(title string, value *string) *huh.Text {
return huh.NewText().Title(title).Value(value).ExternalEditor(false)
}
// fieldText is how a multi-line field shows seed: its textarea turns every CR and LF into a line
// break and a tab into four spaces, and drops other control characters.
func fieldText(seed string) string {
return strings.Map(func(r rune) rune {
if r == utf8.RuneError || (unicode.IsControl(r) && r != '\n') {
return -1
}
return r
}, strings.NewReplacer("\r", "\n", "\t", " ").Replace(seed))
}
// fieldResult is the answer of a multi-line field seeded with seed: seed itself when the user
// changed nothing, so a plain Enter does not rewrite existing text such as CRLF line endings.
func fieldResult(seed, answer string) string {
if answer == fieldText(seed) {
return seed
}
return answer
}
// multiSelect lists every option, scrolling past maxVisibleOptions. Without an explicit height,
// huh sizes the list to its options minus the title line and hides the last option.
func multiSelect[T comparable](title string, options []huh.Option[T], value *[]T) *huh.MultiSelect[T] {