From 5efc4b87504c8ae1033226643467a430854bf409 Mon Sep 17 00:00:00 2001 From: Toby Padilla Date: Wed, 4 Aug 2021 19:02:59 -0500 Subject: [PATCH] Display readmes WIP --- git/git.go | 7 +++++ tui/bubble.go | 54 ++++++++++++++++++++++------------- tui/bubbles/commits/bubble.go | 9 ++---- tui/commands.go | 17 +++++++---- tui/style.go | 19 ++++++++---- tui/viewport_patch.go | 24 ++++++++++++++++ 6 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 tui/viewport_patch.go diff --git a/git/git.go b/git/git.go index 7293c0694..eca024be3 100644 --- a/git/git.go +++ b/git/git.go @@ -88,6 +88,13 @@ func (rs *RepoSource) loadRepos() { l.ForEach(func(c *object.Commit) error { if r.LastUpdated == nil { r.LastUpdated = &c.Author.When + rf, err := c.File("README.md") + if err == nil { + rmd, err := rf.Contents() + if err == nil { + r.Readme = rmd + } + } } rs.commits = append(rs.commits, RepoCommit{Name: rn, Commit: c}) return nil diff --git a/tui/bubble.go b/tui/bubble.go index abdc6ef99..a5e8cfbd7 100644 --- a/tui/bubble.go +++ b/tui/bubble.go @@ -3,8 +3,11 @@ package tui import ( "fmt" "smoothie/git" + "smoothie/tui/bubbles/commits" + "smoothie/tui/bubbles/selection" "time" + "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/gliderlabs/ssh" @@ -23,14 +26,17 @@ const ( type Model struct { state sessionState error string - info string width int height int windowChanges <-chan ssh.Window repoSource *git.RepoSource repos []*git.Repo - activeBubble int - bubbles []tea.Model + boxes []tea.Model + activeBox int + + repoSelect *selection.Bubble + commitsLog *commits.Bubble + readmeViewport *ViewportBubble } func NewModel(width int, height int, windowChanges <-chan ssh.Window, repoSource *git.RepoSource) *Model { @@ -39,7 +45,13 @@ func NewModel(width int, height int, windowChanges <-chan ssh.Window, repoSource height: height, windowChanges: windowChanges, repoSource: repoSource, - bubbles: make([]tea.Model, 2), + boxes: make([]tea.Model, 2), + readmeViewport: &ViewportBubble{ + Viewport: &viewport.Model{ + Width: boxRightWidth - horizontalPadding - 2, + Height: height - verticalPadding - viewportHeightConstant, + }, + }, } m.state = startState return m @@ -53,30 +65,33 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds := make([]tea.Cmd, 0) // Always allow state, error, info, window resize and quit messages switch msg := msg.(type) { - case stateMsg: - m.state = msg.state case tea.KeyMsg: switch msg.String() { case "q", "ctrl+c": return m, tea.Quit case "tab": - m.activeBubble = (m.activeBubble + 1) % 2 + m.activeBox = (m.activeBox + 1) % 2 } case errMsg: m.error = msg.Error() m.state = errorState return m, nil - case infoMsg: - m.info = msg.text case windowMsg: cmds = append(cmds, m.windowChangesCmd) case tea.WindowSizeMsg: m.width = msg.Width m.height = msg.Height + case selection.SelectedMsg: + rmd := m.repos[msg.Index].Readme + m.readmeViewport.Viewport.GotoTop() + m.readmeViewport.Viewport.Height = m.height - verticalPadding - viewportHeightConstant + m.readmeViewport.Viewport.Width = boxLeftWidth - 2 + m.readmeViewport.Viewport.SetContent(rmd) + m.boxes[1] = m.readmeViewport } if m.state == loadedState { - b, cmd := m.bubbles[m.activeBubble].Update(msg) - m.bubbles[m.activeBubble] = b + b, cmd := m.boxes[m.activeBox].Update(msg) + m.boxes[m.activeBox] = b if cmd != nil { cmds = append(cmds, cmd) } @@ -84,33 +99,32 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Batch(cmds...) } -func (m *Model) viewForBubble(i int, width int) string { +func (m *Model) viewForBox(i int, width int) string { var ls lipgloss.Style - if i == m.activeBubble { + if i == m.activeBox { ls = activeBoxStyle.Width(width) } else { ls = inactiveBoxStyle.Width(width) } - return ls.Render(m.bubbles[i].View()) + return ls.Render(m.boxes[i].View()) } func (m *Model) View() string { - pad := 6 - h := headerStyle.Width(m.width - pad).Render("Charm Beta") - f := footerStyle.Render(m.info) + h := headerStyle.Width(m.width - horizontalPadding).Render("Charm Beta") + f := footerStyle.Render("") s := "" content := "" switch m.state { case loadedState: - lb := m.viewForBubble(0, 25) - rb := m.viewForBubble(1, 84) + lb := m.viewForBox(0, boxLeftWidth) + rb := m.viewForBox(1, boxRightWidth) s += lipgloss.JoinHorizontal(lipgloss.Top, lb, rb) case errorState: s += errorStyle.Render(fmt.Sprintf("Bummer: %s", m.error)) default: s = normalStyle.Render(fmt.Sprintf("Doing something weird %d", m.state)) } - content = h + "\n" + s + "\n" + f + content = h + "\n\n" + s + "\n" + f return appBoxStyle.Render(content) } diff --git a/tui/bubbles/commits/bubble.go b/tui/bubbles/commits/bubble.go index 1e7ed7ca5..1894a504d 100644 --- a/tui/bubbles/commits/bubble.go +++ b/tui/bubbles/commits/bubble.go @@ -11,16 +11,15 @@ import ( type Bubble struct { Commits []git.RepoCommit - Margin int - Width int Height int + Width int viewport viewport.Model } -func NewBubble(height int, margin int, width int, rcs []git.RepoCommit) *Bubble { +func NewBubble(height int, width int, rcs []git.RepoCommit) *Bubble { b := &Bubble{ Commits: rcs, - viewport: viewport.Model{Height: height - margin, Width: width}, + viewport: viewport.Model{Height: height, Width: width}, } s := "" for _, rc := range rcs { @@ -37,8 +36,6 @@ func (b *Bubble) Init() tea.Cmd { func (b *Bubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds := make([]tea.Cmd, 0) switch msg := msg.(type) { - case tea.WindowSizeMsg: - b.viewport.Height = msg.Height - b.Margin case tea.KeyMsg: switch msg.String() { case "up", "k": diff --git a/tui/commands.go b/tui/commands.go index 3317d3652..4878ec99d 100644 --- a/tui/commands.go +++ b/tui/commands.go @@ -7,8 +7,6 @@ import ( tea "github.com/charmbracelet/bubbletea" ) -type stateMsg struct{ state sessionState } -type infoMsg struct{ text string } type windowMsg struct{} type errMsg struct{ err error } @@ -24,13 +22,20 @@ func (m *Model) windowChangesCmd() tea.Msg { } func (m *Model) loadGitCmd() tea.Msg { + m.repos = m.repoSource.AllRepos() rs := make([]string, 0) - for _, r := range m.repoSource.AllRepos() { + for _, r := range m.repos { rs = append(rs, r.Name) } - m.bubbles[0] = selection.NewBubble(rs) - m.bubbles[1] = commits.NewBubble(m.height, 7, 80, m.repoSource.GetCommits(200)) - m.activeBubble = 0 + m.repoSelect = selection.NewBubble(rs) + m.boxes[0] = m.repoSelect + m.commitsLog = commits.NewBubble( + m.height-verticalPadding-2, + boxRightWidth-horizontalPadding-2, + m.repoSource.GetCommits(200), + ) + m.boxes[1] = m.commitsLog + m.activeBox = 0 m.state = loadedState return nil } diff --git a/tui/style.go b/tui/style.go index 2cd8e6c0c..1d04dc48e 100644 --- a/tui/style.go +++ b/tui/style.go @@ -4,22 +4,31 @@ import ( "github.com/charmbracelet/lipgloss" ) +const boxLeftWidth = 25 +const boxRightWidth = 80 +const headerHeight = 1 +const footerHeight = 2 +const appPadding = 1 +const boxPadding = 1 +const viewportHeightConstant = 7 // TODO figure out why this needs to be 7 +const horizontalPadding = appPadding * 2 +const verticalPadding = headerHeight + footerHeight + (appPadding * 2) + var appBoxStyle = lipgloss.NewStyle(). - PaddingLeft(2). - PaddingRight(2). - MarginBottom(1) + PaddingLeft(appPadding). + PaddingRight(appPadding) var inactiveBoxStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("#606060")). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("#303030")). - Padding(1) + Padding(boxPadding) var activeBoxStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("#FFFFFF")). BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("#714C7B")). - Padding(1) + Padding(boxPadding) var headerStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("#670083")). diff --git a/tui/viewport_patch.go b/tui/viewport_patch.go new file mode 100644 index 000000000..b924145a0 --- /dev/null +++ b/tui/viewport_patch.go @@ -0,0 +1,24 @@ +package tui + +import ( + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" +) + +type ViewportBubble struct { + Viewport *viewport.Model +} + +func (v *ViewportBubble) Init() tea.Cmd { + return nil +} + +func (v *ViewportBubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + vp, cmd := v.Viewport.Update(msg) + v.Viewport = &vp + return v, cmd +} + +func (v *ViewportBubble) View() string { + return v.Viewport.View() +}