1
0
mirror of https://github.com/golang/go synced 2024-11-19 02:04:42 -07:00
go/internal/lsp/source/highlight.go
Rohan Challa 0a33398bd9 internal/lsp: improve highlighting functionality for fields and methods
Modified the way highlights are tested to allow for author to explicitly
mark the matches. Also added highlighting for fields and methods. Used
type checking in addition to ast to get better matching. Worked with
@stamblerre

Updates #34496

Change-Id: I462703e0011c4e0a4b98016e9c25af9bf1ead0b9
Reviewed-on: https://go-review.googlesource.com/c/tools/+/207899
Run-TryBot: Rohan Challa <rohan@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
2019-11-20 18:14:12 +00:00

95 lines
2.1 KiB
Go

// Copyright 2019 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.
package source
import (
"context"
"go/ast"
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry/trace"
errors "golang.org/x/xerrors"
)
func Highlight(ctx context.Context, view View, uri span.URI, pos protocol.Position) ([]protocol.Range, error) {
ctx, done := trace.StartSpan(ctx, "source.Highlight")
defer done()
f, err := view.GetFile(ctx, uri)
if err != nil {
return nil, err
}
_, cphs, err := view.CheckPackageHandles(ctx, f)
if err != nil {
return nil, err
}
cph, err := WidestCheckPackageHandle(cphs)
if err != nil {
return nil, err
}
pkg, err := cph.Check(ctx)
if err != nil {
return nil, err
}
var ph ParseGoHandle
for _, file := range pkg.Files() {
if file.File().Identity().URI == f.URI() {
ph = file
}
}
if ph == nil {
return nil, errors.Errorf("no ParseGoHandle for %s", f.URI())
}
file, m, _, err := ph.Parse(ctx)
if err != nil {
return nil, err
}
spn, err := m.PointSpan(pos)
if err != nil {
return nil, err
}
rng, err := spn.Range(m.Converter)
if err != nil {
return nil, err
}
path, _ := astutil.PathEnclosingInterval(file, rng.Start, rng.Start)
if len(path) == 0 {
return nil, errors.Errorf("no enclosing position found for %v:%v", int(pos.Line), int(pos.Character))
}
result := []protocol.Range{}
id, ok := path[0].(*ast.Ident)
if !ok {
// If the cursor is not within an identifier, return empty results.
return result, nil
}
idObj := pkg.GetTypesInfo().ObjectOf(id)
ast.Inspect(path[len(path)-1], func(node ast.Node) bool {
n, ok := node.(*ast.Ident)
if !ok {
return true
}
if n.Name != id.Name {
return true
}
if n.Obj != id.Obj {
return true
}
nodeObj := pkg.GetTypesInfo().ObjectOf(n)
if nodeObj != idObj {
return false
}
if rng, err := nodeToProtocolRange(ctx, view, m, n); err == nil {
result = append(result, rng)
}
return true
})
return result, nil
}