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 / span / span.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 span contains support for representing with positions and ranges in
6 // text files.
7 package span
8
9 import (
10         "encoding/json"
11         "fmt"
12         "path"
13 )
14
15 // Span represents a source code range in standardized form.
16 type Span struct {
17         v span
18 }
19
20 // Point represents a single point within a file.
21 // In general this should only be used as part of a Span, as on its own it
22 // does not carry enough information.
23 type Point struct {
24         v point
25 }
26
27 type span struct {
28         URI   URI   `json:"uri"`
29         Start point `json:"start"`
30         End   point `json:"end"`
31 }
32
33 type point struct {
34         Line   int `json:"line"`
35         Column int `json:"column"`
36         Offset int `json:"offset"`
37 }
38
39 // Invalid is a span that reports false from IsValid
40 var Invalid = Span{v: span{Start: invalidPoint.v, End: invalidPoint.v}}
41
42 var invalidPoint = Point{v: point{Line: 0, Column: 0, Offset: -1}}
43
44 // Converter is the interface to an object that can convert between line:column
45 // and offset forms for a single file.
46 type Converter interface {
47         //ToPosition converts from an offset to a line:column pair.
48         ToPosition(offset int) (int, int, error)
49         //ToOffset converts from a line:column pair to an offset.
50         ToOffset(line, col int) (int, error)
51 }
52
53 func New(uri URI, start Point, end Point) Span {
54         s := Span{v: span{URI: uri, Start: start.v, End: end.v}}
55         s.v.clean()
56         return s
57 }
58
59 func NewPoint(line, col, offset int) Point {
60         p := Point{v: point{Line: line, Column: col, Offset: offset}}
61         p.v.clean()
62         return p
63 }
64
65 func Compare(a, b Span) int {
66         if r := CompareURI(a.URI(), b.URI()); r != 0 {
67                 return r
68         }
69         if r := comparePoint(a.v.Start, b.v.Start); r != 0 {
70                 return r
71         }
72         return comparePoint(a.v.End, b.v.End)
73 }
74
75 func ComparePoint(a, b Point) int {
76         return comparePoint(a.v, b.v)
77 }
78
79 func comparePoint(a, b point) int {
80         if !a.hasPosition() {
81                 if a.Offset < b.Offset {
82                         return -1
83                 }
84                 if a.Offset > b.Offset {
85                         return 1
86                 }
87                 return 0
88         }
89         if a.Line < b.Line {
90                 return -1
91         }
92         if a.Line > b.Line {
93                 return 1
94         }
95         if a.Column < b.Column {
96                 return -1
97         }
98         if a.Column > b.Column {
99                 return 1
100         }
101         return 0
102 }
103
104 func (s Span) HasPosition() bool             { return s.v.Start.hasPosition() }
105 func (s Span) HasOffset() bool               { return s.v.Start.hasOffset() }
106 func (s Span) IsValid() bool                 { return s.v.Start.isValid() }
107 func (s Span) IsPoint() bool                 { return s.v.Start == s.v.End }
108 func (s Span) URI() URI                      { return s.v.URI }
109 func (s Span) Start() Point                  { return Point{s.v.Start} }
110 func (s Span) End() Point                    { return Point{s.v.End} }
111 func (s *Span) MarshalJSON() ([]byte, error) { return json.Marshal(&s.v) }
112 func (s *Span) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &s.v) }
113
114 func (p Point) HasPosition() bool             { return p.v.hasPosition() }
115 func (p Point) HasOffset() bool               { return p.v.hasOffset() }
116 func (p Point) IsValid() bool                 { return p.v.isValid() }
117 func (p *Point) MarshalJSON() ([]byte, error) { return json.Marshal(&p.v) }
118 func (p *Point) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &p.v) }
119 func (p Point) Line() int {
120         if !p.v.hasPosition() {
121                 panic(fmt.Errorf("position not set in %v", p.v))
122         }
123         return p.v.Line
124 }
125 func (p Point) Column() int {
126         if !p.v.hasPosition() {
127                 panic(fmt.Errorf("position not set in %v", p.v))
128         }
129         return p.v.Column
130 }
131 func (p Point) Offset() int {
132         if !p.v.hasOffset() {
133                 panic(fmt.Errorf("offset not set in %v", p.v))
134         }
135         return p.v.Offset
136 }
137
138 func (p point) hasPosition() bool { return p.Line > 0 }
139 func (p point) hasOffset() bool   { return p.Offset >= 0 }
140 func (p point) isValid() bool     { return p.hasPosition() || p.hasOffset() }
141 func (p point) isZero() bool {
142         return (p.Line == 1 && p.Column == 1) || (!p.hasPosition() && p.Offset == 0)
143 }
144
145 func (s *span) clean() {
146         //this presumes the points are already clean
147         if !s.End.isValid() || (s.End == point{}) {
148                 s.End = s.Start
149         }
150 }
151
152 func (p *point) clean() {
153         if p.Line < 0 {
154                 p.Line = 0
155         }
156         if p.Column <= 0 {
157                 if p.Line > 0 {
158                         p.Column = 1
159                 } else {
160                         p.Column = 0
161                 }
162         }
163         if p.Offset == 0 && (p.Line > 1 || p.Column > 1) {
164                 p.Offset = -1
165         }
166 }
167
168 // Format implements fmt.Formatter to print the Location in a standard form.
169 // The format produced is one that can be read back in using Parse.
170 func (s Span) Format(f fmt.State, c rune) {
171         fullForm := f.Flag('+')
172         preferOffset := f.Flag('#')
173         // we should always have a uri, simplify if it is file format
174         //TODO: make sure the end of the uri is unambiguous
175         uri := string(s.v.URI)
176         if c == 'f' {
177                 uri = path.Base(uri)
178         } else if !fullForm {
179                 uri = s.v.URI.Filename()
180         }
181         fmt.Fprint(f, uri)
182         if !s.IsValid() || (!fullForm && s.v.Start.isZero() && s.v.End.isZero()) {
183                 return
184         }
185         // see which bits of start to write
186         printOffset := s.HasOffset() && (fullForm || preferOffset || !s.HasPosition())
187         printLine := s.HasPosition() && (fullForm || !printOffset)
188         printColumn := printLine && (fullForm || (s.v.Start.Column > 1 || s.v.End.Column > 1))
189         fmt.Fprint(f, ":")
190         if printLine {
191                 fmt.Fprintf(f, "%d", s.v.Start.Line)
192         }
193         if printColumn {
194                 fmt.Fprintf(f, ":%d", s.v.Start.Column)
195         }
196         if printOffset {
197                 fmt.Fprintf(f, "#%d", s.v.Start.Offset)
198         }
199         // start is written, do we need end?
200         if s.IsPoint() {
201                 return
202         }
203         // we don't print the line if it did not change
204         printLine = fullForm || (printLine && s.v.End.Line > s.v.Start.Line)
205         fmt.Fprint(f, "-")
206         if printLine {
207                 fmt.Fprintf(f, "%d", s.v.End.Line)
208         }
209         if printColumn {
210                 if printLine {
211                         fmt.Fprint(f, ":")
212                 }
213                 fmt.Fprintf(f, "%d", s.v.End.Column)
214         }
215         if printOffset {
216                 fmt.Fprintf(f, "#%d", s.v.End.Offset)
217         }
218 }
219
220 func (s Span) WithPosition(c Converter) (Span, error) {
221         if err := s.update(c, true, false); err != nil {
222                 return Span{}, err
223         }
224         return s, nil
225 }
226
227 func (s Span) WithOffset(c Converter) (Span, error) {
228         if err := s.update(c, false, true); err != nil {
229                 return Span{}, err
230         }
231         return s, nil
232 }
233
234 func (s Span) WithAll(c Converter) (Span, error) {
235         if err := s.update(c, true, true); err != nil {
236                 return Span{}, err
237         }
238         return s, nil
239 }
240
241 func (s *Span) update(c Converter, withPos, withOffset bool) error {
242         if !s.IsValid() {
243                 return fmt.Errorf("cannot add information to an invalid span")
244         }
245         if withPos && !s.HasPosition() {
246                 if err := s.v.Start.updatePosition(c); err != nil {
247                         return err
248                 }
249                 if s.v.End.Offset == s.v.Start.Offset {
250                         s.v.End = s.v.Start
251                 } else if err := s.v.End.updatePosition(c); err != nil {
252                         return err
253                 }
254         }
255         if withOffset && (!s.HasOffset() || (s.v.End.hasPosition() && !s.v.End.hasOffset())) {
256                 if err := s.v.Start.updateOffset(c); err != nil {
257                         return err
258                 }
259                 if s.v.End.Line == s.v.Start.Line && s.v.End.Column == s.v.Start.Column {
260                         s.v.End.Offset = s.v.Start.Offset
261                 } else if err := s.v.End.updateOffset(c); err != nil {
262                         return err
263                 }
264         }
265         return nil
266 }
267
268 func (p *point) updatePosition(c Converter) error {
269         line, col, err := c.ToPosition(p.Offset)
270         if err != nil {
271                 return err
272         }
273         p.Line = line
274         p.Column = col
275         return nil
276 }
277
278 func (p *point) updateOffset(c Converter) error {
279         offset, err := c.ToOffset(p.Line, p.Column)
280         if err != nil {
281                 return err
282         }
283         p.Offset = offset
284         return nil
285 }