flymake.el 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645
  1. ;;; flymake.el --- a universal on-the-fly syntax checker -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2003-2015 Free Software Foundation, Inc.
  3. ;; Author: Pavel Kobyakov <pk_at_work@yahoo.com>
  4. ;; Maintainer: Leo Liu <sdl.web@gmail.com>
  5. ;; Version: 0.3
  6. ;; Keywords: c languages tools
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;;
  20. ;; Flymake is a minor Emacs mode performing on-the-fly syntax checks
  21. ;; using the external syntax check tool (for C/C++ this is usually the
  22. ;; compiler).
  23. ;;; Bugs/todo:
  24. ;; - Only uses "Makefile", not "makefile" or "GNUmakefile"
  25. ;; (from http://bugs.debian.org/337339).
  26. ;;; Code:
  27. (eval-when-compile (require 'cl-lib))
  28. (defgroup flymake nil
  29. "Universal on-the-fly syntax checker."
  30. :version "23.1"
  31. :link '(custom-manual "(flymake) Top")
  32. :group 'tools)
  33. (defcustom flymake-error-bitmap '(exclamation-mark error)
  34. "Bitmap (a symbol) used in the fringe for indicating errors.
  35. The value may also be a list of two elements where the second
  36. element specifies the face for the bitmap. For possible bitmap
  37. symbols, see `fringe-bitmaps'. See also `flymake-warning-bitmap'.
  38. The option `flymake-fringe-indicator-position' controls how and where
  39. this is used."
  40. :group 'flymake
  41. :version "24.3"
  42. :type '(choice (symbol :tag "Bitmap")
  43. (list :tag "Bitmap and face"
  44. (symbol :tag "Bitmap")
  45. (face :tag "Face"))))
  46. (defcustom flymake-warning-bitmap 'question-mark
  47. "Bitmap (a symbol) used in the fringe for indicating warnings.
  48. The value may also be a list of two elements where the second
  49. element specifies the face for the bitmap. For possible bitmap
  50. symbols, see `fringe-bitmaps'. See also `flymake-error-bitmap'.
  51. The option `flymake-fringe-indicator-position' controls how and where
  52. this is used."
  53. :group 'flymake
  54. :version "24.3"
  55. :type '(choice (symbol :tag "Bitmap")
  56. (list :tag "Bitmap and face"
  57. (symbol :tag "Bitmap")
  58. (face :tag "Face"))))
  59. (defcustom flymake-fringe-indicator-position 'left-fringe
  60. "The position to put flymake fringe indicator.
  61. The value can be nil (do not use indicators), `left-fringe' or `right-fringe'.
  62. See `flymake-error-bitmap' and `flymake-warning-bitmap'."
  63. :group 'flymake
  64. :version "24.3"
  65. :type '(choice (const left-fringe)
  66. (const right-fringe)
  67. (const :tag "No fringe indicators" nil)))
  68. (defcustom flymake-compilation-prevents-syntax-check t
  69. "If non-nil, don't start syntax check if compilation is running."
  70. :group 'flymake
  71. :type 'boolean)
  72. (defcustom flymake-start-syntax-check-on-newline t
  73. "Start syntax check if newline char was added/removed from the buffer."
  74. :group 'flymake
  75. :type 'boolean)
  76. (defcustom flymake-no-changes-timeout 0.5
  77. "Time to wait after last change before starting compilation."
  78. :group 'flymake
  79. :type 'number)
  80. (defcustom flymake-gui-warnings-enabled t
  81. "Enables/disables GUI warnings."
  82. :group 'flymake
  83. :type 'boolean)
  84. (defcustom flymake-start-syntax-check-on-find-file t
  85. "Start syntax check on find file."
  86. :group 'flymake
  87. :type 'boolean)
  88. (defcustom flymake-log-level -1
  89. "Logging level, only messages with level lower or equal will be logged.
  90. -1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG"
  91. :group 'flymake
  92. :type 'integer)
  93. (defcustom flymake-xml-program
  94. (if (executable-find "xmlstarlet") "xmlstarlet" "xml")
  95. "Program to use for XML validation."
  96. :type 'file
  97. :group 'flymake
  98. :version "24.4")
  99. (defcustom flymake-master-file-dirs '("." "./src" "./UnitTest")
  100. "Dirs where to look for master files."
  101. :group 'flymake
  102. :type '(repeat (string)))
  103. (defcustom flymake-master-file-count-limit 32
  104. "Max number of master files to check."
  105. :group 'flymake
  106. :type 'integer)
  107. (defcustom flymake-allowed-file-name-masks
  108. '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init)
  109. ("\\.xml\\'" flymake-xml-init)
  110. ("\\.html?\\'" flymake-xml-init)
  111. ("\\.cs\\'" flymake-simple-make-init)
  112. ("\\.p[ml]\\'" flymake-perl-init)
  113. ("\\.php[345]?\\'" flymake-php-init)
  114. ("\\.h\\'" flymake-master-make-header-init flymake-master-cleanup)
  115. ("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup)
  116. ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup)
  117. ("\\.tex\\'" flymake-simple-tex-init)
  118. ("\\.idl\\'" flymake-simple-make-init)
  119. ;; ("\\.cpp\\'" 1)
  120. ;; ("\\.java\\'" 3)
  121. ;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'")
  122. ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2))
  123. ;; ("\\.idl\\'" 1)
  124. ;; ("\\.odl\\'" 1)
  125. ;; ("[0-9]+\\.tex\\'" 2 ("\\.tex\\'")
  126. ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 ))
  127. ;; ("\\.tex\\'" 1)
  128. )
  129. "Files syntax checking is allowed for.
  130. This is an alist with elements of the form:
  131. REGEXP INIT [CLEANUP [NAME]]
  132. REGEXP is a regular expression that matches a file name.
  133. INIT is the init function to use.
  134. CLEANUP is the cleanup function to use, default `flymake-simple-cleanup'.
  135. NAME is the file name function to use, default `flymake-get-real-file-name'."
  136. :group 'flymake
  137. :type '(alist :key-type (regexp :tag "File regexp")
  138. :value-type
  139. (list :tag "Handler functions"
  140. (function :tag "Init function")
  141. (choice :tag "Cleanup function"
  142. (const :tag "flymake-simple-cleanup" nil)
  143. function)
  144. (choice :tag "Name function"
  145. (const :tag "flymake-get-real-file-name" nil)
  146. function))))
  147. (defvar-local flymake-is-running nil
  148. "If t, flymake syntax check process is running for the current buffer.")
  149. (defvar-local flymake-timer nil
  150. "Timer for starting syntax check.")
  151. (defvar-local flymake-last-change-time nil
  152. "Time of last buffer change.")
  153. (defvar-local flymake-check-start-time nil
  154. "Time at which syntax check was started.")
  155. (defvar-local flymake-check-was-interrupted nil
  156. "Non-nil if syntax check was killed by `flymake-compile'.")
  157. (defvar-local flymake-err-info nil
  158. "Sorted list of line numbers and lists of err info in the form (file, err-text).")
  159. (defvar-local flymake-new-err-info nil
  160. "Same as `flymake-err-info', effective when a syntax check is in progress.")
  161. (defun flymake-log (level text &rest args)
  162. "Log a message at level LEVEL.
  163. If LEVEL is higher than `flymake-log-level', the message is
  164. ignored. Otherwise, it is printed using `message'.
  165. TEXT is a format control string, and the remaining arguments ARGS
  166. are the string substitutions (see the function `format')."
  167. (if (<= level flymake-log-level)
  168. (let* ((msg (apply #'format-message text args)))
  169. (message "%s" msg))))
  170. (defun flymake-ins-after (list pos val)
  171. "Insert VAL into LIST after position POS.
  172. POS counts from zero."
  173. (let ((tmp (copy-sequence list)))
  174. (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp)))
  175. tmp))
  176. (defun flymake-set-at (list pos val)
  177. "Set VAL at position POS in LIST.
  178. POS counts from zero."
  179. (let ((tmp (copy-sequence list)))
  180. (setcar (nthcdr pos tmp) val)
  181. tmp))
  182. (defvar flymake-processes nil
  183. "List of currently active flymake processes.")
  184. (defvar-local flymake-output-residual nil)
  185. (defun flymake-get-file-name-mode-and-masks (file-name)
  186. "Return the corresponding entry from `flymake-allowed-file-name-masks'."
  187. (unless (stringp file-name)
  188. (error "Invalid file-name"))
  189. (let ((fnm flymake-allowed-file-name-masks)
  190. (mode-and-masks nil))
  191. (while (and (not mode-and-masks) fnm)
  192. (if (string-match (car (car fnm)) file-name)
  193. (setq mode-and-masks (cdr (car fnm))))
  194. (setq fnm (cdr fnm)))
  195. (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks))
  196. mode-and-masks))
  197. (defun flymake-can-syntax-check-file (file-name)
  198. "Determine whether we can syntax check FILE-NAME.
  199. Return nil if we cannot, non-nil if we can."
  200. (if (flymake-get-init-function file-name) t nil))
  201. (defun flymake-get-init-function (file-name)
  202. "Return init function to be used for the file."
  203. (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name))))
  204. ;;(flymake-log 0 "calling %s" init-f)
  205. ;;(funcall init-f (current-buffer))
  206. init-f))
  207. (defun flymake-get-cleanup-function (file-name)
  208. "Return cleanup function to be used for the file."
  209. (or (nth 1 (flymake-get-file-name-mode-and-masks file-name))
  210. 'flymake-simple-cleanup))
  211. (defun flymake-get-real-file-name-function (file-name)
  212. (or (nth 2 (flymake-get-file-name-mode-and-masks file-name))
  213. 'flymake-get-real-file-name))
  214. (defvar flymake-find-buildfile-cache (make-hash-table :test #'equal))
  215. (defun flymake-get-buildfile-from-cache (dir-name)
  216. "Look up DIR-NAME in cache and return its associated value.
  217. If DIR-NAME is not found, return nil."
  218. (gethash dir-name flymake-find-buildfile-cache))
  219. (defun flymake-add-buildfile-to-cache (dir-name buildfile)
  220. "Associate DIR-NAME with BUILDFILE in the buildfile cache."
  221. (puthash dir-name buildfile flymake-find-buildfile-cache))
  222. (defun flymake-clear-buildfile-cache ()
  223. "Clear the buildfile cache."
  224. (clrhash flymake-find-buildfile-cache))
  225. (defun flymake-find-buildfile (buildfile-name source-dir-name)
  226. "Find buildfile starting from current directory.
  227. Buildfile includes Makefile, build.xml etc.
  228. Return its file name if found, or nil if not found."
  229. (or (flymake-get-buildfile-from-cache source-dir-name)
  230. (let* ((file (locate-dominating-file source-dir-name buildfile-name)))
  231. (if file
  232. (progn
  233. (flymake-log 3 "found buildfile at %s" file)
  234. (flymake-add-buildfile-to-cache source-dir-name file)
  235. file)
  236. (progn
  237. (flymake-log 3 "buildfile for %s not found" source-dir-name)
  238. nil)))))
  239. (defun flymake-fix-file-name (name)
  240. "Replace all occurrences of ‘\\’ with ‘/’."
  241. (when name
  242. (setq name (expand-file-name name))
  243. (setq name (abbreviate-file-name name))
  244. (setq name (directory-file-name name))
  245. name))
  246. (defun flymake-same-files (file-name-one file-name-two)
  247. "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file.
  248. Return t if so, nil if not."
  249. (equal (flymake-fix-file-name file-name-one)
  250. (flymake-fix-file-name file-name-two)))
  251. ;; This is bound dynamically to pass a parameter to a sort predicate below
  252. (defvar flymake-included-file-name)
  253. (defun flymake-find-possible-master-files (file-name master-file-dirs masks)
  254. "Find (by name and location) all possible master files.
  255. Name is specified by FILE-NAME and location is specified by
  256. MASTER-FILE-DIRS. Master files include .cpp and .c for .h.
  257. Files are searched for starting from the .h directory and max
  258. max-level parent dirs. File contents are not checked."
  259. (let* ((dirs master-file-dirs)
  260. (files nil)
  261. (done nil))
  262. (while (and (not done) dirs)
  263. (let* ((dir (expand-file-name (car dirs) (file-name-directory file-name)))
  264. (masks masks))
  265. (while (and (file-exists-p dir) (not done) masks)
  266. (let* ((mask (car masks))
  267. (dir-files (directory-files dir t mask)))
  268. (flymake-log 3 "dir %s, %d file(s) for mask %s"
  269. dir (length dir-files) mask)
  270. (while (and (not done) dir-files)
  271. (when (not (file-directory-p (car dir-files)))
  272. (setq files (cons (car dir-files) files))
  273. (when (>= (length files) flymake-master-file-count-limit)
  274. (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit)
  275. (setq done t)))
  276. (setq dir-files (cdr dir-files))))
  277. (setq masks (cdr masks))))
  278. (setq dirs (cdr dirs)))
  279. (when files
  280. (let ((flymake-included-file-name (file-name-nondirectory file-name)))
  281. (setq files (sort files 'flymake-master-file-compare))))
  282. (flymake-log 3 "found %d possible master file(s)" (length files))
  283. files))
  284. (defun flymake-master-file-compare (file-one file-two)
  285. "Compare two files specified by FILE-ONE and FILE-TWO.
  286. This function is used in sort to move most possible file names
  287. to the beginning of the list (File.h -> File.cpp moved to top)."
  288. (and (equal (file-name-sans-extension flymake-included-file-name)
  289. (file-name-base file-one))
  290. (not (equal file-one file-two))))
  291. (defvar flymake-check-file-limit 8192
  292. "Maximum number of chars to look at when checking possible master file.
  293. Nil means search the entire file.")
  294. (defun flymake-check-patch-master-file-buffer
  295. (master-file-temp-buffer
  296. master-file-name patched-master-file-name
  297. source-file-name patched-source-file-name
  298. include-dirs regexp)
  299. "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME.
  300. If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME
  301. instead of SOURCE-FILE-NAME.
  302. For example, foo.cpp is a master file if it includes foo.h.
  303. Whether a buffer for MATER-FILE-NAME exists, use it as a source
  304. instead of reading master file from disk."
  305. (let* ((source-file-nondir (file-name-nondirectory source-file-name))
  306. (source-file-extension (file-name-extension source-file-nondir))
  307. (source-file-nonext (file-name-sans-extension source-file-nondir))
  308. (found nil)
  309. (inc-name nil)
  310. (search-limit flymake-check-file-limit))
  311. (setq regexp
  312. (format regexp ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\""
  313. ;; Hack for tex files, where \include often excludes .tex.
  314. ;; Maybe this is safe generally.
  315. (if (and (> (length source-file-extension) 1)
  316. (string-equal source-file-extension "tex"))
  317. (format "%s\\(?:\\.%s\\)?"
  318. (regexp-quote source-file-nonext)
  319. (regexp-quote source-file-extension))
  320. (regexp-quote source-file-nondir))))
  321. (unwind-protect
  322. (with-current-buffer master-file-temp-buffer
  323. (if (or (not search-limit)
  324. (> search-limit (point-max)))
  325. (setq search-limit (point-max)))
  326. (flymake-log 3 "checking %s against regexp %s"
  327. master-file-name regexp)
  328. (goto-char (point-min))
  329. (while (and (< (point) search-limit)
  330. (re-search-forward regexp search-limit t))
  331. (let ((match-beg (match-beginning 1))
  332. (match-end (match-end 1)))
  333. (flymake-log 3 "found possible match for %s" source-file-nondir)
  334. (setq inc-name (match-string 1))
  335. (and (> (length source-file-extension) 1)
  336. (string-equal source-file-extension "tex")
  337. (not (string-match (format "\\.%s\\'" source-file-extension)
  338. inc-name))
  339. (setq inc-name (concat inc-name "." source-file-extension)))
  340. (when (eq t (compare-strings
  341. source-file-nondir nil nil
  342. inc-name (- (length inc-name)
  343. (length source-file-nondir)) nil))
  344. (flymake-log 3 "inc-name=%s" inc-name)
  345. (when (flymake-check-include source-file-name inc-name
  346. include-dirs)
  347. (setq found t)
  348. ;; replace-match is not used here as it fails in
  349. ;; XEmacs with 'last match not a buffer' error as
  350. ;; check-includes calls replace-in-string
  351. (flymake-replace-region
  352. match-beg match-end
  353. (file-name-nondirectory patched-source-file-name))))
  354. (forward-line 1)))
  355. (when found
  356. (flymake-save-buffer-in-file patched-master-file-name)))
  357. ;;+(flymake-log 3 "killing buffer %s"
  358. ;; (buffer-name master-file-temp-buffer))
  359. (kill-buffer master-file-temp-buffer))
  360. ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found)
  361. (when found
  362. (flymake-log 2 "found master file %s" master-file-name))
  363. found))
  364. ;;; XXX: remove
  365. (defun flymake-replace-region (beg end rep)
  366. "Replace text in BUFFER in region (BEG END) with REP."
  367. (save-excursion
  368. (goto-char end)
  369. ;; Insert before deleting, so as to better preserve markers's positions.
  370. (insert rep)
  371. (delete-region beg end)))
  372. (defun flymake-read-file-to-temp-buffer (file-name)
  373. "Insert contents of FILE-NAME into newly created temp buffer."
  374. (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name))))))
  375. (with-current-buffer temp-buffer
  376. (insert-file-contents file-name))
  377. temp-buffer))
  378. (defun flymake-copy-buffer-to-temp-buffer (buffer)
  379. "Copy contents of BUFFER into newly created temp buffer."
  380. (with-current-buffer
  381. (get-buffer-create (generate-new-buffer-name
  382. (concat "flymake:" (buffer-name buffer))))
  383. (insert-buffer-substring buffer)
  384. (current-buffer)))
  385. (defun flymake-check-include (source-file-name inc-name include-dirs)
  386. "Check if SOURCE-FILE-NAME can be found in include path.
  387. Return t if it can be found via include path using INC-NAME."
  388. (if (file-name-absolute-p inc-name)
  389. (flymake-same-files source-file-name inc-name)
  390. (while (and include-dirs
  391. (not (flymake-same-files
  392. source-file-name
  393. (concat (file-name-directory source-file-name)
  394. "/" (car include-dirs)
  395. "/" inc-name))))
  396. (setq include-dirs (cdr include-dirs)))
  397. include-dirs))
  398. (defun flymake-find-buffer-for-file (file-name)
  399. "Check if there exists a buffer visiting FILE-NAME.
  400. Return t if so, nil if not."
  401. (let ((buffer-name (get-file-buffer file-name)))
  402. (if buffer-name
  403. (get-buffer buffer-name))))
  404. (defun flymake-create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp)
  405. "Save SOURCE-FILE-NAME with a different name.
  406. Find master file, patch and save it."
  407. (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks))
  408. (master-file-count (length possible-master-files))
  409. (idx 0)
  410. (temp-buffer nil)
  411. (master-file-name nil)
  412. (patched-master-file-name nil)
  413. (found nil))
  414. (while (and (not found) (< idx master-file-count))
  415. (setq master-file-name (nth idx possible-master-files))
  416. (setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master"))
  417. (if (flymake-find-buffer-for-file master-file-name)
  418. (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name)))
  419. (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name)))
  420. (setq found
  421. (flymake-check-patch-master-file-buffer
  422. temp-buffer
  423. master-file-name
  424. patched-master-file-name
  425. source-file-name
  426. patched-source-file-name
  427. (funcall get-incl-dirs-f (file-name-directory master-file-name))
  428. include-regexp))
  429. (setq idx (1+ idx)))
  430. (if found
  431. (list master-file-name patched-master-file-name)
  432. (progn
  433. (flymake-log 3 "none of %d master file(s) checked includes %s" master-file-count
  434. (file-name-nondirectory source-file-name))
  435. nil))))
  436. (defun flymake-save-buffer-in-file (file-name)
  437. "Save the entire buffer contents into file FILE-NAME.
  438. Create parent directories as needed."
  439. (make-directory (file-name-directory file-name) 1)
  440. (write-region nil nil file-name nil 566)
  441. (flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name))
  442. (defun flymake-process-filter (process output)
  443. "Parse OUTPUT and highlight error lines.
  444. It's flymake process filter."
  445. (let ((source-buffer (process-buffer process)))
  446. (flymake-log 3 "received %d byte(s) of output from process %d"
  447. (length output) (process-id process))
  448. (when (buffer-live-p source-buffer)
  449. (with-current-buffer source-buffer
  450. (flymake-parse-output-and-residual output)))))
  451. (defun flymake-process-sentinel (process _event)
  452. "Sentinel for syntax check buffers."
  453. (when (memq (process-status process) '(signal exit))
  454. (let* ((exit-status (process-exit-status process))
  455. (command (process-command process))
  456. (source-buffer (process-buffer process))
  457. (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer))))
  458. (flymake-log 2 "process %d exited with code %d"
  459. (process-id process) exit-status)
  460. (condition-case err
  461. (progn
  462. (flymake-log 3 "cleaning up using %s" cleanup-f)
  463. (when (buffer-live-p source-buffer)
  464. (with-current-buffer source-buffer
  465. (funcall cleanup-f)))
  466. (delete-process process)
  467. (setq flymake-processes (delq process flymake-processes))
  468. (when (buffer-live-p source-buffer)
  469. (with-current-buffer source-buffer
  470. (flymake-parse-residual)
  471. (flymake-post-syntax-check exit-status command)
  472. (setq flymake-is-running nil))))
  473. (error
  474. (let ((err-str (format "Error in process sentinel for buffer %s: %s"
  475. source-buffer (error-message-string err))))
  476. (flymake-log 0 err-str)
  477. (with-current-buffer source-buffer
  478. (setq flymake-is-running nil))))))))
  479. (defun flymake-post-syntax-check (exit-status command)
  480. (save-restriction
  481. (widen)
  482. (setq flymake-err-info flymake-new-err-info)
  483. (setq flymake-new-err-info nil)
  484. (setq flymake-err-info
  485. (flymake-fix-line-numbers
  486. flymake-err-info 1 (count-lines (point-min) (point-max))))
  487. (flymake-delete-own-overlays)
  488. (flymake-highlight-err-lines flymake-err-info)
  489. (let (err-count warn-count)
  490. (setq err-count (flymake-get-err-count flymake-err-info "e"))
  491. (setq warn-count (flymake-get-err-count flymake-err-info "w"))
  492. (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)"
  493. (buffer-name) err-count warn-count
  494. (- (float-time) flymake-check-start-time))
  495. (setq flymake-check-start-time nil)
  496. (if (and (equal 0 err-count) (equal 0 warn-count))
  497. (if (equal 0 exit-status)
  498. (flymake-report-status "" "") ; PASSED
  499. (if (not flymake-check-was-interrupted)
  500. (flymake-report-fatal-status "CFGERR"
  501. (format "Configuration error has occurred while running %s" command))
  502. (flymake-report-status nil ""))) ; "STOPPED"
  503. (flymake-report-status (format "%d/%d" err-count warn-count) "")))))
  504. (defun flymake-parse-output-and-residual (output)
  505. "Split OUTPUT into lines, merge in residual if necessary."
  506. (let* ((buffer-residual flymake-output-residual)
  507. (total-output (if buffer-residual (concat buffer-residual output) output))
  508. (lines-and-residual (flymake-split-output total-output))
  509. (lines (nth 0 lines-and-residual))
  510. (new-residual (nth 1 lines-and-residual)))
  511. (setq flymake-output-residual new-residual)
  512. (setq flymake-new-err-info
  513. (flymake-parse-err-lines
  514. flymake-new-err-info lines))))
  515. (defun flymake-parse-residual ()
  516. "Parse residual if it's non empty."
  517. (when flymake-output-residual
  518. (setq flymake-new-err-info
  519. (flymake-parse-err-lines
  520. flymake-new-err-info
  521. (list flymake-output-residual)))
  522. (setq flymake-output-residual nil)))
  523. (defun flymake-er-make-er (line-no line-err-info-list)
  524. (list line-no line-err-info-list))
  525. (defun flymake-er-get-line (err-info)
  526. (nth 0 err-info))
  527. (defun flymake-er-get-line-err-info-list (err-info)
  528. (nth 1 err-info))
  529. (cl-defstruct (flymake-ler
  530. (:constructor nil)
  531. (:constructor flymake-ler-make-ler (file line type text &optional full-file)))
  532. file line type text full-file)
  533. (defun flymake-ler-set-file (line-err-info file)
  534. (flymake-ler-make-ler file
  535. (flymake-ler-line line-err-info)
  536. (flymake-ler-type line-err-info)
  537. (flymake-ler-text line-err-info)
  538. (flymake-ler-full-file line-err-info)))
  539. (defun flymake-ler-set-full-file (line-err-info full-file)
  540. (flymake-ler-make-ler (flymake-ler-file line-err-info)
  541. (flymake-ler-line line-err-info)
  542. (flymake-ler-type line-err-info)
  543. (flymake-ler-text line-err-info)
  544. full-file))
  545. (defun flymake-ler-set-line (line-err-info line)
  546. (flymake-ler-make-ler (flymake-ler-file line-err-info)
  547. line
  548. (flymake-ler-type line-err-info)
  549. (flymake-ler-text line-err-info)
  550. (flymake-ler-full-file line-err-info)))
  551. (defun flymake-get-line-err-count (line-err-info-list type)
  552. "Return number of errors of specified TYPE.
  553. Value of TYPE is either \"e\" or \"w\"."
  554. (let* ((idx 0)
  555. (count (length line-err-info-list))
  556. (err-count 0))
  557. (while (< idx count)
  558. (when (equal type (flymake-ler-type (nth idx line-err-info-list)))
  559. (setq err-count (1+ err-count)))
  560. (setq idx (1+ idx)))
  561. err-count))
  562. (defun flymake-get-err-count (err-info-list type)
  563. "Return number of errors of specified TYPE for ERR-INFO-LIST."
  564. (let* ((idx 0)
  565. (count (length err-info-list))
  566. (err-count 0))
  567. (while (< idx count)
  568. (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type)))
  569. (setq idx (1+ idx)))
  570. err-count))
  571. (defun flymake-fix-line-numbers (err-info-list min-line max-line)
  572. "Replace line numbers with fixed value.
  573. If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE.
  574. If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE.
  575. The reason for this fix is because some compilers might report
  576. line number outside the file being compiled."
  577. (let* ((count (length err-info-list))
  578. (err-info nil)
  579. (line 0))
  580. (while (> count 0)
  581. (setq err-info (nth (1- count) err-info-list))
  582. (setq line (flymake-er-get-line err-info))
  583. (when (or (< line min-line) (> line max-line))
  584. (setq line (if (< line min-line) min-line max-line))
  585. (setq err-info-list (flymake-set-at err-info-list (1- count)
  586. (flymake-er-make-er line
  587. (flymake-er-get-line-err-info-list err-info)))))
  588. (setq count (1- count))))
  589. err-info-list)
  590. (defun flymake-highlight-err-lines (err-info-list)
  591. "Highlight error lines in BUFFER using info from ERR-INFO-LIST."
  592. (save-excursion
  593. (dolist (err err-info-list)
  594. (flymake-highlight-line (car err) (nth 1 err)))))
  595. (defun flymake-overlay-p (ov)
  596. "Determine whether overlay OV was created by flymake."
  597. (and (overlayp ov) (overlay-get ov 'flymake-overlay)))
  598. (defun flymake-make-overlay (beg end tooltip-text face bitmap)
  599. "Allocate a flymake overlay in range BEG and END."
  600. (when (not (flymake-region-has-flymake-overlays beg end))
  601. (let ((ov (make-overlay beg end nil t))
  602. (fringe (and flymake-fringe-indicator-position
  603. (propertize "!" 'display
  604. (cons flymake-fringe-indicator-position
  605. (if (listp bitmap)
  606. bitmap
  607. (list bitmap)))))))
  608. (overlay-put ov 'face face)
  609. (overlay-put ov 'help-echo tooltip-text)
  610. (overlay-put ov 'flymake-overlay t)
  611. (overlay-put ov 'priority 100)
  612. (overlay-put ov 'evaporate t)
  613. (overlay-put ov 'before-string fringe)
  614. ;;+(flymake-log 3 "created overlay %s" ov)
  615. ov)
  616. (flymake-log 3 "created an overlay at (%d-%d)" beg end)))
  617. (defun flymake-delete-own-overlays ()
  618. "Delete all flymake overlays in BUFFER."
  619. (dolist (ol (overlays-in (point-min) (point-max)))
  620. (when (flymake-overlay-p ol)
  621. (delete-overlay ol)
  622. ;;+(flymake-log 3 "deleted overlay %s" ol)
  623. )))
  624. (defun flymake-region-has-flymake-overlays (beg end)
  625. "Check if region specified by BEG and END has overlay.
  626. Return t if it has at least one flymake overlay, nil if no overlay."
  627. (let ((ov (overlays-in beg end))
  628. (has-flymake-overlays nil))
  629. (while (consp ov)
  630. (when (flymake-overlay-p (car ov))
  631. (setq has-flymake-overlays t))
  632. (setq ov (cdr ov)))
  633. has-flymake-overlays))
  634. (defface flymake-errline
  635. '((((supports :underline (:style wave)))
  636. :underline (:style wave :color "Red1"))
  637. (t
  638. :inherit error))
  639. "Face used for marking error lines."
  640. :version "24.4"
  641. :group 'flymake)
  642. (defface flymake-warnline
  643. '((((supports :underline (:style wave)))
  644. :underline (:style wave :color "DarkOrange"))
  645. (t
  646. :inherit warning))
  647. "Face used for marking warning lines."
  648. :version "24.4"
  649. :group 'flymake)
  650. (defun flymake-highlight-line (line-no line-err-info-list)
  651. "Highlight line LINE-NO in current buffer.
  652. Perhaps use text from LINE-ERR-INFO-LIST to enhance highlighting."
  653. (goto-char (point-min))
  654. (forward-line (1- line-no))
  655. (pcase-let* ((beg (progn (back-to-indentation) (point)))
  656. (end (progn
  657. (end-of-line)
  658. (skip-chars-backward " \t\f\t\n" beg)
  659. (if (eq (point) beg)
  660. (line-beginning-position 2)
  661. (point))))
  662. (tooltip-text (mapconcat #'flymake-ler-text line-err-info-list "\n"))
  663. (`(,face ,bitmap)
  664. (if (> (flymake-get-line-err-count line-err-info-list "e") 0)
  665. (list 'flymake-errline flymake-error-bitmap)
  666. (list 'flymake-warnline flymake-warning-bitmap))))
  667. (flymake-make-overlay beg end tooltip-text face bitmap)))
  668. (defun flymake-parse-err-lines (err-info-list lines)
  669. "Parse err LINES, store info in ERR-INFO-LIST."
  670. (let* ((count (length lines))
  671. (idx 0)
  672. (line-err-info nil)
  673. (real-file-name nil)
  674. (source-file-name buffer-file-name)
  675. (get-real-file-name-f (flymake-get-real-file-name-function source-file-name)))
  676. (while (< idx count)
  677. (setq line-err-info (flymake-parse-line (nth idx lines)))
  678. (when line-err-info
  679. (setq real-file-name (funcall get-real-file-name-f
  680. (flymake-ler-file line-err-info)))
  681. (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name))
  682. (when (flymake-same-files real-file-name source-file-name)
  683. (setq line-err-info (flymake-ler-set-file line-err-info nil))
  684. (setq err-info-list (flymake-add-err-info err-info-list line-err-info))))
  685. (flymake-log 3 "parsed ‘%s’, %s line-err-info" (nth idx lines) (if line-err-info "got" "no"))
  686. (setq idx (1+ idx)))
  687. err-info-list))
  688. (defun flymake-split-output (output)
  689. "Split OUTPUT into lines.
  690. Return last one as residual if it does not end with newline char.
  691. Returns ((LINES) RESIDUAL)."
  692. (when (and output (> (length output) 0))
  693. (let* ((lines (split-string output "[\n\r]+" t))
  694. (complete (equal "\n" (char-to-string (aref output (1- (length output))))))
  695. (residual nil))
  696. (when (not complete)
  697. (setq residual (car (last lines)))
  698. (setq lines (butlast lines)))
  699. (list lines residual))))
  700. (defun flymake-reformat-err-line-patterns-from-compile-el (original-list)
  701. "Grab error line patterns from ORIGINAL-LIST in compile.el format.
  702. Convert it to flymake internal format."
  703. (let* ((converted-list '()))
  704. (dolist (item original-list)
  705. (setq item (cdr item))
  706. (let ((regexp (nth 0 item))
  707. (file (nth 1 item))
  708. (line (nth 2 item))
  709. (col (nth 3 item)))
  710. (if (consp file) (setq file (car file)))
  711. (if (consp line) (setq line (car line)))
  712. (if (consp col) (setq col (car col)))
  713. (when (not (functionp line))
  714. (setq converted-list (cons (list regexp file line col) converted-list)))))
  715. converted-list))
  716. (require 'compile)
  717. (defvar flymake-err-line-patterns ; regexp file-idx line-idx col-idx (optional) text-idx(optional), match-end to end of string is error text
  718. (append
  719. '(
  720. ;; MS Visual C++ 6.0
  721. ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \: \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
  722. 1 3 nil 4)
  723. ;; jikes
  724. ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[0-9]+\:[0-9]+\:[0-9]+\: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)"
  725. 1 3 nil 4)
  726. ;; MS midl
  727. ("midl[ ]*:[ ]*\\(command line error .*\\)"
  728. nil nil nil 1)
  729. ;; MS C#
  730. ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+)\: \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
  731. 1 3 nil 4)
  732. ;; perl
  733. ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
  734. ;; PHP
  735. ("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 2 3 nil 1)
  736. ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1)
  737. ;; ant/javac. Note this also matches gcc warnings!
  738. (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\\(?:\:[0-9]+\\)?\:[ \t\n]*\\(.+\\)"
  739. 2 4 nil 5))
  740. ;; compilation-error-regexp-alist)
  741. (flymake-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist))
  742. "Patterns for matching error/warning lines. Each pattern has the form
  743. \(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX).
  744. Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns
  745. from compile.el")
  746. (define-obsolete-variable-alias 'flymake-warning-re 'flymake-warning-predicate "24.4")
  747. (defvar flymake-warning-predicate "^[wW]arning"
  748. "Predicate matching against error text to detect a warning.
  749. Takes a single argument, the error's text and should return non-nil
  750. if it's a warning.
  751. Instead of a function, it can also be a regular expression.")
  752. (defun flymake-parse-line (line)
  753. "Parse LINE to see if it is an error or warning.
  754. Return its components if so, nil otherwise."
  755. (let ((raw-file-name nil)
  756. (line-no 0)
  757. (err-type "e")
  758. (err-text nil)
  759. (patterns flymake-err-line-patterns)
  760. (matched nil))
  761. (while (and patterns (not matched))
  762. (when (string-match (car (car patterns)) line)
  763. (let* ((file-idx (nth 1 (car patterns)))
  764. (line-idx (nth 2 (car patterns))))
  765. (setq raw-file-name (if file-idx (match-string file-idx line) nil))
  766. (setq line-no (if line-idx (string-to-number
  767. (match-string line-idx line)) 0))
  768. (setq err-text (if (> (length (car patterns)) 4)
  769. (match-string (nth 4 (car patterns)) line)
  770. (flymake-patch-err-text
  771. (substring line (match-end 0)))))
  772. (if (null err-text)
  773. (setq err-text "<no error text>")
  774. (when (cond ((stringp flymake-warning-predicate)
  775. (string-match flymake-warning-predicate err-text))
  776. ((functionp flymake-warning-predicate)
  777. (funcall flymake-warning-predicate err-text)))
  778. (setq err-type "w")))
  779. (flymake-log
  780. 3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s"
  781. file-idx line-idx raw-file-name line-no err-text)
  782. (setq matched t)))
  783. (setq patterns (cdr patterns)))
  784. (if matched
  785. (flymake-ler-make-ler raw-file-name line-no err-type err-text)
  786. ())))
  787. (defun flymake-find-err-info (err-info-list line-no)
  788. "Find (line-err-info-list pos) for specified LINE-NO."
  789. (if err-info-list
  790. (let* ((line-err-info-list nil)
  791. (pos 0)
  792. (count (length err-info-list)))
  793. (while (and (< pos count) (< (car (nth pos err-info-list)) line-no))
  794. (setq pos (1+ pos)))
  795. (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no))
  796. (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list))))
  797. (list line-err-info-list pos))
  798. '(nil 0)))
  799. (defun flymake-line-err-info-is-less-or-equal (line-one line-two)
  800. (or (string< (flymake-ler-type line-one) (flymake-ler-type line-two))
  801. (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
  802. (not (flymake-ler-file line-one)) (flymake-ler-file line-two))
  803. (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
  804. (or (and (flymake-ler-file line-one) (flymake-ler-file line-two))
  805. (and (not (flymake-ler-file line-one)) (not (flymake-ler-file line-two)))))))
  806. (defun flymake-add-line-err-info (line-err-info-list line-err-info)
  807. "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO.
  808. For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'.
  809. The new element is inserted in the proper position, according to
  810. the predicate `flymake-line-err-info-is-less-or-equal'.
  811. The updated value of LINE-ERR-INFO-LIST is returned."
  812. (if (not line-err-info-list)
  813. (list line-err-info)
  814. (let* ((count (length line-err-info-list))
  815. (idx 0))
  816. (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info))
  817. (setq idx (1+ idx)))
  818. (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list)))
  819. (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info))))
  820. line-err-info-list)))
  821. (defun flymake-add-err-info (err-info-list line-err-info)
  822. "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order.
  823. Returns the updated value of ERR-INFO-LIST.
  824. For the format of ERR-INFO-LIST, see `flymake-err-info'.
  825. For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'."
  826. (let* ((line-no (if (flymake-ler-file line-err-info) 1 (flymake-ler-line line-err-info)))
  827. (info-and-pos (flymake-find-err-info err-info-list line-no))
  828. (exists (car info-and-pos))
  829. (pos (nth 1 info-and-pos))
  830. (line-err-info-list nil)
  831. (err-info nil))
  832. (if exists
  833. (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list)))))
  834. (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info))
  835. (setq err-info (flymake-er-make-er line-no line-err-info-list))
  836. (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info)))
  837. ((equal 0 pos) (setq err-info-list (cons err-info err-info-list)))
  838. (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info))))
  839. err-info-list))
  840. (defun flymake-get-project-include-dirs-imp (basedir)
  841. "Include dirs for the project current file belongs to."
  842. (if (flymake-get-project-include-dirs-from-cache basedir)
  843. (progn
  844. (flymake-get-project-include-dirs-from-cache basedir))
  845. ;;else
  846. (let* ((command-line (concat "make -C "
  847. (shell-quote-argument basedir)
  848. " DUMPVARS=INCLUDE_DIRS dumpvars"))
  849. (output (shell-command-to-string command-line))
  850. (lines (split-string output "\n" t))
  851. (count (length lines))
  852. (idx 0)
  853. (inc-dirs nil))
  854. (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx lines))))
  855. (setq idx (1+ idx)))
  856. (when (< idx count)
  857. (let* ((inc-lines (split-string (nth idx lines) " *-I" t))
  858. (inc-count (length inc-lines)))
  859. (while (> inc-count 0)
  860. (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines)))
  861. (push (replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs))
  862. (setq inc-count (1- inc-count)))))
  863. (flymake-add-project-include-dirs-to-cache basedir inc-dirs)
  864. inc-dirs)))
  865. (defvar flymake-get-project-include-dirs-function #'flymake-get-project-include-dirs-imp
  866. "Function used to get project include dirs, one parameter: basedir name.")
  867. (defun flymake-get-project-include-dirs (basedir)
  868. (funcall flymake-get-project-include-dirs-function basedir))
  869. (defun flymake-get-system-include-dirs ()
  870. "System include dirs - from the 'INCLUDE' env setting."
  871. (let* ((includes (getenv "INCLUDE")))
  872. (if includes (split-string includes path-separator t) nil)))
  873. (defvar flymake-project-include-dirs-cache (make-hash-table :test #'equal))
  874. (defun flymake-get-project-include-dirs-from-cache (base-dir)
  875. (gethash base-dir flymake-project-include-dirs-cache))
  876. (defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs)
  877. (puthash base-dir include-dirs flymake-project-include-dirs-cache))
  878. (defun flymake-clear-project-include-dirs-cache ()
  879. (clrhash flymake-project-include-dirs-cache))
  880. (defun flymake-get-include-dirs (base-dir)
  881. "Get dirs to use when resolving local file names."
  882. (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs))))
  883. include-dirs))
  884. ;; (defun flymake-restore-formatting ()
  885. ;; "Remove any formatting made by flymake."
  886. ;; )
  887. ;; (defun flymake-get-program-dir (buffer)
  888. ;; "Get dir to start program in."
  889. ;; (unless (bufferp buffer)
  890. ;; (error "Invalid buffer"))
  891. ;; (with-current-buffer buffer
  892. ;; default-directory))
  893. (defun flymake-safe-delete-file (file-name)
  894. (when (and file-name (file-exists-p file-name))
  895. (delete-file file-name)
  896. (flymake-log 1 "deleted file %s" file-name)))
  897. (defun flymake-safe-delete-directory (dir-name)
  898. (condition-case nil
  899. (progn
  900. (delete-directory dir-name)
  901. (flymake-log 1 "deleted dir %s" dir-name))
  902. (error
  903. (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name))))
  904. (defun flymake-start-syntax-check ()
  905. "Start syntax checking for current buffer."
  906. (interactive)
  907. (flymake-log 3 "flymake is running: %s" flymake-is-running)
  908. (when (and (not flymake-is-running)
  909. (flymake-can-syntax-check-file buffer-file-name))
  910. (when (or (not flymake-compilation-prevents-syntax-check)
  911. (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP")
  912. (flymake-clear-buildfile-cache)
  913. (flymake-clear-project-include-dirs-cache)
  914. (setq flymake-check-was-interrupted nil)
  915. (let* ((source-file-name buffer-file-name)
  916. (init-f (flymake-get-init-function source-file-name))
  917. (cleanup-f (flymake-get-cleanup-function source-file-name))
  918. (cmd-and-args (funcall init-f))
  919. (cmd (nth 0 cmd-and-args))
  920. (args (nth 1 cmd-and-args))
  921. (dir (nth 2 cmd-and-args)))
  922. (if (not cmd-and-args)
  923. (progn
  924. (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name)
  925. (funcall cleanup-f))
  926. (progn
  927. (setq flymake-last-change-time nil)
  928. (flymake-start-syntax-check-process cmd args dir)))))))
  929. (defun flymake-start-syntax-check-process (cmd args dir)
  930. "Start syntax check process."
  931. (condition-case err
  932. (let* ((process
  933. (let ((default-directory (or dir default-directory)))
  934. (when dir
  935. (flymake-log 3 "starting process on dir %s" dir))
  936. (apply 'start-file-process
  937. "flymake-proc" (current-buffer) cmd args))))
  938. (set-process-sentinel process 'flymake-process-sentinel)
  939. (set-process-filter process 'flymake-process-filter)
  940. (push process flymake-processes)
  941. (setq flymake-is-running t)
  942. (setq flymake-last-change-time nil)
  943. (setq flymake-check-start-time (float-time))
  944. (flymake-report-status nil "*")
  945. (flymake-log 2 "started process %d, command=%s, dir=%s"
  946. (process-id process) (process-command process)
  947. default-directory)
  948. process)
  949. (error
  950. (let* ((err-str
  951. (format-message
  952. "Failed to launch syntax check process ‘%s’ with args %s: %s"
  953. cmd args (error-message-string err)))
  954. (source-file-name buffer-file-name)
  955. (cleanup-f (flymake-get-cleanup-function source-file-name)))
  956. (flymake-log 0 err-str)
  957. (funcall cleanup-f)
  958. (flymake-report-fatal-status "PROCERR" err-str)))))
  959. (defun flymake-kill-process (proc)
  960. "Kill process PROC."
  961. (kill-process proc)
  962. (let* ((buf (process-buffer proc)))
  963. (when (buffer-live-p buf)
  964. (with-current-buffer buf
  965. (setq flymake-check-was-interrupted t))))
  966. (flymake-log 1 "killed process %d" (process-id proc)))
  967. (defun flymake-stop-all-syntax-checks ()
  968. "Kill all syntax check processes."
  969. (interactive)
  970. (while flymake-processes
  971. (flymake-kill-process (pop flymake-processes))))
  972. (defun flymake-compilation-is-running ()
  973. (and (boundp 'compilation-in-progress)
  974. compilation-in-progress))
  975. (defun flymake-compile ()
  976. "Kill all flymake syntax checks, start compilation."
  977. (interactive)
  978. (flymake-stop-all-syntax-checks)
  979. (call-interactively 'compile))
  980. (defun flymake-on-timer-event (buffer)
  981. "Start a syntax check for buffer BUFFER if necessary."
  982. (when (buffer-live-p buffer)
  983. (with-current-buffer buffer
  984. (when (and (not flymake-is-running)
  985. flymake-last-change-time
  986. (> (- (float-time) flymake-last-change-time)
  987. flymake-no-changes-timeout))
  988. (setq flymake-last-change-time nil)
  989. (flymake-log 3 "starting syntax check as more than 1 second passed since last change")
  990. (flymake-start-syntax-check)))))
  991. (define-obsolete-function-alias 'flymake-display-err-menu-for-current-line
  992. 'flymake-popup-current-error-menu "24.4")
  993. (defun flymake-popup-current-error-menu (&optional event)
  994. "Pop up a menu with errors/warnings for current line."
  995. (interactive (list last-nonmenu-event))
  996. (let* ((line-no (line-number-at-pos))
  997. (errors (or (car (flymake-find-err-info flymake-err-info line-no))
  998. (user-error "No errors for current line")))
  999. (menu (mapcar (lambda (x)
  1000. (if (flymake-ler-file x)
  1001. (cons (format "%s - %s(%d)"
  1002. (flymake-ler-text x)
  1003. (flymake-ler-file x)
  1004. (flymake-ler-line x))
  1005. x)
  1006. (list (flymake-ler-text x))))
  1007. errors))
  1008. (event (if (mouse-event-p event)
  1009. event
  1010. (list 'mouse-1 (posn-at-point))))
  1011. (title (format "Line %d: %d error(s), %d warning(s)"
  1012. line-no
  1013. (flymake-get-line-err-count errors "e")
  1014. (flymake-get-line-err-count errors "w")))
  1015. (choice (x-popup-menu event (list title (cons "" menu)))))
  1016. (flymake-log 3 "choice=%s" choice)
  1017. (when choice
  1018. (flymake-goto-file-and-line (flymake-ler-full-file choice)
  1019. (flymake-ler-line choice)))))
  1020. (defun flymake-goto-file-and-line (file line)
  1021. "Try to get buffer for FILE and goto line LINE in it."
  1022. (if (not (file-exists-p file))
  1023. (flymake-log 1 "File %s does not exist" file)
  1024. (find-file file)
  1025. (goto-char (point-min))
  1026. (forward-line (1- line))))
  1027. ;; flymake minor mode declarations
  1028. (defvar-local flymake-mode-line nil)
  1029. (defvar-local flymake-mode-line-e-w nil)
  1030. (defvar-local flymake-mode-line-status nil)
  1031. (defun flymake-report-status (e-w &optional status)
  1032. "Show status in mode line."
  1033. (when e-w
  1034. (setq flymake-mode-line-e-w e-w))
  1035. (when status
  1036. (setq flymake-mode-line-status status))
  1037. (let* ((mode-line " Flymake"))
  1038. (when (> (length flymake-mode-line-e-w) 0)
  1039. (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
  1040. (setq mode-line (concat mode-line flymake-mode-line-status))
  1041. (setq flymake-mode-line mode-line)
  1042. (force-mode-line-update)))
  1043. (defun flymake-display-warning (warning)
  1044. "Display a warning to user."
  1045. (message-box warning))
  1046. (defun flymake-report-fatal-status (status warning)
  1047. "Display a warning and switch flymake mode off."
  1048. (when flymake-gui-warnings-enabled
  1049. (flymake-display-warning (format "Flymake: %s. Flymake will be switched OFF" warning))
  1050. )
  1051. (flymake-mode 0)
  1052. (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s"
  1053. (buffer-name) status warning))
  1054. ;;;###autoload
  1055. (define-minor-mode flymake-mode nil
  1056. :group 'flymake :lighter flymake-mode-line
  1057. (cond
  1058. ;; Turning the mode ON.
  1059. (flymake-mode
  1060. (cond
  1061. ((not buffer-file-name)
  1062. (message "Flymake unable to run without a buffer file name"))
  1063. ((not (flymake-can-syntax-check-file buffer-file-name))
  1064. (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name)))
  1065. (t
  1066. (add-hook 'after-change-functions 'flymake-after-change-function nil t)
  1067. (add-hook 'after-save-hook 'flymake-after-save-hook nil t)
  1068. (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t)
  1069. ;;+(add-hook 'find-file-hook 'flymake-find-file-hook)
  1070. (flymake-report-status "" "")
  1071. (setq flymake-timer
  1072. (run-at-time nil 1 'flymake-on-timer-event (current-buffer)))
  1073. (when (and flymake-start-syntax-check-on-find-file
  1074. ;; Since we write temp files in current dir, there's no point
  1075. ;; trying if the directory is read-only (bug#8954).
  1076. (file-writable-p (file-name-directory buffer-file-name)))
  1077. (with-demoted-errors
  1078. (flymake-start-syntax-check))))))
  1079. ;; Turning the mode OFF.
  1080. (t
  1081. (remove-hook 'after-change-functions 'flymake-after-change-function t)
  1082. (remove-hook 'after-save-hook 'flymake-after-save-hook t)
  1083. (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t)
  1084. ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t)
  1085. (flymake-delete-own-overlays)
  1086. (when flymake-timer
  1087. (cancel-timer flymake-timer)
  1088. (setq flymake-timer nil))
  1089. (setq flymake-is-running nil))))
  1090. ;;;###autoload
  1091. (defun flymake-mode-on ()
  1092. "Turn flymake mode on."
  1093. (flymake-mode 1)
  1094. (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name)))
  1095. ;;;###autoload
  1096. (defun flymake-mode-off ()
  1097. "Turn flymake mode off."
  1098. (flymake-mode 0)
  1099. (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name)))
  1100. (defun flymake-after-change-function (start stop _len)
  1101. "Start syntax check for current buffer if it isn't already running."
  1102. ;;+(flymake-log 0 "setting change time to %s" (float-time))
  1103. (let((new-text (buffer-substring start stop)))
  1104. (when (and flymake-start-syntax-check-on-newline (equal new-text "\n"))
  1105. (flymake-log 3 "starting syntax check as new-line has been seen")
  1106. (flymake-start-syntax-check))
  1107. (setq flymake-last-change-time (float-time))))
  1108. (defun flymake-after-save-hook ()
  1109. (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved?
  1110. (progn
  1111. (flymake-log 3 "starting syntax check as buffer was saved")
  1112. (flymake-start-syntax-check)))) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???)
  1113. (defun flymake-kill-buffer-hook ()
  1114. (when flymake-timer
  1115. (cancel-timer flymake-timer)
  1116. (setq flymake-timer nil)))
  1117. ;;;###autoload
  1118. (defun flymake-find-file-hook ()
  1119. ;;+(when flymake-start-syntax-check-on-find-file
  1120. ;;+ (flymake-log 3 "starting syntax check on file open")
  1121. ;;+ (flymake-start-syntax-check)
  1122. ;;+)
  1123. (when (and (not (local-variable-p 'flymake-mode (current-buffer)))
  1124. (flymake-can-syntax-check-file buffer-file-name))
  1125. (flymake-mode)
  1126. (flymake-log 3 "automatically turned ON flymake mode")))
  1127. (defun flymake-get-first-err-line-no (err-info-list)
  1128. "Return first line with error."
  1129. (when err-info-list
  1130. (flymake-er-get-line (car err-info-list))))
  1131. (defun flymake-get-last-err-line-no (err-info-list)
  1132. "Return last line with error."
  1133. (when err-info-list
  1134. (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list))))
  1135. (defun flymake-get-next-err-line-no (err-info-list line-no)
  1136. "Return next line with error."
  1137. (when err-info-list
  1138. (let* ((count (length err-info-list))
  1139. (idx 0))
  1140. (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list))))
  1141. (setq idx (1+ idx)))
  1142. (if (< idx count)
  1143. (flymake-er-get-line (nth idx err-info-list))))))
  1144. (defun flymake-get-prev-err-line-no (err-info-list line-no)
  1145. "Return previous line with error."
  1146. (when err-info-list
  1147. (let* ((count (length err-info-list)))
  1148. (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list))))
  1149. (setq count (1- count)))
  1150. (if (> count 0)
  1151. (flymake-er-get-line (nth (1- count) err-info-list))))))
  1152. (defun flymake-skip-whitespace ()
  1153. "Move forward until non-whitespace is reached."
  1154. (while (looking-at "[ \t]")
  1155. (forward-char)))
  1156. (defun flymake-goto-line (line-no)
  1157. "Go to line LINE-NO, then skip whitespace."
  1158. (goto-char (point-min))
  1159. (forward-line (1- line-no))
  1160. (flymake-skip-whitespace))
  1161. (defun flymake-goto-next-error ()
  1162. "Go to next error in err ring."
  1163. (interactive)
  1164. (let ((line-no (flymake-get-next-err-line-no flymake-err-info (line-number-at-pos))))
  1165. (when (not line-no)
  1166. (setq line-no (flymake-get-first-err-line-no flymake-err-info))
  1167. (flymake-log 1 "passed end of file"))
  1168. (if line-no
  1169. (flymake-goto-line line-no)
  1170. (flymake-log 1 "no errors in current buffer"))))
  1171. (defun flymake-goto-prev-error ()
  1172. "Go to previous error in err ring."
  1173. (interactive)
  1174. (let ((line-no (flymake-get-prev-err-line-no flymake-err-info (line-number-at-pos))))
  1175. (when (not line-no)
  1176. (setq line-no (flymake-get-last-err-line-no flymake-err-info))
  1177. (flymake-log 1 "passed beginning of file"))
  1178. (if line-no
  1179. (flymake-goto-line line-no)
  1180. (flymake-log 1 "no errors in current buffer"))))
  1181. (defun flymake-patch-err-text (string)
  1182. (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string)
  1183. (match-string 1 string)
  1184. string))
  1185. ;;;; general init-cleanup and helper routines
  1186. (defun flymake-create-temp-inplace (file-name prefix)
  1187. (unless (stringp file-name)
  1188. (error "Invalid file-name"))
  1189. (or prefix
  1190. (setq prefix "flymake"))
  1191. (let* ((ext (file-name-extension file-name))
  1192. (temp-name (file-truename
  1193. (concat (file-name-sans-extension file-name)
  1194. "_" prefix
  1195. (and ext (concat "." ext))))))
  1196. (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name)
  1197. temp-name))
  1198. (defun flymake-create-temp-with-folder-structure (file-name _prefix)
  1199. (unless (stringp file-name)
  1200. (error "Invalid file-name"))
  1201. (let* ((dir (file-name-directory file-name))
  1202. ;; Not sure what this slash-pos is all about, but I guess it's just
  1203. ;; trying to remove the leading / of absolute file names.
  1204. (slash-pos (string-match "/" dir))
  1205. (temp-dir (expand-file-name (substring dir (1+ slash-pos))
  1206. temporary-file-directory)))
  1207. (file-truename (expand-file-name (file-name-nondirectory file-name)
  1208. temp-dir))))
  1209. (defun flymake-delete-temp-directory (dir-name)
  1210. "Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error."
  1211. (let* ((temp-dir temporary-file-directory)
  1212. (suffix (substring dir-name (1+ (length temp-dir)))))
  1213. (while (> (length suffix) 0)
  1214. (setq suffix (directory-file-name suffix))
  1215. ;;+(flymake-log 0 "suffix=%s" suffix)
  1216. (flymake-safe-delete-directory
  1217. (file-truename (expand-file-name suffix temp-dir)))
  1218. (setq suffix (file-name-directory suffix)))))
  1219. (defvar-local flymake-temp-source-file-name nil)
  1220. (defvar-local flymake-master-file-name nil)
  1221. (defvar-local flymake-temp-master-file-name nil)
  1222. (defvar-local flymake-base-dir nil)
  1223. (defun flymake-init-create-temp-buffer-copy (create-temp-f)
  1224. "Make a temporary copy of the current buffer, save its name in buffer data and return the name."
  1225. (let* ((source-file-name buffer-file-name)
  1226. (temp-source-file-name (funcall create-temp-f source-file-name "flymake")))
  1227. (flymake-save-buffer-in-file temp-source-file-name)
  1228. (setq flymake-temp-source-file-name temp-source-file-name)
  1229. temp-source-file-name))
  1230. (defun flymake-simple-cleanup ()
  1231. "Do cleanup after `flymake-init-create-temp-buffer-copy'.
  1232. Delete temp file."
  1233. (flymake-safe-delete-file flymake-temp-source-file-name)
  1234. (setq flymake-last-change-time nil))
  1235. (defun flymake-get-real-file-name (file-name-from-err-msg)
  1236. "Translate file name from error message to \"real\" file name.
  1237. Return full-name. Names are real, not patched."
  1238. (let* ((real-name nil)
  1239. (source-file-name buffer-file-name)
  1240. (master-file-name flymake-master-file-name)
  1241. (temp-source-file-name flymake-temp-source-file-name)
  1242. (temp-master-file-name flymake-temp-master-file-name)
  1243. (base-dirs
  1244. (list flymake-base-dir
  1245. (file-name-directory source-file-name)
  1246. (if master-file-name (file-name-directory master-file-name))))
  1247. (files (list (list source-file-name source-file-name)
  1248. (list temp-source-file-name source-file-name)
  1249. (list master-file-name master-file-name)
  1250. (list temp-master-file-name master-file-name))))
  1251. (when (equal 0 (length file-name-from-err-msg))
  1252. (setq file-name-from-err-msg source-file-name))
  1253. (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files))
  1254. ;; if real-name is nil, than file name from err msg is none of the files we've patched
  1255. (if (not real-name)
  1256. (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs)))
  1257. (if (not real-name)
  1258. (setq real-name file-name-from-err-msg))
  1259. (setq real-name (flymake-fix-file-name real-name))
  1260. (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name)
  1261. real-name))
  1262. (defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs files)
  1263. (let* ((base-dirs-count (length base-dirs))
  1264. (file-count (length files))
  1265. (real-name nil))
  1266. (while (and (not real-name) (> base-dirs-count 0))
  1267. (setq file-count (length files))
  1268. (while (and (not real-name) (> file-count 0))
  1269. (let* ((this-dir (nth (1- base-dirs-count) base-dirs))
  1270. (this-file (nth 0 (nth (1- file-count) files)))
  1271. (this-real-name (nth 1 (nth (1- file-count) files))))
  1272. ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" this-dir this-file this-real-name file-name-from-err-msg)
  1273. (when (and this-dir this-file (flymake-same-files
  1274. (expand-file-name file-name-from-err-msg this-dir)
  1275. this-file))
  1276. (setq real-name this-real-name)))
  1277. (setq file-count (1- file-count)))
  1278. (setq base-dirs-count (1- base-dirs-count)))
  1279. real-name))
  1280. (defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs)
  1281. (let* ((real-name nil))
  1282. (if (file-name-absolute-p file-name-from-err-msg)
  1283. (setq real-name file-name-from-err-msg)
  1284. (let* ((base-dirs-count (length base-dirs)))
  1285. (while (and (not real-name) (> base-dirs-count 0))
  1286. (let* ((full-name (expand-file-name file-name-from-err-msg
  1287. (nth (1- base-dirs-count) base-dirs))))
  1288. (if (file-exists-p full-name)
  1289. (setq real-name full-name))
  1290. (setq base-dirs-count (1- base-dirs-count))))))
  1291. real-name))
  1292. (defun flymake-init-find-buildfile-dir (source-file-name buildfile-name)
  1293. "Find buildfile, store its dir in buffer data and return its dir, if found."
  1294. (let* ((buildfile-dir
  1295. (flymake-find-buildfile buildfile-name
  1296. (file-name-directory source-file-name))))
  1297. (if buildfile-dir
  1298. (setq flymake-base-dir buildfile-dir)
  1299. (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name)
  1300. (flymake-report-fatal-status
  1301. "NOMK" (format "No buildfile (%s) found for %s"
  1302. buildfile-name source-file-name)))))
  1303. (defun flymake-init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f create-temp-f master-file-masks include-regexp)
  1304. "Find master file (or buffer), create its copy along with a copy of the source file."
  1305. (let* ((source-file-name buffer-file-name)
  1306. (temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f))
  1307. (master-and-temp-master (flymake-create-master-file
  1308. source-file-name temp-source-file-name
  1309. get-incl-dirs-f create-temp-f
  1310. master-file-masks include-regexp)))
  1311. (if (not master-and-temp-master)
  1312. (progn
  1313. (flymake-log 1 "cannot find master file for %s" source-file-name)
  1314. (flymake-report-status "!" "") ; NOMASTER
  1315. nil)
  1316. (setq flymake-master-file-name (nth 0 master-and-temp-master))
  1317. (setq flymake-temp-master-file-name (nth 1 master-and-temp-master)))))
  1318. (defun flymake-master-cleanup ()
  1319. (flymake-simple-cleanup)
  1320. (flymake-safe-delete-file flymake-temp-master-file-name))
  1321. ;;;; make-specific init-cleanup routines
  1322. (defun flymake-get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f)
  1323. "Create a command line for syntax check using GET-CMD-LINE-F."
  1324. (funcall get-cmd-line-f
  1325. (if use-relative-source
  1326. (file-relative-name source-file-name base-dir)
  1327. source-file-name)
  1328. (if use-relative-base-dir
  1329. (file-relative-name base-dir
  1330. (file-name-directory source-file-name))
  1331. base-dir)))
  1332. (defun flymake-get-make-cmdline (source base-dir)
  1333. (list "make"
  1334. (list "-s"
  1335. "-C"
  1336. base-dir
  1337. (concat "CHK_SOURCES=" source)
  1338. "SYNTAX_CHECK_MODE=1"
  1339. "check-syntax")))
  1340. (defun flymake-get-ant-cmdline (source base-dir)
  1341. (list "ant"
  1342. (list "-buildfile"
  1343. (concat base-dir "/" "build.xml")
  1344. (concat "-DCHK_SOURCES=" source)
  1345. "check-syntax")))
  1346. (defun flymake-simple-make-init-impl (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f)
  1347. "Create syntax check command line for a directly checked source file.
  1348. Use CREATE-TEMP-F for creating temp copy."
  1349. (let* ((args nil)
  1350. (source-file-name buffer-file-name)
  1351. (buildfile-dir (flymake-init-find-buildfile-dir source-file-name build-file-name)))
  1352. (if buildfile-dir
  1353. (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)))
  1354. (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir
  1355. use-relative-base-dir use-relative-source
  1356. get-cmdline-f))))
  1357. args))
  1358. (defun flymake-simple-make-init ()
  1359. (flymake-simple-make-init-impl 'flymake-create-temp-inplace t t "Makefile" 'flymake-get-make-cmdline))
  1360. (defun flymake-master-make-init (get-incl-dirs-f master-file-masks include-regexp)
  1361. "Create make command line for a source file checked via master file compilation."
  1362. (let* ((make-args nil)
  1363. (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
  1364. get-incl-dirs-f 'flymake-create-temp-inplace
  1365. master-file-masks include-regexp)))
  1366. (when temp-master-file-name
  1367. (let* ((buildfile-dir (flymake-init-find-buildfile-dir temp-master-file-name "Makefile")))
  1368. (if buildfile-dir
  1369. (setq make-args (flymake-get-syntax-check-program-args
  1370. temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline)))))
  1371. make-args))
  1372. (defun flymake-find-make-buildfile (source-dir)
  1373. (flymake-find-buildfile "Makefile" source-dir))
  1374. ;;;; .h/make specific
  1375. (defun flymake-master-make-header-init ()
  1376. (flymake-master-make-init
  1377. 'flymake-get-include-dirs
  1378. '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'")
  1379. "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\""))
  1380. ;;;; .java/make specific
  1381. (defun flymake-simple-make-java-init ()
  1382. (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline))
  1383. (defun flymake-simple-ant-java-init ()
  1384. (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline))
  1385. (defun flymake-simple-java-cleanup ()
  1386. "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs."
  1387. (flymake-safe-delete-file flymake-temp-source-file-name)
  1388. (when flymake-temp-source-file-name
  1389. (flymake-delete-temp-directory
  1390. (file-name-directory flymake-temp-source-file-name))))
  1391. ;;;; perl-specific init-cleanup routines
  1392. (defun flymake-perl-init ()
  1393. (let* ((temp-file (flymake-init-create-temp-buffer-copy
  1394. 'flymake-create-temp-inplace))
  1395. (local-file (file-relative-name
  1396. temp-file
  1397. (file-name-directory buffer-file-name))))
  1398. (list "perl" (list "-wc " local-file))))
  1399. ;;;; php-specific init-cleanup routines
  1400. (defun flymake-php-init ()
  1401. (let* ((temp-file (flymake-init-create-temp-buffer-copy
  1402. 'flymake-create-temp-inplace))
  1403. (local-file (file-relative-name
  1404. temp-file
  1405. (file-name-directory buffer-file-name))))
  1406. (list "php" (list "-f" local-file "-l"))))
  1407. ;;;; tex-specific init-cleanup routines
  1408. (defun flymake-get-tex-args (file-name)
  1409. ;;(list "latex" (list "-c-style-errors" file-name))
  1410. (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name)))
  1411. (defun flymake-simple-tex-init ()
  1412. (flymake-get-tex-args (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace)))
  1413. ;; Perhaps there should be a buffer-local variable flymake-master-file
  1414. ;; that people can set to override this stuff. Could inherit from
  1415. ;; the similar AUCTeX variable.
  1416. (defun flymake-master-tex-init ()
  1417. (let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
  1418. 'flymake-get-include-dirs-dot 'flymake-create-temp-inplace
  1419. '("\\.tex\\'")
  1420. "[ \t]*\\in\\(?:put\\|clude\\)[ \t]*{\\(.*%s\\)}")))
  1421. (when temp-master-file-name
  1422. (flymake-get-tex-args temp-master-file-name))))
  1423. (defun flymake-get-include-dirs-dot (_base-dir)
  1424. '("."))
  1425. ;;;; xml-specific init-cleanup routines
  1426. (defun flymake-xml-init ()
  1427. (list flymake-xml-program
  1428. (list "val" (flymake-init-create-temp-buffer-copy
  1429. 'flymake-create-temp-inplace))))
  1430. (provide 'flymake)
  1431. ;;; flymake.el ends here