mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
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:
parent
04840ef8f3
commit
73ad5c96a1
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user