github.com/jd-ly/tools@v0.5.7/internal/lsp/protocol/span.go (about) 1 // Copyright 2018 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 // this file contains protocol<->span converters 6 7 package protocol 8 9 import ( 10 "fmt" 11 12 "github.com/jd-ly/tools/internal/span" 13 errors "golang.org/x/xerrors" 14 ) 15 16 type ColumnMapper struct { 17 URI span.URI 18 Converter *span.TokenConverter 19 Content []byte 20 } 21 22 func URIFromSpanURI(uri span.URI) DocumentURI { 23 return DocumentURI(uri) 24 } 25 26 func URIFromPath(path string) DocumentURI { 27 return URIFromSpanURI(span.URIFromPath(path)) 28 } 29 30 func (u DocumentURI) SpanURI() span.URI { 31 return span.URIFromURI(string(u)) 32 } 33 34 func (m *ColumnMapper) Location(s span.Span) (Location, error) { 35 rng, err := m.Range(s) 36 if err != nil { 37 return Location{}, err 38 } 39 return Location{URI: URIFromSpanURI(s.URI()), Range: rng}, nil 40 } 41 42 func (m *ColumnMapper) Range(s span.Span) (Range, error) { 43 if span.CompareURI(m.URI, s.URI()) != 0 { 44 return Range{}, errors.Errorf("column mapper is for file %q instead of %q", m.URI, s.URI()) 45 } 46 s, err := s.WithAll(m.Converter) 47 if err != nil { 48 return Range{}, err 49 } 50 start, err := m.Position(s.Start()) 51 if err != nil { 52 return Range{}, err 53 } 54 end, err := m.Position(s.End()) 55 if err != nil { 56 return Range{}, err 57 } 58 return Range{Start: start, End: end}, nil 59 } 60 61 func (m *ColumnMapper) Position(p span.Point) (Position, error) { 62 chr, err := span.ToUTF16Column(p, m.Content) 63 if err != nil { 64 return Position{}, err 65 } 66 return Position{ 67 Line: float64(p.Line() - 1), 68 Character: float64(chr - 1), 69 }, nil 70 } 71 72 func (m *ColumnMapper) Span(l Location) (span.Span, error) { 73 return m.RangeSpan(l.Range) 74 } 75 76 func (m *ColumnMapper) RangeSpan(r Range) (span.Span, error) { 77 start, err := m.Point(r.Start) 78 if err != nil { 79 return span.Span{}, err 80 } 81 end, err := m.Point(r.End) 82 if err != nil { 83 return span.Span{}, err 84 } 85 return span.New(m.URI, start, end).WithAll(m.Converter) 86 } 87 88 func (m *ColumnMapper) PointSpan(p Position) (span.Span, error) { 89 start, err := m.Point(p) 90 if err != nil { 91 return span.Span{}, err 92 } 93 return span.New(m.URI, start, start).WithAll(m.Converter) 94 } 95 96 func (m *ColumnMapper) Point(p Position) (span.Point, error) { 97 line := int(p.Line) + 1 98 offset, err := m.Converter.ToOffset(line, 1) 99 if err != nil { 100 return span.Point{}, err 101 } 102 lineStart := span.NewPoint(line, 1, offset) 103 return span.FromUTF16Column(lineStart, int(p.Character)+1, m.Content) 104 } 105 106 func IsPoint(r Range) bool { 107 return r.Start.Line == r.End.Line && r.Start.Character == r.End.Character 108 } 109 110 func CompareRange(a, b Range) int { 111 if r := ComparePosition(a.Start, b.Start); r != 0 { 112 return r 113 } 114 return ComparePosition(a.End, b.End) 115 } 116 117 func ComparePosition(a, b Position) int { 118 if a.Line < b.Line { 119 return -1 120 } 121 if a.Line > b.Line { 122 return 1 123 } 124 if a.Character < b.Character { 125 return -1 126 } 127 if a.Character > b.Character { 128 return 1 129 } 130 return 0 131 } 132 133 func Intersect(a, b Range) bool { 134 if a.Start.Line > b.End.Line || a.End.Line < b.Start.Line { 135 return false 136 } 137 return !((a.Start.Line == b.End.Line) && a.Start.Character > b.End.Character || 138 (a.End.Line == b.Start.Line) && a.End.Character < b.Start.Character) 139 } 140 141 func (r Range) Format(f fmt.State, _ rune) { 142 fmt.Fprintf(f, "%v:%v-%v:%v", r.Start.Line, r.Start.Character, r.End.Line, r.End.Character) 143 }