1
0
mirror of https://github.com/golang/go synced 2024-11-19 07:54:43 -07:00
go/internal/lsp/diff/myers/unified.go
Ian Cottrell b917058f11 internal/lsp: invert the diff dependencies so myers depends on diff
This makes it so the diff package is depended on by all implementations, rather
than the diff package having to depend on the default myers implementation.

Change-Id: I04b9caee6ff1017fa8e5476a7434e4b0e17753c3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/198379
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
2019-10-04 02:16:33 +00:00

154 lines
3.1 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 myers
import (
"fmt"
"strings"
"golang.org/x/tools/internal/lsp/diff"
)
type Unified struct {
From, To string
Hunks []*Hunk
}
type Hunk struct {
FromLine int
ToLine int
Lines []Line
}
type Line struct {
Kind diff.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 diff.Delete:
for i := op.I1; i < op.I2; i++ {
h.Lines = append(h.Lines, Line{Kind: diff.Delete, Content: lines[i]})
last++
}
case diff.Insert:
for _, c := range op.Content {
h.Lines = append(h.Lines, Line{Kind: diff.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: diff.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 diff.Delete:
fromCount++
case diff.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 diff.Delete:
fmt.Fprintf(f, "-%s", l.Content)
case diff.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")
}
}
}
}