From bba59d2e4e65f4f6d2270b24f667315e1c554473 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 03:15:18 +0000 Subject: [PATCH] Bump github.com/charmbracelet/huh from 0.7.0 to 0.8.0 Bumps [github.com/charmbracelet/huh](https://github.com/charmbracelet/huh) from 0.7.0 to 0.8.0. - [Release notes](https://github.com/charmbracelet/huh/releases) - [Commits](https://github.com/charmbracelet/huh/compare/v0.7.0...v0.8.0) --- updated-dependencies: - dependency-name: github.com/charmbracelet/huh dependency-version: 0.8.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 +-- go.sum | 12 +++---- .../charmbracelet/bubbles/cursor/cursor.go | 4 ++- .../charmbracelet/bubbles/table/table.go | 12 +++++-- .../bubbles/textarea/textarea.go | 2 +- .../bubbles/textinput/textinput.go | 2 +- .../charmbracelet/huh/.golangci.yml | 13 +++---- vendor/github.com/charmbracelet/huh/README.md | 12 +++---- .../charmbracelet/huh/field_confirm.go | 18 +++++----- .../charmbracelet/huh/field_filepicker.go | 17 ++++++---- .../charmbracelet/huh/field_input.go | 18 +++++----- .../charmbracelet/huh/field_multiselect.go | 15 ++++---- .../charmbracelet/huh/field_note.go | 13 ++++--- .../charmbracelet/huh/field_select.go | 33 ++++++++++++------ .../charmbracelet/huh/field_text.go | 16 +++++---- vendor/github.com/charmbracelet/huh/form.go | 11 +++--- vendor/github.com/charmbracelet/huh/group.go | 34 +++++++++++-------- .../internal/accessibility/accessibility.go | 14 ++++++-- vendor/github.com/charmbracelet/huh/layout.go | 13 ++++--- vendor/modules.txt | 4 +-- 20 files changed, 156 insertions(+), 111 deletions(-) diff --git a/go.mod b/go.mod index 2e7516f..9c75e54 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,9 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0 github.com/BurntSushi/toml v1.5.0 - github.com/charmbracelet/bubbles v0.21.0 + github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 github.com/charmbracelet/bubbletea v1.3.9 - github.com/charmbracelet/huh v0.7.0 + github.com/charmbracelet/huh v0.8.0 github.com/charmbracelet/huh/spinner v0.0.0-20250714122654-40d2b68703eb github.com/charmbracelet/lipgloss v1.1.0 github.com/charmbracelet/log v0.4.2 diff --git a/go.sum b/go.sum index 0b4b02a..2509c8f 100644 --- a/go.sum +++ b/go.sum @@ -32,18 +32,18 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= -github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= +github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY= +github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY= github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= -github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= -github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= +github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 h1:JFgG/xnwFfbezlUnFMJy0nusZvytYysV4SCS2cYbvws= +github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7/go.mod h1:ISC1gtLcVilLOf23wvTfoQuYbW2q0JevFxPfUzZ9Ybw= github.com/charmbracelet/bubbletea v1.3.9 h1:OBYdfRo6QnlIcXNmcoI2n1NNS65Nk6kI2L2FO1puS/4= github.com/charmbracelet/bubbletea v1.3.9/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= -github.com/charmbracelet/huh v0.7.0 h1:W8S1uyGETgj9Tuda3/JdVkc3x7DBLZYPZc4c+/rnRdc= -github.com/charmbracelet/huh v0.7.0/go.mod h1:UGC3DZHlgOKHvHC07a5vHag41zzhpPFj34U92sOmyuk= +github.com/charmbracelet/huh v0.8.0 h1:Xz/Pm2h64cXQZn/Jvele4J3r7DDiqFCNIVteYukxDvY= +github.com/charmbracelet/huh v0.8.0/go.mod h1:5YVc+SlZ1IhQALxRPpkGwwEKftN/+OlJlnJYlDRFqN4= github.com/charmbracelet/huh/spinner v0.0.0-20250714122654-40d2b68703eb h1:foK5EYUrChM3+7lK6qCEH43p/3oljGMtWtRq+tv3As4= github.com/charmbracelet/huh/spinner v0.0.0-20250714122654-40d2b68703eb/go.mod h1:imftm8y+Db+rZ4Jcb6A7qJ0eOX78s9m84n8cdipC+R0= github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= diff --git a/vendor/github.com/charmbracelet/bubbles/cursor/cursor.go b/vendor/github.com/charmbracelet/bubbles/cursor/cursor.go index d101332..155d56c 100644 --- a/vendor/github.com/charmbracelet/bubbles/cursor/cursor.go +++ b/vendor/github.com/charmbracelet/bubbles/cursor/cursor.go @@ -173,11 +173,13 @@ func (m *Model) BlinkCmd() tea.Cmd { m.blinkTag++ + blinkMsg := BlinkMsg{id: m.id, tag: m.blinkTag} + return func() tea.Msg { defer cancel() <-ctx.Done() if ctx.Err() == context.DeadlineExceeded { - return BlinkMsg{id: m.id, tag: m.blinkTag} + return blinkMsg } return blinkCanceled{} } diff --git a/vendor/github.com/charmbracelet/bubbles/table/table.go b/vendor/github.com/charmbracelet/bubbles/table/table.go index ed29d8c..4dd1203 100644 --- a/vendor/github.com/charmbracelet/bubbles/table/table.go +++ b/vendor/github.com/charmbracelet/bubbles/table/table.go @@ -4,12 +4,13 @@ package table import ( "strings" - "github.com/charmbracelet/bubbles/help" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/mattn/go-runewidth" + + "github.com/charmbracelet/bubbles/help" + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/viewport" ) // Model defines a state for the table widget. @@ -306,6 +307,11 @@ func (m Model) Columns() []Column { // SetRows sets a new rows state. func (m *Model) SetRows(r []Row) { m.rows = r + + if m.cursor > len(m.rows)-1 { + m.cursor = len(m.rows) - 1 + } + m.UpdateViewport() } diff --git a/vendor/github.com/charmbracelet/bubbles/textarea/textarea.go b/vendor/github.com/charmbracelet/bubbles/textarea/textarea.go index d82ae97..61c5537 100644 --- a/vendor/github.com/charmbracelet/bubbles/textarea/textarea.go +++ b/vendor/github.com/charmbracelet/bubbles/textarea/textarea.go @@ -653,7 +653,7 @@ func (m *Model) deleteWordLeft() { // Linter note: it's critical that we acquire the initial cursor position // here prior to altering it via SetCursor() below. As such, moving this // call into the corresponding if clause does not apply here. - oldCol := m.col //nolint:ifshort + oldCol := m.col m.SetCursor(m.col - 1) for unicode.IsSpace(m.value[m.row][m.col]) { diff --git a/vendor/github.com/charmbracelet/bubbles/textinput/textinput.go b/vendor/github.com/charmbracelet/bubbles/textinput/textinput.go index 84cbbc9..9c6666e 100644 --- a/vendor/github.com/charmbracelet/bubbles/textinput/textinput.go +++ b/vendor/github.com/charmbracelet/bubbles/textinput/textinput.go @@ -400,7 +400,7 @@ func (m *Model) deleteWordBackward() { // Linter note: it's critical that we acquire the initial cursor position // here prior to altering it via SetCursor() below. As such, moving this // call into the corresponding if clause does not apply here. - oldPos := m.pos //nolint:ifshort + oldPos := m.pos m.SetCursor(m.pos - 1) for unicode.IsSpace(m.value[m.pos]) { diff --git a/vendor/github.com/charmbracelet/huh/.golangci.yml b/vendor/github.com/charmbracelet/huh/.golangci.yml index 7c0a115..929cb0a 100644 --- a/vendor/github.com/charmbracelet/huh/.golangci.yml +++ b/vendor/github.com/charmbracelet/huh/.golangci.yml @@ -7,7 +7,6 @@ linters: - exhaustive - goconst - godot - - godox - gomoddirectives - goprintffuncname - gosec @@ -27,13 +26,13 @@ linters: - whitespace - wrapcheck exclusions: + rules: + - text: '(slog|log)\.\w+' + linters: + - noctx generated: lax presets: - common-false-positives - paths: - - third_party$ - - builtin$ - - examples$ issues: max-issues-per-linter: 0 max-same-issues: 0 @@ -43,7 +42,3 @@ formatters: - goimports exclusions: generated: lax - paths: - - third_party$ - - builtin$ - - examples$ diff --git a/vendor/github.com/charmbracelet/huh/README.md b/vendor/github.com/charmbracelet/huh/README.md index 5694c79..03484db 100644 --- a/vendor/github.com/charmbracelet/huh/README.md +++ b/vendor/github.com/charmbracelet/huh/README.md @@ -403,14 +403,15 @@ For more on Spinners see the [spinner examples](./spinner/examples) and Bubbletea + Huh? -In addition to its standalone mode, `huh?` has first-class support for -[Bubble Tea][tea] and can be easily integrated into Bubble Tea applications. -It’s incredibly useful in portions of your Bubble Tea application that need -form-like input. +Huh is built on [Bubble Tea][tea] and, in addition to its standalone mode, +`huh?` has first-class support and can be easily integrated into +Bubble Tea applications. It’s very useful in portions of your Bubble Tea +application that need form-like input, and for times when you need more +flexibility than `huh?` alone can offer. Bubble Tea embedded form example -A `huh.Form` is merely a `tea.Model`, so you can use it just as +A `huh.Form` is just a `tea.Model`, so you can use it just as you would any other [Bubble](https://github.com/charmbracelet/bubbles). ```go @@ -476,7 +477,6 @@ For some `Huh?` programs in production, see: * [glyphs](https://github.com/maaslalani/glyphs): a unicode symbol picker * [meteor](https://github.com/stefanlogue/meteor): a highly customisable conventional commit message tool * [freeze](https://github.com/charmbracelet/freeze): a tool for generating images of code and terminal output -* [gum](https://github.com/charmbracelet/gum): a tool for glamorous shell scripts * [savvy](https://github.com/getsavvyinc/savvy-cli): the easiest way to create, share, and run runbooks in the terminal ## Contributing diff --git a/vendor/github.com/charmbracelet/huh/field_confirm.go b/vendor/github.com/charmbracelet/huh/field_confirm.go index 1c4b572..d788f89 100644 --- a/vendor/github.com/charmbracelet/huh/field_confirm.go +++ b/vendor/github.com/charmbracelet/huh/field_confirm.go @@ -35,7 +35,7 @@ type Confirm struct { width int height int inline bool - accessible bool + accessible bool // Deprecated: use RunAccessible instead. theme *Theme keymap ConfirmKeyMap buttonAlignment lipgloss.Position @@ -285,10 +285,7 @@ func (c *Confirm) View() string { promptWidth := lipgloss.Width(sb.String()) buttonsWidth := lipgloss.Width(buttonsRow) - renderWidth := promptWidth - if buttonsWidth > renderWidth { - renderWidth = buttonsWidth - } + renderWidth := max(buttonsWidth, promptWidth) style := lipgloss.NewStyle().Width(renderWidth).Align(c.buttonAlignment) @@ -299,14 +296,14 @@ func (c *Confirm) View() string { // Run runs the confirm field in accessible mode. func (c *Confirm) Run() error { - if c.accessible { - return c.runAccessible(os.Stdout, os.Stdin) + if c.accessible { // TODO: remove in a future release. + return c.RunAccessible(os.Stdout, os.Stdin) } return Run(c) } -// runAccessible runs the confirm field in accessible mode. -func (c *Confirm) runAccessible(w io.Writer, r io.Reader) error { +// RunAccessible runs the confirm field in accessible mode. +func (c *Confirm) RunAccessible(w io.Writer, r io.Reader) error { styles := c.activeStyles() defaultValue := c.GetValue().(bool) opts := "[y/N]" @@ -343,6 +340,9 @@ func (c *Confirm) WithKeyMap(k *KeyMap) Field { } // WithAccessible sets the accessible mode of the confirm field. +// +// Deprecated: you may now call [Confirm.RunAccessible] directly to run the +// field in accessible mode. func (c *Confirm) WithAccessible(accessible bool) Field { c.accessible = accessible return c diff --git a/vendor/github.com/charmbracelet/huh/field_filepicker.go b/vendor/github.com/charmbracelet/huh/field_filepicker.go index 06ab056..760c4ab 100644 --- a/vendor/github.com/charmbracelet/huh/field_filepicker.go +++ b/vendor/github.com/charmbracelet/huh/field_filepicker.go @@ -36,7 +36,7 @@ type FilePicker struct { // options width int height int - accessible bool + accessible bool // Deprecated: use RunAccessible instead. theme *Theme keymap FilePickerKeyMap } @@ -102,7 +102,7 @@ func (f *FilePicker) FileAllowed(v bool) *FilePicker { return f } -// DirAllowed sets whether to allow files to be selected. +// DirAllowed sets whether to allow directories to be selected. func (f *FilePicker) DirAllowed(v bool) *FilePicker { f.picker.DirAllowed = v return f @@ -274,7 +274,7 @@ func (f *FilePicker) View() string { } parts = append(parts, f.pickerView()) return styles.Base.Width(f.width).Height(f.height). - Render(lipgloss.JoinVertical(lipgloss.Top, parts...)) + Render(strings.Join(parts, "\n")) } func (f *FilePicker) pickerView() string { @@ -308,14 +308,14 @@ func (f *FilePicker) setPicking(v bool) { // Run runs the file field. func (f *FilePicker) Run() error { - if f.accessible { - return f.runAccessible(os.Stdout, os.Stdin) + if f.accessible { // TODO: remove in a future release. + return f.RunAccessible(os.Stdout, os.Stdin) } return Run(f) } -// runAccessible runs an accessible file field. -func (f *FilePicker) runAccessible(w io.Writer, r io.Reader) error { +// RunAccessible runs an accessible file field. +func (f *FilePicker) RunAccessible(w io.Writer, r io.Reader) error { styles := f.activeStyles() prompt := styles.Title. PaddingRight(1). @@ -403,6 +403,9 @@ func (f *FilePicker) WithKeyMap(k *KeyMap) Field { } // WithAccessible sets the accessible mode of the file field. +// +// Deprecated: you may now call [FilePicker.RunAccessible] directly to run the +// field in accessible mode. func (f *FilePicker) WithAccessible(accessible bool) Field { f.accessible = accessible return f diff --git a/vendor/github.com/charmbracelet/huh/field_input.go b/vendor/github.com/charmbracelet/huh/field_input.go index 7a66dcd..78a5bd7 100644 --- a/vendor/github.com/charmbracelet/huh/field_input.go +++ b/vendor/github.com/charmbracelet/huh/field_input.go @@ -38,9 +38,9 @@ type Input struct { err error focused bool - accessible bool + accessible bool // Deprecated: use RunAccessible instead. width int - height int // not really used anywhere + height int theme *Theme keymap InputKeyMap @@ -417,8 +417,8 @@ func (i *Input) View() string { // Run runs the input field in accessible mode. func (i *Input) Run() error { - if i.accessible { - return i.runAccessible(os.Stdout, os.Stdin) + if i.accessible { // TODO: remove in a future release. + return i.RunAccessible(os.Stdout, os.Stdin) } return i.run() } @@ -428,8 +428,8 @@ func (i *Input) run() error { return Run(i) } -// runAccessible runs the input field in accessible mode. -func (i *Input) runAccessible(w io.Writer, r io.Reader) error { +// RunAccessible runs the input field in accessible mode. +func (i *Input) RunAccessible(w io.Writer, r io.Reader) error { styles := i.activeStyles() validator := func(input string) error { if i.textinput.CharLimit > 0 && len(input) > i.textinput.CharLimit { @@ -438,8 +438,7 @@ func (i *Input) runAccessible(w io.Writer, r io.Reader) error { return i.validate(input) } - //nolint:exhaustive - switch i.textinput.EchoMode { + switch i.textinput.EchoMode { //nolint:exhaustive case textinput.EchoNormal: prompt := styles.Title. PaddingRight(1). @@ -471,6 +470,9 @@ func (i *Input) WithKeyMap(k *KeyMap) Field { } // WithAccessible sets the accessible mode of the input field. +// +// Deprecated: you may now call [Input.RunAccessible] directly to run the +// field in accessible mode. func (i *Input) WithAccessible(accessible bool) Field { i.accessible = accessible return i diff --git a/vendor/github.com/charmbracelet/huh/field_multiselect.go b/vendor/github.com/charmbracelet/huh/field_multiselect.go index f3328a5..4b66156 100644 --- a/vendor/github.com/charmbracelet/huh/field_multiselect.go +++ b/vendor/github.com/charmbracelet/huh/field_multiselect.go @@ -47,7 +47,7 @@ type MultiSelect[T comparable] struct { // options width int - accessible bool + accessible bool // Deprecated: use RunAccessible instead. theme *Theme keymap MultiSelectKeyMap } @@ -700,14 +700,14 @@ func (m *MultiSelect[T]) setSelectAllHelp() { // Run runs the multi-select field. func (m *MultiSelect[T]) Run() error { - if m.accessible { - return m.runAccessible(os.Stdout, os.Stdin) + if m.accessible { // TODO: remove in a future release. + return m.RunAccessible(os.Stdout, os.Stdin) } return Run(m) } -// runAccessible() runs the multi-select field in accessible mode. -func (m *MultiSelect[T]) runAccessible(w io.Writer, r io.Reader) error { +// RunAccessible runs the multi-select field in accessible mode. +func (m *MultiSelect[T]) RunAccessible(w io.Writer, r io.Reader) error { styles := m.activeStyles() title := styles.Title. PaddingRight(1). @@ -725,7 +725,7 @@ func (m *MultiSelect[T]) runAccessible(w io.Writer, r io.Reader) error { prompt := fmt.Sprintf("Input a number between %d and %d: ", 0, len(m.options.val)) choice = accessibility.PromptInt(w, r, prompt, 0, len(m.options.val), nil) - if choice == 0 { + if choice <= 0 { m.updateValue() err := m.validate(m.accessor.Get()) if err != nil { @@ -774,6 +774,9 @@ func (m *MultiSelect[T]) WithKeyMap(k *KeyMap) Field { } // WithAccessible sets the accessible mode of the multi-select field. +// +// Deprecated: you may now call [MultiSelect.RunAccessible] directly to run the +// field in accessible mode. func (m *MultiSelect[T]) WithAccessible(accessible bool) Field { m.accessible = accessible return m diff --git a/vendor/github.com/charmbracelet/huh/field_note.go b/vendor/github.com/charmbracelet/huh/field_note.go index cb4285c..0b4bdc4 100644 --- a/vendor/github.com/charmbracelet/huh/field_note.go +++ b/vendor/github.com/charmbracelet/huh/field_note.go @@ -26,7 +26,7 @@ type Note struct { showNextButton bool skip bool - accessible bool + accessible bool // Deprecated: use RunAccessible instead. height int width int @@ -242,14 +242,14 @@ func (n *Note) View() string { // Run runs the note field. func (n *Note) Run() error { - if n.accessible { - return n.runAccessible(os.Stdout, os.Stdin) + if n.accessible { // TODO: remove in a future release. + return n.RunAccessible(os.Stdout, os.Stdin) } return Run(n) } -// runAccessible runs an accessible note field. -func (n *Note) runAccessible(w io.Writer, _ io.Reader) error { +// RunAccessible runs an accessible note field. +func (n *Note) RunAccessible(w io.Writer, _ io.Reader) error { styles := n.activeStyles() if n.title.val != "" { _, _ = fmt.Fprintln(w, styles.Title.Render(n.title.val)) @@ -276,6 +276,9 @@ func (n *Note) WithKeyMap(k *KeyMap) Field { } // WithAccessible sets the accessible mode of the note field. +// +// Deprecated: you may now call [Note.RunAccessible] directly to run the +// field in accessible mode. func (n *Note) WithAccessible(accessible bool) Field { n.accessible = accessible return n diff --git a/vendor/github.com/charmbracelet/huh/field_select.go b/vendor/github.com/charmbracelet/huh/field_select.go index 5fe66fe..115c542 100644 --- a/vendor/github.com/charmbracelet/huh/field_select.go +++ b/vendor/github.com/charmbracelet/huh/field_select.go @@ -52,7 +52,7 @@ type Select[T comparable] struct { inline bool width int height int - accessible bool + accessible bool // Deprecated: use RunAccessible instead. theme *Theme keymap SelectKeyMap } @@ -74,6 +74,7 @@ func NewSelect[T comparable]() *Select[T] { validate: func(T) error { return nil }, filtering: false, filter: filter, + id: nextID(), options: Eval[[]Option[T]]{cache: make(map[uint64][]Option[T])}, title: Eval[string]{cache: make(map[uint64]string)}, description: Eval[string]{cache: make(map[uint64]string)}, @@ -539,6 +540,7 @@ func (s *Select[T]) updateViewportHeight() { } s.viewport.Height = max(minHeight, s.height-offset) + s.viewport.YOffset = s.selected } func (s *Select[T]) activeStyles() *FieldStyles { @@ -561,7 +563,6 @@ func (s *Select[T]) titleView() string { if s.filtering { sb.WriteString(s.filter.View()) } else if s.filter.Value() != "" && !s.inline { - sb.WriteString(styles.Title.Render(wrap(s.title.val, maxWidth))) sb.WriteString(styles.Description.Render("/" + s.filter.Value())) } else { sb.WriteString(styles.Title.Render(wrap(s.title.val, maxWidth))) @@ -672,7 +673,7 @@ func (s *Select[T]) View() string { } parts = append(parts, s.viewport.View()) return styles.Base.Width(s.width).Height(s.height). - Render(lipgloss.JoinVertical(lipgloss.Top, parts...)) + Render(strings.Join(parts, "\n")) } // clearFilter clears the value of the filter. @@ -701,14 +702,14 @@ func (s *Select[T]) filterFunc(option string) bool { // Run runs the select field. func (s *Select[T]) Run() error { - if s.accessible { - return s.runAccessible(os.Stdout, os.Stdin) + if s.accessible { // TODO: remove in a future release. + return s.RunAccessible(os.Stdout, os.Stdin) } return Run(s) } -// runAccessible runs an accessible select field. -func (s *Select[T]) runAccessible(w io.Writer, r io.Reader) error { +// RunAccessible runs an accessible select field. +func (s *Select[T]) RunAccessible(w io.Writer, r io.Reader) error { styles := s.activeStyles() _, _ = fmt.Fprintln(w, styles.Title. PaddingRight(1). @@ -718,10 +719,19 @@ func (s *Select[T]) runAccessible(w io.Writer, r io.Reader) error { _, _ = fmt.Fprintf(w, "%d. %s\n", i+1, option.Key) } - prompt := fmt.Sprintf("Input a number between %d and %d: ", 1, len(s.options.val)) + var defaultValue *int + switch s.accessor.(type) { + case *PointerAccessor[T]: // if its of this type, it means it has a default value + s.selectOption() // make sure s.selected is set + idx := s.selected + 1 + defaultValue = &idx + } + prompt := fmt.Sprintf("Enter a number between %d and %d: ", 1, len(s.options.val)) + if len(s.options.val) == 1 { + prompt = "There is only one option available; enter the number 1:" + } for { - selected := s.selected + 1 - choice := accessibility.PromptInt(w, r, prompt, 1, len(s.options.val), &selected) + choice := accessibility.PromptInt(w, r, prompt, 1, len(s.options.val), defaultValue) option := s.options.val[choice-1] if err := s.validate(option.Value); err != nil { _, _ = fmt.Fprintln(w, err.Error()) @@ -759,6 +769,9 @@ func (s *Select[T]) WithKeyMap(k *KeyMap) Field { } // WithAccessible sets the accessible mode of the select field. +// +// Deprecated: you may now call [Select.RunAccessible] directly to run the +// field in accessible mode. func (s *Select[T]) WithAccessible(accessible bool) Field { s.accessible = accessible return s diff --git a/vendor/github.com/charmbracelet/huh/field_text.go b/vendor/github.com/charmbracelet/huh/field_text.go index 827ad65..8f21627 100644 --- a/vendor/github.com/charmbracelet/huh/field_text.go +++ b/vendor/github.com/charmbracelet/huh/field_text.go @@ -40,7 +40,7 @@ type Text struct { validate func(string) error err error - accessible bool + accessible bool // Deprecated: use RunAccessible instead. width int theme *Theme @@ -402,19 +402,20 @@ func (t *Text) View() string { } parts = append(parts, t.textarea.View()) - return styles.Base.Render(lipgloss.JoinVertical(lipgloss.Top, parts...)) + return styles.Base. + Render(strings.Join(parts, "\n")) } // Run runs the text field. func (t *Text) Run() error { - if t.accessible { - return t.runAccessible(os.Stdout, os.Stdin) + if t.accessible { // TODO: remove in a future release. + return t.RunAccessible(os.Stdout, os.Stdin) } return Run(t) } -// runAccessible runs an accessible text field. -func (t *Text) runAccessible(w io.Writer, r io.Reader) error { +// RunAccessible runs an accessible text field. +func (t *Text) RunAccessible(w io.Writer, r io.Reader) error { styles := t.activeStyles() prompt := styles.Title. PaddingRight(1). @@ -456,6 +457,9 @@ func (t *Text) WithKeyMap(k *KeyMap) Field { } // WithAccessible sets the accessible mode of the text field. +// +// Deprecated: you may now call [Text.RunAccessible] directly to run the +// field in accessible mode. func (t *Text) WithAccessible(accessible bool) Field { t.accessible = accessible return t diff --git a/vendor/github.com/charmbracelet/huh/form.go b/vendor/github.com/charmbracelet/huh/form.go index f04bd72..978bc89 100644 --- a/vendor/github.com/charmbracelet/huh/form.go +++ b/vendor/github.com/charmbracelet/huh/form.go @@ -151,7 +151,8 @@ type Field interface { // Run runs the field individually. Run() error - runAccessible(w io.Writer, r io.Reader) error + // RunAccessible runs the field in accessible mode with the given IO. + RunAccessible(w io.Writer, r io.Reader) error // Skip returns whether this input should be skipped or not. Skip() bool @@ -167,6 +168,8 @@ type Field interface { WithTheme(*Theme) Field // WithAccessible sets whether the field should run in accessible mode. + // + // Deprecated: you may now call [Field.RunAccessible] directly to run the field in accessible mode. WithAccessible(bool) Field // WithKeyMap sets the keymap on a field. @@ -540,9 +543,7 @@ func (f *Form) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // heightest group, accounting for the width, wraps, etc. neededHeight := 0 f.selector.Range(func(_ int, group *Group) bool { - if h := group.rawHeight(); h > neededHeight { - neededHeight = h - } + neededHeight = max(neededHeight, group.rawHeight()) return true }) @@ -709,7 +710,7 @@ func (f *Form) runAccessible(w io.Writer, r io.Reader) error { group.selector.Range(func(_ int, field Field) bool { field.Init() field.Focus() - _ = field.WithAccessible(true).runAccessible(w, r) + _ = field.WithAccessible(true).RunAccessible(w, r) _, _ = fmt.Fprintln(w) return true }) diff --git a/vendor/github.com/charmbracelet/huh/group.go b/vendor/github.com/charmbracelet/huh/group.go index 4f9bdb3..e8f9af7 100644 --- a/vendor/github.com/charmbracelet/huh/group.go +++ b/vendor/github.com/charmbracelet/huh/group.go @@ -126,7 +126,7 @@ func (g *Group) WithWidth(width int) *Group { // WithHeight sets the height on a group. func (g *Group) WithHeight(height int) *Group { g.height = height - h := height - g.nonContentHeight() + h := height - g.titleFooterHeight() g.viewport.Height = h g.selector.Range(func(_ int, field Field) bool { // A field height must not exceed the form height. @@ -322,7 +322,6 @@ func (g *Group) getContent() (int, string) { func (g *Group) buildView() { offset, content := g.getContent() - g.viewport.SetContent(content) g.viewport.SetYOffset(offset) } @@ -337,24 +336,24 @@ func (g *Group) Header() string { if g.description != "" { parts = append(parts, styles.Description.Render(wrap(g.description, g.width))) } - return lipgloss.JoinVertical(lipgloss.Top, parts...) + return strings.Join(parts, "\n") } -// nonContentHeight returns the height of the footer + header. -func (g *Group) nonContentHeight() int { - var parts []string +// titleFooterHeight returns the height of the footer + header. +func (g *Group) titleFooterHeight() int { + h := 0 if s := g.Header(); s != "" { - parts = append(parts, s) + h += lipgloss.Height(s) } if s := g.Footer(); s != "" { - parts = append(parts, s) + h += lipgloss.Height(s) } - return lipgloss.Height(lipgloss.JoinVertical(lipgloss.Top, parts...)) + return h } // rawHeight returns the full height of the group, without using a viewport. func (g *Group) rawHeight() int { - return lipgloss.Height(g.Content()) + g.nonContentHeight() + return lipgloss.Height(g.Content()) + g.titleFooterHeight() } // View renders the group. @@ -368,7 +367,14 @@ func (g *Group) View() string { // append an empty line, and the footer (usually the help). parts = append(parts, "", s) } - return lipgloss.JoinVertical(lipgloss.Top, parts...) + if len(parts) > 0 { + // Trim suffix spaces from the last part as it can accidentally + // scroll the view up on some terminals (like Apple's Terminal.app) + // when we right to the bottom rightmost corner cell. + lastIdx := len(parts) - 1 + parts[lastIdx] = strings.TrimSuffix(parts[lastIdx], " ") + } + return strings.Join(parts, "\n") } // Content renders the group's content only (no footer). @@ -392,8 +398,6 @@ func (g *Group) Footer() string { )) } } - return g.styles().Base.Render(lipgloss.JoinVertical( - lipgloss.Top, - parts..., - )) + return g.styles().Base. + Render(strings.Join(parts, "\n")) } diff --git a/vendor/github.com/charmbracelet/huh/internal/accessibility/accessibility.go b/vendor/github.com/charmbracelet/huh/internal/accessibility/accessibility.go index 9e139f4..f25f7f1 100644 --- a/vendor/github.com/charmbracelet/huh/internal/accessibility/accessibility.go +++ b/vendor/github.com/charmbracelet/huh/internal/accessibility/accessibility.go @@ -14,6 +14,13 @@ import ( "github.com/charmbracelet/x/term" ) +func atoi(s string) (int, error) { + if strings.TrimSpace(s) == "" { + return -1, nil + } + return strconv.Atoi(s) //nolint:wrapcheck +} + // PromptInt prompts a user for an integer between a certain range. // // Given invalid input (non-integers, integers outside of the range), the user @@ -32,9 +39,12 @@ func PromptInt( if strings.TrimSpace(s) == "" && defaultValue != nil { return nil } - i, err := strconv.Atoi(s) + i, err := atoi(s) if err != nil || i < low || i > high { - return fmt.Errorf("Invalid: must be between %d and %d", low, high) //nolint:staticcheck + if low == high { + return fmt.Errorf("Invalid: must be %d", low) //nolint:staticcheck + } + return fmt.Errorf("Invalid: must be a number between %d and %d", low, high) //nolint:staticcheck } return nil } diff --git a/vendor/github.com/charmbracelet/huh/layout.go b/vendor/github.com/charmbracelet/huh/layout.go index 4bb7f46..8b7965f 100644 --- a/vendor/github.com/charmbracelet/huh/layout.go +++ b/vendor/github.com/charmbracelet/huh/layout.go @@ -1,6 +1,8 @@ package huh import ( + "strings" + "github.com/charmbracelet/lipgloss" ) @@ -76,11 +78,11 @@ func (l *layoutColumns) View(f *Form) string { header := f.selector.Selected().Header() footer := f.selector.Selected().Footer() - return lipgloss.JoinVertical(lipgloss.Left, + return strings.Join([]string{ header, lipgloss.JoinHorizontal(lipgloss.Left, columns...), footer, - ) + }, "\n") } func (l *layoutColumns) GroupWidth(_ *Form, _ *Group, w int) int { @@ -99,7 +101,7 @@ func (l *layoutStack) View(f *Form) string { if footer := f.selector.Selected().Footer(); footer != "" { columns = append(columns, footer) } - return lipgloss.JoinVertical(lipgloss.Top, columns...) + return strings.Join(columns, "\n") } func (l *layoutStack) GroupWidth(_ *Form, _ *Group, w int) int { @@ -159,10 +161,7 @@ func (l *layoutGrid) View(f *Form) string { } footer := f.selector.Selected().Footer() - return lipgloss.JoinVertical( - lipgloss.Top, - append(rows, footer)..., - ) + return strings.Join(append(rows, footer), "\n") } func (l *layoutGrid) GroupWidth(_ *Form, _ *Group, w int) int { diff --git a/vendor/modules.txt b/vendor/modules.txt index 236a23e..28f663f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -86,7 +86,7 @@ github.com/aymanbagabas/go-osc52/v2 # github.com/catppuccin/go v0.3.0 ## explicit; go 1.19 github.com/catppuccin/go -# github.com/charmbracelet/bubbles v0.21.0 +# github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 ## explicit; go 1.23.0 github.com/charmbracelet/bubbles/cursor github.com/charmbracelet/bubbles/filepicker @@ -105,7 +105,7 @@ github.com/charmbracelet/bubbletea # github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc ## explicit; go 1.18 github.com/charmbracelet/colorprofile -# github.com/charmbracelet/huh v0.7.0 +# github.com/charmbracelet/huh v0.8.0 ## explicit; go 1.23.0 github.com/charmbracelet/huh github.com/charmbracelet/huh/internal/accessibility