diff options
| author | Adictya <[email protected]> | 2025-05-15 08:42:45 +0530 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-05-15 08:29:54 -0500 |
| commit | 15bf40bc102ed5426fa2148b9e8f39acef1174a0 (patch) | |
| tree | 4b005eba92703864a4bc2884b3cdc1fb5ab21a3c /internal/tui/components/util | |
| parent | a33e3e25b6646b6128975836d7f182e89f5eb891 (diff) | |
| download | opencode-15bf40bc102ed5426fa2148b9e8f39acef1174a0.tar.gz opencode-15bf40bc102ed5426fa2148b9e8f39acef1174a0.zip | |
feat(complete-module): add completions logic, dialog and providers
Diffstat (limited to 'internal/tui/components/util')
| -rw-r--r-- | internal/tui/components/util/simple-list.go | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/internal/tui/components/util/simple-list.go b/internal/tui/components/util/simple-list.go new file mode 100644 index 000000000..7b8c4b1cb --- /dev/null +++ b/internal/tui/components/util/simple-list.go @@ -0,0 +1,159 @@ +package utilComponents + +import ( + "github.com/charmbracelet/bubbles/key" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/sst/opencode/internal/tui/layout" + "github.com/sst/opencode/internal/tui/styles" + "github.com/sst/opencode/internal/tui/theme" +) + +type SimpleListItem interface { + Render(selected bool, width int) string +} + +type SimpleList[T SimpleListItem] interface { + tea.Model + layout.Bindings + SetMaxWidth(maxWidth int) + GetSelectedItem() (item T, idx int) + SetItems(items []T) + GetItems() []T +} + +type simpleListCmp[T SimpleListItem] struct { + fallbackMsg string + items []T + selectedIdx int + maxWidth int + maxVisibleItems int + useAlphaNumericKeys bool + width int + height int +} + +type simpleListKeyMap struct { + Up key.Binding + Down key.Binding + UpAlpha key.Binding + DownAlpha key.Binding +} + +var simpleListKeys = simpleListKeyMap{ + Up: key.NewBinding( + key.WithKeys("up"), + key.WithHelp("↑", "previous list item"), + ), + Down: key.NewBinding( + key.WithKeys("down"), + key.WithHelp("↓", "next list item"), + ), + UpAlpha: key.NewBinding( + key.WithKeys("k"), + key.WithHelp("k", "previous list item"), + ), + DownAlpha: key.NewBinding( + key.WithKeys("j"), + key.WithHelp("j", "next list item"), + ), +} + +func (c *simpleListCmp[T]) Init() tea.Cmd { + return nil +} + +func (c *simpleListCmp[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch { + case key.Matches(msg, simpleListKeys.Up) || (c.useAlphaNumericKeys && key.Matches(msg, simpleListKeys.UpAlpha)): + if c.selectedIdx > 0 { + c.selectedIdx-- + } + return c, nil + case key.Matches(msg, simpleListKeys.Down) || (c.useAlphaNumericKeys && key.Matches(msg, simpleListKeys.DownAlpha)): + if c.selectedIdx < len(c.items)-1 { + c.selectedIdx++ + } + return c, nil + } + } + + return c, nil +} + +func (c *simpleListCmp[T]) BindingKeys() []key.Binding { + return layout.KeyMapToSlice(simpleListKeys) +} + +func (c *simpleListCmp[T]) GetSelectedItem() (T, int) { + if len(c.items) > 0 { + return c.items[c.selectedIdx], c.selectedIdx + } + + var zero T + return zero, -1 +} + +func (c *simpleListCmp[T]) SetItems(items []T) { + c.selectedIdx = 0 + c.items = items +} + +func (c *simpleListCmp[T]) GetItems() []T { + return c.items +} + +func (c *simpleListCmp[T]) SetMaxWidth(width int) { + c.maxWidth = width +} + +func (c *simpleListCmp[T]) View() string { + t := theme.CurrentTheme() + baseStyle := styles.BaseStyle() + + items := c.items + maxWidth := c.maxWidth + maxVisibleItems := min(c.maxVisibleItems, len(items)) + startIdx := 0 + + if len(items) <= 0 { + return baseStyle. + Background(t.Background()). + Padding(0, 1). + Width(maxWidth). + Render(c.fallbackMsg) + } + + if len(items) > maxVisibleItems { + halfVisible := maxVisibleItems / 2 + if c.selectedIdx >= halfVisible && c.selectedIdx < len(items)-halfVisible { + startIdx = c.selectedIdx - halfVisible + } else if c.selectedIdx >= len(items)-halfVisible { + startIdx = len(items) - maxVisibleItems + } + } + + endIdx := min(startIdx+maxVisibleItems, len(items)) + + listItems := make([]string, 0, maxVisibleItems) + + for i := startIdx; i < endIdx; i++ { + item := items[i] + title := item.Render(i == c.selectedIdx, maxWidth) + listItems = append(listItems, title) + } + + return lipgloss.JoinVertical(lipgloss.Left, listItems...) +} + +func NewSimpleList[T SimpleListItem](items []T, maxVisibleItems int, fallbackMsg string, useAlphaNumericKeys bool) SimpleList[T] { + return &simpleListCmp[T]{ + fallbackMsg: fallbackMsg, + items: items, + maxVisibleItems: maxVisibleItems, + useAlphaNumericKeys: useAlphaNumericKeys, + selectedIdx: 0, + } +} |
