mirror of
https://github.com/sst/opencode.git
synced 2025-08-25 23:44:08 +00:00
110 lines
2.6 KiB
Go
110 lines
2.6 KiB
Go
package completions
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/lipgloss/v2"
|
|
"github.com/lithammer/fuzzysearch/fuzzy"
|
|
"github.com/sst/opencode/internal/app"
|
|
"github.com/sst/opencode/internal/commands"
|
|
"github.com/sst/opencode/internal/styles"
|
|
"github.com/sst/opencode/internal/theme"
|
|
)
|
|
|
|
type CommandCompletionProvider struct {
|
|
app *app.App
|
|
}
|
|
|
|
func NewCommandCompletionProvider(app *app.App) CompletionProvider {
|
|
return &CommandCompletionProvider{app: app}
|
|
}
|
|
|
|
func (c *CommandCompletionProvider) GetId() string {
|
|
return "commands"
|
|
}
|
|
|
|
func (c *CommandCompletionProvider) GetEmptyMessage() string {
|
|
return "no matching commands"
|
|
}
|
|
|
|
func (c *CommandCompletionProvider) getCommandCompletionItem(
|
|
cmd commands.Command,
|
|
space int,
|
|
) CompletionSuggestion {
|
|
displayFunc := func(s styles.Style) string {
|
|
t := theme.CurrentTheme()
|
|
spacer := strings.Repeat(" ", space)
|
|
display := " /" + cmd.PrimaryTrigger() + s.
|
|
Foreground(t.TextMuted()).
|
|
Render(spacer+cmd.Description)
|
|
return display
|
|
}
|
|
|
|
value := string(cmd.Name)
|
|
return CompletionSuggestion{
|
|
Display: displayFunc,
|
|
Value: value,
|
|
ProviderID: c.GetId(),
|
|
RawData: cmd,
|
|
}
|
|
}
|
|
|
|
func (c *CommandCompletionProvider) GetChildEntries(
|
|
query string,
|
|
) ([]CompletionSuggestion, error) {
|
|
commands := c.app.Commands
|
|
|
|
space := 1
|
|
for _, cmd := range c.app.Commands {
|
|
if cmd.HasTrigger() && lipgloss.Width(cmd.PrimaryTrigger()) > space {
|
|
space = lipgloss.Width(cmd.PrimaryTrigger())
|
|
}
|
|
}
|
|
space += 2
|
|
|
|
sorted := commands.Sorted()
|
|
if query == "" {
|
|
// If no query, return all commands
|
|
items := []CompletionSuggestion{}
|
|
for _, cmd := range sorted {
|
|
if !cmd.HasTrigger() {
|
|
continue
|
|
}
|
|
space := space - lipgloss.Width(cmd.PrimaryTrigger())
|
|
items = append(items, c.getCommandCompletionItem(cmd, space))
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
var commandNames []string
|
|
commandMap := make(map[string]CompletionSuggestion)
|
|
|
|
for _, cmd := range sorted {
|
|
if !cmd.HasTrigger() {
|
|
continue
|
|
}
|
|
space := space - lipgloss.Width(cmd.PrimaryTrigger())
|
|
for _, trigger := range cmd.Trigger {
|
|
commandNames = append(commandNames, trigger)
|
|
commandMap[trigger] = c.getCommandCompletionItem(cmd, space)
|
|
}
|
|
}
|
|
|
|
matches := fuzzy.RankFindFold(query, commandNames)
|
|
sort.Sort(matches)
|
|
|
|
// Convert matches to completion items, deduplicating by command name
|
|
items := []CompletionSuggestion{}
|
|
seen := make(map[string]bool)
|
|
for _, match := range matches {
|
|
if item, ok := commandMap[match.Target]; ok {
|
|
// Use the command's value (name) as the deduplication key
|
|
if !seen[item.Value] {
|
|
seen[item.Value] = true
|
|
items = append(items, item)
|
|
}
|
|
}
|
|
}
|
|
return items, nil
|
|
}
|