Added cquery and ccls backend support to c-c++ layer

<<Amendment 1 01/09/2018>>
Incorporated initial feedback from multiple sources (PR discussion)

<<Amendment 2 04/09/2018>>
Incorporated feedback from MaskRay.
Fixed projectile post-config hooks.
Added `c-c++-adopt-subprojects' layer option.

<<Amendment 3 07/09/18>>
Corrected cache section in README to describe new cache defaults introduced by
Amendment 2.

<<Amendment 4 13/09/18>>
Corrected config var names in readme.
Rebased on current develop branch tip.

<<Amendment 5 14/09/18>>
Minor adaptations for compatibility with upstream ccls changes.

<<Amendment 6 21/09/18>>
Bindings updated for consistency with lsp layer lsp-navigation config variable.

<<Amendment 7 1/11/18>>
Rebased

<<Amendment 8 06/11/18>>
Incorporated readme correction from svenihoney.

<<Amendment 9 06/11/18>>
Updated c-c++/refresh-index wrapper for ccls function renamed upstream.
Moved 2 bindings from 'l' to 'b' to reflect updated lsp-layer mnemonic
This commit is contained in:
cormacc 2018-08-30 21:03:11 +01:00 committed by Codruț Constantin Gușoi
parent 141b6328e3
commit 445f6af93f
5 changed files with 495 additions and 70 deletions

View file

@ -8,15 +8,28 @@
- [[#install][Install]] - [[#install][Install]]
- [[#layer][Layer]] - [[#layer][Layer]]
- [[#default-mode-for-header-files][Default mode for header files]] - [[#default-mode-for-header-files][Default mode for header files]]
- [[#backends][Backends]]
- [[#rtags][RTags]]
- [[#external-dependencies][External dependencies]]
- [[#configuration][Configuration]]
- [[#cquery--ccls-lsp-backends][cquery / ccls (lsp backends)]]
- [[#features-1][Features:]]
- [[#external-dependencies-1][External dependencies]]
- [[#configuration-1][Configuration]]
- [[#completion][Completion]]
- [[#clang-configuration][Clang Configuration]] - [[#clang-configuration][Clang Configuration]]
- [[#clang-format][clang-format]] - [[#clang-format][clang-format]]
- [[#company-clang-and-flycheck][Company-clang and flycheck]] - [[#company-clang-and-flycheck][Company-clang and flycheck]]
- [[#rtags-configuration][RTags configuration]]
- [[#enable-google-set-c-style][Enable google-set-c-style]] - [[#enable-google-set-c-style][Enable google-set-c-style]]
- [[#newlines][Newlines]] - [[#newlines][Newlines]]
- [[#projectile-sub-project-adoption][Projectile sub-project adoption]]
- [[#key-bindings][Key Bindings]] - [[#key-bindings][Key Bindings]]
- [[#formatting-clang-format][Formatting (clang-format)]] - [[#formatting-clang-format][Formatting (clang-format)]]
- [[#rtags][RTags]] - [[#rtags-1][RTags]]
- [[#cquery--ccls][cquery / ccls]]
- [[#goto][goto]]
- [[#helphierarchy][help/hierarchy]]
- [[#backend-language-server][backend (language server)]]
* Description * Description
This layer adds configuration for C/C++ language. This layer adds configuration for C/C++ language.
@ -37,6 +50,7 @@ This layer adds configuration for C/C++ language.
company-ycmd (when =ycmd= layer is included). company-ycmd (when =ycmd= layer is included).
- Support for [[https://github.com/realgud/realgud][realgud]] debugger. - Support for [[https://github.com/realgud/realgud][realgud]] debugger.
- Support for [[https://github.com/Andersbakken/rtags][rtags]]. - Support for [[https://github.com/Andersbakken/rtags][rtags]].
- Support for [[https://github.com/cquery-project/cquery][cquery]] or [[https://github.com/MaskRay/ccls][ccls]] as an lsp backend.
* Install * Install
** Layer ** Layer
@ -59,6 +73,116 @@ by setting the variable =c-c++-default-mode-for-headers= to =c++-mode=.
variable at the root of your project. More info on directory local variables variable at the root of your project. More info on directory local variables
can be found in the [[http://www.gnu.org/software/emacs/manual/html_node/elisp/Directory-Local-Variables.html][dir-locals]]. can be found in the [[http://www.gnu.org/software/emacs/manual/html_node/elisp/Directory-Local-Variables.html][dir-locals]].
** Backends
This layer supports the selection of one of 3 available backends for code navigation etc via the =c-c++-backend= configuration variable.
*** RTags
RTags is a well established clang-based source code indexing tool.
**** External dependencies
Install the RTags server via [[https://formulae.brew.sh/formula/rtags][homebrew]], the [[https://aur.archlinux.org/packages/rtags/][aur]] or from source according to the instructions [[https://github.com/Andersbakken/rtags][here]].
N.B. RTags is not supported on Windows at the time of writing, although there is an [[https://github.com/Andersbakken/rtags/issues/770][open issue with some recent activity]] on github.
**** Configuration
To enable support for =rtags=, set the layer variable
=c-c++-enable-rtags-support= to =t= in your dotfile.
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables c-c++-backend 'rtags)))
#+END_SRC
This will also enable =company-rtags= to be used as a backend for
auto-completion (when =auto-completion= layer is included).
To prevent this, while retaining the rest of Rtags functionality,
set the variable =c-c++-rtags-completion= to =nil=:
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables
c-c++-backend 'rtags
c-c++-enable-rtags-completion nil)))
#+END_SRC
*** cquery / ccls (lsp backends)
[[https://github.com/cquery-project/cquery][cquery]] and [[https://github.com/MaskRay/ccls][ccls]] are alternative implementations of the language server protocol based on libclang. They claim to be more efficient
than existing tools at indexing large code bases.
**** Features:
- Cross references (definitions, references, base/derived classes/methods, type instances, ...)
- Diagnostics
- Completion with =company-lsp=
- Semantic highlighting
- See more on [[https://github.com/cquery-project/cquery/wiki/Emacs]]
- Cross-platform - functional on Windows, Linux and OSX.
**** External dependencies
Install one (or both) of the following:
***** cquery server
Install the =cquery= server. [[https://github.com/cquery-project/cquery/wiki/Getting-started][Instructions]].
***** ccls server
Install the =ccls= server. [[https://github.com/MaskRay/ccls/wiki/Getting-started][Instructions]].
**** Configuration
***** Basic
Select either =cquery= or =ccls= as the =c-c++= layer backend by adding the following to your dotfile:
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables c-c++-backend 'lsp-cquery))) ;or 'lsp-ccls
#+END_SRC
N.B. The [[../../+tools/lsp/README.org][LSP layer]] will be loaded automatically if either backend is selected.
***** Setting path to backend executable
The basic configuration above should work if the cquery/ccls executable folder is present in your path. If not, you can set the path explicitly.
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables
c-c++-backend 'lsp-cquery
c-c++-lsp-executable "/path/to/bin/cquery/or/ccls")))
#+END_SRC
If you need to expand =~= in the path, you can use =file-truename= like
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables
c-c++-backend 'lsp-cquery
c-c++-lsp-executable (file-truename "~/bin/cquery/or/ccls"))))
#+END_SRC
***** Semantic highlighting
Semantic highlighting is disabled by default. To enable, set the =c-c++-lsp-sem-highlight-method= variable to either ='font-lock= or ='overlay=.
To enable the rainbow semantic highlighting colour theme, set =c-c++-lsp-sem-highlight-rainbow= to =t=.
***** Additional configuration options
Both lsp backends are configured to store their index cache in a subdirectory of =.emacs.d/cache=. This can be overridden by
specifying an explicit =c-c++-lsp-cache-dir=. Setting this value to a relative path will cause the index cache to be placed in a
subdirectory of your project root.
There are other initialization options such as the number of indexer threads, cache serialization format.
They have good default values. See [[file:./config.el][config.el]] and the backends' respective homepages for more info.
- [[https://github.com/cquery-project/cquery/wiki/Emacs][Emacs section of =cquery= wiki]]
- [[https://github.com/MaskRay/ccls/wiki/Emacs][Emacs section of =ccls= wiki]]
***** Example dotspacemacs-configuration-layers entry
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables
c-c++-adopt-subprojects t
c-c++-backend 'lsp-ccls
c-c++-lsp-executable (file-truename "~/dev/cpp/ccls/Release/ccls")
c-c++-lsp-sem-highlight-rainbow t)))
#+END_SRC
**** Completion
=company-lsp= provides completion functionality. Client-side cache and sorting have been disabled in favour of server,
as recommended by =cquery=/=ccls= wikis.
** Clang Configuration ** Clang Configuration
To enable Clang support, set the layer variable =c-c++-enable-clang-support= To enable Clang support, set the layer variable =c-c++-enable-clang-support=
to =t= in the dotfile: to =t= in the dotfile:
@ -68,6 +192,8 @@ to =t= in the dotfile:
'((c-c++ :variables c-c++-enable-clang-support t))) '((c-c++ :variables c-c++-enable-clang-support t)))
#+END_SRC #+END_SRC
N.B. do not set this option if either the =cquery= or =ccls= backend
*** clang-format *** clang-format
[[http://clang.llvm.org/docs/ClangFormat.html][clang-format]] allows reformatting either a selected region of code [[http://clang.llvm.org/docs/ClangFormat.html][clang-format]] allows reformatting either a selected region of code
(=clang-format-region=) or a whole buffer (=clang-format-buffer=) (=clang-format-region=) or a whole buffer (=clang-format-buffer=)
@ -80,8 +206,8 @@ To enable automatic buffer formatting on save, set the variable
=c-c++-enable-clang-format-on-save= to =t=: =c-c++-enable-clang-format-on-save= to =t=:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers '( (setq-default dotspacemacs-configuration-layers
(c-c++ :variables c-c++-enable-clang-format-on-save t))) '((c-c++ :variables c-c++-enable-clang-format-on-save t)))
#+END_SRC #+END_SRC
*** Company-clang and flycheck *** Company-clang and flycheck
@ -93,25 +219,6 @@ Not only does this allow proper autocomplete on projects with extra includes and
flags, but there is also support for flycheck so that it doesnt complain about flags, but there is also support for flycheck so that it doesnt complain about
missing header files. missing header files.
** RTags configuration
To enable support for =rtags=, set the layer variable
=c-c++-enable-rtags-support= to =t= in your dotfile.
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables c-c++-enable-rtags-support t)))
#+END_SRC
This will also enable =company-rtags= to be used as a backend for
auto-completion (when =auto-completion= layer is included).
To prevent this, while retaining the rest of Rtags functionality,
set the variable =c-c++-enable-rtags-support= to ='no-completion=:
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables c-c++-enable-rtags-support 'no-completion)))
#+END_SRC
** Enable google-set-c-style ** Enable google-set-c-style
If you have clang enabled with =clang-format= as described earlier in this page If you have clang enabled with =clang-format= as described earlier in this page
you may not have a lot of neeed for =google-set-c-style= if you are already you may not have a lot of neeed for =google-set-c-style= if you are already
@ -140,7 +247,6 @@ set that up like this:
(c-c++ :variables (c-c++ :variables
c-c++-enable-google-style t c-c++-enable-google-style t
c-c++-enable-google-newline t) c-c++-enable-google-newline t)
#+END_SRC
** Newlines ** Newlines
You can enable the =Auto-newline= minor mode that automatically adds newlines You can enable the =Auto-newline= minor mode that automatically adds newlines
@ -151,6 +257,18 @@ after certain characters by setting the =c-c++-enable-auto-newline= variable.
c-c++-enable-auto-newline t) c-c++-enable-auto-newline t)
#+END_SRC #+END_SRC
** Projectile sub-project adoption
To prevent projectile from using subproject root when visiting files in a subproject,
set =c-c++-adopt-subprojects= to =t=.
#+BEGIN_SRC emacs-lisp
(c-c++ :variables
c-c++-adopt-subprojects t)
#+END_SRC emacs-lisp
This is based on a recommendation on the =cquery= and =ccls= wikis, but should be more
generally applicable.
* Key Bindings * Key Bindings
| Key Binding | Description | | Key Binding | Description |
@ -160,7 +278,7 @@ after certain characters by setting the =c-c++-enable-auto-newline= variable.
| ~SPC m g A~ | open matching file in another window | | ~SPC m g A~ | open matching file in another window |
| | (e.g. switch between .cpp and .h, requires a project to work) | | | (e.g. switch between .cpp and .h, requires a project to work) |
| ~SPC m D~ | disaster: disassemble c/c++ code | | ~SPC m D~ | disaster: disassemble c/c++ code |
| ~SPC m r~ | srefactor: refactor thing at point. | | ~SPC m r .~ | srefactor: refactor thing at point. |
*Note:* [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]] is only available for Emacs 24.4+. *Note:* [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]] is only available for Emacs 24.4+.
@ -204,3 +322,37 @@ after certain characters by setting the =c-c++-enable-auto-newline= variable.
| ~SPC m g V~ | print enum value at point | | ~SPC m g V~ | print enum value at point |
| ~SPC m g X~ | fix fixit at point | | ~SPC m g X~ | fix fixit at point |
| ~SPC m g Y~ | cycle overlays on screen | | ~SPC m g Y~ | cycle overlays on screen |
** cquery / ccls
The keybindings listed below are in addition to the default keybindings defined by the [[file:../../+tools/lsp/README.org][LSP layer]].
*** goto
| Key Binding | Description |
|-------------+---------------------------|
| ~SPC m g &~ | find references (address) |
| ~SPC m g R~ | find references (read) |
| ~SPC m g W~ | find references (write) |
| ~SPC m g c~ | find callers |
| ~SPC m g C~ | find callees |
| ~SPC m g v~ | vars |
*** help/hierarchy
| Key Binding | Description |
|-------------+-----------------------------|
| ~SPC m h b~ | base class(es) |
| ~SPC m h d~ | derived class(es) |
| ~SPC m h c~ | call hierarchy |
| ~SPC m h C~ | call hierarchy (inv) |
| ~SPC m h i~ | inheritance hierarchy |
| ~SPC m h I~ | inheritance hierarchy (inv) |
| ~SPC m h m~ | member hierarchy |
| ~SPC m h M~ | member hierarchy (inv) |
*** backend (language server)
| Key Binding | Description |
|-------------+------------------------------------------|
| ~SPC m b f~ | refresh index (e.g. after branch change) |
| ~SPC m b p~ | preprocess file |

View file

@ -17,6 +17,13 @@
(defconst c-c++-mode-hooks '(c-mode-hook c++-mode-hook) (defconst c-c++-mode-hooks '(c-mode-hook c++-mode-hook)
"Primary hooks of the `c-c++' layer.") "Primary hooks of the `c-c++' layer.")
(defconst c-c++-lsp-backends '(lsp-cquery lsp-ccls)
"Language Server Protocol (LSP) backends supported by the `c-c++' layer.")
(defvar c-c++-backend nil
"If `lsp-cquery' or `lsp-ccls' then selects language server protocol backend (cquery or ccls).
If `rtags' then enables rtags support")
(defvar c-c++-enable-auto-newline nil (defvar c-c++-enable-auto-newline nil
"If non nil then enables the `Auto-newline' minor mode.") "If non nil then enables the `Auto-newline' minor mode.")
@ -31,9 +38,8 @@
"If non-nil `google-make-newline-indent' will be added as as "If non-nil `google-make-newline-indent' will be added as as
`c-mode-common-hook'.") `c-mode-common-hook'.")
(defvar c-c++-enable-rtags-support nil (defvar c-c++-enable-rtags-completion t
"If non nil Rtags related packages and configuration are enabled. "If `nil', RTags completion is disabled when the RTags backend is enabled.")
If `no-completion', enable all but completion.")
(defvar c-c++-enable-clang-format-on-save nil (defvar c-c++-enable-clang-format-on-save nil
"If non-nil, automatically format code with ClangFormat on "If non-nil, automatically format code with ClangFormat on
@ -44,3 +50,36 @@
(defvar c-c++-default-mode-for-headers 'c-mode (defvar c-c++-default-mode-for-headers 'c-mode
"Default mode to open header files. Can be `c-mode' or `c++-mode'.") "Default mode to open header files. Can be `c-mode' or `c++-mode'.")
(defvar c-c++-adopt-subprojects nil
"When non-nil, projectile will remember project root when visiting files in subprojects")
;; c-c++-lsp-backend variables
(defvar c-c++-lsp-cache-dir nil
"Cache directory. Absolute and relative paths supported.")
(defvar c-c++-lsp-executable nil
"Path to cquery/ccls executable (default value assumes it's in the path)")
(defvar c-c++-lsp-project-whitelist nil
"A list of project directory patterns for which lsp-c-c++ should be
initialized. This overrides `c-c++-lsp-project-blacklist'.")
(defvar c-c++-lsp-project-blacklist nil
"A list of project root patterns for which lsp-c-c++ shouldn't be
initialized. `c-c++-lsp-project-whitelist' is checked first, then this,
if no pattern matches the project root, lsp-c-c++ will be initialized.")
(defvar c-c++-lsp-sem-highlight-method nil
"Set to 'font-lock or 'overlay to enable semantic highlighting")
(defvar c-c++-lsp-sem-highlight-rainbow nil
"When non-nil, use rainbow semantic highlighting")
;; I've left cquery/ccls -extra-init-params separate for now, as one has defaults while the other doesn't
;; Just to facilitate switching between the two easily
(defvar c-c++-lsp-extra-init-params '(:cacheFormat "msgpack")
"Extra initialisation parameters to pass to the backend. See
https://github.com/cquery-project/cquery/blob/master/src/config.h or
https://github.com/MaskRay/ccls/blob/master/src/config.h
for details.")

View file

@ -9,6 +9,9 @@
;; ;;
;;; License: GPLv3 ;;; License: GPLv3
(require 'cl-lib)
(require 'subr-x)
(defun spacemacs//c-toggle-auto-newline () (defun spacemacs//c-toggle-auto-newline ()
"Toggle auto-newline." "Toggle auto-newline."
(c-toggle-auto-newline 1)) (c-toggle-auto-newline 1))
@ -157,9 +160,9 @@ and the arguments for flyckeck-clang based on a project-specific text file."
rtags-last-request-not-indexed) rtags-last-request-not-indexed)
(gtags-find-tag))) (gtags-find-tag)))
(defun spacemacs/c-c++-tags-find-references-at-point (&optional prefix) (defun spacemacs/c-c++-tags-find-refs-at-point (&optional prefix)
(interactive "P") (interactive "P")
(if (and (not (rtags-find-references-at-point prefix)) (if (and (not (rtags-find-refs-at-point prefix))
rtags-last-request-not-indexed) rtags-last-request-not-indexed)
(gtags-find-rtag))) (gtags-find-rtag)))
@ -182,3 +185,169 @@ and the arguments for flyckeck-clang based on a project-specific text file."
(interactive) (interactive)
(call-interactively (if (spacemacs/c-c++-use-rtags t) (call-interactively (if (spacemacs/c-c++-use-rtags t)
'rtags-imenu 'idomenu))) 'rtags-imenu 'idomenu)))
;; lsp
(defun spacemacs//c-c++-lsp-enabled ()
"Return true if one or other of the lsp backends is enabled"
(member c-c++-backend c-c++-lsp-backends))
;; -- BEGIN helper functions for common configuration of cquery and ccls backends
(defun spacemacs//c-c++-lsp-backend ()
"Return a string representation of the LSP backend specified by the `c-c++-backend' configuration variable, without the `lsp-' prefix."
(ecase c-c++-backend
('lsp-ccls "ccls")
('lsp-cquery "cquery")))
(defun spacemacs//c-c++-lsp-string (prefix suffix)
(concat prefix (spacemacs//c-c++-lsp-backend) suffix))
(defun spacemacs//c-c++-lsp-symbol (prefix suffix)
"Return a symbol for the LSP backend specified by the `c-c++-backend' configuration variable."
(intern (spacemacs//c-c++-lsp-string prefix suffix)))
(defun spacemacs//c-c++-lsp-call-function (prefix suffix &rest args)
(apply (spacemacs//c-c++-lsp-symbol prefix suffix) args))
(defun spacemacs//c-c++-lsp-funcall-interactively (prefix suffix &rest args)
(funcall-interactively (spacemacs//c-c++-lsp-symbol prefix suffix) args))
(defun spacemacs//c-c++-lsp-funcall-interactively-no-args (prefix suffix)
(funcall-interactively (spacemacs//c-c++-lsp-symbol prefix suffix)))
(defun spacemacs//c-c++-lsp-set-symbol (prefix suffix value)
(set (spacemacs//c-c++-lsp-symbol prefix suffix) (symbol-value value)))
(defun spacemacs//c-c++-lsp-set-config (param prefix suffix)
(when (symbol-value param) (spacemacs//c-c++-lsp-set-symbol prefix suffix param)))
(defun spacemacs//c-c++-lsp-apply-config (suffix)
(spacemacs//c-c++-lsp-set-config (intern (concat "c-c++-lsp-" suffix)) nil (concat "-" suffix)))
;; -- END helper functions for common configuration of cquery and ccls backends
(defun spacemacs//c-c++-lsp-enable ()
"Enable the LSP backend specified by the `c-c++-backend' configuration variable."
(progn (condition-case nil
(spacemacs//c-c++-lsp-call-function "lsp-" "-enable")
(user-error nil))))
(defun spacemacs//c-c++-lsp-config ()
"Configure the LSP backend specified by the `c-c++-backend' configuration variable."
(progn
(spacemacs//c-c++-lsp-setup-company)
(spacemacs//c-c++-lsp-define-extensions)
(spacemacs//c-c++-lsp-wrap-functions)
(setq-default flycheck-disabled-checkers '(c/c++-clang c/c++-gcc))
(if (eq c-c++-lsp-cache-dir nil)
(progn
(setq c-c++-lsp-cache-dir (file-truename(concat "~/.emacs.d/.cache/" (symbol-name c-c++-backend))))
(message (concat "c-c++: No c-c++-lsp-cache-dir specified: defaulting to " c-c++-lsp-cache-dir))))
(dolist (param '("executable" "extra-init-params" "cache-dir" "project-whitelist" "project-blacklist" "sem-highlight-method"))
(spacemacs//c-c++-lsp-apply-config param))
(when c-c++-lsp-sem-highlight-rainbow
(unless c-c++-lsp-sem-highlight-method
(progn
(setq c-c++-lsp-sem-highlight-method 'font-lock)
(message "c-c++: No semantic highlight method specified. Defaulting to `font-lock'.")))
(ecase c-c++-backend
('lsp-cquery (cquery-use-default-rainbow-sem-highlight))
('lsp-ccls (ccls-use-default-rainbow-sem-highlight))))
(dolist (mode c-c++-modes)
(spacemacs/lsp-bind-keys-for-mode mode)
(spacemacs//c-c++-lsp-bind-keys-for-mode mode))
(evil-set-initial-state '(spacemacs//c-c++-lsp-symbol nil "-tree-mode") 'emacs)
;;evil-record-macro keybinding clobbers q in cquery-tree-mode-map for some reason?
(evil-make-overriding-map (symbol-value (spacemacs//c-c++-lsp-symbol nil "-tree-mode-map")))))
(defun spacemacs//c-c++-lsp-setup-company ()
"Setup LSP backend auto-completion."
(progn
(spacemacs|add-company-backends :backends company-lsp :modes c-mode-common)
;;Disable client-side cache and sorting, as server does a better job
(setq company-transformers nil company-lsp-async t company-lsp-cache-candidates nil)))
(defun spacemacs//c-c++-lsp-wrap-functions ()
"Wrap navigation functions for the LSP backend specified by the `c-c++-backend' configuration variable."
(defun c-c++/call-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-call-hierarchy" nil))
(defun c-c++/call-hierarchy-inv () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-call-hierarchy" t))
(defun c-c++/inheritance-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-inheritance-hierarchy"))
(defun c-c++/inheritance-hierarchy-inv () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-inheritance-hierarchy" t))
(defun c-c++/member-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively-no-args nil "-member-hierarchy"))
(defun c-c++/preprocess-file () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-preprocess-file"))
(defun c-c++/refresh-index () (interactive) ()
(ecase c-c++-backend
('lsp-cquery (cquery-freshen-index))
('lsp-ccls (ccls-reload)))))
(defun spacemacs//c-c++-lsp-bind-keys-for-mode (mode)
"Bind LSP backend functions for the specified mode."
(spacemacs/set-leader-keys-for-major-mode mode
;; backend
"bf" #'c-c++/refresh-index
"bp" #'c-c++/preprocess-file
;; goto
"gf" 'find-file-at-point
"gF" 'ffap-other-window
;; hierarchy
"ghc" #'c-c++/call-hierarchy
"ghC" #'c-c++/call-hierarchy-inv
"ghi" #'c-c++/inheritance-hierarchy
"ghI" #'c-c++/inheritance-hierarchy-inv
;; members
"gmh" #'c-c++/member-hierarchy)
(spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
"&" 'refs-address
"R" 'refs-read
"W" 'refs-write
"c" 'callers
"C" 'callees
"v" 'vars
"hb" 'base) ;;Replace this with lsp-goto-implementation in lsp-layer?
(when (eq c-c++-backend 'lsp-ccls)
(spacemacs/set-leader-keys-for-major-mode mode
"bR" 'ccls-reload)
(spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
"mc" 'member-classes
"mf" 'member-functions
"mv" 'member-vars)))
(defun spacemacs//c-c++-lsp-define-extensions ()
"Wrap some backend-specific extensions using the find functions provided by lsp-mode and lsp-ui"
(spacemacs//c-c++-lsp-call-function "spacemacs//c-c++-lsp-define-" "-extensions")
(spacemacs/lsp-define-extensions "c-c++" 'vars
(spacemacs//c-c++-lsp-string "$" "/vars"))
(spacemacs/lsp-define-extensions "c-c++" 'refs-address
"textDocument/references"
'(plist-put (lsp--text-document-position-params) :context '(:role 128)))
(spacemacs/lsp-define-extensions "c-c++" 'refs-read
"textDocument/references"
'(plist-put (lsp--text-document-position-params) :context '(:role 8)))
(spacemacs/lsp-define-extensions "c-c++" 'refs-write
"textDocument/references"
'(plist-put (lsp--text-document-position-params) :context '(:role 16))))
(defun spacemacs//c-c++-lsp-define-cquery-extensions ()
(spacemacs/lsp-define-extensions "c-c++" 'callers "$cquery/callers")
(spacemacs/lsp-define-extensions "c-c++" 'callees "$cquery/callers" '(:callee t))
(spacemacs/lsp-define-extensions "c-c++" 'base "$cquery/base"))
(defun spacemacs//c-c++-lsp-define-ccls-extensions ()
(spacemacs/lsp-define-extensions "c-c++" 'callers "$ccls/call")
(spacemacs/lsp-define-extensions "c-c++" 'callees "$ccls/call" '(:callee t))
(spacemacs/lsp-define-extensions "c-c++" 'base "$ccls/inheritance" '(:levels 3))
;;ccls features without a cquery analogue...
(spacemacs/lsp-define-extensions "c-c++" 'member-classes "$ccls/member" `(:kind 2))
(spacemacs/lsp-define-extensions "c-c++" 'member-functions "$ccls/member" `(:kind 3))
(spacemacs/lsp-define-extensions "c-c++" 'member-vars "$ccls/member" `(:kind 0)))

View file

@ -0,0 +1,14 @@
;;; layers.el --- C/C++ Layer declarations File for Spacemacs
;;
;; Copyright (c) 2012-2018 Sylvain Benner & Contributors
;;
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
;; URL: https://github.com/syl20bnr/spacemacs
;;
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3
(when (and (boundp 'c-c++-backend)
(member c-c++-backend '(lsp-cquery lsp-ccls)))
(configuration-layer/declare-layer 'lsp))

View file

@ -36,7 +36,11 @@
stickyfunc-enhance stickyfunc-enhance
xcscope xcscope
ycmd ycmd
)) ;;lsp-backend
(cquery :requires lsp-mode)
(ccls :requires lsp-mode)
projectile))
(defun c-c++/init-cc-mode () (defun c-c++/init-cc-mode ()
(use-package cc-mode (use-package cc-mode
@ -60,7 +64,7 @@
(defun c-c++/init-clang-format () (defun c-c++/init-clang-format ()
(use-package clang-format (use-package clang-format
:if c-c++-enable-clang-support :if (or c-c++-enable-clang-support (spacemacs//c-c++-lsp-enabled))
:init :init
(progn (progn
(when c-c++-enable-clang-format-on-save (when c-c++-enable-clang-format-on-save
@ -75,10 +79,15 @@
(when (configuration-layer/package-used-p 'cmake-mode) (when (configuration-layer/package-used-p 'cmake-mode)
(spacemacs|add-company-backends :backends company-cmake :modes cmake-mode)) (spacemacs|add-company-backends :backends company-cmake :modes cmake-mode))
(when c-c++-enable-clang-support (when c-c++-enable-clang-support
(spacemacs|add-company-backends :backends company-clang (if (spacemacs//c-c++-lsp-enabled)
:modes c-mode-common) (display-warning :error "`c-c++-enable-clang-support' ignored when using lsp backend")
(progn
(spacemacs|add-company-backends :backends company-clang :modes c-mode-common)
(when c-c++-enable-c++11
(setq company-clang-arguments '("-std=c++11")))
(setq company-clang-prefix-guesser 'spacemacs/company-more-than-prefix-guesser) (setq company-clang-prefix-guesser 'spacemacs/company-more-than-prefix-guesser)
(spacemacs/add-to-hooks 'spacemacs/c-c++-load-clang-args c-c++-mode-hooks))) (spacemacs/add-to-hooks 'spacemacs/c-c++-load-clang-args c-c++-mode-hooks)
()))))
(defun c-c++/init-company-c-headers () (defun c-c++/init-company-c-headers ()
(use-package company-c-headers (use-package company-c-headers
@ -89,8 +98,7 @@
(defun c-c++/init-company-rtags () (defun c-c++/init-company-rtags ()
(use-package company-rtags (use-package company-rtags
:if (and c-c++-enable-rtags-support :if (and (eq c-c++-backend 'rtags) c-c++-enable-rtags-completion)
(not (eq c-c++-enable-rtags-support 'no-completion)))
:defer t :defer t
:init :init
(progn (progn
@ -125,7 +133,7 @@
;; TODO lazy load this package ;; TODO lazy load this package
(defun c-c++/init-flycheck-rtags () (defun c-c++/init-flycheck-rtags ()
(use-package flycheck-rtags (use-package flycheck-rtags
:if c-c++-enable-rtags-support)) :if (eq c-c++-backend 'rtags)))
(defun c-c++/post-init-ggtags () (defun c-c++/post-init-ggtags ()
(add-hook 'c-mode-local-vars-hook #'spacemacs/ggtags-mode-enable) (add-hook 'c-mode-local-vars-hook #'spacemacs/ggtags-mode-enable)
@ -161,19 +169,19 @@
;; TODO lazy load this package ;; TODO lazy load this package
(defun c-c++/init-helm-rtags () (defun c-c++/init-helm-rtags ()
(use-package helm-rtags (use-package helm-rtags
:if c-c++-enable-rtags-support :if (eq c-c++-backend 'rtags)
:init (setq rtags-display-result-backend 'helm))) :init (setq rtags-display-result-backend 'helm)))
;; TODO lazy load this package ;; TODO lazy load this package
(defun c-c++/init-ivy-rtags () (defun c-c++/init-ivy-rtags ()
(use-package ivy-rtags (use-package ivy-rtags
:if c-c++-enable-rtags-support :if (eq c-c++-backend 'rtags)
:init (setq rtags-display-result-backend 'ivy))) :init (setq rtags-display-result-backend 'ivy)))
;; TODO lazy load this package ;; TODO lazy load this package
(defun c-c++/init-rtags () (defun c-c++/init-rtags ()
(use-package rtags (use-package rtags
:if c-c++-enable-rtags-support :if (eq c-c++-backend 'rtags)
:init :init
(progn (progn
(setq rtags-autostart-diagnostics t) (setq rtags-autostart-diagnostics t)
@ -227,7 +235,7 @@
(defun c-c++/post-init-srefactor () (defun c-c++/post-init-srefactor ()
(dolist (mode c-c++-modes) (dolist (mode c-c++-modes)
(spacemacs/set-leader-keys-for-major-mode mode "r" 'srefactor-refactor-at-point)) (spacemacs/set-leader-keys-for-major-mode mode "r." 'srefactor-refactor-at-point))
(spacemacs/add-to-hooks 'spacemacs/load-srefactor c-c++-mode-hooks)) (spacemacs/add-to-hooks 'spacemacs/load-srefactor c-c++-mode-hooks))
(defun c-c++/post-init-stickyfunc-enhance () (defun c-c++/post-init-stickyfunc-enhance ()
@ -250,3 +258,46 @@
:post-init :post-init
(dolist (mode c-c++-modes) (dolist (mode c-c++-modes)
(spacemacs/set-leader-keys-for-major-mode mode "gi" 'cscope-index-files)))) (spacemacs/set-leader-keys-for-major-mode mode "gi" 'cscope-index-files))))
;; BEGIN LSP BACKEND PACKAGES
;; See also https://github.com/cquery-project/cquery/wiki/Emacs
(defun c-c++/init-cquery ()
(use-package cquery
:if (eq c-c++-backend 'lsp-cquery)
:defer t
:commands lsp-cquery-enable
:init
(add-hook 'c-mode-common-hook #'spacemacs//c-c++-lsp-enable)
:config
(spacemacs//c-c++-lsp-config)))
;; See also https://github.com/MaskRay/ccls/wiki/Emacs
(defun c-c++/init-ccls ()
(use-package ccls
:if (eq c-c++-backend 'lsp-ccls)
:defer t
:commands lsp-ccls-enable
:init
(add-hook 'c-mode-common-hook #'spacemacs//c-c++-lsp-enable)
:config
(spacemacs//c-c++-lsp-config)))
;;Intentionally adding both cquery and ccls cache dirs to ignore list, to facilitate switching between
;;two without multiple caches polluting projectile find file results
(defun c-c++/pre-init-projectile ()
(spacemacs|use-package-add-hook projectile
:post-config
(progn
(add-to-list 'projectile-globally-ignored-directories ".cquery_cached_index")
(add-to-list 'projectile-globally-ignored-directories ".ccls-cache")
(when c-c++-lsp-cache-dir
(add-to-list 'projectile-globally-ignored-directories c-c++-lsp-cache-dir))
(when c-c++-adopt-subprojects
(setq projectile-project-root-files-top-down-recurring
(append '("compile_commands.json"
".cquery"
".ccls")
projectile-project-root-files-top-down-recurring))))))
;; END LSP BACKEND PACKAGES