Skip to content

Commit

Permalink
wip: usage of astutil.PathEnclosingInterval
Browse files Browse the repository at this point in the history
  • Loading branch information
tbruyelle committed Jul 28, 2024
1 parent 0538217 commit 926d80b
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 36 deletions.
14 changes: 12 additions & 2 deletions cmd/gnols/testdata/document_completion_func_args.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ type MyType struct {
Foo int
}

func (MyType) Bar(int) bool {}

func Hello(x MyType) {
x. // completion here, should return all fields of MyType
x. // completion here, should return all fields & methods of MyType
}
-- input/initialize.json --
{
Expand Down Expand Up @@ -46,15 +48,23 @@ func Hello(x MyType) {
},
"position": {
"character": 3,
"line":7
"line": 9
}
}
-- expected/completion_x.json --
[
{
"detail": "Foo int",
"documentation": "",
"insertText": "Foo",
"kind": 5,
"label": "Foo"
},
{
"detail": "func (MyType) Bar(int) bool",
"documentation": "",
"insertText": "Bar",
"kind": 2,
"label": "Bar"
}
]
74 changes: 74 additions & 0 deletions cmd/gnols/testdata/document_completion_func_args2.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Init phase
lsp initialize input/initialize.json
lsp initialized input/initialized.json
lsp workspace/didChangeConfiguration input/didChangeConfiguration.json
lsp textDocument/didOpen input/didOpen_x.json

lsp textDocument/completion input/completion_x.json
cmpenv output/completion_x.json expected/completion_x.json
-- x.gno --
package foo

import "sub"

func Hello(x sub.MyType) {
x. // completion here, should return all fields of MyType
}
-- sub/sub.gno --
package sub

func (MyType) Bar(int) bool {}

type MyType struct {
Foo int
}
-- input/initialize.json --
{
"rootUri": "file://$WORK"
}
-- input/initialized.json --
{}
-- input/didChangeConfiguration.json --
{
"settings": {
"gno": "$GOBIN/gno",
"gopls": "$GOBIN/gopls",
"root": "$GNOPATH",
"precompileOnSave": true,
"buildOnSave": true
}
}
-- input/didOpen_x.json --
{
"textDocument": {
"uri":"file://$WORK/x.gno",
"text":"${FILE_x.gno}"
}
}
-- input/completion_x.json --
{
"textDocument": {
"uri":"file://$WORK/x.gno"
},
"position": {
"character": 3,
"line": 5
}
}
-- expected/completion_x.json --
[
{
"detail": "Foo int",
"documentation": "",
"insertText": "Foo",
"kind": 5,
"label": "Foo"
},
{
"detail": "func (MyType) Bar(int) bool",
"documentation": "",
"insertText": "Bar",
"kind": 2,
"label": "Bar"
}
]
57 changes: 57 additions & 0 deletions cmd/gnols/testdata/document_completion_func_args3.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Init phase
lsp initialize input/initialize.json
lsp initialized input/initialized.json
lsp workspace/didChangeConfiguration input/didChangeConfiguration.json
lsp textDocument/didOpen input/didOpen_x.json

lsp textDocument/completion input/completion_x.json
cmpenv output/completion_x.json expected/completion_x.json
-- x.gno --
package foo

func Hello(x interface { Foo() int }) {
x. // completion here, should return all fields of MyType
}
-- input/initialize.json --
{
"rootUri": "file://$WORK"
}
-- input/initialized.json --
{}
-- input/didChangeConfiguration.json --
{
"settings": {
"gno": "$GOBIN/gno",
"gopls": "$GOBIN/gopls",
"root": "$GNOPATH",
"precompileOnSave": true,
"buildOnSave": true
}
}
-- input/didOpen_x.json --
{
"textDocument": {
"uri":"file://$WORK/x.gno",
"text":"${FILE_x.gno}"
}
}
-- input/completion_x.json --
{
"textDocument": {
"uri":"file://$WORK/x.gno"
},
"position": {
"character": 3,
"line": 3
}
}
-- expected/completion_x.json --
[
{
"detail": "Foo int",
"documentation": "",
"insertText": "Foo",
"kind": 5,
"label": "Foo"
}
]
114 changes: 80 additions & 34 deletions internal/handler/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ package handler

import (
"context"
"go/ast"
gotoken "go/token"
"log/slog"
"strings"

"golang.org/x/tools/go/ast/astutil"

"github.com/davecgh/go-spew/spew"
"github.com/jdkato/gnols/internal/gno"
"github.com/jdkato/gnols/internal/stdlib"
"go.lsp.dev/jsonrpc2"
"go.lsp.dev/protocol"
)
Expand All @@ -27,7 +31,6 @@ func (h *handler) handleTextDocumentCompletion(ctx context.Context, reply jsonrp
return replyErr(ctx, reply, err)
}
text := strings.TrimSpace(token.Text)

// Extract symbol name and prefix from text
// TODO ensure textDocument/completion is only triggered after a dot '.' and
// if yes why ? Is it a client limitation or configuration, or a LSP spec?
Expand All @@ -37,44 +40,87 @@ func (h *handler) handleTextDocumentCompletion(ctx context.Context, reply jsonrp

items := []protocol.CompletionItem{}

//-----------------------------------------
// Look up local symbols
if syms := h.lookupSymbols(selectors); len(syms) > 0 {
for _, f := range syms {
items = append(items, protocol.CompletionItem{
Label: f.Name,
InsertText: f.Name,
Kind: symbolToKind(f.Kind),
Detail: f.Signature,
Documentation: f.Doc,
})
}
} else {
//-----------------------------------------
// Look up stdlib
if pkg := lookupPkg(stdlib.Packages, selectors[0]); pkg != nil {
for _, s := range pkg.Symbols {
if s.Recv != "" {
// skip symbols with receiver (methods)
continue
pos := gotoken.Pos(doc.PositionToOffset(params.Position))
nodes, _ := astutil.PathEnclosingInterval(doc.Pgf.File, pos, pos)
spew.Dump("ENCLOSING NODES", nodes)
for _, n := range nodes {
switch n := n.(type) {

Check failure on line 47 in internal/handler/completion.go

View workflow job for this annotation

GitHub Actions / lint

singleCaseSwitch: should rewrite switch statement to if statement (gocritic)
case *ast.FuncDecl:
for _, param := range n.Type.Params.List {
if param.Names[0].Name == selectors[0] {
// match, find corresponding type
var typ string
switch t := param.Type.(type) {
case *ast.Ident:
typ = t.Name
case *ast.SelectorExpr:
// TODO find corresponding sub package or stdlib or ??
// and call symbolFind{FOUNDPKG}.find(...)
default:
panic("FIXME cannot find type")
}
spew.Dump("FIND", param.Type, selectors)
syms := symbolFinder{h.currentPkg.Symbols}.find(append([]string{typ}, selectors[1:]...))
// if len(syms) == 0 {
// syms = symbolFinder{h.subPkgs}.find(append([]string{typ}, selectors[1:]...))
// }

spew.Dump("FOUND", syms)
for _, f := range syms {
items = append(items, protocol.CompletionItem{
Label: f.Name,
InsertText: f.Name,
Kind: symbolToKind(f.Kind),
Detail: f.Signature,
Documentation: f.Doc,
})
}
return reply(ctx, items, nil)
}
if len(selectors) > 1 && !strings.HasPrefix(s.Name, selectors[1]) {
// TODO handle multiple selectors? (possible if for example a global
// var is defined in the pkg, and the user is referrencing it.)
}
}
}

// skip symbols that doesn't match the prefix
continue
}
/*
//-----------------------------------------
// Look up local symbols
if syms := h.lookupSymbols(selectors); len(syms) > 0 {
for _, f := range syms {
items = append(items, protocol.CompletionItem{
Label: s.Name,
InsertText: s.Name,
Kind: symbolToKind(s.Kind),
Detail: s.Signature,
Documentation: s.Doc,
Label: f.Name,
InsertText: f.Name,
Kind: symbolToKind(f.Kind),
Detail: f.Signature,
Documentation: f.Doc,
})
}
} else {
//-----------------------------------------
// Look up stdlib
if pkg := lookupPkg(stdlib.Packages, selectors[0]); pkg != nil {
for _, s := range pkg.Symbols {
if s.Recv != "" {
// skip symbols with receiver (methods)
continue
}
if len(selectors) > 1 && !strings.HasPrefix(s.Name, selectors[1]) {
// TODO handle multiple selectors? (possible if for example a global
// var is defined in the pkg, and the user is referrencing it.)
// skip symbols that doesn't match the prefix
continue
}
items = append(items, protocol.CompletionItem{
Label: s.Name,
InsertText: s.Name,
Kind: symbolToKind(s.Kind),
Detail: s.Signature,
Documentation: s.Doc,
})
}
}
}
}
*/
return reply(ctx, items, nil)
}

Expand Down
2 changes: 2 additions & 0 deletions internal/handler/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ func symbolToKind(symbol string) protocol.CompletionItemKind {
return protocol.CompletionItemKindConstant
case "func":
return protocol.CompletionItemKindFunction
case "method":
return protocol.CompletionItemKindMethod
case "type":
return protocol.CompletionItemKindClass
case "var":
Expand Down

0 comments on commit 926d80b

Please sign in to comment.