Skip to content

Commit

Permalink
Merge pull request #54 from lighttiger2505/add-definition-jump
Browse files Browse the repository at this point in the history
feat: Add definition
  • Loading branch information
lighttiger2505 authored Mar 22, 2021
2 parents c81e67e + 5b32042 commit db8733f
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 2 deletions.
85 changes: 85 additions & 0 deletions internal/handler/definition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package handler

import (
"context"
"encoding/json"
"fmt"

"github.com/lighttiger2505/sqls/ast"
"github.com/lighttiger2505/sqls/ast/astutil"
"github.com/lighttiger2505/sqls/internal/database"
"github.com/lighttiger2505/sqls/internal/lsp"
"github.com/lighttiger2505/sqls/parser"
"github.com/lighttiger2505/sqls/parser/parseutil"
"github.com/lighttiger2505/sqls/token"
"github.com/sourcegraph/jsonrpc2"
)

func (s *Server) handleDefinition(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request) (result interface{}, err error) {
if req.Params == nil {
return nil, &jsonrpc2.Error{Code: jsonrpc2.CodeInvalidParams}
}

var params lsp.DefinitionParams
if err := json.Unmarshal(*req.Params, &params); err != nil {
return nil, err
}

f, ok := s.files[params.TextDocument.URI]
if !ok {
return nil, fmt.Errorf("document not found: %s", params.TextDocument.URI)
}

return definition(params.TextDocument.URI, f.Text, params, s.worker.Cache())
}

func definition(url, text string, params lsp.DefinitionParams, dbCache *database.DBCache) (lsp.Definition, error) {
pos := token.Pos{
Line: params.Position.Line,
Col: params.Position.Character + 1,
}
parsed, err := parser.Parse(text)
if err != nil {
return nil, err
}

nodeWalker := parseutil.NewNodeWalker(parsed, pos)
m := astutil.NodeMatcher{
NodeTypes: []ast.NodeType{ast.TypeIdentifer},
}
currentVariable := nodeWalker.CurNodeButtomMatched(m)
if currentVariable == nil {
return nil, nil
}

aliases := parseutil.ExtractAliasedIdentifer(parsed)
if len(aliases) == 0 {
return nil, nil
}

var define ast.Node
for _, v := range aliases {
alias, _ := v.(*ast.Aliased)
if alias.AliasedName.String() == currentVariable.String() {
define = alias.AliasedName
}
}

res := []lsp.Location{
{
URI: url,
Range: lsp.Range{
Start: lsp.Position{
Line: define.Pos().Line,
Character: define.Pos().Col,
},
End: lsp.Position{
Line: define.End().Line,
Character: define.End().Col,
},
},
},
}

return res, nil
}
117 changes: 117 additions & 0 deletions internal/handler/definition_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package handler

import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/lighttiger2505/sqls/internal/config"
"github.com/lighttiger2505/sqls/internal/database"
"github.com/lighttiger2505/sqls/internal/lsp"
)

var definitionTestCases = []struct {
name string
input string
output lsp.Definition
pos lsp.Position
}{
{
name: "",
input: "SELECT ci.ID, ci.Name FROM city as ci",
output: []lsp.Location{
{
URI: testFileURI,
Range: lsp.Range{
Start: lsp.Position{
Line: 0,
Character: 35,
},
End: lsp.Position{
Line: 0,
Character: 37,
},
},
},
},
pos: lsp.Position{
Line: 0,
Character: 8,
},
},
}

func TestDefinition(t *testing.T) {
tx := newTestContext()
tx.setup(t)
defer tx.tearDown()

cfg := &config.Config{
Connections: []*database.DBConfig{
{Driver: "mock"},
},
}
tx.addWorkspaceConfig(t, cfg)

for _, tt := range definitionTestCases {
t.Run(tt.name, func(t *testing.T) {
tx.textDocumentDidOpen(t, testFileURI, tt.input)

params := lsp.DefinitionParams{
TextDocumentPositionParams: lsp.TextDocumentPositionParams{
TextDocument: lsp.TextDocumentIdentifier{
URI: testFileURI,
},
Position: tt.pos,
},
}
var got lsp.Definition
err := tx.conn.Call(tx.ctx, "textDocument/definition", params, &got)
if err != nil {
t.Errorf("conn.Call textDocument/definition: %+v", err)
return
}

if diff := cmp.Diff(tt.output, got); diff != "" {
t.Errorf("unmatch hover contents (- want, + got):\n%s", diff)
}
})
}
}

func TestTypeDefinition(t *testing.T) {
tx := newTestContext()
tx.setup(t)
defer tx.tearDown()

cfg := &config.Config{
Connections: []*database.DBConfig{
{Driver: "mock"},
},
}
tx.addWorkspaceConfig(t, cfg)

for _, tt := range definitionTestCases {
t.Run(tt.name, func(t *testing.T) {
tx.textDocumentDidOpen(t, testFileURI, tt.input)

params := lsp.DefinitionParams{
TextDocumentPositionParams: lsp.TextDocumentPositionParams{
TextDocument: lsp.TextDocumentIdentifier{
URI: testFileURI,
},
Position: tt.pos,
},
}
var got lsp.Definition
err := tx.conn.Call(tx.ctx, "textDocument/typeDefinition", params, &got)
if err != nil {
t.Errorf("conn.Call textDocument/definition: %+v", err)
return
}

if diff := cmp.Diff(tt.output, got); diff != "" {
t.Errorf("unmatch hover contents (- want, + got):\n%s", diff)
}
})
}
}
6 changes: 5 additions & 1 deletion internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ func (s *Server) handle(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.
return s.handleTextDocumentSignatureHelp(ctx, conn, req)
case "textDocument/rename":
return s.handleTextDocumentRename(ctx, conn, req)
case "textDocument/definition":
return s.handleDefinition(ctx, conn, req)
case "textDocument/typeDefinition":
return s.handleDefinition(ctx, conn, req)
}
return nil, &jsonrpc2.Error{Code: jsonrpc2.CodeMethodNotFound, Message: fmt.Sprintf("method not supported: %s", req.Method)}
}
Expand Down Expand Up @@ -149,7 +153,7 @@ func (s *Server) handleInitialize(ctx context.Context, conn *jsonrpc2.Conn, req
WorkDoneProgress: false,
},
},
DefinitionProvider: false,
DefinitionProvider: true,
DocumentFormattingProvider: true,
DocumentRangeFormattingProvider: true,
RenameProvider: true,
Expand Down
2 changes: 1 addition & 1 deletion internal/handler/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func TestInitialized(t *testing.T) {
},
},
CodeActionProvider: true,
DefinitionProvider: false,
DefinitionProvider: true,
DocumentFormattingProvider: true,
DocumentRangeFormattingProvider: true,
RenameProvider: true,
Expand Down
14 changes: 14 additions & 0 deletions internal/lsp/lsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,3 +486,17 @@ type OptionalVersionedTextDocumentIdentifier struct {
Version int32 `json:"version"`
TextDocumentIdentifier
}

type DefinitionParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
PartialResultParams
}

type TypeDefinitionParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
PartialResultParams
}

type Definition = []Location

0 comments on commit db8733f

Please sign in to comment.