Skip to content

Commit

Permalink
Implement support for textDocument/inlayHint
Browse files Browse the repository at this point in the history
  • Loading branch information
mliszcz committed Sep 28, 2023
1 parent 22bdd83 commit 3a927e4
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 1 deletion.
1 change: 1 addition & 0 deletions internal/lsp/general.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitializ

return &protocol.InitializeResult{
Capabilities: protocol.ServerCapabilities{
InlayHintProvider: true,
CodeActionProvider: false,
CompletionProvider: protocol.CompletionOptions{TriggerCharacters: []string{"."}},
DefinitionProvider: true,
Expand Down
77 changes: 77 additions & 0 deletions internal/lsp/inlay_hint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package lsp

import (
"context"

"github.com/nokia/ntt/internal/lsp/protocol"
"github.com/nokia/ntt/ttcn3"
"github.com/nokia/ntt/ttcn3/syntax"
)

func (s *Server) inlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
file := string(params.TextDocument.URI)
tree := ttcn3.ParseFile(file)
begin := tree.PosFor(int(params.Range.Start.Line)+1, int(params.Range.Start.Character+1))
end := tree.PosFor(int(params.Range.End.Line+1), int(params.Range.End.Character+1))
return ProcessInlayHint(tree, &s.db, begin, end), nil
}

func ProcessInlayHint(tree *ttcn3.Tree, db *ttcn3.DB, begin int, end int) []protocol.InlayHint {
var hints []protocol.InlayHint

tree.Inspect(func(n syntax.Node) bool {
if n == nil || n.End() < begin || end < n.Pos() {
return false
}

if callExpr, ok := n.(*syntax.CallExpr); ok {

for _, decl := range tree.LookupWithDB(callExpr.Fun, db) {

if params := getDeclarationParams(decl.Node); params != nil {

for idx, arg := range callExpr.Args.List {

// Stop processing further arguments after the first assignment notation.
// Value arguments are not allowed: ES 201 873-1, 5.4.2, Restrictions, point o).
if binaryExpr, ok := arg.(*syntax.BinaryExpr); ok {
if binaryExpr.Op.String() == ":=" {
break
}
}

name := params.List[idx].Name.Tok.String()
lbl := protocol.InlayHintLabelPart{Value: name + " :="}
pos := syntax.Begin(arg)
pos.Line -= 1
pos.Column -= 1
ppos := protocol.Position{Line: uint32(pos.Line), Character: uint32(pos.Column)}
hint := protocol.InlayHint{
Position: ppos,
Label: []protocol.InlayHintLabelPart{lbl},
Kind: protocol.Parameter,
PaddingRight: true,
}
hints = append(hints, hint)

}

// Stop after the first declaration is processed.
break
}
}
}
return true
})
return hints
}

func getDeclarationParams(node syntax.Node) *syntax.FormalPars {
if decl, ok := node.(*syntax.FuncDecl); ok {
return decl.Params
}
if decl, ok := node.(*syntax.TemplateDecl); ok {
return decl.Params
}
return nil
}
115 changes: 115 additions & 0 deletions internal/lsp/inlay_hint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package lsp_test

import (
"fmt"
"testing"

"github.com/nokia/ntt/internal/fs"
"github.com/nokia/ntt/internal/lsp"
"github.com/nokia/ntt/internal/lsp/protocol"
"github.com/nokia/ntt/ttcn3"
"github.com/stretchr/testify/assert"
)

type Hint struct {
Line uint32
Char uint32
Label string
}

func TestInlayHintForFunction(t *testing.T) {
actual := testInlayHint(t, nil, `
module Test {
function func(integer a := 0, integer b := 0, integer c := 0) {}
function test() {
func(1, 2, 3)
func(1,
2,
3)
func(a := 1, b := 2, c := 3)
func(1 + 2)
func(1, 2, c := 3)
}
}`)

assert.Equal(t, []Hint{
// All parameters in the same line.
{Line: 4, Char: 13, Label: "a :="},
{Line: 4, Char: 16, Label: "b :="},
{Line: 4, Char: 19, Label: "c :="},
// Parameters spanning multiple lines.
{Line: 5, Char: 13, Label: "a :="},
{Line: 6, Char: 13, Label: "b :="},
{Line: 7, Char: 13, Label: "c :="},
// Binary expression parameter.
{Line: 8, Char: 13, Label: "a :="},
// Mixed assignment / value list notation.
{Line: 9, Char: 13, Label: "a :="},
{Line: 9, Char: 14, Label: "b :="},
}[0], actual[0])
}

func TestInlayHintForTemplate(t *testing.T) {
actual := testInlayHint(t, nil, `
module Test {
template integer templ(integer x, integer y) := (x .. y)
function test() {
var template integer t := templ(2, 3)
}
}`)

assert.Equal(t, []Hint{
{Line: 4, Char: 40, Label: "x :="},
{Line: 6, Char: 43, Label: "y :="},
}[0], actual[0])
}

func TestInlayHintNestedCalls(t *testing.T) {
actual := testInlayHint(t, nil, `
module Test {
function foo(integer a) return integer { return 1; }
function bar(integer b) return integer { return 1; }
function baz(integer c) return integer { return 1; }
function test() {
foo(bar(baz(1)))
}
}`)

assert.Equal(t, []Hint{
{Line: 6, Char: 12, Label: "a :="},
{Line: 6, Char: 16, Label: "b :="},
{Line: 6, Char: 20, Label: "c :="},
}[0], actual[0])
}

func testInlayHint(t *testing.T, rng *protocol.Range, text string) []Hint {
t.Helper()

file := fmt.Sprintf("%s.ttcn3", t.Name())
fs.SetContent(file, []byte(text))
tree := ttcn3.ParseFile(file)
if tree.Err != nil {
t.Fatal(tree.Err)
}

// Build index to for tree.Lookup to resolve imported symbols.
db := &ttcn3.DB{}
db.Index(file)

begin := tree.Pos()
end := tree.End()
if rng != nil {
begin = tree.PosFor(int(rng.Start.Line), int(rng.Start.Character))
end = tree.PosFor(int(rng.End.Line), int(rng.End.Character))
}

var hints []Hint
for _, h := range lsp.ProcessInlayHint(tree, db, begin, end) {
hints = append(hints, Hint{
Line: h.Position.Line,
Char: h.Position.Character,
Label: h.Label[0].Value,
})
}
return hints
}
2 changes: 1 addition & 1 deletion internal/lsp/server_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func (s *Server) Resolve(ctx context.Context, params *protocol.InlayHint) (*prot
}

func (s *Server) InlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
return nil, notImplemented("InlayHint")
return s.inlayHint(ctx, params)
}

func (s *Server) CodeAction(context.Context, *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
Expand Down

0 comments on commit 3a927e4

Please sign in to comment.