diff --git a/README.md b/README.md index b87666c2..3b954383 100644 --- a/README.md +++ b/README.md @@ -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`: @@ -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 + diff --git a/eglot.el b/eglot.el index 3d363444..55fa4064 100644 --- a/eglot.el +++ b/eglot.el @@ -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. @@ -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)) @@ -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)) @@ -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) @@ -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) @@ -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)) @@ -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 @@ -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 @@ -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))) (cl-defun eglot--register-unregister (server jsonrpc-id things how) "Helper for `registerCapability'. @@ -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