Fix notifications vs requests

This commit is contained in:
Zachary Yedidia
2020-08-10 22:12:11 -04:00
parent 053134af1c
commit c344f1bfce
5 changed files with 119 additions and 107 deletions

View File

@@ -223,14 +223,17 @@ func LSPComplete(b *Buffer) ([]string, []string) {
}
suggestions := make([]string, len(items))
completions := make([]string, len(items))
for i, item := range items {
suggestions[i] = item.Label
}
completions := make([]string, len(suggestions))
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
if len(item.TextEdit.NewText) > 0 {
completions[i] = util.SliceEndStr(item.TextEdit.NewText, c.X-argstart)
} else if len(item.InsertText) > 0 {
completions[i] = util.SliceEndStr(item.InsertText, c.X-argstart)
} else {
completions[i] = util.SliceEndStr(item.Label, c.X-argstart)
}
}
return completions, suggestions

View File

@@ -0,0 +1,55 @@
package lsp
import "github.com/sourcegraph/go-lsp"
func (s *Server) DidOpen(filename, language, text string, version int) {
doc := lsp.TextDocumentItem{
URI: lsp.DocumentURI("file://" + filename),
LanguageID: language,
Version: version,
Text: text,
}
params := lsp.DidOpenTextDocumentParams{
TextDocument: doc,
}
s.sendNotification("textDocument/didOpen", params)
}
func (s *Server) DidSave(filename string) {
doc := lsp.TextDocumentIdentifier{
URI: lsp.DocumentURI("file://" + filename),
}
params := lsp.DidSaveTextDocumentParams{
TextDocument: doc,
}
s.sendNotification("textDocument/didSave", params)
}
func (s *Server) DidChange(filename string, version int, changes []lsp.TextDocumentContentChangeEvent) {
doc := lsp.VersionedTextDocumentIdentifier{
TextDocumentIdentifier: lsp.TextDocumentIdentifier{
URI: lsp.DocumentURI("file://" + filename),
},
Version: version,
}
params := lsp.DidChangeTextDocumentParams{
TextDocument: doc,
ContentChanges: changes,
}
s.sendNotification("textDocument/didChange", params)
}
func (s *Server) DidClose(filename string) {
doc := lsp.TextDocumentIdentifier{
URI: lsp.DocumentURI("file://" + filename),
}
params := lsp.DidCloseTextDocumentParams{
TextDocument: doc,
}
s.sendNotification("textDocument/didClose", params)
}

View File

@@ -12,58 +12,6 @@ type RPCCompletion struct {
Result lsp.CompletionList `json:"result"`
}
func (s *Server) DidOpen(filename, language, text string, version int) {
doc := lsp.TextDocumentItem{
URI: lsp.DocumentURI("file://" + filename),
LanguageID: language,
Version: version,
Text: text,
}
params := lsp.DidOpenTextDocumentParams{
TextDocument: doc,
}
s.SendMessage("textDocument/didOpen", params)
}
func (s *Server) DidSave(filename string) {
doc := lsp.TextDocumentIdentifier{
URI: lsp.DocumentURI("file://" + filename),
}
params := lsp.DidSaveTextDocumentParams{
TextDocument: doc,
}
s.SendMessage("textDocument/didSave", params)
}
func (s *Server) DidChange(filename string, version int, changes []lsp.TextDocumentContentChangeEvent) {
doc := lsp.VersionedTextDocumentIdentifier{
TextDocumentIdentifier: lsp.TextDocumentIdentifier{
URI: lsp.DocumentURI("file://" + filename),
},
Version: version,
}
params := lsp.DidChangeTextDocumentParams{
TextDocument: doc,
ContentChanges: changes,
}
s.SendMessage("textDocument/didChange", params)
}
func (s *Server) DidClose(filename string) {
doc := lsp.TextDocumentIdentifier{
URI: lsp.DocumentURI("file://" + filename),
}
params := lsp.DidCloseTextDocumentParams{
TextDocument: doc,
}
s.SendMessage("textDocument/didClose", params)
}
func (s *Server) DocumentFormat() {
}
@@ -88,7 +36,7 @@ func (s *Server) Completion(filename string, pos lsp.Position) ([]lsp.Completion
TextDocumentPositionParams: docpos,
Context: cc,
}
resp, err := s.SendMessageGetResponse("textDocument/completion", params)
resp, err := s.sendRequest("textDocument/completion", params)
if err != nil {
return nil, err
}

View File

@@ -35,13 +35,19 @@ type Server struct {
responses map[int]chan ([]byte)
}
type RPCMessage struct {
type RPCRequest struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
Method string `json:"method"`
Params interface{} `json:"params"`
}
type RPCNotification struct {
RPCVersion string `json:"jsonrpc"`
Method string `json:"method"`
Params interface{} `json:"params"`
}
type RPCInit struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
@@ -57,20 +63,23 @@ type RPCResult struct {
func StartServer(l Language) (*Server, error) {
c := exec.Command(l.Command, l.Args...)
log.Println("Running", l.Command, l.Args)
c.Stderr = log.Writer()
stdin, err := c.StdinPipe()
if err != nil {
log.Println("[micro-lsp]", err)
return nil, err
}
stdout, err := c.StdoutPipe()
if err != nil {
log.Println("[micro-lsp]", err)
return nil, err
}
err = c.Start()
if err != nil {
log.Println("[micro-lsp]", err)
return nil, err
}
@@ -143,56 +152,46 @@ func (s *Server) Initialize(directory string) {
},
}
err := s.SendMessage("initialize", params)
if err != nil {
return
}
activeServers[s.language.Command+"-"+directory] = s
s.active = true
resp, err := s.receiveMessage()
go s.receive()
resp, err := s.sendRequest("initialize", params)
if err != nil {
log.Println("[micro-lsp]", err)
return
}
// todo parse capabilities
log.Println("Received", string(resp))
log.Println("[micro-lsp] <<<", string(resp))
var r RPCInit
err = json.Unmarshal(resp, &r)
json.Unmarshal(resp, &r)
err = s.sendNotification("initialized", struct{}{})
if err != nil {
log.Println("[micro-lsp]", err)
return
}
err = s.SendMessage("initialized", struct{}{})
if err != nil {
return
}
slock.Lock()
activeServers[s.language.Command+"-"+directory] = s
slock.Unlock()
s.lock.Lock()
s.capabilities = r.Result.Capabilities
s.root = directory
s.active = true
s.lock.Unlock()
go s.receive()
}
func (s *Server) receive() {
for s.active {
resp, err := s.receiveMessage()
if err != nil {
log.Println(err)
log.Println("[micro-lsp]", err)
continue
}
log.Println("Received", string(resp))
log.Println("[micro-lsp] <<<", string(resp))
var r RPCResult
err = json.Unmarshal(resp, &r)
if err != nil {
log.Println(err)
log.Println("[micro-lsp]", err)
continue
}
@@ -213,13 +212,11 @@ func (s *Server) receive() {
func (s *Server) receiveMessage() ([]byte, error) {
n := -1
for {
log.Println("waiting for header")
b, err := s.stdout.ReadBytes('\n')
if err != nil {
return nil, err
}
headerline := strings.TrimSpace(string(b))
log.Println("Read header", headerline)
if len(headerline) == 0 {
break
}
@@ -239,21 +236,38 @@ func (s *Server) receiveMessage() ([]byte, error) {
return []byte{}, nil
}
log.Println("CONTENT-LENGTH:", n)
bytes := make([]byte, n)
_, err := io.ReadFull(s.stdout, bytes)
if err != nil {
log.Println("ERROR:", err)
log.Println("[micro-lsp]", err)
}
return bytes, err
}
func (s *Server) SendMessageGetResponse(method string, params interface{}) ([]byte, error) {
func (s *Server) sendNotification(method string, params interface{}) error {
m := RPCNotification{
RPCVersion: "2.0",
Method: method,
Params: params,
}
return s.sendMessage(m)
}
func (s *Server) sendRequest(method string, params interface{}) ([]byte, error) {
id := s.requestID
s.requestID++
r := make(chan []byte)
s.responses[id] = r
err := s.SendMessage(method, params)
m := RPCRequest{
RPCVersion: "2.0",
ID: id,
Method: method,
Params: params,
}
err := s.sendMessage(m)
if err != nil {
return nil, err
}
@@ -264,27 +278,19 @@ func (s *Server) SendMessageGetResponse(method string, params interface{}) ([]by
return bytes, nil
}
func (s *Server) SendMessage(method string, params interface{}) error {
m := RPCMessage{
RPCVersion: "2.0",
ID: s.requestID,
Method: method,
Params: params,
}
s.requestID++
func (s *Server) sendMessage(m interface{}) error {
msg, err := json.Marshal(m)
if err != nil {
return err
}
log.Println("[micro-lsp] >>>", string(msg))
// encode header and proper line endings
msg = append(msg, '\r', '\n')
header := []byte("Content-Length: " + strconv.Itoa(len(msg)) + "\r\n\r\n")
msg = append(header, msg...)
log.Println("Sending", string(msg))
s.stdin.Write(msg)
return nil
_, err = s.stdin.Write(msg)
return err
}

View File

@@ -32,11 +32,11 @@ command = "pyls"
install = [["pip", "install", "python-language-server"]]
[language.c]
command = "clangd"
args = ["--log=verbose"]
command = "ccls"
args = []
[language.cpp]
command = "clangd"
command = "ccls"
args = []
[language.haskell]