Emacs for Python and C/C++

  1. 1. Emacs version
  2. 2. Common modules
    1. 2.1. Code completion
    2. 2.2. Syntax checking
  3. 3. Python Mode
  4. 4. C/C++ Mode
    1. 4.1. The tagging system - Trials
    2. 4.2. Setting up gtags
  5. 5. Others

New configuration for the new year.

This document covers the configuration of the syntax checking and code completion for Python and C/C++ in Emacs.

Emacs version

Emacs should be >= 24.4, preferably > 25.0. Mine was 24.3 before the upgrade and it does not work with some of the packages covered next. The upgrade can be done using the standard apt-get protocol following this,

1
2
3
add-apt-repository ppa:kelleyk/emacs
apt-get update
apt-get install emacs25

Root privilege is needed. After installation, make sure the latest version is used, not the old one.

All the packages in emacs mentioned below can be installed via the package system via sources ELPA or MELPA. Details found here.

Common modules

Code completion

Let’s start with two common modules for code completion: packages yasnippets and auto-complete (AC for short). The two modules would work with most of the languages, theoretically.

Yasnippets allows the insertion of code snippets by typing in a few letters. I configured it in the following way,

1
2
3
4
(require 'yasnippet)
(yas-load-directory "path-to-yasnippet/snippets") ;; User provided snippets
(define-key yas-minor-mode-map [(tab)] nil)
(define-key yas-minor-mode-map [(backtab)] 'yas-expand)

The best part is that the users can create their own snippets.

The function of auto-complete is self-explanatory. It tries to complete a few letters with a table of candidates. Following is a basic configuration,

1
2
3
(require 'auto-complete)
(require 'auto-complete-config)
(ac-config-default)

It could be annoying if AC tries to complete every letter one types in. I disabled the automatic completion, so that I auto-complete my input when I want to,

1
2
(setq ac-auto-start nil)
(define-key ac-mode-map (kbd "your_kbd") 'auto-complete)

The default AC table could be squeezed too much by candidates of very long names. One way to avoid that is to install and use the pos-tip package.

1
(require 'pos-tip)

Syntax checking

Another necessary emacs package is flycheck as a general framework for checking the syntax. The setup is as follows,

1
2
3
4
5
(defun flycheck-kbd-map ()
(local-set-key (kbd "your_kbd") 'flycheck-buffer) ;; Check the buffer for errors
(local-set-key (kbd "your_kbd") 'flycheck-clear) ;; Clear the error labels
(local-set-key (kbd "your_kbd") 'flycheck-list-errors)) ;; List the errors in a separate window
(add-hook 'flycheck-mode-hook 'flycheck-kbd-map)

If there were too many errors, flycheck might overflow and clear up all errors. To mitigate that, raise the threshold

1
(setq flycheck-checker-error-threshold 10000)

Python Mode

Now getting to the Python-specific setups, which are based on this video.

Two emacs packages are needed: python-mode and jedi. In the meanwhile, the packages epc, jedi and pylint have to be installed in the Python environment, as the backends to jedi and flycheck in emacs. On the Python side, the installation can be done with pip.

1
pip install [--upgrade] your_packages

The .emacs setup looks like this,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(require 'python-mode)
(add-hook 'python-mode-hook 'yas-minor-mode)
(add-hook 'python-mode-hook 'flycheck-mode)
(autoload 'python-mode "python-mode" "Python Mode." t)
(require 'jedi)
(add-to-list 'ac-sources 'ac-source-jedi-direct)
(setq jedi:complete-on-dot t)
(setq jedi:tooltip-method 'pos-tip)
(defun jedi-config:setup-keys ()
(local-set-key (kbd "your_kbd") 'jedi:goto-definition)
(local-set-key (kbd "your_kbd") 'jedi:show-doc))
(add-hook 'python-mode-hook 'jedi:setup)
(add-hook 'python-mode-hook 'jedi-config:setup-keys)

If Cython is needed as well, install packages cython-mode and flycheck-cython in emacs. And the setup, (require ’cython-mode) (require ’flycheck-cython) (add-hook ’cython-mode-hook ’yas-minor-mode) (add-hook ’cython-mode-hook ’flycheck-mode) (autoload ’cython-mode “cython-mode” “Cython Mode.” t)

With the Cython mode present, the association of file extensions could be tricky. One needs to disable the default settings in the Python mode, so as to enable correct activation of cython-mode.

1
2
3
4
5
(setq auto-mode-alist (rassq-delete-all 'python-mode auto-mode-alist))
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(setq auto-mode-alist (rassq-delete-all 'cython-mode auto-mode-alist))
(add-to-list 'auto-mode-alist '("\\.pyx\\'" . cython-mode))
(add-to-list 'auto-mode-alist '("\\.pxd\\'" . cython-mode))

With the above setup, the python and cython modes are activated when and only when py files and pyx/pxd files are opened, respectively.

C/C++ Mode

The configuration to be presented is rather simple. However, the exploration of some possibilities took quite a while.

The tagging system - Trials

The center issue is the parsing of the source code, i.e. the tagging system. C/C++ code requires compilation and linking and the parsing is not as simple as that of Python. I found three options: rtags, ctags and gtags. (Well, there is also etags, which was not tried out.)

Rtags, based on LLVM/Clang, appears to be popular. Moreover, there is a cmake-ide package that integrates well with rtags and the CMake ecosystem. The best part is that it can infer all compiler flags from the cmake files. And unlike the other two tools, no extra tagging file has to be generated. The compilation of the code is also straight-forward, since everything is defined by the CMake files. The rtags-based tools in emacs can be easily found using command package-list-packages.

One example setup of the cmake-ide mode can be found here. I also tried a similar setup, which requires cmake-ide and its dependencies,

1
2
3
4
(require 'rtags)
(require 'cmake-ide)
(cmake-ide-setup)
(setq cmake-ide-flags-c++ (append '("-std=c++11")))

However, one year later, the same author switched to another set of tools that is light-weight. I ditched the rtags approach too, after trying for half an hour. The installation of rtags is OK, only took 2.5 hours. The running of rtags is painful - it uses up all allowable resources. The author used a combination of ctags and counsel-etags. This combination had certain minor problems on my machine. So I continued to look for other solutions.

Then there comes the gtags-based approach. Two configurations that are more or less equivalent are discussed. One is based on helm-gtags, the other ggtags. I tried the setup with helm-gtags,

1
2
3
4
5
6
7
(add-hook 'c-mode-hook 'helm-gtags-mode)
(add-hook 'c++-mode-hook 'helm-gtags-mode)
(eval-after-load "helm-gtags"
'(progn
(define-key helm-gtags-mode-map (kbd "your_kbd") 'helm-gtags-dwim)
(define-key helm-gtags-mode-map (kbd "your_kbd") 'helm-gtags-pop-stack)
(define-key helm-gtags-mode-map (kbd "your_kbd") 'helm-gtags-update-tags)))

It works, but not so stable on my system. Sometimes the parse fails without a good reason.

Finally ggtags is down-selected.

Setting up gtags

The command line tool gtags can be downloaded from here and the installation procedure is standard. In emacs, the packages company and ggtags are required. Basically company calls ggtags via company-capf for code completion. AC is replaced by company, as the latter works with gtags better than AC. The setup is as follows,

1
2
3
4
5
6
7
8
(defun company-kbd-map ()
(local-set-key (kbd "your_kbd") 'company-complete)) ;; Just like auto-complete
(add-hook 'company-mode-hook 'company-kbd-map)
(defun ggtags-kbd-map ()
(local-set-key (kbd "your_kbd") 'ggtags-find-tag-dwim) ;; Jump to definition
(local-set-key (kbd "your_kbd") 'ggtags-prev-mark) ;; Return to the file before jumping
(local-set-key (kbd "your_kbd") 'ggtags-update-tags)) ;; Refresh the tagging files
(add-hook 'ggtags-mode-hook 'ggtags-kbd-map)

Since company is used instead of AC, AC needs to be turned off explicitly in C/C++ modes. Yasnippets and flycheck are used as well. Particularly, flycheck for c++-mode is to set for the C++11 standard.

1
2
3
4
5
6
7
8
9
10
(add-hook 'c-mode-common-hook
(lambda ()
(when (derived-mode-p 'c-mode 'c++-mode)
(auto-complete-mode 0)
(yas-minor-mode 1)
(flycheck-mode 1)
(ggtags-mode 1)
(company-mode 1))))
(add-hook 'c++-mode-hook
(lambda () (setq flycheck-gcc-language-standard "c++11")))

Others

I do recommend the solarized color theme, which requires packages color-theme and color-theme-solarized. For emacs >= 24, activate by

1
(load-theme 'solarized t)

Other references:

  1. auto-complete
  2. flycheck
  3. emacswiki for Python