flymake-chromium.el 5.3 KB

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