diff --git a/go.mod b/go.mod index e0fc5bb..783a479 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/stretchr/testify v1.10.0 ) -require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect +require golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect require ( github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 19993e4..75d7637 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/images/example.png b/images/example.png index 8aacbff..ade1ad2 100644 Binary files a/images/example.png and b/images/example.png differ diff --git a/pkg/diff/ast_compare.go b/pkg/diff/ast_compare.go index de8873f..497f2dc 100644 --- a/pkg/diff/ast_compare.go +++ b/pkg/diff/ast_compare.go @@ -1,9 +1,6 @@ package diff import ( - "fmt" - "strings" - "github.com/goccy/go-yaml/ast" ) @@ -176,32 +173,3 @@ func ignoreIndexes(diffs []*Diff, opts DiffOptions) []*Diff { return resultDiffs } - -func nodePathString(n ast.Node) string { - path := n.GetPath()[2:] - // Path of the MappingNode points to the first key in the map. - if n.Type() == ast.MappingType { - path = path[:strings.LastIndex(path, ".")] - } - return path -} - -func nodeValueString(n ast.Node) string { - switch n.Type() { - case ast.MappingType, ast.SequenceType: - indent := n.GetToken().Position.IndentNum - s := n.String() - lines := strings.Split(s, "\n") - for i, line := range lines { - lines[i] = fmt.Sprintf(" %s", line[indent:]) - } - s = strings.Join(lines, "\n") - return fmt.Sprintf("\n%s", s) - default: - return n.String() - } -} - -func nodeMetadata(n ast.Node) string { - return fmt.Sprintf("[line:%d <%s>]", n.GetToken().Position.Line, n.Type()) -} diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go index 6c77da6..e093a13 100644 --- a/pkg/diff/diff.go +++ b/pkg/diff/diff.go @@ -20,13 +20,13 @@ func (d *Diff) Format(opts FormatOptions) string { if d.leftNode == nil { // Added sign := "+" path := nodePathString(d.rightNode) - value := nodeValueString(d.rightNode) + value, _ := nodeValueString(d.rightNode, 4) metadata := nodeMetadata(d.rightNode) if !opts.Plain { sign = color.HiGreenString(sign) path = color.HiGreenString(path) - value = color.HiWhiteString(value) + value = colorize(value) metadata = color.HiCyanString(metadata) } @@ -43,13 +43,13 @@ func (d *Diff) Format(opts FormatOptions) string { } else if d.rightNode == nil { //Deleted sign := "-" path := nodePathString(d.leftNode) - value := nodeValueString(d.leftNode) + value, _ := nodeValueString(d.leftNode, 4) metadata := nodeMetadata(d.leftNode) if !opts.Plain { sign = color.HiRedString(sign) path = color.HiRedString(path) - value = color.HiWhiteString(value) + value = colorize(value) metadata = color.HiCyanString(metadata) } @@ -65,16 +65,32 @@ func (d *Diff) Format(opts FormatOptions) string { } else { //Modified sign := "~" path := nodePathString(d.leftNode) - leftValue := nodeValueString(d.leftNode) - rightValue := nodeValueString(d.rightNode) + leftValue, leftMultiLine := nodeValueString(d.leftNode, 4) + rightValue, rightMultiLine := nodeValueString(d.rightNode, 4) leftMetadata := nodeMetadata(d.leftNode) rightMetadata := nodeMetadata(d.rightNode) + symbol := "->" + + multiline := leftMultiLine || rightMultiLine + + if multiline && !leftMultiLine { + leftValue = fmt.Sprintf("\n %s", leftValue) + } + + if multiline && !rightMultiLine { + rightValue = fmt.Sprintf("\n %s", rightValue) + } + + if multiline { + symbol = "\n ↓" + } + if !opts.Plain { sign = color.HiYellowString(sign) path = color.HiYellowString(path) - leftValue = color.HiWhiteString(leftValue) - rightValue = color.HiWhiteString(rightValue) + leftValue = colorize(leftValue) + rightValue = colorize(rightValue) leftMetadata = color.HiCyanString(leftMetadata) rightMetadata = color.HiCyanString(rightMetadata) } @@ -83,9 +99,9 @@ func (d *Diff) Format(opts FormatOptions) string { b.WriteString(fmt.Sprintf("%s %s", sign, path)) } else { if opts.Metadata { - b.WriteString(fmt.Sprintf("%s %s: %s %s -> %s %s", sign, path, leftMetadata, leftValue, rightMetadata, rightValue)) + b.WriteString(fmt.Sprintf("%s %s: %s %s %s %s %s", sign, path, leftMetadata, leftValue, symbol, rightMetadata, rightValue)) } else { - b.WriteString(fmt.Sprintf("%s %s: %s -> %s", sign, path, leftValue, rightValue)) + b.WriteString(fmt.Sprintf("%s %s: %s %s %s", sign, path, leftValue, symbol, rightValue)) } } } diff --git a/pkg/diff/format.go b/pkg/diff/format.go new file mode 100644 index 0000000..4dbbfac --- /dev/null +++ b/pkg/diff/format.go @@ -0,0 +1,111 @@ +package diff + +import ( + "fmt" + "strings" + + "github.com/fatih/color" + "github.com/goccy/go-yaml/ast" + "github.com/goccy/go-yaml/lexer" + "github.com/goccy/go-yaml/printer" +) + +func nodePathString(n ast.Node) string { + path := n.GetPath()[2:] + // Path of the MappingNode points to the first key in the map. + if n.Type() == ast.MappingType { + path = path[:strings.LastIndex(path, ".")] + } + return path +} + +func nodeValueString(n ast.Node, indent int) (string, bool) { + s := n.String() + lines := strings.Split(s, "\n") + if len(lines) == 1 { + return s, false + } + + nodeIndentLevel := 0 + for i, line := range lines { + if i == 0 { + nodeIndentLevel = findIndentLevel(line) + lines[i] = fmt.Sprintf("%s%s%s", "\n", strings.Repeat(" ", indent), line[nodeIndentLevel:]) + } else { + lines[i] = fmt.Sprintf("%s%s", strings.Repeat(" ", indent), line[nodeIndentLevel:]) + } + } + + return strings.Join(lines, "\n"), true +} + +func nodeMetadata(n ast.Node) string { + return fmt.Sprintf("[line:%d <%s>]", n.GetToken().Position.Line, n.Type()) +} + +func findIndentLevel(s string) int { + for i, c := range s { + if c != ' ' { + return i + } + } + return 0 +} + +var p printer.Printer + +func init() { + p = printer.Printer{} + //p.LineNumber = true + //p.LineNumberFormat = func(num int) string { + // fn := color.New(color.Bold, color.FgHiWhite).SprintFunc() + // return fn(fmt.Sprintf("%2d | ", num)) + //} + p.Bool = func() *printer.Property { + return &printer.Property{ + Prefix: format(color.FgHiMagenta), + Suffix: format(color.Reset), + } + } + p.Number = func() *printer.Property { + return &printer.Property{ + Prefix: format(color.FgHiMagenta), + Suffix: format(color.Reset), + } + } + p.MapKey = func() *printer.Property { + return &printer.Property{ + Prefix: format(color.FgHiCyan), + Suffix: format(color.Reset), + } + } + p.Anchor = func() *printer.Property { + return &printer.Property{ + Prefix: format(color.FgHiYellow), + Suffix: format(color.Reset), + } + } + p.Alias = func() *printer.Property { + return &printer.Property{ + Prefix: format(color.FgHiYellow), + Suffix: format(color.Reset), + } + } + p.String = func() *printer.Property { + return &printer.Property{ + Prefix: format(color.FgHiGreen), + Suffix: format(color.Reset), + } + } +} + +const escape = "\x1b" + +func format(attr color.Attribute) string { + return fmt.Sprintf("%s[%dm", escape, attr) +} + +func colorize(s string) string { + tokens := lexer.Tokenize(s) + return p.PrintTokens(tokens) +}