diff --git a/layers/+lang/c-c++/README.org b/layers/+lang/c-c++/README.org index 5eba8b83a876..ba506959284b 100644 --- a/layers/+lang/c-c++/README.org +++ b/layers/+lang/c-c++/README.org @@ -8,15 +8,28 @@ - [[#install][Install]] - [[#layer][Layer]] - [[#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-format][clang-format]] - [[#company-clang-and-flycheck][Company-clang and flycheck]] - - [[#rtags-configuration][RTags configuration]] - [[#enable-google-set-c-style][Enable google-set-c-style]] - [[#newlines][Newlines]] + - [[#projectile-sub-project-adoption][Projectile sub-project adoption]] - [[#key-bindings][Key Bindings]] - [[#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 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). - Support for [[https://github.com/realgud/realgud][realgud]] debugger. - 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 ** Layer @@ -52,22 +66,134 @@ by setting the variable =c-c++-default-mode-for-headers= to =c++-mode=. #+BEGIN_SRC emacs-lisp (setq-default dotspacemacs-configuration-layers - '((c-c++ :variables c-c++-default-mode-for-headers 'c++-mode))) + '((c-c++ :variables c-c++-default-mode-for-headers 'c++-mode))) #+END_SRC *Note:* To set the variable for a given project, create a directory local 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]]. +** 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 To enable Clang support, set the layer variable =c-c++-enable-clang-support= to =t= in the dotfile: #+BEGIN_SRC emacs-lisp (setq-default dotspacemacs-configuration-layers - '((c-c++ :variables c-c++-enable-clang-support t))) + '((c-c++ :variables c-c++-enable-clang-support t))) #+END_SRC +N.B. do not set this option if either the =cquery= or =ccls= backend + *** clang-format [[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=) @@ -81,7 +207,7 @@ To enable automatic buffer formatting on save, set the variable #+BEGIN_SRC emacs-lisp (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 *** 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 doesn’t complain about 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 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 @@ -140,7 +247,6 @@ set that up like this: (c-c++ :variables c-c++-enable-google-style t c-c++-enable-google-newline t) -#+END_SRC ** 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) #+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 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 | | | (e.g. switch between .cpp and .h, requires a project to work) | | ~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+. @@ -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 X~ | fix fixit at point | | ~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 | diff --git a/layers/+lang/c-c++/config.el b/layers/+lang/c-c++/config.el index 066f0f945e42..ab333bf74a05 100644 --- a/layers/+lang/c-c++/config.el +++ b/layers/+lang/c-c++/config.el @@ -17,6 +17,13 @@ (defconst c-c++-mode-hooks '(c-mode-hook c++-mode-hook) "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 "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 `c-mode-common-hook'.") -(defvar c-c++-enable-rtags-support nil - "If non nil Rtags related packages and configuration are enabled. - If `no-completion', enable all but completion.") +(defvar c-c++-enable-rtags-completion t + "If `nil', RTags completion is disabled when the RTags backend is enabled.") (defvar c-c++-enable-clang-format-on-save nil "If non-nil, automatically format code with ClangFormat on @@ -44,3 +50,36 @@ (defvar c-c++-default-mode-for-headers '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.") diff --git a/layers/+lang/c-c++/funcs.el b/layers/+lang/c-c++/funcs.el index c40162194c77..210a3f5defcb 100644 --- a/layers/+lang/c-c++/funcs.el +++ b/layers/+lang/c-c++/funcs.el @@ -9,6 +9,9 @@ ;; ;;; License: GPLv3 +(require 'cl-lib) +(require 'subr-x) + (defun spacemacs//c-toggle-auto-newline () "Toggle auto-newline." (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) (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") - (if (and (not (rtags-find-references-at-point prefix)) + (if (and (not (rtags-find-refs-at-point prefix)) rtags-last-request-not-indexed) (gtags-find-rtag))) @@ -182,3 +185,169 @@ and the arguments for flyckeck-clang based on a project-specific text file." (interactive) (call-interactively (if (spacemacs/c-c++-use-rtags t) '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))) diff --git a/layers/+lang/c-c++/layers.el b/layers/+lang/c-c++/layers.el new file mode 100644 index 000000000000..1dfcb9c84f96 --- /dev/null +++ b/layers/+lang/c-c++/layers.el @@ -0,0 +1,13 @@ +;;; layers.el --- C/C++ Layer declarations File for Spacemacs +;; +;; Copyright (c) 2012-2018 Sylvain Benner & Contributors +;; +;; Author: Sylvain Benner +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +(when (member c-c++-backend '(lsp-cquery lsp-ccls)) + (configuration-layer/declare-layer 'lsp)) diff --git a/layers/+lang/c-c++/packages.el b/layers/+lang/c-c++/packages.el index b895efdddc49..8304d43cec29 100644 --- a/layers/+lang/c-c++/packages.el +++ b/layers/+lang/c-c++/packages.el @@ -11,32 +11,36 @@ (setq c-c++-packages '( - cc-mode - clang-format - company - (company-c-headers :requires company) - (company-rtags :requires company rtags) - company-ycmd - counsel-gtags - disaster - flycheck - (flycheck-rtags :requires flycheck rtags) - gdb-mi - ggtags - google-c-style - helm-cscope - helm-gtags - (helm-rtags :requires helm rtags) - (ivy-rtags :requires ivy rtags) - org - realgud - rtags - semantic - srefactor - stickyfunc-enhance - xcscope - ycmd - )) + cc-mode + clang-format + company + (company-c-headers :requires company) + (company-rtags :requires company rtags) + company-ycmd + counsel-gtags + disaster + flycheck + (flycheck-rtags :requires flycheck rtags) + gdb-mi + ggtags + google-c-style + helm-cscope + helm-gtags + (helm-rtags :requires helm rtags) + (ivy-rtags :requires ivy rtags) + org + realgud + rtags + semantic + srefactor + stickyfunc-enhance + xcscope + ycmd + ;;lsp-backend + (cquery :requires lsp-mode) + (ccls :requires lsp-mode) + projectile)) + (defun c-c++/init-cc-mode () (use-package cc-mode @@ -60,7 +64,7 @@ (defun c-c++/init-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 (progn (when c-c++-enable-clang-format-on-save @@ -75,10 +79,15 @@ (when (configuration-layer/package-used-p 'cmake-mode) (spacemacs|add-company-backends :backends company-cmake :modes cmake-mode)) (when c-c++-enable-clang-support - (spacemacs|add-company-backends :backends company-clang - :modes c-mode-common) - (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))) + (if (spacemacs//c-c++-lsp-enabled) + (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) + (spacemacs/add-to-hooks 'spacemacs/c-c++-load-clang-args c-c++-mode-hooks) + ())))) (defun c-c++/init-company-c-headers () (use-package company-c-headers @@ -89,8 +98,7 @@ (defun c-c++/init-company-rtags () (use-package company-rtags - :if (and c-c++-enable-rtags-support - (not (eq c-c++-enable-rtags-support 'no-completion))) + :if (and (eq c-c++-backend 'rtags) c-c++-enable-rtags-completion) :defer t :init (progn @@ -125,7 +133,7 @@ ;; TODO lazy load this package (defun c-c++/init-flycheck-rtags () (use-package flycheck-rtags - :if c-c++-enable-rtags-support)) + :if (eq c-c++-backend 'rtags))) (defun c-c++/post-init-ggtags () (add-hook 'c-mode-local-vars-hook #'spacemacs/ggtags-mode-enable) @@ -161,19 +169,19 @@ ;; TODO lazy load this package (defun c-c++/init-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))) ;; TODO lazy load this package (defun c-c++/init-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))) ;; TODO lazy load this package (defun c-c++/init-rtags () (use-package rtags - :if c-c++-enable-rtags-support + :if (eq c-c++-backend 'rtags) :init (progn (setq rtags-autostart-diagnostics t) @@ -227,7 +235,7 @@ (defun c-c++/post-init-srefactor () (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)) (defun c-c++/post-init-stickyfunc-enhance () @@ -250,3 +258,46 @@ :post-init (dolist (mode c-c++-modes) (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