Git: components 301-320
This commit is contained in:
121 files changed
+7031
-2
No files matched your search
+120
@@ -0,0 +1,120 @@
|
||||
package mujica
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"mujicaui/icons"
|
||||
"mujicaui/theme"
|
||||
)
|
||||
|
||||
// Branch is a local or remote branch.
|
||||
type Branch struct {
|
||||
// Name is unique; remote names carry the remote, as origin/main.
|
||||
Name string
|
||||
Remote bool
|
||||
// Current marks the checked-out branch.
|
||||
Current bool
|
||||
// Upstream is the tracked remote branch, if any.
|
||||
Upstream string
|
||||
Ahead, Behind int
|
||||
}
|
||||
|
||||
// GitAction is a row action of a version-control list.
|
||||
type GitAction struct {
|
||||
ID string
|
||||
Label string
|
||||
// Icon names an icon from icons/.
|
||||
Icon string
|
||||
}
|
||||
|
||||
// BranchListOptions configure a BranchList.
|
||||
type BranchListOptions struct {
|
||||
// Actions show on every row; Action returns their IDs.
|
||||
Actions []GitAction
|
||||
Status DataStatus
|
||||
Error string
|
||||
}
|
||||
|
||||
// BranchList shows branches with upstream and ahead/behind counts.
|
||||
func BranchList(c *ui.Context, s *ListState[string], branches []Branch, opts BranchListOptions) GitListResult {
|
||||
gitActionsCheck(opts.Actions)
|
||||
var r GitListResult
|
||||
v := List(c, s, len(branches), ListOptions[string]{
|
||||
Key: func(i int) string { return branchKey(branches[i]) },
|
||||
Label: func(i int) string { return branches[i].Name },
|
||||
Status: opts.Status, Error: opts.Error, Empty: msg(c, "branch_list.empty"),
|
||||
}, func(i int) {
|
||||
b := branches[i]
|
||||
branchListRow(c, b)
|
||||
gitRowActions(c, opts.Actions, b.Name, &r)
|
||||
})
|
||||
r.Element, r.changed, r.submitted = v.Element, v.Changed(), v.Submitted()
|
||||
return r
|
||||
}
|
||||
|
||||
func branchKey(b Branch) string {
|
||||
if b.Name == "" {
|
||||
panic("mujica: Branch needs a Name")
|
||||
}
|
||||
if b.Ahead < 0 || b.Behind < 0 {
|
||||
panic("mujica: Branch Ahead and Behind must not be negative")
|
||||
}
|
||||
return b.Name
|
||||
}
|
||||
|
||||
func branchListRow(c *ui.Context, b Branch) {
|
||||
k := Tokens(c)
|
||||
u := Density(c).Unit()
|
||||
small := FontSize(c, theme.CaptionSize)
|
||||
mark := ui.Box(c).Size(16, 16).Shrink(0).Center().Role(ui.RoleNone)
|
||||
if b.Current {
|
||||
mark.TextColor(k.AccentText).Children(func() { ui.Icon(c, icons.Must("check")).Size(14, 14) })
|
||||
}
|
||||
ui.Icon(c, icons.Must("git-branch")).Size(14, 14).Shrink(0).TextColor(k.TextMuted)
|
||||
name := ui.Text(c, b.Name).SingleLine().MinWidth(0).Shrink(1)
|
||||
if b.Current {
|
||||
name.FontWeight(600)
|
||||
ui.Text(c, msg(c, "branch_list.current")).FontSize(small).TextColor(k.AccentText).Shrink(0)
|
||||
}
|
||||
ui.Spacer(c)
|
||||
if b.Upstream != "" {
|
||||
ui.Row(c).Gap(u).AlignItems(ui.Center).Shrink(0).TextColor(k.TextMuted).Children(func() {
|
||||
ui.Text(c, b.Upstream).FontSize(small).SingleLine().MaxWidth(160)
|
||||
if b.Ahead > 0 {
|
||||
ui.Text(c, fmt.Sprintf("↑%d", b.Ahead)).FontSize(small).FontFeatures("tnum").Label(fmt.Sprintf(msg(c, "branch_list.ahead"), b.Ahead))
|
||||
}
|
||||
if b.Behind > 0 {
|
||||
ui.Text(c, fmt.Sprintf("↓%d", b.Behind)).FontSize(small).FontFeatures("tnum").Label(fmt.Sprintf(msg(c, "branch_list.behind"), b.Behind))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// gitActionsCheck panics on incomplete or duplicate actions.
|
||||
func gitActionsCheck(actions []GitAction) {
|
||||
seen := map[string]bool{}
|
||||
for _, a := range actions {
|
||||
if a.ID == "" || a.Label == "" || a.Icon == "" {
|
||||
panic("mujica: GitAction needs an ID, Label and Icon")
|
||||
}
|
||||
if seen[a.ID] {
|
||||
panic("mujica: duplicate GitAction " + a.ID)
|
||||
}
|
||||
seen[a.ID] = true
|
||||
icons.Must(a.Icon)
|
||||
}
|
||||
}
|
||||
|
||||
// gitRowActions shows row actions and records the one used.
|
||||
func gitRowActions(c *ui.Context, actions []GitAction, item string, r *GitListResult) {
|
||||
for _, a := range actions {
|
||||
b := iconAction(c, icons.Must(a.Icon), a.Label).Tooltip(a.Label).Shrink(0)
|
||||
if b.Clicked() && !b.IsDisabled() {
|
||||
r.action, r.item = a.ID, item
|
||||
slog.Debug("mujica: git list action", "action", a.ID, "item", item)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user