mirror of
https://github.com/golang/go
synced 2024-11-19 07:14:45 -07:00
149 lines
2.9 KiB
Go
149 lines
2.9 KiB
Go
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package diff
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
type Unified struct {
|
||
|
From, To string
|
||
|
Hunks []*Hunk
|
||
|
}
|
||
|
|
||
|
type Hunk struct {
|
||
|
FromLine int
|
||
|
ToLine int
|
||
|
Lines []Line
|
||
|
}
|
||
|
|
||
|
type Line struct {
|
||
|
Kind OpKind
|
||
|
Content string
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
edge = 3
|
||
|
gap = edge * 2
|
||
|
)
|
||
|
|
||
|
func ToUnified(from, to string, lines []string, ops []*Op) Unified {
|
||
|
u := Unified{
|
||
|
From: from,
|
||
|
To: to,
|
||
|
}
|
||
|
if len(ops) == 0 {
|
||
|
return u
|
||
|
}
|
||
|
var h *Hunk
|
||
|
last := -(gap + 2)
|
||
|
for _, op := range ops {
|
||
|
switch {
|
||
|
case op.I1 < last:
|
||
|
panic("cannot convert unsorted operations to unified diff")
|
||
|
case op.I1 == last:
|
||
|
//direct extension
|
||
|
case op.I1 <= last+gap:
|
||
|
//within range of previous lines, add the joiners
|
||
|
addEqualLines(h, lines, last, op.I1)
|
||
|
default:
|
||
|
//need to start a new hunk
|
||
|
if h != nil {
|
||
|
// add the edge to the previous hunk
|
||
|
addEqualLines(h, lines, last, last+edge)
|
||
|
u.Hunks = append(u.Hunks, h)
|
||
|
}
|
||
|
h = &Hunk{
|
||
|
FromLine: op.I1 + 1,
|
||
|
ToLine: op.J1 + 1,
|
||
|
}
|
||
|
// add the edge to the new hunk
|
||
|
delta := addEqualLines(h, lines, op.I1-edge, op.I1)
|
||
|
h.FromLine -= delta
|
||
|
h.ToLine -= delta
|
||
|
}
|
||
|
last = op.I1
|
||
|
switch op.Kind {
|
||
|
case Delete:
|
||
|
for i := op.I1; i < op.I2; i++ {
|
||
|
h.Lines = append(h.Lines, Line{Kind: Delete, Content: lines[i]})
|
||
|
last++
|
||
|
}
|
||
|
case Insert:
|
||
|
for _, c := range op.Content {
|
||
|
h.Lines = append(h.Lines, Line{Kind: Insert, Content: c})
|
||
|
}
|
||
|
default:
|
||
|
// all other op types ignored
|
||
|
}
|
||
|
}
|
||
|
if h != nil {
|
||
|
// add the edge to the final hunk
|
||
|
addEqualLines(h, lines, last, last+edge)
|
||
|
u.Hunks = append(u.Hunks, h)
|
||
|
}
|
||
|
return u
|
||
|
}
|
||
|
|
||
|
func addEqualLines(h *Hunk, lines []string, start, end int) int {
|
||
|
delta := 0
|
||
|
for i := start; i < end; i++ {
|
||
|
if i < 0 {
|
||
|
continue
|
||
|
}
|
||
|
if i >= len(lines) {
|
||
|
return delta
|
||
|
}
|
||
|
h.Lines = append(h.Lines, Line{Kind: Equal, Content: lines[i]})
|
||
|
delta++
|
||
|
}
|
||
|
return delta
|
||
|
}
|
||
|
|
||
|
func (u Unified) Format(f fmt.State, r rune) {
|
||
|
fmt.Fprintf(f, "--- %s\n", u.From)
|
||
|
fmt.Fprintf(f, "+++ %s\n", u.To)
|
||
|
for _, hunk := range u.Hunks {
|
||
|
fromCount, toCount := 0, 0
|
||
|
for _, l := range hunk.Lines {
|
||
|
switch l.Kind {
|
||
|
case Delete:
|
||
|
fromCount++
|
||
|
case Insert:
|
||
|
toCount++
|
||
|
default:
|
||
|
fromCount++
|
||
|
toCount++
|
||
|
}
|
||
|
}
|
||
|
fmt.Fprint(f, "@@")
|
||
|
if fromCount > 1 {
|
||
|
fmt.Fprintf(f, " -%d,%d", hunk.FromLine, fromCount)
|
||
|
} else {
|
||
|
fmt.Fprintf(f, " -%d", hunk.FromLine)
|
||
|
}
|
||
|
if toCount > 1 {
|
||
|
fmt.Fprintf(f, " +%d,%d", hunk.ToLine, toCount)
|
||
|
} else {
|
||
|
fmt.Fprintf(f, " +%d", hunk.ToLine)
|
||
|
}
|
||
|
fmt.Fprint(f, " @@\n")
|
||
|
for _, l := range hunk.Lines {
|
||
|
switch l.Kind {
|
||
|
case Delete:
|
||
|
fmt.Fprintf(f, "-%s", l.Content)
|
||
|
case Insert:
|
||
|
fmt.Fprintf(f, "+%s", l.Content)
|
||
|
default:
|
||
|
fmt.Fprintf(f, " %s", l.Content)
|
||
|
}
|
||
|
if !strings.HasSuffix(l.Content, "\n") {
|
||
|
fmt.Fprintf(f, "\n\\ No newline at end of file\n")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|