From 74708f54338b01986df39eb78f987550a21bf8b0 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 15 Apr 2022 00:09:14 -0400 Subject: [PATCH] wip: fix readme wrap --- go.mod | 2 +- go.sum | 2 ++ ui/components/code/code.go | 1 + ui/components/selector/selector.go | 49 +++++++++++++++++++++++++----- ui/components/yankable/yankable.go | 22 ++------------ ui/pages/selection/selection.go | 31 ++++++++++++++++--- ui/styles/styles.go | 4 +-- 7 files changed, 76 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index cdb1e1659d728c33e3f85d0cea217234400d8a89..bf64cb6a7fa106c494a8c63d8f790945b58268c2 100755 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( ) require ( - github.com/aymanbagabas/go-osc52 v1.0.0 + github.com/aymanbagabas/go-osc52 v1.0.1 github.com/charmbracelet/keygen v0.3.0 github.com/gobwas/glob v0.2.3 github.com/gogs/git-module v1.6.0 diff --git a/go.sum b/go.sum index 805fc0b23db5c6a947ce3a6a6098b6801a27c3fe..54cbe32c6164f809f0bd7433dae17ed4a3f3a8d9 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52 v1.0.0 h1:yjRSILSEUSIhuRcyOJ55tbSKtvBLmJDgbPErH8pXcxM= github.com/aymanbagabas/go-osc52 v1.0.0/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= +github.com/aymanbagabas/go-osc52 v1.0.1 h1:juDXgeKhMfVnylcoA4S7p9E4q+9DErUZGkX8t2ZR2j8= +github.com/aymanbagabas/go-osc52 v1.0.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k= diff --git a/ui/components/code/code.go b/ui/components/code/code.go index f0a800a60cc9481d5cd5acf0751474e95c8c295f..c45d1140f3e6a2ec8237061a7385c77ee022c03c 100644 --- a/ui/components/code/code.go +++ b/ui/components/code/code.go @@ -70,6 +70,7 @@ func (r *Code) Init() tea.Cmd { if err != nil { return common.ErrorCmd(err) } + // FIXME reset underline and color c = wrap.String(f, w) r.viewport.Viewport.SetContent(c) return nil diff --git a/ui/components/selector/selector.go b/ui/components/selector/selector.go index 9274f58acb225a9f407cf947a94e1cec14f196a8..6444f5ffb87bc6fbbeccffcea41deb9f090a98d6 100644 --- a/ui/components/selector/selector.go +++ b/ui/components/selector/selector.go @@ -9,9 +9,10 @@ import ( // Selector is a list of items that can be selected. type Selector struct { - list list.Model - common common.Common - active int + list list.Model + common common.Common + active int + filterState list.FilterState } // IdentifiableItem is an item that can be identified by a string and extends list.Item. @@ -27,8 +28,12 @@ type SelectMsg string type ActiveMsg string // New creates a new selector. -func New(common common.Common, items []list.Item, delegate list.ItemDelegate) *Selector { - l := list.New(items, delegate, common.Width, common.Height) +func New(common common.Common, items []IdentifiableItem, delegate list.ItemDelegate) *Selector { + itms := make([]list.Item, len(items)) + for i, item := range items { + itms[i] = item + } + l := list.New(itms, delegate, common.Width, common.Height) l.SetShowTitle(false) l.SetShowHelp(false) l.SetShowStatusBar(false) @@ -76,12 +81,20 @@ func (s *Selector) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case key.Matches(msg, s.common.Keymap.Select): cmds = append(cmds, s.selectCmd) } + case list.FilterMatchesMsg: + cmds = append(cmds, s.activeFilterCmd) } m, cmd := s.list.Update(msg) s.list = m if cmd != nil { cmds = append(cmds, cmd) } + // Track filter state and update active item when filter state changes. + filterState := s.list.FilterState() + if s.filterState != filterState { + cmds = append(cmds, s.activeFilterCmd) + } + s.filterState = filterState // Send ActiveMsg when index change. if s.active != s.list.Index() { cmds = append(cmds, s.activeCmd) @@ -97,12 +110,34 @@ func (s *Selector) View() string { func (s *Selector) selectCmd() tea.Msg { item := s.list.SelectedItem() - i := item.(IdentifiableItem) + i, ok := item.(IdentifiableItem) + if !ok { + return SelectMsg("") + } return SelectMsg(i.ID()) } func (s *Selector) activeCmd() tea.Msg { item := s.list.SelectedItem() - i := item.(IdentifiableItem) + i, ok := item.(IdentifiableItem) + if !ok { + return ActiveMsg("") + } + return ActiveMsg(i.ID()) +} + +func (s *Selector) activeFilterCmd() tea.Msg { + // Here we use VisibleItems because when list.FilterMatchesMsg is sent, + // VisibleItems is the only way to get the list of filtered items. The list + // bubble should export something like list.FilterMatchesMsg.Items(). + items := s.list.VisibleItems() + if len(items) == 0 { + return nil + } + item := items[0] + i, ok := item.(IdentifiableItem) + if !ok { + return nil + } return ActiveMsg(i.ID()) } diff --git a/ui/components/yankable/yankable.go b/ui/components/yankable/yankable.go index acdf915d7a064aae44d008d8c71e2f0734c7958a..5539ca2355f609507537accab80c758bc3ca86d0 100644 --- a/ui/components/yankable/yankable.go +++ b/ui/components/yankable/yankable.go @@ -1,14 +1,11 @@ package yankable import ( - "fmt" - "log" - "strings" + "io" "github.com/aymanbagabas/go-osc52" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" - "github.com/gliderlabs/ssh" ) type Yankable struct { @@ -19,26 +16,13 @@ type Yankable struct { osc52 *osc52.Output } -func New(s ssh.Session, style, yankStyle lipgloss.Style, text string) *Yankable { - environ := s.Environ() - termExists := false - for _, env := range environ { - if strings.HasPrefix(env, "TERM=") { - termExists = true - break - } - } - if !termExists { - pty, _, _ := s.Pty() - environ = append(environ, fmt.Sprintf("TERM=%s", pty.Term)) - } - log.Print(environ) +func New(w io.Writer, environ []string, style, yankStyle lipgloss.Style, text string) *Yankable { return &Yankable{ yankStyle: yankStyle, style: style, text: text, clicked: false, - osc52: osc52.NewOutput(s, environ), + osc52: osc52.NewOutput(w, environ), } } diff --git a/ui/pages/selection/selection.go b/ui/pages/selection/selection.go index 8c1b3864379ebe236dfdd36ef4f047b63374f715..5020047b66100ebb0bfc584a73c9bca0ce864f87 100644 --- a/ui/pages/selection/selection.go +++ b/ui/pages/selection/selection.go @@ -2,6 +2,7 @@ package selection import ( "fmt" + "strings" "time" "github.com/charmbracelet/bubbles/key" @@ -37,12 +38,14 @@ func New(s session.Session, common common.Common) *Selection { sel := &Selection{ s: s, common: common, - activeBox: 1, + activeBox: selectorBox, // start with the selector focused } readme := code.New(common, "", "") readme.NoContentStyle = readme.NoContentStyle.SetString("No readme found.") sel.readme = readme - sel.selector = selector.New(common, []list.Item{}, ItemDelegate{common.Styles, &sel.activeBox}) + sel.selector = selector.New(common, + []selector.IdentifiableItem{}, + ItemDelegate{common.Styles, &sel.activeBox}) return sel } @@ -52,7 +55,11 @@ func (s *Selection) SetSize(width, height int) { sw := s.common.Styles.SelectorBox.GetWidth() wm := sw + s.common.Styles.SelectorBox.GetHorizontalFrameSize() + - s.common.Styles.ReadmeBox.GetHorizontalFrameSize() + s.common.Styles.ReadmeBox.GetHorizontalFrameSize() + + // +1 to get wrapping to work. + // This is needed because the readme box width has to be -1 from the + // readme style in order for wrapping to not break. + 1 hm := s.common.Styles.ReadmeBox.GetVerticalFrameSize() s.readme.SetSize(width-wm, height-hm) s.selector.SetSize(sw, height) @@ -104,12 +111,26 @@ func (s *Selection) FullHelp() [][]key.Binding { // Init implements tea.Model. func (s *Selection) Init() tea.Cmd { + session := s.s.Session() + environ := session.Environ() + termExists := false + for _, env := range environ { + if strings.HasPrefix(env, "TERM=") { + termExists = true + break + } + } + if !termExists { + pty, _, _ := session.Pty() + environ = append(environ, fmt.Sprintf("TERM=%s", pty.Term)) + } items := make([]list.Item, 0) cfg := s.s.Config() // TODO clean up this yank := func(text string) *yankable.Yankable { return yankable.New( - s.s.Session(), + session, + environ, lipgloss.NewStyle().Foreground(lipgloss.Color("168")), lipgloss.NewStyle().Foreground(lipgloss.Color("168")).SetString("Copied!"), text, @@ -122,7 +143,7 @@ func (s *Selection) Init() tea.Cmd { Name: r.Repo, Description: r.Note, LastUpdate: time.Now(), - URL: yank(repoUrl(cfg, r.Name)), + URL: yank(repoUrl(cfg, r.Repo)), }) } for _, r := range cfg.Source.AllRepos() { diff --git a/ui/styles/styles.go b/ui/styles/styles.go index 89fed7d14ec22157e7a973691cb67a8823d12d43..795ce4994ed27e7e8a384d720ad05f6c6f2334c1 100644 --- a/ui/styles/styles.go +++ b/ui/styles/styles.go @@ -122,9 +122,7 @@ func DefaultStyles() *Styles { Width(64) s.ReadmeBox = lipgloss.NewStyle(). - BorderForeground(s.InactiveBorderColor). - Padding(1). - MarginRight(1) + Margin(1, 1, 1, 0) s.RepoTitleBorder = lipgloss.Border{ Top: "─",