diff --git a/internal/lsp/protocol/printers.go b/internal/lsp/protocol/printers.go index f4f80db567..e4995b4736 100644 --- a/internal/lsp/protocol/printers.go +++ b/internal/lsp/protocol/printers.go @@ -17,9 +17,9 @@ import ( ) func (p Position) Format(f fmt.State, c rune) { - fmt.Fprintf(f, "%d", int(p.Line)) + fmt.Fprintf(f, "%d", int(p.Line)+1) if p.Character >= 0 { - fmt.Fprintf(f, ":%d", int(p.Character)) + fmt.Fprintf(f, ":%d", int(p.Character)+1) } } @@ -28,7 +28,7 @@ func (r Range) Format(f fmt.State, c rune) { case r.Start == r.End || r.End.Line < 0: fmt.Fprintf(f, "%v", r.Start) case r.End.Line == r.Start.Line: - fmt.Fprintf(f, "%v¦%d", r.Start, int(r.End.Character)) + fmt.Fprintf(f, "%v¦%d", r.Start, int(r.End.Character)+1) default: fmt.Fprintf(f, "%v¦%v", r.Start, r.End) } diff --git a/internal/lsp/source/definition.go b/internal/lsp/source/definition.go index 0df2bd139e..4354638166 100644 --- a/internal/lsp/source/definition.go +++ b/internal/lsp/source/definition.go @@ -5,11 +5,13 @@ package source import ( + "bytes" "context" "fmt" "go/ast" "go/token" "go/types" + "io/ioutil" "golang.org/x/tools/go/ast/astutil" ) @@ -43,10 +45,7 @@ func Definition(ctx context.Context, f *File, pos token.Pos) (Range, error) { } } } - return Range{ - Start: obj.Pos(), - End: obj.Pos() + token.Pos(len([]byte(obj.Name()))), // TODO: use real range of obj - }, nil + return objToRange(f.view.Config.Fset, obj), nil } // ident returns the ident plus any extra information needed @@ -93,3 +92,30 @@ func checkIdentifier(f *ast.File, pos token.Pos) (ident, error) { } return result, nil } + +func objToRange(fSet *token.FileSet, obj types.Object) Range { + p := obj.Pos() + f := fSet.File(p) + pos := f.Position(p) + if pos.Column == 1 { + // Column is 1, so we probably do not have full position information + // Currently exportdata does not store the column. + // For now we attempt to read the original source and find the identifier + // within the line. If we find it we patch the column to match its offset. + // TODO: we have probably already added the full data for the file to the + // fileset, we ought to track it rather than adding it over and over again + // TODO: if we parse from source, we will never need this hack + if src, err := ioutil.ReadFile(pos.Filename); err == nil { + newF := fSet.AddFile(pos.Filename, -1, len(src)) + newF.SetLinesForContent(src) + lineStart := lineStart(newF, pos.Line) + offset := newF.Offset(lineStart) + col := bytes.Index(src[offset:], []byte(obj.Name())) + p = newF.Pos(offset + col) + } + } + return Range{ + Start: p, + End: p + token.Pos(len([]byte(obj.Name()))), // TODO: use real range of obj + } +}