[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / tools / emacs / flymake-chromium.el
blob91aac410ff5707c9e7b02ff8f9edc88678479196
1 ;; Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 ;; Use of this source code is governed by a BSD-style license that can be
3 ;; found in the LICENSE file.
5 ;; Set up flymake for use with chromium code. Uses ninja (since none of the
6 ;; other chromium build systems have latency that allows interactive use).
7 ;;
8 ;; Requires a modern emacs (GNU Emacs >= 23) and that gyp has already generated
9 ;; the build.ninja file(s). See defcustoms below for settable knobs.
12 (require 'flymake)
14 (defcustom cr-flymake-ninja-build-file "out/Debug/build.ninja"
15 "Relative path from chromium's src/ directory to the
16 build.ninja file to use.")
18 (defcustom cr-flymake-ninja-executable "ninja"
19 "Ninja executable location; either in $PATH or explicitly given.")
21 (defun cr-flymake-absbufferpath ()
22 "Return the absolute path to the current buffer, or nil if the
23 current buffer has no path."
24 (when buffer-file-truename
25 (expand-file-name buffer-file-truename)))
27 (defun cr-flymake-chromium-src ()
28 "Return chromium's src/ directory, or nil on failure."
29 (let ((srcdir (locate-dominating-file
30 (cr-flymake-absbufferpath) cr-flymake-ninja-build-file)))
31 (when srcdir (expand-file-name srcdir))))
33 (defun cr-flymake-string-prefix-p (prefix str)
34 "Return non-nil if PREFIX is a prefix of STR (23.2 has string-prefix-p but
35 that's case insensitive and also 23.1 doesn't have it)."
36 (string= prefix (substring str 0 (length prefix))))
38 (defun cr-flymake-current-file-name ()
39 "Return the relative path from chromium's src/ directory to the
40 file backing the current buffer or nil if it doesn't look like
41 we're under chromium/src/."
42 (when (and (cr-flymake-chromium-src)
43 (cr-flymake-string-prefix-p
44 (cr-flymake-chromium-src) (cr-flymake-absbufferpath)))
45 (substring (cr-flymake-absbufferpath) (length (cr-flymake-chromium-src)))))
47 (defun cr-flymake-from-build-to-src-root ()
48 "Return a path fragment for getting from the build.ninja file to src/."
49 (replace-regexp-in-string
50 "[^/]+" ".."
51 (substring
52 (file-name-directory
53 (file-truename (or (and (cr-flymake-string-prefix-p
54 "/" cr-flymake-ninja-build-file)
55 cr-flymake-ninja-build-file)
56 (concat (cr-flymake-chromium-src)
57 cr-flymake-ninja-build-file))))
58 (length (cr-flymake-chromium-src)))))
60 (defun cr-flymake-getfname (file-name-from-error-message)
61 "Strip cruft from the passed-in filename to help flymake find the real file."
62 (file-name-nondirectory file-name-from-error-message))
64 (defun cr-flymake-ninja-command-line ()
65 "Return the command-line for running ninja, as a list of strings, or nil if
66 we're not during a save"
67 (unless (buffer-modified-p)
68 (list cr-flymake-ninja-executable
69 (list "-C"
70 (concat (cr-flymake-chromium-src)
71 (file-name-directory cr-flymake-ninja-build-file))
72 (concat (cr-flymake-from-build-to-src-root)
73 (cr-flymake-current-file-name) "^")))))
75 (defun cr-flymake-kick-off-check-after-save ()
76 "Kick off a syntax check after file save, if flymake-mode is on."
77 (when flymake-mode (flymake-start-syntax-check)))
79 (defadvice next-error (around cr-flymake-next-error activate)
80 "If flymake has something to say, let it say it; otherwise
81 revert to normal next-error behavior."
82 (if (not flymake-err-info)
83 (condition-case msg
84 ad-do-it
85 (error (message "%s" (prin1-to-string msg))))
86 (flymake-goto-next-error)
87 ;; copy/pasted from flymake-display-err-menu-for-current-line because I
88 ;; couldn't find a way to have it tell me what the relevant error for this
89 ;; line was in a single call:
90 (let* ((line-no (flymake-current-line-no))
91 (line-err-info-list
92 (nth 0 (flymake-find-err-info flymake-err-info line-no)))
93 (menu-data (flymake-make-err-menu-data line-no line-err-info-list)))
94 (prin1 (car (car (car (cdr menu-data)))) t))))
96 (defun cr-flymake-find-file ()
97 "Enable flymake, but only if it makes sense, and immediately
98 disable timer-based execution."
99 (when (and (not flymake-mode)
100 (not buffer-read-only)
101 (cr-flymake-current-file-name))
102 ;; Since flymake-allowed-file-name-masks requires static regexps to match
103 ;; against, can't use cr-flymake-chromium-src here. Instead we add a
104 ;; generic regexp, but only to a buffer-local version of the variable.
105 (set (make-local-variable 'flymake-allowed-file-name-masks)
106 (list (list "\\.c\\(\\|c\\|pp\\)"
107 'cr-flymake-ninja-command-line
108 'ignore
109 'cr-flymake-getfname)))
110 (flymake-find-file-hook)
111 (if flymake-mode
112 (cancel-timer flymake-timer)
113 (kill-local-variable 'flymake-allowed-file-name-masks))))
115 (defun cr-compile ()
116 "Run the interactive compile command with the working directory
117 set to src/."
118 (interactive)
119 (let ((default-directory (cr-flymake-chromium-src)))
120 (call-interactively 'compile)))
122 (add-hook 'find-file-hook 'cr-flymake-find-file 'append)
123 (add-hook 'after-save-hook 'cr-flymake-kick-off-check-after-save)
125 ;; Show flymake infrastructure ERRORs in hopes of fixing them. Set to 3 for
126 ;; DEBUG-level output from flymake.el.
127 (setq flymake-log-level 0)
129 (provide 'flymake-chromium)