mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-30 14:47:16 +09:00
Fix notifications vs requests
This commit is contained in:
@@ -223,14 +223,17 @@ func LSPComplete(b *Buffer) ([]string, []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suggestions := make([]string, len(items))
|
suggestions := make([]string, len(items))
|
||||||
|
completions := make([]string, len(items))
|
||||||
|
|
||||||
for i, item := range items {
|
for i, item := range items {
|
||||||
suggestions[i] = item.Label
|
suggestions[i] = item.Label
|
||||||
}
|
if len(item.TextEdit.NewText) > 0 {
|
||||||
|
completions[i] = util.SliceEndStr(item.TextEdit.NewText, c.X-argstart)
|
||||||
completions := make([]string, len(suggestions))
|
} else if len(item.InsertText) > 0 {
|
||||||
for i := range suggestions {
|
completions[i] = util.SliceEndStr(item.InsertText, c.X-argstart)
|
||||||
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
|
} else {
|
||||||
|
completions[i] = util.SliceEndStr(item.Label, c.X-argstart)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return completions, suggestions
|
return completions, suggestions
|
||||||
|
|||||||
55
internal/lsp/notifications.go
Normal file
55
internal/lsp/notifications.go
Normal 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)
|
||||||
|
}
|
||||||
@@ -12,58 +12,6 @@ type RPCCompletion struct {
|
|||||||
Result lsp.CompletionList `json:"result"`
|
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() {
|
func (s *Server) DocumentFormat() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -88,7 +36,7 @@ func (s *Server) Completion(filename string, pos lsp.Position) ([]lsp.Completion
|
|||||||
TextDocumentPositionParams: docpos,
|
TextDocumentPositionParams: docpos,
|
||||||
Context: cc,
|
Context: cc,
|
||||||
}
|
}
|
||||||
resp, err := s.SendMessageGetResponse("textDocument/completion", params)
|
resp, err := s.sendRequest("textDocument/completion", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,13 +35,19 @@ type Server struct {
|
|||||||
responses map[int]chan ([]byte)
|
responses map[int]chan ([]byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RPCMessage struct {
|
type RPCRequest struct {
|
||||||
RPCVersion string `json:"jsonrpc"`
|
RPCVersion string `json:"jsonrpc"`
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Params interface{} `json:"params"`
|
Params interface{} `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RPCNotification struct {
|
||||||
|
RPCVersion string `json:"jsonrpc"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Params interface{} `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
type RPCInit struct {
|
type RPCInit struct {
|
||||||
RPCVersion string `json:"jsonrpc"`
|
RPCVersion string `json:"jsonrpc"`
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
@@ -57,20 +63,23 @@ type RPCResult struct {
|
|||||||
func StartServer(l Language) (*Server, error) {
|
func StartServer(l Language) (*Server, error) {
|
||||||
c := exec.Command(l.Command, l.Args...)
|
c := exec.Command(l.Command, l.Args...)
|
||||||
|
|
||||||
log.Println("Running", l.Command, l.Args)
|
c.Stderr = log.Writer()
|
||||||
|
|
||||||
stdin, err := c.StdinPipe()
|
stdin, err := c.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("[micro-lsp]", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, err := c.StdoutPipe()
|
stdout, err := c.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("[micro-lsp]", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Start()
|
err = c.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("[micro-lsp]", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,56 +152,46 @@ func (s *Server) Initialize(directory string) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.SendMessage("initialize", params)
|
activeServers[s.language.Command+"-"+directory] = s
|
||||||
if err != nil {
|
s.active = true
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := s.receiveMessage()
|
go s.receive()
|
||||||
|
|
||||||
|
resp, err := s.sendRequest("initialize", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("[micro-lsp]", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo parse capabilities
|
// todo parse capabilities
|
||||||
log.Println("Received", string(resp))
|
log.Println("[micro-lsp] <<<", string(resp))
|
||||||
|
|
||||||
var r RPCInit
|
var r RPCInit
|
||||||
err = json.Unmarshal(resp, &r)
|
json.Unmarshal(resp, &r)
|
||||||
|
|
||||||
|
err = s.sendNotification("initialized", struct{}{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("[micro-lsp]", err)
|
||||||
return
|
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.capabilities = r.Result.Capabilities
|
||||||
s.root = directory
|
s.root = directory
|
||||||
s.active = true
|
|
||||||
s.lock.Unlock()
|
|
||||||
|
|
||||||
go s.receive()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) receive() {
|
func (s *Server) receive() {
|
||||||
for s.active {
|
for s.active {
|
||||||
resp, err := s.receiveMessage()
|
resp, err := s.receiveMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println("[micro-lsp]", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Println("Received", string(resp))
|
log.Println("[micro-lsp] <<<", string(resp))
|
||||||
|
|
||||||
var r RPCResult
|
var r RPCResult
|
||||||
err = json.Unmarshal(resp, &r)
|
err = json.Unmarshal(resp, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println("[micro-lsp]", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,13 +212,11 @@ func (s *Server) receive() {
|
|||||||
func (s *Server) receiveMessage() ([]byte, error) {
|
func (s *Server) receiveMessage() ([]byte, error) {
|
||||||
n := -1
|
n := -1
|
||||||
for {
|
for {
|
||||||
log.Println("waiting for header")
|
|
||||||
b, err := s.stdout.ReadBytes('\n')
|
b, err := s.stdout.ReadBytes('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
headerline := strings.TrimSpace(string(b))
|
headerline := strings.TrimSpace(string(b))
|
||||||
log.Println("Read header", headerline)
|
|
||||||
if len(headerline) == 0 {
|
if len(headerline) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -239,21 +236,38 @@ func (s *Server) receiveMessage() ([]byte, error) {
|
|||||||
return []byte{}, nil
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("CONTENT-LENGTH:", n)
|
|
||||||
|
|
||||||
bytes := make([]byte, n)
|
bytes := make([]byte, n)
|
||||||
_, err := io.ReadFull(s.stdout, bytes)
|
_, err := io.ReadFull(s.stdout, bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("ERROR:", err)
|
log.Println("[micro-lsp]", err)
|
||||||
}
|
}
|
||||||
return bytes, 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
|
id := s.requestID
|
||||||
|
s.requestID++
|
||||||
r := make(chan []byte)
|
r := make(chan []byte)
|
||||||
s.responses[id] = r
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -264,27 +278,19 @@ func (s *Server) SendMessageGetResponse(method string, params interface{}) ([]by
|
|||||||
return bytes, nil
|
return bytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SendMessage(method string, params interface{}) error {
|
func (s *Server) sendMessage(m interface{}) error {
|
||||||
m := RPCMessage{
|
|
||||||
RPCVersion: "2.0",
|
|
||||||
ID: s.requestID,
|
|
||||||
Method: method,
|
|
||||||
Params: params,
|
|
||||||
}
|
|
||||||
s.requestID++
|
|
||||||
|
|
||||||
msg, err := json.Marshal(m)
|
msg, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("[micro-lsp] >>>", string(msg))
|
||||||
|
|
||||||
// encode header and proper line endings
|
// encode header and proper line endings
|
||||||
msg = append(msg, '\r', '\n')
|
msg = append(msg, '\r', '\n')
|
||||||
header := []byte("Content-Length: " + strconv.Itoa(len(msg)) + "\r\n\r\n")
|
header := []byte("Content-Length: " + strconv.Itoa(len(msg)) + "\r\n\r\n")
|
||||||
msg = append(header, msg...)
|
msg = append(header, msg...)
|
||||||
|
|
||||||
log.Println("Sending", string(msg))
|
_, err = s.stdin.Write(msg)
|
||||||
|
return err
|
||||||
s.stdin.Write(msg)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ command = "pyls"
|
|||||||
install = [["pip", "install", "python-language-server"]]
|
install = [["pip", "install", "python-language-server"]]
|
||||||
|
|
||||||
[language.c]
|
[language.c]
|
||||||
command = "clangd"
|
command = "ccls"
|
||||||
args = ["--log=verbose"]
|
args = []
|
||||||
|
|
||||||
[language.cpp]
|
[language.cpp]
|
||||||
command = "clangd"
|
command = "ccls"
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
[language.haskell]
|
[language.haskell]
|
||||||
|
|||||||
Reference in New Issue
Block a user