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