diff --git a/gopls/internal/cmd/capabilities_test.go b/gopls/internal/cmd/capabilities_test.go
index 9809b72..a3a438f 100644
--- a/gopls/internal/cmd/capabilities_test.go
+++ b/gopls/internal/cmd/capabilities_test.go
@@ -124,9 +124,15 @@
TextDocument: protocol.TextDocumentIdentifier{
URI: uri,
},
- Position: protocol.Position{
- Line: 0,
- Character: 28,
+ Range: protocol.Range{
+ Start: protocol.Position{
+ Line: 0,
+ Character: 28,
+ },
+ End: protocol.Position{
+ Line: 0,
+ Character: 28,
+ },
},
},
})
diff --git a/gopls/internal/goasm/definition.go b/gopls/internal/goasm/definition.go
index b3c5251..74a27ce 100644
--- a/gopls/internal/goasm/definition.go
+++ b/gopls/internal/goasm/definition.go
@@ -21,7 +21,7 @@
)
// Definition handles the textDocument/definition request for Go assembly files.
-func Definition(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, position protocol.Position) ([]protocol.Location, error) {
+func Definition(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.Location, error) {
ctx, done := event.Start(ctx, "goasm.Definition")
defer done()
@@ -36,7 +36,7 @@
return nil, err
}
mapper := protocol.NewMapper(fh.URI(), content)
- offset, err := mapper.PositionOffset(position)
+ start, end, err := mapper.RangeOffsets(rng)
if err != nil {
return nil, err
}
@@ -51,7 +51,7 @@
// For now, just find the identifier around the cursor.
var found *asm.Ident
for _, id := range file.Idents {
- if id.Offset <= offset && offset <= id.End() {
+ if id.Offset <= start && end <= id.End() {
found = &id
break
}
diff --git a/gopls/internal/golang/call_hierarchy.go b/gopls/internal/golang/call_hierarchy.go
index 194935a..e0cfb60 100644
--- a/gopls/internal/golang/call_hierarchy.go
+++ b/gopls/internal/golang/call_hierarchy.go
@@ -26,7 +26,7 @@
)
// PrepareCallHierarchy returns an array of CallHierarchyItem for a file and the position within the file.
-func PrepareCallHierarchy(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp protocol.Position) ([]protocol.CallHierarchyItem, error) {
+func PrepareCallHierarchy(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.CallHierarchyItem, error) {
ctx, done := event.Start(ctx, "golang.PrepareCallHierarchy")
defer done()
@@ -34,12 +34,11 @@
if err != nil {
return nil, err
}
- pos, err := pgf.PositionPos(pp)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
- // TODO(hxjiang): replace PrepareCallHierarchy's input position with range.
- obj, err := callHierarchyFuncAtPos(pkg.TypesInfo(), pgf, astutil.RangeOf(pos, pos))
+ obj, err := callHierarchyFuncAtPos(pkg.TypesInfo(), pgf, astutil.RangeOf(start, end))
if err != nil {
return nil, err
}
@@ -47,25 +46,27 @@
if err != nil {
return nil, err
}
- rng := declLoc.Range
+ // TODO(hxjiang): right now, the returned call hierachy item is limited to
+ // a single item where the range is. With the range support gopls can return
+ // a slice of CallHierarchyItem based on the input selected range.
return []protocol.CallHierarchyItem{{
Name: obj.Name(),
Kind: protocol.Function,
Tags: []protocol.SymbolTag{},
Detail: callHierarchyItemDetail(obj, declLoc),
URI: declLoc.URI,
- Range: rng,
- SelectionRange: rng,
+ Range: declLoc.Range,
+ SelectionRange: declLoc.Range,
}}, nil
}
// IncomingCalls returns an array of CallHierarchyIncomingCall for a file and the position within the file.
-func IncomingCalls(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pos protocol.Position) ([]protocol.CallHierarchyIncomingCall, error) {
+func IncomingCalls(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.CallHierarchyIncomingCall, error) {
ctx, done := event.Start(ctx, "golang.IncomingCalls")
defer done()
- refs, err := references(ctx, snapshot, fh, pos, false)
+ refs, err := references(ctx, snapshot, fh, rng, false)
if err != nil {
if errors.Is(err, ErrNoIdentFound) || errors.Is(err, errNoObjectFound) {
return nil, nil
diff --git a/gopls/internal/golang/comment.go b/gopls/internal/golang/comment.go
index 517910e..ccc0cfe 100644
--- a/gopls/internal/golang/comment.go
+++ b/gopls/internal/golang/comment.go
@@ -60,8 +60,8 @@
// If there is no reference at pos, returns errNoCommentReference.
//
// TODO(hxjiang): simplify the error handling.
-func docLinkDefinition(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, pos token.Pos) ([]protocol.Location, error) {
- obj, _, err := resolveDocLink(pkg, pgf, astutil.RangeOf(pos, pos))
+func docLinkDefinition(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, start, end token.Pos) ([]protocol.Location, error) {
+ obj, _, err := resolveDocLink(pkg, pgf, astutil.RangeOf(start, end))
if err != nil {
return nil, err
}
diff --git a/gopls/internal/golang/definition.go b/gopls/internal/golang/definition.go
index 1722d9d..42b60fa 100644
--- a/gopls/internal/golang/definition.go
+++ b/gopls/internal/golang/definition.go
@@ -26,7 +26,7 @@
)
// Definition handles the textDocument/definition request for Go files.
-func Definition(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, position protocol.Position) ([]protocol.Location, error) {
+func Definition(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.Location, error) {
ctx, done := event.Start(ctx, "golang.Definition")
defer done()
@@ -34,14 +34,14 @@
if err != nil {
return nil, err
}
- pos, err := pgf.PositionPos(position)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
- cur, _ := pgf.Cursor.FindByPos(pos, pos) // can't fail
+ cur, _ := pgf.Cursor.FindByPos(start, end) // can't fail
- // Handle the case where the cursor is in an import.
- importLocations, err := importDefinition(ctx, snapshot, pkg, pgf, pos)
+ // Handle the case where the range is in an import.
+ importLocations, err := importDefinition(ctx, snapshot, pkg, pgf, start, end)
if err != nil {
return nil, err
}
@@ -51,7 +51,7 @@
// Handle the case where the cursor is in the package name.
// We use "<= End" to accept a query immediately after the package name.
- if pgf.File != nil && astutil.NodeContainsPos(pgf.File.Name, pos) {
+ if pgf.File != nil && astutil.NodeContains(pgf.File.Name, astutil.RangeOf(start, end)) {
// If there's no package documentation, just use current file.
declFile := pgf
for _, pgf := range pkg.CompiledGoFiles() {
@@ -68,19 +68,19 @@
}
// Handle the case where the cursor is in a linkname directive.
- locations, err := linknameDefinition(ctx, snapshot, pgf.Mapper, position)
+ locations, err := linknameDefinition(ctx, snapshot, pgf.Mapper, rng)
if !errors.Is(err, ErrNoLinkname) {
return locations, err // may be success or failure
}
// Handle the case where the cursor is in an embed directive.
- locations, err = embedDefinition(pgf.Mapper, position)
+ locations, err = embedDefinition(pgf.Mapper, rng)
if !errors.Is(err, ErrNoEmbed) {
return locations, err // may be success or failure
}
// Handle the case where the cursor is in a doc link.
- locations, err = docLinkDefinition(ctx, snapshot, pkg, pgf, pos)
+ locations, err = docLinkDefinition(ctx, snapshot, pkg, pgf, start, end)
if !errors.Is(err, errNoCommentReference) {
return locations, err // may be success or failure
}
@@ -195,7 +195,7 @@
for _, decl := range pgf.File.Decls {
if decl, ok := decl.(*ast.FuncDecl); ok &&
decl.Body == nil &&
- astutil.NodeContainsPos(decl.Name, pos) {
+ astutil.NodeContains(decl.Name, astutil.RangeOf(start, end)) {
return nonGoDefinition(ctx, snapshot, pkg, decl.Name.Name)
}
}
@@ -326,11 +326,11 @@
// import spec containing pos.
//
// If pos is not inside an import spec, it returns nil, nil.
-func importDefinition(ctx context.Context, s *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, pos token.Pos) ([]protocol.Location, error) {
+func importDefinition(ctx context.Context, s *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, start, end token.Pos) ([]protocol.Location, error) {
var imp *ast.ImportSpec
for _, spec := range pgf.File.Imports {
// We use "<= End" to accept a query immediately after an ImportSpec.
- if astutil.NodeContainsPos(spec.Path, pos) {
+ if astutil.NodeContains(spec.Path, astutil.RangeOf(start, end)) {
imp = spec
}
}
diff --git a/gopls/internal/golang/embeddirective.go b/gopls/internal/golang/embeddirective.go
index 33f4f5e..8a1051a 100644
--- a/gopls/internal/golang/embeddirective.go
+++ b/gopls/internal/golang/embeddirective.go
@@ -27,8 +27,8 @@
// embedDefinition finds a file matching the embed directive at pos in the mapped file.
// If there is no embed directive at pos, returns ErrNoEmbed.
// If multiple files match the embed pattern, one is picked at random.
-func embedDefinition(m *protocol.Mapper, pos protocol.Position) ([]protocol.Location, error) {
- pattern, _ := parseEmbedDirective(m, protocol.Range{Start: pos, End: pos})
+func embedDefinition(m *protocol.Mapper, rng protocol.Range) ([]protocol.Location, error) {
+ pattern, _ := parseEmbedDirective(m, rng)
if pattern == "" {
return nil, ErrNoEmbed
}
diff --git a/gopls/internal/golang/highlight.go b/gopls/internal/golang/highlight.go
index 874db3a..c7d135c 100644
--- a/gopls/internal/golang/highlight.go
+++ b/gopls/internal/golang/highlight.go
@@ -22,7 +22,7 @@
"golang.org/x/tools/internal/fmtstr"
)
-func Highlight(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, position protocol.Position) ([]protocol.DocumentHighlight, error) {
+func Highlight(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.DocumentHighlight, error) {
ctx, done := event.Start(ctx, "golang.Highlight")
defer done()
@@ -33,27 +33,27 @@
return nil, fmt.Errorf("getting package for Highlight: %w", err)
}
- pos, err := pgf.PositionPos(position)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
- path, _ := goastutil.PathEnclosingInterval(pgf.File, pos, pos)
+ path, _ := goastutil.PathEnclosingInterval(pgf.File, start, end)
if len(path) == 0 {
- return nil, fmt.Errorf("no enclosing position found for %v:%v", position.Line, position.Character)
+ return nil, fmt.Errorf("no enclosing position found for %v:%v-%v:%v", rng.Start.Line, rng.Start.Character, rng.End.Line, rng.End.Character)
}
// If start == end for astutil.PathEnclosingInterval, the 1-char interval
// following start is used instead. As a result, we might not get an exact
// match so we should check the 1-char interval to the left of the passed
// in position to see if that is an exact match.
if _, ok := path[0].(*ast.Ident); !ok {
- if p, _ := goastutil.PathEnclosingInterval(pgf.File, pos-1, pos-1); p != nil {
+ if p, _ := goastutil.PathEnclosingInterval(pgf.File, start-1, end-1); p != nil {
switch p[0].(type) {
case *ast.Ident, *ast.SelectorExpr:
path = p // use preceding ident/selector
}
}
}
- result, err := highlightPath(pkg.TypesInfo(), path, pos)
+ result, err := highlightPath(pkg.TypesInfo(), path, start)
if err != nil {
return nil, err
}
diff --git a/gopls/internal/golang/implementation.go b/gopls/internal/golang/implementation.go
index d1fd590..1863949 100644
--- a/gopls/internal/golang/implementation.go
+++ b/gopls/internal/golang/implementation.go
@@ -54,11 +54,11 @@
//
// If the position denotes a method, the computation is applied to its
// receiver type and then its corresponding methods are returned.
-func Implementation(ctx context.Context, snapshot *cache.Snapshot, f file.Handle, pp protocol.Position) ([]protocol.Location, error) {
+func Implementation(ctx context.Context, snapshot *cache.Snapshot, f file.Handle, rng protocol.Range) ([]protocol.Location, error) {
ctx, done := event.Start(ctx, "golang.Implementation")
defer done()
- locs, err := implementations(ctx, snapshot, f, pp)
+ locs, err := implementations(ctx, snapshot, f, rng)
if err != nil {
return nil, err
}
@@ -67,20 +67,20 @@
return locs, nil
}
-func implementations(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp protocol.Position) ([]protocol.Location, error) {
+func implementations(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.Location, error) {
// Type check the current package.
pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
if err != nil {
return nil, err
}
- pos, err := pgf.PositionPos(pp)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
- cur, _ := pgf.Cursor.FindByPos(pos, pos) // can't fail
+ cur, _ := pgf.Cursor.FindByPos(start, end) // can't fail
// Find implementations based on func signatures.
- if locs, err := implFuncs(pkg, cur, pos); err != errNotHandled {
+ if locs, err := implFuncs(pkg, cur, start, end); err != errNotHandled {
return locs, err
}
@@ -890,7 +890,7 @@
//
// implFuncs returns errNotHandled to indicate that we should try the
// regular method-sets algorithm.
-func implFuncs(pkg *cache.Package, curSel inspector.Cursor, pos token.Pos) ([]protocol.Location, error) {
+func implFuncs(pkg *cache.Package, curSel inspector.Cursor, start, end token.Pos) ([]protocol.Location, error) {
info := pkg.TypesInfo()
if info.Types == nil || info.Defs == nil || info.Uses == nil {
panic("one of info.Types, .Defs or .Uses is nil")
@@ -918,7 +918,7 @@
) {
switch n := cur.Node().(type) {
case *ast.FuncDecl, *ast.FuncLit:
- if inToken(n.Pos(), "func", pos) {
+ if inToken(n.Pos(), "func", start, end) {
// Case 1: concrete function declaration.
// Report uses of corresponding function types.
switch n := n.(type) {
@@ -930,14 +930,14 @@
}
case *ast.FuncType:
- if n.Func.IsValid() && inToken(n.Func, "func", pos) && !beneathFuncDef(cur) {
+ if n.Func.IsValid() && inToken(n.Func, "func", start, end) && !beneathFuncDef(cur) {
// Case 2a: function type.
// Report declarations of corresponding concrete functions.
return funcDefs(pkg, info.TypeOf(n))
}
case *ast.CallExpr:
- if inToken(n.Lparen, "(", pos) {
+ if inToken(n.Lparen, "(", start, end) {
t := dynamicFuncCallType(info, n)
if t == nil {
return nil, fmt.Errorf("not a dynamic function call")
@@ -1059,8 +1059,8 @@
return nil
}
-// inToken reports whether pos is within the token of
+// inToken reports whether range is within the token of
// the specified position and string.
-func inToken(tokPos token.Pos, tokStr string, pos token.Pos) bool {
- return tokPos <= pos && pos <= tokPos+token.Pos(len(tokStr))
+func inToken(tokPos token.Pos, tokStr string, start, end token.Pos) bool {
+ return tokPos <= start && end <= tokPos+token.Pos(len(tokStr))
}
diff --git a/gopls/internal/golang/inline_all.go b/gopls/internal/golang/inline_all.go
index 59109cd..9b8697f 100644
--- a/gopls/internal/golang/inline_all.go
+++ b/gopls/internal/golang/inline_all.go
@@ -51,7 +51,7 @@
// Collect references.
var refs []protocol.Location
{
- funcPos, err := pgf.Mapper.PosPosition(pgf.Tok, origDecl.Name.NamePos)
+ funcRng, err := pgf.Mapper.PosRange(pgf.Tok, origDecl.Name.NamePos, origDecl.Name.NamePos)
if err != nil {
return nil, err
}
@@ -59,7 +59,7 @@
if err != nil {
return nil, err
}
- refs, err = References(ctx, snapshot, fh, funcPos, false)
+ refs, err = References(ctx, snapshot, fh, funcRng, false)
if err != nil {
return nil, fmt.Errorf("finding references to rewrite: %v", err)
}
diff --git a/gopls/internal/golang/linkname.go b/gopls/internal/golang/linkname.go
index f125092..1156d15 100644
--- a/gopls/internal/golang/linkname.go
+++ b/gopls/internal/golang/linkname.go
@@ -24,8 +24,8 @@
// linknameDefinition finds the definition of the linkname directive in m at pos.
// If there is no linkname directive at pos, returns ErrNoLinkname.
-func linknameDefinition(ctx context.Context, snapshot *cache.Snapshot, m *protocol.Mapper, from protocol.Position) ([]protocol.Location, error) {
- pkgPath, name, _ := parseLinkname(m, protocol.Range{Start: from, End: from})
+func linknameDefinition(ctx context.Context, snapshot *cache.Snapshot, m *protocol.Mapper, from protocol.Range) ([]protocol.Location, error) {
+ pkgPath, name, _ := parseLinkname(m, from)
if pkgPath == "" {
return nil, ErrNoLinkname
}
diff --git a/gopls/internal/golang/references.go b/gopls/internal/golang/references.go
index 140e20c..af226e8 100644
--- a/gopls/internal/golang/references.go
+++ b/gopls/internal/golang/references.go
@@ -42,8 +42,8 @@
// References returns a list of all references (sorted with
// definitions before uses) to the object denoted by the identifier at
// the given file/position, searching the entire workspace.
-func References(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp protocol.Position, includeDeclaration bool) ([]protocol.Location, error) {
- references, err := references(ctx, snapshot, fh, pp, includeDeclaration)
+func References(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range, includeDeclaration bool) ([]protocol.Location, error) {
+ references, err := references(ctx, snapshot, fh, rng, includeDeclaration)
if err != nil {
return nil, err
}
@@ -65,12 +65,12 @@
// references returns a list of all references (sorted with
// definitions before uses) to the object denoted by the identifier at
// the given file/position, searching the entire workspace.
-func references(ctx context.Context, snapshot *cache.Snapshot, f file.Handle, pp protocol.Position, includeDeclaration bool) ([]reference, error) {
+func references(ctx context.Context, snapshot *cache.Snapshot, f file.Handle, rng protocol.Range, includeDeclaration bool) ([]reference, error) {
ctx, done := event.Start(ctx, "golang.references")
defer done()
// Is the cursor within the package name declaration?
- _, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp)
+ _, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, rng)
if err != nil {
return nil, err
}
@@ -79,7 +79,7 @@
if inPackageName {
refs, err = packageReferences(ctx, snapshot, f.URI())
} else {
- refs, err = ordinaryReferences(ctx, snapshot, f.URI(), pp)
+ refs, err = ordinaryReferences(ctx, snapshot, f.URI(), rng)
}
if err != nil {
return nil, err
@@ -215,7 +215,7 @@
}
// ordinaryReferences computes references for all ordinary objects (not package declarations).
-func ordinaryReferences(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI, pp protocol.Position) ([]reference, error) {
+func ordinaryReferences(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI, rng protocol.Range) ([]reference, error) {
// Strategy: use the reference information computed by the
// type checker to find the declaration. First type-check this
// package to find the declaration, then type check the
@@ -234,11 +234,11 @@
// Find the selected object (declaration or reference).
// For struct{T}, we choose the field (Def) over the type (Use).
- pos, err := pgf.PositionPos(pp)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
- cur, _ := pgf.Cursor.FindByPos(pos, pos) // can't fail
+ cur, _ := pgf.Cursor.FindByPos(start, end) // can't fail
candidates, err := objectsAt(pkg.TypesInfo(), cur)
if err != nil {
diff --git a/gopls/internal/golang/rename.go b/gopls/internal/golang/rename.go
index c9ca2c5..640a49f 100644
--- a/gopls/internal/golang/rename.go
+++ b/gopls/internal/golang/rename.go
@@ -106,12 +106,12 @@
// The returned usererr is intended to be displayed to the user to explain why
// the prepare fails. Probably we could eliminate the redundancy in returning
// two errors, but for now this is done defensively.
-func PrepareRename(ctx context.Context, snapshot *cache.Snapshot, f file.Handle, pp protocol.Position) (_ *PrepareItem, usererr, err error) {
+func PrepareRename(ctx context.Context, snapshot *cache.Snapshot, f file.Handle, rng protocol.Range) (_ *PrepareItem, usererr, err error) {
ctx, done := event.Start(ctx, "golang.PrepareRename")
defer done()
// Is the cursor within the package name declaration?
- if pgf, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp); err != nil {
+ if pgf, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, rng); err != nil {
return nil, err, err
} else if inPackageName {
item, err := prepareRenamePackageName(ctx, snapshot, pgf)
@@ -131,15 +131,15 @@
if err != nil {
return nil, nil, err
}
- pos, err := pgf.PositionPos(pp)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, nil, err
}
- cur, _ := pgf.Cursor.FindByPos(pos, pos) // can't fail
+ cur, _ := pgf.Cursor.FindByPos(start, end) // can't fail
// Check if we're in a 'func' keyword. If so, we hijack the renaming to
// change the function signature.
- if item, err := prepareRenameFuncSignature(pgf, pos, cur); err != nil {
+ if item, err := prepareRenameFuncSignature(pgf, start, end, cur); err != nil {
return nil, nil, err
} else if item != nil {
return item, nil, nil
@@ -151,7 +151,7 @@
// objectsAt will have returned an error in this case.
// TODO(adonovan): move this logic into objectsAt.
var ok bool
- cur, ok = docCommentPosToIdent(pgf, pos, cur)
+ cur, ok = docCommentPosToIdent(pgf, start, end, cur)
if !ok {
return nil, nil, err
}
@@ -170,16 +170,16 @@
if err := checkRenamable(obj, node); err != nil {
return nil, nil, err
}
- rng, err := pgf.NodeRange(node)
+ nodeRng, err := pgf.NodeRange(node)
if err != nil {
return nil, nil, err
}
if _, isImport := node.(*ast.ImportSpec); isImport {
// We're not really renaming the import path.
- rng.End = rng.Start
+ nodeRng.End = nodeRng.Start
}
return &PrepareItem{
- Range: rng,
+ Range: nodeRng,
Text: obj.Name(),
}, nil, nil
}
@@ -228,8 +228,8 @@
//
// The resulting text is the signature of the function, which may be edited to
// the new signature.
-func prepareRenameFuncSignature(pgf *parsego.File, pos token.Pos, cursor inspector.Cursor) (*PrepareItem, error) {
- fdecl := funcKeywordDecl(pos, cursor)
+func prepareRenameFuncSignature(pgf *parsego.File, start, end token.Pos, cursor inspector.Cursor) (*PrepareItem, error) {
+ fdecl := funcKeywordDecl(start, end, cursor)
if fdecl == nil {
return nil, nil
}
@@ -283,8 +283,8 @@
// renameFuncSignature computes and applies the effective change signature
// operation resulting from a 'renamed' (=rewritten) signature.
-func renameFuncSignature(ctx context.Context, pkg *cache.Package, pgf *parsego.File, pos token.Pos, snapshot *cache.Snapshot, cursor inspector.Cursor, f file.Handle, pp protocol.Position, newName string) (map[protocol.DocumentURI][]protocol.TextEdit, error) {
- fdecl := funcKeywordDecl(pos, cursor)
+func renameFuncSignature(ctx context.Context, pkg *cache.Package, pgf *parsego.File, start, end token.Pos, snapshot *cache.Snapshot, cursor inspector.Cursor, f file.Handle, rng protocol.Range, newName string) (map[protocol.DocumentURI][]protocol.TextEdit, error) {
+ fdecl := funcKeywordDecl(start, end, cursor)
if fdecl == nil {
return nil, nil
}
@@ -343,11 +343,11 @@
newParams = append(newParams, info.idx)
}
- rng, err := pgf.PosRange(ftyp.Func, ftyp.Func)
+ funcRng, err := pgf.PosRange(ftyp.Func, ftyp.Func)
if err != nil {
return nil, err
}
- changes, err := ChangeSignature(ctx, snapshot, pkg, pgf, rng, newParams)
+ changes, err := ChangeSignature(ctx, snapshot, pkg, pgf, funcRng, newParams)
if err != nil {
return nil, err
}
@@ -360,13 +360,13 @@
// funcKeywordDecl returns the FuncDecl for which pos is in the 'func' keyword,
// if any.
-func funcKeywordDecl(pos token.Pos, cursor inspector.Cursor) *ast.FuncDecl {
+func funcKeywordDecl(start, end token.Pos, cursor inspector.Cursor) *ast.FuncDecl {
fdecl, _ := cursorutil.FirstEnclosing[*ast.FuncDecl](cursor)
if fdecl == nil {
return nil
}
ftyp := fdecl.Type
- if pos < ftyp.Func || pos > ftyp.Func+token.Pos(len("func")) { // tolerate renaming immediately after 'func'
+ if start < ftyp.Func || end > ftyp.Func+token.Pos(len("func")) { // tolerate renaming immediately after 'func'
return nil
}
return fdecl
@@ -410,7 +410,7 @@
// Rename returns a map of TextEdits for each file modified when renaming a
// given identifier within a package.
-func Rename(ctx context.Context, snapshot *cache.Snapshot, f file.Handle, pp protocol.Position, newName string) ([]protocol.DocumentChange, error) {
+func Rename(ctx context.Context, snapshot *cache.Snapshot, f file.Handle, rng protocol.Range, newName string) ([]protocol.DocumentChange, error) {
ctx, done := event.Start(ctx, "golang.Rename")
defer done()
@@ -418,24 +418,24 @@
if err != nil {
return nil, err
}
- pos, err := pgf.PositionPos(pp)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
- cur, ok := pgf.Cursor.FindByPos(pos, pos)
+ cur, ok := pgf.Cursor.FindByPos(start, end)
if !ok {
return nil, fmt.Errorf("can't find cursor for selection")
}
- if edits, err := renameFuncSignature(ctx, pkg, pgf, pos, snapshot, cur, f, pp, newName); err != nil {
+ if edits, err := renameFuncSignature(ctx, pkg, pgf, start, end, snapshot, cur, f, rng, newName); err != nil {
return nil, err
} else if edits != nil {
return editsToDocChanges(ctx, snapshot, edits)
}
// Cursor within package name declaration?
- _, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp)
+ _, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, rng)
if err != nil {
return nil, err
}
@@ -463,7 +463,7 @@
if !isValidIdentifier(newName) {
return nil, fmt.Errorf("invalid identifier to rename: %q", newName)
}
- editMap, err = renameOrdinary(ctx, snapshot, f.URI(), pp, newName)
+ editMap, err = renameOrdinary(ctx, snapshot, f.URI(), rng, newName)
if err != nil {
return nil, err
}
@@ -561,7 +561,7 @@
}
// renameOrdinary renames an ordinary (non-package) name throughout the workspace.
-func renameOrdinary(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI, pp protocol.Position, newName string) (map[protocol.DocumentURI][]diff.Edit, error) {
+func renameOrdinary(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI, rng protocol.Range, newName string) (map[protocol.DocumentURI][]diff.Edit, error) {
// Type-check the referring package and locate the object(s).
//
// Unlike NarrowestPackageForFile, this operation prefers the
@@ -586,11 +586,11 @@
if err != nil {
return nil, err // "can't happen"
}
- pos, err := pgf.PositionPos(pp)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
- cur, _ := pgf.Cursor.FindByPos(pos, pos) // cannot fail
+ cur, _ := pgf.Cursor.FindByPos(start, end) // cannot fail
targets, err := objectsAt(pkg.TypesInfo(), cur)
if err != nil {
@@ -598,7 +598,7 @@
// objectsAt will have returned an error in this case.
// TODO(adonovan): move this logic into objectsAt.
var ok bool
- cur, ok = docCommentPosToIdent(pgf, pos, cur)
+ cur, ok = docCommentPosToIdent(pgf, start, end, cur)
if !ok {
return nil, err
}
@@ -631,7 +631,7 @@
if err != nil {
return nil, err
}
- return renameOrdinary(ctx, snapshot, loc.URI, loc.Range.Start, newName)
+ return renameOrdinary(ctx, snapshot, loc.URI, loc.Range, newName)
}
}
}
@@ -1752,31 +1752,31 @@
// docCommentPosToIdent returns a cursor for the identifier whose doc
// comment contains pos, if any. The pos must be within an occurrence
// of the identifier's name, otherwise it returns zero.
-func docCommentPosToIdent(pgf *parsego.File, pos token.Pos, cur inspector.Cursor) (inspector.Cursor, bool) {
+func docCommentPosToIdent(pgf *parsego.File, start, end token.Pos, cur inspector.Cursor) (inspector.Cursor, bool) {
for curId := range cur.Preorder((*ast.Ident)(nil)) {
id := curId.Node().(*ast.Ident)
- if pos > id.Pos() {
+ if start > id.Pos() {
continue // Doc comments are not located after an ident.
}
doc := docComment(pgf, curId)
- if doc == nil || !(doc.Pos() <= pos && pos < doc.End()) {
+ if doc == nil || !(doc.Pos() <= start && end < doc.End()) {
continue
}
docRegexp := regexp.MustCompile(`\b` + id.Name + `\b`)
for _, comment := range doc.List {
- if isDirective(comment.Text) || !(comment.Pos() <= pos && pos < comment.End()) {
+ if isDirective(comment.Text) || !(comment.Pos() <= start && end < comment.End()) {
continue
}
- start := comment.Pos()
+ commentStart := comment.Pos()
text, err := pgf.NodeText(comment)
if err != nil {
return inspector.Cursor{}, false
}
for _, locs := range docRegexp.FindAllIndex(text, -1) {
- matchStart := start + token.Pos(locs[0])
- matchEnd := start + token.Pos(locs[1])
- if matchStart <= pos && pos <= matchEnd {
+ matchStart := commentStart + token.Pos(locs[0])
+ matchEnd := commentStart + token.Pos(locs[1])
+ if matchStart <= start && end <= matchEnd {
return curId, true
}
}
@@ -1814,15 +1814,15 @@
// whether the position ppos lies within it.
//
// Note: also used by references.
-func parsePackageNameDecl(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, ppos protocol.Position) (*parsego.File, bool, error) {
+func parsePackageNameDecl(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) (*parsego.File, bool, error) {
pgf, err := snapshot.ParseGo(ctx, fh, parsego.Header)
if err != nil {
return nil, false, err
}
// Careful: because we used parsego.Header,
// pgf.Pos(ppos) may be beyond EOF => (0, err).
- pos, _ := pgf.PositionPos(ppos)
- return pgf, astutil.NodeContainsPos(pgf.File.Name, pos), nil
+ start, end, _ := pgf.RangePos(rng)
+ return pgf, astutil.NodeContains(pgf.File.Name, astutil.RangeOf(start, end)), nil
}
// posEdit returns an edit to replace the (start, end) range of tf with 'new'.
diff --git a/gopls/internal/golang/signature_help.go b/gopls/internal/golang/signature_help.go
index 260bd0f..3c97112 100644
--- a/gopls/internal/golang/signature_help.go
+++ b/gopls/internal/golang/signature_help.go
@@ -23,7 +23,7 @@
// SignatureHelp returns information about the signature of the innermost
// function call enclosing the position, or nil if there is none.
-func SignatureHelp(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, params *protocol.SignatureHelpParams) (*protocol.SignatureInformation, error) {
+func SignatureHelp(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range, context *protocol.SignatureHelpContext) (*protocol.SignatureInformation, error) {
ctx, done := event.Start(ctx, "golang.SignatureHelp")
defer done()
@@ -33,13 +33,13 @@
if err != nil {
return nil, fmt.Errorf("getting file for SignatureHelp: %w", err)
}
- pos, err := pgf.PositionPos(params.Position)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
// Find a call expression surrounding the query position.
var callExpr *ast.CallExpr
- path, _ := astutil.PathEnclosingInterval(pgf.File, pos, pos)
+ path, _ := astutil.PathEnclosingInterval(pgf.File, start, end)
if path == nil {
return nil, fmt.Errorf("cannot find node enclosing position")
}
@@ -66,7 +66,7 @@
}
case *ast.CallExpr:
// Beware: the ')' may be missing.
- if node.Lparen <= pos && pos <= node.Rparen {
+ if node.Lparen <= start && end <= node.Rparen {
callExpr = node
fnval = callExpr.Fun
break loop
@@ -81,7 +81,7 @@
// golang/go#43397: don't offer signature help when the user is typing
// in a string literal unless it was manually invoked or help is already active.
if node.Kind == token.STRING &&
- (params.Context == nil || (params.Context.TriggerKind != protocol.SigInvoked && !params.Context.IsRetrigger)) {
+ (context == nil || (context.TriggerKind != protocol.SigInvoked && !context.IsRetrigger)) {
return nil, nil
}
}
@@ -128,7 +128,7 @@
if err != nil {
return nil, err
}
- return signatureInformation(s, snapshot.Options(), pos, callExpr)
+ return signatureInformation(s, snapshot.Options(), start, end, callExpr)
}
mq := MetadataQualifierForFile(snapshot, pgf.File, pkg.Metadata())
@@ -153,10 +153,10 @@
return nil, err
}
s.name = name
- return signatureInformation(s, snapshot.Options(), pos, callExpr)
+ return signatureInformation(s, snapshot.Options(), start, end, callExpr)
}
-func signatureInformation(sig *signature, options *settings.Options, pos token.Pos, call *ast.CallExpr) (*protocol.SignatureInformation, error) {
+func signatureInformation(sig *signature, options *settings.Options, start, end token.Pos, call *ast.CallExpr) (*protocol.SignatureInformation, error) {
paramInfo := make([]protocol.ParameterInformation, 0, len(sig.params))
for _, p := range sig.params {
paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p})
@@ -165,13 +165,13 @@
Label: sig.name + sig.Format(),
Documentation: stringToSigInfoDocumentation(sig.doc, options),
Parameters: paramInfo,
- ActiveParameter: activeParameter(sig, pos, call),
+ ActiveParameter: activeParameter(sig, start, end, call),
}, nil
}
// activeParameter returns a pointer to a variable containing
// the index of the active parameter (if known), or nil otherwise.
-func activeParameter(sig *signature, pos token.Pos, call *ast.CallExpr) *uint32 {
+func activeParameter(sig *signature, start, end token.Pos, call *ast.CallExpr) *uint32 {
if call == nil {
return nil
}
@@ -180,13 +180,13 @@
return nil
}
// Check if the position is even in the range of the arguments.
- if !(call.Lparen < pos && pos <= call.Rparen) {
+ if !(call.Lparen < start && end <= call.Rparen) {
return nil
}
var activeParam uint32
for _, arg := range call.Args {
- if pos <= arg.End() {
+ if end <= arg.End() {
break
}
// Don't advance the active parameter for the last parameter of a variadic function.
diff --git a/gopls/internal/golang/type_hierarchy.go b/gopls/internal/golang/type_hierarchy.go
index b1448ad..f2e72b7 100644
--- a/gopls/internal/golang/type_hierarchy.go
+++ b/gopls/internal/golang/type_hierarchy.go
@@ -33,18 +33,18 @@
// - fix pkg=command-line-arguments problem with query initiated at "error" in builtins.go
// PrepareTypeHierarchy returns the TypeHierarchyItems for the types at the selected position.
-func PrepareTypeHierarchy(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp protocol.Position) ([]protocol.TypeHierarchyItem, error) {
+func PrepareTypeHierarchy(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.TypeHierarchyItem, error) {
pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
if err != nil {
return nil, err
}
- pos, err := pgf.PositionPos(pp)
+ start, end, err := pgf.RangePos(rng)
if err != nil {
return nil, err
}
// For now, we require that the selection be a type name.
- cur, ok := pgf.Cursor.FindByPos(pos, pos)
+ cur, ok := pgf.Cursor.FindByPos(start, end)
if !ok {
return nil, fmt.Errorf("no enclosing syntax") // can't happen
}
diff --git a/gopls/internal/mcp/references.go b/gopls/internal/mcp/references.go
index a95c1f7..d49bce1 100644
--- a/gopls/internal/mcp/references.go
+++ b/gopls/internal/mcp/references.go
@@ -28,7 +28,7 @@
}
defer release()
pos := params.Location.Range.Start
- refs, err := golang.References(ctx, snapshot, fh, pos, true)
+ refs, err := golang.References(ctx, snapshot, fh, protocol.Range{Start: pos, End: pos}, true)
if err != nil {
return nil, nil, err
}
diff --git a/gopls/internal/mcp/rename_symbol.go b/gopls/internal/mcp/rename_symbol.go
index d94021c..0534e29 100644
--- a/gopls/internal/mcp/rename_symbol.go
+++ b/gopls/internal/mcp/rename_symbol.go
@@ -38,7 +38,7 @@
if err != nil {
return nil, nil, err
}
- changes, err := golang.Rename(ctx, snapshot, fh, loc.Range.Start, params.NewName)
+ changes, err := golang.Rename(ctx, snapshot, fh, loc.Range, params.NewName)
if err != nil {
return nil, nil, err
}
diff --git a/gopls/internal/mcp/symbol_references.go b/gopls/internal/mcp/symbol_references.go
index d38cb70..e9966e0 100644
--- a/gopls/internal/mcp/symbol_references.go
+++ b/gopls/internal/mcp/symbol_references.go
@@ -49,7 +49,7 @@
if err != nil {
return nil, nil, err
}
- refs, err := golang.References(ctx, snapshot, declFH, loc.Range.Start, true)
+ refs, err := golang.References(ctx, snapshot, declFH, loc.Range, true)
if err != nil {
return nil, nil, err
}
diff --git a/gopls/internal/mod/hover.go b/gopls/internal/mod/hover.go
index 26cd5e2..d93b373 100644
--- a/gopls/internal/mod/hover.go
+++ b/gopls/internal/mod/hover.go
@@ -25,7 +25,7 @@
"golang.org/x/tools/internal/event"
)
-func Hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, position protocol.Position) (*protocol.Hover, error) {
+func Hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) (*protocol.Hover, error) {
// We only provide hover information for the view's go.mod files.
if !slices.Contains(snapshot.View().ModFiles(), fh.URI()) {
return nil, nil
@@ -39,22 +39,22 @@
if err != nil {
return nil, fmt.Errorf("getting modfile handle: %w", err)
}
- offset, err := pm.Mapper.PositionOffset(position)
+ startOffset, endOffset, err := pm.Mapper.RangeOffsets(rng)
if err != nil {
return nil, fmt.Errorf("computing cursor position: %w", err)
}
// If the cursor position is on a module statement
- if hover, ok := hoverOnModuleStatement(ctx, pm, offset, snapshot, fh); ok {
+ if hover, ok := hoverOnModuleStatement(ctx, pm, startOffset, endOffset, snapshot, fh); ok {
return hover, nil
}
- return hoverOnRequireStatement(ctx, pm, offset, snapshot, fh)
+ return hoverOnRequireStatement(ctx, pm, startOffset, endOffset, snapshot, fh)
}
-func hoverOnRequireStatement(ctx context.Context, pm *cache.ParsedModule, offset int, snapshot *cache.Snapshot, fh file.Handle) (*protocol.Hover, error) {
+func hoverOnRequireStatement(ctx context.Context, pm *cache.ParsedModule, startOffset, endOffset int, snapshot *cache.Snapshot, fh file.Handle) (*protocol.Hover, error) {
// Confirm that the cursor is at the position of a require statement.
var req *modfile.Require
- var startOffset, endOffset int
+ var depStartOffset, depEndOffset int
for _, r := range pm.File.Require {
dep := []byte(r.Mod.Path)
s, e := r.Syntax.Start.Byte, r.Syntax.End.Byte
@@ -64,8 +64,8 @@
}
// Shift the start position to the location of the
// dependency within the require statement.
- startOffset, endOffset = s+i, e
- if startOffset <= offset && offset <= endOffset {
+ depStartOffset, depEndOffset = s+i, e
+ if depStartOffset <= startOffset && endOffset <= depEndOffset {
req = r
break
}
@@ -122,12 +122,12 @@
}, nil
}
-func hoverOnModuleStatement(ctx context.Context, pm *cache.ParsedModule, offset int, snapshot *cache.Snapshot, fh file.Handle) (*protocol.Hover, bool) {
+func hoverOnModuleStatement(ctx context.Context, pm *cache.ParsedModule, startOffset, endOffset int, snapshot *cache.Snapshot, fh file.Handle) (*protocol.Hover, bool) {
module := pm.File.Module
if module == nil {
return nil, false // no module stmt
}
- if offset < module.Syntax.Start.Byte || offset > module.Syntax.End.Byte {
+ if endOffset < module.Syntax.Start.Byte || startOffset > module.Syntax.End.Byte {
return nil, false // cursor not in module stmt
}
diff --git a/gopls/internal/protocol/generate/output.go b/gopls/internal/protocol/generate/output.go
index 3f2206b..963aed8 100644
--- a/gopls/internal/protocol/generate/output.go
+++ b/gopls/internal/protocol/generate/output.go
@@ -119,14 +119,23 @@
out.WriteString("\t\t\treturn nil, true, fmt.Errorf(\"%%w: %%s\", jsonrpc2.ErrParse, err)\n\t\t}\n")
p = ", ¶ms"
- // If the parameter extends the TextDocumentPositionParam, verify the
- // position is within the provided range.
+ // Ensure consistency between Range and Position. If the client provides
+ // only a Position, synthesize a zero-width Range at that location.
+ //
+ // Crucially, we do not clear the Position field. Since this request is
+ // forwarded, the downstream receiver (gopls) will re-validate that the
+ // Position lies within the Range.
if extends(nm, "TextDocumentPositionParams") {
- out.WriteString(` if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ out.WriteString(` if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %%v is outside the provided range %%v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
`)
-
}
}
@@ -314,6 +323,11 @@
json = fmt.Sprintf(" `json:\"%s,omitempty\"`", p.Name)
}
generateDoc(out, p.Documentation)
+ if docs := appendTypePropDocComments[name]; docs != nil {
+ if doc, ok := docs[p.Name]; ok {
+ out.WriteString(doc)
+ }
+ }
if star {
fmt.Fprintf(out, "\t%s *%s %s\n", goName(p.Name), tp, json)
} else {
diff --git a/gopls/internal/protocol/generate/tables.go b/gopls/internal/protocol/generate/tables.go
index e8b965a..1aa12d0 100644
--- a/gopls/internal/protocol/generate/tables.go
+++ b/gopls/internal/protocol/generate/tables.go
@@ -302,6 +302,14 @@
// properties (e.g. edits, commands) it's waiting for.`,
}
+// prependMethodDocComments specifies doc comments that will be prepend to
+// an LSP type's properties existing doc comments.
+var appendTypePropDocComments = map[string]map[string]string{
+ "TextDocumentPositionParams": {"position": ` //
+ // Deprecated: gopls should use [TextDocumentPositionParams.Range] instead.
+`},
+}
+
// appendTypeProp specifies block of code (typically properties with doc comment)
// that will be append to a struct.
var appendTypeProp = map[string]string{
diff --git a/gopls/internal/protocol/mapper.go b/gopls/internal/protocol/mapper.go
index 6a92a2c..c7977cf 100644
--- a/gopls/internal/protocol/mapper.go
+++ b/gopls/internal/protocol/mapper.go
@@ -362,6 +362,7 @@
func LocationTextDocumentPositionParams(loc Location) TextDocumentPositionParams {
return TextDocumentPositionParams{
TextDocument: TextDocumentIdentifier{URI: loc.URI},
- Position: loc.Range.Start,
+ Range: loc.Range,
+ Position: loc.Range.Start, // not used
}
}
diff --git a/gopls/internal/protocol/protocol.go b/gopls/internal/protocol/protocol.go
index d92e4c5..d809bb4 100644
--- a/gopls/internal/protocol/protocol.go
+++ b/gopls/internal/protocol/protocol.go
@@ -10,6 +10,7 @@
"encoding/json"
"fmt"
"io"
+ "log"
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/jsonrpc2"
@@ -62,6 +63,10 @@
}
func (c clientConn) Call(ctx context.Context, method string, params any, result any) error {
+ if method == "textDocument/completion" {
+ log.Printf("params 1 = %v", params)
+ }
+
id, err := c.conn.Call(ctx, method, params, result)
if ctx.Err() != nil {
cancelCall(ctx, c, id)
diff --git a/gopls/internal/protocol/tsprotocol.go b/gopls/internal/protocol/tsprotocol.go
index 10aa2a4..644d3c4 100644
--- a/gopls/internal/protocol/tsprotocol.go
+++ b/gopls/internal/protocol/tsprotocol.go
@@ -5624,6 +5624,8 @@
// The text document.
TextDocument TextDocumentIdentifier `json:"textDocument"`
// The position inside the text document.
+ //
+ // Deprecated: gopls should use [TextDocumentPositionParams.Range] instead.
Position Position `json:"position"`
// Range is an optional field representing the user's text selection in the document.
// If provided, the Position must be contained within this range.
diff --git a/gopls/internal/protocol/tsserver.go b/gopls/internal/protocol/tsserver.go
index cbf6147..241abaf 100644
--- a/gopls/internal/protocol/tsserver.go
+++ b/gopls/internal/protocol/tsserver.go
@@ -387,9 +387,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.Completion(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -401,9 +407,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.Declaration(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -415,9 +427,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.Definition(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -483,9 +501,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.DocumentHighlight(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -541,9 +565,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.Hover(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -555,9 +585,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.Implementation(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -580,9 +616,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.InlineCompletion(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -605,9 +647,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.LinkedEditingRange(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -619,9 +667,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.Moniker(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -644,9 +698,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.PrepareCallHierarchy(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -658,9 +718,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.PrepareRename(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -672,9 +738,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.PrepareTypeHierarchy(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -708,9 +780,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.References(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -722,9 +800,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.Rename(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -780,9 +864,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.SignatureHelp(ctx, ¶ms)
if err != nil {
return nil, true, err
@@ -794,9 +884,15 @@
if err := UnmarshalJSON(raw, ¶ms); err != nil {
return nil, true, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
}
- if !params.Range.Empty() && !params.Range.Contains(params.Position) {
+ if params.Range != (Range{}) && !params.Range.Contains(params.Position) {
return nil, true, fmt.Errorf("position %v is outside the provided range %v.", params.Position, params.Range)
}
+ if params.Range == (Range{}) {
+ params.Range = Range{
+ Start: params.Position,
+ End: params.Position,
+ }
+ }
resp, err := server.TypeDefinition(ctx, ¶ms)
if err != nil {
return nil, true, err
diff --git a/gopls/internal/server/call_hierarchy.go b/gopls/internal/server/call_hierarchy.go
index dc8cd4c..ee521ce 100644
--- a/gopls/internal/server/call_hierarchy.go
+++ b/gopls/internal/server/call_hierarchy.go
@@ -24,7 +24,7 @@
defer release()
switch snapshot.FileKind(fh) {
case file.Go:
- return golang.PrepareCallHierarchy(ctx, snapshot, fh, params.Position)
+ return golang.PrepareCallHierarchy(ctx, snapshot, fh, params.Range)
}
return nil, nil // empty result
}
@@ -40,7 +40,7 @@
defer release()
switch snapshot.FileKind(fh) {
case file.Go:
- return golang.IncomingCalls(ctx, snapshot, fh, params.Item.Range.Start)
+ return golang.IncomingCalls(ctx, snapshot, fh, params.Item.Range)
}
return nil, nil // empty result
}
diff --git a/gopls/internal/server/completion.go b/gopls/internal/server/completion.go
index 8ff7921..53d8527 100644
--- a/gopls/internal/server/completion.go
+++ b/gopls/internal/server/completion.go
@@ -36,29 +36,34 @@
}
defer release()
+ if params.Range.Start != params.Range.End {
+ return nil, fmt.Errorf("textDocument/completion request only applicable for position")
+ }
+ pos := params.Range.Start
+
var candidates []completion.CompletionItem
var surrounding *completion.Selection
switch snapshot.FileKind(fh) {
case file.Go:
- candidates, surrounding, err = completion.Completion(ctx, snapshot, fh, params.Position, params.Context)
+ candidates, surrounding, err = completion.Completion(ctx, snapshot, fh, pos, params.Context)
case file.Mod:
candidates, surrounding = nil, nil
case file.Work:
- cl, err := work.Completion(ctx, snapshot, fh, params.Position)
+ cl, err := work.Completion(ctx, snapshot, fh, pos)
if err != nil {
break
}
return cl, nil
case file.Tmpl:
var cl *protocol.CompletionList
- cl, err = template.Completion(ctx, snapshot, fh, params.Position, params.Context)
+ cl, err = template.Completion(ctx, snapshot, fh, pos, params.Context)
if err != nil {
break // use common error handling, candidates==nil
}
return cl, nil
}
if err != nil {
- event.Error(ctx, "no completions found", err, label.Position.Of(params.Position))
+ event.Error(ctx, "no completions found", err, label.Position.Of(pos))
}
if candidates == nil || surrounding == nil {
complEmpty.Inc()
diff --git a/gopls/internal/server/definition.go b/gopls/internal/server/definition.go
index 964fa40..bc02325 100644
--- a/gopls/internal/server/definition.go
+++ b/gopls/internal/server/definition.go
@@ -35,11 +35,11 @@
defer release()
switch kind := snapshot.FileKind(fh); kind {
case file.Tmpl:
- return template.Definition(snapshot, fh, params.Position)
+ return template.Definition(snapshot, fh, params.Range)
case file.Go:
- return golang.Definition(ctx, snapshot, fh, params.Position)
+ return golang.Definition(ctx, snapshot, fh, params.Range)
case file.Asm:
- return goasm.Definition(ctx, snapshot, fh, params.Position)
+ return goasm.Definition(ctx, snapshot, fh, params.Range)
default:
return nil, fmt.Errorf("can't find definitions for file type %s", kind)
}
@@ -55,22 +55,10 @@
return nil, err
}
- var rng protocol.Range
- if params.Range == (protocol.Range{}) {
- // No selection range was provided.
- // Default to an empty range at the position.
- rng = protocol.Range{
- Start: params.Position,
- End: params.Position,
- }
- } else {
- rng = params.Range
- }
-
defer release()
switch kind := snapshot.FileKind(fh); kind {
case file.Go:
- return golang.TypeDefinition(ctx, snapshot, fh, rng)
+ return golang.TypeDefinition(ctx, snapshot, fh, params.Range)
default:
return nil, fmt.Errorf("can't find type definitions for file type %s", kind)
}
diff --git a/gopls/internal/server/highlight.go b/gopls/internal/server/highlight.go
index 6ff73d8..83b2660 100644
--- a/gopls/internal/server/highlight.go
+++ b/gopls/internal/server/highlight.go
@@ -27,9 +27,9 @@
switch snapshot.FileKind(fh) {
case file.Tmpl:
- return template.Highlight(ctx, snapshot, fh, params.Position)
+ return template.Highlight(ctx, snapshot, fh, params.Range)
case file.Go:
- rngs, err := golang.Highlight(ctx, snapshot, fh, params.Position)
+ rngs, err := golang.Highlight(ctx, snapshot, fh, params.Range)
if err != nil {
event.Error(ctx, "no highlight", err)
}
diff --git a/gopls/internal/server/hover.go b/gopls/internal/server/hover.go
index 0df8afb..d0c2c83 100644
--- a/gopls/internal/server/hover.go
+++ b/gopls/internal/server/hover.go
@@ -34,21 +34,9 @@
}
defer release()
- var rng protocol.Range
- if params.Range == (protocol.Range{}) {
- // No selection range was provided.
- // Default to an empty range at the position.
- rng = protocol.Range{
- Start: params.Position,
- End: params.Position,
- }
- } else {
- rng = params.Range
- }
-
switch snapshot.FileKind(fh) {
case file.Mod:
- return mod.Hover(ctx, snapshot, fh, params.Position)
+ return mod.Hover(ctx, snapshot, fh, params.Range)
case file.Go:
var pkgURL func(path golang.PackagePath, fragment string) protocol.URI
if snapshot.Options().LinksInHover == settings.LinksInHover_Gopls {
@@ -61,11 +49,11 @@
}
}
}
- return golang.Hover(ctx, snapshot, fh, rng, pkgURL)
+ return golang.Hover(ctx, snapshot, fh, params.Range, pkgURL)
case file.Tmpl:
- return template.Hover(ctx, snapshot, fh, params.Position)
+ return template.Hover(ctx, snapshot, fh, params.Range)
case file.Work:
- return work.Hover(ctx, snapshot, fh, params.Position)
+ return work.Hover(ctx, snapshot, fh, params.Range)
}
return nil, nil // empty result
}
diff --git a/gopls/internal/server/implementation.go b/gopls/internal/server/implementation.go
index c4e59c9..37a132b 100644
--- a/gopls/internal/server/implementation.go
+++ b/gopls/internal/server/implementation.go
@@ -32,5 +32,5 @@
if snapshot.FileKind(fh) != file.Go {
return nil, nil // empty result
}
- return golang.Implementation(ctx, snapshot, fh, params.Position)
+ return golang.Implementation(ctx, snapshot, fh, params.Range)
}
diff --git a/gopls/internal/server/references.go b/gopls/internal/server/references.go
index 2916f27..f419390 100644
--- a/gopls/internal/server/references.go
+++ b/gopls/internal/server/references.go
@@ -34,7 +34,7 @@
case file.Tmpl:
return template.References(ctx, snapshot, fh, params)
case file.Go:
- return golang.References(ctx, snapshot, fh, params.Position, params.Context.IncludeDeclaration)
+ return golang.References(ctx, snapshot, fh, params.Range, params.Context.IncludeDeclaration)
}
return nil, nil // empty result
}
diff --git a/gopls/internal/server/rename.go b/gopls/internal/server/rename.go
index c7abc4f..e12e915 100644
--- a/gopls/internal/server/rename.go
+++ b/gopls/internal/server/rename.go
@@ -30,7 +30,7 @@
return nil, fmt.Errorf("cannot rename in file of type %s", kind)
}
- changes, err := golang.Rename(ctx, snapshot, fh, params.Position, params.NewName)
+ changes, err := golang.Rename(ctx, snapshot, fh, params.Range, params.NewName)
if err != nil {
return nil, err
}
@@ -59,7 +59,7 @@
// Do not return errors here, as it adds clutter.
// Returning a nil result means there is not a valid rename.
- item, usererr, err := golang.PrepareRename(ctx, snapshot, fh, params.Position)
+ item, usererr, err := golang.PrepareRename(ctx, snapshot, fh, params.Range)
if err != nil {
// Return usererr here rather than err, to avoid cluttering the UI with
// internal error details.
diff --git a/gopls/internal/server/signature_help.go b/gopls/internal/server/signature_help.go
index c8b6cb6..f89115b 100644
--- a/gopls/internal/server/signature_help.go
+++ b/gopls/internal/server/signature_help.go
@@ -28,14 +28,14 @@
return nil, nil // empty result
}
- info, err := golang.SignatureHelp(ctx, snapshot, fh, params)
+ info, err := golang.SignatureHelp(ctx, snapshot, fh, params.Range, params.Context)
if err != nil {
// TODO(rfindley): is this correct? Apparently, returning an error from
// signatureHelp is distracting in some editors, though I haven't confirmed
// that recently.
//
// It's unclear whether we still need to avoid returning this error result.
- event.Error(ctx, "signature help failed", err, label.Position.Of(params.Position))
+ event.Error(ctx, "signature help failed", err, label.Position.Of(params.Range.Start), label.Position.Of(params.Range.End))
return nil, nil
}
if info == nil {
diff --git a/gopls/internal/server/type_hierarchy.go b/gopls/internal/server/type_hierarchy.go
index 037c8c5..61bced8 100644
--- a/gopls/internal/server/type_hierarchy.go
+++ b/gopls/internal/server/type_hierarchy.go
@@ -25,7 +25,7 @@
defer release()
switch snapshot.FileKind(fh) {
case file.Go:
- return golang.PrepareTypeHierarchy(ctx, snapshot, fh, params.Position)
+ return golang.PrepareTypeHierarchy(ctx, snapshot, fh, params.Range)
}
return nil, fmt.Errorf("unsupported file type: %v", fh)
}
diff --git a/gopls/internal/telemetry/telemetry_test.go b/gopls/internal/telemetry/telemetry_test.go
index 63a809c..2bbab7d 100644
--- a/gopls/internal/telemetry/telemetry_test.go
+++ b/gopls/internal/telemetry/telemetry_test.go
@@ -263,7 +263,7 @@
).Run(t, files, func(_ *testing.T, env *Env) {
env.OpenFile("a.go")
before := totalLatencySamples(t, "completion", false)
- loc := env.RegexpSearch("a.go", "x")
+ loc := env.RegexpSearch("a.go", "()x")
for i := 0; i < 10; i++ {
env.Completion(loc)
}
diff --git a/gopls/internal/template/highlight.go b/gopls/internal/template/highlight.go
index 8a8244d..2e83c8b 100644
--- a/gopls/internal/template/highlight.go
+++ b/gopls/internal/template/highlight.go
@@ -14,20 +14,20 @@
"golang.org/x/tools/gopls/internal/protocol"
)
-func Highlight(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, loc protocol.Position) ([]protocol.DocumentHighlight, error) {
+func Highlight(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.DocumentHighlight, error) {
buf, err := fh.Content()
if err != nil {
return nil, err
}
p := parseBuffer(fh.URI(), buf)
- pos, err := p.mapper.PositionOffset(loc)
+ start, end, err := p.mapper.RangeOffsets(rng)
if err != nil {
return nil, err
}
if p.parseErr == nil {
for _, s := range p.symbols {
- if s.start <= pos && pos < s.start+s.len {
+ if s.start <= start && end < s.start+s.len {
return markSymbols(p, s)
}
}
@@ -36,8 +36,8 @@
// these tokens exist whether or not there was a parse error
// (symbols require a successful parse)
for _, tok := range p.tokens {
- if tok.start <= pos && pos < tok.end {
- wordAt := wordAt(p.buf, pos)
+ if tok.start <= start && end < tok.end {
+ wordAt := wordAt(p.buf, start)
if len(wordAt) > 0 {
return markWordInToken(p, wordAt)
}
diff --git a/gopls/internal/template/implementations.go b/gopls/internal/template/implementations.go
index f0e5552..2e6bf72 100644
--- a/gopls/internal/template/implementations.go
+++ b/gopls/internal/template/implementations.go
@@ -97,8 +97,8 @@
// does not understand scoping (if any) in templates. This code is
// for definitions, type definitions, and implementations.
// Results only for variables and templates.
-func Definition(snapshot *cache.Snapshot, fh file.Handle, loc protocol.Position) ([]protocol.Location, error) {
- x, _, err := symAtPosition(fh, loc)
+func Definition(snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.Location, error) {
+ x, _, err := symAtRange(fh, rng)
if err != nil {
return nil, err
}
@@ -121,8 +121,8 @@
return ans, nil
}
-func Hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, position protocol.Position) (*protocol.Hover, error) {
- sym, p, err := symAtPosition(fh, position)
+func Hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) (*protocol.Hover, error) {
+ sym, p, err := symAtRange(fh, rng)
if err != nil {
return nil, err
}
@@ -151,13 +151,13 @@
value = fmt.Sprintf("oops, sym=%#v", sym)
}
- rng, err := p.mapper.OffsetRange(sym.offsets())
+ symRng, err := p.mapper.OffsetRange(sym.offsets())
if err != nil {
return nil, err
}
return &protocol.Hover{
- Range: rng,
+ Range: symRng,
Contents: protocol.MarkupContent{
Kind: protocol.Markdown,
Value: value,
@@ -166,7 +166,7 @@
}
func References(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, params *protocol.ReferenceParams) ([]protocol.Location, error) {
- sym, _, err := symAtPosition(fh, params.Position)
+ sym, _, err := symAtRange(fh, params.Range)
if err != nil {
return nil, err
}
@@ -233,19 +233,19 @@
// TODO: still need to do rename, etc
-func symAtPosition(fh file.Handle, posn protocol.Position) (*symbol, *parsed, error) {
+func symAtRange(fh file.Handle, rng protocol.Range) (*symbol, *parsed, error) {
buf, err := fh.Content()
if err != nil {
return nil, nil, err
}
p := parseBuffer(fh.URI(), buf)
- offset, err := p.mapper.PositionOffset(posn)
+ start, end, err := p.mapper.RangeOffsets(rng)
if err != nil {
return nil, nil, err
}
var syms []symbol
for _, s := range p.symbols {
- if s.start <= offset && offset < s.start+s.len {
+ if s.start <= start && end < s.start+s.len {
syms = append(syms, s)
}
}
diff --git a/gopls/internal/test/integration/completion/completion_test.go b/gopls/internal/test/integration/completion/completion_test.go
index 68bae9d..072a3a2 100644
--- a/gopls/internal/test/integration/completion/completion_test.go
+++ b/gopls/internal/test/integration/completion/completion_test.go
@@ -1300,8 +1300,8 @@
env.OpenFile("a.go")
tests := map[string][]string{
- `DoubleWrap\[()\]\(\)`: {"InterfaceA", "TypeA", "InterfaceB", "TypeB", "TypeC"},
- `DoubleWrap\[InterfaceA, (_)\]\(\)`: {"InterfaceB", "TypeB", "TypeX", "InterfaceA", "TypeA"},
+ `DoubleWrap\[()\]\(\)`: {"InterfaceA", "TypeA", "InterfaceB", "TypeB", "TypeC"},
+ `DoubleWrap\[InterfaceA, ()\_\]\(\)`: {"InterfaceB", "TypeB", "TypeX", "InterfaceA", "TypeA"},
}
for re, wantLabels := range tests {
diff --git a/gopls/internal/work/completion.go b/gopls/internal/work/completion.go
index 870450b..cbe8bc9 100644
--- a/gopls/internal/work/completion.go
+++ b/gopls/internal/work/completion.go
@@ -35,7 +35,7 @@
}
// Find the use statement the user is in.
- use, pathStart, _ := usePath(pw, cursor)
+ use, pathStart, _ := usePath(pw, cursor, cursor)
if use == nil {
return &protocol.CompletionList{}, nil
}
diff --git a/gopls/internal/work/hover.go b/gopls/internal/work/hover.go
index c59c147..5fd7650 100644
--- a/gopls/internal/work/hover.go
+++ b/gopls/internal/work/hover.go
@@ -16,7 +16,7 @@
"golang.org/x/tools/internal/event"
)
-func Hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, position protocol.Position) (*protocol.Hover, error) {
+func Hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) (*protocol.Hover, error) {
// We only provide hover information for the view's go.work file.
if fh.URI() != snapshot.View().GoWork() {
return nil, nil
@@ -30,14 +30,14 @@
if err != nil {
return nil, fmt.Errorf("getting go.work file handle: %w", err)
}
- offset, err := pw.Mapper.PositionOffset(position)
+ startOffset, endOffset, err := pw.Mapper.RangeOffsets(rng)
if err != nil {
return nil, fmt.Errorf("computing cursor offset: %w", err)
}
// Confirm that the cursor is inside a use statement, and then find
// the position of the use statement's directory path.
- use, pathStart, pathEnd := usePath(pw, offset)
+ use, pathStart, pathEnd := usePath(pw, startOffset, endOffset)
// The cursor position is not on a use statement.
if use == nil {
@@ -59,7 +59,7 @@
mod := pm.File.Module.Mod
// Get the range to highlight for the hover.
- rng, err := pw.Mapper.OffsetRange(pathStart, pathEnd)
+ pathRng, err := pw.Mapper.OffsetRange(pathStart, pathEnd)
if err != nil {
return nil, err
}
@@ -69,11 +69,11 @@
Kind: options.PreferredContentFormat,
Value: mod.Path,
},
- Range: rng,
+ Range: pathRng,
}, nil
}
-func usePath(pw *cache.ParsedWorkFile, offset int) (use *modfile.Use, pathStart, pathEnd int) {
+func usePath(pw *cache.ParsedWorkFile, startOffset, endOffset int) (use *modfile.Use, pathStart, pathEnd int) {
for _, u := range pw.File.Use {
path := []byte(u.Path)
s, e := u.Syntax.Start.Byte, u.Syntax.End.Byte
@@ -85,7 +85,7 @@
// Shift the start position to the location of the
// module directory within the use statement.
pathStart, pathEnd = s+i, s+i+len(path)
- if pathStart <= offset && offset <= pathEnd {
+ if pathStart <= startOffset && endOffset <= pathEnd {
return u, pathStart, pathEnd
}
}