1// Copyright 2018 The Go Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// this file contains protocol<->span converters 16 17package protocol 18 19import ( 20 "fmt" 21 22 "../span" 23 errors "golang.org/x/xerrors" 24) 25 26type ColumnMapper struct { 27 URI span.URI 28 Converter *span.TokenConverter 29 Content []byte 30} 31 32func NewURI(uri span.URI) string { 33 return string(uri) 34} 35 36func (m *ColumnMapper) Location(s span.Span) (Location, error) { 37 rng, err := m.Range(s) 38 if err != nil { 39 return Location{}, err 40 } 41 return Location{URI: NewURI(s.URI()), Range: rng}, nil 42} 43 44func (m *ColumnMapper) Range(s span.Span) (Range, error) { 45 if span.CompareURI(m.URI, s.URI()) != 0 { 46 return Range{}, errors.Errorf("column mapper is for file %q instead of %q", m.URI, s.URI()) 47 } 48 s, err := s.WithAll(m.Converter) 49 if err != nil { 50 return Range{}, err 51 } 52 start, err := m.Position(s.Start()) 53 if err != nil { 54 return Range{}, err 55 } 56 end, err := m.Position(s.End()) 57 if err != nil { 58 return Range{}, err 59 } 60 return Range{Start: start, End: end}, nil 61} 62 63func (m *ColumnMapper) Position(p span.Point) (Position, error) { 64 chr, err := span.ToUTF16Column(p, m.Content) 65 if err != nil { 66 return Position{}, err 67 } 68 return Position{ 69 Line: float64(p.Line() - 1), 70 Character: float64(chr - 1), 71 }, nil 72} 73 74func (m *ColumnMapper) Span(l Location) (span.Span, error) { 75 return m.RangeSpan(l.Range) 76} 77 78func (m *ColumnMapper) RangeSpan(r Range) (span.Span, error) { 79 start, err := m.Point(r.Start) 80 if err != nil { 81 return span.Span{}, err 82 } 83 end, err := m.Point(r.End) 84 if err != nil { 85 return span.Span{}, err 86 } 87 return span.New(m.URI, start, end).WithAll(m.Converter) 88} 89 90func (m *ColumnMapper) PointSpan(p Position) (span.Span, error) { 91 start, err := m.Point(p) 92 if err != nil { 93 return span.Span{}, err 94 } 95 return span.New(m.URI, start, start).WithAll(m.Converter) 96} 97 98func (m *ColumnMapper) Point(p Position) (span.Point, error) { 99 line := int(p.Line) + 1 100 offset, err := m.Converter.ToOffset(line, 1) 101 if err != nil { 102 return span.Point{}, err 103 } 104 lineStart := span.NewPoint(line, 1, offset) 105 return span.FromUTF16Column(lineStart, int(p.Character)+1, m.Content) 106} 107 108func IsPoint(r Range) bool { 109 return r.Start.Line == r.End.Line && r.Start.Character == r.End.Character 110} 111 112func CompareRange(a, b Range) int { 113 if r := ComparePosition(a.Start, b.Start); r != 0 { 114 return r 115 } 116 return ComparePosition(a.End, b.End) 117} 118 119func ComparePosition(a, b Position) int { 120 if a.Line < b.Line { 121 return -1 122 } 123 if a.Line > b.Line { 124 return 1 125 } 126 if a.Character < b.Character { 127 return -1 128 } 129 if a.Character > b.Character { 130 return 1 131 } 132 return 0 133} 134 135func (r Range) Format(f fmt.State, _ rune) { 136 fmt.Fprintf(f, "%v:%v-%v:%v", r.Start.Line, r.Start.Character, r.End.Line, r.End.Character) 137} 138