diff --git a/CHANGELOG.develop b/CHANGELOG.develop index 1d168c82f..d687b5c8e 100644 --- a/CHANGELOG.develop +++ b/CHANGELOG.develop @@ -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 diff --git a/layers/+lang/c-c++/README.org b/layers/+lang/c-c++/README.org index 3deaedf59..c9e3b2cd4 100644 --- a/layers/+lang/c-c++/README.org +++ b/layers/+lang/c-c++/README.org @@ -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 | diff --git a/layers/+lang/c-c++/config.el b/layers/+lang/c-c++/config.el index 43cfd4d1b..8a9c87083 100644 --- a/layers/+lang/c-c++/config.el +++ b/layers/+lang/c-c++/config.el @@ -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.") diff --git a/layers/+lang/c-c++/funcs.el b/layers/+lang/c-c++/funcs.el index da9843b7a..c9b176cb8 100644 --- a/layers/+lang/c-c++/funcs.el +++ b/layers/+lang/c-c++/funcs.el @@ -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)) diff --git a/layers/+lang/c-c++/layers.el b/layers/+lang/c-c++/layers.el index d8ab3876f..e07faf5e5 100644 --- a/layers/+lang/c-c++/layers.el +++ b/layers/+lang/c-c++/layers.el @@ -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))))) diff --git a/layers/+lang/c-c++/packages.el b/layers/+lang/c-c++/packages.el index bf89cf3ce..4b64ef516 100644 --- a/layers/+lang/c-c++/packages.el +++ b/layers/+lang/c-c++/packages.el @@ -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))))) diff --git a/layers/+tools/lsp/funcs.el b/layers/+tools/lsp/funcs.el index 2ae6fa80f..361f4cd60 100644 --- a/layers/+tools/lsp/funcs.el +++ b/layers/+tools/lsp/funcs.el @@ -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/---'. + +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 /find- and /peek-, 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))