- add sources.
[platform/framework/web/crosswalk.git] / src / tools / emacs / flymake-chromium.el
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.
4
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.
10
11
12 (require 'flymake)
13
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.")
17
18 (defcustom cr-flymake-ninja-executable "ninja"
19   "Ninja executable location; either in $PATH or explicitly given.")
20
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)))
26
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))))
32
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))))
37
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)))))
46
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)))))
59
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))
63
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) "^")))))
74
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)))
78
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))))
95
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))))
114
115 (add-hook 'find-file-hook 'cr-flymake-find-file 'append)
116 (add-hook 'after-save-hook 'cr-flymake-kick-off-check-after-save)
117
118 ;; Show flymake infrastructure ERRORs in hopes of fixing them.  Set to 3 for
119 ;; DEBUG-level output from flymake.el.
120 (setq flymake-log-level 0)
121
122 (provide 'flymake-chromium)