Files
MujicaUI/agent/agent_diff.go
T

129 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package agent
import (
"fmt"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/MujicaUI/core"
"git.zacharyzhang.com/ZacharyZhang-NY/MujicaUI/icons"
"git.zacharyzhang.com/ZacharyZhang-NY/MujicaUI/internal"
"git.zacharyzhang.com/ZacharyZhang-NY/MujicaUI/theme"
)
// FileChange is a proposed edit; empty Old adds a file.
type FileChange struct {
Path string
Old, New string
}
// FileDecision is a review state; zero is FilePending.
type FileDecision int
const (
FilePending FileDecision = iota
FileAccepted
FileRejected
)
// agentDiffCache holds a change's line diff until its text changes.
type agentDiffCache struct {
old, new string
lines []internal.DiffLine
add, del int
firstEdit int
done bool
}
func (dc *agentDiffCache) update(ch FileChange) {
if dc.done && dc.old == ch.Old && dc.new == ch.New {
return
}
dc.old, dc.new, dc.done = ch.Old, ch.New, true
dc.lines = internal.LineDiff(internal.SplitLines(ch.Old), internal.SplitLines(ch.New))
dc.add, dc.del = internal.DiffStats(dc.lines)
dc.firstEdit = 0
for i, l := range dc.lines {
if l.Op != internal.DiffEqual {
dc.firstEdit = i
break
}
}
}
// agentDiffOf returns the cached diff of ch kept on holder.
func agentDiffOf(holder *ui.Element, ch FileChange) *agentDiffCache {
dc := ui.Local(holder, "mujica.agent.diff", func() *agentDiffCache { return &agentDiffCache{} })
(*dc).update(ch)
return *dc
}
// agentDiffStats shows signed added and removed counts.
func agentDiffStats(c *ui.Context, add, del int) {
k := core.Tokens(c)
size := core.FontSize(c, theme.CaptionSize+1)
ui.Row(c).Gap(core.Density(c).Unit() * 1.5).Shrink(0).Label(fmt.Sprintf(core.Msg(c, "file_change_card.stats"), add, del)).Children(func() {
ui.Text(c, fmt.Sprintf("+%d", add)).TextColor(k.Success).FontSize(size).Font(theme.MonoFont)
ui.Text(c, fmt.Sprintf("−%d", del)).TextColor(k.Danger).FontSize(size).Font(theme.MonoFont)
})
}
// agentDiffRow draws one numbered, signed, tinted diff line.
func agentDiffRow(c *ui.Context, l internal.DiffLine) {
k := core.Tokens(c)
u := core.Density(c).Unit()
sign, bg, fg := " ", ui.Transparent, k.TextMuted
switch l.Op {
case internal.DiffInsert:
sign, bg, fg = "+", k.Success.Alpha(0.14), k.Success
case internal.DiffDelete:
sign, bg, fg = "−", k.Danger.Alpha(0.14), k.Danger
}
num := func(n int) string {
if n == 0 {
return ""
}
return fmt.Sprint(n)
}
ui.Row(c).Gap(u*2).Background(bg).Padding(0, u).Children(func() {
ui.Text(c, num(l.Old)).Width(36).TextAlign(ui.End).TextColor(k.TextMuted).Shrink(0)
ui.Text(c, num(l.New)).Width(36).TextAlign(ui.End).TextColor(k.TextMuted).Shrink(0)
ui.Text(c, sign).TextColor(fg).Width(10).Shrink(0)
text := l.Text
if text == "" {
text = " "
}
ui.Text(c, text).Grow(1).Shrink(1)
})
}
// agentDiffView shows lines[from:to] in a capped well, virtualized when long.
func agentDiffView(c *ui.Context, lines []internal.DiffLine, maxHeight float32) *ui.Element {
w := AgentWellRows(c, len(lines), func(i int) { agentDiffRow(c, lines[i]) }, maxHeight)
return w.Padding(core.Density(c).Unit(), 0)
}
// agentDecisionMark shows a decision by icon and word.
func agentDecisionMark(c *ui.Context, d FileDecision) {
ui.Row(c).Gap(core.Density(c).Unit()).AlignItems(ui.Center).Shrink(0).Children(func() {
AgentCaption(c, agentDecisionIcon(c, d))
})
}
// agentDecisionIcon draws a named decision icon, returning its word.
func agentDecisionIcon(c *ui.Context, d FileDecision) string {
k := core.Tokens(c)
tone, icon, word := k.TextMuted, "circle", core.Msg(c, "file_change_card.pending")
switch d {
case FileAccepted:
tone, icon, word = k.Success, "circle-check", core.Msg(c, "file_change_card.accepted")
case FileRejected:
tone, icon, word = k.Danger, "circle-x", core.Msg(c, "file_change_card.rejected")
case FilePending:
default:
panic(fmt.Sprintf("mujica: unknown FileDecision %d", int(d)))
}
ui.Icon(c, icons.Must(icon)).Size(14, 14).TextColor(tone).Shrink(0).Label(word)
return word
}