diff --git a/feed.go b/feed.go index 653d320..2145498 100644 --- a/feed.go +++ b/feed.go @@ -4,8 +4,13 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "code.gitea.io/sdk/gitea" + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" ) // Activity stores an entry in a gitea user's activity feed. @@ -84,4 +89,155 @@ func getActivityFeed() []Activity { return feed } +type listKeyMap struct { + toggleSpinner key.Binding + toggleTitleBar key.Binding + toggleStatusBar key.Binding + togglePagination key.Binding + toggleHelpMenu key.Binding +} +func newListKeyMap() *listKeyMap { + return &listKeyMap{ + toggleSpinner: key.NewBinding( + key.WithKeys("s"), + key.WithHelp("s", "toggle spinner"), + ), + toggleTitleBar: key.NewBinding( + key.WithKeys("T"), + key.WithHelp("T", "toggle title"), + ), + toggleStatusBar: key.NewBinding( + key.WithKeys("S"), + key.WithHelp("S", "toggle status"), + ), + togglePagination: key.NewBinding( + key.WithKeys("P"), + key.WithHelp("P", "toggle pagination"), + ), + toggleHelpMenu: key.NewBinding( + key.WithKeys("H"), + key.WithHelp("H", "toggle help"), + ), + } +} + +type feedviewer struct { + list list.Model + feed []Activity + appStyle lipgloss.Style + keys listKeyMap +} + +func (m feedviewer) Init() tea.Cmd { + m.appStyle = lipgloss.NewStyle().Padding(1, 2) + return nil +} + +func (m feedviewer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + h, v := m.appStyle.GetFrameSize() + m.list.SetSize(msg.Width-h, msg.Height-v) + case tea.KeyMsg: + if m.list.FilterState() == list.Filtering { + break + } + switch { + case key.Matches(msg, m.keys.toggleSpinner): + return m, m.list.ToggleSpinner() + case key.Matches(msg, m.keys.toggleTitleBar): + v := !m.list.ShowTitle() + m.list.SetShowTitle(v) + m.list.SetShowFilter(v) + m.list.SetFilteringEnabled(v) + return m, nil + case key.Matches(msg, m.keys.toggleStatusBar): + m.list.SetShowStatusBar(!m.list.ShowStatusBar()) + return m, nil + case key.Matches(msg, m.keys.togglePagination): + m.list.SetShowPagination(!m.list.ShowPagination()) + return m, nil + case key.Matches(msg, m.keys.toggleHelpMenu): + m.list.SetShowHelp(!m.list.ShowHelp()) + return m, nil + default: + switch msg.String() { + case "ctrl+c": + return m, tea.Quit + } + } + } + newListModel, cmd := m.list.Update(msg) + m.list = newListModel + return m, tea.Batch(cmd) +} + +func (m feedviewer) View() string { + return m.appStyle.Render(m.list.View()) +} + +type item struct { + Activity +} + +func (i item) Title() string { + switch i.Activity.op_type { + case "create_issue": + return fmt.Sprintf("%s created an issue", i.act_user.UserName) + case "commit_repo": + var data map[string]interface{} + if err := json.NewDecoder(strings.NewReader(i.content)).Decode(&data); err != nil { + return "JSON decode error: "+fmt.Sprint(err) + } + commits := data["Commits"].([]interface{}) + commits_text := fmt.Sprintf("%d commit", len(commits)) + if len(commits) > 1 { + commits_text += "s" + } + return fmt.Sprintf("%s pushed %s to %s", i.act_user.UserName, commits_text, i.ref_name) + case "comment_issue": + split := strings.Split(i.content, "|") + issue_num := split[0] + // comment := strings.TrimPrefix(i.content, issue_num+"|") + return fmt.Sprintf("%s commented on #%s", i.act_user.UserName, issue_num) + default: + return fmt.Sprintf("%s performed an unknown action. (%s)", i.act_user.UserName, i.op_type) + } +} +func (i item) Description() string { + switch i.op_type { + case "commit_repo": + var data map[string]interface{} + if err := json.NewDecoder(strings.NewReader(i.content)).Decode(&data); err != nil { + return "JSON decode error: "+fmt.Sprint(err) + } + s := "" + commits := data["Commits"].([]interface{}) + commit := commits[0].(map[string]interface{}) + s += styles.text.Render(fmt.Sprintf("[%s] ", commit["Sha1"].(string)[0:10])) + + commit["Message"].(string) + return s + default: return "" + } + +} +func (i item) FilterValue() string { return "" } + +func feed() { + feed := getActivityFeed() + items := []list.Item{} + + for _, activity := range feed { + items = append(items, item{ + activity, + }) + } + + p := feedviewer{} + p.list = list.New(items, list.NewDefaultDelegate(), 0, 0) + // Setup list + if _, err := tea.NewProgram(p, tea.WithAltScreen()).Run(); err != nil { + panic(err) + } +} diff --git a/go.mod b/go.mod index 37f8bc0..678d6d0 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,18 @@ module code.retroedge.tech/noah/gitivity go 1.19 require ( - code.gitea.io/sdk/gitea v0.17.1 // indirect - github.com/akamensky/argparse v1.4.0 // indirect + code.gitea.io/sdk/gitea v0.17.1 + github.com/akamensky/argparse v1.4.0 + github.com/charmbracelet/bubbles v0.18.0 + github.com/charmbracelet/bubbletea v0.25.0 + github.com/charmbracelet/lipgloss v0.9.1 + github.com/yuin/gopher-lua v1.1.1 +) + +require ( + github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/bubbles v0.18.0 // indirect - github.com/charmbracelet/bubbletea v0.25.0 // indirect github.com/charmbracelet/harmonica v0.2.0 // indirect - github.com/charmbracelet/lipgloss v0.9.1 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect github.com/go-fed/httpsig v1.1.0 // indirect @@ -23,7 +28,7 @@ require ( github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/rivo/uniseg v0.4.6 // indirect - github.com/yuin/gopher-lua v1.1.1 // indirect + github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.15.0 // indirect diff --git a/go.sum b/go.sum index 3fbdd82..778902e 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ code.gitea.io/sdk/gitea v0.17.1 h1:3jCPOG2ojbl8AcfaUCRYLT5MUcBMFwS0OSK2mA5Zok8= code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2miadoTNM= github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc= github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= @@ -49,6 +51,8 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg= github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wrYjDSCcZ78NoftLQyHBSLW/Cx79Y= +github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/main.go b/main.go index 83c6400..9efa664 100644 --- a/main.go +++ b/main.go @@ -56,6 +56,6 @@ func main() { } else if Summary.Happened() { summary() } else if Feed.Happened() { - //feed() + feed() } }