mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-26 04:04:22 +01:00
wip: refactoring tui
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user