chore: simplify completions

This commit is contained in:
adamdottv 2025-07-03 12:48:14 -05:00
parent 3e2a0c7281
commit fce59db94a
No known key found for this signature in database
GPG key ID: 9CB48779AF150E75
5 changed files with 30 additions and 104 deletions

View file

@ -46,9 +46,6 @@ type SendMsg struct {
Text string
Attachments []Attachment
}
type CompletionDialogTriggeredMsg struct {
InitialValue string
}
type OptimisticMessageAddedMsg struct {
Message opencode.Message
}
@ -129,7 +126,11 @@ func New(
func (a *App) Key(commandName commands.CommandName) string {
t := theme.CurrentTheme()
base := styles.NewStyle().Background(t.Background()).Foreground(t.Text()).Bold(true).Render
muted := styles.NewStyle().Background(t.Background()).Foreground(t.TextMuted()).Faint(true).Render
muted := styles.NewStyle().
Background(t.Background()).
Foreground(t.TextMuted()).
Faint(true).
Render
command := a.Commands[commandName]
kb := command.Keybindings[0]
key := kb.Key
@ -201,7 +202,10 @@ func (a *App) InitializeProvider() tea.Cmd {
}
}
func getDefaultModel(response *opencode.ConfigProvidersResponse, provider opencode.Provider) *opencode.Model {
func getDefaultModel(
response *opencode.ConfigProvidersResponse,
provider opencode.Provider,
) *opencode.Model {
if match, ok := response.Default[provider.ID]; ok {
model := provider.Models[match]
return &model

View file

@ -1,32 +0,0 @@
package completions
import (
"strings"
"github.com/sst/opencode/internal/app"
"github.com/sst/opencode/internal/components/dialog"
)
type CompletionManager struct {
providers map[string]dialog.CompletionProvider
}
func NewCompletionManager(app *app.App) *CompletionManager {
return &CompletionManager{
providers: map[string]dialog.CompletionProvider{
"files": NewFileAndFolderContextGroup(app),
"commands": NewCommandCompletionProvider(app),
},
}
}
func (m *CompletionManager) DefaultProvider() dialog.CompletionProvider {
return m.providers["commands"]
}
func (m *CompletionManager) GetProvider(input string) dialog.CompletionProvider {
if strings.HasPrefix(input, "/") {
return m.providers["commands"]
}
return m.providers["files"]
}

View file

@ -7,7 +7,6 @@ import (
"github.com/charmbracelet/bubbles/v2/textarea"
tea "github.com/charmbracelet/bubbletea/v2"
"github.com/charmbracelet/lipgloss/v2"
"github.com/sst/opencode/internal/app"
"github.com/sst/opencode/internal/components/list"
"github.com/sst/opencode/internal/styles"
"github.com/sst/opencode/internal/theme"
@ -79,7 +78,6 @@ type CompletionDialog interface {
tea.ViewModel
SetWidth(width int)
IsEmpty() bool
SetProvider(provider CompletionProvider)
}
type completionDialogComponent struct {
@ -114,8 +112,6 @@ func (c *completionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case []CompletionItemI:
c.list.SetItems(msg)
case app.CompletionDialogTriggeredMsg:
c.pseudoSearchTextArea.SetValue(msg.InitialValue)
case tea.KeyMsg:
if c.pseudoSearchTextArea.Focused() {
if !key.Matches(msg, completionDialogKeys.Complete) {
@ -214,19 +210,8 @@ func (c *completionDialogComponent) IsEmpty() bool {
return c.list.IsEmpty()
}
func (c *completionDialogComponent) SetProvider(provider CompletionProvider) {
if c.completionProvider.GetId() != provider.GetId() {
c.completionProvider = provider
c.list.SetEmptyMessage(" " + provider.GetEmptyMessage())
c.list.SetItems([]CompletionItemI{})
}
}
func (c *completionDialogComponent) complete(item CompletionItemI) tea.Cmd {
value := c.pseudoSearchTextArea.Value()
if value == "" {
return nil
}
// Check if this is a command completion
isCommand := c.completionProvider.GetId() == "commands"

View file

@ -27,7 +27,6 @@ type FindDialog interface {
SetWidth(width int)
SetHeight(height int)
IsEmpty() bool
SetProvider(provider CompletionProvider)
}
type findDialogComponent struct {
@ -151,12 +150,6 @@ func (f *findDialogComponent) IsEmpty() bool {
return f.list.IsEmpty()
}
func (f *findDialogComponent) SetProvider(provider CompletionProvider) {
f.completionProvider = provider
f.list.SetEmptyMessage(" " + provider.GetEmptyMessage())
f.list.SetItems([]CompletionItemI{})
}
func (f *findDialogComponent) selectFile(item CompletionItemI) tea.Cmd {
return tea.Sequence(
f.Close(),
@ -184,9 +177,15 @@ func createTextInput(existing *textinput.Model) textinput.Model {
ti := textinput.New()
ti.Styles.Blurred.Placeholder = styles.NewStyle().Foreground(textMutedColor).Background(bgColor).Lipgloss()
ti.Styles.Blurred.Placeholder = styles.NewStyle().
Foreground(textMutedColor).
Background(bgColor).
Lipgloss()
ti.Styles.Blurred.Text = styles.NewStyle().Foreground(textColor).Background(bgColor).Lipgloss()
ti.Styles.Focused.Placeholder = styles.NewStyle().Foreground(textMutedColor).Background(bgColor).Lipgloss()
ti.Styles.Focused.Placeholder = styles.NewStyle().
Foreground(textMutedColor).
Background(bgColor).
Lipgloss()
ti.Styles.Focused.Text = styles.NewStyle().Foreground(textColor).Background(bgColor).Lipgloss()
ti.Styles.Cursor.Color = t.Primary()
ti.VirtualCursor = true
@ -213,7 +212,6 @@ func NewFindDialog(completionProvider CompletionProvider) FindDialog {
false,
)
// Load initial items
go func() {
items, err := completionProvider.GetChildEntries("")
if err != nil {

View file

@ -51,7 +51,7 @@ type appModel struct {
editor chat.EditorComponent
messages chat.MessagesComponent
completions dialog.CompletionDialog
completionManager *completions.CompletionManager
commandProvider dialog.CompletionProvider
showCompletionDialog bool
leaderBinding *key.Binding
isLeaderSequence bool
@ -105,6 +105,7 @@ var BUGGED_SCROLL_KEYS = map[string]bool{
"m": true,
"[": true,
";": true,
"<": true,
}
func isScrollRelatedInput(keyString string) bool {
@ -134,6 +135,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyPressMsg:
keyString := msg.String()
if time.Since(a.lastScroll) < time.Millisecond*100 && (BUGGED_SCROLL_KEYS[keyString] || isScrollRelatedInput(keyString)) {
return a, nil
}
@ -174,37 +176,16 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
// 3. Handle completions trigger
if keyString == "/" && !a.showCompletionDialog {
if keyString == "/" &&
!a.showCompletionDialog &&
a.editor.Value() == "" {
a.showCompletionDialog = true
initialValue := "/"
currentInput := a.editor.Value()
// if the input doesn't end with a space,
// then we want to include the last word
// (ie, `packages/`)
if !strings.HasSuffix(currentInput, " ") {
words := strings.Split(a.editor.Value(), " ")
if len(words) > 0 {
lastWord := words[len(words)-1]
lastWord = strings.TrimSpace(lastWord)
initialValue = lastWord + "/"
}
}
updated, cmd := a.completions.Update(
app.CompletionDialogTriggeredMsg{
InitialValue: initialValue,
},
)
a.completions = updated.(dialog.CompletionDialog)
cmds = append(cmds, cmd)
updated, cmd = a.editor.Update(msg)
updated, cmd := a.editor.Update(msg)
a.editor = updated.(chat.EditorComponent)
cmds = append(cmds, cmd)
updated, cmd = a.updateCompletions(msg)
updated, cmd = a.completions.Update(msg)
a.completions = updated.(dialog.CompletionDialog)
cmds = append(cmds, cmd)
@ -214,7 +195,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if a.showCompletionDialog {
switch keyString {
case "tab", "enter", "esc", "ctrl+c":
updated, cmd := a.updateCompletions(msg)
updated, cmd := a.completions.Update(msg)
a.completions = updated.(dialog.CompletionDialog)
cmds = append(cmds, cmd)
return a, tea.Batch(cmds...)
@ -224,7 +205,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
a.editor = updated.(chat.EditorComponent)
cmds = append(cmds, cmd)
updated, cmd = a.updateCompletions(msg)
updated, cmd = a.completions.Update(msg)
a.completions = updated.(dialog.CompletionDialog)
cmds = append(cmds, cmd)
@ -971,22 +952,12 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
return a, tea.Batch(cmds...)
}
func (a appModel) updateCompletions(msg tea.Msg) (tea.Model, tea.Cmd) {
currentInput := a.editor.Value()
if currentInput != "" {
provider := a.completionManager.GetProvider(currentInput)
a.completions.SetProvider(provider)
}
return a.completions.Update(msg)
}
func NewModel(app *app.App) tea.Model {
completionManager := completions.NewCompletionManager(app)
initialProvider := completionManager.DefaultProvider()
commandProvider := completions.NewCommandCompletionProvider(app)
messages := chat.NewMessagesComponent(app)
editor := chat.NewEditorComponent(app)
completions := dialog.NewCompletionDialogComponent(initialProvider)
completions := dialog.NewCompletionDialogComponent(commandProvider)
var leaderBinding *key.Binding
if app.Config.Keybinds.Leader != "" {
@ -1000,7 +971,7 @@ func NewModel(app *app.App) tea.Model {
editor: editor,
messages: messages,
completions: completions,
completionManager: completionManager,
commandProvider: commandProvider,
leaderBinding: leaderBinding,
isLeaderSequence: false,
showCompletionDialog: false,