138 lines
3.1 KiB
Go
138 lines
3.1 KiB
Go
|
package settings
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
|
||
|
"git.mlow.ca/mlow/lmcli/pkg/tui/bubbles/list"
|
||
|
"git.mlow.ca/mlow/lmcli/pkg/tui/model"
|
||
|
"git.mlow.ca/mlow/lmcli/pkg/tui/shared"
|
||
|
"git.mlow.ca/mlow/lmcli/pkg/tui/styles"
|
||
|
"github.com/charmbracelet/bubbles/viewport"
|
||
|
tea "github.com/charmbracelet/bubbletea"
|
||
|
"github.com/charmbracelet/lipgloss"
|
||
|
)
|
||
|
|
||
|
type Model struct {
|
||
|
App *model.AppModel
|
||
|
prevView shared.View
|
||
|
content viewport.Model
|
||
|
modelList list.Model
|
||
|
width int
|
||
|
height int
|
||
|
}
|
||
|
|
||
|
type modelOpt struct {
|
||
|
provider string
|
||
|
model string
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
modelListId int = iota + 1
|
||
|
)
|
||
|
|
||
|
func Settings(app *model.AppModel) *Model {
|
||
|
m := &Model{
|
||
|
App: app,
|
||
|
content: viewport.New(0, 0),
|
||
|
}
|
||
|
return m
|
||
|
}
|
||
|
|
||
|
func (m *Model) Init() tea.Cmd {
|
||
|
m.modelList = list.NewWithGroups(m.getModelOptions())
|
||
|
m.modelList.ID = modelListId
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (m *Model) Update(msg tea.Msg) (shared.ViewModel, tea.Cmd) {
|
||
|
var cmd tea.Cmd
|
||
|
|
||
|
switch msg := msg.(type) {
|
||
|
case tea.KeyMsg:
|
||
|
m.modelList, cmd = m.modelList.Update(msg)
|
||
|
if cmd != nil {
|
||
|
return m, cmd
|
||
|
}
|
||
|
|
||
|
switch msg.String() {
|
||
|
case "esc":
|
||
|
return m, func() tea.Msg {
|
||
|
return shared.MsgViewChange(m.prevView)
|
||
|
}
|
||
|
}
|
||
|
case shared.MsgViewEnter:
|
||
|
m.prevView = shared.View(msg)
|
||
|
m.modelList.Focus()
|
||
|
m.content.SetContent(m.renderContent())
|
||
|
case tea.WindowSizeMsg:
|
||
|
m.width, m.height = msg.Width, msg.Height
|
||
|
m.content.Width = msg.Width
|
||
|
m.content.Height = msg.Height
|
||
|
m.content.SetContent(m.renderContent())
|
||
|
case list.MsgOptionSelected:
|
||
|
switch msg.ID {
|
||
|
case modelListId:
|
||
|
if modelOpt, ok := msg.Option.Value.(modelOpt); ok {
|
||
|
m.App.Model = modelOpt.model
|
||
|
m.App.ProviderName = modelOpt.provider
|
||
|
}
|
||
|
return m, shared.ChangeView(m.prevView)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m.modelList, cmd = m.modelList.Update(msg)
|
||
|
if cmd != nil {
|
||
|
return m, cmd
|
||
|
}
|
||
|
|
||
|
m.content.SetContent(m.renderContent())
|
||
|
return m, nil
|
||
|
}
|
||
|
|
||
|
func (m *Model) getModelOptions() []list.OptionGroup {
|
||
|
modelOpts := []list.OptionGroup{}
|
||
|
for _, p := range m.App.Ctx.Config.Providers {
|
||
|
provider := p.Name
|
||
|
if provider == "" {
|
||
|
provider = p.Kind
|
||
|
}
|
||
|
providerLabel := p.Display
|
||
|
if providerLabel == "" {
|
||
|
providerLabel = strings.ToUpper(provider[:1]) + provider[1:]
|
||
|
}
|
||
|
group := list.OptionGroup{
|
||
|
Name: providerLabel,
|
||
|
}
|
||
|
for _, model := range p.Models {
|
||
|
group.Options = append(group.Options, list.Option{
|
||
|
Label: model,
|
||
|
Value: modelOpt{provider, model},
|
||
|
})
|
||
|
}
|
||
|
modelOpts = append(modelOpts, group)
|
||
|
}
|
||
|
return modelOpts
|
||
|
}
|
||
|
|
||
|
func (m *Model) Header(width int) string {
|
||
|
boldStyle := lipgloss.NewStyle().Bold(true)
|
||
|
// TODO: update header depending on active settings mode (model, agent, etc)
|
||
|
header := boldStyle.Render("Model selection")
|
||
|
return styles.Header.Width(width).Render(header)
|
||
|
}
|
||
|
|
||
|
func (m *Model) Content(width, height int) string {
|
||
|
// TODO: see Header()
|
||
|
currentModel := " Active model: " + m.App.ActiveModel(lipgloss.NewStyle())
|
||
|
m.modelList.Width, m.modelList.Height = width, height - 2
|
||
|
return "\n" + currentModel + "\n" + m.modelList.View()
|
||
|
}
|
||
|
|
||
|
func (m *Model) Footer(width int) string {
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
func (m *Model) renderContent() string {
|
||
|
return m.modelList.View()
|
||
|
}
|