15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; Set up flymake for use with chromium code.  Uses ninja (since none of the
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; other chromium build systems have latency that allows interactive use).
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);;
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; Requires a modern emacs (GNU Emacs >= 23) and that gyp has already generated
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; the build.ninja file(s).  See defcustoms below for settable knobs.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(require 'flymake)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defcustom cr-flymake-ninja-build-file "out/Debug/build.ninja"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Relative path from chromium's src/ directory to the
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  build.ninja file to use.")
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defcustom cr-flymake-ninja-executable "ninja"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Ninja executable location; either in $PATH or explicitly given.")
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-absbufferpath ()
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Return the absolute path to the current buffer, or nil if the
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current buffer has no path."
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (when buffer-file-truename
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (expand-file-name buffer-file-truename)))
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-chromium-src ()
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Return chromium's src/ directory, or nil on failure."
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (let ((srcdir (locate-dominating-file
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 (cr-flymake-absbufferpath) cr-flymake-ninja-build-file)))
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (when srcdir (expand-file-name srcdir))))
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-string-prefix-p (prefix str)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Return non-nil if PREFIX is a prefix of STR (23.2 has string-prefix-p but
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  that's case insensitive and also 23.1 doesn't have it)."
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (string= prefix (substring str 0 (length prefix))))
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-current-file-name ()
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Return the relative path from chromium's src/ directory to the
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file backing the current buffer or nil if it doesn't look like
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  we're under chromium/src/."
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (when (and (cr-flymake-chromium-src)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             (cr-flymake-string-prefix-p
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (cr-flymake-chromium-src) (cr-flymake-absbufferpath)))
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (substring (cr-flymake-absbufferpath) (length (cr-flymake-chromium-src)))))
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-from-build-to-src-root ()
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Return a path fragment for getting from the build.ninja file to src/."
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (replace-regexp-in-string
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   "[^/]+" ".."
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   (substring
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (file-name-directory
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     (file-truename (or (and (cr-flymake-string-prefix-p
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              "/" cr-flymake-ninja-build-file)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             cr-flymake-ninja-build-file)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        (concat (cr-flymake-chromium-src)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                cr-flymake-ninja-build-file))))
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (length (cr-flymake-chromium-src)))))
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-getfname (file-name-from-error-message)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Strip cruft from the passed-in filename to help flymake find the real file."
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (file-name-nondirectory file-name-from-error-message))
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-ninja-command-line ()
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Return the command-line for running ninja, as a list of strings, or nil if
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  we're not during a save"
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (unless (buffer-modified-p)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (list cr-flymake-ninja-executable
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (list "-C"
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                (concat (cr-flymake-chromium-src)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        (file-name-directory cr-flymake-ninja-build-file))
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                (concat (cr-flymake-from-build-to-src-root)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        (cr-flymake-current-file-name) "^")))))
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-kick-off-check-after-save ()
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Kick off a syntax check after file save, if flymake-mode is on."
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (when flymake-mode (flymake-start-syntax-check)))
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defadvice next-error (around cr-flymake-next-error activate)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "If flymake has something to say, let it say it; otherwise
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   revert to normal next-error behavior."
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (if (not flymake-err-info)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (condition-case msg
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ad-do-it
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (error (message "%s" (prin1-to-string msg))))
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (flymake-goto-next-error)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ;; copy/pasted from flymake-display-err-menu-for-current-line because I
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ;; couldn't find a way to have it tell me what the relevant error for this
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ;; line was in a single call:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (let* ((line-no (flymake-current-line-no))
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           (line-err-info-list
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (nth 0 (flymake-find-err-info flymake-err-info line-no)))
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           (menu-data (flymake-make-err-menu-data line-no line-err-info-list)))
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (prin1 (car (car (car (cdr menu-data)))) t))))
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(defun cr-flymake-find-file ()
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "Enable flymake, but only if it makes sense, and immediately
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  disable timer-based execution."
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (when (and (not flymake-mode)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             (not buffer-read-only)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             (cr-flymake-current-file-name))
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ;; Since flymake-allowed-file-name-masks requires static regexps to match
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ;; against, can't use cr-flymake-chromium-src here.  Instead we add a
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ;; generic regexp, but only to a buffer-local version of the variable.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (set (make-local-variable 'flymake-allowed-file-name-masks)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (list (list "\\.c\\(\\|c\\|pp\\)"
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     'cr-flymake-ninja-command-line
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     'ignore
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     'cr-flymake-getfname)))
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (flymake-find-file-hook)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (if flymake-mode
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (cancel-timer flymake-timer)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (kill-local-variable 'flymake-allowed-file-name-masks))))
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(add-hook 'find-file-hook 'cr-flymake-find-file 'append)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(add-hook 'after-save-hook 'cr-flymake-kick-off-check-after-save)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; Show flymake infrastructure ERRORs in hopes of fixing them.  Set to 3 for
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles);; DEBUG-level output from flymake.el.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(setq flymake-log-level 0)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(provide 'flymake-chromium)
123