Detailed changes
@@ -88,16 +88,7 @@ func (r *Code) Init() tea.Cmd {
if err != nil {
return common.ErrorCmd(err)
}
- if r.showLineNumber {
- f = withLineNumber(f)
- }
- // FIXME: this is a hack to reset formatting at the end of every line.
- c = wrap.String(f, w)
- s := strings.Split(c, "\n")
- for i, l := range s {
- s[i] = l + "\x1b[0m"
- }
- r.Viewport.Model.SetContent(strings.Join(s, "\n"))
+ r.Viewport.Model.SetContent(f)
return nil
}
@@ -170,9 +161,6 @@ func (r *Code) ScrollPercent() float64 {
func (r *Code) glamourize(w int, md string) (string, error) {
r.renderMutex.Lock()
defer r.renderMutex.Unlock()
- if w > 120 {
- w = 120
- }
tr, err := glamour.NewTermRenderer(
glamour.WithStyles(r.styleConfig),
glamour.WithWordWrap(w),
@@ -215,7 +203,17 @@ func (r *Code) renderFile(path, content string, width int) (string, error) {
if err != nil {
return "", err
}
- return s.String(), nil
+ c := s.String()
+ if r.showLineNumber {
+ c = withLineNumber(c)
+ }
+ // FIXME: this is a hack to reset formatting at the end of every line.
+ c = wrap.String(c, width)
+ f := strings.Split(c, "\n")
+ for i, l := range f {
+ f[i] = l + "\x1b[0m"
+ }
+ return strings.Join(f, "\n"), nil
}
func withLineNumber(s string) string {
@@ -5,6 +5,7 @@ import (
"fmt"
"path/filepath"
+ "github.com/alecthomas/chroma/lexers"
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
ggit "github.com/charmbracelet/soft-serve/git"
@@ -107,12 +108,20 @@ func (f *Files) ShortHelp() []key.Binding {
case filesViewContent:
copyKey := f.common.KeyMap.Copy
copyKey.SetHelp("c", "copy content")
- return []key.Binding{
+ b := []key.Binding{
f.common.KeyMap.UpDown,
f.common.KeyMap.BackItem,
copyKey,
- lineNo,
}
+ lexer := lexers.Match(f.currentContent.ext)
+ lang := ""
+ if lexer != nil && lexer.Config() != nil {
+ lang = lexer.Config().Name
+ }
+ if lang != "markdown" {
+ b = append(b, lineNo)
+ }
+ return b
default:
return []key.Binding{}
}
@@ -157,13 +166,21 @@ func (f *Files) FullHelp() [][]key.Binding {
k.HalfPageDown,
k.HalfPageUp,
},
- {
- k.Down,
- k.Up,
- copyKey,
- lineNo,
- },
}...)
+ lc := []key.Binding{
+ k.Down,
+ k.Up,
+ copyKey,
+ }
+ lexer := lexers.Match(f.currentContent.ext)
+ lang := ""
+ if lexer != nil && lexer.Config() != nil {
+ lang = lexer.Config().Name
+ }
+ if lang != "markdown" {
+ lc = append(lc, lineNo)
+ }
+ b = append(b, lc)
}
return b
}
@@ -88,6 +88,7 @@ func (l *Log) ShortHelp() []key.Binding {
copyKey := l.common.KeyMap.Copy
copyKey.SetHelp("c", "copy hash")
return []key.Binding{
+ l.common.KeyMap.UpDown,
l.common.KeyMap.SelectItem,
copyKey,
}
@@ -61,7 +61,7 @@ func (d ItemDelegate) Height() int {
}
// Spacing returns the spacing between items. Implements list.ItemDelegate.
-func (d ItemDelegate) Spacing() int { return 0 }
+func (d ItemDelegate) Spacing() int { return 1 }
// Update implements list.ItemDelegate.
func (d ItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
@@ -97,10 +97,13 @@ func (d ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list
itemStyle := styles.MenuItem.Copy()
if isSelected {
- itemStyle = itemStyle.BorderForeground(styles.ActiveBorderColor)
+ itemStyle = itemStyle.Copy().
+ BorderStyle(lipgloss.Border{
+ Left: "┃",
+ }).
+ BorderForeground(styles.ActiveBorderColor)
if d.activeBox != nil && *d.activeBox == readmeBox {
- // TODO make this into its own color
- itemStyle = itemStyle.BorderForeground(lipgloss.Color("15"))
+ itemStyle = itemStyle.BorderForeground(styles.InactiveBorderColor)
}
}
@@ -108,14 +111,17 @@ func (d ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list
if i.repo.IsPrivate() {
title += " 🔒"
}
+ if isSelected {
+ title += " "
+ }
updatedStr := fmt.Sprintf(" Updated %s", humanize.Time(i.lastUpdate))
- updated := styles.MenuLastUpdate.
- Copy().
- Width(m.Width() - itemStyle.GetHorizontalFrameSize() - lipgloss.Width(title)).
- Render(updatedStr)
- titleStyle := lipgloss.NewStyle().
- Align(lipgloss.Left).
- Width(m.Width() - itemStyle.GetHorizontalFrameSize() - lipgloss.Width(updated))
+ updatedStyle := styles.MenuLastUpdate.Copy().
+ Align(lipgloss.Right).
+ Width(m.Width() - itemStyle.GetHorizontalFrameSize() - lipgloss.Width(title))
+ if isSelected {
+ updatedStyle = updatedStyle.Bold(true)
+ }
+ updated := updatedStyle.Render(updatedStr)
if isFiltered && index < len(m.VisibleItems()) {
// Get indices of matched characters
@@ -125,19 +131,30 @@ func (d ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list
if isFiltered {
unmatched := lipgloss.NewStyle().Inline(true)
matched := unmatched.Copy().Underline(true)
+ if isSelected {
+ unmatched = unmatched.Bold(true)
+ matched = matched.Bold(true)
+ }
title = lipgloss.StyleRunes(title, matchedRunes, matched, unmatched)
}
+ titleStyle := lipgloss.NewStyle()
+ if isSelected {
+ titleStyle = titleStyle.Bold(true)
+ }
title = titleStyle.Render(title)
+ desc := lipgloss.NewStyle().
+ Faint(true).
+ Render(i.Description())
s.WriteString(lipgloss.JoinHorizontal(lipgloss.Bottom, title, updated))
s.WriteString("\n")
- s.WriteString(i.Description())
- s.WriteString("\n\n")
+ s.WriteString(desc)
+ s.WriteString("\n")
cmdStyle := styles.RepoCommand.Copy()
cmd := cmdStyle.Render(i.Command())
if !i.copied.IsZero() && i.copied.Add(time.Second).After(time.Now()) {
cmd = cmdStyle.Render("Copied!")
}
s.WriteString(cmd)
- w.Write([]byte(itemStyle.Render(s.String())))
+ fmt.Fprint(w, itemStyle.Render(s.String()))
}
@@ -1,6 +1,8 @@
package selection
import (
+ "strings"
+
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
@@ -21,11 +23,12 @@ const (
// Selection is the model for the selection screen/page.
type Selection struct {
- s session.Session
- common common.Common
- readme *code.Code
- selector *selector.Selector
- activeBox box
+ s session.Session
+ common common.Common
+ readme *code.Code
+ readmeHeight int
+ selector *selector.Selector
+ activeBox box
}
// New creates a new selection model.
@@ -49,20 +52,31 @@ func New(s session.Session, common common.Common) *Selection {
return sel
}
+func (s *Selection) getReadmeHeight() int {
+ rh := s.readmeHeight
+ if rh > s.common.Height/3 {
+ rh = s.common.Height / 3
+ }
+ return rh
+}
+
+func (s *Selection) getMargins() (wm, hm int) {
+ wm = 0
+ hm = s.common.Styles.SelectorBox.GetVerticalFrameSize() +
+ s.common.Styles.SelectorBox.GetHeight()
+ if rh := s.getReadmeHeight(); rh > 0 {
+ hm += s.common.Styles.ReadmeBox.GetVerticalFrameSize() +
+ rh
+ }
+ return
+}
+
// SetSize implements common.Component.
func (s *Selection) SetSize(width, height int) {
s.common.SetSize(width, height)
- sw := s.common.Styles.SelectorBox.GetWidth()
- wm := sw +
- s.common.Styles.SelectorBox.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)
+ wm, hm := s.getMargins()
+ s.readme.SetSize(width-wm, s.getReadmeHeight())
+ s.selector.SetSize(width-wm, height-hm)
}
// ShortHelp implements help.KeyMap.
@@ -135,6 +149,7 @@ func (s *Selection) FullHelp() [][]key.Binding {
// Init implements tea.Model.
func (s *Selection) Init() tea.Cmd {
+ var readmeCmd tea.Cmd
items := make([]selector.IdentifiableItem, 0)
cfg := s.s.Config()
pk := s.s.PublicKey()
@@ -153,6 +168,11 @@ func (s *Selection) Init() tea.Cmd {
})
}
for _, r := range cfg.Source.AllRepos() {
+ if r.Repo() == "config" {
+ rm, rp := r.Readme()
+ s.readmeHeight = strings.Count(rm, "\n")
+ readmeCmd = s.readme.SetContent(rm, rp)
+ }
if r.IsPrivate() && cfg.AuthRepo(r.Repo(), pk) < wgit.AdminAccess {
continue
}
@@ -189,6 +209,7 @@ func (s *Selection) Init() tea.Cmd {
return tea.Batch(
s.selector.Init(),
s.selector.SetItems(items),
+ readmeCmd,
)
}
@@ -207,10 +228,6 @@ func (s *Selection) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if cmd != nil {
cmds = append(cmds, cmd)
}
- case selector.ActiveMsg:
- cmds = append(cmds, s.changeActive(msg))
- // reset readme position when active item change
- s.readme.GotoTop()
case tea.KeyMsg:
switch {
case key.Matches(msg, s.common.KeyMap.Section):
@@ -238,30 +255,20 @@ func (s *Selection) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// View implements tea.Model.
func (s *Selection) View() string {
- wm := s.common.Styles.SelectorBox.GetWidth() +
- s.common.Styles.SelectorBox.GetHorizontalFrameSize() +
- s.common.Styles.ReadmeBox.GetHorizontalFrameSize()
- hm := s.common.Styles.ReadmeBox.GetVerticalFrameSize()
+ rh := s.getReadmeHeight()
rs := s.common.Styles.ReadmeBox.Copy().
- Width(s.common.Width - wm).
- Height(s.common.Height - hm)
+ Width(s.common.Width).
+ Height(rh)
if s.activeBox == readmeBox {
rs.BorderForeground(s.common.Styles.ActiveBorderColor)
}
- readme := rs.Render(s.readme.View())
- return lipgloss.JoinHorizontal(
- lipgloss.Top,
- readme,
- s.selector.View(),
- )
-}
-
-func (s *Selection) changeActive(msg selector.ActiveMsg) tea.Cmd {
- item, ok := msg.IdentifiableItem.(Item)
- if !ok {
- return nil
+ view := s.selector.View()
+ if rh > 0 {
+ readme := rs.Render(s.readme.View())
+ view = lipgloss.JoinVertical(lipgloss.Top,
+ readme,
+ view,
+ )
}
- r := item.repo
- rm, rp := r.Readme()
- return s.readme.SetContent(rm, rp)
+ return view
}
@@ -126,10 +126,11 @@ func DefaultStyles() *Styles {
SetString(">")
s.MenuItem = lipgloss.NewStyle().
- Padding(1, 2).
- Height(4).
- Border(lipgloss.RoundedBorder()).
- BorderForeground(lipgloss.Color("241"))
+ PaddingLeft(1).
+ Border(lipgloss.Border{
+ Left: " ",
+ }, false, false, false, true).
+ Height(3)
s.MenuLastUpdate = lipgloss.NewStyle().
Foreground(lipgloss.Color("241")).
@@ -253,7 +254,7 @@ func DefaultStyles() *Styles {
s.LogItemActive = s.LogItemInactive.Copy().
Border(lipgloss.Border{
- Left: "│",
+ Left: "┃",
}, false, false, false, true).
BorderForeground(lipgloss.Color("#B083EA"))