main.go (3177B)
1 package main 2 3 import ( 4 "fmt" 5 "strings" 6 7 "git.figbert.com/caret/api" 8 "git.figbert.com/caret/comments" 9 "git.figbert.com/caret/ui" 10 "git.figbert.com/caret/utils" 11 12 "github.com/charmbracelet/bubbles/list" 13 "github.com/charmbracelet/bubbletea" 14 ) 15 16 type model struct { 17 width, height int 18 page int 19 msg string 20 posts list.Model 21 } 22 23 func (m model) Init() tea.Cmd { 24 return tea.Batch(api.FetchPage(m.page), startLoading) 25 } 26 27 func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { 28 var cmds []tea.Cmd 29 30 switch msg := msg.(type) { 31 case tea.WindowSizeMsg: 32 m.width = msg.Width 33 m.height = msg.Height 34 m.posts.SetWidth(msg.Width) 35 m.posts.SetHeight(msg.Height - 4) 36 case tea.KeyMsg: 37 switch msg.String() { 38 case "ctrl+c": 39 return m, tea.Quit 40 case "o": 41 cmds = append(cmds, attemptToOpenPostURL(m.posts.SelectedItem())) 42 case "c": 43 cmds = append(cmds, attemptToOpenPostComments(m.posts.SelectedItem())) 44 case " ": 45 cmds = append(cmds, displayLinkedArticle(m.posts.SelectedItem()), startLoading) 46 case "enter": 47 cmds = append(cmds, fetchComments(m.posts.SelectedItem()), startLoading) 48 case "j": 49 if m.posts.Index() == len(m.posts.Items())-1 { 50 m.page++ 51 cmds = append(cmds, api.FetchPage(m.page), startLoading) 52 } 53 fallthrough 54 default: 55 var cmd tea.Cmd 56 m.posts, cmd = m.posts.Update(msg) 57 cmds = append(cmds, cmd) 58 } 59 case api.PageMsg: 60 m.msg = "" 61 for _, pst := range []api.Post(msg) { 62 m.posts.SetItems(append(m.posts.Items(), item{post: pst})) 63 } 64 case api.PostMsg: 65 cmds = append(cmds, comments.Load(api.Post(msg))) 66 case api.ErrorMsg: 67 m.msg = fmt.Sprintf("Failed to fetch new stories -> %s", msg) 68 cmds = append(cmds, clearMsg) 69 case loading: 70 m.msg = "Loading…" 71 case utils.Error: 72 m.msg = "Error! How perplexing." 73 cmds = append(cmds, clearMsg) 74 case utils.NoExternalURL: 75 m.msg = "This post does not have an external URL to open." 76 cmds = append(cmds, clearMsg) 77 case platformUnsupported: 78 m.msg = "Exotic! Opening URLs on your OS is not yet supported. Reach out!" 79 cmds = append(cmds, clearMsg) 80 case utils.RunCommand: 81 cmds = append(cmds, run(msg)) 82 case returnedFromReading, msgExpired: 83 m.msg = "" 84 } 85 86 return m, tea.Batch(cmds...) 87 } 88 89 func (m model) View() string { 90 var view strings.Builder 91 92 view.WriteString("\n " + ui.LobstersRed().Render("Lobsters")) 93 94 padding := m.width - 1 - 8 - len(m.msg) - 1 95 if padding < 0 { 96 errorDot := ui.LobstersRed().Render("● ") 97 padding = m.width - 1 - 8 - 1 - 1 98 if padding < 0 { 99 view.WriteString(" " + errorDot) 100 } else { 101 view.WriteString(strings.Repeat(" ", padding) + errorDot) 102 } 103 } else { 104 view.WriteString(strings.Repeat(" ", padding) + ui.Gray().Render(m.msg) + " ") 105 } 106 107 view.WriteString("\n " + ui.HR(m.width-2) + "\n") 108 if len(m.posts.Items()) > 0 { 109 view.WriteString(m.posts.View()) 110 } 111 112 return view.String() 113 } 114 115 func main() { 116 m := model{ 117 page: 1, 118 posts: list.New([]list.Item{}, itemDelegate{}, 0, 0), 119 } 120 m.posts.SetShowStatusBar(false) 121 m.posts.SetShowHelp(false) 122 m.posts.SetFilteringEnabled(false) 123 m.posts.SetShowTitle(false) 124 m.posts.SetShowPagination(false) 125 126 tea.NewProgram(m, tea.WithAltScreen()).Run() 127 }