- Add --thanks flag to bd info command - Make bd thanks a hidden command (deprecated but still works) - Part of CLI consolidation effort (bd-9115) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
276 lines
6.9 KiB
Go
276 lines
6.9 KiB
Go
package main
|
|
|
|
import (
|
|
"cmp"
|
|
"fmt"
|
|
"slices"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
"github.com/spf13/cobra"
|
|
"github.com/steveyegge/beads/internal/ui"
|
|
)
|
|
|
|
// lipgloss styles for the thanks page using Ayu theme
|
|
var (
|
|
thanksTitleStyle = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(ui.ColorWarn)
|
|
|
|
thanksSubtitleStyle = lipgloss.NewStyle().
|
|
Foreground(ui.ColorMuted)
|
|
|
|
thanksSectionStyle = lipgloss.NewStyle().
|
|
Foreground(ui.ColorAccent).
|
|
Bold(true)
|
|
|
|
thanksNameStyle = lipgloss.NewStyle().
|
|
Foreground(ui.ColorPass)
|
|
|
|
thanksLabelStyle = lipgloss.NewStyle().
|
|
Foreground(ui.ColorWarn)
|
|
|
|
thanksDimStyle = lipgloss.NewStyle().
|
|
Foreground(ui.ColorMuted)
|
|
)
|
|
|
|
// thanksBoxStyle returns a box style with dynamic width
|
|
func thanksBoxStyle(width int) lipgloss.Style {
|
|
return lipgloss.NewStyle().
|
|
BorderStyle(lipgloss.DoubleBorder()).
|
|
BorderForeground(ui.ColorMuted).
|
|
Padding(1, 4).
|
|
Width(width - 4).
|
|
Align(lipgloss.Center)
|
|
}
|
|
|
|
// Static list of human contributors to the beads project.
|
|
// To update: run `git shortlog -sn --all` in the beads repo.
|
|
// Map of contributor name -> commit count, sorted by contribution count descending.
|
|
var beadsContributors = map[string]int{
|
|
"Steve Yegge": 2959,
|
|
"matt wilkie": 64,
|
|
"Ryan Snodgrass": 43,
|
|
"Travis Cline": 9,
|
|
"David Laing": 7,
|
|
"Ryan Newton": 6,
|
|
"Joshua Shanks": 6,
|
|
"Daan van Etten": 5,
|
|
"Augustinas Malinauskas": 4,
|
|
"Matteo Landi": 4,
|
|
"Baishampayan Ghose": 4,
|
|
"Charles P. Cross": 4,
|
|
"Abhinav Gupta": 3,
|
|
"Brian Williams": 3,
|
|
"Marco Del Pin": 3,
|
|
"Willi Ballenthin": 3,
|
|
"Ben Lovell": 2,
|
|
"Ben Madore": 2,
|
|
"Dane Bertram": 2,
|
|
"Dennis Schön": 2,
|
|
"Troy Gaines": 2,
|
|
"Zoe Gagnon": 2,
|
|
"Peter Schilling": 2,
|
|
"Adam Spiers": 1,
|
|
"Aodhan Hayter": 1,
|
|
"Assim Elhammouti": 1,
|
|
"Bryce Roche": 1,
|
|
"Caleb Leak": 1,
|
|
"David Birks": 1,
|
|
"Dean Giberson": 1,
|
|
"Eli": 1,
|
|
"Graeme Foster": 1,
|
|
"Gurdas Nijor": 1,
|
|
"Jimmy Stridh": 1,
|
|
"Joel Klabo": 1,
|
|
"Johannes Zillmann": 1,
|
|
"John Lam": 1,
|
|
"Jonathan Berger": 1,
|
|
"Joshua Park": 1,
|
|
"Juan Vargas": 1,
|
|
"Kasper Zutterman": 1,
|
|
"Kris Hansen": 1,
|
|
"Logan Thomas": 1,
|
|
"Lon Lundgren": 1,
|
|
"Mark Wotton": 1,
|
|
"Markus Flür": 1,
|
|
"Michael Shuffett": 1,
|
|
"Midworld Kim": 1,
|
|
"Nikolai Prokoschenko": 1,
|
|
"Peter Loron": 1,
|
|
"Rod Davenport": 1,
|
|
"Serhii": 1,
|
|
"Shaun Cutts": 1,
|
|
"Sophie Smithburg": 1,
|
|
"Tim Haasdyk": 1,
|
|
"Travis Lyons": 1,
|
|
"Yaakov Nemoy": 1,
|
|
"Yunsik Kim": 1,
|
|
"Zachary Rosen": 1,
|
|
}
|
|
|
|
var thanksCmd = &cobra.Command{
|
|
Use: "thanks",
|
|
Short: "Thank the human contributors to beads",
|
|
Hidden: true, // Deprecated: use 'bd info --thanks' instead
|
|
Long: `Display a thank you page listing all human contributors to the beads project.
|
|
|
|
DEPRECATED: Use 'bd info --thanks' instead.
|
|
|
|
Examples:
|
|
bd info --thanks # Show thank you page (preferred)
|
|
bd thanks # Legacy command (still works)
|
|
`,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
printThanksPage()
|
|
},
|
|
}
|
|
|
|
// getContributorsSorted returns contributors sorted by commit count descending
|
|
func getContributorsSorted() []string {
|
|
type kv struct {
|
|
name string
|
|
commits int
|
|
}
|
|
var sorted []kv
|
|
for name, commits := range beadsContributors {
|
|
sorted = append(sorted, kv{name, commits})
|
|
}
|
|
slices.SortFunc(sorted, func(a, b kv) int {
|
|
return cmp.Compare(b.commits, a.commits) // descending order
|
|
})
|
|
names := make([]string, len(sorted))
|
|
for i, kv := range sorted {
|
|
names[i] = kv.name
|
|
}
|
|
return names
|
|
}
|
|
|
|
// printThanksPage displays the thank you page
|
|
func printThanksPage() {
|
|
fmt.Println()
|
|
|
|
// get sorted contributors and split into top 20 and rest
|
|
allContributors := getContributorsSorted()
|
|
topN := 20
|
|
if topN > len(allContributors) {
|
|
topN = len(allContributors)
|
|
}
|
|
|
|
topContributors := allContributors[:topN]
|
|
additionalContributors := allContributors[topN:]
|
|
|
|
// calculate content width based on featured contributors columns
|
|
contentWidth := calculateColumnsWidth(topContributors, 4) + 4 // +4 for indent
|
|
|
|
// build header content with styled text
|
|
title := thanksTitleStyle.Render("THANK YOU!")
|
|
subtitle := thanksSubtitleStyle.Render("To all the humans who contributed to beads")
|
|
header := title + "\n\n" + subtitle
|
|
|
|
// render header in a bordered box matching content width
|
|
fmt.Println(thanksBoxStyle(contentWidth).Render(header))
|
|
fmt.Println()
|
|
|
|
// print featured contributors section
|
|
fmt.Println(thanksSectionStyle.Render(" Featured Contributors"))
|
|
fmt.Println()
|
|
printThanksColumns(topContributors, 4)
|
|
|
|
// print additional contributors with line wrapping
|
|
if len(additionalContributors) > 0 {
|
|
fmt.Println()
|
|
fmt.Println(thanksSectionStyle.Render(" Additional Contributors"))
|
|
fmt.Println()
|
|
printThanksWrappedList("", additionalContributors, contentWidth)
|
|
}
|
|
fmt.Println()
|
|
}
|
|
|
|
// calculateColumnsWidth returns the total width needed for displaying names in columns
|
|
func calculateColumnsWidth(names []string, cols int) int {
|
|
if len(names) == 0 {
|
|
return 0
|
|
}
|
|
|
|
maxWidth := 0
|
|
for _, name := range names {
|
|
if len(name) > maxWidth {
|
|
maxWidth = len(name)
|
|
}
|
|
}
|
|
if maxWidth > 20 {
|
|
maxWidth = 20
|
|
}
|
|
colWidth := maxWidth + 2
|
|
|
|
return colWidth * cols
|
|
}
|
|
|
|
// printThanksColumns prints names in n columns, sorted horizontally by input order
|
|
func printThanksColumns(names []string, cols int) {
|
|
if len(names) == 0 {
|
|
return
|
|
}
|
|
|
|
// find max width for alignment
|
|
maxWidth := 0
|
|
for _, name := range names {
|
|
if len(name) > maxWidth {
|
|
maxWidth = len(name)
|
|
}
|
|
}
|
|
if maxWidth > 20 {
|
|
maxWidth = 20
|
|
}
|
|
colWidth := maxWidth + 2
|
|
|
|
// print in rows, reading left to right
|
|
for i := 0; i < len(names); i += cols {
|
|
fmt.Print(" ")
|
|
for j := 0; j < cols && i+j < len(names); j++ {
|
|
name := names[i+j]
|
|
if len(name) > 20 {
|
|
name = name[:17] + "..."
|
|
}
|
|
padded := fmt.Sprintf("%-*s", colWidth, name)
|
|
fmt.Print(thanksNameStyle.Render(padded))
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|
|
|
|
// printThanksWrappedList prints a list with word wrapping at name boundaries
|
|
func printThanksWrappedList(label string, names []string, maxWidth int) {
|
|
indent := " "
|
|
|
|
fmt.Print(indent)
|
|
lineLen := len(indent)
|
|
|
|
if label != "" {
|
|
fmt.Print(thanksLabelStyle.Render(label) + " ")
|
|
lineLen += len(label) + 1
|
|
}
|
|
|
|
for i, name := range names {
|
|
suffix := ", "
|
|
if i == len(names)-1 {
|
|
suffix = ""
|
|
}
|
|
entry := name + suffix
|
|
|
|
if lineLen+len(entry) > maxWidth && lineLen > len(indent) {
|
|
fmt.Println()
|
|
fmt.Print(indent)
|
|
lineLen = len(indent)
|
|
}
|
|
|
|
fmt.Print(thanksDimStyle.Render(entry))
|
|
lineLen += len(entry)
|
|
}
|
|
fmt.Println()
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(thanksCmd)
|
|
}
|