[c-c++] C/C++ layer refactor to support multiple backends

This commit is contained in:
syl20bnr 2019-09-30 23:48:24 -04:00
parent ab818140d0
commit d536b36d15
7 changed files with 976 additions and 841 deletions

View File

@ -1165,8 +1165,7 @@ Other:
(thanks to Cormac Cannon, Sergey Litovchuk, Fangrui Song and David Vo)
- Fixed =lsp= support for =ccls= server (thanks to Alexander Dalshov)
- Added automatic formatting on save using ClangFormat with the variables
=c-c++-enable-clang-format-on-save= and =c-c++-enable-clang-support=
(thanks to Robbert van der Helm)
=c-c++-enable-clang-format-on-save= (thanks to Robbert van der Helm)
- Added possible value =no-completion= to =c-c++-enable-rtags-support= flag.
This adds the option to opt-out of =company-rtags= while enabling Rtags.
- Added option to use =google-c-style= with the variable

View File

@ -9,64 +9,67 @@
- [[#features][Features:]]
- [[#install][Install]]
- [[#layer][Layer]]
- [[#default-mode-for-header-files][Default mode for header files]]
- [[#backends][Backends]]
- [[#rtags][RTags]]
- [[#external-dependencies][External dependencies]]
- [[#configuration][Configuration]]
- [[#lsp][LSP]]
- [[#features-1][Features]]
- [[#external-dependencies-1][External dependencies]]
- [[#external-dependencies][External dependencies]]
- [[#clangd][clangd]]
- [[#ccls-server][ccls server]]
- [[#cquery-server][cquery server]]
- [[#configuration-1][Configuration]]
- [[#configuration][Configuration]]
- [[#basic][Basic]]
- [[#selecting-an-alternate-lsp-server][Selecting an alternate LSP server]]
- [[#setting-path-to-backend-executable][Setting path to backend executable]]
- [[#semantic-highlighting][Semantic highlighting]]
- [[#cache-directory-absolute-or-relative][Cache directory (absolute or relative)]]
- [[#additional-configuration-options][Additional configuration options]]
- [[#example-dotspacemacs-configuration-layers-entry][Example dotspacemacs-configuration-layers entry]]
- [[#completion][Completion]]
- [[#debugger-dap-integration][Debugger (dap integration)]]
- [[#rtags][rtags]]
- [[#external-dependencies-1][External dependencies]]
- [[#configuration-1][Configuration]]
- [[#default-mode-for-header-files][Default mode for header files]]
- [[#organize-file-header-includes-on-save][Organize file header includes on save]]
- [[#clang-configuration][Clang Configuration]]
- [[#clang-format][clang-format]]
- [[#company-clang-and-flycheck][Company-clang and flycheck]]
- [[#clang-format][clang-format]]
- [[#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-1][RTags]]
- [[#lsp-1][LSP]]
- [[#cquery--ccls][cquery / ccls]]
- [[#backend-language-server][backend (language server)]]
- [[#goto][goto]]
- [[#cquery--ccls][cquery / ccls]]
- [[#backend-language-server][backend (language server)]]
- [[#goto][goto]]
- [[#gotohierarchy][goto/hierarchy]]
- [[#gotomember][goto/member]]
- [[#debugger][debugger]]
- [[#debugger][debugger]]
- [[#rtags-1][RTags]]
- [[#additional-key-bindings][Additional key-bindings]]
- [[#disassemble][Disassemble]]
- [[#formatting-clang-format][Formatting (clang-format)]]
- [[#open-matching-files][Open matching files]]
- [[#refactor][Refactor]]
* Description
This layer adds configuration for C/C++ language.
** Features:
- Support syntax checking via flycheck with Clang.
- Support for disassembly of code with [[https://github.com/jart/disaster][disaster]].
- Multiple backends support:
- LSP with either =clangd=, [[https://github.com/cquery-project/cquery][cquery]] or [[https://github.com/MaskRay/ccls][ccls]]
- [[https://github.com/Andersbakken/rtags][rtags]] (gtags)
- [[https://github.com/abingham/emacs-ycmd][emacs-ycmd]]
- Support for debuggers [[https://github.com/realgud/realgud][realgud]] and [[https://github.com/emacs-lsp/dap-mode][dap]] (with LSP backend)
- Support syntax checking via flycheck (=syntax-checking= layer required)
- Auto-completion via company (=auto-completion= layer required)
- Support code reformatting with [[http://clang.llvm.org/docs/ClangFormat.html][clang-format]].
- Display function or variable definition at the bottom. (when =semantic= layer
is included)
- Display current function cursor is in at the top. See [[https://github.com/tuhdo/semantic-stickyfunc-enhance][stickyfunc-demos]] for
demos in some programming languages. (when =semantic= layer is included)
- Support common refactoring with [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]]. See [[https://github.com/tuhdo/semantic-refactor/blob/master/srefactor-demos/demos.org][srefactor-demos]] for
demonstration of refactoring features. (when =semantic= layer is included)
- Support code navigation via cscope (when =cscope= layer is included) and gtags.
- Support auto-completion (when =auto-completion= layer is included) via
company-clang (when =c-c++-enable-clang-support= is turned on), or
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.
- Support for disassembly of code with [[https://github.com/jart/disaster][disaster]].
- =sematic= layer integration:
- Function or variable definition at the bottom
- Current function cursor is in at the top. See [[https://github.com/tuhdo/semantic-stickyfunc-enhance][stickyfunc-demos]] for
demos in some programming languages.
- Support common refactoring with [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]]. See [[https://github.com/tuhdo/semantic-refactor/blob/master/srefactor-demos/demos.org][srefactor-demos]] for
demonstration of refactoring features.
- =cscope= layer integration:
- code navigation
* Install
** Layer
@ -74,7 +77,171 @@ To use this configuration layer, add it to your =~/.spacemacs=. You will need to
add =c-c++= to the existing =dotspacemacs-configuration-layers= list in this
file.
*Note:* [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]] is only available for Emacs 24.4+
** Backends
Supported backends are:
- =lsp-clangd= using clangd LSP server
- =lsp-ccls= using ccls LSP server
- =lsp-cquery= using cquery LSP server
- =rtags= using [[https://github.com/Andersbakken/rtags][rtags]]
- =ycmd= using [[https://github.com/abingham/emacs-ycmd][emacs-ycmd]]
To choose a default backend set the layer variable =c-c++-backend=:
#+BEGIN_SRC elisp
(c-c++ :variables =c-c++-backend= 'lsp-clangd)
#+END_SRC
Alternatively the =lsp-clangd= backend will be automatically chosen if the layer
=lsp= is used and you did not specify any value for =c-c++-backend=.
*Note:* It is recommended to use a modern backend like the =lsp= ones.
Backend can be chosen on a per project basis using directory local variables
(files named =.dir-locals.el= at the root of a project), an example to use the
=lsp-ccls= backend:
#+BEGIN_SRC elisp
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((c++-mode (c-c++-backend . lsp-ccls)))
#+END_SRC
*Note:* you can easily add a directory local variable with ~SPC f v d~.
*** LSP
LSP support is provided via the [[file:../../+tools/lsp/README.org][LSP layer]], using one of three available backends
(all based on libclang).
- [[https://clang.llvm.org/extra/clangd/][clangd]]
- [[https://github.com/cquery-project/cquery][cquery]]
- [[https://github.com/MaskRay/ccls][ccls]]
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 (=cquery=, =ccls=)
- See more on [[https://github.com/cquery-project/cquery/wiki/Emacs]]
- Cross-platform - functional on Windows, Linux and macOS.
**** External dependencies
Install one (or more) of the following (=clangd= is used by default):
***** clangd
Install =clang= using a binary distribution downloaded from the [[http://releases.llvm.org/download.html][LLVM releases
page]] or via your package manager. This is the default implementation used by the
emacs =lsp-mode= package and probably the easiest to install.
- [[https://clang.llvm.org/extra/clangd/Extensions.html][clangd protocol extensions page]]
***** ccls server
Install the =ccls= server. See [[https://github.com/MaskRay/ccls/wiki][instructions]]. This is currently the most fully
featured implementation, including semantic highlighting and some navigation/
introspection features not provided by clangd.
Note that prebuild binaries exist for most Linux distros and MacOS using
Homebrew.
***** cquery server
Install the =cquery= server. See [[https://github.com/cquery-project/cquery/wiki][instructions]]. This implementation appears to be
unmaintained and continued support is provided here purely for existing users.
It is recommended to use the =lsp-ccls= backend instead if you can.
Note that prebuild binaries exist for most Linux distros and MacOS using
Homebrew.
**** Configuration
***** Basic
To use the default =clangd= language server, select =lsp-clangd= 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-clangd)))
#+END_SRC
***** Selecting an alternate LSP server
To choose an alternate LSP server set the layer variable =c-c++-backend= to
another supported backend, for instance =lsp-ccls=:
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables c-c++-backend 'lsp-ccls)))
#+END_SRC
***** Semantic highlighting
Currently only available for =lsp-ccls= and =lps-cquery=. Semantic highlighting
can precisely highlight identifiers.
Semantic highlighting is disabled by default. To enable it set the layer
=c-c++-lsp-enable-semantic-highlight= to non-nil. It is possible to give a
different color for each identifier by setting the variable to ='rainbow=.
When semantic highlighting is enabled the method used to highlight the text
relies on the =font-lock= mechanism of Emacs which is the fastest. More
accurate but also slower method is to use the overlays. To use the overlays set
the layer variable =c-c++-lsp-semantic-highlight-method= to ='overlay=.
***** Cache directory (absolute or relative)
Currently only available for =lsp-ccls= and =lps-cquery=.
All 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 current project root.
***** Additional configuration options
See the full list of configuration options you can set at:
- [[https://github.com/MaskRay/ccls/wiki/Emacs][Emacs section of =ccls= wiki]]
- [[https://github.com/cquery-project/cquery/wiki/Emacs][Emacs section of =cquery= 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-enable-semantic-highlight 'rainbow)))
#+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.
**** Debugger (dap integration)
To install the debug adapter you may run =M-x dap-gdb-lldb-setup= when you are
on Linux or download it manually from [[https://marketplace.visualstudio.com/items?itemName=webfreak.debug][Native Debug]] and adjust the
=dap-gdb-lldb-path= 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++-backend=:
#+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
** Default mode for header files
Mode for header files is auto detected by `c-or-c++-mode' in Emacs > 26.1+.
@ -90,150 +257,6 @@ Older Emacs will open header files in =c-mode= by default, you can open them in
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 RTags, or one of three available implementations
of the [[https://github.com/Microsoft/language-server-protocol][Language Server Protocol]]
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++-backend=:
#+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
*** LSP
LSP support is provided via the [[file:../../+tools/lsp/README.org][LSP layer]], using one of three available backends (all based on libclang).
- [[https://clang.llvm.org/extra/clangd/][clangd]]
- [[https://github.com/cquery-project/cquery][cquery]]
- [[https://github.com/MaskRay/ccls][ccls]]
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 (=cquery=, =ccls=)
- See more on [[https://github.com/cquery-project/cquery/wiki/Emacs]]
- Cross-platform - functional on Windows, Linux and macOS.
**** External dependencies
Install one (or more) of the following (=clangd= is used by default) :
***** clangd
Install =clang= using a binary distribution downloaded from the [[http://releases.llvm.org/download.html][LLVM releases page]] or via your package manager.
This is the default implementation used by the emacs =lsp-mode= package and probably the easiest to install.
- [[https://clang.llvm.org/extra/clangd/Extensions.html][clangd protocol extensions page]]
***** ccls server
Install the =ccls= server. [[https://github.com/MaskRay/ccls/wiki/Getting-started][Instructions]].
This is currently the most fully featured implementation, including semantic highlighting and some navigation/
introspection features not provided by clangd.
***** cquery server
Install the =cquery= server. [[https://github.com/cquery-project/cquery/wiki/Getting-started][Instructions]].
This implementation appears to be unmaintained, and continued support is provided here purely for existing users.
**** Configuration
***** Basic
To use the default =clangd= language server, simply select =lsp= 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)))
#+END_SRC
N.B. The [[file:../../+tools/lsp/README.org][LSP layer]] will be loaded automatically.
***** Selecting an alternate LSP server
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((c-c++ :variables c-c++-backend 'lsp c-c++-lsp-server 'ccls))) ; or 'cquery or 'clangd
#+END_SRC
***** 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
c-c++-server 'ccls
c-c++-lsp-executable "/path/to/bin/ccls/clangd/or/cquery")))
#+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
c-c++-server 'ccls
c-c++-lsp-executable (file-truename "~/bin/clangd/ccls/or/cquery"))))
#+END_SRC
***** Semantic highlighting :ccls:cquery:
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 :ccls:cquery:
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 =config.el= of
the layer and the backends' respective homepages for more info.
- [[https://github.com/MaskRay/ccls/wiki/Emacs][Emacs section of =ccls= wiki]]
- [[https://github.com/cquery-project/cquery/wiki/Emacs][Emacs section of =cquery= 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
c-c++-server '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.
**** Debugger (dap integration)
To install the debug adapter you may run =M-x dap-gdb-lldb-setup= when you are
on Linux or download it manually from [[https://marketplace.visualstudio.com/items?itemName=webfreak.debug][Native Debug]] and adjust
=dap-gdb-lldb-path=.
** Organize file header includes on save
To organize the file header includes on save, set the layer variable
=c++-enable-organize-includes-on-save= to =t= in the dotfile:
@ -243,24 +266,12 @@ To organize the file header includes on save, set the layer variable
'((c-c++ :variables c++-enable-organize-includes-on-save t)))
#+END_SRC
** 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)))
#+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
(=clang-format-region=) or a whole buffer (=clang-format-buffer=)
according to a style defined in a =.clang-format= file. This file
is either located in the same directory as the file being edited,
or any of its parent directories. If no =.clang-format= is found,
then a default style will be used.
(=clang-format-region=) or a whole buffer (=clang-format-buffer=) according to a
style defined in a =.clang-format= file. This file is either located in the same
directory as the file being edited, or any of its parent directories. If no
=.clang-format= is found, then a default style will be used.
To enable automatic buffer formatting on save, set the variable
=c-c++-enable-clang-format-on-save= to =t=:
@ -270,15 +281,6 @@ To enable automatic buffer formatting on save, set the variable
'((c-c++ :variables c-c++-enable-clang-format-on-save t)))
#+END_SRC
*** Company-clang and flycheck
This layer adds some fancy improvements to =company-clang=. It includes a hook
to load a projects =.clang_complete= file, which is just a text file with one
clang flag per line, a format also used by other text editor clang plugins.
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.
** 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
@ -328,74 +330,22 @@ generally applicable.
* Key bindings
| Key binding | Description |
|-------------+---------------------------------------------------------------|
| ~SPC m g a~ | open matching file |
| | (e.g. switch between .cpp and .h, requires a project to work) |
| ~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 i~ | organize includes |
*Note:* [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]] is only available for Emacs 24.4+.
** Formatting (clang-format)
| Key binding | Description |
|-------------+---------------------------------|
| ~SPC m = =~ | format current region or buffer |
| ~SPC m = f~ | format current function |
** RTags
| Key binding | Description |
|-------------+---------------------------------|
| ~SPC m g .~ | find symbol at point |
| ~SPC m g ,~ | find references at point |
| ~SPC m g ;~ | find file |
| ~SPC m g /~ | find all references at point |
| ~SPC m g [~ | location stack back |
| ~SPC m g ]~ | location stack forward |
| ~SPC m g >~ | c++ tags find symbol |
| ~SPC m g <~ | c++ tags find references |
| ~SPC m g B~ | show rtags buffer |
| ~SPC m g d~ | print dependencies |
| ~SPC m g D~ | diagnostics |
| ~SPC m g e~ | reparse file |
| ~SPC m g E~ | preprocess file |
| ~SPC m g F~ | fixit |
| ~SPC m g G~ | guess function at point |
| ~SPC m g h~ | print class hierarchy |
| ~SPC m g I~ | c++ tags imenu |
| ~SPC m g L~ | copy and print current location |
| ~SPC m g M~ | symbol info |
| ~SPC m g O~ | goto offset |
| ~SPC m g p~ | set current project |
| ~SPC m g R~ | rename symbol |
| ~SPC m g s~ | print source arguments |
| ~SPC m g S~ | display summary |
| ~SPC m g T~ | taglist |
| ~SPC m g v~ | find virtuals at point |
| ~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 |
** LSP
The default key bindings for LSP implementations are defined by/documented in the [[file:../../+tools/lsp/README.org][LSP layer]].
The default key bindings for LSP implementations are defined by/documented in
the [[file:../../+tools/lsp/README.org][LSP layer]].
** cquery / ccls
*** cquery / ccls
The key bindings listed below are in addition to
A ~[ccls]~ or ~[cquery]~ suffix indicates that the binding is for the indicated backend only.
*** backend (language server)
**** backend (language server)
| Key binding | Description |
|-------------+------------------------------------------|
| ~SPC m b f~ | refresh index (e.g. after branch change) |
| ~SPC m b p~ | preprocess file |
*** goto
**** goto
| Key binding | Description |
|-------------+---------------------------|
@ -428,7 +378,7 @@ A ~[ccls]~ or ~[cquery]~ suffix indicates that the binding is for the indicated
| ~SPC m g m f~ | member functions [ccls] |
| ~SPC m g m v~ | member variables [ccls] |
** debugger
*** debugger
| Key binding | Description |
|---------------+---------------------------------|
@ -474,3 +424,68 @@ A ~[ccls]~ or ~[cquery]~ suffix indicates that the binding is for the indicated
| ~SPC m d w o~ | goto output buffer if present |
| ~SPC m d w s~ | list sessions |
| ~SPC m d w b~ | list breakpoints |
** RTags
| Key binding | Description |
|-------------+---------------------------------|
| ~SPC m g .~ | find symbol at point |
| ~SPC m g ,~ | find references at point |
| ~SPC m g ;~ | find file |
| ~SPC m g /~ | find all references at point |
| ~SPC m g [~ | location stack back |
| ~SPC m g ]~ | location stack forward |
| ~SPC m g >~ | c++ tags find symbol |
| ~SPC m g <~ | c++ tags find references |
| ~SPC m g B~ | show rtags buffer |
| ~SPC m g d~ | print dependencies |
| ~SPC m g D~ | diagnostics |
| ~SPC m g e~ | reparse file |
| ~SPC m g E~ | preprocess file |
| ~SPC m g F~ | fixit |
| ~SPC m g G~ | guess function at point |
| ~SPC m g h~ | print class hierarchy |
| ~SPC m g I~ | c++ tags imenu |
| ~SPC m g L~ | copy and print current location |
| ~SPC m g M~ | symbol info |
| ~SPC m g O~ | goto offset |
| ~SPC m g p~ | set current project |
| ~SPC m g R~ | rename symbol |
| ~SPC m g s~ | print source arguments |
| ~SPC m g S~ | display summary |
| ~SPC m g T~ | taglist |
| ~SPC m g v~ | find virtuals at point |
| ~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 |
** Additional key-bindings
*** Disassemble
| Key binding | Description |
|-------------+----------------------------------|
| ~SPC m D~ | disaster: disassemble c/c++ code |
| | |
*** Formatting (clang-format)
| Key binding | Description |
|-------------+---------------------------------|
| ~SPC m = =~ | format current region or buffer |
| ~SPC m = f~ | format current function |
*** Open matching files
| Key binding | Description |
|-------------+---------------------------------------------------------------|
| ~SPC m g a~ | open matching file |
| | (e.g. switch between .cpp and .h, requires a project to work) |
| ~SPC m g A~ | open matching file in another window |
| | (e.g. switch between .cpp and .h, requires a project to work) |
*** Refactor
| Key binding | Description |
|-------------+-------------------------------------|
| ~SPC m r .~ | srefactor: refactor thing at point. |
| ~SPC m r i~ | organize includes |

View File

@ -15,49 +15,34 @@
(spacemacs|define-jump-handlers c-mode)
(defvar c-c++-backend nil
"May be `nil', `rtags' or `lsp'.")
(defconst c-c++-lsp-backends '(lsp-cquery lsp-ccls)
"Language Server Protocol (LSP) backends supported by the `c-c++' layer.")
"The backend to use for IDE features.
Possible values are `lsp-ccls', `lsp-cquery', `lsp-clangd', `rtags' and `ycmd'.")
;; lsp
(defconst c-c++-lsp-servers '(clangd ccls cquery)
"Language Server Protocol (LSP) backends supported by the `c-c++' layer.")
(defvar c-c++-lsp-server 'clangd
"May be any member of `c-c++-lsp-servers'")
(defvar c-c++-lsp-cache-dir nil
"Cache directory. Absolute and relative paths supported.")
"Cache directory for lsp backends.
Can be nil, an absolute path or a relative path.
If it is nil then the cache directory is in `spacemacs-cache-directory'.
If it is a relative path then it is relative to the project root.
(defvar c-c++-lsp-executable nil
"Path to cquery/ccls executable (default value assumes it's in the path)")
Notes:
- The name of the selected LSP backend is automatically appended to this
path.
- This variable has no effect with `lsp-clangd' backend.")
(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-enable-semantic-highlight nil
"If non-nil then enable semantic highlighting.
If `t' then regular semantic highlighting is enabled.
If `rainbow' then rainbow semantic highlighting is enabled.
Rainbow semantic highlighting gives a unique color to each identifier.")
(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-semantic-highlight-method 'font-lock
"Method used to highlight the text when semantic highlighting is enabled.
(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")
(defvar c-c++-lsp-initialization-options nil
"Extra initialisation parameters to pass to the lsp backend. See
https://github.com/MaskRay/ccls/blob/master/src/config.hh
for details. N.B. This is remapped to cquery-extra-init-params when using cquery backend")
(defvar c-c++-lsp-args nil
"Extra args to pass to the backend. E.g. to log to file.
https://github.com/MaskRay/ccls/wiki/Emacs for details. N.B. this is remapped to cquery-extra-args when using cquery backend")
By default `font-lock' is used to highlight the text, set the variable to
`overlay' if you want to use overlays. Note that overlays can be slower.")
;; rtags
@ -68,9 +53,6 @@ https://github.com/MaskRay/ccls/wiki/Emacs for details. N.B. this is remapped to
;; clang
(defvar c-c++-enable-clang-support nil
"If non nil Clang related packages and configuration are enabled.")
(defvar c-c++-enable-clang-format-on-save nil
"If non-nil, automatically format code with ClangFormat on
save. Clang support has to be enabled for this to work.")

View File

@ -12,152 +12,332 @@
(require 'cl-lib)
(require 'subr-x)
(defun spacemacs//c-toggle-auto-newline ()
"Toggle auto-newline."
(c-toggle-auto-newline 1))
(defun spacemacs//c-c++-backend ()
"Returns selected backend."
(if c-c++-backend
c-c++-backend
(cond
((configuration-layer/layer-used-p 'lsp) 'lsp-clangd)
(t nil))))
(defun spacemacs//c-c++-setup-backend ()
"Conditionally setup c-c++ backend."
(pcase (spacemacs//c-c++-backend)
(`lsp-clangd (spacemacs//c-c++-setup-lsp-clangd))
(`lsp-ccls (spacemacs//c-c++-setup-lsp-ccls))
(`lsp-cquery (spacemacs//c-c++-setup-lsp-cquery))
(`rtags (spacemacs//c-c++-setup-rtags))
(`ycmd (spacemacs//c-c++-setup-ycmd))))
(defun spacemacs//c-c++-setup-company ()
"Conditionally setup C/C++ company integration based on backend."
(pcase (spacemacs//c-c++-backend)
(`lsp-clangd (spacemacs//c-c++-setup-lsp-company))
(`lsp-ccls (spacemacs//c-c++-setup-lsp-company))
(`lsp-cquery (spacemacs//c-c++-setup-lsp-company))
(`rtags (spacemacs//c-c++-setup-rtags-company))
(`ycmd (spacemacs//c-c++-setup-ycmd-company))))
(defun spacemacs//c-c++-setup-dap ()
"Conditionally setup C/C++ DAP integration based on backend."
;; currently DAP is only available using LSP
(pcase (spacemacs//c-c++-backend)
(`lsp-clangd (spacemacs//c-c++-setup-lsp-dap))
(`lsp-ccls (spacemacs//c-c++-setup-lsp-dap))
(`lsp-cquery (spacemacs//c-c++-setup-lsp-dap))))
(defun spacemacs//c-c++-setup-eldoc ()
"Conditionally setup C/C++ eldoc integration based on backend."
(pcase (spacemacs//c-c++-backend)
;; lsp setup eldoc on its own
(`ycmd (spacemacs//c-c++-setup-ycmd-eldoc))))
(defun spacemacs//c-c++-setup-flycheck ()
"Conditionally setup C/C++ flycheck integration based on backend."
(pcase (spacemacs//c-c++-backend)
(`lsp-clangd (spacemacs//c-c++-setup-lsp-flycheck))
(`lsp-ccls (spacemacs//c-c++-setup-lsp-flycheck))
(`lsp-cquery (spacemacs//c-c++-setup-lsp-flycheck))
(`rtags (spacemacs//c-c++-setup-rtags-flycheck))
(`ycmd (spacemacs//c-c++-setup-ycmd-flycheck))))
(defun spacemacs//c-c++-setup-format ()
"Conditionally setup format based on backend."
(pcase (spacemacs//c-c++-backend)
(`lsp-clangd (spacemacs//c-c++-setup-clang-format))
(`lsp-ccls (spacemacs//c-c++-setup-clang-format))
(`lsp-cquery (spacemacs//c-c++-setup-clang-format))))
;; lsp
;; clang
(defun spacemacs/clang-format-function (&optional style)
"Format the current function with clang-format according to STYLE."
(interactive)
(save-excursion
(c-mark-function)
(clang-format (region-beginning) (region-end) style)
(deactivate-mark) ; If the function is already formatted, then remove the mark
(message "Formatted function %s" (c-defun-name))))
(defun spacemacs//c-c++-setup-lsp-clangd ()
"Setup LSP clangd."
;; extensions
(spacemacs/lsp-define-extensions
"c-c++" "lsp-clangd"
'clangd-other-file "textDocument/switchSourceHeader" 'buffer-file-name)
(lsp))
(defun spacemacs/clang-format-region-or-buffer (&optional style)
"Format the current region or buffer with clang-format according to STYLE."
(interactive)
(save-excursion
(if (region-active-p)
(progn
(clang-format-region (region-beginning) (region-end) style)
(message "Formatted region"))
(progn
(clang-format-buffer style)
(message "Formatted buffer %s" (buffer-name))))))
;; ccls
(defun spacemacs//clang-format-on-save ()
"Format the current buffer with clang-format on save when
`c-c++-enable-clang-format-on-save' is non-nil."
(when c-c++-enable-clang-format-on-save
(spacemacs/clang-format-region-or-buffer)))
(defun spacemacs//c-c++-setup-lsp-ccls ()
"Setup LSP ccls."
(require 'ccls)
;; configuration
(let ((cache-dir
(if (null c-c++-lsp-cache-dir)
(concat spacemacs-cache-directory "lsp-ccls")
(concat (file-truename (file-name-as-directory c-c++-lsp-cache-dir))
"lsp-ccls"))))
(append ccls-initialization-options
`(:cache (:directory ,cache-dir))))
(defun spacemacs/clang-format-on-save ()
"Add before-save hook for clang-format."
(add-hook 'before-save-hook 'spacemacs//clang-format-on-save nil t))
;; semantic highlight
(when c-c++-lsp-enable-semantic-highlight
(setq ccls-sem-highlight-method c-c++-lsp-semantic-highlight-method)
(when (eq 'rainbow c-c++-lsp-enable-semantic-highlight)
(ccls-use-default-rainbow-sem-highlight)))
(defun spacemacs/company-more-than-prefix-guesser ()
(spacemacs/c-c++-load-clang-args)
(company-clang-guess-prefix))
;; extensions
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'refs-address "textDocument/references" '(:role 128))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'refs-read "textDocument/references" '(:role 8))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'refs-write "textDocument/references" '(:role 16))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'callers "$ccls/call")
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'callees "$ccls/call" '(:callee t))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'base "$ccls/inheritance")
;;ccls features without a cquery analogue...
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'derived "$ccls/inheritance" '(:derived t))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'member-types "$ccls/member" `(:kind 2))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'member-functions "$ccls/member" `(:kind 3))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-ccls"
'member-vars "$ccls/member" `(:kind 0))
;; Based on the Sarcasm/irony-mode compilation database code.
(defun spacemacs/company-find-clang-complete-file ()
(when buffer-file-name
(let ((dir (locate-dominating-file buffer-file-name ".clang_complete")))
(when dir
(concat (file-name-as-directory dir) ".clang_complete")))))
;; key bindings
(dolist (mode c-c++-modes)
(spacemacs/set-leader-keys-for-major-mode mode
;; backend
"bf" 'ccls-reload
"bp" 'ccls-preprocess-file
;; goto
"gf" 'find-file-at-point
"gF" 'ffap-other-window
;; hierarchy
"ghc" 'ccls-call-hierarchy
"ghC" 'spacemacs/c-c++-lsp-ccls-call-hierarchy-inv
"ghi" 'ccls-inheritance-hierarchy
"ghI" 'spacemacs/c-c++-lsp-ccls-inheritance-hierarchy-inv
;; members
"gmh" 'ccls-member-hierarchy)
;; Based on the Sarcasm/irony-mode compilation database code.
(defun spacemacs/company-load-clang-complete-file (cc-file)
"Load the flags from CC-FILE, one flag per line."
(let ((invocation-dir (expand-file-name (file-name-directory cc-file)))
(case-fold-search nil)
(include-regex "\\(-I\\|-isystem\\|-iquote\\|-idirafter\\)\\s-*\\(\\S-+\\)")
compile-flags)
(with-temp-buffer
(insert-file-contents cc-file)
;; Replace relative paths with absolute paths (by @trishume)
;; (goto-char (point-min))
(while (re-search-forward include-regex nil t)
(replace-match (format "%s%s" (match-string 1)
(expand-file-name (match-string 2)
invocation-dir))))
;; Turn lines into a list
(setq compile-flags
;; remove whitespaces at the end of each line, if any
(mapcar #'(lambda (line)
(if (string-match "[ \t]+$" line)
(replace-match "" t t line)
line))
(split-string (buffer-string) "\n" t))))
compile-flags))
;;Replace this with lsp-goto-implementation in lsp-layer?
(spacemacs/lsp-bind-extensions-for-mode
mode "c-c++" "lsp-ccls"
"&" 'refs-address
"R" 'refs-read
"W" 'refs-write
"c" 'callers
"C" 'callees
"v" 'vars
"hb" 'base)
(defun spacemacs//c-c++-get-standard-include-paths (lang)
"Returns the default system header include paths for LANG if gcc is on the
system and supports it, else returns a default set of include paths."
(let* ((start "#include <...> search starts here:")
(end "End of search list.")
(gcc-tmplt "echo | gcc -x%s -E -v - 2>&1")
(sed-tmplt " | sed -n '/%s/,/%s/{/%s/b;/%s/b;p}' | sed -e 's/^ *//g'")
(template (concat gcc-tmplt sed-tmplt))
(inc-dirs-cmd (format template lang start end start end))
(inc-dirs (split-string (shell-command-to-string inc-dirs-cmd)
"\n" t)))
(if (and inc-dirs (every 'file-exists-p inc-dirs))
inc-dirs
'("/usr/include" "/usr/local/include"))))
(spacemacs/lsp-bind-extensions-for-mode
mode "c-c++" "lsp-ccls"
"hd" 'derived
"mt" 'member-types
"mf" 'member-functions
"mv" 'member-vars))
(defun spacemacs//filter-and-substring (flags filter-prefix substr-index)
"Returns all the strings in FLAGS starting with FILTER-PREFIX. The returned
strings are substringed from SUBSTR-INDEX inclusive to the end of the string."
(mapcar (lambda (f) (substring f substr-index))
(remove-if-not (lambda (f) (string-prefix-p filter-prefix f))
flags)))
;;(evil-set-initial-state 'ccls--tree-mode 'emacs)
;;evil-record-macro keybinding clobbers q in cquery-tree-mode-map for some reason?
;;(evil-make-overriding-map 'ccls-tree-mode-map)
(lsp))
(defun spacemacs/c-c++-load-clang-args ()
"Sets the arguments for company-clang, the system paths for company-c-headers
and the arguments for flyckeck-clang based on a project-specific text file."
(unless company-clang-arguments
(let* ((cc-file (spacemacs/company-find-clang-complete-file))
(flags (if cc-file
(spacemacs/company-load-clang-complete-file cc-file)
'()))
(i-paths (spacemacs//filter-and-substring flags
"-I" 2))
(iquote-paths (spacemacs//filter-and-substring flags
"-iquote" 7))
(isystem-paths (spacemacs//filter-and-substring flags
"-isystem" 8))
(idirafter-paths (spacemacs//filter-and-substring flags
"-idirafter" 10)))
(setq-local company-clang-arguments flags)
(setq-local flycheck-clang-args flags)
(setq-local company-c-headers-path-user
(append '(".")
iquote-paths))
(setq-local company-c-headers-path-system
(append i-paths
isystem-paths
(when (string-equal major-mode "c++-mode")
(spacemacs//c-c++-get-standard-include-paths "c++"))
(when (string-equal major-mode "c-mode")
(spacemacs//c-c++-get-standard-include-paths "c"))
idirafter-paths)))))
;; cquery
;; cpp-auto-include
(defun spacemacs//c-c++-setup-lsp-cquery ()
"Setup LSP cquery."
(require 'cquery)
;; configuration
(setq cquery-cache-dir
(if (null c-c++-lsp-cache-dir)
(concat spacemacs-cache-directory "lsp-cquery")
(concat (file-truename (file-name-as-directory c-c++-lsp-cache-dir))
"lsp-cquery")))
(defalias 'spacemacs/c++-organize-includes 'cpp-auto-include)
;; semantic highlight
(when c-c++-lsp-enable-semantic-highlight
(setq cquery-sem-highlight-method c-c++-lsp-semantic-highlight-method)
(when (eq 'rainbow c-c++-lsp-enable-semantic-highlight)
(cquery-use-default-rainbow-sem-highlight)))
(defun spacemacs//c++-organize-includes-on-save ()
"Organize the includes on save when `c++-enable-organize-includes-on-save'
is non-nil."
(when c++-enable-organize-includes-on-save
(spacemacs/c++-organize-includes)))
;; extensions
(spacemacs/lsp-define-extensions
"c-c++" "lsp-cquery"
'refs-address "textDocument/references"
'(plist-put (lsp--text-document-position-params) :context '(:role 128)))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-cquery"
'refs-read "textDocument/references"
'(plist-put (lsp--text-document-position-params) :context '(:role 8)))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-cquery"
'refs-write "textDocument/references"
'(plist-put (lsp--text-document-position-params) :context '(:role 16)))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-cquery"
'callers "$cquery/callers")
(spacemacs/lsp-define-extensions
"c-c++" "lsp-cquery"
'callees "$cquery/callers" '(:callee t))
(spacemacs/lsp-define-extensions
"c-c++" "lsp-cquery"
'base "$cquery/base")
(defun spacemacs/c++-organize-includes-on-save ()
"Add before-save hook for c++-organize-includes."
(add-hook 'before-save-hook
#'spacemacs//c++-organize-includes-on-save nil t))
;; key bindings
(dolist (mode c-c++-modes)
(spacemacs/set-leader-keys-for-major-mode mode
;; backend
"bf" 'cquery-freshen-index
"bp" 'cquery-preprocess-file
;; goto
"gf" 'find-file-at-point
"gF" 'ffap-other-window
;; hierarchy
"ghc" 'cquery-call-hierarchy
"ghC" 'spacemacs/c-c++-lsp-cquery-call-hierarchy-inv
"ghi" 'cquery-inheritance-hierarchy
"ghI" 'spacemacs/c-c++-lsp-cquery-inheritance-hierarchy-inv
;; members
"gmh" 'cquery-member-hierarchy)
;;Replace this with lsp-goto-implementation in lsp-layer?
(spacemacs/lsp-bind-extensions-for-mode
mode "c-c++" "lsp-cquery"
"&" 'refs-address
"R" 'refs-read
"W" 'refs-write
"c" 'callers
"C" 'callees
"v" 'vars
"hb" 'base))
;;(evil-set-initial-state 'ccls--tree-mode 'emacs)
;;evil-record-macro keybinding clobbers q in cquery-tree-mode-map for some reason?
;;(evil-make-overriding-map 'ccls-tree-mode-map)
(lsp))
(defun spacemacs//c-c++-setup-lsp-company ()
"Setup lsp auto-completion."
(spacemacs|add-company-backends
:backends company-lsp
:modes c-mode c++-mode
:append-hooks nil
:call-hooks t)
(company-mode))
(defun spacemacs//c-c++-setup-lsp-dap ()
"Setup DAP integration."
(require 'dap-gdb-lldb))
(defun spacemacs//c-c++-setup-lsp-flycheck ()
"Setup LSP syntax checking."
(when (or (spacemacs/enable-flycheck 'c-mode)
(spacemacs/enable-flycheck 'c++-mode))
(require 'lsp-ui-flycheck)
(lsp-ui-flycheck-enable nil)
(flycheck-mode)))
;; rtags
(defun spacemacs//c-c++-setup-rtags ()
"Setup rtags backend."
(setq rtags-autostart-diagnostics t)
(add-hook 'rtags-jump-hook 'evil-set-jump)
(rtags-diagnostics)
;; key bindings
(evil-define-key 'normal rtags-mode-map
(kbd "RET") 'rtags-select-other-window
(kbd "M-RET") 'rtags-select
(kbd "q") 'rtags-bury-or-delete)
;; TODO check for consistency with gtags key bindings
;; see https://github.com/syl20bnr/spacemacs/blob/develop/layers/+tags/gtags/funcs.el#L70
(dolist (mode c-c++-modes)
(spacemacs/set-leader-keys-for-major-mode mode
"g." 'spacemacs/c-c++-tags-find-symbol-at-point
"g," 'spacemacs/c-c++-tags-find-references-at-point
"g;" 'spacemacs/c-c++-tags-find-file
"g/" 'rtags-find-all-references-at-point
"g[" 'rtags-location-stack-back
"g]" 'rtags-location-stack-forward
"g>" 'spacemacs/c-c++-tags-find-symbol
"g<" 'spacemacs/c-c++-tags-find-references
"gB" 'rtags-show-rtags-buffer
"gd" 'rtags-print-dependencies
"gD" 'rtags-diagnostics
"ge" 'rtags-reparse-file
"gE" 'rtags-preprocess-file
"gF" 'rtags-fixit
"gG" 'rtags-guess-function-at-point
"gh" 'rtags-print-class-hierarchy
"gI" 'spacemacs/c-c++-tags-imenu
"gL" 'rtags-copy-and-print-current-location
"gM" 'rtags-symbol-info
"gO" 'rtags-goto-offset
"gp" 'rtags-set-current-project
"gR" 'rtags-rename-symbol
"gs" 'rtags-print-source-arguments
"gS" 'rtags-display-summary
"gT" 'rtags-taglist
"gv" 'rtags-find-virtuals-at-point
"gV" 'rtags-print-enum-value-at-point
"gX" 'rtags-fix-fixit-at-point
"gY" 'rtags-cycle-through-diagnostics)))
(defun spacemacs//c-c++-setup-rtags-company ()
"Setup rtags auto-completion."
(setq rtags-completions-enabled t)
(spacemacs|add-company-backends
:backends company-rtags
:modes c-mode-common
:append-hooks nil
:call-hooks t))
(defun spacemacs//c-c++-setup-rtags-flycheck ()
"Setup rtags syntax checking."
(when (or (spacemacs/enable-flycheck 'c-mode)
(spacemacs/enable-flycheck 'c++-mode))
(require 'flycheck-rtags)
(flycheck-mode)))
(defun spacemacs//c-c++-setup-rtags-semantic ()
"Setup semantic for rtags."
(semantic-mode)
(spacemacs//disable-semantic-idle-summary-mode))
(defun spacemacs/c-c++-use-rtags (&optional useFileManager)
"Return non-nil if rtags function should be used."
;; this function is used to fallback on gtags function if rtags is not
@ -204,192 +384,126 @@ is non-nil."
'rtags-imenu 'idomenu)))
;; lsp
;; -- BEGIN helper functions for common configuration of cquery and ccls backends
(defun spacemacs//c-c++-lsp-string (prefix suffix)
(concat prefix (symbol-name c-c++-lsp-server) suffix))
;; ycmd
(defun spacemacs//c-c++-lsp-symbol (prefix suffix)
"Return a symbol for the LSP server specified by the `c-c++-lsp-server' 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 (&rest parameters)
"Configure ccls or cquery (both take similarly named configuration parameters)."
(dolist (suffix parameters) (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-apply-clangd-config ()
"Configure clangd."
(when c-c++-lsp-executable (setq lsp-clients-clangd-executable c-c++-lsp-executable))
(when c-c++-lsp-args (setq lsp-clients-clangd-args c-c++-lsp-args)))
(defun spacemacs//c-c++-lsp-config ()
"Configure the LSP server specified by the `c-c++-lsp-server' configuration variable."
(progn
(message "Configuring c-c++ lsp backend")
(spacemacs//c-c++-lsp-define-extensions)
(if (eq c-c++-lsp-server 'clangd)
(spacemacs//c-c++-lsp-apply-clangd-config)
(spacemacs//c-c++-lsp-wrap-functions)
(spacemacs//c-c++-lsp-apply-config "executable" "initialization-options" "args" "project-whitelist" "project-blacklist" "sem-highlight-method"))
;; TODO Do we still want to disable c/c++-clang if using clangd as lsp-server?
(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++-lsp-server))))
(message (concat "c-c++: No c-c++-lsp-cache-dir specified: defaulting to " c-c++-lsp-cache-dir))))
(ecase c-c++-lsp-server
('clangd nil)
('cquery (setq cquery-cache-dir c-c++-lsp-cache-dir)
(setq cquery-extra-args c-c++-lsp-args)
(setq cquery-extra-init-params
(if c-c++-lsp-initialization-options
(append c-c++-lsp-initialization-options '(:cacheFormat "msgpack"))
'(:cacheFormat "msgpack"))))
('ccls (setq ccls-initialization-options
(if c-c++-lsp-initialization-options
(append c-c++-lsp-initialization-options `(:cache (:directory ,c-c++-lsp-cache-dir)))
`(:cache (:directory ,c-c++-lsp-cache-dir ))))))
(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'.")))
;; This doesn't work, as can't apply (apply ...) to a macro...
;; (unless (eq c-c++-lsp-server 'clangd)
;; (spacemacs//c-c++-lsp-call-function nil "-use-default-rainbow-sem-highlight"))
(ecase c-c++-lsp-server
('clangd nil)
('cquery (cquery-use-default-rainbow-sem-highlight))
('ccls (ccls-use-default-rainbow-sem-highlight))))
(dolist (mode c-c++-modes)
(spacemacs//c-c++-lsp-bind-keys-for-mode mode))
(unless (eq c-c++-lsp-server 'clangd)
(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"))))
;; DAP layer now declared as a dependency in layers.el
(require 'dap-gdb-lldb)))
(defun spacemacs//c-c++-lsp-wrap-functions ()
"Wrap navigation functions for the LSP server specified by the `c-c++-lsp-server' configuration variable.
This is only valid for 'ccls or 'cquery."
(defun c-c++/call-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-call-hierarchy"))
(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++-lsp-server
('clangd nil)
('cquery (cquery-freshen-index))
('ccls (ccls-reload)))))
(defun spacemacs//c-c++-lsp-bind-keys-for-mode (mode)
"Bind LSP backend functions for the specified mode."
(message "Binding keys for mode `%s'" mode)
;; Don't bind this -- redundant, and the current wrapper doesn't work -- not invoking correctly
;; (if (eq c-c++-lsp-server 'clangd)
;; (spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
;; "o" 'clangd-other-file)
(unless (eq c-c++-lsp-server 'clangd)
(defun spacemacs//c-c++-setup-ycmd ()
"Setup ycmd backend."
(add-to-list 'spacemacs-jump-handlers-c++-mode '(ycmd-goto :async t))
(add-to-list 'spacemacs-jump-handlers-c-mode '(ycmd-goto :async t))
(dolist (mode c-c++-modes)
(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)
"gG" 'ycmd-goto-imprecise))
(ycmd-mode))
;; goto/peek
(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 'ccls)
(spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
"hd" 'derived
"mt" 'member-types
"mf" 'member-functions
"mv" 'member-vars)))
(defun spacemacs//c-c++-setup-ycmd-company ()
"Setup ycmd auto-completion."
(spacemacs|add-company-backends
:backends company-ycmd
:modes c-mode-common
:append-hooks nil
:call-hooks t))
(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")
(defun spacemacs//c-c++-setup-ycmd-eldoc ()
"Setup ycmd eldoc integration."
(ycmd-eldoc-setup))
(unless (eq c-c++-lsp-server 'clangd)
(spacemacs/lsp-define-extensions "c-c++" 'vars (spacemacs//c-c++-lsp-string "$" "/vars"))))
(defun spacemacs//c-c++-setup-ycmd-flycheck ()
"Setup ycmd syntax checking."
(when (or (spacemacs/enable-flycheck 'c-mode)
(spacemacs/enable-flycheck 'c++-mode))
(flycheck-ycmd-setup)
(flycheck-mode)))
(defun spacemacs//c-c++-lsp-define-cquery-extensions ()
(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)))
(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++-setup-ycmd-semantic ()
"Setup semantic for ycmd."
(semantic-mode))
(defun spacemacs//c-c++-lsp-define-ccls-extensions ()
(spacemacs/lsp-define-extensions "c-c++" 'refs-address "textDocument/references" '(:role 128))
(spacemacs/lsp-define-extensions "c-c++" 'refs-read "textDocument/references" '(:role 8))
(spacemacs/lsp-define-extensions "c-c++" 'refs-write "textDocument/references" '(:role 16))
(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")
;;ccls features without a cquery analogue...
(spacemacs/lsp-define-extensions "c-c++" 'derived "$ccls/inheritance" '(:derived t))
(spacemacs/lsp-define-extensions "c-c++" 'member-types "$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)))
;; style
(defun spacemacs//c-c++-lsp-define-clangd-extensions ()
;;
;; None of these work...
;; (spacemacs/lsp-define-extensions "c-c++" 'clangd-other-file "textDocument/switchSourceHeader" `(:TextDocumentIdentifier ,buffer-file-name))
;; (spacemacs/lsp-define-extensions "c-c++" 'clangd-other-file "textDocument/switchSourceHeader" '(:TextDocumentIdentifier 'buffer-file-name))
(spacemacs/lsp-define-extensions "c-c++" 'clangd-other-file "textDocument/switchSourceHeader" 'buffer-file-name)
;; (spacemacs/lsp-define-extensions "c-c++" 'clangd-other-file "textDocument/switchSourceHeader")
)
(defun spacemacs//c-toggle-auto-newline ()
"Toggle auto-newline."
(c-toggle-auto-newline 1))
;; clang
(defun spacemacs//c-c++-setup-clang-format ()
"Setup clang format."
(when c-c++-enable-clang-format-on-save
(spacemacs/add-to-hooks 'spacemacs/clang-format-on-save c-c++-mode-hooks))
(dolist (mode c-c++-modes)
(spacemacs/declare-prefix-for-mode mode "m=" "format")
(spacemacs/set-leader-keys-for-major-mode mode
"==" 'spacemacs/clang-format-region-or-buffer
"=f" 'spacemacs/clang-format-function)))
(defun spacemacs/clang-format-function (&optional style)
"Format the current function with clang-format according to STYLE."
(interactive)
(save-excursion
(c-mark-function)
(clang-format (region-beginning) (region-end) style)
(deactivate-mark) ; If the function is already formatted, then remove the mark
(message "Formatted function %s" (c-defun-name))))
(defun spacemacs/clang-format-region-or-buffer (&optional style)
"Format the current region or buffer with clang-format according to STYLE."
(interactive)
(save-excursion
(if (region-active-p)
(progn
(clang-format-region (region-beginning) (region-end) style)
(message "Formatted region"))
(progn
(clang-format-buffer style)
(message "Formatted buffer %s" (buffer-name))))))
(defun spacemacs//clang-format-on-save ()
"Format the current buffer with clang-format on save when
`c-c++-enable-clang-format-on-save' is non-nil."
(when c-c++-enable-clang-format-on-save
(spacemacs/clang-format-region-or-buffer)))
(defun spacemacs/clang-format-on-save ()
"Add before-save hook for clang-format."
(add-hook 'before-save-hook 'spacemacs//clang-format-on-save nil t))
;; ccls
(defun spacemacs/c-c++-lsp-ccls-call-hierarchy-inv ()
(interactive)
(ccls-call-hierarchy t))
(defun spacemacs/c-c++-lsp-ccls-inheritance-hierarchy-inv ()
(interactive)
(ccls-inheritance-hierarchy t))
;; cquery
(defun spacemacs/c-c++-lsp-cquery-call-hierarchy-inv ()
(interactive)
(cquery-call-hierarchy t))
(defun spacemacs/c-c++-lsp-cquery-inheritance-hierarchy-inv ()
(interactive)
(cquery-inheritance-hierarchy t))
;; cpp-auto-include
(defalias 'spacemacs/c++-organize-includes 'cpp-auto-include)
(defun spacemacs//c++-organize-includes-on-save ()
"Organize the includes on save when `c++-enable-organize-includes-on-save'
is non-nil."
(when c++-enable-organize-includes-on-save
(spacemacs/c++-organize-includes)))
(defun spacemacs/c++-organize-includes-on-save ()
"Add before-save hook for c++-organize-includes."
(add-hook 'before-save-hook
#'spacemacs//c++-organize-includes-on-save nil t))
(defun spacemacs//c-c++-setup-lsp-dap ()
"Setup DAP integration."
(require 'dap-lldb))

View File

@ -9,6 +9,10 @@
;;
;;; License: GPLv3
(when (and (boundp 'c-c++-backend)
(eq c-c++-backend 'lsp))
(configuration-layer/declare-layer-dependencies '(lsp dap)))
(when (fboundp 'spacemacs//c-c++-backend)
(pcase (spacemacs//c-c++-backend)
(`lsp-clangd (configuration-layer/declare-layer-dependencies '(lsp dap)))
(`lsp-ccls (configuration-layer/declare-layer-dependencies '(lsp dap)))
(`lsp-cquery (configuration-layer/declare-layer-dependencies '(lsp dap)))
(`rtags (configuration-layer/declare-layer-dependencies '(ggtags)))
(`ycmd (configuration-layer/declare-layer-dependencies '(ycmd)))))

View File

@ -13,46 +13,49 @@
'(
cc-mode
clang-format
company
(company-c-headers :requires company)
(company-rtags :requires company rtags)
company-ycmd
counsel-gtags
(cpp-auto-include
:location (recipe :fetcher github
:repo "syohex/emacs-cpp-auto-include"))
dap-mode
disaster
eldoc
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)
lsp-mode ;;Owned/initialised by lsp-layer
org
projectile
realgud
rtags
semantic
srefactor
stickyfunc-enhance
xcscope
ycmd
;;lsp-backend
(cquery :requires lsp-mode)
;; lsp
(ccls :requires lsp-mode)
projectile
))
(cquery :requires lsp-mode)
dap-mode
;; rtags
(company-rtags :requires company rtags)
counsel-gtags
(flycheck-rtags :requires flycheck rtags)
ggtags
helm-gtags
(helm-rtags :requires helm rtags)
(ivy-rtags :requires ivy rtags)
rtags
;; ycmd
(company-ycmd :requires company)
(flycheck-ycmd :requires flycheck)
ycmd))
(defun c-c++/init-cc-mode ()
(use-package cc-mode
:defer t
:init
(progn
(add-hook 'c-mode-local-vars-hook #'spacemacs//c-c++-setup-backend)
(add-hook 'c++-mode-local-vars-hook #'spacemacs//c-c++-setup-backend)
(put 'c-c++-backend 'safe-local-variable 'symbolp)
(when c-c++-default-mode-for-headers
(add-to-list 'auto-mode-alist
`("\\.h\\'" . ,c-c++-default-mode-for-headers)))
@ -69,28 +72,17 @@
"ga" 'projectile-find-other-file
"gA" 'projectile-find-other-file-other-window)))))
(defun c-c++/init-ccls ()
(use-package ccls))
(defun c-c++/init-clang-format ()
(use-package clang-format
:if (or c-c++-enable-clang-support (eq c-c++-backend 'lsp))
:init
(progn
(when c-c++-enable-clang-format-on-save
(spacemacs/add-to-hooks 'spacemacs/clang-format-on-save c-c++-mode-hooks))
(dolist (mode c-c++-modes)
(spacemacs/declare-prefix-for-mode mode "m=" "format")
(spacemacs/set-leader-keys-for-major-mode mode
"==" 'spacemacs/clang-format-region-or-buffer
"=f" 'spacemacs/clang-format-function)))))
:init (spacemacs/add-to-hooks #'spacemacs//c-c++-setup-format
c-c++-mode-hooks)))
(defun c-c++/post-init-company ()
(when c-c++-enable-clang-support
(if (eq c-c++-backend 'lsp)
(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)
(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)
()))))
(add-hook 'c-mode-local-vars-hook #'spacemacs//c-c++-setup-company)
(add-hook 'c++-mode-local-vars-hook #'spacemacs//c-c++-setup-company))
(defun c-c++/init-company-c-headers ()
(use-package company-c-headers
@ -101,17 +93,12 @@
(defun c-c++/init-company-rtags ()
(use-package company-rtags
:if (and (eq c-c++-backend 'rtags) c-c++-enable-rtags-completion)
:defer t
:init
(progn
(setq rtags-completions-enabled t)
(spacemacs|add-company-backends
:backends company-rtags
:modes c-mode-common))))
:defer t))
(defun c-c++/post-init-company-ycmd ()
(spacemacs|add-company-backends :backends company-ycmd :modes c-mode-common))
(defun c-c++/init-company-ycmd ()
(use-package company-ycmd
:defer t
:commands company-ycmd))
(defun c-c++/post-init-counsel-gtags ()
(dolist (mode c-c++-modes)
@ -130,6 +117,15 @@
(spacemacs/set-leader-keys-for-major-mode 'c++-mode
"ri" #'spacemacs/c++-organize-includes))))
(defun c-c++/init-cquery ()
(use-package cquery))
(defun c-c++/pre-init-dap-mode ()
(add-to-list 'spacemacs--dap-supported-modes 'c-mode)
(add-to-list 'spacemacs--dap-supported-modes 'c++-mode)
(add-hook 'c-mode-local-vars-hook #'spacemacs//c-c++-setup-dap)
(add-hook 'c++-mode-local-vars-hook #'spacemacs//c-c++-setup-dap))
(defun c-c++/init-disaster ()
(use-package disaster
:defer t
@ -140,16 +136,21 @@
(spacemacs/set-leader-keys-for-major-mode mode
"D" 'disaster)))))
(defun c-c++/post-init-flycheck ()
(dolist (mode c-c++-modes)
(spacemacs/enable-flycheck mode))
(when c-c++-enable-clang-support
(spacemacs/add-to-hooks 'spacemacs/c-c++-load-clang-args c-c++-mode-hooks)))
(defun c-c++/post-init-eldoc ()
(add-hook 'c-mode-local-vars-hook #'spacemacs//c-c++-setup-eldoc)
(add-hook 'c++-mode-local-vars-hook #'spacemacs//c-c++-setup-eldoc))
(defun c-c++/post-init-flycheck ()
(add-hook 'c-mode-local-vars-hook #'spacemacs//c-c++-setup-flycheck)
(add-hook 'c++-mode-local-vars-hook #'spacemacs//c-c++-setup-flycheck))
;; TODO lazy load this package
(defun c-c++/init-flycheck-rtags ()
(use-package flycheck-rtags
:if (eq c-c++-backend 'rtags)))
:defer t))
(defun c-c++/init-flycheck-ycmd ()
(use-package flycheck-ycmd
:defer t))
(defun c-c++/post-init-ggtags ()
(add-hook 'c-mode-local-vars-hook #'spacemacs/ggtags-mode-enable)
@ -167,10 +168,13 @@
(defun c-c++/init-google-c-style ()
(use-package google-c-style
:if (or 'c-c++-enable-google-style 'c-c++-enable-google-newline)
:config (progn
(when c-c++-enable-google-style (add-hook 'c-mode-common-hook 'google-set-c-style))
(when c-c++-enable-google-newline (add-hook 'c-mode-common-hook 'google-make-newline-indent)))))
:defer t
:init
(progn
(when c-c++-enable-google-style
(add-hook 'c-mode-common-hook 'google-set-c-style))
(when c-c++-enable-google-newline
(add-hook 'c-mode-common-hook 'google-make-newline-indent)))))
(defun c-c++/pre-init-helm-cscope ()
(spacemacs|use-package-add-hook xcscope
@ -182,75 +186,45 @@
(dolist (mode c-c++-modes)
(spacemacs/helm-gtags-define-keys-for-mode mode)))
;; TODO lazy load this package
(defun c-c++/init-helm-rtags ()
(use-package helm-rtags
:if (eq c-c++-backend 'rtags)
:defer t
:init (setq rtags-display-result-backend 'helm)))
;; TODO lazy load this package
(defun c-c++/init-ivy-rtags ()
(use-package ivy-rtags
:if (eq c-c++-backend 'rtags)
:defer t
:init (setq rtags-display-result-backend 'ivy)))
;; TODO lazy load this package
(defun c-c++/init-rtags ()
(use-package rtags
:if (eq c-c++-backend 'rtags)
:init
(defun c-c++/pre-init-org ()
(spacemacs|use-package-add-hook org
:post-config (add-to-list 'org-babel-load-languages '(C . t))))
(defun c-c++/pre-init-projectile ()
(spacemacs|use-package-add-hook projectile
:post-config
(progn
(setq rtags-autostart-diagnostics t)
(add-hook 'rtags-jump-hook 'evil-set-jump)
(rtags-diagnostics)
;; key bindings
(evil-define-key 'normal rtags-mode-map
(kbd "RET") 'rtags-select-other-window
(kbd "M-RET") 'rtags-select
(kbd "q") 'rtags-bury-or-delete)
;; TODO check for consistency with gtags key bindings
;; see https://github.com/syl20bnr/spacemacs/blob/develop/layers/+tags/gtags/funcs.el#L70
(dolist (mode c-c++-modes)
(spacemacs/set-leader-keys-for-major-mode mode
"g." 'spacemacs/c-c++-tags-find-symbol-at-point
"g," 'spacemacs/c-c++-tags-find-references-at-point
"g;" 'spacemacs/c-c++-tags-find-file
"g/" 'rtags-find-all-references-at-point
"g[" 'rtags-location-stack-back
"g]" 'rtags-location-stack-forward
"g>" 'spacemacs/c-c++-tags-find-symbol
"g<" 'spacemacs/c-c++-tags-find-references
"gB" 'rtags-show-rtags-buffer
"gd" 'rtags-print-dependencies
"gD" 'rtags-diagnostics
"ge" 'rtags-reparse-file
"gE" 'rtags-preprocess-file
"gF" 'rtags-fixit
"gG" 'rtags-guess-function-at-point
"gh" 'rtags-print-class-hierarchy
"gI" 'spacemacs/c-c++-tags-imenu
"gL" 'rtags-copy-and-print-current-location
"gM" 'rtags-symbol-info
"gO" 'rtags-goto-offset
"gp" 'rtags-set-current-project
"gR" 'rtags-rename-symbol
"gs" 'rtags-print-source-arguments
"gS" 'rtags-display-summary
"gT" 'rtags-taglist
"gv" 'rtags-find-virtuals-at-point
"gV" 'rtags-print-enum-value-at-point
"gX" 'rtags-fix-fixit-at-point
"gY" 'rtags-cycle-through-diagnostics)))))
;; Ignore lsp cache dir, in case user has opted for cache within project source tree
(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))))))
(defun c-c++/init-rtags ()
;; config in `funcs.el'
(use-package rtags
:defer t))
(defun c-c++/post-init-realgud()
(dolist (mode c-c++-modes)
(spacemacs/add-realgud-debugger mode "gdb")))
(defun c-c++/post-init-semantic ()
(spacemacs/add-to-hooks 'semantic-mode c-c++-mode-hooks)
(when (or (configuration-layer/layer-used-p 'gtags)
(configuration-layer/layer-used-p 'lsp))
(spacemacs/add-to-hooks 'spacemacs//disable-semantic-idle-summary-mode c-c++-mode-hooks t)))
(add-hook 'c-mode-local-vars-hook #'spacemacs//c-c++-setup-semantic)
(add-hook 'c++-mode-local-vars-hook #'spacemacs//c-c++-setup-semantic))
(defun c-c++/post-init-srefactor ()
(dolist (mode c-c++-modes)
@ -260,60 +234,19 @@
(defun c-c++/post-init-stickyfunc-enhance ()
(spacemacs/add-to-hooks 'spacemacs/load-stickyfunc-enhance c-c++-mode-hooks))
(defun c-c++/post-init-ycmd ()
(spacemacs/add-to-hooks 'ycmd-mode c-c++-mode-hooks)
(add-to-list 'spacemacs-jump-handlers-c++-mode '(ycmd-goto :async t))
(add-to-list 'spacemacs-jump-handlers-c-mode '(ycmd-goto :async t))
(dolist (mode c-c++-modes)
(spacemacs/set-leader-keys-for-major-mode mode
"gG" 'ycmd-goto-imprecise)))
(defun c-c++/pre-init-org ()
(spacemacs|use-package-add-hook org
:post-config (add-to-list 'org-babel-load-languages '(C . t))))
(defun c-c++/pre-init-xcscope ()
(spacemacs|use-package-add-hook xcscope
:post-init
(dolist (mode c-c++-modes)
(spacemacs/set-leader-keys-for-major-mode mode "gi" 'cscope-index-files))))
;; BEGIN LSP BACKEND PACKAGES
(defun c-c++/post-init-lsp-mode ()
(when (eq c-c++-backend 'lsp)
(spacemacs//c-c++-lsp-config)
(unless (eq c-c++-lsp-server 'clangd)
(require c-c++-lsp-server) ; i.e. the 'ccls or 'cquery package
(remhash 'clangd lsp-clients))
(spacemacs/add-to-hooks 'lsp c-c++-mode-hooks)))
;; See also https://github.com/cquery-project/cquery/wiki/Emacs
(defun c-c++/init-cquery ()
(use-package cquery
:if (and (eq c-c++-backend 'lsp) (eq c-c++-lsp-server 'cquery))))
;; See also https://github.com/MaskRay/ccls/wiki/Emacs
(defun c-c++/init-ccls ()
(use-package ccls
:if (and (eq c-c++-backend 'lsp) (eq c-c++-lsp-server 'ccls))))
(defun c-c++/pre-init-projectile ()
(spacemacs|use-package-add-hook projectile
:post-config
(defun c-c++/init-ycmd ()
(use-package ycmd
:defer t
:init
(progn
(when c-c++-lsp-cache-dir
;; Ignore lsp cache dir, in case user has opted for cache within project source tree
(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
(defun c-c++/pre-init-dap-mode ()
(dolist (mode c-c++-modes)
(add-to-list 'spacemacs--dap-supported-modes mode)
(when (eq c-c++-backend 'lsp) (spacemacs/add-to-hooks 'spacemacs//c-c++-setup-lsp-dap c-c++-mode-hooks))))
(unless (boundp 'ycmd-global-config)
(setq-default ycmd-global-config
(concat (configuration-layer/get-layer-path 'ycmd)
"global_conf.py")))
(setq-default ycmd-parse-conditions '(save mode-enabled)))))

View File

@ -15,6 +15,18 @@
(add-to-list (intern (format "spacemacs-jump-handlers-%S" m))
'(lsp-ui-peek-find-definitions :async t))))
;; Key bindings
;; Used for lsp-ui-peek-mode, but may be able to use some spacemacs fn. instead?
(defun spacemacs/lsp-define-key (keymap key def &rest bindings)
"Define multiple key bindings with KEYMAP KEY DEF BINDINGS."
(interactive)
(while key
(define-key keymap (kbd key) def)
(setq key (pop bindings)
def (pop bindings))))
(defun spacemacs/lsp-bind-keys ()
"Define key bindings for the lsp minor mode."
(ecase lsp-navigation
@ -63,8 +75,7 @@
;; text/code
"xh" #'lsp-document-highlight
"xl" #'lsp-lens-show
"xL" #'lsp-lens-hide
))
"xL" #'lsp-lens-hide))
(defun spacemacs//lsp-bind-simple-navigation-functions (prefix-char)
(spacemacs/set-leader-keys-for-minor-mode 'lsp-mode
@ -78,8 +89,7 @@
(concat prefix-char "s") #'helm-lsp-workspace-symbol
(concat prefix-char "S") #'helm-lsp-global-workspace-symbol)
(spacemacs/set-leader-keys-for-minor-mode 'lsp-mode
(concat prefix-char "s") #'lsp-ui-find-workspace-symbol))
)
(concat prefix-char "s") #'lsp-ui-find-workspace-symbol)))
(defun spacemacs//lsp-bind-peek-navigation-functions (prefix-char)
(spacemacs/set-leader-keys-for-minor-mode 'lsp-mode
@ -95,7 +105,7 @@
(defun spacemacs//lsp-declare-prefixes-for-mode (mode)
"Define key binding prefixes for the specific MODE."
(unless (member mode lsp-layer--active-mode-list)
(push mode lsp-layer--active-mode-list)
(add-to-list 'lsp-layer--active-mode-list mode)
(spacemacs/declare-prefix-for-mode mode "m=" "format")
(spacemacs/declare-prefix-for-mode mode "ma" "code actions")
(spacemacs/declare-prefix-for-mode mode "mb" "backend")
@ -110,6 +120,130 @@
(spacemacs/declare-prefix-for-mode mode (concat prefix "h") "hierarchy")
(spacemacs/declare-prefix-for-mode mode (concat prefix "m") "members"))))
(defun spacemacs//lsp-bind-extensions-for-mode (mode
layer-name
backend-name
key
kind)
"Bind extensions under the appropriate prefix(es) for the major-mode MODE.
MODE should be a quoted symbol corresponding to a valid major mode.
LAYER-NAME is the name string of the layer
BACKEND-NAME is the name string of the back-end set for the layer
KEY is a string corresponding to a key sequence
KIND is a quoted symbol corresponding to an extension defined using
`lsp-define-extensions'."
(ecase lsp-navigation
('simple (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key)
(spacemacs//lsp-extension-name
layer-name backend-name "find" kind)))
('peek (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key)
(spacemacs//lsp-extension-name
layer-name backend-name "peek" kind)))
('both (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key)
(spacemacs//lsp-extension-name
layer-name backend-name "find" kind)
(concat "G" key)
(spacemacs//lsp-extension-name
layer-name backend-name "peek" kind)))))
(defun spacemacs/lsp-bind-extensions-for-mode (mode
layer-name
backend-name
key
kind
&rest bindings)
"Bind extensions under the appropriate prefix(es) for the major-mode MODE.
MODE is a quoted symbol corresponding to a valid major mode.
LAYER-NAME is the name string of the layer
BACKEND-NAME is the name string of the back-end set for the layer
KEY is a string corresponding to a key sequence
KIND is a quoted symbol corresponding to an extension defined using
`lsp-define-extensions'.
BINDINGS is other KEY and KIND to create other key bindings."
(while key
(spacemacs//lsp-bind-extensions-for-mode mode layer-name backend-name key kind)
(setq key (pop bindings)
kind (pop bindings))))
;; Extensions
(defun spacemacs/lsp-define-extensions (layer-name
backend-name
kind
request
&optional extra)
"Wrap backend-specific LSP extensions.
This function uses using `lsp-find-custom' and `lsp-ui-peek-find-custom'.
The function names are defined in `spacemacs//lsp-extension-name.'"
(dolist (nav-mode '("find" "peek"))
(if extra
(spacemacs//lsp-define-custom-extension
layer-name backend-name nav-mode kind request extra)
(spacemacs//lsp-define-custom-extension
layer-name backend-name nav-mode kind request))))
(defun spacemacs//lsp-extension-name (layer-name backend-name nav-mode kind)
"Return the extension name.
Pattern is `spacemacs/<layer-name>-<backend-end>-<nav-mode>-<kind>'.
Examples of return name:
- spacemacs/c-c++-lsp-clangd-find-clangd-other-file
- spacemacs/c-c++-lsp-clangd-peek-clangd-other-file
LAYER-NAME is the name string of the layer
BACKEND-NAME is the name string of the back-end set for the layer
NAV-MODE is a string with value `peek' or `find'
KIND is a quoted symbol corresponding to an extension defined using
`lsp-define-extensions'."
(intern
(concat "spacemacs/"
layer-name "-" backend-name "-" nav-mode "-" (symbol-name kind))))
(defun spacemacs//lsp-define-custom-extension (layer-name
backend-name
nav-mode
kind
request
&optional extra)
"Helper function to define custom LSP extensions.
LAYER-NAME is the name string of the layer
BACKEND-NAME is the name string of the back-end set for the layer
NAV-MODE is a string with value `peek' or `find'
KIND is a quoted symbol corresponding to an extension defined using
`lsp-define-extensions'.
REQUEST is a string defining the request
EXTRA is an additional parameter pass to LSP function"
(let ((lsp-extension-fn (if (equal nav-mode "find")
'lsp-find-locations
'lsp-ui-peek-find-custom))
(extension-name (spacemacs//lsp-extension-name
layer-name backend-name nav-mode kind))
(extension-descriptor (format (concat nav-mode " %s")
(symbol-name kind))))
(if extra
(defalias extension-name
`(lambda ()
,extension-descriptor
(interactive)
(funcall ',lsp-extension-fn ,request ',extra)))
(defalias extension-name
`(lambda ()
,extension-descriptor
(interactive)
(funcall ',lsp-extension-fn ,request))))))
;; Utils
(defun spacemacs/lsp-ui-doc-func ()
"Toggle the function signature in the lsp-ui-doc overlay"
(interactive)
@ -124,72 +258,16 @@
(defun spacemacs/lsp-ui-sideline-ignore-duplicate ()
"Toggle ignore duplicates for lsp-ui-sideline overlay"
(interactive)
(setq lsp-ui-sideline-ignore-duplicate (not lsp-ui-sideline-ignore-duplicate)))
;; Used for lsp-ui-peek-mode, but may be able to use some spacemacs fn. instead?
(defun spacemacs/lsp-define-key (keymap key def &rest bindings)
"Define multiple key bindings with KEYMAP KEY DEF BINDINGS."
(interactive)
(while key
(define-key keymap (kbd key) def)
(setq key (pop bindings)
def (pop bindings))))
;; These functions facilitate extension of the navigation-mode keybindings in derived layers
;; See c/c++ layer for a usage example
(defun spacemacs//lsp-get-extension-name (layer-name nav-mode kind)
(intern (concat layer-name "/" nav-mode "-" (symbol-name kind))))
(defun spacemacs//lsp-define-custom-extension (layer-name nav-mode kind request &optional extra)
(let ((lsp-extension-fn (if (equal nav-mode "find")
'lsp-find-locations
'lsp-ui-peek-find-custom))
(extension-name (spacemacs//lsp-get-extension-name layer-name nav-mode kind))
(extension-descriptor (format (concat nav-mode " %s") (symbol-name kind))))
(if extra
(defalias extension-name `(lambda () ,extension-descriptor (interactive) (funcall ',lsp-extension-fn ,request ',extra)))
(defalias extension-name `(lambda () ,extension-descriptor (interactive) (funcall ',lsp-extension-fn ,request))))))
(defun spacemacs/lsp-define-extensions (layer-name kind request &optional extra)
"Wrap backend-specific LSP extensions using lsp-find-custom and lsp-ui-peek-find-custom.
The function names will be <layer-name>/find-<kind> and <layer-name>/peek-<kind>, respectively."
(dolist (nav-mode '("find" "peek"))
(if extra
(spacemacs//lsp-define-custom-extension layer-name nav-mode kind request extra)
(spacemacs//lsp-define-custom-extension layer-name nav-mode kind request))))
(defun spacemacs//lsp-bind-extensions (mode layer-name key kind)
(ecase lsp-navigation
('simple (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key) (spacemacs//lsp-get-extension-name layer-name "find" kind)))
('peek (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key) (spacemacs//lsp-get-extension-name layer-name "peek" kind)))
('both (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key) (spacemacs//lsp-get-extension-name layer-name "find" kind)
(concat "G" key) (spacemacs//lsp-get-extension-name layer-name "peek" kind)))))
(defun spacemacs/lsp-bind-extensions-for-mode (mode layer-name key kind &rest bindings)
"Bind find/peek extensions under the appropriate prefix(es) for the major-mode
MODE. MODE should be a quoted symbol corresponding to a valid major mode.
LAYER-NAME and KEY should be quoted strings. KIND should be quoted symbol corresponding to
a find extension defined using `lsp-define-extensions'"
(while key
(spacemacs//lsp-bind-extensions mode layer-name key kind)
(setq key (pop bindings) kind (pop bindings))))
(defun spacemacs/lsp-avy-goto-word ()
(interactive)
(spacemacs//lsp-avy-document-symbol t))
(defun spacemacs/lsp-avy-goto-symbol ()
(interactive)
(spacemacs//lsp-avy-document-symbol nil))
(setq lsp-ui-sideline-ignore-duplicate
(not lsp-ui-sideline-ignore-duplicate)))
(defun spacemacs//lsp-action-placeholder ()
(interactive)
(message "Watch this space... (to be implemented in 'lsp-mode)"))
(message "Not supported yet... (to be implemented in 'lsp-mode')"))
;; ivy integration
;; From https://github.com/MaskRay/Config/blob/master/home/.config/doom/autoload/misc.el#L118
(defun spacemacs//lsp-avy-document-symbol (all)
(interactive)
(let ((line 0) (col 0) (w (selected-window))
@ -201,12 +279,15 @@ a find extension defined using `lsp-define-extensions'"
(save-excursion
(goto-char 1)
(cl-loop for loc in
(lsp--send-request (lsp--make-request
"textDocument/documentSymbol"
`(:textDocument ,(lsp--text-document-identifier)
:all ,(if all t :json-false)
:startLine ,start-line :endLine ,end-line)))
for range = (if ccls loc (->> loc (gethash "location") (gethash "range")))
(lsp--send-request
(lsp--make-request
"textDocument/documentSymbol"
`(:textDocument ,(lsp--text-document-identifier)
:all ,(if all t :json-false)
:startLine ,start-line :endLine ,end-line)))
for range = (if ccls
loc
(->> loc (gethash "location") (gethash "range")))
for range_start = (gethash "start" range)
for range_end = (gethash "end" range)
for l0 = (gethash "line" range_start)
@ -224,7 +305,14 @@ a find extension defined using `lsp-define-extensions'"
(setq point1 (point))
(setq line l1 col c1)
(push `((,point0 . ,point1) . ,w) candidates)))
;; (require 'avy)
(avy-with avy-document-symbol
(avy--process candidates
(avy--style-fn avy-style)))))
(defun spacemacs/lsp-avy-goto-word ()
(interactive)
(spacemacs//lsp-avy-document-symbol t))
(defun spacemacs/lsp-avy-goto-symbol ()
(interactive)
(spacemacs//lsp-avy-document-symbol nil))