GoSetup-bubble/setup/fields/select.go

157 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package fields
import (
"bubble/setup/utils"
"fmt"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
)
// SelectModel структура описывающая модель поля выбора опции
type SelectModel struct {
label string //Имя поля
description string //Описание пол
options []string //Элементы выбора
focus int //Фокус для управления опциями
open bool //Открыт ли список
chosen string //Выбранный элемент
optionsCount int //Количество элементов к показу
validate textinput.ValidateFunc
err error
}
// NewSelectModel создаем новую поля выбора опции
func NewSelectModel(label, value, description string, options []string, validator textinput.ValidateFunc) *SelectModel {
//Проверка, что указанный по умолчанию элемент есть в списке опции
selectModel := &SelectModel{
options: options,
label: label,
description: description,
focus: len(options),
validate: validator,
optionsCount: 10,
}
found := false
for i := range options {
if options[i] == value {
found = true
}
}
if !found {
value = ""
}
selectModel.chosen = value
selectModel.SelectValidate()
return selectModel
}
func (m *SelectModel) Init() tea.Cmd {
return textinput.Blink
}
func (m *SelectModel) Update(msg tea.Msg) (FieldModel, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
//Отслеживаем нажатия клавиш.
//Если список открыт, то отслеживаем клавиши отдельно
if m.open {
switch msg.String() {
case "esc":
//Закрываем список
m.open = false
case "up":
//Уменьшаем фокус, поднимаем его
m.focus--
if m.focus < 0 {
m.focus = len(m.options) - 1
}
case "down":
//Увеличиваем фокус, опускаем его
m.focus++
if m.focus == len(m.options) {
m.focus = 0
}
case "enter":
//Выбираем опцию из списка
if len(m.options) == 0 || m.focus >= len(m.options) {
return m, nil
}
m.chosen = m.options[m.focus]
m.open = false
m.focus = 0
m.SelectValidate()
return m, nil
}
} else {
//Если список не открыт и был нажат enter, открываем его и устанавливаем фокус на основе опций.
switch msg.String() {
case "enter":
m.open = true
for optionIdx := range m.options {
if m.options[optionIdx] == m.chosen {
m.focus = optionIdx
}
}
if m.chosen == "" && len(m.options) > 0 {
m.focus = 0
}
}
}
}
return m, cmd
}
func (m *SelectModel) View() string {
res := fmt.Sprintf("%s: %s", m.label, m.chosen)
if m.err != nil && !m.open {
res += fmt.Sprintf("\nОшибка валидации: %s", m.err)
} else if m.description != "" {
res += fmt.Sprintf("\n%s", m.description)
}
if m.open && len(m.options) > 0 {
start, end := utils.CalculateSelectOptionsIndex(m.focus, m.optionsCount, len(m.options))
for i := start; i < end; i++ {
option := m.options[i]
prefix := "\n\t"
if m.focus == i {
prefix += "-> "
} else {
prefix += " "
}
res += prefix + option
}
}
return res
}
func (m *SelectModel) Close() {
m.open = false
}
func (m *SelectModel) Focus() {
}
func (m *SelectModel) Blur() {
m.open = false
}
func (m *SelectModel) CaptureKeys() bool {
return m.open
}
func (m *SelectModel) GetLabel() string {
return m.label
}
func (m *SelectModel) GetValue() interface{} {
return m.chosen
}
func (m *SelectModel) SelectValidate() {
if m.validate != nil {
m.err = m.validate(m.chosen)
}
}