-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
initial language server protocol implementation #27
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"os" | ||
|
||
"github.com/haya14busa/go-vimlparser/langserver" | ||
"github.com/sourcegraph/jsonrpc2" | ||
) | ||
|
||
func main() { | ||
log.Println("langserver-vim: reading on stdin, writing on stdout") | ||
var connOpt []jsonrpc2.ConnOpt | ||
<-jsonrpc2.NewConn(context.Background(), jsonrpc2.NewBufferedStream(stdrwc{}, jsonrpc2.VSCodeObjectCodec{}), langserver.NewHandler(), connOpt...).DisconnectNotify() | ||
log.Println("langserver-vim: connections closed") | ||
} | ||
|
||
type stdrwc struct{} | ||
|
||
func (stdrwc) Read(p []byte) (int, error) { | ||
return os.Stdin.Read(p) | ||
} | ||
|
||
func (stdrwc) Write(p []byte) (int, error) { | ||
return os.Stdout.Write(p) | ||
} | ||
|
||
func (stdrwc) Close() error { | ||
if err := os.Stdin.Close(); err != nil { | ||
return err | ||
} | ||
return os.Stdout.Close() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package langserver | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
|
||
"github.com/sourcegraph/jsonrpc2" | ||
) | ||
|
||
func (h *LangHandler) handleInitialize(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 InitializeParams | ||
if err := json.Unmarshal(*req.Params, ¶ms); err != nil { | ||
return nil, err | ||
} | ||
|
||
return InitializeResult{ | ||
Capabilities: ServerCapabilities{ | ||
TextDocumentSync: TDSKFull, | ||
DocumentSymbolProvider: true, | ||
}, | ||
}, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package langserver | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
|
||
"github.com/sourcegraph/jsonrpc2" | ||
) | ||
|
||
func (h *LangHandler) handleTextDocumentDidOpen(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 DidOpenTextDocumentParams | ||
if err := json.Unmarshal(*req.Params, ¶ms); err != nil { | ||
return nil, err | ||
} | ||
|
||
f, err := NewVimFile(params.TextDocument) | ||
if err != nil { | ||
return nil, err | ||
} else { | ||
h.files[params.TextDocument.URI] = f | ||
return nil, nil | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package langserver | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/haya14busa/go-vimlparser/ast" | ||
|
||
"github.com/sourcegraph/jsonrpc2" | ||
) | ||
|
||
func (h *LangHandler) handleTextDocumentSymbols(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 DocumentSymbolParams | ||
if err := json.Unmarshal(*req.Params, ¶ms); err != nil { | ||
return nil, err | ||
} | ||
|
||
if f, ok := h.files[params.TextDocument.URI]; ok { | ||
node, err := f.GetAst() | ||
if err != nil { | ||
return nil, err | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
return getDocumentSymbols(params, node), nil | ||
} | ||
return nil, nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [govet] reported by reviewdog 🐶 |
||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
return nil, errors.New(fmt.Sprintf("% not open", params.TextDocument.URI)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [govet] reported by reviewdog 🐶 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
} | ||
} | ||
|
||
func getDocumentSymbols(params DocumentSymbolParams, node ast.Node) []SymbolInformation { | ||
var symbols []SymbolInformation | ||
ast.Inspect(node, func(n ast.Node) bool { | ||
var name string | ||
var kind SymbolKind | ||
var pos ast.Pos | ||
switch x := n.(type) { | ||
case *ast.Function: | ||
switch y := x.Name.(type) { | ||
case *ast.Ident: | ||
kind = SKFunction | ||
name = y.Name | ||
pos = y.NamePos | ||
} | ||
|
||
if name != "" { | ||
symbols = append(symbols, SymbolInformation{ | ||
Name: name, | ||
Kind: kind, | ||
Location: Location{ | ||
URI: params.TextDocument.URI, | ||
Range: Range{ | ||
Start: Position{ | ||
Line: pos.Line - 1, | ||
Character: pos.Column - 1, | ||
}, | ||
End: Position{ | ||
Line: pos.Line - 1, | ||
Character: pos.Column + len(name) - 1, | ||
}, | ||
}, | ||
}, | ||
}) | ||
return false | ||
} | ||
} | ||
return true | ||
}) | ||
return symbols | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package langserver | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"fmt" | ||
|
||
"github.com/haya14busa/go-vimlparser" | ||
"github.com/haya14busa/go-vimlparser/ast" | ||
|
||
"github.com/sourcegraph/jsonrpc2" | ||
) | ||
|
||
func NewHandler() jsonrpc2.Handler { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
var langHandler = &LangHandler{ | ||
files: make(map[string]*vimfile), | ||
} | ||
return jsonrpc2.HandlerWithError(langHandler.handle) | ||
} | ||
|
||
type LangHandler struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
files map[string]*vimfile | ||
} | ||
|
||
type vimfile struct { | ||
TextDocumentItem | ||
Ast *ast.File | ||
AstError error | ||
} | ||
|
||
func NewVimFile(textDocumentItem TextDocumentItem) (result *vimfile, error error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
return &vimfile{ | ||
TextDocumentItem: textDocumentItem, | ||
Ast: nil, | ||
AstError: nil, | ||
}, nil | ||
} | ||
|
||
func (f *vimfile) GetAst() (result *ast.File, error error) { | ||
if f.AstError != nil { | ||
return nil, f.AstError | ||
} else if f.Ast != nil { | ||
return f.Ast, nil | ||
} else { | ||
opt := &vimlparser.ParseOption{Neovim: false} | ||
r := bytes.NewBufferString(f.Text) | ||
ast, err := vimlparser.ParseFile(r, f.URI, opt) | ||
f.Ast = ast | ||
f.AstError = err | ||
return ast, err | ||
} | ||
} | ||
|
||
func (h *LangHandler) handle(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request) (result interface{}, err error) { | ||
switch req.Method { | ||
case "initialize": | ||
return h.handleInitialize(ctx, conn, req) | ||
case "textDocument/didOpen": | ||
return h.handleTextDocumentDidOpen(ctx, conn, req) | ||
case "textDocument/documentSymbol": | ||
return h.handleTextDocumentSymbols(ctx, conn, req) | ||
} | ||
|
||
return nil, &jsonrpc2.Error{Code: jsonrpc2.CodeMethodNotFound, Message: fmt.Sprintf("method not supported: %s", req.Method)} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package langserver | ||
|
||
type InitializeParams struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
ProcessID int `json:"processId,omitempty"` | ||
RootPath string `json:"rootPath,omitempty"` | ||
InitializationOptions InitializeOptions `json:"initializationOptions,omitempty"` | ||
Capabilities ClientCapabilities `json:"capabilities",omitempty` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [govet] reported by reviewdog 🐶 |
||
Trace string `json:"trace,omitempty"` | ||
} | ||
|
||
type InitializeOptions struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
} | ||
|
||
type ClientCapabilities struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
} | ||
|
||
type InitializeResult struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
Capabilities ServerCapabilities `json:"capabilities,omitempty"` | ||
} | ||
|
||
type TextDocumentSyncKind int | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
|
||
const ( | ||
TDSKNone TextDocumentSyncKind = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
TDSKFull = 1 | ||
TDSKIncremental = 2 | ||
) | ||
|
||
type ServerCapabilities struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
TextDocumentSync TextDocumentSyncKind `json:"textDocumentSync,omitempty"` | ||
DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"` | ||
} | ||
|
||
type TextDocumentItem struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
URI string `json:"uri"` | ||
LanguageId string `json:"languageId"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
Version int `json:"version"` | ||
Text string `json:"text"` | ||
} | ||
|
||
type TextDocumentIdentifier struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
URI string `json:"uri"` | ||
} | ||
|
||
type DidOpenTextDocumentParams struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
TextDocument TextDocumentItem `json:"textDocument"` | ||
} | ||
|
||
type DocumentSymbolParams struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
TextDocument TextDocumentIdentifier | ||
} | ||
|
||
type SymbolKind int | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
|
||
const ( | ||
SKFile SymbolKind = 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
SKModule SymbolKind = 2 | ||
SKNamespace SymbolKind = 3 | ||
SKPackage SymbolKind = 4 | ||
SKClass SymbolKind = 5 | ||
SKMethod SymbolKind = 6 | ||
SKProperty SymbolKind = 7 | ||
SKField SymbolKind = 8 | ||
SKConstructor SymbolKind = 9 | ||
SKEnum SymbolKind = 10 | ||
SKInterface SymbolKind = 11 | ||
SKFunction SymbolKind = 12 | ||
SKVariable SymbolKind = 13 | ||
SKConstant SymbolKind = 14 | ||
SKString SymbolKind = 15 | ||
SKNumber SymbolKind = 16 | ||
SKBoolean SymbolKind = 17 | ||
SKArray SymbolKind = 18 | ||
) | ||
|
||
type SymbolInformation struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
Name string `json:"name"` | ||
Kind SymbolKind `json:"kind"` | ||
Location Location `json:"location"` | ||
} | ||
|
||
type Location struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
URI string `json:"uri"` | ||
Range Range `json:"range"` | ||
} | ||
|
||
type Range struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
Start Position `json:"start"` | ||
End Position `json:"end"` | ||
} | ||
|
||
type Position struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [golint] reported by reviewdog 🐶 |
||
Line int `json:"line"` | ||
Character int `json:"character"` | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[golint] reported by reviewdog 🐶
if block ends with a return statement, so drop this else and outdent its block