Added cquery and ccls backend support to c-c++ layer
<<Amendment 1 01/09/2018>> Incorporated initial feedback from multiple sources (PR discussion) <<Amendment 2 04/09/2018>> Incorporated feedback from MaskRay. Fixed projectile post-config hooks. Added `c-c++-adopt-subprojects' layer option. <<Amendment 3 07/09/18>> Corrected cache section in README to describe new cache defaults introduced by Amendment 2. <<Amendment 4 13/09/18>> Corrected config var names in readme. Rebased on current develop branch tip. <<Amendment 5 14/09/18>> Minor adaptations for compatibility with upstream ccls changes. <<Amendment 6 21/09/18>> Bindings updated for consistency with lsp layer lsp-navigation config variable. <<Amendment 7 1/11/18>> Rebased <<Amendment 8 06/11/18>> Incorporated readme correction from svenihoney. <<Amendment 9 06/11/18>> Updated c-c++/refresh-index wrapper for ccls function renamed upstream. Moved 2 bindings from 'l' to 'b' to reflect updated lsp-layer mnemonic
This commit is contained in:
parent
141b6328e3
commit
445f6af93f
|
@ -8,15 +8,28 @@
|
||||||
- [[#install][Install]]
|
- [[#install][Install]]
|
||||||
- [[#layer][Layer]]
|
- [[#layer][Layer]]
|
||||||
- [[#default-mode-for-header-files][Default mode for header files]]
|
- [[#default-mode-for-header-files][Default mode for header files]]
|
||||||
|
- [[#backends][Backends]]
|
||||||
|
- [[#rtags][RTags]]
|
||||||
|
- [[#external-dependencies][External dependencies]]
|
||||||
|
- [[#configuration][Configuration]]
|
||||||
|
- [[#cquery--ccls-lsp-backends][cquery / ccls (lsp backends)]]
|
||||||
|
- [[#features-1][Features:]]
|
||||||
|
- [[#external-dependencies-1][External dependencies]]
|
||||||
|
- [[#configuration-1][Configuration]]
|
||||||
|
- [[#completion][Completion]]
|
||||||
- [[#clang-configuration][Clang Configuration]]
|
- [[#clang-configuration][Clang Configuration]]
|
||||||
- [[#clang-format][clang-format]]
|
- [[#clang-format][clang-format]]
|
||||||
- [[#company-clang-and-flycheck][Company-clang and flycheck]]
|
- [[#company-clang-and-flycheck][Company-clang and flycheck]]
|
||||||
- [[#rtags-configuration][RTags configuration]]
|
|
||||||
- [[#enable-google-set-c-style][Enable google-set-c-style]]
|
- [[#enable-google-set-c-style][Enable google-set-c-style]]
|
||||||
- [[#newlines][Newlines]]
|
- [[#newlines][Newlines]]
|
||||||
|
- [[#projectile-sub-project-adoption][Projectile sub-project adoption]]
|
||||||
- [[#key-bindings][Key Bindings]]
|
- [[#key-bindings][Key Bindings]]
|
||||||
- [[#formatting-clang-format][Formatting (clang-format)]]
|
- [[#formatting-clang-format][Formatting (clang-format)]]
|
||||||
- [[#rtags][RTags]]
|
- [[#rtags-1][RTags]]
|
||||||
|
- [[#cquery--ccls][cquery / ccls]]
|
||||||
|
- [[#goto][goto]]
|
||||||
|
- [[#helphierarchy][help/hierarchy]]
|
||||||
|
- [[#backend-language-server][backend (language server)]]
|
||||||
|
|
||||||
* Description
|
* Description
|
||||||
This layer adds configuration for C/C++ language.
|
This layer adds configuration for C/C++ language.
|
||||||
|
@ -37,6 +50,7 @@ This layer adds configuration for C/C++ language.
|
||||||
company-ycmd (when =ycmd= layer is included).
|
company-ycmd (when =ycmd= layer is included).
|
||||||
- Support for [[https://github.com/realgud/realgud][realgud]] debugger.
|
- Support for [[https://github.com/realgud/realgud][realgud]] debugger.
|
||||||
- Support for [[https://github.com/Andersbakken/rtags][rtags]].
|
- Support for [[https://github.com/Andersbakken/rtags][rtags]].
|
||||||
|
- Support for [[https://github.com/cquery-project/cquery][cquery]] or [[https://github.com/MaskRay/ccls][ccls]] as an lsp backend.
|
||||||
|
|
||||||
* Install
|
* Install
|
||||||
** Layer
|
** Layer
|
||||||
|
@ -59,6 +73,116 @@ by setting the variable =c-c++-default-mode-for-headers= to =c++-mode=.
|
||||||
variable at the root of your project. More info on directory local variables
|
variable at the root of your project. More info on directory local variables
|
||||||
can be found in the [[http://www.gnu.org/software/emacs/manual/html_node/elisp/Directory-Local-Variables.html][dir-locals]].
|
can be found in the [[http://www.gnu.org/software/emacs/manual/html_node/elisp/Directory-Local-Variables.html][dir-locals]].
|
||||||
|
|
||||||
|
** Backends
|
||||||
|
This layer supports the selection of one of 3 available backends for code navigation etc via the =c-c++-backend= configuration variable.
|
||||||
|
|
||||||
|
*** RTags
|
||||||
|
RTags is a well established clang-based source code indexing tool.
|
||||||
|
|
||||||
|
**** External dependencies
|
||||||
|
Install the RTags server via [[https://formulae.brew.sh/formula/rtags][homebrew]], the [[https://aur.archlinux.org/packages/rtags/][aur]] or from source according to the instructions [[https://github.com/Andersbakken/rtags][here]].
|
||||||
|
N.B. RTags is not supported on Windows at the time of writing, although there is an [[https://github.com/Andersbakken/rtags/issues/770][open issue with some recent activity]] on github.
|
||||||
|
|
||||||
|
**** Configuration
|
||||||
|
To enable support for =rtags=, set the layer variable
|
||||||
|
=c-c++-enable-rtags-support= to =t= in your dotfile.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq-default dotspacemacs-configuration-layers
|
||||||
|
'((c-c++ :variables c-c++-backend 'rtags)))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
This will also enable =company-rtags= to be used as a backend for
|
||||||
|
auto-completion (when =auto-completion= layer is included).
|
||||||
|
To prevent this, while retaining the rest of Rtags functionality,
|
||||||
|
set the variable =c-c++-rtags-completion= to =nil=:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq-default dotspacemacs-configuration-layers
|
||||||
|
'((c-c++ :variables
|
||||||
|
c-c++-backend 'rtags
|
||||||
|
c-c++-enable-rtags-completion nil)))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
*** cquery / ccls (lsp backends)
|
||||||
|
[[https://github.com/cquery-project/cquery][cquery]] and [[https://github.com/MaskRay/ccls][ccls]] are alternative implementations of the language server protocol based on libclang. They claim to be more efficient
|
||||||
|
than existing tools at indexing large code bases.
|
||||||
|
|
||||||
|
**** Features:
|
||||||
|
- Cross references (definitions, references, base/derived classes/methods, type instances, ...)
|
||||||
|
- Diagnostics
|
||||||
|
- Completion with =company-lsp=
|
||||||
|
- Semantic highlighting
|
||||||
|
- See more on [[https://github.com/cquery-project/cquery/wiki/Emacs]]
|
||||||
|
- Cross-platform - functional on Windows, Linux and OSX.
|
||||||
|
|
||||||
|
**** External dependencies
|
||||||
|
Install one (or both) of the following:
|
||||||
|
|
||||||
|
***** cquery server
|
||||||
|
Install the =cquery= server. [[https://github.com/cquery-project/cquery/wiki/Getting-started][Instructions]].
|
||||||
|
|
||||||
|
***** ccls server
|
||||||
|
Install the =ccls= server. [[https://github.com/MaskRay/ccls/wiki/Getting-started][Instructions]].
|
||||||
|
|
||||||
|
**** Configuration
|
||||||
|
***** Basic
|
||||||
|
Select either =cquery= or =ccls= as the =c-c++= layer backend by adding the following to your dotfile:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq-default dotspacemacs-configuration-layers
|
||||||
|
'((c-c++ :variables c-c++-backend 'lsp-cquery))) ;or 'lsp-ccls
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
N.B. The [[../../+tools/lsp/README.org][LSP layer]] will be loaded automatically if either backend is selected.
|
||||||
|
|
||||||
|
***** Setting path to backend executable
|
||||||
|
The basic configuration above should work if the cquery/ccls executable folder is present in your path. If not, you can set the path explicitly.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq-default dotspacemacs-configuration-layers
|
||||||
|
'((c-c++ :variables
|
||||||
|
c-c++-backend 'lsp-cquery
|
||||||
|
c-c++-lsp-executable "/path/to/bin/cquery/or/ccls")))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
If you need to expand =~= in the path, you can use =file-truename= like
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq-default dotspacemacs-configuration-layers
|
||||||
|
'((c-c++ :variables
|
||||||
|
c-c++-backend 'lsp-cquery
|
||||||
|
c-c++-lsp-executable (file-truename "~/bin/cquery/or/ccls"))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
***** Semantic highlighting
|
||||||
|
Semantic highlighting is disabled by default. To enable, set the =c-c++-lsp-sem-highlight-method= variable to either ='font-lock= or ='overlay=.
|
||||||
|
To enable the rainbow semantic highlighting colour theme, set =c-c++-lsp-sem-highlight-rainbow= to =t=.
|
||||||
|
|
||||||
|
***** Additional configuration options
|
||||||
|
Both lsp backends are configured to store their index cache in a subdirectory of =.emacs.d/cache=. This can be overridden by
|
||||||
|
specifying an explicit =c-c++-lsp-cache-dir=. Setting this value to a relative path will cause the index cache to be placed in a
|
||||||
|
subdirectory of your project root.
|
||||||
|
|
||||||
|
There are other initialization options such as the number of indexer threads, cache serialization format.
|
||||||
|
They have good default values. See [[file:./config.el][config.el]] and the backends' respective homepages for more info.
|
||||||
|
- [[https://github.com/cquery-project/cquery/wiki/Emacs][Emacs section of =cquery= wiki]]
|
||||||
|
- [[https://github.com/MaskRay/ccls/wiki/Emacs][Emacs section of =ccls= wiki]]
|
||||||
|
|
||||||
|
***** Example dotspacemacs-configuration-layers entry
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq-default dotspacemacs-configuration-layers
|
||||||
|
'((c-c++ :variables
|
||||||
|
c-c++-adopt-subprojects t
|
||||||
|
c-c++-backend 'lsp-ccls
|
||||||
|
c-c++-lsp-executable (file-truename "~/dev/cpp/ccls/Release/ccls")
|
||||||
|
c-c++-lsp-sem-highlight-rainbow t)))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
**** Completion
|
||||||
|
=company-lsp= provides completion functionality. Client-side cache and sorting have been disabled in favour of server,
|
||||||
|
as recommended by =cquery=/=ccls= wikis.
|
||||||
|
|
||||||
** Clang Configuration
|
** Clang Configuration
|
||||||
To enable Clang support, set the layer variable =c-c++-enable-clang-support=
|
To enable Clang support, set the layer variable =c-c++-enable-clang-support=
|
||||||
to =t= in the dotfile:
|
to =t= in the dotfile:
|
||||||
|
@ -68,6 +192,8 @@ to =t= in the dotfile:
|
||||||
'((c-c++ :variables c-c++-enable-clang-support t)))
|
'((c-c++ :variables c-c++-enable-clang-support t)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
N.B. do not set this option if either the =cquery= or =ccls= backend
|
||||||
|
|
||||||
*** clang-format
|
*** clang-format
|
||||||
[[http://clang.llvm.org/docs/ClangFormat.html][clang-format]] allows reformatting either a selected region of code
|
[[http://clang.llvm.org/docs/ClangFormat.html][clang-format]] allows reformatting either a selected region of code
|
||||||
(=clang-format-region=) or a whole buffer (=clang-format-buffer=)
|
(=clang-format-region=) or a whole buffer (=clang-format-buffer=)
|
||||||
|
@ -80,8 +206,8 @@ To enable automatic buffer formatting on save, set the variable
|
||||||
=c-c++-enable-clang-format-on-save= to =t=:
|
=c-c++-enable-clang-format-on-save= to =t=:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(setq-default dotspacemacs-configuration-layers '(
|
(setq-default dotspacemacs-configuration-layers
|
||||||
(c-c++ :variables c-c++-enable-clang-format-on-save t)))
|
'((c-c++ :variables c-c++-enable-clang-format-on-save t)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
*** Company-clang and flycheck
|
*** Company-clang and flycheck
|
||||||
|
@ -93,25 +219,6 @@ Not only does this allow proper autocomplete on projects with extra includes and
|
||||||
flags, but there is also support for flycheck so that it doesn’t complain about
|
flags, but there is also support for flycheck so that it doesn’t complain about
|
||||||
missing header files.
|
missing header files.
|
||||||
|
|
||||||
** RTags configuration
|
|
||||||
To enable support for =rtags=, set the layer variable
|
|
||||||
=c-c++-enable-rtags-support= to =t= in your dotfile.
|
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(setq-default dotspacemacs-configuration-layers
|
|
||||||
'((c-c++ :variables c-c++-enable-rtags-support t)))
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
This will also enable =company-rtags= to be used as a backend for
|
|
||||||
auto-completion (when =auto-completion= layer is included).
|
|
||||||
To prevent this, while retaining the rest of Rtags functionality,
|
|
||||||
set the variable =c-c++-enable-rtags-support= to ='no-completion=:
|
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(setq-default dotspacemacs-configuration-layers
|
|
||||||
'((c-c++ :variables c-c++-enable-rtags-support 'no-completion)))
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Enable google-set-c-style
|
** Enable google-set-c-style
|
||||||
If you have clang enabled with =clang-format= as described earlier in this page
|
If you have clang enabled with =clang-format= as described earlier in this page
|
||||||
you may not have a lot of neeed for =google-set-c-style= if you are already
|
you may not have a lot of neeed for =google-set-c-style= if you are already
|
||||||
|
@ -140,7 +247,6 @@ set that up like this:
|
||||||
(c-c++ :variables
|
(c-c++ :variables
|
||||||
c-c++-enable-google-style t
|
c-c++-enable-google-style t
|
||||||
c-c++-enable-google-newline t)
|
c-c++-enable-google-newline t)
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Newlines
|
** Newlines
|
||||||
You can enable the =Auto-newline= minor mode that automatically adds newlines
|
You can enable the =Auto-newline= minor mode that automatically adds newlines
|
||||||
|
@ -151,6 +257,18 @@ after certain characters by setting the =c-c++-enable-auto-newline= variable.
|
||||||
c-c++-enable-auto-newline t)
|
c-c++-enable-auto-newline t)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
** Projectile sub-project adoption
|
||||||
|
To prevent projectile from using subproject root when visiting files in a subproject,
|
||||||
|
set =c-c++-adopt-subprojects= to =t=.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(c-c++ :variables
|
||||||
|
c-c++-adopt-subprojects t)
|
||||||
|
#+END_SRC emacs-lisp
|
||||||
|
|
||||||
|
This is based on a recommendation on the =cquery= and =ccls= wikis, but should be more
|
||||||
|
generally applicable.
|
||||||
|
|
||||||
* Key Bindings
|
* Key Bindings
|
||||||
|
|
||||||
| Key Binding | Description |
|
| Key Binding | Description |
|
||||||
|
@ -160,7 +278,7 @@ after certain characters by setting the =c-c++-enable-auto-newline= variable.
|
||||||
| ~SPC m g A~ | open matching file in another window |
|
| ~SPC m g A~ | open matching file in another window |
|
||||||
| | (e.g. switch between .cpp and .h, requires a project to work) |
|
| | (e.g. switch between .cpp and .h, requires a project to work) |
|
||||||
| ~SPC m D~ | disaster: disassemble c/c++ code |
|
| ~SPC m D~ | disaster: disassemble c/c++ code |
|
||||||
| ~SPC m r~ | srefactor: refactor thing at point. |
|
| ~SPC m r .~ | srefactor: refactor thing at point. |
|
||||||
|
|
||||||
*Note:* [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]] is only available for Emacs 24.4+.
|
*Note:* [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]] is only available for Emacs 24.4+.
|
||||||
|
|
||||||
|
@ -204,3 +322,37 @@ after certain characters by setting the =c-c++-enable-auto-newline= variable.
|
||||||
| ~SPC m g V~ | print enum value at point |
|
| ~SPC m g V~ | print enum value at point |
|
||||||
| ~SPC m g X~ | fix fixit at point |
|
| ~SPC m g X~ | fix fixit at point |
|
||||||
| ~SPC m g Y~ | cycle overlays on screen |
|
| ~SPC m g Y~ | cycle overlays on screen |
|
||||||
|
|
||||||
|
** cquery / ccls
|
||||||
|
The keybindings listed below are in addition to the default keybindings defined by the [[file:../../+tools/lsp/README.org][LSP layer]].
|
||||||
|
|
||||||
|
*** goto
|
||||||
|
|
||||||
|
| Key Binding | Description |
|
||||||
|
|-------------+---------------------------|
|
||||||
|
| ~SPC m g &~ | find references (address) |
|
||||||
|
| ~SPC m g R~ | find references (read) |
|
||||||
|
| ~SPC m g W~ | find references (write) |
|
||||||
|
| ~SPC m g c~ | find callers |
|
||||||
|
| ~SPC m g C~ | find callees |
|
||||||
|
| ~SPC m g v~ | vars |
|
||||||
|
|
||||||
|
*** help/hierarchy
|
||||||
|
|
||||||
|
| Key Binding | Description |
|
||||||
|
|-------------+-----------------------------|
|
||||||
|
| ~SPC m h b~ | base class(es) |
|
||||||
|
| ~SPC m h d~ | derived class(es) |
|
||||||
|
| ~SPC m h c~ | call hierarchy |
|
||||||
|
| ~SPC m h C~ | call hierarchy (inv) |
|
||||||
|
| ~SPC m h i~ | inheritance hierarchy |
|
||||||
|
| ~SPC m h I~ | inheritance hierarchy (inv) |
|
||||||
|
| ~SPC m h m~ | member hierarchy |
|
||||||
|
| ~SPC m h M~ | member hierarchy (inv) |
|
||||||
|
|
||||||
|
*** backend (language server)
|
||||||
|
|
||||||
|
| Key Binding | Description |
|
||||||
|
|-------------+------------------------------------------|
|
||||||
|
| ~SPC m b f~ | refresh index (e.g. after branch change) |
|
||||||
|
| ~SPC m b p~ | preprocess file |
|
||||||
|
|
|
@ -17,6 +17,13 @@
|
||||||
(defconst c-c++-mode-hooks '(c-mode-hook c++-mode-hook)
|
(defconst c-c++-mode-hooks '(c-mode-hook c++-mode-hook)
|
||||||
"Primary hooks of the `c-c++' layer.")
|
"Primary hooks of the `c-c++' layer.")
|
||||||
|
|
||||||
|
(defconst c-c++-lsp-backends '(lsp-cquery lsp-ccls)
|
||||||
|
"Language Server Protocol (LSP) backends supported by the `c-c++' layer.")
|
||||||
|
|
||||||
|
(defvar c-c++-backend nil
|
||||||
|
"If `lsp-cquery' or `lsp-ccls' then selects language server protocol backend (cquery or ccls).
|
||||||
|
If `rtags' then enables rtags support")
|
||||||
|
|
||||||
(defvar c-c++-enable-auto-newline nil
|
(defvar c-c++-enable-auto-newline nil
|
||||||
"If non nil then enables the `Auto-newline' minor mode.")
|
"If non nil then enables the `Auto-newline' minor mode.")
|
||||||
|
|
||||||
|
@ -31,9 +38,8 @@
|
||||||
"If non-nil `google-make-newline-indent' will be added as as
|
"If non-nil `google-make-newline-indent' will be added as as
|
||||||
`c-mode-common-hook'.")
|
`c-mode-common-hook'.")
|
||||||
|
|
||||||
(defvar c-c++-enable-rtags-support nil
|
(defvar c-c++-enable-rtags-completion t
|
||||||
"If non nil Rtags related packages and configuration are enabled.
|
"If `nil', RTags completion is disabled when the RTags backend is enabled.")
|
||||||
If `no-completion', enable all but completion.")
|
|
||||||
|
|
||||||
(defvar c-c++-enable-clang-format-on-save nil
|
(defvar c-c++-enable-clang-format-on-save nil
|
||||||
"If non-nil, automatically format code with ClangFormat on
|
"If non-nil, automatically format code with ClangFormat on
|
||||||
|
@ -44,3 +50,36 @@
|
||||||
|
|
||||||
(defvar c-c++-default-mode-for-headers 'c-mode
|
(defvar c-c++-default-mode-for-headers 'c-mode
|
||||||
"Default mode to open header files. Can be `c-mode' or `c++-mode'.")
|
"Default mode to open header files. Can be `c-mode' or `c++-mode'.")
|
||||||
|
|
||||||
|
(defvar c-c++-adopt-subprojects nil
|
||||||
|
"When non-nil, projectile will remember project root when visiting files in subprojects")
|
||||||
|
|
||||||
|
;; c-c++-lsp-backend variables
|
||||||
|
(defvar c-c++-lsp-cache-dir nil
|
||||||
|
"Cache directory. Absolute and relative paths supported.")
|
||||||
|
|
||||||
|
(defvar c-c++-lsp-executable nil
|
||||||
|
"Path to cquery/ccls executable (default value assumes it's in the path)")
|
||||||
|
|
||||||
|
(defvar c-c++-lsp-project-whitelist nil
|
||||||
|
"A list of project directory patterns for which lsp-c-c++ should be
|
||||||
|
initialized. This overrides `c-c++-lsp-project-blacklist'.")
|
||||||
|
|
||||||
|
(defvar c-c++-lsp-project-blacklist nil
|
||||||
|
"A list of project root patterns for which lsp-c-c++ shouldn't be
|
||||||
|
initialized. `c-c++-lsp-project-whitelist' is checked first, then this,
|
||||||
|
if no pattern matches the project root, lsp-c-c++ will be initialized.")
|
||||||
|
|
||||||
|
(defvar c-c++-lsp-sem-highlight-method nil
|
||||||
|
"Set to 'font-lock or 'overlay to enable semantic highlighting")
|
||||||
|
|
||||||
|
(defvar c-c++-lsp-sem-highlight-rainbow nil
|
||||||
|
"When non-nil, use rainbow semantic highlighting")
|
||||||
|
|
||||||
|
;; I've left cquery/ccls -extra-init-params separate for now, as one has defaults while the other doesn't
|
||||||
|
;; Just to facilitate switching between the two easily
|
||||||
|
(defvar c-c++-lsp-extra-init-params '(:cacheFormat "msgpack")
|
||||||
|
"Extra initialisation parameters to pass to the backend. See
|
||||||
|
https://github.com/cquery-project/cquery/blob/master/src/config.h or
|
||||||
|
https://github.com/MaskRay/ccls/blob/master/src/config.h
|
||||||
|
for details.")
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
;;
|
;;
|
||||||
;;; License: GPLv3
|
;;; License: GPLv3
|
||||||
|
|
||||||
|
(require 'cl-lib)
|
||||||
|
(require 'subr-x)
|
||||||
|
|
||||||
(defun spacemacs//c-toggle-auto-newline ()
|
(defun spacemacs//c-toggle-auto-newline ()
|
||||||
"Toggle auto-newline."
|
"Toggle auto-newline."
|
||||||
(c-toggle-auto-newline 1))
|
(c-toggle-auto-newline 1))
|
||||||
|
@ -157,9 +160,9 @@ and the arguments for flyckeck-clang based on a project-specific text file."
|
||||||
rtags-last-request-not-indexed)
|
rtags-last-request-not-indexed)
|
||||||
(gtags-find-tag)))
|
(gtags-find-tag)))
|
||||||
|
|
||||||
(defun spacemacs/c-c++-tags-find-references-at-point (&optional prefix)
|
(defun spacemacs/c-c++-tags-find-refs-at-point (&optional prefix)
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(if (and (not (rtags-find-references-at-point prefix))
|
(if (and (not (rtags-find-refs-at-point prefix))
|
||||||
rtags-last-request-not-indexed)
|
rtags-last-request-not-indexed)
|
||||||
(gtags-find-rtag)))
|
(gtags-find-rtag)))
|
||||||
|
|
||||||
|
@ -182,3 +185,169 @@ and the arguments for flyckeck-clang based on a project-specific text file."
|
||||||
(interactive)
|
(interactive)
|
||||||
(call-interactively (if (spacemacs/c-c++-use-rtags t)
|
(call-interactively (if (spacemacs/c-c++-use-rtags t)
|
||||||
'rtags-imenu 'idomenu)))
|
'rtags-imenu 'idomenu)))
|
||||||
|
|
||||||
|
|
||||||
|
;; lsp
|
||||||
|
(defun spacemacs//c-c++-lsp-enabled ()
|
||||||
|
"Return true if one or other of the lsp backends is enabled"
|
||||||
|
(member c-c++-backend c-c++-lsp-backends))
|
||||||
|
|
||||||
|
;; -- BEGIN helper functions for common configuration of cquery and ccls backends
|
||||||
|
(defun spacemacs//c-c++-lsp-backend ()
|
||||||
|
"Return a string representation of the LSP backend specified by the `c-c++-backend' configuration variable, without the `lsp-' prefix."
|
||||||
|
(ecase c-c++-backend
|
||||||
|
('lsp-ccls "ccls")
|
||||||
|
('lsp-cquery "cquery")))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-string (prefix suffix)
|
||||||
|
(concat prefix (spacemacs//c-c++-lsp-backend) suffix))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-symbol (prefix suffix)
|
||||||
|
"Return a symbol for the LSP backend specified by the `c-c++-backend' configuration variable."
|
||||||
|
(intern (spacemacs//c-c++-lsp-string prefix suffix)))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-call-function (prefix suffix &rest args)
|
||||||
|
(apply (spacemacs//c-c++-lsp-symbol prefix suffix) args))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-funcall-interactively (prefix suffix &rest args)
|
||||||
|
(funcall-interactively (spacemacs//c-c++-lsp-symbol prefix suffix) args))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-funcall-interactively-no-args (prefix suffix)
|
||||||
|
(funcall-interactively (spacemacs//c-c++-lsp-symbol prefix suffix)))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-set-symbol (prefix suffix value)
|
||||||
|
(set (spacemacs//c-c++-lsp-symbol prefix suffix) (symbol-value value)))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-set-config (param prefix suffix)
|
||||||
|
(when (symbol-value param) (spacemacs//c-c++-lsp-set-symbol prefix suffix param)))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-apply-config (suffix)
|
||||||
|
(spacemacs//c-c++-lsp-set-config (intern (concat "c-c++-lsp-" suffix)) nil (concat "-" suffix)))
|
||||||
|
;; -- END helper functions for common configuration of cquery and ccls backends
|
||||||
|
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-enable ()
|
||||||
|
"Enable the LSP backend specified by the `c-c++-backend' configuration variable."
|
||||||
|
(progn (condition-case nil
|
||||||
|
(spacemacs//c-c++-lsp-call-function "lsp-" "-enable")
|
||||||
|
(user-error nil))))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-config ()
|
||||||
|
"Configure the LSP backend specified by the `c-c++-backend' configuration variable."
|
||||||
|
(progn
|
||||||
|
(spacemacs//c-c++-lsp-setup-company)
|
||||||
|
(spacemacs//c-c++-lsp-define-extensions)
|
||||||
|
(spacemacs//c-c++-lsp-wrap-functions)
|
||||||
|
(setq-default flycheck-disabled-checkers '(c/c++-clang c/c++-gcc))
|
||||||
|
|
||||||
|
(if (eq c-c++-lsp-cache-dir nil)
|
||||||
|
(progn
|
||||||
|
(setq c-c++-lsp-cache-dir (file-truename(concat "~/.emacs.d/.cache/" (symbol-name c-c++-backend))))
|
||||||
|
(message (concat "c-c++: No c-c++-lsp-cache-dir specified: defaulting to " c-c++-lsp-cache-dir))))
|
||||||
|
|
||||||
|
(dolist (param '("executable" "extra-init-params" "cache-dir" "project-whitelist" "project-blacklist" "sem-highlight-method"))
|
||||||
|
(spacemacs//c-c++-lsp-apply-config param))
|
||||||
|
|
||||||
|
(when c-c++-lsp-sem-highlight-rainbow
|
||||||
|
(unless c-c++-lsp-sem-highlight-method
|
||||||
|
(progn
|
||||||
|
(setq c-c++-lsp-sem-highlight-method 'font-lock)
|
||||||
|
(message "c-c++: No semantic highlight method specified. Defaulting to `font-lock'.")))
|
||||||
|
(ecase c-c++-backend
|
||||||
|
('lsp-cquery (cquery-use-default-rainbow-sem-highlight))
|
||||||
|
('lsp-ccls (ccls-use-default-rainbow-sem-highlight))))
|
||||||
|
|
||||||
|
(dolist (mode c-c++-modes)
|
||||||
|
(spacemacs/lsp-bind-keys-for-mode mode)
|
||||||
|
(spacemacs//c-c++-lsp-bind-keys-for-mode mode))
|
||||||
|
|
||||||
|
(evil-set-initial-state '(spacemacs//c-c++-lsp-symbol nil "-tree-mode") 'emacs)
|
||||||
|
;;evil-record-macro keybinding clobbers q in cquery-tree-mode-map for some reason?
|
||||||
|
(evil-make-overriding-map (symbol-value (spacemacs//c-c++-lsp-symbol nil "-tree-mode-map")))))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-setup-company ()
|
||||||
|
"Setup LSP backend auto-completion."
|
||||||
|
(progn
|
||||||
|
(spacemacs|add-company-backends :backends company-lsp :modes c-mode-common)
|
||||||
|
;;Disable client-side cache and sorting, as server does a better job
|
||||||
|
(setq company-transformers nil company-lsp-async t company-lsp-cache-candidates nil)))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-wrap-functions ()
|
||||||
|
"Wrap navigation functions for the LSP backend specified by the `c-c++-backend' configuration variable."
|
||||||
|
(defun c-c++/call-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-call-hierarchy" nil))
|
||||||
|
(defun c-c++/call-hierarchy-inv () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-call-hierarchy" t))
|
||||||
|
(defun c-c++/inheritance-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-inheritance-hierarchy"))
|
||||||
|
(defun c-c++/inheritance-hierarchy-inv () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-inheritance-hierarchy" t))
|
||||||
|
(defun c-c++/member-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively-no-args nil "-member-hierarchy"))
|
||||||
|
(defun c-c++/preprocess-file () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-preprocess-file"))
|
||||||
|
(defun c-c++/refresh-index () (interactive) ()
|
||||||
|
(ecase c-c++-backend
|
||||||
|
('lsp-cquery (cquery-freshen-index))
|
||||||
|
('lsp-ccls (ccls-reload)))))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-bind-keys-for-mode (mode)
|
||||||
|
"Bind LSP backend functions for the specified mode."
|
||||||
|
(spacemacs/set-leader-keys-for-major-mode mode
|
||||||
|
;; backend
|
||||||
|
"bf" #'c-c++/refresh-index
|
||||||
|
"bp" #'c-c++/preprocess-file
|
||||||
|
;; goto
|
||||||
|
"gf" 'find-file-at-point
|
||||||
|
"gF" 'ffap-other-window
|
||||||
|
;; hierarchy
|
||||||
|
"ghc" #'c-c++/call-hierarchy
|
||||||
|
"ghC" #'c-c++/call-hierarchy-inv
|
||||||
|
"ghi" #'c-c++/inheritance-hierarchy
|
||||||
|
"ghI" #'c-c++/inheritance-hierarchy-inv
|
||||||
|
;; members
|
||||||
|
"gmh" #'c-c++/member-hierarchy)
|
||||||
|
|
||||||
|
(spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
|
||||||
|
"&" 'refs-address
|
||||||
|
"R" 'refs-read
|
||||||
|
"W" 'refs-write
|
||||||
|
"c" 'callers
|
||||||
|
"C" 'callees
|
||||||
|
"v" 'vars
|
||||||
|
"hb" 'base) ;;Replace this with lsp-goto-implementation in lsp-layer?
|
||||||
|
|
||||||
|
(when (eq c-c++-backend 'lsp-ccls)
|
||||||
|
(spacemacs/set-leader-keys-for-major-mode mode
|
||||||
|
"bR" 'ccls-reload)
|
||||||
|
(spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
|
||||||
|
"mc" 'member-classes
|
||||||
|
"mf" 'member-functions
|
||||||
|
"mv" 'member-vars)))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-define-extensions ()
|
||||||
|
"Wrap some backend-specific extensions using the find functions provided by lsp-mode and lsp-ui"
|
||||||
|
(spacemacs//c-c++-lsp-call-function "spacemacs//c-c++-lsp-define-" "-extensions")
|
||||||
|
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'vars
|
||||||
|
(spacemacs//c-c++-lsp-string "$" "/vars"))
|
||||||
|
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'refs-address
|
||||||
|
"textDocument/references"
|
||||||
|
'(plist-put (lsp--text-document-position-params) :context '(:role 128)))
|
||||||
|
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'refs-read
|
||||||
|
"textDocument/references"
|
||||||
|
'(plist-put (lsp--text-document-position-params) :context '(:role 8)))
|
||||||
|
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'refs-write
|
||||||
|
"textDocument/references"
|
||||||
|
'(plist-put (lsp--text-document-position-params) :context '(:role 16))))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-define-cquery-extensions ()
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'callers "$cquery/callers")
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'callees "$cquery/callers" '(:callee t))
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'base "$cquery/base"))
|
||||||
|
|
||||||
|
(defun spacemacs//c-c++-lsp-define-ccls-extensions ()
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'callers "$ccls/call")
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'callees "$ccls/call" '(:callee t))
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'base "$ccls/inheritance" '(:levels 3))
|
||||||
|
;;ccls features without a cquery analogue...
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'member-classes "$ccls/member" `(:kind 2))
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'member-functions "$ccls/member" `(:kind 3))
|
||||||
|
(spacemacs/lsp-define-extensions "c-c++" 'member-vars "$ccls/member" `(:kind 0)))
|
||||||
|
|
14
layers/+lang/c-c++/layers.el
Normal file
14
layers/+lang/c-c++/layers.el
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
;;; layers.el --- C/C++ Layer declarations File for Spacemacs
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2012-2018 Sylvain Benner & Contributors
|
||||||
|
;;
|
||||||
|
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
|
||||||
|
;; URL: https://github.com/syl20bnr/spacemacs
|
||||||
|
;;
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
;;
|
||||||
|
;;; License: GPLv3
|
||||||
|
|
||||||
|
(when (and (boundp 'c-c++-backend)
|
||||||
|
(member c-c++-backend '(lsp-cquery lsp-ccls)))
|
||||||
|
(configuration-layer/declare-layer 'lsp))
|
|
@ -36,7 +36,11 @@
|
||||||
stickyfunc-enhance
|
stickyfunc-enhance
|
||||||
xcscope
|
xcscope
|
||||||
ycmd
|
ycmd
|
||||||
))
|
;;lsp-backend
|
||||||
|
(cquery :requires lsp-mode)
|
||||||
|
(ccls :requires lsp-mode)
|
||||||
|
projectile))
|
||||||
|
|
||||||
|
|
||||||
(defun c-c++/init-cc-mode ()
|
(defun c-c++/init-cc-mode ()
|
||||||
(use-package cc-mode
|
(use-package cc-mode
|
||||||
|
@ -60,7 +64,7 @@
|
||||||
|
|
||||||
(defun c-c++/init-clang-format ()
|
(defun c-c++/init-clang-format ()
|
||||||
(use-package clang-format
|
(use-package clang-format
|
||||||
:if c-c++-enable-clang-support
|
:if (or c-c++-enable-clang-support (spacemacs//c-c++-lsp-enabled))
|
||||||
:init
|
:init
|
||||||
(progn
|
(progn
|
||||||
(when c-c++-enable-clang-format-on-save
|
(when c-c++-enable-clang-format-on-save
|
||||||
|
@ -75,10 +79,15 @@
|
||||||
(when (configuration-layer/package-used-p 'cmake-mode)
|
(when (configuration-layer/package-used-p 'cmake-mode)
|
||||||
(spacemacs|add-company-backends :backends company-cmake :modes cmake-mode))
|
(spacemacs|add-company-backends :backends company-cmake :modes cmake-mode))
|
||||||
(when c-c++-enable-clang-support
|
(when c-c++-enable-clang-support
|
||||||
(spacemacs|add-company-backends :backends company-clang
|
(if (spacemacs//c-c++-lsp-enabled)
|
||||||
:modes c-mode-common)
|
(display-warning :error "`c-c++-enable-clang-support' ignored when using lsp backend")
|
||||||
|
(progn
|
||||||
|
(spacemacs|add-company-backends :backends company-clang :modes c-mode-common)
|
||||||
|
(when c-c++-enable-c++11
|
||||||
|
(setq company-clang-arguments '("-std=c++11")))
|
||||||
(setq company-clang-prefix-guesser 'spacemacs/company-more-than-prefix-guesser)
|
(setq company-clang-prefix-guesser 'spacemacs/company-more-than-prefix-guesser)
|
||||||
(spacemacs/add-to-hooks 'spacemacs/c-c++-load-clang-args c-c++-mode-hooks)))
|
(spacemacs/add-to-hooks 'spacemacs/c-c++-load-clang-args c-c++-mode-hooks)
|
||||||
|
()))))
|
||||||
|
|
||||||
(defun c-c++/init-company-c-headers ()
|
(defun c-c++/init-company-c-headers ()
|
||||||
(use-package company-c-headers
|
(use-package company-c-headers
|
||||||
|
@ -89,8 +98,7 @@
|
||||||
|
|
||||||
(defun c-c++/init-company-rtags ()
|
(defun c-c++/init-company-rtags ()
|
||||||
(use-package company-rtags
|
(use-package company-rtags
|
||||||
:if (and c-c++-enable-rtags-support
|
:if (and (eq c-c++-backend 'rtags) c-c++-enable-rtags-completion)
|
||||||
(not (eq c-c++-enable-rtags-support 'no-completion)))
|
|
||||||
:defer t
|
:defer t
|
||||||
:init
|
:init
|
||||||
(progn
|
(progn
|
||||||
|
@ -125,7 +133,7 @@
|
||||||
;; TODO lazy load this package
|
;; TODO lazy load this package
|
||||||
(defun c-c++/init-flycheck-rtags ()
|
(defun c-c++/init-flycheck-rtags ()
|
||||||
(use-package flycheck-rtags
|
(use-package flycheck-rtags
|
||||||
:if c-c++-enable-rtags-support))
|
:if (eq c-c++-backend 'rtags)))
|
||||||
|
|
||||||
(defun c-c++/post-init-ggtags ()
|
(defun c-c++/post-init-ggtags ()
|
||||||
(add-hook 'c-mode-local-vars-hook #'spacemacs/ggtags-mode-enable)
|
(add-hook 'c-mode-local-vars-hook #'spacemacs/ggtags-mode-enable)
|
||||||
|
@ -161,19 +169,19 @@
|
||||||
;; TODO lazy load this package
|
;; TODO lazy load this package
|
||||||
(defun c-c++/init-helm-rtags ()
|
(defun c-c++/init-helm-rtags ()
|
||||||
(use-package helm-rtags
|
(use-package helm-rtags
|
||||||
:if c-c++-enable-rtags-support
|
:if (eq c-c++-backend 'rtags)
|
||||||
:init (setq rtags-display-result-backend 'helm)))
|
:init (setq rtags-display-result-backend 'helm)))
|
||||||
|
|
||||||
;; TODO lazy load this package
|
;; TODO lazy load this package
|
||||||
(defun c-c++/init-ivy-rtags ()
|
(defun c-c++/init-ivy-rtags ()
|
||||||
(use-package ivy-rtags
|
(use-package ivy-rtags
|
||||||
:if c-c++-enable-rtags-support
|
:if (eq c-c++-backend 'rtags)
|
||||||
:init (setq rtags-display-result-backend 'ivy)))
|
:init (setq rtags-display-result-backend 'ivy)))
|
||||||
|
|
||||||
;; TODO lazy load this package
|
;; TODO lazy load this package
|
||||||
(defun c-c++/init-rtags ()
|
(defun c-c++/init-rtags ()
|
||||||
(use-package rtags
|
(use-package rtags
|
||||||
:if c-c++-enable-rtags-support
|
:if (eq c-c++-backend 'rtags)
|
||||||
:init
|
:init
|
||||||
(progn
|
(progn
|
||||||
(setq rtags-autostart-diagnostics t)
|
(setq rtags-autostart-diagnostics t)
|
||||||
|
@ -227,7 +235,7 @@
|
||||||
|
|
||||||
(defun c-c++/post-init-srefactor ()
|
(defun c-c++/post-init-srefactor ()
|
||||||
(dolist (mode c-c++-modes)
|
(dolist (mode c-c++-modes)
|
||||||
(spacemacs/set-leader-keys-for-major-mode mode "r" 'srefactor-refactor-at-point))
|
(spacemacs/set-leader-keys-for-major-mode mode "r." 'srefactor-refactor-at-point))
|
||||||
(spacemacs/add-to-hooks 'spacemacs/load-srefactor c-c++-mode-hooks))
|
(spacemacs/add-to-hooks 'spacemacs/load-srefactor c-c++-mode-hooks))
|
||||||
|
|
||||||
(defun c-c++/post-init-stickyfunc-enhance ()
|
(defun c-c++/post-init-stickyfunc-enhance ()
|
||||||
|
@ -250,3 +258,46 @@
|
||||||
:post-init
|
:post-init
|
||||||
(dolist (mode c-c++-modes)
|
(dolist (mode c-c++-modes)
|
||||||
(spacemacs/set-leader-keys-for-major-mode mode "gi" 'cscope-index-files))))
|
(spacemacs/set-leader-keys-for-major-mode mode "gi" 'cscope-index-files))))
|
||||||
|
|
||||||
|
;; BEGIN LSP BACKEND PACKAGES
|
||||||
|
|
||||||
|
;; See also https://github.com/cquery-project/cquery/wiki/Emacs
|
||||||
|
(defun c-c++/init-cquery ()
|
||||||
|
(use-package cquery
|
||||||
|
:if (eq c-c++-backend 'lsp-cquery)
|
||||||
|
:defer t
|
||||||
|
:commands lsp-cquery-enable
|
||||||
|
:init
|
||||||
|
(add-hook 'c-mode-common-hook #'spacemacs//c-c++-lsp-enable)
|
||||||
|
:config
|
||||||
|
(spacemacs//c-c++-lsp-config)))
|
||||||
|
|
||||||
|
;; See also https://github.com/MaskRay/ccls/wiki/Emacs
|
||||||
|
(defun c-c++/init-ccls ()
|
||||||
|
(use-package ccls
|
||||||
|
:if (eq c-c++-backend 'lsp-ccls)
|
||||||
|
:defer t
|
||||||
|
:commands lsp-ccls-enable
|
||||||
|
:init
|
||||||
|
(add-hook 'c-mode-common-hook #'spacemacs//c-c++-lsp-enable)
|
||||||
|
:config
|
||||||
|
(spacemacs//c-c++-lsp-config)))
|
||||||
|
|
||||||
|
;;Intentionally adding both cquery and ccls cache dirs to ignore list, to facilitate switching between
|
||||||
|
;;two without multiple caches polluting projectile find file results
|
||||||
|
(defun c-c++/pre-init-projectile ()
|
||||||
|
(spacemacs|use-package-add-hook projectile
|
||||||
|
:post-config
|
||||||
|
(progn
|
||||||
|
(add-to-list 'projectile-globally-ignored-directories ".cquery_cached_index")
|
||||||
|
(add-to-list 'projectile-globally-ignored-directories ".ccls-cache")
|
||||||
|
(when c-c++-lsp-cache-dir
|
||||||
|
(add-to-list 'projectile-globally-ignored-directories c-c++-lsp-cache-dir))
|
||||||
|
(when c-c++-adopt-subprojects
|
||||||
|
(setq projectile-project-root-files-top-down-recurring
|
||||||
|
(append '("compile_commands.json"
|
||||||
|
".cquery"
|
||||||
|
".ccls")
|
||||||
|
projectile-project-root-files-top-down-recurring))))))
|
||||||
|
|
||||||
|
;; END LSP BACKEND PACKAGES
|
||||||
|
|
Loading…
Reference in a new issue