Add eglot.md; mv Emacs.md lsp-mode.md

Fangrui Song 2018-12-08 09:44:22 -08:00
parent 4f08ab476f
commit 41c4d67491
3 changed files with 72 additions and 70 deletions

@ -6,7 +6,9 @@
- [[FAQ]] - [[FAQ]]
* Editor configuration * Editor configuration
- [[Atom]] - [[Atom]]
- [[Emacs]] - Emacs
+ [[lsp-mode]] (+ emacs-ccls)
+ [[eglot]]
- Vim/Neovim - Vim/Neovim
+ [[coc.nvim]] + [[coc.nvim]]
+ [[LanguageClient-neovim]] + [[LanguageClient-neovim]]

59
eglot.md Normal file

@ -0,0 +1,59 @@
1. See [[Getting started]] to build the `ccls` executable
2. Install [eglot](https://github.com/joaotavora/eglot)
3. Open a C/C++/ObjC source file.
4. `M-x eglot-ensure`
eglot uses builtin `project.el` to detect the project root. If you want to use projectile:
```elisp
(defun projectile-project-find-function (dir)
(let* ((root (projectile-project-root dir)))
(and root (cons 'transient root))))
(with-eval-after-load 'project
(add-to-list 'project-find-functions 'projectile-project-find-function))
```
### Completion
eglot defines `completion-at-point-functions`, set `company-capf` to the only or the first item of `company-backends`.
ccls has a fuzzy matching algorithm to order candidates according to your query. You may want to disable client-side sorting:
```elisp
(setq company-transformers nil)
```
### Misc
Use help window to display hierarchies:
```elisp
(defun eglot-ccls-inheritance-hierarchy (&optional derived)
"Show inheritance hierarchy for the thing at point.
If DERIVED is non-nil (interactively, with prefix argument), show
the children of class at point."
(interactive "P")
(if-let* ((res (jsonrpc-request
(eglot--current-server-or-lose)
:$ccls/inheritance
(append (eglot--TextDocumentPositionParams)
`(:derived ,(if derived t :json-false))
'(:levels 100) '(:hierarchy t))))
(tree (list (cons 0 res))))
(with-help-window "*ccls inheritance*"
(with-current-buffer standard-output
(while tree
(pcase-let ((`(,depth . ,node) (pop tree)))
(cl-destructuring-bind (&key uri range) (plist-get node :location)
(insert (make-string depth ?\ ) (plist-get node :name) "\n")
(make-text-button (+ (point-at-bol 0) depth) (point-at-eol 0)
'action (lambda (_arg)
(interactive)
(find-file (eglot--uri-to-path uri))
(goto-char (car (eglot--range-region range)))))
(cl-loop for child across (plist-get node :children)
do (push (cons (1+ depth) child) tree)))))))
(eglot--error "Hierarchy unavailable")))
```

@ -1,6 +1,6 @@
1. See [[Getting started]] to build the `ccls` executable 1. See [[Getting started]] to build the `ccls` executable
2. Install [lsp-mode](https://github.com/emacs-lsp/lsp-mode) and optionally, [lsp-ui](https://github.com/emacs-lsp/lsp-ui) + [company-lsp](https://github.com/tigersoldier/company-lsp) 2. Install [lsp-mode](https://github.com/emacs-lsp/lsp-mode) and optionally, [lsp-ui](https://github.com/emacs-lsp/lsp-ui) + [company-lsp](https://github.com/tigersoldier/company-lsp)
3. Install [emacs-ccls](https://github.com/MaskRay/emacs-ccls) (ccls on Melpa) and [configure](#configure) it 3. Install [emacs-ccls](https://github.com/MaskRay/emacs-ccls) (Melpa: https://melpa.org/#/ccls) and [configure](#configure) it
4. Open a source file where either [[.ccls|Getting-started#ccls]] or [[compile_commands.json]] is in the project root (it works without them, if you don't need extra compiler command line options like `-I`) 4. Open a source file where either [[.ccls|Getting-started#ccls]] or [[compile_commands.json]] is in the project root (it works without them, if you don't need extra compiler command line options like `-I`)
5. `(require 'ccls)`, `M-x lsp` 5. `(require 'ccls)`, `M-x lsp`
@ -10,10 +10,6 @@
Alternatively, you may install https://github.com/joaotavora/eglot Alternatively, you may install https://github.com/joaotavora/eglot
### Install [emacs-ccls](https://github.com/MaskRay/emacs-ccls)
https://melpa.org/#/ccls
### Configure ### Configure
#### spacemacs #### spacemacs
@ -27,8 +23,12 @@ set `c-c++-backend` to `lsp-ccls` in the `+lang/c-c++` layer
:commands lsp :commands lsp
:config (require 'lsp-clients)) :config (require 'lsp-clients))
(use-package ccls :defer t) (use-package company-lsp
(add-hook 'c++-mode-hook (lambda () (require 'ccls) (lsp))) :commands company-lsp)
(use-package ccls
:hook ((c-mode c++-mode objc-mode) .
(lambda () (cl-pushnew #'company-lsp company-backends) (require 'ccls) (lsp))))
``` ```
The only required configuration is `ccls-executable`. Others have good defaults. The only required configuration is `ccls-executable`. Others have good defaults.
@ -41,7 +41,7 @@ The only required configuration is `ccls-executable`. Others have good defaults.
;; (setq ccls-executable "/usr/bin/ccls") ;; (setq ccls-executable "/usr/bin/ccls")
;; ;; Log file ;; ;; Log file
;; (setq ccls-extra-args '("--log-file=/tmp/cq.log")) ;; (setq ccls-extra-args '("--log-file=/tmp/ccls.log"))
``` ```
A more flexible way is to leave `ccls-executable` unchanged (default: `ccls`) and create a shell wrapper named `ccls` that is in your `PATH`: A more flexible way is to leave `ccls-executable` unchanged (default: `ccls`) and create a shell wrapper named `ccls` that is in your `PATH`:
@ -59,36 +59,10 @@ Some common settings to lsp-mode lsp-ui and emacs-ccls:
#### Projects with subprojects #### Projects with subprojects
When `M-x lsp-ccls-enable` is invoked, projectile is consulted to locate the project root which determines the associated lsp-mode workspace. When `M-x lsp` is invoked, projectile is consulted to locate the project root which determines the associated lsp-mode workspace.
If your project has subprojects, `(projectile-project-root)` may think files in the subproject belong to the child workspace, which is not desired. `touch .ccls-root` in the root directory to override projectile roots. If your project has subprojects, `(projectile-project-root)` may think files in the subproject belong to the child workspace, which is not desired. `touch .ccls-root` in the root directory to override projectile roots.
If you do not mind files in subprojects are treated as part of the whole project in projectile: Read `lsp-project-whitelist lsp-project-blacklist` if you don't want to start ccls for some paths.
```elisp
(with-eval-after-load 'projectile
(setq projectile-project-root-files-top-down-recurring
(append '("compile_commands.json"
".ccls")
projectile-project-root-files-top-down-recurring)))
```
To turn on ccls for all C/C++ modes:
```elisp
(defun +ccls/enable ()
(condition-case nil
(lsp-ccls-enable)
(user-error nil)))
(use-package ccls
:commands lsp-ccls-enable
:init
(add-hook 'c-mode-hook #'+ccls/enable)
(add-hook 'c++-mode-hook #'+ccls/enable)
(add-hook 'objc-mode-hook #'+ccls/enable)
(add-hook 'cuda-mode-hook #'+ccls/enable)
)
;; Also see lsp-project-whitelist lsp-project-blacklist
```
### Diagnostics ### Diagnostics
@ -322,36 +296,3 @@ For out-of-band changes to the files in the workspace that are not made in the L
`(ccls-reload)` to reload/rebuild indexes for every file. `(ccls-reload)` to reload/rebuild indexes for every file.
* Performance of lsp-ui-flycheck https://github.com/emacs-lsp/lsp-ui/issues/45 * Performance of lsp-ui-flycheck https://github.com/emacs-lsp/lsp-ui/issues/45
### eglot
Use help window to display hierarchies:
```elisp
(defun eglot-ccls-inheritance-hierarchy (&optional derived)
"Show inheritance hierarchy for the thing at point.
If DERIVED is non-nil (interactively, with prefix argument), show
the children of class at point."
(interactive "P")
(if-let* ((res (jsonrpc-request
(eglot--current-server-or-lose)
:$ccls/inheritance
(append (eglot--TextDocumentPositionParams)
`(:derived ,(if derived t :json-false))
'(:levels 100) '(:hierarchy t))))
(tree (list (cons 0 res))))
(with-help-window "*ccls inheritance*"
(with-current-buffer standard-output
(while tree
(pcase-let ((`(,depth . ,node) (pop tree)))
(cl-destructuring-bind (&key uri range) (plist-get node :location)
(insert (make-string depth ?\ ) (plist-get node :name) "\n")
(make-text-button (+ (point-at-bol 0) depth) (point-at-eol 0)
'action (lambda (_arg)
(interactive)
(find-file (eglot--uri-to-path uri))
(goto-char (car (eglot--range-region range)))))
(cl-loop for child across (plist-get node :children)
do (push (cons (1+ depth) child) tree)))))))
(eglot--error "Hierarchy unavailable")))
```