summaryrefslogtreecommitdiffhomepage
path: root/packages/tui
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-07-10 05:51:47 -0500
committeradamdottv <[email protected]>2025-07-10 05:53:00 -0500
commit85dbfeb3147cefa597938a315f0848a0d978640b (patch)
tree050bc9dd4a8a1a4e84431ccd637bdfc383ba433e /packages/tui
parent085c0e4e2b8518d740f75372367a44d19b22f90e (diff)
downloadopencode-85dbfeb3147cefa597938a315f0848a0d978640b.tar.gz
opencode-85dbfeb3147cefa597938a315f0848a0d978640b.zip
feat(tui): @symbol attachments
Diffstat (limited to 'packages/tui')
-rw-r--r--packages/tui/internal/completions/commands.go23
-rw-r--r--packages/tui/internal/completions/files.go (renamed from packages/tui/internal/completions/files-folders.go)26
-rw-r--r--packages/tui/internal/completions/symbols.go118
-rw-r--r--packages/tui/internal/components/chat/editor.go41
-rw-r--r--packages/tui/internal/components/dialog/complete.go174
-rw-r--r--packages/tui/internal/tui/tui.go15
6 files changed, 301 insertions, 96 deletions
diff --git a/packages/tui/internal/completions/commands.go b/packages/tui/internal/completions/commands.go
index 3a5dc3bb1..bb48d540c 100644
--- a/packages/tui/internal/completions/commands.go
+++ b/packages/tui/internal/completions/commands.go
@@ -29,17 +29,26 @@ func (c *CommandCompletionProvider) GetEmptyMessage() string {
return "no matching commands"
}
-func getCommandCompletionItem(cmd commands.Command, space int, t theme.Theme) dialog.CompletionItemI {
+func (c *CommandCompletionProvider) getCommandCompletionItem(
+ cmd commands.Command,
+ space int,
+ t theme.Theme,
+) dialog.CompletionItemI {
spacer := strings.Repeat(" ", space)
- title := " /" + cmd.PrimaryTrigger() + styles.NewStyle().Foreground(t.TextMuted()).Render(spacer+cmd.Description)
+ title := " /" + cmd.PrimaryTrigger() + styles.NewStyle().
+ Foreground(t.TextMuted()).
+ Render(spacer+cmd.Description)
value := string(cmd.Name)
return dialog.NewCompletionItem(dialog.CompletionItem{
- Title: title,
- Value: value,
+ Title: title,
+ Value: value,
+ ProviderID: c.GetId(),
})
}
-func (c *CommandCompletionProvider) GetChildEntries(query string) ([]dialog.CompletionItemI, error) {
+func (c *CommandCompletionProvider) GetChildEntries(
+ query string,
+) ([]dialog.CompletionItemI, error) {
t := theme.CurrentTheme()
commands := c.app.Commands
@@ -60,7 +69,7 @@ func (c *CommandCompletionProvider) GetChildEntries(query string) ([]dialog.Comp
continue
}
space := space - lipgloss.Width(cmd.PrimaryTrigger())
- items = append(items, getCommandCompletionItem(cmd, space, t))
+ items = append(items, c.getCommandCompletionItem(cmd, space, t))
}
return items, nil
}
@@ -77,7 +86,7 @@ func (c *CommandCompletionProvider) GetChildEntries(query string) ([]dialog.Comp
// Add all triggers as searchable options
for _, trigger := range cmd.Trigger {
commandNames = append(commandNames, trigger)
- commandMap[trigger] = getCommandCompletionItem(cmd, space, t)
+ commandMap[trigger] = c.getCommandCompletionItem(cmd, space, t)
}
}
diff --git a/packages/tui/internal/completions/files-folders.go b/packages/tui/internal/completions/files.go
index 55e0c1a1b..861762db8 100644
--- a/packages/tui/internal/completions/files-folders.go
+++ b/packages/tui/internal/completions/files.go
@@ -14,20 +14,20 @@ import (
"github.com/sst/opencode/internal/theme"
)
-type filesAndFoldersContextGroup struct {
+type filesContextGroup struct {
app *app.App
gitFiles []dialog.CompletionItemI
}
-func (cg *filesAndFoldersContextGroup) GetId() string {
+func (cg *filesContextGroup) GetId() string {
return "files"
}
-func (cg *filesAndFoldersContextGroup) GetEmptyMessage() string {
+func (cg *filesContextGroup) GetEmptyMessage() string {
return "no matching files"
}
-func (cg *filesAndFoldersContextGroup) getGitFiles() []dialog.CompletionItemI {
+func (cg *filesContextGroup) getGitFiles() []dialog.CompletionItemI {
t := theme.CurrentTheme()
items := make([]dialog.CompletionItemI, 0)
base := styles.NewStyle().Background(t.BackgroundElement())
@@ -50,8 +50,10 @@ func (cg *filesAndFoldersContextGroup) getGitFiles() []dialog.CompletionItemI {
title += red(" -" + strconv.Itoa(int(file.Removed)))
}
item := dialog.NewCompletionItem(dialog.CompletionItem{
- Title: title,
- Value: file.Path,
+ Title: title,
+ Value: file.Path,
+ ProviderID: cg.GetId(),
+ Raw: file,
})
items = append(items, item)
}
@@ -60,7 +62,7 @@ func (cg *filesAndFoldersContextGroup) getGitFiles() []dialog.CompletionItemI {
return items
}
-func (cg *filesAndFoldersContextGroup) GetChildEntries(
+func (cg *filesContextGroup) GetChildEntries(
query string,
) ([]dialog.CompletionItemI, error) {
items := make([]dialog.CompletionItemI, 0)
@@ -94,8 +96,10 @@ func (cg *filesAndFoldersContextGroup) GetChildEntries(
}
if !exists {
item := dialog.NewCompletionItem(dialog.CompletionItem{
- Title: file,
- Value: file,
+ Title: file,
+ Value: file,
+ ProviderID: cg.GetId(),
+ Raw: file,
})
items = append(items, item)
}
@@ -104,8 +108,8 @@ func (cg *filesAndFoldersContextGroup) GetChildEntries(
return items, nil
}
-func NewFileAndFolderContextGroup(app *app.App) dialog.CompletionProvider {
- cg := &filesAndFoldersContextGroup{
+func NewFileContextGroup(app *app.App) dialog.CompletionProvider {
+ cg := &filesContextGroup{
app: app,
}
go func() {
diff --git a/packages/tui/internal/completions/symbols.go b/packages/tui/internal/completions/symbols.go
new file mode 100644
index 000000000..fea1b7117
--- /dev/null
+++ b/packages/tui/internal/completions/symbols.go
@@ -0,0 +1,118 @@
+package completions
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+ "strings"
+
+ "github.com/sst/opencode-sdk-go"
+ "github.com/sst/opencode/internal/app"
+ "github.com/sst/opencode/internal/components/dialog"
+ "github.com/sst/opencode/internal/styles"
+ "github.com/sst/opencode/internal/theme"
+)
+
+type symbolsContextGroup struct {
+ app *app.App
+}
+
+func (cg *symbolsContextGroup) GetId() string {
+ return "symbols"
+}
+
+func (cg *symbolsContextGroup) GetEmptyMessage() string {
+ return "no matching symbols"
+}
+
+type SymbolKind int
+
+const (
+ SymbolKindFile SymbolKind = 1
+ SymbolKindModule SymbolKind = 2
+ SymbolKindNamespace SymbolKind = 3
+ SymbolKindPackage SymbolKind = 4
+ SymbolKindClass SymbolKind = 5
+ SymbolKindMethod SymbolKind = 6
+ SymbolKindProperty SymbolKind = 7
+ SymbolKindField SymbolKind = 8
+ SymbolKindConstructor SymbolKind = 9
+ SymbolKindEnum SymbolKind = 10
+ SymbolKindInterface SymbolKind = 11
+ SymbolKindFunction SymbolKind = 12
+ SymbolKindVariable SymbolKind = 13
+ SymbolKindConstant SymbolKind = 14
+ SymbolKindString SymbolKind = 15
+ SymbolKindNumber SymbolKind = 16
+ SymbolKindBoolean SymbolKind = 17
+ SymbolKindArray SymbolKind = 18
+ SymbolKindObject SymbolKind = 19
+ SymbolKindKey SymbolKind = 20
+ SymbolKindNull SymbolKind = 21
+ SymbolKindEnumMember SymbolKind = 22
+ SymbolKindStruct SymbolKind = 23
+ SymbolKindEvent SymbolKind = 24
+ SymbolKindOperator SymbolKind = 25
+ SymbolKindTypeParameter SymbolKind = 26
+)
+
+func (cg *symbolsContextGroup) GetChildEntries(
+ query string,
+) ([]dialog.CompletionItemI, error) {
+ items := make([]dialog.CompletionItemI, 0)
+
+ query = strings.TrimSpace(query)
+ if query == "" {
+ return items, nil
+ }
+
+ symbols, err := cg.app.Client.Find.Symbols(
+ context.Background(),
+ opencode.FindSymbolsParams{Query: opencode.F(query)},
+ )
+ if err != nil {
+ slog.Error("Failed to get symbol completion items", "error", err)
+ return items, err
+ }
+ if symbols == nil {
+ return items, nil
+ }
+
+ t := theme.CurrentTheme()
+ baseStyle := styles.NewStyle().Background(t.BackgroundElement())
+ base := baseStyle.Render
+ muted := baseStyle.Foreground(t.TextMuted()).Render
+
+ for _, sym := range *symbols {
+ parts := strings.Split(sym.Name, ".")
+ lastPart := parts[len(parts)-1]
+ title := base(lastPart)
+
+ uriParts := strings.Split(sym.Location.Uri, "/")
+ lastTwoParts := uriParts[len(uriParts)-2:]
+ joined := strings.Join(lastTwoParts, "/")
+ title += muted(fmt.Sprintf(" %s", joined))
+
+ start := int(sym.Location.Range.Start.Line)
+ end := int(sym.Location.Range.End.Line)
+ title += muted(fmt.Sprintf(":L%d-%d", start, end))
+
+ value := fmt.Sprintf("%s?start=%d&end=%d", sym.Location.Uri, start, end)
+
+ item := dialog.NewCompletionItem(dialog.CompletionItem{
+ Title: title,
+ Value: value,
+ ProviderID: cg.GetId(),
+ Raw: sym,
+ })
+ items = append(items, item)
+ }
+
+ return items, nil
+}
+
+func NewSymbolsContextGroup(app *app.App) dialog.CompletionProvider {
+ return &symbolsContextGroup{
+ app: app,
+ }
+}
diff --git a/packages/tui/internal/components/chat/editor.go b/packages/tui/internal/components/chat/editor.go
index 4f6249722..444f5bef1 100644
--- a/packages/tui/internal/components/chat/editor.go
+++ b/packages/tui/internal/components/chat/editor.go
@@ -140,9 +140,9 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.spinner = createSpinner()
return m, tea.Batch(m.spinner.Tick, m.textarea.Focus())
case dialog.CompletionSelectedMsg:
- switch msg.ProviderID {
+ switch msg.Item.GetProviderID() {
case "commands":
- commandName := strings.TrimPrefix(msg.CompletionValue, "/")
+ commandName := strings.TrimPrefix(msg.Item.GetValue(), "/")
updated, cmd := m.Clear()
m = updated.(*editorComponent)
cmds = append(cmds, cmd)
@@ -152,7 +152,7 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
atIndex := m.textarea.LastRuneIndex('@')
if atIndex == -1 {
// Should not happen, but as a fallback, just insert.
- m.textarea.InsertString(msg.CompletionValue + " ")
+ m.textarea.InsertString(msg.Item.GetValue() + " ")
return m, nil
}
@@ -163,7 +163,7 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Now, insert the attachment at the position where the '@' was.
// The cursor is now at `atIndex` after the replacement.
- filePath := msg.CompletionValue
+ filePath := msg.Item.GetValue()
extension := filepath.Ext(filePath)
mediaType := ""
switch extension {
@@ -186,15 +186,32 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.textarea.InsertAttachment(attachment)
m.textarea.InsertString(" ")
return m, nil
- default:
- existingValue := m.textarea.Value()
- lastSpaceIndex := strings.LastIndex(existingValue, " ")
- if lastSpaceIndex == -1 {
- m.textarea.SetValue(msg.CompletionValue + " ")
- } else {
- modifiedValue := existingValue[:lastSpaceIndex+1] + msg.CompletionValue
- m.textarea.SetValue(modifiedValue + " ")
+ case "symbols":
+ atIndex := m.textarea.LastRuneIndex('@')
+ if atIndex == -1 {
+ // Should not happen, but as a fallback, just insert.
+ m.textarea.InsertString(msg.Item.GetValue() + " ")
+ return m, nil
}
+
+ cursorCol := m.textarea.CursorColumn()
+ m.textarea.ReplaceRange(atIndex, cursorCol, "")
+
+ symbol := msg.Item.GetRaw().(opencode.Symbol)
+ parts := strings.Split(symbol.Name, ".")
+ lastPart := parts[len(parts)-1]
+ attachment := &textarea.Attachment{
+ ID: uuid.NewString(),
+ Display: "@" + lastPart,
+ URL: msg.Item.GetValue(),
+ Filename: lastPart,
+ MediaType: "text/plain",
+ }
+ m.textarea.InsertAttachment(attachment)
+ m.textarea.InsertString(" ")
+ return m, nil
+ default:
+ slog.Debug("Unknown provider", "provider", msg.Item.GetProviderID())
return m, nil
}
}
diff --git a/packages/tui/internal/components/dialog/complete.go b/packages/tui/internal/components/dialog/complete.go
index 8173c8af1..0e8019a23 100644
--- a/packages/tui/internal/components/dialog/complete.go
+++ b/packages/tui/internal/components/dialog/complete.go
@@ -2,12 +2,15 @@ package dialog
import (
"log/slog"
+ "sort"
"strings"
"github.com/charmbracelet/bubbles/v2/key"
"github.com/charmbracelet/bubbles/v2/textarea"
tea "github.com/charmbracelet/bubbletea/v2"
"github.com/charmbracelet/lipgloss/v2"
+ "github.com/lithammer/fuzzysearch/fuzzy"
+ "github.com/muesli/reflow/truncate"
"github.com/sst/opencode/internal/components/list"
"github.com/sst/opencode/internal/styles"
"github.com/sst/opencode/internal/theme"
@@ -15,32 +18,35 @@ import (
)
type CompletionItem struct {
- Title string
- Value string
+ Title string
+ Value string
+ ProviderID string
+ Raw any
}
type CompletionItemI interface {
list.ListItem
GetValue() string
DisplayValue() string
+ GetProviderID() string
+ GetRaw() any
}
func (ci *CompletionItem) Render(selected bool, width int) string {
t := theme.CurrentTheme()
baseStyle := styles.NewStyle().Foreground(t.Text())
+ truncatedStr := truncate.String(string(ci.DisplayValue()), uint(width-4))
+
itemStyle := baseStyle.
Background(t.BackgroundElement()).
- Width(width).
Padding(0, 1)
if selected {
itemStyle = itemStyle.Foreground(t.Primary())
}
- title := itemStyle.Render(
- ci.DisplayValue(),
- )
+ title := itemStyle.Render(truncatedStr)
return title
}
@@ -52,6 +58,14 @@ func (ci *CompletionItem) GetValue() string {
return ci.Value
}
+func (ci *CompletionItem) GetProviderID() string {
+ return ci.ProviderID
+}
+
+func (ci *CompletionItem) GetRaw() any {
+ return ci.Raw
+}
+
func NewCompletionItem(completionItem CompletionItem) CompletionItemI {
return &completionItem
}
@@ -63,9 +77,8 @@ type CompletionProvider interface {
}
type CompletionSelectedMsg struct {
- SearchString string
- CompletionValue string
- ProviderID string
+ Item CompletionItemI
+ SearchString string
}
type CompletionDialogCompleteItemMsg struct {
@@ -83,7 +96,7 @@ type CompletionDialog interface {
type completionDialogComponent struct {
query string
- completionProvider CompletionProvider
+ providers []CompletionProvider
width int
height int
pseudoSearchTextArea textarea.Model
@@ -109,6 +122,52 @@ func (c *completionDialogComponent) Init() tea.Cmd {
return nil
}
+func (c *completionDialogComponent) getAllCompletions(query string) tea.Cmd {
+ return func() tea.Msg {
+ allItems := make([]CompletionItemI, 0)
+
+ // Collect results from all providers
+ for _, provider := range c.providers {
+ items, err := provider.GetChildEntries(query)
+ if err != nil {
+ slog.Error(
+ "Failed to get completion items",
+ "provider",
+ provider.GetId(),
+ "error",
+ err,
+ )
+ continue
+ }
+ allItems = append(allItems, items...)
+ }
+
+ // If there's a query, use fuzzy ranking to sort results
+ if query != "" && len(allItems) > 0 {
+ // Create a slice of display values for fuzzy matching
+ displayValues := make([]string, len(allItems))
+ for i, item := range allItems {
+ displayValues[i] = item.DisplayValue()
+ }
+
+ // Get fuzzy matches with ranking
+ matches := fuzzy.RankFindFold(query, displayValues)
+
+ // Sort by score (best matches first)
+ sort.Sort(matches)
+
+ // Reorder items based on fuzzy ranking
+ rankedItems := make([]CompletionItemI, 0, len(matches))
+ for _, match := range matches {
+ rankedItems = append(rankedItems, allItems[match.OriginalIndex])
+ }
+
+ return rankedItems
+ }
+
+ return allItems
+ }
+}
func (c *completionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
switch msg := msg.(type) {
@@ -126,14 +185,7 @@ func (c *completionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if query != c.query {
c.query = query
- cmd = func() tea.Msg {
- items, err := c.completionProvider.GetChildEntries(query)
- if err != nil {
- slog.Error("Failed to get completion items", "error", err)
- }
- return items
- }
- cmds = append(cmds, cmd)
+ cmds = append(cmds, c.getAllCompletions(query))
}
u, cmd := c.list.Update(msg)
@@ -149,23 +201,18 @@ func (c *completionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
return c, c.complete(item)
case key.Matches(msg, completionDialogKeys.Cancel):
- // Only close on backspace when there are no characters left, unless we're back to just the trigger
value := c.pseudoSearchTextArea.Value()
- if msg.String() != "backspace" || (len(value) <= len(c.trigger) && value != c.trigger) {
+ width := lipgloss.Width(value)
+ triggerWidth := lipgloss.Width(c.trigger)
+ // Only close on backspace when there are no characters left, unless we're back to just the trigger
+ if msg.String() != "backspace" || (width <= triggerWidth && value != c.trigger) {
return c, c.close()
}
}
return c, tea.Batch(cmds...)
} else {
- cmd := func() tea.Msg {
- items, err := c.completionProvider.GetChildEntries("")
- if err != nil {
- slog.Error("Failed to get completion items", "error", err)
- }
- return items
- }
- cmds = append(cmds, cmd)
+ cmds = append(cmds, c.getAllCompletions(""))
cmds = append(cmds, c.pseudoSearchTextArea.Focus())
return c, tea.Batch(cmds...)
}
@@ -177,19 +224,7 @@ func (c *completionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (c *completionDialogComponent) View() string {
t := theme.CurrentTheme()
baseStyle := styles.NewStyle().Foreground(t.Text())
-
- maxWidth := 40
- completions := c.list.GetItems()
-
- for _, cmd := range completions {
- title := cmd.DisplayValue()
- width := lipgloss.Width(title)
- if width > maxWidth-4 {
- maxWidth = width + 4
- }
- }
-
- c.list.SetMaxWidth(maxWidth)
+ c.list.SetMaxWidth(c.width)
return baseStyle.
Padding(0, 0).
@@ -213,12 +248,10 @@ func (c *completionDialogComponent) IsEmpty() bool {
func (c *completionDialogComponent) complete(item CompletionItemI) tea.Cmd {
value := c.pseudoSearchTextArea.Value()
-
return tea.Batch(
util.CmdHandler(CompletionSelectedMsg{
- SearchString: value,
- CompletionValue: item.GetValue(),
- ProviderID: c.completionProvider.GetId(),
+ SearchString: value,
+ Item: item,
}),
c.close(),
)
@@ -230,32 +263,53 @@ func (c *completionDialogComponent) close() tea.Cmd {
return util.CmdHandler(CompletionDialogCloseMsg{})
}
-func NewCompletionDialogComponent(completionProvider CompletionProvider, trigger string) CompletionDialog {
+func NewCompletionDialogComponent(
+ trigger string,
+ providers ...CompletionProvider,
+) CompletionDialog {
ti := textarea.New()
+ ti.SetValue(trigger)
+
+ // Use a generic empty message if we have multiple providers
+ emptyMessage := "no matching items"
+ if len(providers) == 1 {
+ emptyMessage = providers[0].GetEmptyMessage()
+ }
li := list.NewListComponent(
[]CompletionItemI{},
7,
- completionProvider.GetEmptyMessage(),
+ emptyMessage,
false,
)
- go func() {
- items, err := completionProvider.GetChildEntries("")
- if err != nil {
- slog.Error("Failed to get completion items", "error", err)
- }
- li.SetItems(items)
- }()
-
- // Initialize the textarea with the trigger character
- ti.SetValue(trigger)
-
- return &completionDialogComponent{
+ c := &completionDialogComponent{
query: "",
- completionProvider: completionProvider,
+ providers: providers,
pseudoSearchTextArea: ti,
list: li,
trigger: trigger,
}
+
+ // Load initial items from all providers
+ go func() {
+ allItems := make([]CompletionItemI, 0)
+ for _, provider := range providers {
+ items, err := provider.GetChildEntries("")
+ if err != nil {
+ slog.Error(
+ "Failed to get completion items",
+ "provider",
+ provider.GetId(),
+ "error",
+ err,
+ )
+ continue
+ }
+ allItems = append(allItems, items...)
+ }
+ li.SetItems(allItems)
+ }()
+
+ return c
}
diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go
index 73dd01186..38b61efab 100644
--- a/packages/tui/internal/tui/tui.go
+++ b/packages/tui/internal/tui/tui.go
@@ -65,6 +65,7 @@ type appModel struct {
completions dialog.CompletionDialog
commandProvider dialog.CompletionProvider
fileProvider dialog.CompletionProvider
+ symbolsProvider dialog.CompletionProvider
showCompletionDialog bool
fileCompletionActive bool
leaderBinding *key.Binding
@@ -202,7 +203,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, cmd)
// Set command provider for command completion
- a.completions = dialog.NewCompletionDialogComponent(a.commandProvider, "/")
+ a.completions = dialog.NewCompletionDialogComponent("/", a.commandProvider)
updated, cmd = a.completions.Update(msg)
a.completions = updated.(dialog.CompletionDialog)
cmds = append(cmds, cmd)
@@ -220,8 +221,8 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
a.editor = updated.(chat.EditorComponent)
cmds = append(cmds, cmd)
- // Set file provider for file completion
- a.completions = dialog.NewCompletionDialogComponent(a.fileProvider, "@")
+ // Set both file and symbols providers for @ completion
+ a.completions = dialog.NewCompletionDialogComponent("@", a.fileProvider, a.symbolsProvider)
updated, cmd = a.completions.Update(msg)
a.completions = updated.(dialog.CompletionDialog)
cmds = append(cmds, cmd)
@@ -922,7 +923,7 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
a.modal = themeDialog
case commands.FileListCommand:
a.editor.Blur()
- provider := completions.NewFileAndFolderContextGroup(a.app)
+ provider := completions.NewFileContextGroup(a.app)
findDialog := dialog.NewFindDialog(provider)
findDialog.SetWidth(layout.Current.Container.Width - 8)
a.modal = findDialog
@@ -1030,11 +1031,12 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
func NewModel(app *app.App) tea.Model {
commandProvider := completions.NewCommandCompletionProvider(app)
- fileProvider := completions.NewFileAndFolderContextGroup(app)
+ fileProvider := completions.NewFileContextGroup(app)
+ symbolsProvider := completions.NewSymbolsContextGroup(app)
messages := chat.NewMessagesComponent(app)
editor := chat.NewEditorComponent(app)
- completions := dialog.NewCompletionDialogComponent(commandProvider, "/")
+ completions := dialog.NewCompletionDialogComponent("/", commandProvider)
var leaderBinding *key.Binding
if app.Config.Keybinds.Leader != "" {
@@ -1050,6 +1052,7 @@ func NewModel(app *app.App) tea.Model {
completions: completions,
commandProvider: commandProvider,
fileProvider: fileProvider,
+ symbolsProvider: symbolsProvider,
leaderBinding: leaderBinding,
isLeaderSequence: false,
showCompletionDialog: false,