summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-06-18 15:51:21 -0500
committeradamdottv <[email protected]>2025-06-18 15:51:26 -0500
commit87d1d3fb62c45684d38c29f075d0742b9546ee28 (patch)
tree6312f54201442c707362051b5aeca5e5470b3264
parente054454109140883ef52c00d833d560896361f6c (diff)
downloadopencode-87d1d3fb62c45684d38c29f075d0742b9546ee28.tar.gz
opencode-87d1d3fb62c45684d38c29f075d0742b9546ee28.zip
fix(tui): file completion quirks
-rw-r--r--packages/tui/internal/app/app.go3
-rw-r--r--packages/tui/internal/components/chat/editor.go6
-rw-r--r--packages/tui/internal/components/dialog/complete.go64
-rw-r--r--packages/tui/internal/tui/tui.go47
4 files changed, 80 insertions, 40 deletions
diff --git a/packages/tui/internal/app/app.go b/packages/tui/internal/app/app.go
index 940ac7b2f..6f0733aa3 100644
--- a/packages/tui/internal/app/app.go
+++ b/packages/tui/internal/app/app.go
@@ -42,6 +42,9 @@ type SendMsg struct {
Text string
Attachments []Attachment
}
+type CompletionDialogTriggerdMsg struct {
+ InitialValue string
+}
func New(
ctx context.Context,
diff --git a/packages/tui/internal/components/chat/editor.go b/packages/tui/internal/components/chat/editor.go
index 46d160478..154d3c370 100644
--- a/packages/tui/internal/components/chat/editor.go
+++ b/packages/tui/internal/components/chat/editor.go
@@ -80,7 +80,7 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} else {
existingValue := m.textarea.Value()
modifiedValue := strings.Replace(existingValue, msg.SearchString, msg.CompletionValue, 1)
- m.textarea.SetValue(modifiedValue)
+ m.textarea.SetValue(modifiedValue + " ")
return m, nil
}
}
@@ -152,11 +152,11 @@ func (m *editorComponent) SetSize(width, height int) tea.Cmd {
}
func (m *editorComponent) Value() string {
- return strings.TrimSpace(m.textarea.Value())
+ return m.textarea.Value()
}
func (m *editorComponent) Submit() (tea.Model, tea.Cmd) {
- value := m.Value()
+ value := strings.TrimSpace(m.Value())
m.textarea.Reset()
if value == "" {
return m, nil
diff --git a/packages/tui/internal/components/dialog/complete.go b/packages/tui/internal/components/dialog/complete.go
index ea7a801bc..11cdce915 100644
--- a/packages/tui/internal/components/dialog/complete.go
+++ b/packages/tui/internal/components/dialog/complete.go
@@ -7,6 +7,7 @@ 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"
@@ -111,39 +112,13 @@ func (c *completionDialogComponent) Init() tea.Cmd {
return nil
}
-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"
-
- return tea.Batch(
- util.CmdHandler(CompletionSelectedMsg{
- SearchString: value,
- CompletionValue: item.GetValue(),
- IsCommand: isCommand,
- }),
- c.close(),
- )
-}
-
-func (c *completionDialogComponent) close() tea.Cmd {
- c.list.SetItems([]CompletionItemI{})
- c.pseudoSearchTextArea.Reset()
- c.pseudoSearchTextArea.Blur()
-
- return util.CmdHandler(CompletionDialogCloseMsg{})
-}
-
func (c *completionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
switch msg := msg.(type) {
case []CompletionItemI:
c.list.SetItems(msg)
+ case app.CompletionDialogTriggerdMsg:
+ c.pseudoSearchTextArea.SetValue(msg.InitialValue)
case tea.KeyMsg:
if c.pseudoSearchTextArea.Focused() {
if !key.Matches(msg, completionDialogKeys.Complete) {
@@ -194,13 +169,12 @@ func (c *completionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
items, err := c.completionProvider.GetChildEntries("")
if err != nil {
slog.Error("Failed to get completion items", "error", err)
- // status.Error(err.Error())
}
return items
}
cmds = append(cmds, cmd)
cmds = append(cmds, c.pseudoSearchTextArea.Focus())
- c.pseudoSearchTextArea.SetValue(msg.String())
+ // c.pseudoSearchTextArea.SetValue(msg.String())
return c, tea.Batch(cmds...)
}
case tea.WindowSizeMsg:
@@ -255,6 +229,34 @@ func (c *completionDialogComponent) SetProvider(provider CompletionProvider) {
}
}
+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"
+
+ return tea.Batch(
+ util.CmdHandler(CompletionSelectedMsg{
+ SearchString: value,
+ CompletionValue: item.GetValue(),
+ IsCommand: isCommand,
+ }),
+ c.close(),
+ )
+}
+
+func (c *completionDialogComponent) close() tea.Cmd {
+ c.list.SetItems([]CompletionItemI{})
+ c.pseudoSearchTextArea.Reset()
+ c.pseudoSearchTextArea.Blur()
+
+ return util.CmdHandler(CompletionDialogCloseMsg{})
+}
+
func NewCompletionDialogComponent(completionProvider CompletionProvider) CompletionDialog {
ti := textarea.New()
@@ -268,7 +270,7 @@ func NewCompletionDialogComponent(completionProvider CompletionProvider) Complet
go func() {
items, err := completionProvider.GetChildEntries("")
if err != nil {
- // status.Error(err.Error())
+ slog.Error("Failed to get completion items", "error", err)
}
li.SetItems(items)
}()
diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go
index 98d16ecc4..c1262678b 100644
--- a/packages/tui/internal/tui/tui.go
+++ b/packages/tui/internal/tui/tui.go
@@ -5,6 +5,7 @@ import (
"log/slog"
"os"
"os/exec"
+ "strings"
"github.com/charmbracelet/bubbles/v2/key"
tea "github.com/charmbracelet/bubbletea/v2"
@@ -90,10 +91,49 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// 3. Handle completions trigger
switch msg.String() {
case "/":
- a.showCompletionDialog = true
+ if !a.showCompletionDialog {
+ 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
+ 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.CompletionDialogTriggerdMsg{
+ InitialValue: initialValue,
+ },
+ )
+ a.completions = updated.(dialog.CompletionDialog)
+ cmds = append(cmds, cmd)
+
+ updated, cmd = a.completions.Update(msg)
+ a.completions = updated.(dialog.CompletionDialog)
+ cmds = append(cmds, cmd)
+
+ updated, cmd = a.editor.Update(msg)
+ a.editor = updated.(chat.EditorComponent)
+ cmds = append(cmds, cmd)
+ return a, tea.Sequence(cmds...)
+ }
}
if a.showCompletionDialog {
+ switch msg.String() {
+ case "tab", "enter", "esc":
+ context, contextCmd := a.completions.Update(msg)
+ a.completions = context.(dialog.CompletionDialog)
+ cmds = append(cmds, contextCmd)
+ return a, tea.Batch(cmds...)
+ }
+
updated, cmd := a.editor.Update(msg)
a.editor = updated.(chat.EditorComponent)
cmds = append(cmds, cmd)
@@ -106,11 +146,6 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
a.completions = context.(dialog.CompletionDialog)
cmds = append(cmds, contextCmd)
return a, tea.Batch(cmds...)
-
- // Doesn't forward event if enter key is pressed
- // if msg.String() == "enter" {
- // return a, tea.Batch(cmds...)
- // }
}
// 4. Maximize editor responsiveness for printable characters