package main import ( "fmt" "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" ) type selectingModel struct { initialFilter string list list.Model } func StartSelecting(initialFilter string) *selectingModel { items, err := getItems() if err != nil { panic(err) } lst := list.New(items, list.NewDefaultDelegate(), 0, 0) lst.Title = "Commands" m := selectingModel{ list: lst, initialFilter: initialFilter, } return &m } func (m *selectingModel) Init() tea.Cmd { if m.initialFilter != "" { // ok so this is scuffed! // there's no way to just set the filter, so instead we mimic typing it. // we can ignore every command except the last one, which will just update our visible items lst, cmd := m.list.Update(tea.KeyMsg{ Type: tea.KeyRunes, Runes: []rune{'/'}, }) for _, chr := range m.initialFilter { lst, cmd = lst.Update(tea.KeyMsg{ Type: tea.KeyRunes, Runes: []rune{chr}, }) } lst, _ = lst.Update(tea.KeyMsg{ Type: tea.KeyEnter, Runes: []rune{}, }) m.list = lst return tea.Batch(tea.EnterAltScreen, cmd) } return tea.EnterAltScreen } func (m *selectingModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd switch msg := msg.(type) { case tea.WindowSizeMsg: h, v := appStyle.GetFrameSize() m.list.SetSize(msg.Width-h, msg.Height-v) case tea.KeyMsg: // Don't match any of the keys below if we're actively filtering. if m.list.FilterState() == list.Filtering { break } switch msg.String() { case "+", "n": cmds = append(cmds, newItemCmd()) case "enter", " ": if m.list.SelectedItem() != nil { return switchToConfirm(m) } case "e": if m.list.SelectedItem() != nil { cmds = append(cmds, editItemCmd(m.list.SelectedItem().(item))) } case "d": if m.list.SelectedItem() != nil { cmds = append(cmds, deleteItemCmd(m.list.SelectedItem().(item))) } } case vimFinishedMsg: if msg.err != nil { fmt.Println(msg.err) return m, tea.Quit } return switchToDetails(m, msg.snippet) case setListItemsMsg: cmds = append(cmds, m.list.SetItems(msg.newItems)) case updateListMsg: cmds = append(cmds, func() tea.Msg { items, err := getItems() if err != nil { return fatalErrorMsg(err) } return setListItemsMsg{items} }) case fatalErrorMsg: fmt.Printf("encountered fatal error: %s\n", msg.Error()) return m, tea.Quit } // This will also call our delegate's update function. newListModel, cmd := m.list.Update(msg) m.list = newListModel cmds = append(cmds, cmd) return m, tea.Batch(cmds...) } func (m *selectingModel) View() string { return appStyle.Render(m.list.View()) } type setListItemsMsg struct { newItems []list.Item }