Skip to content
yurytch edited this page Nov 4, 2019 · 4 revisions

RTags consists of three executables, rdm, rc and rp. rdm is the server application, and monitors all your indexed files for changes, and reindexes, using rp, when a source file or one of its dependencies is modified. Since clang is a fully compliant compiler it needs specific information about how your sources are compiled to be able to properly index them. This is done through telling rdm about the compile line using rc. First you need to start rdm. There are multiple ways to do so, either automatically (Launchd/Systemd/Emacs) or manually. To manually start rdm, just run rdm in a shell. Call rdm with the flag --help to print all the options available. We also provide manual pages for rdm and rc. If you always want to start rdm with specific options, put those options in the file ~/.rdmrc, see Setting rdm default options.

# Start rdm in the background
rdm &
# Index the file _foobar.c_
rc -c gcc -I... -fsomeflag -c foobar.c
# Load the compilation commands JSON file
rc -J /path/to/a/directory/containing/compile_commands.json

You can generate a compile_commands.json with various different tools, one might fit better than the other, depending on your project build system.

  • ninja
    ninja -t compdb cxx cc > compile_commands.json
    rc -J
        

    With ninja it’s also possible to pipe the commands directly to rc.

    ninja -t commands | rc -c -
    # Parse commands for a specific target only
    ninja -t commands rdm | rc -c -
        
  • cmake

    cmake can generate a compile_commands.json file as well.

    cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 .
    rc -J
        
  • Bear

    For other projects you can use bear to generate a compile_commands.json file. However, if you are cross-compiling you probably need to adjust the command entries in the compile_commands.json file to match the correct compiler. Furthermore, make sure you clean your project before invoking bear.

    make clean
    bear make
    rc -J
    # Parse commands for a specific target only
    make clean
    bear make rdm
    rc -J
        
  • make

    You can ask make to only print the recipes without actually doing something. This way may be perfectly fine for not too complex Makefiles.

    make clean
    make -nk | rc -c -
        

    There are very likely similar things you can do with other build systems that we’re unfamiliar with, please let us know if you do.

  • A different approach to get your files indexed is the man-in-the-middle

    This can be done like this:

    ln -s /path/to/rtags/bin/gcc-rtags-wrapper.sh /somewhere/that/is/in/your/path/before/usr/bin/gcc
    ln -s /path/to/rtags/bin/gcc-rtags-wrapper.sh /somewhere/that/is/in/your/path/before/usr/bin/c++
    ln -s /path/to/rtags/bin/gcc-rtags-wrapper.sh /somewhere/that/is/in/your/path/before/usr/bin/cc
    ln -s /path/to/rtags/bin/gcc-rtags-wrapper.sh /somewhere/that/is/in/your/path/before/usr/bin/g++
        

    E.g.

    $ which -a gcc | xargs file
    /home/abakken/bin/gcc: symbolic link to `/home/abakken/dev/rtags/bin/gcc-rtags-wrapper.sh'
    /usr/bin/gcc:         symbolic link to `gcc-4.7'
        

    Now every time you compile a file with which gcc rc will get its grubby hands all over your command line and make sure RTags knows about it.

RTags will group source files into projects based on some heuristics.

Essentially it will look for certain files/dirs (like configure/CMakeLists.txt/scons.1/.git) etc to try to determine the likely project root for each source file. For generated source files that end up in the build directory we try to find the source root based on similar heuristics around config.status/CMakeCache.txt etc. Usually this works out reasonably well. If it doesn’t for you, you can pass --project-root /path/to/the/project/root to rc.

RTags only gives you information about current project when you ask for things by name. You can explicitly change the current project using:

rc -w foobar

We try to do it automatically for you by passing along information about the current buffer when we call rc from elisp so that rdm can update its current project on demand.

RTags keeps a cache of indexed data so you don’t have to reindex everything if you restart it. The location of this data is by default ~/.cache/rtags but can be overridden by passing --data-dir /other/dir to rdm.

Elisp

Functions

(rtags-start-process-unless-running)

Start the rdm process unless the process is already running. You may create hook to automatically call this function upon entering, e.g. c-mode or c++mode.

E.g.

(add-hook 'c-mode-hook 'rtags-start-process-unless-running)
(add-hook 'c++-mode-hook 'rtags-start-process-unless-running)
(add-hook 'objc-mode-hook 'rtags-start-process-unless-running)
(rtags-restart-process)

Restart the rdm process.

(rtags-find-symbol-at-point)

Follow symbol under cursor. For references this goes to the definition (or declaration if no definition is known of the symbol. For declarations it goes to the definition and vice versa. For definitions of variables/parameters with constructors it goes to the constructor in question. If you pass a prefix argument, limit to current source file, if you pass a prefix argument and have narrowed the current file, limit to the narrowed region. This prefix argument is the same for: rtags-find-references-at-point, rtags-find-symbol, rtags-find-references

(rtags-find-references-at-point)

Find all references to symbol under cursor. If symbol is itself a reference it will find all references to the referenced symbol

(rtags-find-symbol)

Prompt for name of symbol to go to. Imagine the following code:

namespace N
{
class C
{
public:
    int func(int);
};
};

using namespace N;
int C::func(int val)
{
    return val * 2;
}

int N::C::func(int) will now be accessible by the following names:

  • func
  • func(int)
  • C::func(int)
  • C::func
  • N::C::func(int)
  • N::C::func
(rtags-find-references)

Prompt for name of symbol to find references to. Same as above but find references to symbol rather than declarations and definitions.

(rtags-diagnostics)

Start an async process in a buffer to receive warnings/errors from clang whenever a file gets reindexed. It integrates with flymake to put highlighting on code with warnings and errors

(rtags-enable-standard-keybindings)

Sets up a ton of standard keybindings under C-c r. If you pass a mode to the function it will set it up on that mode, otherwise it will use c-mode-base-map). You can choose a different prefix than C-c r like this:

(rtags-enable-standard-keybindings c-mode-base-map "\C-xr")
(rtags-find-file)

Lets you jump to file by name (partial or full, concept kinda stolen from gtags.el) with completion in the project. This includes all files under what we determine to be the root of the project, not just source files.

(rtags-find-virtuals-at-point)

For virtual functions, show the various reimplementations of the function at point

(rtags-fixit)

Apply clang’s automatic fixits in current file. If you pass a prefix arg use ediff to apply it. See (https://clang.llvm.org/diagnostics.html) for more info.

(rtags-imenu)

Provides an ido-based imenu like interface to a subset of the symbols in the current file. Note that it does not actually use imenu infrastructure.

(rtags-location-stack-back)
(rtags-location-stack-forward)

Whenever RTags jumps somewhere it pushes a location onto its stack. Jump back and forward in this stack

(rtags-next-match)
(rtags-previous-match)

For functions that return more than one match, jump to the next/previous one.

(rtags-preprocess-file)

Preprocess current file according to known C(XX)Flags and show the result in a buffer. If region is active only display the preprocessed output for that region.

(rtags-print-symbol-info)

Print some info about symbol under cursor

(rtags-symbol-type)

Print the type of the symbol under cursor.

(rtags-print-dependencies)

Open a buffer showing files that depend on current file/files that current file depends on.

(rtags-print-enum-value-at-point)

Print integral value of enum value at point

(rtags-quit-rdm)

Shut down rdm

(rtags-rename-symbol)

Rename symbol under cursor. Make sure all files are saved and fully indexed before using.

(rtags-reparse-file)

Explicitly trigger a reparse of current file. Mostly for debugging. Unless we have bugs it should not be necessary.

(rtags-show-rtags-buffer)

Switch to *RTags* buffer. This is the buffer where a number of functions display their alternatives when they have more than one match.

(rtags-include-file)

Insert selected or entered include, e.g. “string.h”/<string.h> in current buffer, either at the top, after the first include statement or with prefix argument (C-u) at current point.

(rtags-get-include-file-for-symbol)

Insert include for entered symbol or symbol under courser in current buffer, either at the top, after the first include statement or with prefix argument (C-u) at current point.

Variables

rtags-path

Path to rc/rdm if they’re not in $PATH.

rtags-jump-to-first-match

Similar to compilation-auto-jump-to-first-error. Whether to jump to the first match automatically when there’s more than one.

rtags-find-file-case-insensitive

Whether to match files case-insensitively

rtags-find-file-prefer-exact-match

Whether to exclude partial matches for file names when an exact match is found. E.g. /foobar.cpp /bar.cpp If rtags-find-file-prefer-exact-match is t a query for bar.cpp would only return /bar.cpp, otherwise both foobar.cpp and bar.cpp would be returned.

Fall back to other taggers

You can do something like the following to fall back to e.g. gtags if RTags doesn’t have a certain project indexed:

(defun use-rtags (&optional useFileManager)
  (and (rtags-executable-find "rc")
       (cond ((not (gtags-get-rootpath)) t)
             ((and (not (eq major-mode 'c++-mode))
                   (not (eq major-mode 'c-mode))) (rtags-has-filemanager))
             (useFileManager (rtags-has-filemanager))
             (t (rtags-is-indexed)))))

(defun tags-find-symbol-at-point (&optional prefix)
  (interactive "P")
  (if (and (not (rtags-find-symbol-at-point prefix)) rtags-last-request-not-indexed)
      (gtags-find-tag)))
(defun tags-find-references-at-point (&optional prefix)
  (interactive "P")
  (if (and (not (rtags-find-references-at-point prefix)) rtags-last-request-not-indexed)
      (gtags-find-rtag)))
(defun tags-find-symbol ()
  (interactive)
  (call-interactively (if (use-rtags) 'rtags-find-symbol 'gtags-find-symbol)))
(defun tags-find-references ()
  (interactive)
  (call-interactively (if (use-rtags) 'rtags-find-references 'gtags-find-rtag)))
(defun tags-find-file ()
  (interactive)
  (call-interactively (if (use-rtags t) 'rtags-find-file 'gtags-find-file)))
(defun tags-imenu ()
  (interactive)
  (call-interactively (if (use-rtags t) 'rtags-imenu 'idomenu)))

(define-key c-mode-base-map (kbd "M-.") (function tags-find-symbol-at-point))
(define-key c-mode-base-map (kbd "M-,") (function tags-find-references-at-point))
(define-key c-mode-base-map (kbd "M-;") (function tags-find-file))
(define-key c-mode-base-map (kbd "C-.") (function tags-find-symbol))
(define-key c-mode-base-map (kbd "C-,") (function tags-find-references))
(define-key c-mode-base-map (kbd "C-<") (function rtags-find-virtuals-at-point))
(define-key c-mode-base-map (kbd "M-i") (function tags-imenu))

(define-key global-map (kbd "M-.") (function tags-find-symbol-at-point))
(define-key global-map (kbd "M-,") (function tags-find-references-at-point))
(define-key global-map (kbd "M-;") (function tags-find-file))
(define-key global-map (kbd "C-.") (function tags-find-symbol))
(define-key global-map (kbd "C-,") (function tags-find-references))
(define-key global-map (kbd "C-<") (function rtags-find-virtuals-at-point))
(define-key global-map (kbd "M-i") (function tags-imenu))

Code Completion in Emacs:

To enable code completion in Emacs with company mode do the following:

  • Enable completions in RTags:
(setq rtags-completions-enabled t)
  • Enable company-mode
(require 'company)
(global-company-mode)
  • Add company-rtags to company-backends:
(push 'company-rtags company-backends)

This minimal init.el configuration should be enough to get completion to work.

(require 'package)
(package-initialize)
(require 'rtags)
(require 'company)

(setq rtags-completions-enabled t)
(push 'company-rtags company-backends)
(global-company-mode)
(define-key c-mode-base-map (kbd "<C-tab>") (function company-complete))

To enable completion in Emacs with auto-complete-mode do the following: …TODO…

RTags Flycheck integration

To turn on RTags Flycheck support you need to load the flycheck-rtags package.

(require 'flycheck-rtags)

Optional

You may explicitly select the RTags Flycheck checker for some major modes for better experience.

At the moment there is no customize option available to choose between rtags-diagnostics overlays or Flycheck overlays, nor is it planned right now. We recommend setting flycheck-highlighting-mode locally to nil as the RTags overlays are more accurate.

Further, Flycheck will trigger automatically, based on events, the syntax checker for the current buffer, this is however, pretty useless in conjunction with RTags. We trigger it manually because we find it gives you a better experience. To turn off the automatic Flycheck syntax checking, set the variable flycheck-check-syntax-automatically locally to nil.

(setq rtags-autostart-diagnostics t)
(defun my-flycheck-rtags-setup ()
  (flycheck-select-checker 'rtags)
  (setq-local flycheck-highlighting-mode nil) ;; RTags creates more accurate overlays.
  (setq-local flycheck-check-syntax-automatically nil))
(add-hook 'c-mode-hook #'my-flycheck-rtags-setup)
(add-hook 'c++-mode-hook #'my-flycheck-rtags-setup)
(add-hook 'objc-mode-hook #'my-flycheck-rtags-setup)

Helm integration

You can use Helm to view the result, to do so, set rtags-display-result-backend to helm. You don’t need to load helm-rtags, we do it. If you have installed RTags through MELPA you need to install helm-rtags.

(setq rtags-display-result-backend 'helm)

Ivy integration

You can use Ivy to view the result, to do so, set rtags-display-result-backend to ivy. You don’t need to load ivy-rtags, we do it. If you have installed RTags through MELPA you need to install ivy-rtags.

(setq rtags-display-result-backend 'ivy)

Support for other editors

There are several other projects integrating RTags with other editors.

Sublime Text:

Vim:

Neovim:

Atom:

Note to those maintainers. If you need RTags to behave differently or add features to make these other integration’s easier (like produce output in other formats etc), just drop us a note.

Videos

Here are some videos demonstrating how to use RTags with Emacs though some of these may be outdated:

Set up RTags

Set up symlinks and run the daemon

Project setup using make

Project setup using ninja

Navigation/references

Fixits

“IMenu” / virtuals / filenames

Rename symbol

Enums and cursor info