internal/lsp: switch folding range to protocol ranges

Change-Id: I899b3cd89901b99a5c65a5be79ac561289506623
Reviewed-on: https://go-review.googlesource.com/c/tools/+/193724
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
Rebecca Stambler 2019-09-05 20:14:09 -04:00
parent 04840ef8f3
commit 73ad5c96a1
4 changed files with 71 additions and 58 deletions

View File

@ -15,14 +15,27 @@ func (s *Server) foldingRange(ctx context.Context, params *protocol.FoldingRange
if err != nil {
return nil, err
}
m, err := getMapper(ctx, f)
if err != nil {
return nil, err
}
ranges, err := source.FoldingRange(ctx, view, f, s.session.Options().LineFoldingOnly)
if err != nil {
return nil, err
}
return source.ToProtocolFoldingRanges(m, ranges)
return toProtocolFoldingRanges(ranges)
}
func toProtocolFoldingRanges(ranges []*source.FoldingRangeInfo) ([]protocol.FoldingRange, error) {
result := make([]protocol.FoldingRange, 0, len(ranges))
for _, info := range ranges {
rng, err := info.Range()
if err != nil {
return nil, err
}
result = append(result, protocol.FoldingRange{
StartLine: rng.Start.Line,
StartCharacter: rng.Start.Character,
EndLine: rng.End.Line,
EndCharacter: rng.End.Character,
Kind: string(info.Kind),
})
}
return result, nil
}

View File

@ -27,7 +27,7 @@ func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLink
if err != nil {
return nil, err
}
m, err := getMapper(ctx, f)
data, _, err := f.Handle(ctx).Read(ctx)
if err != nil {
return nil, err
}
@ -35,6 +35,8 @@ func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLink
if file == nil {
return nil, err
}
tok := view.Session().Cache().FileSet().File(file.Pos())
m := protocol.NewColumnMapper(f.URI(), f.URI().Filename(), f.FileSet(), tok, data)
var links []protocol.DocumentLink
ast.Inspect(file, func(node ast.Node) bool {

View File

@ -11,7 +11,7 @@ import (
)
type FoldingRangeInfo struct {
Range span.Range
mappedRange
Kind protocol.FoldingRangeKind
}
@ -24,9 +24,14 @@ func FoldingRange(ctx context.Context, view View, f GoFile, lineFoldingOnly bool
if err != nil {
return nil, err
}
data, _, err := f.Handle(ctx).Read(ctx)
if err != nil {
return nil, err
}
m := protocol.NewColumnMapper(f.URI(), f.URI().Filename(), fset, fset.File(file.Pos()), data)
// Get folding ranges for comments separately as they are not walked by ast.Inspect.
ranges = append(ranges, commentsFoldingRange(f.FileSet(), file)...)
ranges = append(ranges, commentsFoldingRange(view, m, file)...)
foldingFunc := foldingRange
if lineFoldingOnly {
@ -34,29 +39,26 @@ func FoldingRange(ctx context.Context, view View, f GoFile, lineFoldingOnly bool
}
visit := func(n ast.Node) bool {
rng := foldingFunc(fset, n)
rng := foldingFunc(view, m, n)
if rng != nil {
ranges = append(ranges, rng)
}
return true
}
// Walk the ast and collect folding ranges.
ast.Inspect(file, visit)
sort.Slice(ranges, func(i, j int) bool {
if ranges[i].Range.Start < ranges[j].Range.Start {
return true
} else if ranges[i].Range.Start > ranges[j].Range.Start {
return false
}
return ranges[i].Range.End < ranges[j].Range.End
irng, _ := ranges[i].Range()
jrng, _ := ranges[j].Range()
return protocol.CompareRange(irng, jrng) < 0
})
return ranges, nil
}
// foldingRange calculates the folding range for n.
func foldingRange(fset *token.FileSet, n ast.Node) *FoldingRangeInfo {
func foldingRange(view View, m *protocol.ColumnMapper, n ast.Node) *FoldingRangeInfo {
var kind protocol.FoldingRangeKind
var start, end token.Pos
switch n := n.(type) {
@ -80,18 +82,22 @@ func foldingRange(fset *token.FileSet, n ast.Node) *FoldingRangeInfo {
}
start, end = n.Lparen+1, n.Rparen
}
if !start.IsValid() || !end.IsValid() {
return nil
}
return &FoldingRangeInfo{
Range: span.NewRange(fset, start, end),
mappedRange: mappedRange{
m: m,
spanRange: span.NewRange(view.Session().Cache().FileSet(), start, end),
},
Kind: kind,
}
}
// lineFoldingRange calculates the line folding range for n.
func lineFoldingRange(fset *token.FileSet, n ast.Node) *FoldingRangeInfo {
func lineFoldingRange(view View, m *protocol.ColumnMapper, n ast.Node) *FoldingRangeInfo {
fset := view.Session().Cache().FileSet()
// TODO(suzmue): include trailing empty lines before the closing
// parenthesis/brace.
var kind protocol.FoldingRangeKind
@ -169,7 +175,10 @@ func lineFoldingRange(fset *token.FileSet, n ast.Node) *FoldingRangeInfo {
return nil
}
return &FoldingRangeInfo{
Range: span.NewRange(fset, start, end),
mappedRange: mappedRange{
m: m,
spanRange: span.NewRange(fset, start, end),
},
Kind: kind,
}
}
@ -177,39 +186,20 @@ func lineFoldingRange(fset *token.FileSet, n ast.Node) *FoldingRangeInfo {
// commentsFoldingRange returns the folding ranges for all comment blocks in file.
// The folding range starts at the end of the first comment, and ends at the end of the
// comment block and has kind protocol.Comment.
func commentsFoldingRange(fset *token.FileSet, file *ast.File) (comments []*FoldingRangeInfo) {
func commentsFoldingRange(view View, m *protocol.ColumnMapper, file *ast.File) (comments []*FoldingRangeInfo) {
for _, commentGrp := range file.Comments {
// Don't fold single comments.
if len(commentGrp.List) <= 1 {
continue
}
comments = append(comments, &FoldingRangeInfo{
mappedRange: mappedRange{
m: m,
// Fold from the end of the first line comment to the end of the comment block.
Range: span.NewRange(fset, commentGrp.List[0].End(), commentGrp.End()),
spanRange: span.NewRange(view.Session().Cache().FileSet(), commentGrp.List[0].End(), commentGrp.End()),
},
Kind: protocol.Comment,
})
}
return comments
}
func ToProtocolFoldingRanges(m *protocol.ColumnMapper, ranges []*FoldingRangeInfo) ([]protocol.FoldingRange, error) {
var res []protocol.FoldingRange
for _, r := range ranges {
spn, err := r.Range.Span()
if err != nil {
return nil, err
}
rng, err := m.Range(spn)
if err != nil {
return nil, err
}
res = append(res, protocol.FoldingRange{
StartLine: rng.Start.Line,
StartCharacter: rng.Start.Character,
EndLine: rng.End.Line,
EndCharacter: rng.End.Character,
Kind: string(r.Kind),
})
}
return res, nil
}

View File

@ -305,7 +305,7 @@ func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) {
func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, data string, ranges []*source.FoldingRangeInfo) {
t.Helper()
// Fold all ranges.
nonOverlapping := nonOverlappingRanges(ranges)
nonOverlapping := nonOverlappingRanges(t, ranges)
for i, rngs := range nonOverlapping {
got, err := foldRanges(string(data), rngs)
if err != nil {
@ -332,7 +332,7 @@ func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, data s
}
}
nonOverlapping := nonOverlappingRanges(kindOnly)
nonOverlapping := nonOverlappingRanges(t, kindOnly)
for i, rngs := range nonOverlapping {
got, err := foldRanges(string(data), rngs)
if err != nil {
@ -352,13 +352,13 @@ func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, data s
}
}
func nonOverlappingRanges(ranges []*source.FoldingRangeInfo) (res [][]*source.FoldingRangeInfo) {
func nonOverlappingRanges(t *testing.T, ranges []*source.FoldingRangeInfo) (res [][]*source.FoldingRangeInfo) {
for _, fRng := range ranges {
setNum := len(res)
for i := 0; i < len(res); i++ {
canInsert := true
for _, rng := range res[i] {
if conflict(rng, fRng) {
if conflict(t, rng, fRng) {
canInsert = false
break
}
@ -376,9 +376,17 @@ func nonOverlappingRanges(ranges []*source.FoldingRangeInfo) (res [][]*source.Fo
return res
}
func conflict(a, b *source.FoldingRangeInfo) bool {
func conflict(t *testing.T, a, b *source.FoldingRangeInfo) bool {
arng, err := a.Range()
if err != nil {
t.Fatal(err)
}
brng, err := b.Range()
if err != nil {
t.Fatal(err)
}
// a start position is <= b start positions
return a.Range.Start <= b.Range.Start && a.Range.End > b.Range.Start
return protocol.ComparePosition(arng.Start, brng.Start) <= 0 && protocol.ComparePosition(arng.End, brng.Start) > 0
}
func foldRanges(contents string, ranges []*source.FoldingRangeInfo) (string, error) {
@ -388,7 +396,7 @@ func foldRanges(contents string, ranges []*source.FoldingRangeInfo) (string, err
// to preserve the offsets.
for i := len(ranges) - 1; i >= 0; i-- {
fRange := ranges[i]
spn, err := fRange.Range.Span()
spn, err := fRange.Span()
if err != nil {
return "", err
}