refactor!(cc): remove irony and rtags

BREAKING CHANGE: This removes the irony and rtags packages so we can
lean on LSP servers like clangd and ccls fully, which provide the same
features with much more consistency.

Close: #8049
This commit is contained in:
Henrik Lissner 2024-09-09 15:34:17 -04:00
parent 01c19094e8
commit 1a33838423
No known key found for this signature in database
GPG key ID: B60957CA074D39A3
6 changed files with 34 additions and 288 deletions

View file

@ -6,10 +6,11 @@
* Description :unfold:
This module adds support for the C-family of languages: C, C++, and Objective-C.
- Code completion (~company-irony~)
- eldoc support (~irony-eldoc~)
- Syntax-checking (~flycheck-irony~)
- Code navigation (~rtags~)
Through LSP, this module offers:
- Code completion
- eldoc support
- Syntax-checking
- Code navigation
- File Templates ([[../../editor/file-templates/templates/c-mode][c-mode]], [[../../editor/file-templates/templates/c++-mode][c++-mode]])
- Snippets ([[https://github.com/hlissner/doom-snippets/tree/master/cc-mode][cc-mode]], [[https://github.com/hlissner/doom-snippets/tree/master/c-mode][c-mode]], [[https://github.com/hlissner/doom-snippets/tree/master/c++-mode][c++-mode]])
- Several improvements to C++11 indentation and syntax highlighting.
@ -22,32 +23,22 @@ This module adds support for the C-family of languages: C, C++, and Objective-C.
** Module flags
- +lsp ::
Enable LSP support for ~c-mode~, ~c++-mode~, and ~objc-mode~. Requires [[doom-module::tools
lsp]] and a langserver (supports ccls, clangd, and cquery). Replaces irony &
rtags.
lsp]] and a langserver (supports ccls, clangd, and cquery).
- +tree-sitter ::
Leverages tree-sitter for better syntax highlighting and structural text
editing. Requires [[doom-module::tools tree-sitter]].
** Packages
- [[doom-package:cmake-mode]]
- [[doom-package:company-glsl]]
- [[doom-package:cuda-mode]]
- [[doom-package:demangle-mode]]
- [[doom-package:disaster]]
- [[doom-package:glsl-mode]]
- [[doom-package:company-glsl]]
- [[doom-package:modern-cpp-font-lock]] unless [[doom-module:+tree-sitter]]
- [[doom-package:opencl-mode]]
- if [[doom-module:+lsp]]
- [[doom-package:ccls]] if [[doom-module::tools lsp -eglot]]
- else
- [[doom-package:company-irony]]
- [[doom-package:company-irony-c-headers]]
- [[doom-package:flycheck-irony]]
- [[doom-package:helm-rtags]] if [[doom-module::completion helm]]
- [[doom-package:irony]]
- [[doom-package:irony-eldoc]]
- [[doom-package:ivy-rtags]] if [[doom-module::completion ivy]]
- [[doom-package:rtags]]
** Hacks
/No hacks documented for this module./
@ -62,7 +53,6 @@ This module adds support for the C-family of languages: C, C++, and Objective-C.
This module's requirements change depending on how you use it.
- If [[doom-module:+lsp]] is enabled, you need one of *clangd v9+* or *ccls*.
- If [[doom-module:+lsp]] is *not* enabled, you need *irony-server* and *rtags*.
- Other features in this module depend on:
- (optional) glslangValidator, for GLSL completion in ~glsl-mode~
- (optional) cmake, for code completion in ~cmake-mode~
@ -87,51 +77,6 @@ recommended.
alternative install methods listed [[https://github.com/MaskRay/ccls/wiki/Install][in the project's wiki]].
+ cmake-language-server :: available through ~pip~ on most distributions
** irony-server
Irony powers the code completion, eldoc and syntax checking systems.
After installing its dependencies (Clang and CMake), run ~M-x
irony-install-server~ in Emacs.
*** macOS
Due to linking issues, macOS users must compile irony-server manually:
#+begin_src sh
brew install cmake
brew install llvm
git clone https://github.com/Sarcasm/irony-mode irony-mode
#+end_src
#+begin_src sh
mkdir irony-mode/server/build
pushd irony-mode/server/build
DEST="$HOME/.emacs.d/.local/etc/irony-server/"
cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm \
-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \
-DCMAKE_INSTALL_PREFIX="$DEST" ../
cmake --build . --use-stderr --config Release --target install
install_name_tool -change @rpath/libclang.dylib \
/usr/local/opt/llvm/lib/libclang.dylib \
"$DEST/bin/irony-server"
# Cleanup
popd
rm -rf irony-mode
#+end_src
** rtags
Code navigation requires an [[https://github.com/Andersbakken/rtags][rtags]] server (~rdm~) installed. This should be
available through your OS's package manager.
This module will auto-start ~rdm~ when you open C/C++ buffers (so long as one
isn't already running). If you prefer to run it yourself:
#+begin_src sh
rdm &
rc -J $PROJECT_ROOT # loads PROJECT_ROOT's compile_commands.json
#+end_src
** =:editor format=
The formatter used is [[doom-executable:clang-format]] which should be installed alongside =clang=.
@ -163,28 +108,20 @@ additional function to get inheritance type hierarchy is added:
#+end_quote
** Project compile settings
By default, a set of default compile settings are defined in
~+cc-default-compiler-options~ for C, C++ and Objective C. Irony, rtags and
flycheck will fall back to these. *This variable does nothing for LSP users.*
For a more universal solution: both LSP servers and irony will recognize a
[[https://sarcasm.github.io/notes/dev/compilation-database.html#ninja][compilation database]] (a ~compile_commands.json~ file). There are [[https://sarcasm.github.io/notes/dev/compilation-database.html][many ways to
generate one]]. Here is an example using [[http://www.cmake.org/][CMake]] and [[https://github.com/rizsotto/Bear][bear]]:
LSP servers and Flycheck will recognize a [[https://sarcasm.github.io/notes/dev/compilation-database.html#ninja][compilation database]] (a
~compile_commands.json~ file). There are [[https://sarcasm.github.io/notes/dev/compilation-database.html][many ways to generate one]]. Here is an
example using [[http://www.cmake.org/][CMake]] and [[https://github.com/rizsotto/Bear][bear]]:
#+begin_src sh
# For CMake projects
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
#+end_src
#+begin_src sh
# For non-CMake projects
make clean
bear make
$ make clean
$ bear make
#+end_src
Use ~M-x +cc/reload-compile-db~ to reload your compile db in an already-open
C/C++/ObjC buffer.
*** Known issues with bear on macOS
MacOS' [[https://support.apple.com/en-us/HT204899][System Integrity Protection (SIP)]] might interfere with bear if ~make~ is
under ~/usr/bin/~ which results in an empty compilation database.
@ -228,6 +165,7 @@ Search for your combination of =(LSP client package, LSP server)=. You are using
*** LSP-mode with clangd
#+begin_src emacs-lisp
;;; add to $DOOMDIR/config.el
(after! lsp-clangd
(setq lsp-clients-clangd-args
'("-j=3"
@ -244,6 +182,7 @@ server everywhere clangd can be used.
*** LSP-mode with ccls
#+begin_src emacs-lisp
;;; add to $DOOMDIR/config.el
(after! ccls
(setq ccls-initialization-options '(:index (:comments 2) :completion (:detailedLabel t)))
(set-lsp-priority! 'ccls 2)) ; optional as ccls is the default in Doom
@ -255,7 +194,9 @@ documentation]] lists available options, use =t= for ~true~, =:json-false= for
*** Eglot with clangd
#+begin_src emacs-lisp
(set-eglot-client! 'cc-mode '("clangd" "-j=3" "--clang-tidy"))
;;; add to $DOOMDIR/config.el
(after! cc-mode
(set-eglot-client! 'cc-mode '("clangd" "-j=3" "--clang-tidy")))
#+end_src
This will both set your clangd flags and choose clangd as the default server (if
@ -263,7 +204,9 @@ it is the last =set-eglot-client! 'cc-mode= in your config).
*** Eglot with ccls
#+begin_src emacs-lisp
(set-eglot-client! 'cc-mode '("ccls" "--init={\"index\": {\"threads\": 3}}"))
;;; add to $DOOMDIR/config.el
(after! cc-mode
(set-eglot-client! 'cc-mode '("ccls" "--init={\"index\": {\"threads\": 3}}")))
#+end_src
This will both set your ccls flags and choose ccls as the default server (if it

View file

@ -93,40 +93,6 @@ simpler."
;;
;; Commands
;;;###autoload
(defun +cc/reload-compile-db ()
"Reload the current project's JSON compilation database."
(interactive)
(unless (memq major-mode '(c-mode c++-mode objc-mode))
(user-error "Not a C/C++/ObjC buffer"))
;; first rtag
(when (and (featurep 'rtags)
rtags-enabled
(executable-find rtags-rc-binary-name))
(with-temp-buffer
(message "Reloaded compile commands for rtags daemon")
(rtags-call-rc :silent t "-J" (or (doom-project-root) default-directory))))
;; then irony
(when (and (featurep 'irony) irony-mode)
(+cc-init-irony-compile-options-h))
;; Otherwise, LSP
(when (bound-and-true-p lsp-mode)
(lsp-workspace-restart))
(when (bound-and-true-p eglot-managed-mode)
(eglot-reconnect)))
;;;###autoload
(defun +cc/imenu ()
"Invoke `rtags-imenu' if a running rdm process is available, otherwise invoke
`imenu'."
(interactive)
(call-interactively
(if (and (processp rtags-rdm-process)
(not (eq (process-status rtags-rdm-process) 'exit))
(not (eq (process-status rtags-rdm-process) 'signal)))
#'rtags-imenu
#'imenu)))
;; Eglot specific helper, courtesy of MaskRay
;;;###autoload
(defun +cc/eglot-ccls-show-inheritance-hierarchy (&optional derived)
@ -181,52 +147,14 @@ the children of class at point."
t)))
(defvar +cc--project-includes-alist nil)
;;;###autoload
(defun +cc-init-irony-compile-options-h ()
"Initialize compiler options for irony-mode. It searches for the nearest
compilation database and initailizes it, otherwise falling back on
`+cc-default-compiler-options' and `+cc-default-include-paths'.
See https://github.com/Sarcasm/irony-mode#compilation-database for details on
compilation dbs."
(when (memq major-mode '(c-mode c++-mode objc-mode))
(require 'irony-cdb)
(unless (irony-cdb-autosetup-compile-options)
(let ((project-root (doom-project-root))
(include-paths (+cc-resolve-include-paths)))
(setf (alist-get project-root +cc--project-includes-alist)
include-paths)
(irony-cdb--update-compile-options
(append (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))
(cl-loop for path in include-paths
collect (format "-I%s" path)))
project-root)))))
;; ;;;###autoload
;; (defun +cc|init-ccls-compile-options ()
;; "TODO"
;; (when (memq major-mode '(c-mode c++-mode objc-mode))
;; (when-let (include-paths (+cc-resolve-include-paths))
;; (let ((args (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))))
;; (setf (alist-get (or (lsp-workspace-root)
;; (lsp--suggest-project-root)
;; (doom-project-root))
;; +cc--project-includes-alist)
;; include-paths)
;; (setq ccls-initialization-options
;; `(:clang (:extraArgs
;; [,@(cl-loop for path in include-paths
;; collect (format "-I%s" path))])))))))
;;;###autoload
(defun +cc-init-ffap-integration-h ()
"Takes the local project include paths and registers them with ffap.
This way, `find-file-at-point' (and `+lookup/file') will know where to find most
header files."
(when-let (project-root (or (bound-and-true-p irony--working-directory)
(and (featurep 'lsp)
(when-let (project-root (and (featurep 'lsp)
(or (lsp-workspace-root)
(doom-project-root)))))
(doom-project-root))))
(require 'ffap)
(make-local-variable 'ffap-c-path)
(make-local-variable 'ffap-c++-path)

View file

@ -4,8 +4,8 @@
(list "include"
"includes")
"A list of default relative paths which will be searched for up from the
current file, to be passed to irony as extra header search paths. Paths can be
absolute. This is ignored if your project has a compilation database.
current file. Paths can be absolute. This is ignored if your project has a
compilation database.
This is ignored by ccls.")
@ -13,21 +13,6 @@ This is ignored by ccls.")
"Fallback major mode for .h files if all other heuristics fail (in
`+cc-c-c++-objc-mode').")
(defvar +cc-default-compiler-options
`((c-mode . nil)
(c++-mode
. ,(list "-std=c++1z" ; use C++17 draft by default
(when (featurep :system 'macos)
;; NOTE beware: you'll get abi-inconsistencies when passing
;; std-objects to libraries linked with libstdc++ (e.g. if you
;; use boost which wasn't compiled with libc++)
"-stdlib=libc++")))
(objc-mode . nil))
"A list of default compiler options for the C family. These are ignored if a
compilation database is present in the project.
This is ignored by ccls.")
;;
;;; Packages
@ -37,9 +22,8 @@ This is ignored by ccls.")
;; Use `c-mode'/`c++-mode'/`objc-mode' depending on heuristics
:mode ("\\.h\\'" . +cc-c-c++-objc-mode)
;; Ensure find-file-at-point recognize system libraries in C modes. It must be
;; set up before the likes of irony/lsp are initialized. Also, we use
;; local-vars hooks to ensure these only run in their respective major modes,
;; and not their derived modes.
;; set up before lsp is initialized. Also, we use local-vars hooks to ensure
;; these only run in their respective major modes, and not derived modes.
:hook ((c-mode-local-vars c++-mode-local-vars objc-mode-local-vars) . +cc-init-ffap-integration-h)
;;; Improve fontification in C/C++ (also see `modern-cpp-font-lock')
:hook (c-mode-common . rainbow-delimiters-mode)
@ -139,38 +123,6 @@ This is ignored by ccls.")
:hook (c++-mode . modern-c++-font-lock-mode))
(use-package! irony
:unless (modulep! +lsp)
:commands irony-install-server
;; Initialize compilation database, if present. Otherwise, fall back on
;; `+cc-default-compiler-options'.
:hook (irony-mode . +cc-init-irony-compile-options-h)
;; Only initialize `irony-mode' if the server is available. Otherwise fail
;; quietly and gracefully.
:hook ((c-mode-local-vars c++-mode-local-vars objc-mode-local-vars) . +cc-init-irony-mode-maybe-h)
:preface (setq irony-server-install-prefix (concat doom-data-dir "irony-server/"))
:config
(defun +cc-init-irony-mode-maybe-h ()
(if (file-directory-p irony-server-install-prefix)
(irony-mode +1)
(message "Irony server isn't installed")))
(setq irony-cdb-search-directory-list '("." "build" "build-conda"))
(use-package! irony-eldoc
:hook (irony-mode . irony-eldoc))
(use-package! flycheck-irony
:when (and (modulep! :checkers syntax)
(not (modulep! :checkers syntax +flymake)))
:config (flycheck-irony-setup))
(use-package! company-irony
:when (modulep! :completion company)
:init (set-company-backend! 'irony-mode '(:separate company-irony-c-headers company-irony))
:config (require 'company-irony-c-headers)))
;;
;; Major modes
@ -198,57 +150,7 @@ This is ignored by ccls.")
;;
;; Rtags Support
(use-package! rtags
:unless (modulep! +lsp)
;; Only initialize rtags-mode if rtags and rdm are available.
:hook ((c-mode-local-vars c++-mode-local-vars objc-mode-local-vars) . +cc-init-rtags-maybe-h)
:preface (setq rtags-install-path (concat doom-data-dir "rtags/"))
:config
(defun +cc-init-rtags-maybe-h ()
"Start an rtags server in c-mode and c++-mode buffers.
If rtags or rdm aren't available, fail silently instead of throwing a breaking error."
(and (require 'rtags nil t)
(rtags-executable-find rtags-rdm-binary-name)
(rtags-start-process-unless-running)))
(setq rtags-autostart-diagnostics t
rtags-use-bookmarks nil
rtags-completions-enabled nil
rtags-display-result-backend
(cond ((modulep! :completion ivy) 'ivy)
((modulep! :completion helm) 'helm)
('default))
;; These executables are named rtags-* on debian
rtags-rc-binary-name
(or (cl-find-if #'executable-find (list rtags-rc-binary-name "rtags-rc"))
rtags-rc-binary-name)
rtags-rdm-binary-name
(or (cl-find-if #'executable-find (list rtags-rdm-binary-name "rtags-rdm"))
rtags-rdm-binary-name)
;; If not using ivy or helm to view results, use a pop-up window rather
;; than displaying it in the current window...
rtags-results-buffer-other-window t
;; ...and don't auto-jump to first match before making a selection.
rtags-jump-to-first-match nil)
(set-lookup-handlers! '(c-mode c++-mode)
:definition #'rtags-find-symbol-at-point
:references #'rtags-find-references-at-point)
;; Use rtags-imenu instead of imenu/counsel-imenu
(define-key! (c-mode-map c++-mode-map) [remap imenu] #'+cc/imenu)
;; Ensure rtags cleans up after itself properly when exiting Emacs, rather
;; than display a jarring confirmation prompt for killing it.
(add-hook! 'kill-emacs-hook (ignore-errors (rtags-cancel-process)))
(add-hook 'rtags-jump-hook #'better-jumper-set-jump))
;;
;; LSP
;;; LSP
(when (modulep! +lsp)
(add-hook! '(c-mode-local-vars-hook

View file

@ -9,19 +9,6 @@
(modulep! :tools tree-sitter))
"This module requires (:tools tree-sitter)")
(when (require 'rtags nil t)
;; rtags
(when-let (bins (cl-remove-if #'rtags-executable-find
(list rtags-rdm-binary-name
rtags-rc-binary-name)))
(warn! "Couldn't find the rtag client and/or server programs %s. Disabling rtags support"
bins)))
;; irony server
(when (require 'irony nil t)
(unless (file-directory-p irony-server-install-prefix)
(warn! "Irony server isn't installed. Run M-x irony-install-server")))
(when (modulep! :completion company)
;; glslangValidator
(unless (executable-find "glslangValidator")

View file

@ -7,9 +7,10 @@
(package! cuda-mode :pin "c3dae31b3d1abedf4d0b98840127e2cac73d6ad8")
(package! demangle-mode :pin "04f545adab066708d6151f13da65aaf519f8ac4e")
(package! disaster :pin "b20f8e1ef96167a7beed5eb4fc6ef72488bd3662")
(package! opencl-mode :pin "204d5d9e0f5cb2cbe810f2933230eb08fe2c7695")
(unless (modulep! +tree-sitter)
(package! modern-cpp-font-lock :pin "43c6b68ff58fccdf9deef11674a172e4eaa8455c"))
(package! opencl-mode :pin "204d5d9e0f5cb2cbe810f2933230eb08fe2c7695")
(when (package! glsl-mode :pin "9b2e5f28e489a1f73c4aed734105618ac0dc0c43")
(when (modulep! :completion company)
@ -17,20 +18,6 @@
:recipe (:host github :repo "Kaali/company-glsl")
:pin "404cd0694ab34971f9c01eb22126cd2e7d3f9dc4")))
(if (modulep! +lsp)
(unless (modulep! :tools lsp +eglot)
;; ccls package is necessary only for lsp-mode.
(when (and (modulep! +lsp)
(not (modulep! :tools lsp +eglot)))
(package! ccls :pin "41399b0eba03f9b80769ced71501ba702db4cd62"))
(when (package! irony :pin "40e0ce19eb850bdf1f77225f11713cc816250d95")
(package! irony-eldoc :pin "73e79a89fad982a2ba072f2fcc1b4e41f0aa2978")
(when (and (modulep! :checkers syntax)
(not (modulep! :checkers syntax +flymake)))
(package! flycheck-irony :pin "42dbecd4a865cabeb301193bb4d660e26ae3befe"))
(when (modulep! :completion company)
(package! company-irony :pin "b44711dfce445610c1ffaec4951c6ff3882b216a")
(package! company-irony-c-headers :pin "72c386aeb079fb261d9ec02e39211272f76bbd97")))
(when (package! rtags :pin "f472b5d0a05270d5c93945b6a71771ab69068147")
(when (modulep! :completion ivy)
(package! ivy-rtags))
(when (modulep! :completion helm)
(package! helm-rtags))))

View file

@ -40,7 +40,6 @@ is added to the jump-list (managed by [[doom-package:better-jumper]]).
[[fn:recenter]] is called after many hooks and commands, such as:
- [[var:better-jumper-post-jump-hook]]
- [[var:rtags-after-find-file-hook]]
- [[var:org-follow-link-hook]]
- [[var:imenu-after-jump-hook]]
- [[var:counsel-grep-post-action-hook]]