selection.go

  1package selection
  2
  3import (
  4	"fmt"
  5	"time"
  6
  7	"github.com/charmbracelet/bubbles/key"
  8	"github.com/charmbracelet/bubbles/list"
  9	tea "github.com/charmbracelet/bubbletea"
 10	"github.com/charmbracelet/lipgloss"
 11	appCfg "github.com/charmbracelet/soft-serve/config"
 12	"github.com/charmbracelet/soft-serve/ui/common"
 13	"github.com/charmbracelet/soft-serve/ui/components/selector"
 14	"github.com/charmbracelet/soft-serve/ui/components/yankable"
 15	"github.com/charmbracelet/soft-serve/ui/session"
 16)
 17
 18type Selection struct {
 19	s        session.Session
 20	common   common.Common
 21	selector *selector.Selector
 22}
 23
 24func New(s session.Session, common common.Common) *Selection {
 25	sel := &Selection{
 26		s:        s,
 27		common:   common,
 28		selector: selector.New(common, []list.Item{}),
 29	}
 30	return sel
 31}
 32
 33func (s *Selection) SetSize(width, height int) {
 34	s.common.SetSize(width, height)
 35	s.selector.SetSize(width, height)
 36}
 37
 38func (s *Selection) ShortHelp() []key.Binding {
 39	k := s.selector.KeyMap()
 40	return []key.Binding{
 41		s.common.Keymap.UpDown,
 42		s.common.Keymap.Select,
 43		k.Filter,
 44		k.ClearFilter,
 45	}
 46}
 47
 48func (s *Selection) FullHelp() [][]key.Binding {
 49	k := s.selector.KeyMap()
 50	return [][]key.Binding{
 51		{
 52			k.CursorUp,
 53			k.CursorDown,
 54			k.NextPage,
 55			k.PrevPage,
 56			k.GoToStart,
 57			k.GoToEnd,
 58		},
 59		{
 60			k.Filter,
 61			k.ClearFilter,
 62			k.CancelWhileFiltering,
 63			k.AcceptWhileFiltering,
 64			k.ShowFullHelp,
 65			k.CloseFullHelp,
 66		},
 67		// Ignore the following keys:
 68		// k.Quit,
 69		// k.ForceQuit,
 70	}
 71}
 72
 73func (s *Selection) Init() tea.Cmd {
 74	items := make([]list.Item, 0)
 75	cfg := s.s.Config()
 76	yank := func(text string) *yankable.Yankable {
 77		return yankable.New(
 78			lipgloss.NewStyle().Foreground(lipgloss.Color("168")),
 79			lipgloss.NewStyle().Foreground(lipgloss.Color("168")).SetString("Copied!"),
 80			text,
 81		)
 82	}
 83	// Put configured repos first
 84	for _, r := range cfg.Repos {
 85		items = append(items, selector.Item{
 86			Title:       r.Name,
 87			Name:        r.Repo,
 88			Description: r.Note,
 89			LastUpdate:  time.Now(),
 90			URL:         yank(repoUrl(cfg, r.Name)),
 91		})
 92	}
 93	for _, r := range cfg.Source.AllRepos() {
 94		exists := false
 95		for _, item := range items {
 96			item := item.(selector.Item)
 97			if item.Name == r.Name() {
 98				exists = true
 99				break
100			}
101		}
102		if !exists {
103			items = append(items, selector.Item{
104				Title:       r.Name(),
105				Name:        r.Name(),
106				Description: "",
107				LastUpdate:  time.Now(),
108				URL:         yank(repoUrl(cfg, r.Name())),
109			})
110		}
111	}
112	return s.selector.SetItems(items)
113}
114
115func (s *Selection) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
116	cmds := make([]tea.Cmd, 0)
117	switch msg := msg.(type) {
118	default:
119		m, cmd := s.selector.Update(msg)
120		s.selector = m.(*selector.Selector)
121		if cmd != nil {
122			cmds = append(cmds, cmd)
123		}
124	}
125	return s, tea.Batch(cmds...)
126}
127
128func (s *Selection) View() string {
129	return s.selector.View()
130}
131
132func repoUrl(cfg *appCfg.Config, name string) string {
133	port := ""
134	if cfg.Port != 22 {
135		port += fmt.Sprintf(":%d", cfg.Port)
136	}
137	return fmt.Sprintf("git clone ssh://%s/%s", cfg.Host+port, name)
138}