GoSetup-bubble/setup/main.go

229 lines
6.2 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 setup
import (
"bubble/bootstrap"
"bubble/types"
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/sirupsen/logrus"
)
func Start() {
p := tea.NewProgram(NewMain(), tea.WithAltScreen())
if _, err := p.Run(); err != nil {
panic(err)
}
}
type Main struct {
current tea.Model
overlay tea.Model
Applications []types.PackageApplication
CurrentApplication *types.PackageApplication
CurrentSection *types.Section
CurrentSectionIdx int
Width int
Height int
}
func NewMain() *Main {
apps := bootstrap.LoadApplications()
m := &Main{
Applications: apps,
CurrentSectionIdx: 0,
}
m.current = NewListApplicationsModel(m.Applications, m.Width, m.Height)
return m
}
func (m *Main) Init() tea.Cmd {
return m.current.Init()
}
func (m *Main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
if m.overlay != nil {
var cmd tea.Cmd
m.overlay, cmd = m.overlay.Update(msg)
if cmd != nil {
cmds = append(cmds, cmd)
}
} else {
var cmd tea.Cmd
m.current, cmd = m.current.Update(msg)
if cmd != nil {
cmds = append(cmds, cmd)
}
}
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.Width = msg.Width
m.Height = msg.Height
if m.current != nil {
m.current, _ = m.current.Update(msg)
}
if m.overlay != nil {
m.overlay, _ = m.overlay.Update(msg)
}
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
}
case types.NextSectionMsg:
m.CurrentSectionIdx++
if m.CurrentSectionIdx == len(m.CurrentApplication.Sections) {
return m, tea.Quit
}
for sectionIdx := m.CurrentSectionIdx; sectionIdx < len(m.CurrentApplication.Sections); sectionIdx++ {
//todo переделать. Учесть динамические индексы.
section := m.CurrentApplication.Sections[sectionIdx]
if CheckCondition(section.Condition, m.CurrentApplication) {
m.CurrentSectionIdx = sectionIdx
m.CurrentSection = &section
break
}
}
if m.CurrentSection == nil {
return m, func() tea.Msg {
return types.ShowModalMsg{
Type: types.ModalError,
Title: "Ошибка конфигурации",
Message: "Это приложение не имеет доступных секций для настройки\n" +
"Возможно оно повреждено или не поддерживается",
ModalButtons: []types.ModalButton{{Text: "Выйти", Value: true}},
OnResult: func(result any) tea.Cmd {
return tea.Quit
},
}
}
}
//todo переделать. Учесть динамические индексы.
if m.CurrentSectionIdx == len(m.CurrentApplication.Sections)-1 && m.CurrentSection.Type == types.SectionFinal {
m.current = NewFinalModel(m.CurrentApplication.Variables, m.Width, m.Height)
} else {
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, 0, m.Width, m.Height)
}
case types.SugarMsg:
m.Sugar(msg)
case types.SelectedAppMsg:
//получаем сообщение о выборе приложения
m.CurrentApplication = &msg.App
//ищем доступную секцию
for sectionIdx := 0; sectionIdx < len(m.CurrentApplication.Sections); sectionIdx++ {
section := m.CurrentApplication.Sections[sectionIdx]
if CheckCondition(section.Condition, m.CurrentApplication) {
m.CurrentSectionIdx = sectionIdx
m.CurrentSection = &section
break
}
}
//если секция не была найдена, то выходим
if m.CurrentSection == nil {
logrus.Infof("select app, eq nil, out")
return m, tea.Quit
}
//создаем новую форму
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, 0, m.Width, m.Height)
case types.BackToListMsg:
m.CurrentApplication = nil
m.CurrentSection = nil
m.CurrentSectionIdx = 0
m.current = NewListApplicationsModel(m.Applications, m.Width, m.Height)
case types.ShowModalMsg:
m.overlay = NewModalModel(msg, m.Width, m.Height)
return m, nil
case types.CloseModalMsg:
logrus.Infof("modal close msg get")
m.overlay = nil
return m, tea.Batch(cmds...)
}
return m, tea.Batch(cmds...)
}
func (m *Main) View() string {
view := m.current.View()
if m.overlay != nil {
view = m.overlay.View()
}
return view
}
func (m *Main) Sugar(sugar types.SugarMsg) {
if m.IsMultiField(sugar.VariableName) {
m.DeactivateField(sugar.VariableName, sugar.FieldName)
}
if IsParent(sugar.VariableName, m.CurrentApplication.Sections) {
if sugar.Compute != "" {
Recompute(m.CurrentApplication)
}
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, sugar.Focus, m.Width, m.Height)
}
}
func IsParent(variableName string, sections []types.Section) bool {
for _, section := range sections {
for _, parent := range section.Parent {
if parent == variableName {
return true
}
}
for _, field := range section.Fields {
for _, parent := range field.Parent {
if parent == variableName {
return true
}
}
}
}
return false
}
func (m *Main) IsMultiField(variableName string) bool {
var count int
for _, section := range m.CurrentApplication.Sections {
for _, field := range section.Fields {
if field.Name == variableName {
count++
}
}
}
return count > 1
}
func (m *Main) DeactivateField(variableName, fieldName string) {
for sectionIdx, section := range m.CurrentApplication.Sections {
for fieldIdx, field := range section.Fields {
if field.Variable.Name == variableName {
if field.Name != fieldName {
m.CurrentApplication.Sections[sectionIdx].Fields[fieldIdx].Active = false
} else {
m.CurrentApplication.Sections[sectionIdx].Fields[fieldIdx].Active = true
}
}
}
}
}
func (m *Main) RecomputeFields() {
for i := range m.CurrentApplication.Sections {
section := &m.CurrentApplication.Sections[i]
for j := range section.Fields {
field := &section.Fields[j]
if field.FieldType == "compute" && field.Compute != "" {
if field.Variable != nil {
continue
}
value, err := ComputeValue(field.Compute, m.CurrentApplication)
if err != nil {
value = fmt.Sprintf("Ошибка вычисления: %v", err)
}
field.Variable.Value = value
}
}
}
}