(or emacs irrelevant)

Using Emacs as a C++ IDE

Recently, I've had to code some C++ at work. And I saw it as a good opportunity to step up my Emacs' IDE game. I've eschewed clang-based tools until now, but GCC isn't adding AST support any time soon, and CEDET is too slow and too clumsy with macros for the particular project that I had. Here's the line in Eigen that broke the camel's back. Basically it's 30 lines of macros that expand to 30 lines of typedefs. Maybe it's a valid implementation choice, I'd rather avoid the macros altogether, but in any case I couldn't get CEDET to parse that.

Use Rtags for navigation

The first thing I tried was rtags. My project was CMake-based, so I just put this line in my subdirectory Makefile:

cmake:
    cd ../build && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..

The -DCMAKE_EXPORT_COMPILE_COMMANDS=1 causes a compile_commands.json file to be emitted during the actual compilation. This file describes the compile flags for every source file. These flags are essential in helping the parser understand what's going on.

Then, in the build directory I start:

rdm & rc -J .

Finally, rtags-find-symbol-at-point should work now. I still like to use CEDET as backup, it's pretty good at tracking variables defined in the current function:

(defun ciao-goto-symbol ()
  (interactive)
  (deactivate-mark)
  (ring-insert find-tag-marker-ring (point-marker))
  (or (and (require 'rtags nil t)
           (rtags-find-symbol-at-point))
      (and (require 'semantic/ia)
           (condition-case nil
               (semantic-ia-fast-jump (point))
             (error nil)))))
(define-key c++-mode-map (kbd "M-.") 'ciao-goto-symbol)
(define-key c++-mode-map (kbd "M-,") 'pop-tag-mark)

For my other C++ projects which aren't CMake-based, I use the excellent bear tool to emit the compile_commands.json file. It's as easy as:

make clean
bear make

Use Irony for completion

It didn't take long to figure out that rtags isn't great at completion. I almost accepted that's just the way it is. But this morning I decided to make some changes and try irony-mode. And it worked beautifully for completion! What's ironic, is that irony-mode doesn't have goto-symbol, so the time spent to figure out rtags was worth it.

Here's my Irony setup; I only changed the C-M-i binding to the newly written counsel-irony, now available in the counsel package on MELPA:

(add-hook 'c++-mode-hook 'irony-mode)
(add-hook 'c-mode-hook 'irony-mode)

(defun my-irony-mode-hook ()
  (define-key irony-mode-map
      [remap completion-at-point] 'counsel-irony)
  (define-key irony-mode-map
      [remap complete-symbol] 'counsel-irony))
(add-hook 'irony-mode-hook 'my-irony-mode-hook)
(add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options)

And here are some screenshots of counsel-irony:

screenshot-1

First of all, the completion is displayed inline, similarly to modern IDEs. You can use all of Ivy's regex tricks to complete your candidate:

screenshot-2

Note how the power of regex matching allows me to narrow the initial 1622 candidates to only 22 functions that have src1 and src2 as arguments. One of the candidates is cut off for being longer than the window width. You can still match against the invisible text, but you won't see it. It's possible to use C-c C-o (ivy-occur) to store the current candidates into a buffer:

screenshot-3

Clicking the mouse on any of the lines in the new buffer will insert the appropriate symbol into the C++ buffer.

Outro

I'd like to thank the authors of rtags and irony-mode for these nice packages. Hopefully, counsel-irony is a nice addition. Happy hacking!