Skip to content
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

Add go-langserver #74

Merged
merged 1 commit into from
Aug 18, 2018
Merged

Add go-langserver #74

merged 1 commit into from
Aug 18, 2018

Conversation

edkolev
Copy link
Contributor

@edkolev edkolev commented Aug 15, 2018

This PR adds auto-detection for go-mode buffers utilizing https://github.com/sourcegraph/go-langserver.

@edkolev
Copy link
Contributor Author

edkolev commented Aug 17, 2018

I'm getting these errors on save:

server-reply (id:2) ERROR Fri Aug 17 22:22:58 2018:
(:id 2 :error
     (:code -32601 :message "method not supported: textDocument/willSaveWaitUntil" :data nil)
     :jsonrpc "2.0")

Seems like eglot--server-capable is misbehaving when it receives multiple inputs. With go-langserver, the capabilities are (as returned by (eglot--capabilities (eglot--current-server-or-lose))):

(:textDocumentSync 2 :hoverProvider t :completionProvider (:triggerCharacters ["."]) :signatureHelpProvider (:triggerCharacters ["(" ","]) :definitionProvider t :typeDefinitionProvider t :referencesProvider t :documentSymbolProvider t :workspaceSymbolProvider t :implementationProvider t :documentFormattingProvider t :xworkspaceReferencesProvider t :xdefinitionProvider t :xworkspaceSymbolByProperties t)

Here's the return value of eglot--server-capable, which seems to me inconsistent:

;; this is how the function is called here https://github.com/joaotavora/eglot/blob/master/eglot.el#L1215
(eglot--server-capable :textDocumentSync :willSaveWaitUntil) ;; => 2

(eglot--server-capable :willSaveWaitUntil :textDocumentSync) ;; => nil
(eglot--server-capable :textDocumentSync) ;; => 2
(eglot--server-capable :willSaveWaitUntil) ;; => nil

@edkolev
Copy link
Contributor Author

edkolev commented Aug 17, 2018

I just pushed another commit, intended to address the issue above.

@joaotavora
Copy link
Owner

@edkolev, although redesigning this problematic function isn't bad per se, you are breaking other use cases. I think, the correct fix is more like this

diff --git a/eglot.el b/eglot.el
index 88c6b45..63fbce2 100644
--- a/eglot.el
+++ b/eglot.el
@@ -728,12 +728,12 @@ under cursor."
                    feats)
     (cl-loop for caps = (eglot--capabilities (eglot--current-server-or-lose))
              then (cadr probe)
-             for feat in feats
+             for (feat . more) on feats
              for probe = (plist-member caps feat)
              if (not probe) do (cl-return nil)
              if (eq (cadr probe) :json-false) do (cl-return nil)
-             if (not (listp (cadr probe))) do (cl-return (cadr probe))
-             finally (cl-return (or probe t)))))
+             if (not (listp (cadr probe))) do (cl-return (if more nil (cadr probe)))
+             finally (cl-return (or (cadr probe) t)))))
 
 (defun eglot--range-region (range &optional markers)
   "Return region (BEG . END) that represents LSP RANGE.

Here is a unit test with some cases that the function must pass. Feel free to add more and discuss them here. If there are no objections I will push my version (and the unit test) sometime tomorrow.

(ert-deftest eglot-capabilities ()
  "Test `eglot--server-capable'"
  (cl-letf (((symbol-function 'eglot--capabilities)
             (lambda (_dummy)
               ;; test data lifted from Golangserver example at
               ;; https://github.com/joaotavora/eglot/pull/74
               (list :textDocumentSync 2 :hoverProvider t
                     :completionProvider '(:triggerCharacters ["."])
                     :signatureHelpProvider '(:triggerCharacters ["(" ","])
                     :definitionProvider t :typeDefinitionProvider t
                     :referencesProvider t :documentSymbolProvider t
                     :workspaceSymbolProvider t :implementationProvider t
                     :documentFormattingProvider t :xworkspaceReferencesProvider t
                     :xdefinitionProvider t :xworkspaceSymbolByProperties t)))
            ((symbol-function 'eglot--current-server-or-lose)
             (lambda () nil)))
    (should (eql 2 (eglot--server-capable :textDocumentSync)))
    (should (eglot--server-capable :completionProvider :triggerCharacters))
    (should (equal '(:triggerCharacters ["."]) (eglot--server-capable :completionProvider)))
    (should-not (eglot--server-capable :foobarbaz))
    (should-not (eglot--server-capable :textDocumentSync :foobarbaz))))

joaotavora added a commit that referenced this pull request Aug 17, 2018
* eglot-tests.el (eglot-capabilities): New test.

* eglot.el (eglot--server-capable): Fix problems with queries for
multiple capabilities.
@joaotavora
Copy link
Owner

I will push my version (and the unit test) sometime tomorrow.

Actually, I changed my mind. Better push it now and amend it if you have any objections.

@edkolev
Copy link
Contributor Author

edkolev commented Aug 18, 2018

No objections, plus I don't see the error in the logs anymore. I removed the commit which changed the eglot--server-capable function.

I'm getting however this lisp error with the go language server (I don't see it with the python lang server):

Debugger entered--Lisp error: (wrong-type-argument char-or-string-p nil)
  insert(nil)
  (progn (condition-case nil (progn (funcall mode)) (error nil)) (insert string) (font-lock-ensure) (buffer-string))
  (unwind-protect (progn (condition-case nil (progn (funcall mode)) (error nil)) (insert string) (font-lock-ensure) (buffer-string)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))
  (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (condition-case nil (progn (funcall mode)) (error nil)) (insert string) (font-lock-ensure) (buffer-string)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer))))
  (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (condition-case nil (progn (funcall mode)) (error nil)) (insert string) (font-lock-ensure) (buffer-string)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
  (let ((mode x6) (string x4)) (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (condition-case nil (progn (funcall mode)) (error nil)) (insert string) (font-lock-ensure) (buffer-string)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer))))))
  (let* ((val (if (stringp markup) (list (string-trim markup) (intern "gfm-mode")) (list (plist-get markup :value) (intern (concat (plist-get markup :language) "-mode"))))) (x4 (car val)) (x5 (cdr val)) (x6 (car x5)) (x7 (cdr x5))) (let ((mode x6) (string x4)) (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (condition-case nil (progn (funcall mode)) (error nil)) (insert string) (font-lock-ensure) (buffer-string)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))))))
  eglot--format-markup(nil)
  mapconcat(eglot--format-markup (nil) "\n")
  (let ((heading (and range (let* ((val (eglot--range-region range)) (x24 (car val)) (x25 (cdr val))) (let ((end x25) (beg x24)) (concat (buffer-substring beg end) ": "))))) (body (mapconcat (function eglot--format-markup) (if (vectorp contents) contents (list contents)) "\n"))) (if (or heading (cl-plusp (length body))) (progn (concat heading body))))
  eglot--hover-info(nil nil)
  (and t (eglot--hover-info contents range))
  (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil))
  (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil)))
  (progn (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil))))
  (if (or (get-buffer-window buffer) (ert-running-test)) (progn (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil)))))
  (if sig-showing nil (if (or (get-buffer-window buffer) (ert-running-test)) (progn (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil))))))
  (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:contents :range :allow-other-keys)) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ':allow-other-keys --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:contents :range)" (car --cl-keys--)))))) (if sig-showing nil (if (or (get-buffer-window buffer) (ert-running-test)) (progn (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil)))))))
  (let* ((contents (car (cdr (plist-member --cl-rest-- ':contents)))) (range (car (cdr (plist-member --cl-rest-- ':range))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:contents :range :allow-other-keys)) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ':allow-other-keys --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:contents :range)" (car --cl-keys--)))))) (if sig-showing nil (if (or (get-buffer-window buffer) (ert-running-test)) (progn (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil))))))))
  (closure ((jsonrpc-lambda-elem12) (sig-showing) (position-params :textDocument (:uri "file:///Users/edkolev/Exercism/go/isogram/isogram.go") :position (:line 6 :character 0)) (server . #<eglot-lsp-server eglot-lsp-server>) (buffer . #<buffer isogram.go>) eglot--managed-mode t) (&rest --cl-rest--) "\n\n(fn &key CONTENTS RANGE)" (let* ((contents (car (cdr (plist-member --cl-rest-- ':contents)))) (range (car (cdr (plist-member --cl-rest-- ':range))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:contents :range :allow-other-keys)) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ':allow-other-keys --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:contents :range)" (car --cl-keys--)))))) (if sig-showing nil (if (or (get-buffer-window buffer) (ert-running-test)) (progn (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil)))))))))()
  apply((closure ((jsonrpc-lambda-elem12) (sig-showing) (position-params :textDocument (:uri "file:///Users/edkolev/Exercism/go/isogram/isogram.go") :position (:line 6 :character 0)) (server . #<eglot-lsp-server eglot-lsp-server>) (buffer . #<buffer isogram.go>) eglot--managed-mode t) (&rest --cl-rest--) "\n\n(fn &key CONTENTS RANGE)" (let* ((contents (car (cdr (plist-member --cl-rest-- ':contents)))) (range (car (cdr (plist-member --cl-rest-- ':range))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:contents :range :allow-other-keys)) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ':allow-other-keys --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:contents :range)" (car --cl-keys--)))))) (if sig-showing nil (if (or (get-buffer-window buffer) (ert-running-test)) (progn (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil))))))))) nil)
  (closure ((sig-showing) (position-params :textDocument (:uri "file:///Users/edkolev/Exercism/go/isogram/isogram.go") :position (:line 6 :character 0)) (server . #<eglot-lsp-server eglot-lsp-server>) (buffer . #<buffer isogram.go>) eglot--managed-mode t) (jsonrpc-lambda-elem12) (apply (function (lambda (&rest --cl-rest--) "\n\n(fn &key CONTENTS RANGE)" (let* ((contents (car (cdr (plist-member --cl-rest-- ':contents)))) (range (car (cdr (plist-member --cl-rest-- ':range))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:contents :range :allow-other-keys)) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ':allow-other-keys --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:contents :range)" (car --cl-keys--)))))) (if sig-showing nil (if (or (get-buffer-window buffer) (ert-running-test)) (progn (save-current-buffer (set-buffer buffer) (let* ((info (and t (eglot--hover-info contents range)))) (if info (eldoc-message info) nil)))))))))) jsonrpc-lambda-elem12))(nil)
  jsonrpc-connection-receive(#<eglot-lsp-server eglot-lsp-server> (:id 13 :result nil :jsonrpc "2.0"))
  jsonrpc--process-filter(#<process EGLOT (isogram/go-mode)> "Content-Length: 39\015\n\015\n{\"id\":13,\"result\":null,\"jsonrpc\":\"2.0\"}")

@joaotavora
Copy link
Owner

I'm getting however this lisp error with the go language server (I don't see it with the python lang server):

This is likely a bug introduced by a later commit. It shouldn't be very hard to fix...

joaotavora added a commit that referenced this pull request Aug 18, 2018
* eglot.el (eglot-eldoc-function): Check non-nil contents.
@joaotavora
Copy link
Owner

This is likely a bug introduced by a later commit.

Actually, it wasn't, but I fixed it anyway.

@joaotavora joaotavora merged commit e711bdb into joaotavora:master Aug 18, 2018
@joaotavora
Copy link
Owner

Pushed with a tweak to the commit message

@edkolev
Copy link
Contributor Author

edkolev commented Aug 19, 2018

Great, thanks!

I've signed FSF's copyright assignment BTW.

@joaotavora
Copy link
Owner

joaotavora commented Aug 19, 2018 via email

mkcms pushed a commit that referenced this pull request Oct 24, 2018
Copyright-paperwork-exempt: yes

* eglot.el (eglot--mode-line-format): Fix a typo.
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 18, 2022
…tiple features

* eglot-tests.el (eglot-capabilities): New test.

* eglot.el (eglot--server-capable): Fix problems with queries for
multiple capabilities.
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 18, 2022
…er message

* eglot.el (eglot-eldoc-function): Check non-nil contents.
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
…tiple features

* eglot-tests.el (eglot-capabilities): New test.

* eglot.el (eglot--server-capable): Fix problems with queries for
multiple capabilities.
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
…er message

* eglot.el (eglot-eldoc-function): Check non-nil contents.
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
* eglot-tests.el (eglot-capabilities): New test.

* eglot.el (eglot--server-capable): Fix problems with queries for
multiple capabilities.

#74: joaotavora/eglot#74
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
* eglot.el (eglot-eldoc-function): Check non-nil contents.

#74: joaotavora/eglot#74
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
Copyright-paperwork-exempt: yes

* README.md (Installation and usage): Add go-langserver.
* eglot.el (eglot-server-programs): Add go-langserver.
(#74: joaotavora/eglot#74
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
Copyright-paperwork-exempt: yes

* eglot.el (eglot--mode-line-format): Fix a typo.

(#74: joaotavora/eglot#74
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Oct 12, 2022
* eglot-tests.el (eglot-capabilities): New test.

* eglot.el (eglot--server-capable): Fix problems with queries for
multiple capabilities.

GitHub-reference: per joaotavora/eglot#74
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Oct 12, 2022
* eglot.el (eglot-eldoc-function): Check non-nil contents.

GitHub-reference: per joaotavora/eglot#74
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Oct 12, 2022
Copyright-paperwork-exempt: yes

* README.md (Installation and usage): Add go-langserver.
* eglot.el (eglot-server-programs): Add go-langserver.

GitHub-reference: joaotavora/eglot#74
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Oct 12, 2022
Copyright-paperwork-exempt: yes

* eglot.el (eglot--mode-line-format): Fix a typo.

GitHub-reference: joaotavora/eglot#74
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants