Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / diff / unified.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package diff
6
7 import (
8         "fmt"
9         "strings"
10 )
11
12 // Unified represents a set of edits as a unified diff.
13 type Unified struct {
14         // From is the name of the original file.
15         From string
16         // To is the name of the modified file.
17         To string
18         // Hunks is the set of edit hunks needed to transform the file content.
19         Hunks []*Hunk
20 }
21
22 // Hunk represents a contiguous set of line edits to apply.
23 type Hunk struct {
24         // The line in the original source where the hunk starts.
25         FromLine int
26         // The line in the original source where the hunk finishes.
27         ToLine int
28         // The set of line based edits to apply.
29         Lines []Line
30 }
31
32 // Line represents a single line operation to apply as part of a Hunk.
33 type Line struct {
34         // Kind is the type of line this represents, deletion, insertion or copy.
35         Kind OpKind
36         // Content is the content of this line.
37         // For deletion it is the line being removed, for all others it is the line
38         // to put in the output.
39         Content string
40 }
41
42 // OpKind is used to denote the type of operation a line represents.
43 type OpKind int
44
45 const (
46         // Delete is the operation kind for a line that is present in the input
47         // but not in the output.
48         Delete OpKind = iota
49         // Insert is the operation kind for a line that is new in the output.
50         Insert
51         // Equal is the operation kind for a line that is the same in the input and
52         // output, often used to provide context around edited lines.
53         Equal
54 )
55
56 // String returns a human readable representation of an OpKind. It is not
57 // intended for machine processing.
58 func (k OpKind) String() string {
59         switch k {
60         case Delete:
61                 return "delete"
62         case Insert:
63                 return "insert"
64         case Equal:
65                 return "equal"
66         default:
67                 panic("unknown operation kind")
68         }
69 }
70
71 const (
72         edge = 3
73         gap  = edge * 2
74 )
75
76 // ToUnified takes a file contents and a sequence of edits, and calculates
77 // a unified diff that represents those edits.
78 func ToUnified(from, to string, content string, edits []TextEdit) Unified {
79         u := Unified{
80                 From: from,
81                 To:   to,
82         }
83         if len(edits) == 0 {
84                 return u
85         }
86         c, edits, partial := prepareEdits(content, edits)
87         if partial {
88                 edits = lineEdits(content, c, edits)
89         }
90         lines := splitLines(content)
91         var h *Hunk
92         last := 0
93         toLine := 0
94         for _, edit := range edits {
95                 start := edit.Span.Start().Line() - 1
96                 end := edit.Span.End().Line() - 1
97                 switch {
98                 case h != nil && start == last:
99                         //direct extension
100                 case h != nil && start <= last+gap:
101                         //within range of previous lines, add the joiners
102                         addEqualLines(h, lines, last, start)
103                 default:
104                         //need to start a new hunk
105                         if h != nil {
106                                 // add the edge to the previous hunk
107                                 addEqualLines(h, lines, last, last+edge)
108                                 u.Hunks = append(u.Hunks, h)
109                         }
110                         toLine += start - last
111                         h = &Hunk{
112                                 FromLine: start + 1,
113                                 ToLine:   toLine + 1,
114                         }
115                         // add the edge to the new hunk
116                         delta := addEqualLines(h, lines, start-edge, start)
117                         h.FromLine -= delta
118                         h.ToLine -= delta
119                 }
120                 last = start
121                 for i := start; i < end; i++ {
122                         h.Lines = append(h.Lines, Line{Kind: Delete, Content: lines[i]})
123                         last++
124                 }
125                 if edit.NewText != "" {
126                         for _, line := range splitLines(edit.NewText) {
127                                 h.Lines = append(h.Lines, Line{Kind: Insert, Content: line})
128                                 toLine++
129                         }
130                 }
131         }
132         if h != nil {
133                 // add the edge to the final hunk
134                 addEqualLines(h, lines, last, last+edge)
135                 u.Hunks = append(u.Hunks, h)
136         }
137         return u
138 }
139
140 func splitLines(text string) []string {
141         lines := strings.SplitAfter(text, "\n")
142         if lines[len(lines)-1] == "" {
143                 lines = lines[:len(lines)-1]
144         }
145         return lines
146 }
147
148 func addEqualLines(h *Hunk, lines []string, start, end int) int {
149         delta := 0
150         for i := start; i < end; i++ {
151                 if i < 0 {
152                         continue
153                 }
154                 if i >= len(lines) {
155                         return delta
156                 }
157                 h.Lines = append(h.Lines, Line{Kind: Equal, Content: lines[i]})
158                 delta++
159         }
160         return delta
161 }
162
163 // Format converts a unified diff to the standard textual form for that diff.
164 // The output of this function can be passed to tools like patch.
165 func (u Unified) Format(f fmt.State, r rune) {
166         if len(u.Hunks) == 0 {
167                 return
168         }
169         fmt.Fprintf(f, "--- %s\n", u.From)
170         fmt.Fprintf(f, "+++ %s\n", u.To)
171         for _, hunk := range u.Hunks {
172                 fromCount, toCount := 0, 0
173                 for _, l := range hunk.Lines {
174                         switch l.Kind {
175                         case Delete:
176                                 fromCount++
177                         case Insert:
178                                 toCount++
179                         default:
180                                 fromCount++
181                                 toCount++
182                         }
183                 }
184                 fmt.Fprint(f, "@@")
185                 if fromCount > 1 {
186                         fmt.Fprintf(f, " -%d,%d", hunk.FromLine, fromCount)
187                 } else {
188                         fmt.Fprintf(f, " -%d", hunk.FromLine)
189                 }
190                 if toCount > 1 {
191                         fmt.Fprintf(f, " +%d,%d", hunk.ToLine, toCount)
192                 } else {
193                         fmt.Fprintf(f, " +%d", hunk.ToLine)
194                 }
195                 fmt.Fprint(f, " @@\n")
196                 for _, l := range hunk.Lines {
197                         switch l.Kind {
198                         case Delete:
199                                 fmt.Fprintf(f, "-%s", l.Content)
200                         case Insert:
201                                 fmt.Fprintf(f, "+%s", l.Content)
202                         default:
203                                 fmt.Fprintf(f, " %s", l.Content)
204                         }
205                         if !strings.HasSuffix(l.Content, "\n") {
206                                 fmt.Fprintf(f, "\n\\ No newline at end of file\n")
207                         }
208                 }
209         }
210 }