blob: 1dc555a94bdbaee94195ba53d95fb351383ad3ad [file] [log] [blame] [view]
# Emacs
## Debugging
[Linux Debugging]( has some Emacs-specific debugging tips.
## Syntax-error Highlighting
[Ninja]( users get in-line highlighting of syntax errors using
`flymake.el` on each buffer-save:
(load-file "src/tools/emacs/flymake-chromium.el")
## [ycmd]( (YouCompleteMe) + flycheck
[emacs-ycmd]( in combination with
flycheck provides:
* advanced code completion
* syntax checking
* navigation to declarations and definitions (using `ycmd-goto`) based on
on-the-fly processing using clang. A quick demo video showing code
completion and flycheck highlighting a missing semicolon syntax error:
[![video preview][img]][video]
### Requirements
* Your build system is set up for building with clang or wrapper+clang
### Setup
1. Clone, update external git repositories and ycmd from into a directory, e.g. `~/dev/ycmd`
1. Test `ycmd` by running `~/dev/ycmd$ python ycmd/` You should see
`KeyError: 'hmac_secret'`
1. Install the following packages to emacs, for example from melpa:
* `ycmd`
* `company-ycmd`
* `flycheck-ycmd`
1. [More info on configuring emacs-ycmd](
1. Assuming your checkout of Chromium is in `~/dev/blink`, i.e. this is the
directory in which you find the `src`folder, create a symbolic link as
cd ~/dev/blink
ln -s src/tools/vim/
1. Add something like the following to your `init.el`
;; ycmd
;;; Googlers can replace a lot of this with (require 'google-ycmd).
(require 'ycmd)
(require 'company-ycmd)
(require 'flycheck-ycmd)
;; Show completions after 0.15 seconds
(setq company-idle-delay 0.15)
;; Activate for editing C++ files
(add-hook 'c++-mode-hook 'ycmd-mode)
(add-hook 'c++-mode-hook 'company-mode)
(add-hook 'c++-mode-hook 'flycheck-mode)
;; Replace the directory information with where you downloaded ycmd to
(set-variable 'ycmd-server-command (list "python" (substitute-in-file-name "$HOME/dev/ycmd/ycmd/")))
;; Edit according to where you have your Chromium/Blink checkout
(add-to-list 'ycmd-extra-conf-whitelist (substitute-in-file-name "$HOME/dev/blink/"))
;; Show flycheck errors in idle-mode as well
(setq ycmd-parse-conditions '(save new-line mode-enabled idle-change))
;; Makes emacs-ycmd less verbose
(setq url-show-status nil)
### Troubleshooting
* If no completions show up or emacs reports errors, you can check the
`*ycmd-server*` buffer for errors. See the next bullet point for how to
handle "OS Error: No such file or directory"
* Launching emacs from an OS menu might result in a different environment so
that `ycmd` does not find ninja. In that case, you can use a package like
[exec-path from shell]( and
add the following to your `init.el`:
(require 'exec-path-from-shell)
(when (memq window-system '(mac ns x))
## ff-get-other-file
There's a builtin function called `ff-get-other-file` which will get the "other
file" based on file extension. I have this bound to C-o in c-mode
(`(local-set-key "\C-o" 'ff-get-other-file)`). While "other file" is per-mode
defined, in c-like languages it means jumping between the header and the source
file. So I switch back and forth between the header and the source with C-o. If
we had separate include/ and src/ directories, this would be a pain to setup,
but this might just work out of the box for you. See the documentation for the
variable `cc-other-file-alist` for more information.
One drawback of ff-get-other-file is that it will always switch to a matching
buffer, even if the other file is in a different directory, so if you have,A.h, then ff-get-other-file will switch to A.h from rather
than load A.h(2) from the appropriate directory. If you prefer something (C
specific) that always finds, try this:
(defun cc-other-file()
"Toggles source/header file"
(let ((buf (current-buffer))
(name (file-name-sans-extension (buffer-file-name)))
(cadr (assoc (concat "\\."
(file-name-extension (buffer-file-name))
(dolist (e other-extens)
(if (let ((f (concat name e)))
(and (file-exists-p f) (find-file f)))
_Note: if you know an easy way to change the ff-get-other-file behavior, please
replace this hack with that solution! - stevenjb@chromium.org_
## Use Google's C++ style!
We have an emacs module,
which adds c-mode formatting. Then add to your .emacs:
(load "/<path/to/chromium>/src/buildtools/clang_format/script/clang-format.el")
(add-hook 'c-mode-common-hook
(function (lambda () (local-set-key (kbd "TAB") 'clang-format-region))))
Now, you can use the
key to format the current line (even a long line) or region.
## Highlight long lines
One nice way to highlight long lines and other style issues:
(require 'whitespace)
(setq whitespace-style '(face indentation trailing empty lines-tail))
(setq whitespace-line-column nil)
(set-face-attribute 'whitespace-line nil
:background "purple"
:foreground "white"
:weight 'bold)
(global-whitespace-mode 1)
Note: You might need to grab the latest version of
## gyp
### `gyp` style
There is a gyp mode that provides basic indentation and font-lock (syntax
highlighting) support. The mode derives from python.el (bundled with newer
You can find it in /src/tools/gyp/tools/emacs
See the README file there for installation instructions.
**Important**: the mode is only tested with `python.el` (bundled with newer
emacsen), not with `python-mode.el` (outdated and less maintained these days).
### deep nesting
A couple of helpers that show a summary of where you are; the first by tracing
the indentation hierarchy upwards, the second by only showing `#if`s and
`#else`s that are relevant to the current line:
(defun ami-summarize-indentation-at-point ()
"Echo a summary of how one gets from the left-most column to
POINT in terms of indentation changes."
(let ((cur-indent most-positive-fixnum)
(trace '()))
(while (not (bobp))
(let ((current-line (buffer-substring (line-beginning-position)
(when (and (not (string-match "^\\s-*$" current-line))
(< (current-indentation) cur-indent))
(setq cur-indent (current-indentation))
(setq trace (cons current-line trace))
(if (or (string-match "^\\s-*}" current-line)
(string-match "^\\s-*else " current-line)
(string-match "^\\s-*elif " current-line))
(setq cur-indent (1+ cur-indent)))))
(forward-line -1))
(message "%s" (mapconcat 'identity trace "\n")))))
(require 'cl)
(defun ami-summarize-preprocessor-branches-at-point ()
"Summarize the C preprocessor branches needed to get to point."
(flet ((current-line-text ()
(buffer-substring (line-beginning-position) (line-end-position))))
(let ((eol (or (end-of-line) (point)))
deactivate-mark directives-stack)
(goto-char (point-min))
(while (re-search-forward "^#\\(if\\|else\\|endif\\)" eol t)
(if (or (string-prefix-p "#if" (match-string 0))
(string-prefix-p "#else" (match-string 0)))
(push (current-line-text) directives-stack)
(if (string-prefix-p "#endif" (match-string 0))
(while (string-prefix-p "#else" (pop directives-stack)) t))))
(message "%s" (mapconcat 'identity (reverse directives-stack) "\n"))))))
## find-things-fast
erg wrote a suite of tools that do common operations from the root of your
repository, called
[Find Things Fast]( It contains
ido completion over `git ls-files` (or the svn find equivalent) and `grepsource`
that only git greps files with extensions we care about (or the equivalent the
`find | xargs grep` statement in non-git repos.)
## vc-mode and find-file performance
When you first open a file under git control, vc mode kicks in and does a high
level stat of your git repo. For huge repos, especially WebKit and Chromium,
this makes opening a file take literally seconds. This snippet disables VC git
for chrome directories:
; Turn off VC git for chrome
(when (locate-library "vc")
(defadvice vc-registered (around nochrome-vc-registered (file))
(message (format "nochrome-vc-registered %s" file))
(if (string-match ".*chrome/src.*" file)
(message (format "Skipping VC mode for %s" % file))
(setq ad-return-value nil)
(ad-activate 'vc-registered)
## git tools
We're collecting Chrome-specific tools under `tools/emacs`. See the files there
for details.
* `trybot.el`: import Windows trybot output into a `compilation-mode` buffer.
## ERC for IRC
See [ErcIrc](
* Figure out how to make `M-x compile` default to
`cd /path/to/chrome/root; make -r chrome`.