mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-26 09:31:59 +00:00
Created Emacs (markdown)
parent
75b3eff6dc
commit
cd6e534ac6
223
Emacs.md
Normal file
223
Emacs.md
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
1. See [[Getting started]] to build the `bin/ccls` executable
|
||||||
|
1. Install [lsp-mode](https://github.com/emacs-lsp/lsp-mode)
|
||||||
|
2. Install [emacs-ccls](https://github.com/ccls-project/emacs-ccls) and [configure](#configure) it
|
||||||
|
3. Open a source file where either [[.ccls|Getting-started#ccls]] or [[compile_commands.json]] is in the project root (it may work without them, though not recommended)
|
||||||
|
4. `M-x lsp-ccls-enable`. Don't invoke `M-x lsp-mode`. `lsp-ccls-enable` will turn on `lsp-mode` for you
|
||||||
|
|
||||||
|
### Install [emacs-ccls](https://github.com/ccls-project/emacs-ccls)
|
||||||
|
|
||||||
|
https://melpa.org/#/ccls
|
||||||
|
|
||||||
|
### Configure
|
||||||
|
|
||||||
|
The only required configuration is `ccls-executable`. Others have good defaults.
|
||||||
|
|
||||||
|
`xref-find-definitions` (default: `M-.`) / highlighting of the symbol at point / type signature in echo area should work out-of-box. Read on for customization and more features.
|
||||||
|
|
||||||
|
```elisp
|
||||||
|
(setq ccls-executable "/path/to/ccls/build/release/bin/ccls")
|
||||||
|
;; ;; Arch Linux aur/ccls-git aur/ccls
|
||||||
|
;; (setq ccls-executable "/usr/bin/ccls")
|
||||||
|
|
||||||
|
;; ;; Log file
|
||||||
|
;; (setq ccls-extra-args '("--log-file=/tmp/cq.log"))
|
||||||
|
;; ;; Cache directory, both relative and absolute paths are supported
|
||||||
|
;; (setq ccls-cache-dir ".ccls_cached_index")
|
||||||
|
;; ;; Initialization options
|
||||||
|
;; (setq ccls-extra-init-params '(:cacheFormat "msgpack"))
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Projects with subprojects
|
||||||
|
|
||||||
|
For each source file that has turned on `lsp-ccls-enable`, variable `ccls-project-roots`, projectile, `compile_commands.json` are consulted to locate the project root and 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. `(setq ccls-project-roots '("~/my-root-project" ))` to override projectile roots.
|
||||||
|
|
||||||
|
If you do not mind files in subprojects are treated as part of the whole project in projectile:
|
||||||
|
|
||||||
|
```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-common-hook #'ccls//enable))
|
||||||
|
;; Also see lsp-project-whitelist lsp-project-blacklist ccls-root-matchers
|
||||||
|
```
|
||||||
|
|
||||||
|
### Diagnostics
|
||||||
|
|
||||||
|
* `M-x lsp-capabilities` LSP workspace is initialized correctly
|
||||||
|
* `M-: xref-backend-functions` is `(lsp--xref-backend)` for cross references
|
||||||
|
* `M-: completion-at-point-functions` is `(lsp-completion-at-point)` for completion
|
||||||
|
|
||||||
|
The buffer `*lsp-ccls stderr*` and `--log-file=/tmp/cq.log` contain logs.
|
||||||
|
|
||||||
|
## [[Initialization options]]
|
||||||
|
|
||||||
|
Initialization options are defined in [config.h](https://github.com/ccls-project/ccls/blob/master/src/config.h), but you need to customize them in S-exp.
|
||||||
|
Use `t` for true, `:json-false` for false, `:json-null` for null.
|
||||||
|
|
||||||
|
```elisp
|
||||||
|
(setq ccls-extra-init-params '(:index (:comments 2) :cacheFormat "msgpack" :completion (:detailedLabel t)))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Find definitions/references
|
||||||
|
|
||||||
|
`xref-find-definitions` (default: `M-.`) should work out-of-box. If not, check if `M-: xref-backend-functions` is `(lsp--xref-backend)`, which should be set by lsp-mode when you execute `(lsp-ccls-enable)`.
|
||||||
|
|
||||||
|
There is heuristic to make `textDocument/definition` work in comments and macro replacement-list, which does something similar to `rtags-find-symbol-at-point`
|
||||||
|
![](https://camo.githubusercontent.com/314cc7c618184b53fff990daf4f334993ceb42b5/68747470733a2f2f707470622e70772f333479352e676966)
|
||||||
|
|
||||||
|
`xref-find-references` (default: `M-?`) will give a prompt. To inhibit the prompt, add `xref-find-references` to `xref-prompt-for-identifier`. (See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=29619 for changing the default behavior.)
|
||||||
|
|
||||||
|
There are Helm/Ivy alternatives for `xref-find-{definitions,references,apropos}`
|
||||||
|
|
||||||
|
* [helm-xref](https://github.com/brotzeit/helm-xref)
|
||||||
|
* [ivy-xref](https://github.com/alexmurray/ivy-xref)
|
||||||
|
|
||||||
|
Check https://github.com/emacs-lsp/lsp-ui for a supplement of lsp-mode. It provides some higher level UI features.
|
||||||
|
|
||||||
|
`lsp-ui-peek-find-{definitions,references}` from [lsp-ui-peek.el](https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-peek.el) provide peek views. An additional benefit is you get a window local jump list dedicated to cross references which I bind to <kbd>C-p</kbd> and <kbd>C-t</kbd>
|
||||||
|
|
||||||
|
```elisp
|
||||||
|
(define-key evil-normal-state-map (kbd "C-p") 'lsp-ui-peek-jump-forward)
|
||||||
|
(define-key evil-normal-state-map (kbd "C-t") 'lsp-ui-peek-jump-backward)
|
||||||
|
```
|
||||||
|
|
||||||
|
![lsp-ui-peek-find-references](https://ptpb.pw/KUYz.jpg)
|
||||||
|
|
||||||
|
![references + hydra](https://ptpb.pw/fhWh.jpg)
|
||||||
|
|
||||||
|
### Symbol highlight
|
||||||
|
|
||||||
|
The identifier (or user-defined operator) at point is highlighted with its other references. If you build trunk libclang, the references will be differentiated for different usage: read/write.
|
||||||
|
|
||||||
|
![textDocument/documentHighlight](https://ptpb.pw/lQ3K.jpg)
|
||||||
|
|
||||||
|
### imenu/workspace symbol search
|
||||||
|
|
||||||
|
Use [lsp-imenu.el](https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-imenu.el) for `textDocument/documentSymbol` (outline). [lsp-ui-imenu.el](https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-imenu.el) provides a sidebar.
|
||||||
|
|
||||||
|
![lsp-imenu + hydra](https://ptpb.pw/XWw7.jpg)
|
||||||
|
|
||||||
|
`xref-find-apropos` (default: `C-M-.`) invokes `workspace/symbol` to fuzzy-find symbols in the project. However, the function tries to be smart and splits the pattern and `regexp-quote` them for you, which actually gets in the way. Consider using `lsp-ui{,-peek}-workspace-symbol` in the lsp-ui package.
|
||||||
|
|
||||||
|
For a symbol named `Name::FooBar`, all of `FooBar`, `foo bar`, `nafoba` find them, but with different priorities.
|
||||||
|
|
||||||
|
### ccls cross-reference extension
|
||||||
|
|
||||||
|
Aside from definitions/references/workspace symbol, ccls provides some LSP extensions that find base/derived classes/methods, vars of a type, callers of a function. You may call:
|
||||||
|
```elisp
|
||||||
|
(ccls-xref-find-custom "$ccls/base")
|
||||||
|
(ccls-xref-find-custom "$ccls/callers")
|
||||||
|
(ccls-xref-find-custom "$ccls/derived")
|
||||||
|
(ccls-xref-find-custom "$ccls/vars")
|
||||||
|
|
||||||
|
;; Alternatively, use lsp-ui-peek interface
|
||||||
|
(lsp-ui-peek-find-custom 'base "$ccls/base")
|
||||||
|
(lsp-ui-peek-find-custom 'callers "$ccls/callers")
|
||||||
|
(lsp-ui-peek-find-custom 'random "$ccls/random") ;; jump to a random declaration
|
||||||
|
```
|
||||||
|
|
||||||
|
### Documentation (comments)
|
||||||
|
|
||||||
|
lsp-ui-doc.el renders comments in a child frame (Emacs >= 26) or inline (< 26).
|
||||||
|
![](https://camo.githubusercontent.com/fe1e12f9be72c2295d732d6265b42bde0d121ee8/68747470733a2f2f707470622e70772f5a6275462e6a7067)
|
||||||
|
|
||||||
|
```elisp
|
||||||
|
(setq lsp-ui-doc-include-signature nil) ; don't include type signature in the child frame
|
||||||
|
(setq lsp-ui-sideline-show-symbol nil) ; don't show symbol on the right of info
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out [MaskRay's config](https://github.com/MaskRay/Config/blob/master/home/.emacs.d/private/%2Bmy/my-code/packages.el) for some (ab)use, e.g. a hydra for next/prev arbitrary/read/write reference. The `"role"` is highly experimental, and you need a trunk libclang (>= 7.0.0) for the role feature.
|
||||||
|
|
||||||
|
### Completion
|
||||||
|
|
||||||
|
Install [company-lsp](https://github.com/tigersoldier/company-lsp) and add `company-lsp` to `company-backends`. Consider disabling client-side cache and sorting because the server does a better job.
|
||||||
|
|
||||||
|
```elisp
|
||||||
|
(setq company-transformers nil company-lsp-async t company-lsp-cache-candidates nil)
|
||||||
|
```
|
||||||
|
|
||||||
|
Type `#i"` (or `#include "`) for quote-style includes and `#i<` (or `#include <`) for system headers.
|
||||||
|
|
||||||
|
See https://github.com/ccls-project/ccls/pull/391#issuecomment-362872732 for an alternative view (contextual parent as detail, signature as label)
|
||||||
|
```elisp
|
||||||
|
(setq ccls-extra-init-params '(:completion (:detailedLabel t)))
|
||||||
|
```
|
||||||
|
|
||||||
|
![company-lsp + company-quickhelp](https://ptpb.pw/AC6J.jpg)
|
||||||
|
|
||||||
|
### lsp-ui-flycheck
|
||||||
|
|
||||||
|
![](https://ptpb.pw/5KIc.jpg)
|
||||||
|
|
||||||
|
### Semantic highlighting
|
||||||
|
|
||||||
|
To enable semantic highlighting:
|
||||||
|
|
||||||
|
```elisp
|
||||||
|
(setq ccls-sem-highlight-method 'font-lock)
|
||||||
|
;; alternatively, (setq ccls-sem-highlight-method 'overlay)
|
||||||
|
|
||||||
|
;; For rainbow semantic highlighting
|
||||||
|
(ccls-use-default-rainbow-sem-highlight)
|
||||||
|
```
|
||||||
|
|
||||||
|
Different variables/functions/types will be assigned different faces, while uses of the same variable/function/type share the same face. The colors can be customized:
|
||||||
|
```elisp
|
||||||
|
ccls-sem-function-colors
|
||||||
|
ccls-sem-macro-colors
|
||||||
|
;; ...
|
||||||
|
ccls-sem-member-face ;; defaults to t :slant italic
|
||||||
|
```
|
||||||
|
|
||||||
|
by default only one face is used for each symbol kind (type/function/variable/member function)
|
||||||
|
|
||||||
|
While `(setq ccls-sem-highlight-method 'overlay)` is more accurate than `'font-lock`, it may cause severe performance issues. The short story is that the large number of overlays generated by ccls creates a similarly large number of markers. If the buffer currently edited is a multibyte buffer and contains at least one non-ASCII character, these markers may slow down `line-number-at-pos` (a function heavily relied upon by `lsp-mode`) by orders of magnitude; the effect gets worse with increasing distance from `(point-min)`.
|
||||||
|
For the long story, refer to the corresponding [emacs-devel thread](https://lists.gnu.org/archive/html/emacs-devel/2018-03/msg00565.html); if you wish to use `ccls-sem-highlight` without the associated slowdown, the following options exist (should you find more, please add them to this wiki page):
|
||||||
|
|
||||||
|
1. while [this patch](https://lists.gnu.org/archive/html/emacs-devel/2018-03/msg00708.html) by Stefan Monnier does not completely solve the underlying performance issue, it significantly alleviates it for usual buffer sizes
|
||||||
|
|
||||||
|
2. [the noverlay branch of Emacs](https://github.com/emacs-mirror/emacs/commits/feature/noverlay) reimplements overlays in a way that avoids markers. Although large numbers of markers would still lead to performance issues with the noverlay branch, ccls performance should be excellent
|
||||||
|
|
||||||
|
3. both 1. and 2. require recompiling Emacs from sources; if that is unacceptable, performance can be restored using `(set-buffer-multibyte nil)`. Note, however, that this will lead to non-ASCII characters being displayed as escape sequences. Also, this workaround has been verified to remove the performance penalty affecting `line-number-at-pos`, but it has not been tested whether disabling multibyte handling causes other issues with `lsp-mode` or ccls.
|
||||||
|
|
||||||
|
![](https://ptpb.pw/qAWN.jpg)
|
||||||
|
|
||||||
|
### Call/member/inheritance Hierarchies
|
||||||
|
|
||||||
|
`M-x ccls-member-hierarchy`
|
||||||
|
![$ccls/memberHierarchy](https://ptpb.pw/iOSt.gif)
|
||||||
|
|
||||||
|
```elisp
|
||||||
|
(ccls-call-hierarchy nil) ; caller hierarchy
|
||||||
|
(ccls-call-hierarchy t) ; callee hierarchy
|
||||||
|
```
|
||||||
|
![$ccls/callHierarchy](https://ptpb.pw/Dv8K.gif)
|
||||||
|
|
||||||
|
```elisp
|
||||||
|
(ccls-inheritance-hierarchy nil) ; base hierarchy
|
||||||
|
(ccls-inheritance-hierarchy t) ; derived hierarchy
|
||||||
|
```
|
||||||
|
|
||||||
|
![$ccls/inheritanceHierarchy](https://ptpb.pw/JkyT.gif)
|
||||||
|
|
||||||
|
### Misc
|
||||||
|
|
||||||
|
For out-of-band changes to the files in the workspace that are not made in the LSP client (e.g. git pull), call
|
||||||
|
`(ccls-freshen-index)` to rebuild indexes for every file or `(ccls-freshen-index (list "^/tmp/c/"))` to rebuild indexes for files matched by a regex whitelist.
|
||||||
|
|
||||||
|
* A proposal to integrate ccls and lsp-mode into spacemacs: https://github.com/syl20bnr/spacemacs/issues/10134
|
||||||
|
* Discussion of symbol hierarchies (member hierarchy, inheritance hierarchy, call hierarchy) https://github.com/emacs-lsp/lsp-ui/issues/73
|
||||||
|
* Performance of lsp-ui-flycheck https://github.com/emacs-lsp/lsp-ui/issues/45
|
Loading…
Reference in New Issue
Block a user