1package tui
2
3import (
4 "fmt"
5 "smoothie/git"
6 "smoothie/tui/bubbles/commits"
7 "time"
8
9 tea "github.com/charmbracelet/bubbletea"
10 "github.com/gliderlabs/ssh"
11)
12
13type sessionState int
14
15const (
16 startState sessionState = iota
17 errorState
18 loadedState
19 quittingState
20 quitState
21)
22
23type Model struct {
24 state sessionState
25 error string
26 info string
27 width int
28 height int
29 windowChanges <-chan ssh.Window
30 repoSource *git.RepoSource
31 commitTimeline *commits.Bubble
32}
33
34func NewModel(width int, height int, windowChanges <-chan ssh.Window, repoSource *git.RepoSource) *Model {
35 m := &Model{
36 width: width,
37 height: height,
38 windowChanges: windowChanges,
39 repoSource: repoSource,
40 }
41 m.state = startState
42 return m
43}
44
45func (m *Model) Init() tea.Cmd {
46 return tea.Batch(m.windowChangesCmd, m.loadGitCmd)
47}
48
49func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
50 cmds := make([]tea.Cmd, 0)
51 // Always allow state, error, info, window resize and quit messages
52 switch msg := msg.(type) {
53 case stateMsg:
54 m.state = msg.state
55 case tea.KeyMsg:
56 switch msg.String() {
57 case "q", "ctrl+c":
58 return m, tea.Quit
59 case "j", "k", "up", "down":
60 _, cmd := m.commitTimeline.Update(msg)
61 cmds = append(cmds, cmd)
62 }
63 case errMsg:
64 m.error = msg.Error()
65 m.state = errorState
66 return m, nil
67 case infoMsg:
68 m.info = msg.text
69 case windowMsg:
70 cmds = append(cmds, m.windowChangesCmd)
71 case tea.WindowSizeMsg:
72 m.width = msg.Width
73 m.height = msg.Height
74 m.commitTimeline.Height = msg.Height
75 }
76 return m, tea.Batch(cmds...)
77}
78
79func (m *Model) View() string {
80 pad := 6
81 h := headerStyle.Width(m.width - pad).Render("Charm Beta")
82 f := footerStyle.Render(m.info)
83 s := ""
84 content := ""
85 switch m.state {
86 case loadedState:
87 s += m.commitTimeline.View()
88 case errorState:
89 s += errorStyle.Render(fmt.Sprintf("Bummer: %s", m.error))
90 default:
91 s = normalStyle.Render(fmt.Sprintf("Doing something weird %d", m.state))
92 }
93 content = h + "\n" + s + "\n" + f
94 return appBoxStyle.Render(content)
95}
96
97func SessionHandler(reposPath string) func(ssh.Session) (tea.Model, []tea.ProgramOption) {
98 rs := git.NewRepoSource(reposPath, time.Second*10)
99 return func(s ssh.Session) (tea.Model, []tea.ProgramOption) {
100 if len(s.Command()) == 0 {
101 pty, changes, active := s.Pty()
102 if !active {
103 return nil, nil
104 }
105 return NewModel(pty.Window.Width, pty.Window.Height, changes, rs), []tea.ProgramOption{tea.WithAltScreen()}
106 }
107 return nil, nil
108 }
109}