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

Introduce cquery support #6

Merged
merged 4 commits into from
May 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ for the language of your choice. Otherwise, it prompts you to enter one:
* Python's [pyls][pyls]
* Bash's [bash-language-server][bash-language-server]
* PHP's [php-language-server][php-language-server]
* [cquery][cquery] for C/C++


I'll add to this list as I test more servers. In the meantime you can
customize `eglot-server-programs`:
Expand Down Expand Up @@ -196,5 +198,7 @@ Under the hood:
[bash-language-server]: https://github.com/mads-hartmann/bash-language-server
[php-language-server]: https://github.com/felixfbecker/php-language-server
[company-mode]: https://github.com/company-mode/company-mode
[cquery]: https://github.com/cquery-project/cquery



50 changes: 41 additions & 9 deletions eglot.el
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
(python-mode . ("pyls"))
(js-mode . ("javascript-typescript-stdio"))
(sh-mode . ("bash-language-server" "start"))
(c++-mode . (eglot-cquery "cquery"))
(c-mode . (eglot-cquery "cquery"))
(php-mode . ("php" "vendor/felixfbecker/\
language-server/bin/php-language-server.php")))
"How the command `eglot' guesses the server to start.
Expand Down Expand Up @@ -430,7 +432,7 @@ INTERACTIVE is t if called interactively."
(defun eglot--process-sentinel (proc change)
"Called when PROC undergoes CHANGE."
(let ((server (process-get proc 'eglot-server)))
(eglot--log-event server `(:message "Process state changed" :change ,change))
(eglot--debug server "Process state changed: %s" change)
(when (not (process-live-p proc))
(with-current-buffer (eglot-events-buffer server)
(let ((inhibit-read-only t))
Expand Down Expand Up @@ -595,8 +597,7 @@ originated."
(condition-case-unless-debug _err
(apply #'eglot-handle-notification server method params)
(cl-no-applicable-method
(eglot--log-event
server '(:error `(:message "Notification unimplemented"))))))
(eglot--debug server "Notification unimplemented: %s" method))))
(continuations
(cancel-timer (cl-third continuations))
(remhash id (eglot--pending-continuations server))
Expand Down Expand Up @@ -636,7 +637,7 @@ originated."
(defun eglot--call-deferred (server)
"Call SERVER's deferred actions, who may again defer themselves."
(when-let ((actions (hash-table-values (eglot--deferred-actions server))))
(eglot--log-event server `(:running-deferred ,(length actions)))
(eglot--debug server "running %d deferred actions" (length actions))
(mapc #'funcall (mapcar #'car actions))))

(cl-defmacro eglot--lambda (cl-lambda-list &body body)
Expand Down Expand Up @@ -680,7 +681,7 @@ TIMER)."
(when existing (setq existing (cadr existing)))
(if (eglot-server-ready-p server deferred)
(remhash (list deferred buf) (eglot--deferred-actions server))
(eglot--log-event server `(:deferring ,method :id ,id :params ,params))
(eglot--debug server "deferring %s (id %s)" method id)
(let* ((buf (current-buffer)) (point (point))
(later (lambda ()
(when (buffer-live-p buf)
Expand All @@ -702,8 +703,7 @@ TIMER)."
(puthash id
(list (or success-fn
(eglot--lambda (&rest _ignored)
(eglot--log-event
server (eglot--obj :message "success ignored" :id id))))
(eglot--debug server "%s success ignored (id %s)" method id)))
(or error-fn
(eglot--lambda (&key code message &allow-other-keys)
(setf (eglot--status server) `(,message t))
Expand Down Expand Up @@ -772,6 +772,10 @@ DEFERRED is passed to `eglot--async-request', which see."
(let ((warning-minimum-level :error))
(display-warning 'eglot (apply #'format format args) :warning)))

(defun eglot--debug (server format &rest args)
"Warning message with FORMAT and ARGS."
(eglot--log-event server `(:message ,(format format args))))

(defun eglot--pos-to-lsp-position (&optional pos)
"Convert point POS to LSP position."
(save-excursion
Expand Down Expand Up @@ -1032,7 +1036,7 @@ function with the server still running."
"Unreported diagnostics for this buffer.")

(cl-defmethod eglot-handle-notification
(_server (_method (eql :textDocument/publishDiagnostics)) &key uri diagnostics)
(server (_method (eql :textDocument/publishDiagnostics)) &key uri diagnostics)
"Handle notification publishDiagnostics"
(if-let ((buffer (find-buffer-visiting (eglot--uri-to-path uri))))
(with-current-buffer buffer
Expand All @@ -1054,7 +1058,7 @@ function with the server still running."
(setq eglot--unreported-diagnostics nil))
(t
(setq eglot--unreported-diagnostics diags)))))
(eglot--warn "Diagnostics received for unvisited %s" uri)))
(eglot--debug server "Diagnostics received for unvisited %s" uri)))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my environment, the problem is not so much that cquery sends diagnostics, but more that eglot warns even though the diagnostics message says there is no problem. Example diagnostics message:
{"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///usr/include/setjmp.h","diagnostics":[]}}
Note that the "diagnostics" array is empty.

An alternative fix might be to keep eglot--warn, but only call it if the length of the diagnostics array is greater than zero. Then we'll still see the warnings for the files that actually have a problem, but silence it for the vast majority of files that don't have a problem.


(cl-defun eglot--register-unregister (server jsonrpc-id things how)
"Helper for `registerCapability'.
Expand Down Expand Up @@ -1613,6 +1617,34 @@ Proceed? "
(funcall (or eglot--current-flymake-report-fn #'ignore)
eglot--unreported-diagnostics)))))


;;; cquery-specific
;;;
(defclass eglot-cquery (eglot-lsp-server) ()
:documentation "cquery's C/C++ langserver.")

(cl-defmethod eglot-initialization-options ((server eglot-cquery))
"Passes through required cquery initialization options"
(let* ((root (car (project-roots (eglot--project server))))
(cache (expand-file-name ".cquery_cached_index/" root)))
(vector :cacheDirectory (file-name-as-directory cache)
:progressReportFrequencyMs -1)))

(cl-defmethod eglot-handle-notification
((server eglot-cquery) (_method (eql :$cquery/progress))
&rest counts &key activeThreads &allow-other-keys)
"No-op for noisy $cquery/progress extension")

(cl-defmethod eglot-handle-notification
((server eglot-cquery) (_method (eql :$cquery/setInactiveRegions))
&key uri inactiveRegions &allow-other-keys)
"No-op for unsupported $cquery/setInactiveRegions extension")

(cl-defmethod eglot-handle-notification
((server eglot-cquery) (_method (eql :$cquery/publishSemanticHighlighting))
&key uri symbols &allow-other-keys)
"No-op for unsupported $cquery/publishSemanticHighlighting extension")

(provide 'eglot)
;;; eglot.el ends here

Expand Down