Home | History | Annotate | Download | only in emacs
      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)
    123