wip: refactoring tui

This commit is contained in:
adamdottv
2025-05-29 15:18:47 -05:00
parent 37c0c1f358
commit 005d6e0bde
30 changed files with 168 additions and 4674 deletions

View File

@@ -29,7 +29,7 @@ func header(width int) string {
}
func lspsConfigured(width int) string {
cfg := config.Get()
// cfg := config.Get()
title := "LSP Servers"
title = ansi.Truncate(title, width, "…")
@@ -44,37 +44,37 @@ func lspsConfigured(width int) string {
// Get LSP names and sort them for consistent ordering
var lspNames []string
for name := range cfg.LSP {
lspNames = append(lspNames, name)
}
// for name := range cfg.LSP {
// lspNames = append(lspNames, name)
// }
sort.Strings(lspNames)
var lspViews []string
for _, name := range lspNames {
lsp := cfg.LSP[name]
lspName := baseStyle.
Foreground(t.Text()).
Render(fmt.Sprintf("• %s", name))
// for _, name := range lspNames {
// lsp := cfg.LSP[name]
// lspName := baseStyle.
// Foreground(t.Text()).
// Render(fmt.Sprintf("• %s", name))
cmd := lsp.Command
cmd = ansi.Truncate(cmd, width-lipgloss.Width(lspName)-3, "…")
// cmd := lsp.Command
// cmd = ansi.Truncate(cmd, width-lipgloss.Width(lspName)-3, "…")
lspPath := baseStyle.
Foreground(t.TextMuted()).
Render(fmt.Sprintf(" (%s)", cmd))
// lspPath := baseStyle.
// Foreground(t.TextMuted()).
// Render(fmt.Sprintf(" (%s)", cmd))
lspViews = append(lspViews,
baseStyle.
Width(width).
Render(
lipgloss.JoinHorizontal(
lipgloss.Left,
lspName,
lspPath,
),
),
)
}
// lspViews = append(lspViews,
// baseStyle.
// Width(width).
// Render(
// lipgloss.JoinHorizontal(
// lipgloss.Left,
// lspName,
// lspPath,
// ),
// ),
// )
// }
return baseStyle.
Width(width).

View File

@@ -17,7 +17,6 @@ import (
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/sst/opencode/internal/config"
"github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/status"
"github.com/sst/opencode/internal/tui/app"
@@ -239,11 +238,11 @@ func (f *filepickerCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
func (f *filepickerCmp) addAttachmentToMessage() (tea.Model, tea.Cmd) {
modeInfo := GetSelectedModel(config.Get())
if !modeInfo.SupportsAttachments {
status.Error(fmt.Sprintf("Model %s doesn't support attachments", modeInfo.Name))
return f, nil
}
// modeInfo := GetSelectedModel(config.Get())
// if !modeInfo.SupportsAttachments {
// status.Error(fmt.Sprintf("Model %s doesn't support attachments", modeInfo.Name))
// return f, nil
// }
selectedFilePath := f.selectedFile
if !isExtSupported(selectedFilePath) {

View File

@@ -1,15 +1,10 @@
package dialog
import (
"fmt"
"slices"
"strings"
"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/llm/models"
"github.com/sst/opencode/internal/tui/layout"
"github.com/sst/opencode/internal/tui/styles"
"github.com/sst/opencode/internal/tui/theme"
@@ -23,7 +18,7 @@ const (
// ModelSelectedMsg is sent when a model is selected
type ModelSelectedMsg struct {
Model models.Model
// Model models.Model
}
// CloseModelDialogMsg is sent when a model is selected
@@ -36,9 +31,9 @@ type ModelDialog interface {
}
type modelDialogCmp struct {
models []models.Model
provider models.ModelProvider
availableProviders []models.ModelProvider
// models []models.Model
// provider models.ModelProvider
// availableProviders []models.ModelProvider
selectedIdx int
width int
@@ -126,7 +121,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(ModelSelectedMsg{Model: m.models[m.selectedIdx]})
case key.Matches(msg, modelKeys.Escape):
return m, util.CmdHandler(CloseModelDialogMsg{})
}
@@ -143,8 +138,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.models) - 1
// m.scrollOffset = max(0, len(m.models)-numVisibleModels)
}
// Keep selection visible
@@ -155,12 +150,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.models)-1 {
// m.selectedIdx++
// } else {
// m.selectedIdx = 0
// m.scrollOffset = 0
// }
// Keep selection visible
if m.selectedIdx >= m.scrollOffset+numVisibleModels {
@@ -172,16 +167,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)
}
func (m *modelDialogCmp) View() string {
@@ -189,33 +184,33 @@ 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))
// 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))
// 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.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))
// }
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,
)
@@ -230,22 +225,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.models) > numVisibleModels {
// if m.scrollOffset > 0 {
// indicator += "↑ "
// }
// if m.scrollOffset+numVisibleModels < len(m.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 == "" {
@@ -268,51 +263,52 @@ func (m *modelDialogCmp) BindingKeys() []key.Binding {
}
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)
// 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) models.Model {
agentCfg := cfg.Agents[config.AgentPrimary]
selectedModelId := agentCfg.Model
return models.SupportedModels[selectedModelId]
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) []models.ModelProvider {
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
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 []models.ModelProvider, provider models.ModelProvider) int {
func findProviderIndex(providers []string, provider string) int {
for i, p := range providers {
if p == provider {
return i
@@ -321,50 +317,51 @@ func findProviderIndex(providers []models.ModelProvider, provider models.ModelPr
return -1
}
func (m *modelDialogCmp) setupModelsForProvider(provider models.ModelProvider) {
cfg := config.Get()
agentCfg := cfg.Agents[config.AgentPrimary]
selectedModelId := agentCfg.Model
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.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 {
for i, model := range m.models {
if model.ID == selectedModelId {
m.selectedIdx = i
// Adjust scroll position to keep selected model visible
if m.selectedIdx >= numVisibleModels {
m.scrollOffset = m.selectedIdx - (numVisibleModels - 1)
}
break
}
}
}
// if provider == models.SupportedModels[selectedModelId].Provider {
// for i, model := range m.models {
// if model.ID == selectedModelId {
// m.selectedIdx = i
// // Adjust scroll position to keep selected model visible
// if m.selectedIdx >= numVisibleModels {
// m.scrollOffset = m.selectedIdx - (numVisibleModels - 1)
// }
// break
// }
// }
// }
}
func getModelsForProvider(provider models.ModelProvider) []models.Model {
var providerModels []models.Model
for _, model := range models.SupportedModels {
if model.Provider == provider {
providerModels = append(providerModels, model)
}
}
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
})
// 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
// return providerModels
}
func NewModelDialogCmp() ModelDialog {