mirror of
https://github.com/golang/go
synced 2024-11-05 16:46:10 -07:00
55644ead90
Code actions that apply convenience fixes were filtered by the start line so it wasn't possible to narrow the scope to a specific range. This change allows clients to send a specific range (or cursor position) to filter all fixes where the range doesn't intersect with the provided range. It also widens the diagnostic returned by fillstruct analysis. The idea is to provide a way to narrow the scope without breaking clients that do want to ask for code actions using the entire line. Updates golang/go#40438 Change-Id: Ifd984a092a4a3bf0b3a2a5426d3e65023ba4eebc Reviewed-on: https://go-review.googlesource.com/c/tools/+/244519 Run-TryBot: Pontus Leitzler <leitzler@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
144 lines
3.3 KiB
Go
144 lines
3.3 KiB
Go
// Copyright 2018 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.
|
|
|
|
// this file contains protocol<->span converters
|
|
|
|
package protocol
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"golang.org/x/tools/internal/span"
|
|
errors "golang.org/x/xerrors"
|
|
)
|
|
|
|
type ColumnMapper struct {
|
|
URI span.URI
|
|
Converter *span.TokenConverter
|
|
Content []byte
|
|
}
|
|
|
|
func URIFromSpanURI(uri span.URI) DocumentURI {
|
|
return DocumentURI(uri)
|
|
}
|
|
|
|
func URIFromPath(path string) DocumentURI {
|
|
return URIFromSpanURI(span.URIFromPath(path))
|
|
}
|
|
|
|
func (u DocumentURI) SpanURI() span.URI {
|
|
return span.URIFromURI(string(u))
|
|
}
|
|
|
|
func (m *ColumnMapper) Location(s span.Span) (Location, error) {
|
|
rng, err := m.Range(s)
|
|
if err != nil {
|
|
return Location{}, err
|
|
}
|
|
return Location{URI: URIFromSpanURI(s.URI()), Range: rng}, nil
|
|
}
|
|
|
|
func (m *ColumnMapper) Range(s span.Span) (Range, error) {
|
|
if span.CompareURI(m.URI, s.URI()) != 0 {
|
|
return Range{}, errors.Errorf("column mapper is for file %q instead of %q", m.URI, s.URI())
|
|
}
|
|
s, err := s.WithAll(m.Converter)
|
|
if err != nil {
|
|
return Range{}, err
|
|
}
|
|
start, err := m.Position(s.Start())
|
|
if err != nil {
|
|
return Range{}, err
|
|
}
|
|
end, err := m.Position(s.End())
|
|
if err != nil {
|
|
return Range{}, err
|
|
}
|
|
return Range{Start: start, End: end}, nil
|
|
}
|
|
|
|
func (m *ColumnMapper) Position(p span.Point) (Position, error) {
|
|
chr, err := span.ToUTF16Column(p, m.Content)
|
|
if err != nil {
|
|
return Position{}, err
|
|
}
|
|
return Position{
|
|
Line: float64(p.Line() - 1),
|
|
Character: float64(chr - 1),
|
|
}, nil
|
|
}
|
|
|
|
func (m *ColumnMapper) Span(l Location) (span.Span, error) {
|
|
return m.RangeSpan(l.Range)
|
|
}
|
|
|
|
func (m *ColumnMapper) RangeSpan(r Range) (span.Span, error) {
|
|
start, err := m.Point(r.Start)
|
|
if err != nil {
|
|
return span.Span{}, err
|
|
}
|
|
end, err := m.Point(r.End)
|
|
if err != nil {
|
|
return span.Span{}, err
|
|
}
|
|
return span.New(m.URI, start, end).WithAll(m.Converter)
|
|
}
|
|
|
|
func (m *ColumnMapper) PointSpan(p Position) (span.Span, error) {
|
|
start, err := m.Point(p)
|
|
if err != nil {
|
|
return span.Span{}, err
|
|
}
|
|
return span.New(m.URI, start, start).WithAll(m.Converter)
|
|
}
|
|
|
|
func (m *ColumnMapper) Point(p Position) (span.Point, error) {
|
|
line := int(p.Line) + 1
|
|
offset, err := m.Converter.ToOffset(line, 1)
|
|
if err != nil {
|
|
return span.Point{}, err
|
|
}
|
|
lineStart := span.NewPoint(line, 1, offset)
|
|
return span.FromUTF16Column(lineStart, int(p.Character)+1, m.Content)
|
|
}
|
|
|
|
func IsPoint(r Range) bool {
|
|
return r.Start.Line == r.End.Line && r.Start.Character == r.End.Character
|
|
}
|
|
|
|
func CompareRange(a, b Range) int {
|
|
if r := ComparePosition(a.Start, b.Start); r != 0 {
|
|
return r
|
|
}
|
|
return ComparePosition(a.End, b.End)
|
|
}
|
|
|
|
func ComparePosition(a, b Position) int {
|
|
if a.Line < b.Line {
|
|
return -1
|
|
}
|
|
if a.Line > b.Line {
|
|
return 1
|
|
}
|
|
if a.Character < b.Character {
|
|
return -1
|
|
}
|
|
if a.Character > b.Character {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func Intersect(a, b Range) bool {
|
|
if a.Start.Line > b.End.Line || a.End.Line < b.Start.Line {
|
|
return false
|
|
}
|
|
return !((a.Start.Line == b.End.Line) && a.Start.Character > b.End.Character ||
|
|
(a.End.Line == b.Start.Line) && a.End.Character < b.Start.Character)
|
|
}
|
|
|
|
func (r Range) Format(f fmt.State, _ rune) {
|
|
fmt.Fprintf(f, "%v:%v-%v:%v", r.Start.Line, r.Start.Character, r.End.Line, r.End.Character)
|
|
}
|