wip: refactoring tui

This commit is contained in:
adamdottv
2025-05-30 15:34:22 -05:00
parent f5e2c596d4
commit c69c9327da
13 changed files with 244 additions and 263 deletions

View File

@@ -335,7 +335,10 @@ func (m *statusCmp) projectDiagnostics() string {
func (m statusCmp) model() string {
t := theme.CurrentTheme()
model := "Claude Sonnet 4" // models.SupportedModels[coder.Model]
model := "None"
if m.app.Model != nil {
model = *m.app.Model.Name
}
return styles.Padded().
Background(t.Secondary()).

View File

@@ -1,14 +1,18 @@
package dialog
import (
"context"
"fmt"
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/sst/opencode/internal/config"
"github.com/sst/opencode/internal/tui/app"
"github.com/sst/opencode/internal/tui/layout"
"github.com/sst/opencode/internal/tui/styles"
"github.com/sst/opencode/internal/tui/theme"
"github.com/sst/opencode/internal/tui/util"
"github.com/sst/opencode/pkg/client"
)
const (
@@ -16,24 +20,25 @@ const (
maxDialogWidth = 40
)
// ModelSelectedMsg is sent when a model is selected
type ModelSelectedMsg struct {
// Model models.Model
}
// CloseModelDialogMsg is sent when a model is selected
type CloseModelDialogMsg struct{}
type CloseModelDialogMsg struct {
Provider *client.ProviderInfo
Model *client.ProviderModel
}
// ModelDialog interface for the model selection dialog
type ModelDialog interface {
tea.Model
layout.Bindings
SetProviders(providers []client.ProviderInfo)
}
type modelDialogCmp struct {
// models []models.Model
// provider models.ModelProvider
// availableProviders []models.ModelProvider
app *app.App
availableProviders []client.ProviderInfo
provider client.ProviderInfo
model *client.ProviderModel
selectedIdx int
width int
@@ -100,10 +105,28 @@ var modelKeys = modelKeyMap{
}
func (m *modelDialogCmp) Init() tea.Cmd {
m.setupModels()
// cfg := config.Get()
// modelInfo := GetSelectedModel(cfg)
// m.availableProviders = getEnabledProviders(cfg)
// m.hScrollPossible = len(m.availableProviders) > 1
// m.provider = modelInfo.Provider
// m.hScrollOffset = findProviderIndex(m.availableProviders, m.provider)
// m.setupModelsForProvider(m.provider)
m.availableProviders, _ = m.app.ListProviders(context.Background())
m.hScrollOffset = 0
m.hScrollPossible = len(m.availableProviders) > 1
m.provider = m.availableProviders[m.hScrollOffset]
return nil
}
func (m *modelDialogCmp) SetProviders(providers []client.ProviderInfo) {
m.availableProviders = providers
}
func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
@@ -121,7 +144,7 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.switchProvider(1)
}
case key.Matches(msg, modelKeys.Enter):
// return m, util.CmdHandler(ModelSelectedMsg{Model: m.models[m.selectedIdx]})
return m, util.CmdHandler(CloseModelDialogMsg{Provider: &m.provider, Model: &m.provider.Models[m.selectedIdx]})
case key.Matches(msg, modelKeys.Escape):
return m, util.CmdHandler(CloseModelDialogMsg{})
}
@@ -138,8 +161,8 @@ func (m *modelDialogCmp) moveSelectionUp() {
if m.selectedIdx > 0 {
m.selectedIdx--
} else {
// m.selectedIdx = len(m.models) - 1
// m.scrollOffset = max(0, len(m.models)-numVisibleModels)
m.selectedIdx = len(m.provider.Models) - 1
m.scrollOffset = max(0, len(m.provider.Models)-numVisibleModels)
}
// Keep selection visible
@@ -150,12 +173,12 @@ func (m *modelDialogCmp) moveSelectionUp() {
// moveSelectionDown moves the selection down or wraps to top
func (m *modelDialogCmp) moveSelectionDown() {
// if m.selectedIdx < len(m.models)-1 {
// m.selectedIdx++
// } else {
// m.selectedIdx = 0
// m.scrollOffset = 0
// }
if m.selectedIdx < len(m.provider.Models)-1 {
m.selectedIdx++
} else {
m.selectedIdx = 0
m.scrollOffset = 0
}
// Keep selection visible
if m.selectedIdx >= m.scrollOffset+numVisibleModels {
@@ -167,16 +190,16 @@ func (m *modelDialogCmp) switchProvider(offset int) {
newOffset := m.hScrollOffset + offset
// Ensure we stay within bounds
// if newOffset < 0 {
// newOffset = len(m.availableProviders) - 1
// }
// if newOffset >= len(m.availableProviders) {
// newOffset = 0
// }
if newOffset < 0 {
newOffset = len(m.availableProviders) - 1
}
if newOffset >= len(m.availableProviders) {
newOffset = 0
}
m.hScrollOffset = newOffset
// m.provider = m.availableProviders[m.hScrollOffset]
// m.setupModelsForProvider(m.provider)
m.provider = m.availableProviders[m.hScrollOffset]
m.setupModelsForProvider(m.provider.Id)
}
func (m *modelDialogCmp) View() string {
@@ -184,33 +207,32 @@ func (m *modelDialogCmp) View() string {
baseStyle := styles.BaseStyle()
// Capitalize first letter of provider name
// providerName := strings.ToUpper(string(m.provider)[:1]) + string(m.provider[1:])
// title := baseStyle.
// Foreground(t.Primary()).
// Bold(true).
// Width(maxDialogWidth).
// Padding(0, 0, 1).
// Render(fmt.Sprintf("Select %s Model", providerName))
title := baseStyle.
Foreground(t.Primary()).
Bold(true).
Width(maxDialogWidth).
Padding(0, 0, 1).
Render(fmt.Sprintf("Select %s Model", m.provider.Name))
// Render visible models
// endIdx := min(m.scrollOffset+numVisibleModels, len(m.models))
// modelItems := make([]string, 0, endIdx-m.scrollOffset)
//
// for i := m.scrollOffset; i < endIdx; i++ {
// itemStyle := baseStyle.Width(maxDialogWidth)
// if i == m.selectedIdx {
// itemStyle = itemStyle.Background(t.Primary()).
// Foreground(t.Background()).Bold(true)
// }
// modelItems = append(modelItems, itemStyle.Render(m.models[i].Name))
// }
endIdx := min(m.scrollOffset+numVisibleModels, len(m.provider.Models))
modelItems := make([]string, 0, endIdx-m.scrollOffset)
for i := m.scrollOffset; i < endIdx; i++ {
itemStyle := baseStyle.Width(maxDialogWidth)
if i == m.selectedIdx {
itemStyle = itemStyle.Background(t.Primary()).
Foreground(t.Background()).Bold(true)
}
modelItems = append(modelItems, itemStyle.Render(*m.provider.Models[i].Name))
}
scrollIndicator := m.getScrollIndicators(maxDialogWidth)
content := lipgloss.JoinVertical(
lipgloss.Left,
// title,
// baseStyle.Width(maxDialogWidth).Render(lipgloss.JoinVertical(lipgloss.Left, modelItems...)),
title,
baseStyle.Width(maxDialogWidth).Render(lipgloss.JoinVertical(lipgloss.Left, modelItems...)),
scrollIndicator,
)
@@ -225,22 +247,22 @@ func (m *modelDialogCmp) View() string {
func (m *modelDialogCmp) getScrollIndicators(maxWidth int) string {
var indicator string
// if len(m.models) > numVisibleModels {
// if m.scrollOffset > 0 {
// indicator += "↑ "
// }
// if m.scrollOffset+numVisibleModels < len(m.models) {
// indicator += "↓ "
// }
// }
if len(m.provider.Models) > numVisibleModels {
if m.scrollOffset > 0 {
indicator += "↑ "
}
if m.scrollOffset+numVisibleModels < len(m.provider.Models) {
indicator += "↓ "
}
}
if m.hScrollPossible {
if m.hScrollOffset > 0 {
indicator = "← " + indicator
}
// if m.hScrollOffset < len(m.availableProviders)-1 {
// indicator += "→"
// }
if m.hScrollOffset < len(m.availableProviders)-1 {
indicator += "→"
}
}
if indicator == "" {
@@ -262,70 +284,26 @@ func (m *modelDialogCmp) BindingKeys() []key.Binding {
return layout.KeyMapToSlice(modelKeys)
}
func (m *modelDialogCmp) setupModels() {
// cfg := config.Get()
// modelInfo := GetSelectedModel(cfg)
// m.availableProviders = getEnabledProviders(cfg)
// m.hScrollPossible = len(m.availableProviders) > 1
//
// m.provider = modelInfo.Provider
// m.hScrollOffset = findProviderIndex(m.availableProviders, m.provider)
//
// m.setupModelsForProvider(m.provider)
}
func GetSelectedModel(cfg *config.Config) string {
return "Claude Sonnet 4"
// agentCfg := cfg.Agents[config.AgentPrimary]
// selectedModelId := agentCfg.Model
// return models.SupportedModels[selectedModelId]
}
func getEnabledProviders(cfg *config.Config) []string {
return []string{"anthropic", "openai", "google"}
// var providers []models.ModelProvider
// for providerId, provider := range cfg.Providers {
// if !provider.Disabled {
// providers = append(providers, providerId)
// }
// }
//
// // Sort by provider popularity
// slices.SortFunc(providers, func(a, b models.ModelProvider) int {
// rA := models.ProviderPopularity[a]
// rB := models.ProviderPopularity[b]
//
// // models not included in popularity ranking default to last
// if rA == 0 {
// rA = 999
// }
// if rB == 0 {
// rB = 999
// }
// return rA - rB
// })
// return providers
}
// findProviderIndex returns the index of the provider in the list, or -1 if not found
func findProviderIndex(providers []string, provider string) int {
for i, p := range providers {
if p == provider {
return i
}
}
return -1
}
// func findProviderIndex(providers []string, provider string) int {
// for i, p := range providers {
// if p == provider {
// return i
// }
// }
// return -1
// }
func (m *modelDialogCmp) setupModelsForProvider(_ string) {
m.selectedIdx = 0
m.scrollOffset = 0
func (m *modelDialogCmp) setupModelsForProvider(provider string) {
// cfg := config.Get()
// agentCfg := cfg.Agents[config.AgentPrimary]
// selectedModelId := agentCfg.Model
// m.provider = provider
// m.models = getModelsForProvider(provider)
m.selectedIdx = 0
m.scrollOffset = 0
// Try to select the current model if it belongs to this provider
// if provider == models.SupportedModels[selectedModelId].Provider {
@@ -342,28 +320,8 @@ func (m *modelDialogCmp) setupModelsForProvider(provider string) {
// }
}
func getModelsForProvider(provider string) []string {
return []string{"Claude Sonnet 4"}
// var providerModels []models.Model
// for _, model := range models.SupportedModels {
// if model.Provider == provider {
// providerModels = append(providerModels, model)
// }
// }
// reverse alphabetical order (if llm naming was consistent latest would appear first)
// slices.SortFunc(providerModels, func(a, b models.Model) int {
// if a.Name > b.Name {
// return -1
// } else if a.Name < b.Name {
// return 1
// }
// return 0
// })
// return providerModels
}
func NewModelDialogCmp() ModelDialog {
return &modelDialogCmp{}
func NewModelDialogCmp(app *app.App) ModelDialog {
return &modelDialogCmp{
app: app,
}
}