Created Emacs (markdown)

Fangrui Song 2018-03-30 23:51:22 -07:00
parent 75b3eff6dc
commit cd6e534ac6

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