-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial language server protocol implementation
- Loading branch information
1 parent
f57a807
commit d320a46
Showing
6 changed files
with
323 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | ||
return getDocumentSymbols(params, node), nil | ||
} | ||
return nil, nil | ||
} else { | ||
return nil, errors.New(fmt.Sprintf("% not open", params.TextDocument.URI)) | ||
} | ||
} | ||
|
||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | ||
var langHandler = &LangHandler{ | ||
files: make(map[string]*vimfile), | ||
} | ||
return jsonrpc2.HandlerWithError(langHandler.handle) | ||
} | ||
|
||
type LangHandler struct { | ||
files map[string]*vimfile | ||
} | ||
|
||
type vimfile struct { | ||
TextDocumentItem | ||
Ast *ast.File | ||
AstError error | ||
} | ||
|
||
func NewVimFile(textDocumentItem TextDocumentItem) (result *vimfile, error error) { | ||
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)} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package langserver | ||
|
||
type InitializeParams struct { | ||
ProcessID int `json:"processId,omitempty"` | ||
RootPath string `json:"rootPath,omitempty"` | ||
InitializationOptions InitializeOptions `json:"initializationOptions,omitempty"` | ||
Capabilities ClientCapabilities `json:"capabilities",omitempty` | ||
Trace string `json:"trace,omitempty"` | ||
} | ||
|
||
type InitializeOptions struct { | ||
} | ||
|
||
type ClientCapabilities struct { | ||
} | ||
|
||
type InitializeResult struct { | ||
Capabilities ServerCapabilities `json:"capabilities,omitempty"` | ||
} | ||
|
||
type TextDocumentSyncKind int | ||
|
||
const ( | ||
TDSKNone TextDocumentSyncKind = 0 | ||
TDSKFull = 1 | ||
TDSKIncremental = 2 | ||
) | ||
|
||
type ServerCapabilities struct { | ||
TextDocumentSync TextDocumentSyncKind `json:"textDocumentSync,omitempty"` | ||
DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"` | ||
} | ||
|
||
type TextDocumentItem struct { | ||
URI string `json:"uri"` | ||
LanguageId string `json:"languageId"` | ||
Version int `json:"version"` | ||
Text string `json:"text"` | ||
} | ||
|
||
type TextDocumentIdentifier struct { | ||
URI string `json:"uri"` | ||
} | ||
|
||
type DidOpenTextDocumentParams struct { | ||
TextDocument TextDocumentItem `json:"textDocument"` | ||
} | ||
|
||
type DocumentSymbolParams struct { | ||
TextDocument TextDocumentIdentifier | ||
} | ||
|
||
type SymbolKind int | ||
|
||
const ( | ||
SKFile SymbolKind = 1 | ||
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 { | ||
Name string `json:"name"` | ||
Kind SymbolKind `json:"kind"` | ||
Location Location `json:"location"` | ||
} | ||
|
||
type Location struct { | ||
URI string `json:"uri"` | ||
Range Range `json:"range"` | ||
} | ||
|
||
type Range struct { | ||
Start Position `json:"start"` | ||
End Position `json:"end"` | ||
} | ||
|
||
type Position struct { | ||
Line int `json:"line"` | ||
Character int `json:"character"` | ||
} |