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 model struct { activeSection int cursor []int choices Choices selected []map[int]struct{} } func getBrowserSessions() []sessionOrCommand { // Placeholder return []sessionOrCommand{{ displayString: "primary", commandString: "", }, { displayString: "breakfast", commandString: "", }} } func initialModel() model { return model{ activeSection: BrowserSessions, // Need syntax of two-dimensional slices 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: make([]map[int]struct{}, 32, 32), } } 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 "up", "k": if m.cursor[m.activeSection] > 0 { m.cursor[m.activeSection]-- } case "down", "j": if m.cursor[m.activeSection] < len(m.browserSessions)+len(m.commands)-1 { m.cursor[m.activeSection]++ } case "enter", " ": // TODO: Let's have two separate cursors, and have tab move the active // set from brower sessions to terminals. if m.cursor[m.activeSection] < len(m.browserSessions)-1 { _, ok := m.selected[m.cursor] if ok { delete(m.selected, m.cursor) } else { m.selected[m.cursor] = struct{}{} } } else { _, ok := m.selected[m.cursor] if ok { delete(m.selected, m.cursor) } else { m.selected[m.cursor] = struct{}{} } } } } return m, nil } func (m model) View() string { s := "What should we buy at the market?\n\n" for i, choice := range m.choices { cursor := " " if m.cursor == i { cursor = ">" } checked := " " if _, ok := m.selected[i]; ok { checked = "x" } s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice) } 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) } }