diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 8a4940ab..4eba4cc8 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -17,9 +17,8 @@ import ( "sync" "time" - luar "layeh.com/gopher-luar" - dmp "github.com/sergi/go-diff/diffmatchpatch" + lspt "github.com/sourcegraph/go-lsp" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/lsp" ulua "github.com/zyedidia/micro/v2/internal/lua" @@ -29,6 +28,7 @@ import ( "golang.org/x/text/encoding/htmlindex" "golang.org/x/text/encoding/unicode" "golang.org/x/text/transform" + luar "layeh.com/gopher-luar" ) const backupTime = 8000 @@ -137,12 +137,36 @@ func (b *SharedBuffer) insert(pos Loc, value []byte) { inslines := bytes.Count(value, []byte{'\n'}) b.MarkModified(pos.Y, pos.Y+inslines) + + b.lspDidChange(pos, pos.MoveLA(util.CharacterCount(value), b.LineArray), string(value)) } func (b *SharedBuffer) remove(start, end Loc) []byte { b.isModified = true b.HasSuggestions = false defer b.MarkModified(start.Y, end.Y) - return b.LineArray.remove(start, end) + sub := b.LineArray.remove(start, end) + b.lspDidChange(start, end, "") + return sub +} + +func (b *SharedBuffer) lspDidChange(start, end Loc, text string) { + b.version++ + // TODO: convert to UTF16 codepoints + change := lspt.TextDocumentContentChangeEvent{ + Range: &lspt.Range{ + Start: lspt.Position{ + Line: start.Y, + Character: start.X, + }, + End: lspt.Position{ + Line: end.Y, + Character: end.X, + }, + }, + Text: text, + } + + b.server.DidChange(b.AbsPath, b.version, []lspt.TextDocumentContentChangeEvent{change}) } // MarkModified marks the buffer as modified for this frame diff --git a/internal/lsp/requests.go b/internal/lsp/requests.go index bbaa6a2f..4aacbd7b 100644 --- a/internal/lsp/requests.go +++ b/internal/lsp/requests.go @@ -1,12 +1,10 @@ package lsp import ( - "log" - "github.com/sourcegraph/go-lsp" ) -func (s *Server) DidOpen(filename, language, text string, version int) error { +func (s *Server) DidOpen(filename, language, text string, version int) { doc := lsp.TextDocumentItem{ URI: lsp.DocumentURI("file://" + filename), LanguageID: language, @@ -18,12 +16,58 @@ func (s *Server) DidOpen(filename, language, text string, version int) error { TextDocument: doc, } - resp, err := s.SendMessage("textDocument/didOpen", params) - if err != nil { - return err + go s.SendMessage("textDocument/didOpen", params) +} + +func (s *Server) DidSave(filename string) { + doc := lsp.TextDocumentIdentifier{ + URI: lsp.DocumentURI("file://" + filename), } - log.Println("Received", string(resp)) - - return nil + params := lsp.DidSaveTextDocumentParams{ + TextDocument: doc, + } + go 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, + } + go s.SendMessage("textDocument/didChange", params) +} + +func (s *Server) DidClose(filename string) { + doc := lsp.TextDocumentIdentifier{ + URI: lsp.DocumentURI("file://" + filename), + } + + params := lsp.DidCloseTextDocumentParams{ + TextDocument: doc, + } + go s.SendMessage("textDocument/didClose", params) +} + +func (s *Server) DocumentFormat() { + +} + +func (s *Server) DocumentRangeFormat() { + +} + +func (s *Server) Completion() { + +} + +func (s *Server) CompletionResolve() { + } diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 432e0f1c..459e210b 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -3,22 +3,23 @@ package lsp import ( "bufio" "encoding/json" - "fmt" "io" "log" "os" "os/exec" "strconv" "strings" + "sync" "github.com/sourcegraph/go-lsp" "github.com/zyedidia/micro/v2/internal/util" ) -var ActiveServers map[string]*Server +var activeServers map[string]*Server +var slock sync.Mutex func init() { - ActiveServers = make(map[string]*Server) + activeServers = make(map[string]*Server) } type Server struct { @@ -27,6 +28,8 @@ type Server struct { stdout *bufio.Reader language *Language capabilities lsp.ServerCapabilities + root string + lock sync.Mutex } type RPCMessage struct { @@ -68,12 +71,14 @@ func StartServer(l Language) (*Server, error) { s.stdout = bufio.NewReader(stdout) s.language = &l - // ActiveServers[l.Command] = s + // activeServers[l.Command] = s return s, nil } -func (s *Server) Initialize(directory string) error { +// Initialize performs the LSP initialization handshake +// The directory must be an absolute path +func (s *Server) Initialize(directory string) { params := lsp.InitializeParams{ ProcessID: os.Getpid(), RootURI: lsp.DocumentURI("file://" + directory), @@ -128,30 +133,35 @@ func (s *Server) Initialize(directory string) error { }, } - resp, err := s.SendMessage("initialize", params) - if err != nil { - return err - } + go func() { + resp, err := s.SendMessage("initialize", params) + if err != nil { + return + } - // todo parse capabilities - log.Println("Received", string(resp)) + // todo parse capabilities + log.Println("Received", string(resp)) - var r RPCInit - err = json.Unmarshal(resp, &r) - if err != nil { - return err - } + var r RPCInit + err = json.Unmarshal(resp, &r) + if err != nil { + return + } - fmt.Println(r) - s.capabilities = r.Result.Capabilities - fmt.Println(s.capabilities) + _, err = s.SendMessage("initialized", struct{}{}) + if err != nil { + return + } - _, err = s.SendMessage("initialized", struct{}{}) - if err != nil { - return err - } + slock.Lock() + activeServers[s.language.Command+"-"+directory] = s + slock.Unlock() - return nil + s.lock.Lock() + s.capabilities = r.Result.Capabilities + s.root = directory + s.lock.Unlock() + }() } func (s *Server) SendMessage(method string, params interface{}) ([]byte, error) { @@ -174,6 +184,7 @@ func (s *Server) SendMessage(method string, params interface{}) ([]byte, error) log.Println("Sending", string(msg)) + s.lock.Lock() s.stdin.Write(msg) n := -1 @@ -208,5 +219,9 @@ func (s *Server) SendMessage(method string, params interface{}) ([]byte, error) return nil, err } + log.Println("Received", string(bytes)) + + s.lock.Unlock() + return bytes, nil }