Detailed changes
@@ -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
@@ -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)
}
@@ -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":
@@ -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
}
@@ -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")).
@@ -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()
+}