mirror of
https://github.com/golang/go
synced 2024-11-19 06:54:39 -07:00
cc9bfb3eec
It is now in the diff package written in terms of edits, instead of the myers package. This also means that the unified handling is no longer pluggable because it does not need to be. Change-Id: I7141b023e95ed0c1d21cbc81c7420c117fc5ef1a Reviewed-on: https://go-review.googlesource.com/c/tools/+/198517 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
170 lines
3.5 KiB
Go
170 lines
3.5 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"
|
|
|
|
"golang.org/x/tools/internal/span"
|
|
)
|
|
|
|
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, content string, edits []TextEdit) Unified {
|
|
u := Unified{
|
|
From: from,
|
|
To: to,
|
|
}
|
|
if len(edits) == 0 {
|
|
return u
|
|
}
|
|
lines := splitLines(content)
|
|
var h *Hunk
|
|
last := 0
|
|
c := span.NewContentConverter(from, []byte(content))
|
|
toLine := 0
|
|
for _, edit := range edits {
|
|
spn, _ := edit.Span.WithAll(c)
|
|
start := spn.Start().Line() - 1
|
|
end := spn.End().Line() - 1
|
|
if spn.Start().Column() > 1 || spn.End().Column() > 1 {
|
|
panic("cannot convert partial line edits to unified diff")
|
|
}
|
|
switch {
|
|
case start < last:
|
|
panic("cannot convert unsorted edits to unified diff")
|
|
case h != nil && start == last:
|
|
//direct extension
|
|
case h != nil && start <= last+gap:
|
|
//within range of previous lines, add the joiners
|
|
addEqualLines(h, lines, last, start)
|
|
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)
|
|
}
|
|
toLine += start - last
|
|
h = &Hunk{
|
|
FromLine: start + 1,
|
|
ToLine: toLine + 1,
|
|
}
|
|
// add the edge to the new hunk
|
|
delta := addEqualLines(h, lines, start-edge, start)
|
|
h.FromLine -= delta
|
|
h.ToLine -= delta
|
|
}
|
|
last = start
|
|
if edit.NewText == "" {
|
|
for i := start; i < end; i++ {
|
|
h.Lines = append(h.Lines, Line{Kind: Delete, Content: lines[i]})
|
|
last++
|
|
}
|
|
} else {
|
|
for _, line := range splitLines(edit.NewText) {
|
|
h.Lines = append(h.Lines, Line{Kind: Insert, Content: line})
|
|
toLine++
|
|
}
|
|
}
|
|
}
|
|
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 splitLines(text string) []string {
|
|
lines := strings.SplitAfter(text, "\n")
|
|
if lines[len(lines)-1] == "" {
|
|
lines = lines[:len(lines)-1]
|
|
}
|
|
return lines
|
|
}
|
|
|
|
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) {
|
|
if len(u.Hunks) == 0 {
|
|
return
|
|
}
|
|
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")
|
|
}
|
|
}
|
|
}
|
|
}
|