fix: move repo readme into its own model

Ayman Bagabas created

* fix refs switch flickering

Change summary

ui/pages/repo/readme.go | 105 +++++++++++++++++++++++++++++++++++++++++++
ui/pages/repo/refs.go   |  19 ++++---
ui/pages/repo/repo.go   |  55 ++--------------------
3 files changed, 121 insertions(+), 58 deletions(-)

Detailed changes

ui/pages/repo/readme.go 🔗

@@ -0,0 +1,105 @@
+package repo
+
+import (
+	"fmt"
+
+	"github.com/charmbracelet/bubbles/key"
+	tea "github.com/charmbracelet/bubbletea"
+	"github.com/charmbracelet/soft-serve/ui/common"
+	"github.com/charmbracelet/soft-serve/ui/components/code"
+	"github.com/charmbracelet/soft-serve/ui/git"
+)
+
+// Readme is the readme component page.
+type Readme struct {
+	common common.Common
+	code   *code.Code
+	ref    RefMsg
+	repo   git.GitRepo
+}
+
+// NewReadme creates a new readme model.
+func NewReadme(common common.Common) *Readme {
+	readme := code.New(common, "", "")
+	readme.NoContentStyle = readme.NoContentStyle.SetString("No readme found.")
+	return &Readme{
+		code:   readme,
+		common: common,
+	}
+}
+
+// SetSize implements common.Component.
+func (r *Readme) SetSize(width, height int) {
+	r.common.SetSize(width, height)
+	r.code.SetSize(width, height)
+}
+
+// ShortHelp implements help.KeyMap.
+func (r *Readme) ShortHelp() []key.Binding {
+	b := []key.Binding{
+		r.common.KeyMap.UpDown,
+	}
+	return b
+}
+
+// FullHelp implements help.KeyMap.
+func (r *Readme) FullHelp() [][]key.Binding {
+	k := r.code.KeyMap
+	b := [][]key.Binding{
+		{
+			k.PageDown,
+			k.PageUp,
+			k.HalfPageDown,
+			k.HalfPageUp,
+		},
+		{
+			k.Down,
+			k.Up,
+		},
+	}
+	return b
+}
+
+// Init implements tea.Model.
+func (r *Readme) Init() tea.Cmd {
+	if r.repo == nil {
+		return common.ErrorCmd(git.ErrMissingRepo)
+	}
+	rm, rp := r.repo.Readme()
+	r.code.GotoTop()
+	return r.code.SetContent(rm, rp)
+}
+
+// Update implements tea.Model.
+func (r *Readme) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	cmds := make([]tea.Cmd, 0)
+	switch msg := msg.(type) {
+	case RepoMsg:
+		r.repo = git.GitRepo(msg)
+		cmds = append(cmds, r.Init())
+	case RefMsg:
+		r.ref = msg
+		cmds = append(cmds, r.Init())
+	}
+	c, cmd := r.code.Update(msg)
+	r.code = c.(*code.Code)
+	if cmd != nil {
+		cmds = append(cmds, cmd)
+	}
+	return r, tea.Batch(cmds...)
+}
+
+// View implements tea.Model.
+func (r *Readme) View() string {
+	return r.code.View()
+}
+
+// StausBarValue implements statusbar.StatusBar.
+func (r *Readme) StatusBarValue() string {
+	return ""
+}
+
+// StatusBarInfo implements statusbar.StatusBar.
+func (r *Readme) StatusBarInfo() string {
+	return fmt.Sprintf("☰ %.f%%", r.code.ScrollPercent()*100)
+}

ui/pages/repo/refs.go 🔗

@@ -105,10 +105,12 @@ func (r *Refs) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		r.ref = msg
 		cmds = append(cmds, r.Init())
 	case RefItemsMsg:
-		cmds = append(cmds, r.selector.SetItems(msg.items))
-		i := r.selector.SelectedItem()
-		if i != nil {
-			r.activeRef = i.(RefItem).Reference
+		if r.refPrefix == msg.prefix {
+			cmds = append(cmds, r.selector.SetItems(msg.items))
+			i := r.selector.SelectedItem()
+			if i != nil {
+				r.activeRef = i.(RefItem).Reference
+			}
 		}
 	case selector.ActiveMsg:
 		switch sel := msg.IdentifiableItem.(type) {
@@ -119,11 +121,12 @@ func (r *Refs) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	case selector.SelectMsg:
 		switch i := msg.IdentifiableItem.(type) {
 		case RefItem:
-			cmds = append(cmds,
-				switchRefCmd(i.Reference),
-				tabs.SelectTabCmd(int(filesTab)),
-			)
+			cmds = append(cmds, switchRefCmd(i.Reference))
 		}
+	// FileItemsMsg indicates that the Files model has updated the items and
+	// it's time to switch tabs.
+	case FileItemsMsg:
+		cmds = append(cmds, tabs.SelectTabCmd(int(filesTab)))
 	case tea.KeyMsg:
 		switch msg.String() {
 		case "l", "right":

ui/pages/repo/repo.go 🔗

@@ -9,7 +9,6 @@ import (
 	"github.com/charmbracelet/lipgloss"
 	ggit "github.com/charmbracelet/soft-serve/git"
 	"github.com/charmbracelet/soft-serve/ui/common"
-	"github.com/charmbracelet/soft-serve/ui/components/code"
 	"github.com/charmbracelet/soft-serve/ui/components/statusbar"
 	"github.com/charmbracelet/soft-serve/ui/components/tabs"
 	"github.com/charmbracelet/soft-serve/ui/git"
@@ -53,8 +52,7 @@ func New(s session.Session, c common.Common) *Repo {
 	sb := statusbar.New(c)
 	// Tabs must match the order of tab constants above.
 	tb := tabs.New(c, []string{"Readme", "Files", "Commits", "Branches", "Tags"})
-	readme := code.New(c, "", "")
-	readme.NoContentStyle = readme.NoContentStyle.SetString("No readme found.")
+	readme := NewReadme(c)
 	log := NewLog(c)
 	files := NewFiles(c)
 	branches := NewRefs(c, ggit.RefsHeads)
@@ -108,12 +106,7 @@ func (r *Repo) commonHelp() []key.Binding {
 // ShortHelp implements help.KeyMap.
 func (r *Repo) ShortHelp() []key.Binding {
 	b := r.commonHelp()
-	switch r.activeTab {
-	case readmeTab:
-		b = append(b, r.common.KeyMap.UpDown)
-	default:
-		b = append(b, r.boxes[r.activeTab].(help.KeyMap).ShortHelp()...)
-	}
+	b = append(b, r.boxes[r.activeTab].(help.KeyMap).ShortHelp()...)
 	return b
 }
 
@@ -121,24 +114,7 @@ func (r *Repo) ShortHelp() []key.Binding {
 func (r *Repo) FullHelp() [][]key.Binding {
 	b := make([][]key.Binding, 0)
 	b = append(b, r.commonHelp())
-	switch r.activeTab {
-	case readmeTab:
-		k := r.boxes[readmeTab].(*code.Code).KeyMap
-		b = append(b, [][]key.Binding{
-			{
-				k.PageDown,
-				k.PageUp,
-				k.HalfPageDown,
-				k.HalfPageUp,
-			},
-			{
-				k.Down,
-				k.Up,
-			},
-		}...)
-	default:
-		b = append(b, r.boxes[r.activeTab].(help.KeyMap).FullHelp()...)
-	}
+	b = append(b, r.boxes[r.activeTab].(help.KeyMap).FullHelp()...)
 	return b
 }
 
@@ -157,10 +133,8 @@ func (r *Repo) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	case RepoMsg:
 		r.activeTab = 0
 		r.selectedRepo = git.GitRepo(msg)
-		r.boxes[readmeTab].(*code.Code).GotoTop()
 		cmds = append(cmds,
 			r.tabs.Init(),
-			r.updateReadmeCmd,
 			r.updateRefCmd,
 			r.updateModels(msg),
 		)
@@ -224,11 +198,6 @@ func (r *Repo) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	case UpdateStatusBarMsg:
 		cmds = append(cmds, r.updateStatusBarCmd)
 	case tea.WindowSizeMsg:
-		b, cmd := r.boxes[readmeTab].Update(msg)
-		r.boxes[readmeTab] = b.(*code.Code)
-		if cmd != nil {
-			cmds = append(cmds, cmd)
-		}
 		cmds = append(cmds, r.updateModels(msg))
 	}
 	s, cmd := r.statusbar.Update(msg)
@@ -296,14 +265,8 @@ func (r *Repo) headerView() string {
 }
 
 func (r *Repo) updateStatusBarCmd() tea.Msg {
-	var info, value string
-	switch r.activeTab {
-	case readmeTab:
-		info = fmt.Sprintf("☰ %.f%%", r.boxes[readmeTab].(*code.Code).ScrollPercent()*100)
-	default:
-		value = r.boxes[r.activeTab].(statusbar.Model).StatusBarValue()
-		info = r.boxes[r.activeTab].(statusbar.Model).StatusBarInfo()
-	}
+	value := r.boxes[r.activeTab].(statusbar.Model).StatusBarValue()
+	info := r.boxes[r.activeTab].(statusbar.Model).StatusBarInfo()
 	return statusbar.StatusBarMsg{
 		Key:    r.selectedRepo.Name(),
 		Value:  value,
@@ -312,14 +275,6 @@ func (r *Repo) updateStatusBarCmd() tea.Msg {
 	}
 }
 
-func (r *Repo) updateReadmeCmd() tea.Msg {
-	if r.selectedRepo == nil {
-		return common.ErrorCmd(git.ErrMissingRepo)
-	}
-	rm, rp := r.selectedRepo.Readme()
-	return r.boxes[readmeTab].(*code.Code).SetContent(rm, rp)
-}
-
 func (r *Repo) updateRefCmd() tea.Msg {
 	head, err := r.selectedRepo.HEAD()
 	if err != nil {