Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

hover: Include struct and interface fields #169

Merged
merged 1 commit into from
Mar 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 72 additions & 2 deletions langserver/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func (h *LangHandler) handleHover(ctx context.Context, conn jsonrpc2.JSONRPC2, r
qf := func(*types.Package) string { return "" }

var s string
var extra string
if f, ok := o.(*types.Var); ok && f.IsField() {
// TODO(sqs): make this be like (T).F not "struct field F string".
s = "struct " + o.String()
Expand All @@ -63,6 +64,11 @@ func (h *LangHandler) handleHover(ctx context.Context, conn jsonrpc2.JSONRPC2, r
typ := obj.Type().Underlying()
if _, ok := typ.(*types.Struct); ok {
s = "type " + obj.Name() + " struct"
extra = prettyPrintTypesString(types.TypeString(typ, qf))
}
if _, ok := typ.(*types.Interface); ok {
s = "type " + obj.Name() + " interface"
extra = prettyPrintTypesString(types.TypeString(typ, qf))
}
}
if s == "" {
Expand Down Expand Up @@ -109,9 +115,15 @@ func (h *LangHandler) handleHover(ctx context.Context, conn jsonrpc2.JSONRPC2, r
return doc.Text()
}

comments := findComments(o)
contents := maybeAddComments(findComments(o), []lsp.MarkedString{{Language: "go", Value: s}})
if extra != "" {
// If we have extra info, ensure it comes after the usually
// more useful documentation
contents = append(contents, lsp.MarkedString{Language: "go", Value: extra})
}

return &lsp.Hover{
Contents: maybeAddComments(comments, []lsp.MarkedString{{Language: "go", Value: s}}),
Contents: contents,
Range: rangeForNode(fset, node),
}, nil
}
Expand Down Expand Up @@ -165,3 +177,61 @@ func commentsToText(cgroups []*ast.CommentGroup) (text string) {
}
return text
}

// prettyPrintTypesString is pretty printing specific to the output of
// types.*String. Instead of re-implementing the printer, we can just
// transform its output.
func prettyPrintTypesString(s string) string {
// Don't bother including the fields if it is empty
if strings.HasSuffix(s, "{}") {
return ""
}
var b bytes.Buffer
b.Grow(len(s))
depth := 0
for i := 0; i < len(s); i++ {
c := s[i]
switch c {
case ';':
b.WriteByte('\n')
for j := 0; j < depth; j++ {
b.WriteString(" ")
}
// Skip following space
i++

case '{':
if i == len(s)-1 {
// This should never happen, but in case it
// does give up
return s
}

n := s[i+1]
if n == '}' {
// Do not modify {}
b.WriteString("{}")
// We have already written }, so skip
i++
} else {
// We expect fields to follow, insert a newline and space
depth++
b.WriteString(" {\n")
for j := 0; j < depth; j++ {
b.WriteString(" ")
}
}

case '}':
depth--
if depth < 0 {
return s
}
b.WriteString("\n}")

default:
b.WriteByte(c)
}
}
return b.String()
}
6 changes: 4 additions & 2 deletions langserver/langserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ func TestServer(t *testing.T) {
wantHover: map[string]string{
// "a.go:1:28": "(T).F string", // TODO(sqs): see golang/hover.go; this is the output we want
"a.go:1:28": "struct field F string",
"a.go:1:17": "type T struct",
"a.go:1:17": `type T struct; struct {
F string
}`,
},
wantSymbols: map[string][]string{
"a.go": []string{"/src/test/pkg/a.go:class:pkg.T:1:17"},
Expand Down Expand Up @@ -780,7 +782,7 @@ type Header struct {
"a.go:12:5": "var logit func(); logit is pkg2.X \n\n",
"a.go:12:13": "package pkg2 (\"test/pkg/vendor/github.com/a/pkg2\"); Package pkg2 shows dependencies. \n\nHow to \n\n```\nExample Code!\n\n```\n",
"a.go:12:18": "func X(); X does the unknown. \n\n",
"a.go:15:6": "type T struct; T is a struct. \n\n",
"a.go:15:6": "type T struct; T is a struct. \n\n; struct {\n F string\n H Header\n}",
"a.go:17:2": "struct field F string; F is a string field. \n\n",
"a.go:20:2": "struct field H test/pkg/vendor/github.com/a/pkg2.Header; H is a header. \n\n",
"a.go:20:4": "package pkg2 (\"test/pkg/vendor/github.com/a/pkg2\"); Package pkg2 shows dependencies. \n\nHow to \n\n```\nExample Code!\n\n```\n",
Expand Down