package main import ( "fmt" "os" tea "github.com/charmbracelet/bubbletea" ) const ( BrowserSessions int = iota // Enumerating the sections Commands ) type sessionOrCommand struct { displayString string commandString string } type Choices [][]sessionOrCommand type SelectionSet map[int]struct{} type model struct { activeSection int cursor []int choices Choices selected []SelectionSet } var browserSelection SelectionSet var commandSelection SelectionSet func getBrowserSessions() []sessionOrCommand { // Placeholder return []sessionOrCommand{{ displayString: "primary", commandString: "", }, { displayString: "breakfast", commandString: "", }} } func initialModel() model { browserSelection = make(SelectionSet) commandSelection = make(SelectionSet) return model{ activeSection: BrowserSessions, cursor: []int{0, 0}, choices: Choices{ getBrowserSessions(), []sessionOrCommand{{ displayString: "neomutt", commandString: "neomutt", }, { displayString: "bottom", commandString: "btm --group --battery --color gruvbox-light", }}, }, // An array maps which indicates which choices are selected. We're // using the map like a mathematical set. The keys refer to the // indexes of the `choices` slice, above. selected: []SelectionSet{browserSelection, commandSelection}, } } func (m model) Init() tea.Cmd { return nil } func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch msg.String() { case "ctrl+c", "q": return m, tea.Quit case "tab": if m.activeSection == BrowserSessions { m.activeSection = Commands } else { m.activeSection = BrowserSessions } case "up", "k": if m.cursor[m.activeSection] > 0 { m.cursor[m.activeSection]-- } case "down", "j": if m.cursor[m.activeSection] < len(m.choices[m.activeSection])-1 { m.cursor[m.activeSection]++ } case "enter", " ": _, ok := m.selected[m.activeSection][m.cursor[m.activeSection]] if ok { delete(m.selected[m.activeSection], m.cursor[m.activeSection]) } else { m.selected[m.activeSection][m.cursor[m.activeSection]] = struct{}{} } } } return m, nil } func (m model) View() string { s := "What should we buy at the market?\n\n" for j := 0; j < 2; j++ { for i, choice := range m.choices[j] { cursor := " " if m.cursor[j] == i { cursor = ">" } checked := " " if _, ok := m.selected[j][i]; ok { checked = "x" } s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice.displayString) } s += "\n\n" } // s += fmt.Sprintf("\n%+v", m.selected) // debug s += "\nPress q to quit.\n" return s } func main() { p := tea.NewProgram(initialModel()) if err := p.Start(); err != nil { fmt.Printf("Alas, there's been an error: %v", err) os.Exit(1) } }