bubbletea/examples/autocomplete/main.go

132 lines
2.8 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
func main() {
p := tea.NewProgram(initialModel())
if _, err := p.Run(); err != nil {
log.Fatal(err)
}
}
type gotReposSuccessMsg []repo
type gotReposErrMsg error
type repo struct {
Name string `json:"name"`
}
const reposURL = "https://api.github.com/orgs/charmbracelet/repos"
func getRepos() tea.Msg {
req, err := http.NewRequest(http.MethodGet, reposURL, nil)
if err != nil {
return gotReposErrMsg(err)
}
req.Header.Add("Accept", "application/vnd.github+json")
req.Header.Add("X-GitHub-Api-Version", "2022-11-28")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return gotReposErrMsg(err)
}
defer resp.Body.Close() // nolint: errcheck
data, err := io.ReadAll(resp.Body)
if err != nil {
return gotReposErrMsg(err)
}
var repos []repo
err = json.Unmarshal(data, &repos)
if err != nil {
return gotReposErrMsg(err)
}
return gotReposSuccessMsg(repos)
}
type model struct {
textInput textinput.Model
help help.Model
keymap keymap
}
type keymap struct{}
func (k keymap) ShortHelp() []key.Binding {
return []key.Binding{
key.NewBinding(key.WithKeys("tab"), key.WithHelp("tab", "complete")),
key.NewBinding(key.WithKeys("ctrl+n"), key.WithHelp("ctrl+n", "next")),
key.NewBinding(key.WithKeys("ctrl+p"), key.WithHelp("ctrl+p", "prev")),
key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "quit")),
}
}
func (k keymap) FullHelp() [][]key.Binding {
return [][]key.Binding{k.ShortHelp()}
}
func initialModel() model {
ti := textinput.New()
ti.Placeholder = "repository"
ti.Prompt = "charmbracelet/"
ti.PromptStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("63"))
ti.Cursor.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("63"))
ti.Focus()
ti.CharLimit = 50
ti.Width = 20
ti.ShowSuggestions = true
h := help.New()
km := keymap{}
return model{textInput: ti, help: h, keymap: km}
}
func (m model) Init() tea.Cmd {
return tea.Batch(getRepos, textinput.Blink)
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.Type {
case tea.KeyEnter, tea.KeyCtrlC, tea.KeyEsc:
return m, tea.Quit
}
case gotReposSuccessMsg:
var suggestions []string
for _, r := range msg {
suggestions = append(suggestions, r.Name)
}
m.textInput.SetSuggestions(suggestions)
}
var cmd tea.Cmd
m.textInput, cmd = m.textInput.Update(msg)
return m, cmd
}
func (m model) View() string {
return fmt.Sprintf(
"Pick a Charm™ repo:\n\n %s\n\n%s\n\n",
m.textInput.View(),
m.help.View(m.keymap),
)
}