Mercurial > emacs
annotate lisp/progmodes/flymake.el @ 57149:319d48feb1e9
*** empty log message ***
author | Luc Teirlinck <teirllm@auburn.edu> |
---|---|
date | Sun, 19 Sep 2004 01:11:35 +0000 |
parents | 26e0724718e2 |
children | fbcb259c5936 |
rev | line source |
---|---|
55822 | 1 ;;; flymake.el -- a universal on-the-fly syntax checker |
2 | |
3 ;; Copyright (C) 2003 Free Software Foundation | |
4 | |
5 ;; Author: Pavel Kobiakov <pk_at_work@yahoo.com> | |
6 ;; Maintainer: Pavel Kobiakov <pk_at_work@yahoo.com> | |
7 ;; Version: 0.3 | |
8 ;; Keywords: c languages tools | |
9 | |
10 ;; This file is part of GNU Emacs. | |
11 | |
12 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
13 ;; it under the terms of the GNU General Public License as published by | |
14 ;; the Free Software Foundation; either version 2, or (at your option) | |
15 ;; any later version. | |
16 | |
17 ;; GNU Emacs is distributed in the hope that it will be useful, | |
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 ;; GNU General Public License for more details. | |
21 | |
22 ;; You should have received a copy of the GNU General Public License | |
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
25 ;; Boston, MA 02111-1307, USA. | |
26 | |
27 ;;; Commentary: | |
28 ;; | |
29 ;; Flymake is a minor Emacs mode performing on-the-fly syntax | |
30 ;; checks using the external syntax check tool (for C/C++ this | |
31 ;; is usually the compiler) | |
32 | |
33 ;;; Code: | |
34 | |
35 ;;;_* Provide | |
36 (provide 'flymake) | |
37 | |
38 ;;;; [[ Overlay compatibility | |
39 (autoload 'make-overlay "overlay" "Overlay compatibility kit." t) | |
40 (autoload 'overlayp "overlay" "Overlay compatibility kit." t) | |
41 (autoload 'overlays-in "overlay" "Overlay compatibility kit." t) | |
42 (autoload 'delete-overlay "overlay" "Overlay compatibility kit." t) | |
43 (autoload 'overlay-put "overlay" "Overlay compatibility kit." t) | |
44 (autoload 'overlay-get "overlay" "Overlay compatibility kit." t) | |
45 ;;;; ]] | |
46 | |
47 ;;;; [[ cross-emacs compatibility routines | |
48 (defvar flymake-emacs | |
49 (cond | |
50 ((string-match "XEmacs" emacs-version) 'xemacs) | |
51 (t 'emacs) | |
52 ) | |
53 "Currently used emacs flavor" | |
54 ) | |
55 | |
56 (defun flymake-makehash(&optional test) | |
57 (cond | |
58 ((equal flymake-emacs 'xemacs) (if test (make-hash-table :test test) (make-hash-table))) | |
59 (t (makehash test)) | |
60 ) | |
61 ) | |
62 | |
63 (defun flymake-time-to-float(&optional tm) | |
64 "Convert `current-time` to a float number of seconds." | |
65 (multiple-value-bind (s0 s1 s2) (or tm (current-time)) | |
66 (+ (* (float (ash 1 16)) s0) (float s1) (* 0.0000001 s2))) | |
67 ) | |
68 (defun flymake-float-time() | |
69 (cond | |
70 ((equal flymake-emacs 'xemacs) (flymake-time-to-float (current-time))) | |
71 (t (float-time)) | |
72 ) | |
73 ) | |
74 | |
75 (defun flymake-replace-regexp-in-string(regexp rep str) | |
76 (cond | |
77 ((equal flymake-emacs 'xemacs) (replace-in-string str regexp rep)) | |
78 (t (replace-regexp-in-string regexp rep str)) | |
79 ) | |
80 ) | |
81 | |
82 (defun flymake-split-string-remove-empty-edges(str pattern) | |
83 "split, then remove first and/or last in case it's empty" | |
84 (let* ((splitted (split-string str pattern))) | |
85 (if (and (> (length splitted) 0) (= 0 (length (elt splitted 0)))) | |
86 (setq splitted (cdr splitted)) | |
87 ) | |
88 (if (and (> (length splitted) 0) (= 0 (length (elt splitted (1- (length splitted)))))) | |
89 (setq splitted (reverse (cdr (reverse splitted)))) | |
90 ) | |
91 splitted | |
92 ) | |
93 ) | |
94 (defun flymake-split-string(str pattern) | |
95 (cond | |
96 ((equal flymake-emacs 'xemacs) (flymake-split-string-remove-empty-edges str pattern)) | |
97 (t (split-string str pattern)) | |
98 ) | |
99 ) | |
100 | |
101 (defun flymake-get-temp-dir() | |
102 (cond | |
103 ((equal flymake-emacs 'xemacs) (temp-directory)) | |
104 (t temporary-file-directory) | |
105 ) | |
106 ) | |
107 | |
108 (defun flymake-line-beginning-position() | |
109 (save-excursion | |
110 (beginning-of-line) | |
111 (point) | |
112 ) | |
113 ) | |
114 | |
115 (defun flymake-line-end-position() | |
116 (save-excursion | |
117 (end-of-line) | |
118 (point) | |
119 ) | |
120 ) | |
121 | |
122 (defun flymake-popup-menu(pos menu-data) | |
123 (cond | |
124 ((equal flymake-emacs 'xemacs) | |
125 (let* ((x-pos (nth 0 (nth 0 pos))) | |
126 (y-pos (nth 1 (nth 0 pos))) | |
127 (fake-event-props '(button 1 x 1 y 1))) | |
128 (setq fake-event-props (plist-put fake-event-props 'x x-pos)) | |
129 (setq fake-event-props (plist-put fake-event-props 'y y-pos)) | |
130 (popup-menu (flymake-make-xemacs-menu menu-data) (make-event 'button-press fake-event-props)) | |
131 ) | |
132 ) | |
133 (t (x-popup-menu pos (flymake-make-emacs-menu menu-data))) | |
134 ) | |
135 ) | |
136 | |
137 (defun flymake-make-emacs-menu(menu-data) | |
138 (let* ((menu-title (nth 0 menu-data)) | |
139 (menu-items (nth 1 menu-data)) | |
140 (menu-commands nil)) | |
141 | |
142 (setq menu-commands (mapcar (lambda (foo) | |
143 (cons (nth 0 foo) (nth 1 foo))) | |
144 menu-items)) | |
145 (list menu-title (cons "" menu-commands)) | |
146 ) | |
147 ) | |
148 | |
149 (defun flymake-nop() | |
150 ) | |
151 | |
152 (defun flymake-make-xemacs-menu(menu-data) | |
153 (let* ((menu-title (nth 0 menu-data)) | |
154 (menu-items (nth 1 menu-data)) | |
155 (menu-commands nil)) | |
156 (setq menu-commands (mapcar (lambda (foo) | |
157 (vector (nth 0 foo) (or (nth 1 foo) '(flymake-nop)) t)) | |
158 menu-items)) | |
159 (cons menu-title menu-commands) | |
160 ) | |
161 ) | |
162 | |
163 (defun flymake-xemacs-window-edges(&optional window) | |
164 (let ((edges (window-pixel-edges window)) | |
165 tmp) | |
166 (setq tmp edges) | |
167 (setcar tmp (/ (car tmp) (face-width 'default))) | |
168 (setq tmp (cdr tmp)) | |
169 (setcar tmp (/ (car tmp) (face-height 'default))) | |
170 (setq tmp (cdr tmp)) | |
171 (setcar tmp (/ (car tmp) (face-width 'default))) | |
172 (setq tmp (cdr tmp)) | |
173 (setcar tmp (/ (car tmp) (face-height 'default))) | |
174 edges | |
175 ) | |
176 ) | |
177 | |
178 (defun flymake-current-row() | |
179 "return current row in current frame" | |
180 (cond | |
181 ((equal flymake-emacs 'xemacs) (count-lines (window-start) (point))) | |
182 (t (+ (car (cdr (window-edges))) (count-lines (window-start) (point)))) | |
183 ) | |
184 ) | |
185 | |
186 (defun flymake-selected-frame() | |
187 (cond | |
188 ((equal flymake-emacs 'xemacs) (selected-window)) | |
189 (t (selected-frame)) | |
190 ) | |
191 ) | |
192 | |
193 ;;;; ]] | |
194 | |
195 (defcustom flymake-log-level -1 | |
196 "Logging level, only messages with level > flymake-log-level will not be logged | |
197 -1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG" | |
198 :group 'flymake | |
199 :type 'integer | |
200 ) | |
201 | |
202 (defun flymake-log(level text &rest args) | |
203 "Log a message with optional arguments" | |
204 (if (<= level flymake-log-level) | |
205 (let* ((msg (apply 'format text args))) | |
206 (message msg) | |
207 ;(with-temp-buffer | |
208 ; (insert msg) | |
209 ; (insert "\n") | |
210 ; (flymake-save-buffer-in-file (current-buffer) "d:/flymake.log" t) ; make log file name customizable | |
211 ;) | |
212 ) | |
213 ) | |
214 ) | |
215 | |
216 (defun flymake-ins-after(list pos val) | |
217 "insert val into list after position pos" | |
218 (let ((tmp (copy-sequence list))) ; (???) | |
219 (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp))) | |
220 tmp | |
221 ) | |
222 ) | |
223 | |
224 (defun flymake-set-at(list pos val) | |
225 "set val at position pos in list" | |
226 (let ((tmp (copy-sequence list))) ; (???) | |
227 (setcar (nthcdr pos tmp) val) | |
228 tmp | |
229 ) | |
230 ) | |
231 | |
232 (defvar flymake-pid-to-names(flymake-makehash) | |
233 "pid -> source buffer name, output file name mapping" | |
234 ) | |
235 | |
236 (defun flymake-reg-names(pid source-buffer-name) | |
237 "Save into in pid map" | |
238 (unless (stringp source-buffer-name) | |
239 (error "invalid buffer name") | |
240 ) | |
241 (puthash pid (list source-buffer-name) flymake-pid-to-names) | |
242 ) | |
243 | |
244 (defun flymake-get-source-buffer-name(pid) | |
245 "Return buffer name stored in pid map" | |
246 (nth 0 (gethash pid flymake-pid-to-names)) | |
247 ) | |
248 | |
249 (defun flymake-unreg-names(pid) | |
250 "Delete pid->buffer name mapping" | |
251 (remhash pid flymake-pid-to-names) | |
252 ) | |
253 | |
254 (defun flymake-get-buffer-var(buffer var-name) | |
255 "switch to buffer if necessary and return local variable var" | |
256 (unless (bufferp buffer) | |
257 (error "invalid buffer") | |
258 ) | |
259 | |
260 (if (eq buffer (current-buffer)) | |
261 (symbol-value var-name) | |
262 ;else | |
263 (save-excursion | |
264 (set-buffer buffer) | |
265 (symbol-value var-name) | |
266 ) | |
267 ) | |
268 ) | |
269 | |
270 (defun flymake-set-buffer-var(buffer var-name var-value) | |
271 "switch to buffer if necessary and set local variable var-name to var-value" | |
272 (unless (bufferp buffer) | |
273 (error "invalid buffer") | |
274 ) | |
275 | |
276 (if (eq buffer (current-buffer)) | |
277 (set var-name var-value) | |
278 ;else | |
279 (save-excursion | |
280 (set-buffer buffer) | |
281 (set var-name var-value) | |
282 ) | |
283 ) | |
284 ) | |
285 | |
286 (defvar flymake-buffer-data(flymake-makehash) | |
287 "data specific to syntax check tool, in name-value pairs" | |
288 ) | |
289 (make-variable-buffer-local 'flymake-buffer-data) | |
290 (defun flymake-get-buffer-data(buffer) | |
291 (flymake-get-buffer-var buffer 'flymake-buffer-data) | |
292 ) | |
293 (defun flymake-set-buffer-data(buffer data) | |
294 (flymake-set-buffer-var buffer 'flymake-buffer-data data) | |
295 ) | |
296 (defun flymake-get-buffer-value(buffer name) | |
297 (gethash name (flymake-get-buffer-data buffer)) | |
298 ) | |
299 (defun flymake-set-buffer-value(buffer name value) | |
300 (puthash name value (flymake-get-buffer-data buffer)) | |
301 ) | |
302 | |
303 (defvar flymake-output-residual nil | |
304 "" | |
305 ) | |
306 (make-variable-buffer-local 'flymake-output-residual) | |
307 (defun flymake-get-buffer-output-residual(buffer) | |
308 (flymake-get-buffer-var buffer 'flymake-output-residual) | |
309 ) | |
310 (defun flymake-set-buffer-output-residual(buffer residual) | |
311 (flymake-set-buffer-var buffer 'flymake-output-residual residual) | |
312 ) | |
313 | |
314 (defcustom flymake-allowed-file-name-masks '((".+\\.c$" flymake-simple-make-init flymake-simple-cleanup flymake-get-real-file-name) | |
315 (".+\\.cpp$" flymake-simple-make-init flymake-simple-cleanup flymake-get-real-file-name) | |
316 (".+\\.xml$" flymake-xml-init flymake-simple-cleanup flymake-get-real-file-name) | |
317 (".+\\.html?$" flymake-xml-init flymake-simple-cleanup flymake-get-real-file-name) | |
318 (".+\\.cs$" flymake-simple-make-init flymake-simple-cleanup flymake-get-real-file-name) | |
319 (".+\\.pl$" flymake-perl-init flymake-simple-cleanup flymake-get-real-file-name) | |
320 (".+\\.h$" flymake-master-make-header-init flymake-master-cleanup flymake-get-real-file-name) | |
321 (".+\\.java$" flymake-simple-make-java-init flymake-simple-java-cleanup flymake-get-real-file-name) | |
322 (".+[0-9]+\\.tex$" flymake-master-tex-init flymake-master-cleanup flymake-get-real-file-name) | |
323 (".+\\.tex$" flymake-simple-tex-init flymake-simple-cleanup flymake-get-real-file-name) | |
324 (".+\\.idl$" flymake-simple-make-init flymake-simple-cleanup flymake-get-real-file-name) | |
325 ; (".+\\.cpp$" 1) | |
326 ; (".+\\.java$" 3) | |
327 ; (".+\\.h$" 2 (".+\\.cpp$" ".+\\.c$") | |
328 ; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2)) | |
329 ; (".+\\.idl$" 1) | |
330 ; (".+\\.odl$" 1) | |
331 ; (".+[0-9]+\\.tex$" 2 (".+\\.tex$") | |
332 ; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 )) | |
333 ; (".+\\.tex$" 1) | |
334 ) | |
335 "*Files syntax checking is allowed for" | |
336 :group 'flymake | |
337 :type '(repeat (string symbol symbol symbol)) | |
338 ) | |
339 | |
340 (defun flymake-get-file-name-mode-and-masks(file-name) | |
341 "return the corresponding entry from flymake-allowed-file-name-masks" | |
342 (unless (stringp file-name) | |
343 (error "invalid file-name") | |
344 ) | |
345 (let ((count (length flymake-allowed-file-name-masks)) | |
346 (idx 0) | |
347 (mode-and-masks nil)) | |
348 (while (and (not mode-and-masks) (< idx count)) | |
349 (if (string-match (nth 0 (nth idx flymake-allowed-file-name-masks)) file-name) | |
350 (setq mode-and-masks (cdr (nth idx flymake-allowed-file-name-masks))) | |
351 ) | |
352 (setq idx (1+ idx)) | |
353 ) | |
354 (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks)) | |
355 mode-and-masks | |
356 ) | |
357 ) | |
358 | |
359 (defun flymake-can-syntax-check-file(file-name) | |
360 "Determine whether we can syntax check file-name: nil if cannot, non-nil if can" | |
361 (if (flymake-get-init-function file-name) | |
362 t | |
363 ;else | |
364 nil | |
365 ) | |
366 ) | |
367 | |
368 (defun flymake-get-init-function(file-name) | |
369 "return init function to be used for the file" | |
370 (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name)))) | |
371 ;(flymake-log 0 "calling %s" init-f) | |
372 ;(funcall init-f (current-buffer)) | |
373 ) | |
374 (nth 0 (flymake-get-file-name-mode-and-masks file-name)) | |
375 ) | |
376 | |
377 (defun flymake-get-cleanup-function(file-name) | |
378 "return cleanup function to be used for the file" | |
379 (nth 1 (flymake-get-file-name-mode-and-masks file-name)) | |
380 ) | |
381 | |
382 (defun flymake-get-real-file-name-function(file-name) | |
383 "" | |
384 (or (nth 2 (flymake-get-file-name-mode-and-masks file-name)) 'flymake-get-real-file-name) | |
385 ) | |
386 | |
387 (defcustom flymake-buildfile-dirs '("." ".." "../.." "../../.." "../../../.." "../../../../.." "../../../../../.." "../../../../../../.." "../../../../../../../.." "../../../../../../../../.." "../../../../../../../../../.." "../../../../../../../../../../..") | |
388 "dirs to look for buildfile" | |
389 :group 'flymake | |
390 :type '(repeat (string)) | |
391 ) | |
392 | |
393 (defvar flymake-find-buildfile-cache (flymake-makehash 'equal)) | |
394 (defun flymake-get-buildfile-from-cache(dir-name) | |
395 (gethash dir-name flymake-find-buildfile-cache) | |
396 ) | |
397 (defun flymake-add-buildfile-to-cache(dir-name buildfile) | |
398 (puthash dir-name buildfile flymake-find-buildfile-cache) | |
399 ) | |
400 (defun flymake-clear-buildfile-cache() | |
401 (clrhash flymake-find-buildfile-cache) | |
402 ) | |
403 | |
404 (defun flymake-find-buildfile(buildfile-name source-dir-name dirs) | |
405 "find buildfile (i.e. Makefile, build.xml, etc.) starting from current directory. Return its path or nil if not found" | |
406 (if (flymake-get-buildfile-from-cache source-dir-name) | |
407 (progn | |
408 (flymake-get-buildfile-from-cache source-dir-name) | |
409 ) | |
410 ;else | |
411 (let* ((buildfile-dir nil) | |
412 (buildfile nil) | |
413 (dir-count (length dirs)) | |
414 (dir-idx 0) | |
415 (found nil)) | |
416 | |
417 (while (and (not found) (< dir-idx dir-count)) | |
418 | |
419 (setq buildfile-dir (concat source-dir-name (nth dir-idx dirs))) | |
420 (setq buildfile (concat buildfile-dir "/" buildfile-name)) | |
421 | |
422 (when (file-exists-p buildfile) | |
423 (setq found t) | |
424 ) | |
425 | |
426 (setq dir-idx (1+ dir-idx)) | |
427 ) | |
428 (if found | |
429 (progn | |
430 (flymake-log 3 "found buildfile at %s/%s" buildfile-dir buildfile-name) | |
431 (flymake-add-buildfile-to-cache source-dir-name buildfile-dir) | |
432 buildfile-dir | |
433 ) | |
434 ;else | |
435 (progn | |
436 (flymake-log 3 "buildfile for %s not found" source-dir-name) | |
437 nil | |
438 ) | |
439 ) | |
440 ) | |
441 ) | |
442 ) | |
443 | |
444 (defun flymake-fix-path-name(name) | |
445 "replace all occurences of '\' with '/'" | |
446 (when name | |
447 (let* ((new-name (flymake-replace-regexp-in-string "[\\]" "/" (expand-file-name name))) | |
448 (last-char (elt new-name (1- (length new-name))))) | |
449 (setq new-name (flymake-replace-regexp-in-string "\\./" "" new-name)) | |
450 (if (equal "/" (char-to-string last-char)) | |
451 (setq new-name (substring new-name 0 (1- (length new-name)))) | |
452 ) | |
453 new-name | |
454 ) | |
455 ) | |
456 ) | |
457 | |
458 (defun flymake-same-files(file-name-one file-name-two) | |
459 "t if file-name-one and file-name-two actually point to the same file" | |
460 (equal (flymake-fix-path-name file-name-one) (flymake-fix-path-name file-name-two)) | |
461 ) | |
462 | |
463 (defun flymake-ensure-ends-with-slash(path) | |
464 (if (not (= (elt path (1- (length path))) (string-to-char "/"))) | |
465 (concat path "/") | |
466 ;else | |
467 path | |
468 ) | |
469 ) | |
470 | |
471 (defun flymake-get-common-path-prefix(string-one string-two) | |
472 "return common prefix for two paths" | |
473 (when (and string-one string-two) | |
474 (let* ((slash-pos-one -1) | |
475 (slash-pos-two -1) | |
476 (done nil) | |
477 (prefix nil)) | |
478 | |
479 (setq string-one (flymake-ensure-ends-with-slash string-one)) | |
480 (setq string-two (flymake-ensure-ends-with-slash string-two)) | |
481 | |
482 (while (not done) | |
483 (setq slash-pos-one (string-match "/" string-one (1+ slash-pos-one))) | |
484 (setq slash-pos-two (string-match "/" string-two (1+ slash-pos-two))) | |
485 | |
486 (if (and slash-pos-one slash-pos-two | |
487 (= slash-pos-one slash-pos-two) | |
488 (string= (substring string-one 0 slash-pos-one) (substring string-two 0 slash-pos-two))) | |
489 (progn | |
490 (setq prefix (substring string-one 0 (1+ slash-pos-one))) | |
491 ) | |
492 ;else | |
493 (setq done t) | |
494 ) | |
495 ) | |
496 prefix | |
497 ) | |
498 ) | |
499 ) | |
500 | |
501 (defun flymake-build-relative-path(from-dir to-dir) | |
502 "return rel: from-dir/rel == to-dir" | |
503 (if (not (equal (elt from-dir 0) (elt to-dir 0))) | |
504 (error "first chars in paths %s, %s must be equal (same drive)" from-dir to-dir) | |
505 ;else | |
506 (let* ((from (flymake-ensure-ends-with-slash (flymake-fix-path-name from-dir))) | |
507 (to (flymake-ensure-ends-with-slash (flymake-fix-path-name to-dir))) | |
508 (prefix (flymake-get-common-path-prefix from to)) | |
509 (from-suffix (substring from (length prefix))) | |
510 (up-count (length (flymake-split-string from-suffix "[/]"))) | |
511 (to-suffix (substring to (length prefix))) | |
512 (idx 0) | |
513 (rel nil)) | |
514 | |
515 (if (and (> (length to-suffix) 0) (equal "/" (char-to-string (elt to-suffix 0)))) | |
516 (setq to-suffix (substring to-suffix 1)) | |
517 ) | |
518 | |
519 (while (< idx up-count) | |
520 (if (> (length rel) 0) | |
521 (setq rel (concat rel "/")) | |
522 ) | |
523 (setq rel (concat rel "..")) | |
524 (setq idx (1+ idx)) | |
525 ) | |
526 (if (> (length rel) 0) | |
527 (setq rel (concat rel "/")) | |
528 ) | |
529 (if (> (length to-suffix) 0) | |
530 (setq rel (concat rel to-suffix)) | |
531 ) | |
532 | |
533 (or rel "./") | |
534 ) | |
535 ) | |
536 ) | |
537 | |
538 (defcustom flymake-master-file-dirs '("." "./src" "./UnitTest") | |
539 "dirs where to llok for master files" | |
540 :group 'flymake | |
541 :type '(repeat (string)) | |
542 ) | |
543 | |
544 (defcustom flymake-master-file-count-limit 32 | |
545 "max number of master files to check" | |
546 :group 'flymake | |
547 :type 'integer | |
548 ) | |
549 | |
550 (defun flymake-find-possible-master-files(file-name master-file-dirs masks) | |
551 "find (by name and location) all posible master files, which are .cpp and .c for and .h. | |
552 Files are searched for starting from the .h directory and max max-level parent dirs. | |
553 File contents are not checked." | |
554 (let* ((dir-idx 0) | |
555 (dir-count (length master-file-dirs)) | |
556 (files nil) | |
557 (done nil) | |
558 (masks-count (length masks))) | |
559 | |
560 (while (and (not done) (< dir-idx dir-count)) | |
561 (let* ((dir (concat (flymake-fix-path-name (file-name-directory file-name)) "/" (nth dir-idx master-file-dirs))) | |
562 (masks-idx 0)) | |
563 (while (and (file-exists-p dir) (not done) (< masks-idx masks-count)) | |
564 (let* ((mask (nth masks-idx masks)) | |
565 (dir-files (directory-files dir t mask)) | |
566 (file-count (length dir-files)) | |
567 (file-idx 0)) | |
568 | |
569 (flymake-log 3 "dir %s, %d file(s) for mask %s" dir file-count mask) | |
570 (while (and (not done) (< file-idx file-count)) | |
571 (when (not (file-directory-p (nth file-idx dir-files))) | |
572 (setq files (cons (nth file-idx dir-files) files)) | |
573 (when (>= (length files) flymake-master-file-count-limit) | |
574 (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit) | |
575 (setq done t) | |
576 ) | |
577 ) | |
578 (setq file-idx (1+ file-idx)) | |
579 ) | |
580 ) | |
581 (setq masks-idx (1+ masks-idx)) | |
582 ) | |
583 ) | |
584 (setq dir-idx (1+ dir-idx)) | |
585 ) | |
586 (when files | |
587 (setq flymake-included-file-name (file-name-nondirectory file-name)) | |
588 (setq files (sort files 'flymake-master-file-compare)) | |
589 (setq flymake-included-file-name nil) | |
590 ) | |
591 (flymake-log 3 "found %d possible master file(s)" (length files)) | |
592 files | |
593 ) | |
594 ) | |
595 | |
596 (defvar flymake-included-file-name nil ; this is used to pass a parameter to a sort predicate below | |
597 "" | |
598 ) | |
599 | |
600 (defun flymake-master-file-compare(file-one file-two) | |
601 "used in sort to move most possible file names to the beginning of the list (File.h -> File.cpp moved to top" | |
602 (and (equal (file-name-sans-extension flymake-included-file-name) | |
603 (file-name-sans-extension (file-name-nondirectory file-one))) | |
604 (not (equal file-one file-two)) | |
605 ) | |
606 ) | |
607 | |
608 (defcustom flymake-check-file-limit 8192 | |
609 "max number of chars to look at when checking possible master file" | |
610 :group 'flymake | |
611 :type 'integer | |
612 ) | |
613 | |
614 (defun flymake-check-patch-master-file-buffer(master-file-temp-buffer | |
615 master-file-name patched-master-file-name | |
616 source-file-name patched-source-file-name | |
617 include-dirs regexp-list) | |
618 "check whether master-file-name is indeed a master file for source-file-name. | |
619 For .cpp master file this means it includes source-file-name (.h). | |
620 If yes, patch a copy of master-file-name to include patched-source-file-name instead of source-file-name. | |
621 Whenether a buffer for master-file-name exists, use it as a source instead of reading master file from disk" | |
622 (let* ((found nil) | |
623 (regexp (format (nth 0 regexp-list) ; "[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" | |
624 (file-name-nondirectory source-file-name))) | |
625 (path-idx (nth 1 regexp-list)) | |
626 (name-idx (nth 2 regexp-list)) | |
627 (inc-path nil) | |
628 (inc-name nil) | |
629 (search-limit flymake-check-file-limit)) | |
630 (save-excursion | |
631 (unwind-protect | |
632 (progn | |
633 (set-buffer master-file-temp-buffer) | |
634 (when (> search-limit (point-max)) | |
635 (setq search-limit (point-max)) | |
636 ) | |
637 (flymake-log 3 "checking %s against regexp %s" master-file-name regexp) | |
638 (goto-char (point-min)) | |
639 (while (and (< (point) search-limit) (re-search-forward regexp search-limit t)) | |
640 (let* ((match-beg (match-beginning name-idx)) | |
641 (match-end (match-end name-idx))) | |
642 | |
643 (flymake-log 3 "found possible match for %s" (file-name-nondirectory source-file-name)) | |
644 (setq inc-path (match-string path-idx)) | |
645 (setq inc-name (match-string name-idx)) | |
646 (when (string= inc-name (file-name-nondirectory source-file-name)) | |
647 (flymake-log 3 "inc-path=%s inc-name=%s" inc-path inc-name) | |
648 (when (flymake-check-include source-file-name inc-path inc-name include-dirs) | |
649 (setq found t) | |
650 ; replace-match is not used here as it fails in xemacs with | |
651 ; 'last match not a buffer' error as check-includes calls replace-in-string | |
652 (flymake-replace-region (current-buffer) match-beg match-end | |
653 (file-name-nondirectory patched-source-file-name)) | |
654 ) | |
655 ) | |
656 (forward-line 1) | |
657 ) | |
658 ) | |
659 (when found | |
660 (flymake-save-buffer-in-file (current-buffer) patched-master-file-name) | |
661 ) | |
662 ) | |
663 ;+(flymake-log 3 "killing buffer %s" (buffer-name master-file-temp-buffer)) | |
664 (kill-buffer master-file-temp-buffer) | |
665 ) | |
666 ) | |
667 ;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found) | |
668 (when found | |
669 (flymake-log 2 "found master file %s" master-file-name) | |
670 ) | |
671 found | |
672 ) | |
673 ) | |
674 | |
675 (defun flymake-replace-region(buffer beg end rep) | |
676 "replace text in buffer in region (beg; end) with rep" | |
677 (save-excursion | |
678 (delete-region beg end) | |
679 (goto-char beg) | |
680 (insert rep) | |
681 ) | |
682 ) | |
683 | |
684 (defun flymake-read-file-to-temp-buffer(file-name) | |
685 "isert contents of file-name into newly created temp buffer" | |
686 (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name)))))) | |
687 (save-excursion | |
688 (set-buffer temp-buffer) | |
689 (insert-file-contents file-name) | |
690 ) | |
691 temp-buffer | |
692 ) | |
693 ) | |
694 | |
695 (defun flymake-copy-buffer-to-temp-buffer(buffer) | |
696 "copy contents of buffer into newly created temp buffer" | |
697 (let ((contents nil) | |
698 (temp-buffer nil)) | |
699 (save-excursion | |
700 (set-buffer buffer) | |
701 (setq contents (buffer-string)) | |
702 | |
703 (setq temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (buffer-name buffer))))) | |
704 (set-buffer temp-buffer) | |
705 (insert contents) | |
706 ) | |
707 temp-buffer | |
708 ) | |
709 ) | |
710 | |
711 (defun flymake-check-include(source-file-name inc-path inc-name include-dirs) | |
712 "t if source-file-name is the one found via include dirs using inc-path and inc-name" | |
713 (if (file-name-absolute-p inc-path) | |
714 (flymake-same-files source-file-name (concat inc-path "/" inc-name)) | |
715 ;else | |
716 (let* ((count (length include-dirs)) | |
717 (idx 0) | |
718 (file-name nil) | |
719 (found nil)) | |
720 (while (and (not found) (< idx count)) | |
721 (setq file-name (concat (file-name-directory source-file-name) "/" (nth idx include-dirs))) | |
722 (if (> (length inc-path) 0) | |
723 (setq file-name (concat file-name "/" inc-path)) | |
724 ) | |
725 (setq file-name (concat file-name "/" inc-name)) | |
726 (when (flymake-same-files source-file-name file-name) | |
727 (setq found t) | |
728 ) | |
729 (setq idx (1+ idx)) | |
730 ) | |
731 found | |
732 ) | |
733 ) | |
734 ) | |
735 | |
736 (defun flymake-find-buffer-for-file(file-name) | |
737 "buffer if there exists a buffer visiting file-name, nil otherwise" | |
738 (let ((buffer-name (get-file-buffer file-name))) | |
739 (if buffer-name | |
740 (get-buffer buffer-name) | |
741 ) | |
742 ) | |
743 ) | |
744 | |
745 (defun flymake-create-master-file(source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp-list) | |
746 "save source-file-name with a different name, find master file, patch it and save it to." | |
747 (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks)) | |
748 (master-file-count (length possible-master-files)) | |
749 (idx 0) | |
750 (temp-buffer nil) | |
751 (master-file-name nil) | |
752 (patched-master-file-name nil) | |
753 (found nil)) | |
754 | |
755 (while (and (not found) (< idx master-file-count)) | |
756 (setq master-file-name (nth idx possible-master-files)) | |
757 (setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master")) | |
758 (if (flymake-find-buffer-for-file master-file-name) | |
759 (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name))) | |
760 ;else | |
761 (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name)) | |
762 ) | |
763 (setq found | |
764 (flymake-check-patch-master-file-buffer | |
765 temp-buffer | |
766 master-file-name | |
767 patched-master-file-name | |
768 source-file-name | |
769 patched-source-file-name | |
770 (funcall get-incl-dirs-f (file-name-directory master-file-name)) | |
771 include-regexp-list)) | |
772 (setq idx (1+ idx)) | |
773 ) | |
774 (if found | |
775 (list master-file-name patched-master-file-name) | |
776 ;else | |
777 (progn | |
778 (flymake-log 3 "none of %d master file(s) checked includes %s" master-file-count | |
779 (file-name-nondirectory source-file-name)) | |
780 nil | |
781 ) | |
782 ) | |
783 ) | |
784 ) | |
785 | |
786 (defun flymake-save-buffer-in-file(buffer file-name) | |
787 (or buffer | |
788 (error "invalid buffer") | |
789 ) | |
790 (save-excursion | |
791 (save-restriction | |
792 (set-buffer buffer) | |
793 (widen) | |
794 (make-directory (file-name-directory file-name) 1) | |
795 (write-region (point-min) (point-max) file-name nil 566) | |
796 ) | |
797 ) | |
798 (flymake-log 3 "saved buffer %s in file %s" (buffer-name buffer) file-name) | |
799 ) | |
800 | |
801 (defun flymake-save-string-to-file(file-name data) | |
802 "save string data to file file-name" | |
803 (write-region data nil file-name nil 566) | |
804 ) | |
805 | |
806 (defun flymake-read-file-to-string(file-name) | |
807 "read file contents and return them as a string" | |
808 (with-temp-buffer | |
809 (insert-file-contents file-name) | |
810 (buffer-substring (point-min) (point-max)) | |
811 ) | |
812 ) | |
813 | |
814 (defun flymake-process-filter(process output) | |
815 "flymake process filter: parse output, highlight err lines" | |
816 (let* ((pid (process-id process)) | |
817 (source-buffer (get-buffer (flymake-get-source-buffer-name pid)))) | |
818 | |
819 (flymake-log 3 "received %d byte(s) of output from process %d" (length output) pid) | |
820 (when source-buffer | |
821 (flymake-parse-output-and-residual source-buffer output) | |
822 ) | |
823 ) | |
824 ) | |
825 | |
826 (defun flymake-process-sentinel(process event) | |
827 "Sentinel for syntax check buffers" | |
828 (if (memq (process-status process) '(signal exit)) | |
829 (let*((exit-status (process-exit-status process)) | |
830 (command (process-command process)) | |
831 (pid (process-id process)) | |
832 (source-buffer (get-buffer (flymake-get-source-buffer-name pid))) | |
833 (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer)))) | |
834 | |
835 (flymake-log 2 "process %d exited with code %d" pid exit-status) | |
836 (condition-case err | |
837 (progn | |
838 (flymake-log 3 "cleaning up using %s" cleanup-f) | |
839 (funcall cleanup-f source-buffer) | |
840 | |
841 (flymake-unreg-names pid) | |
842 (delete-process process) | |
843 | |
844 (when source-buffer | |
845 (save-excursion | |
846 (set-buffer source-buffer) | |
847 | |
848 (flymake-parse-residual source-buffer) | |
849 (flymake-post-syntax-check source-buffer) | |
850 (flymake-set-buffer-is-running source-buffer nil) | |
851 ) | |
852 ) | |
853 ) | |
854 (error | |
855 (let ((err-str (format "Error in process sentinel for buffer %s: %s" | |
856 source-buffer (error-message-string err)))) | |
857 (flymake-log 0 err-str) | |
858 (flymake-set-buffer-is-running source-buffer nil) | |
859 ) | |
860 ) | |
861 ) | |
862 ) | |
863 ) | |
864 ) | |
865 | |
866 (defun flymake-post-syntax-check(source-buffer) | |
867 "" | |
868 (flymake-set-buffer-err-info source-buffer (flymake-get-buffer-new-err-info source-buffer)) | |
869 (flymake-set-buffer-new-err-info source-buffer nil) | |
870 | |
871 (flymake-set-buffer-err-info source-buffer (flymake-fix-line-numbers | |
872 (flymake-get-buffer-err-info source-buffer) | |
873 1 | |
874 (flymake-count-lines source-buffer))) | |
875 (flymake-delete-own-overlays source-buffer) | |
876 (flymake-highlight-err-lines source-buffer (flymake-get-buffer-err-info source-buffer)) | |
877 | |
878 (let ((err-count (flymake-get-err-count (flymake-get-buffer-err-info source-buffer) "e")) | |
879 (warn-count (flymake-get-err-count (flymake-get-buffer-err-info source-buffer) "w"))) | |
880 | |
881 (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)" | |
882 (buffer-name source-buffer) err-count warn-count | |
883 (- (flymake-float-time) (flymake-get-buffer-check-start-time source-buffer))) | |
884 (flymake-set-buffer-check-start-time source-buffer nil) | |
885 (if (and (equal 0 err-count) (equal 0 warn-count)) | |
886 (if (equal 0 exit-status) | |
887 (flymake-report-status source-buffer "" "") ; PASSED | |
888 ;else | |
889 (if (not (flymake-get-buffer-check-was-interrupted source-buffer)) | |
890 (flymake-report-fatal-status (current-buffer) "CFGERR" | |
891 (format "Configuration error has occured while running %s" command)) | |
892 ;else | |
893 (flymake-report-status source-buffer nil "") ; "STOPPED" | |
894 ) | |
895 ) | |
896 ;else | |
897 (flymake-report-status source-buffer (format "%d/%d" err-count warn-count) "") | |
898 ) | |
899 ) | |
900 ) | |
901 | |
902 (defun flymake-parse-output-and-residual(source-buffer output) | |
903 "split output into lines, merge in residual if necessary" | |
904 (save-excursion | |
905 (set-buffer source-buffer) | |
906 (let* ((buffer-residual (flymake-get-buffer-output-residual source-buffer)) | |
907 (total-output (if buffer-residual (concat buffer-residual output) output)) | |
908 (lines-and-residual (flymake-split-output total-output)) | |
909 (lines (nth 0 lines-and-residual)) | |
910 (new-residual (nth 1 lines-and-residual))) | |
911 | |
912 (flymake-set-buffer-output-residual source-buffer new-residual) | |
913 (flymake-set-buffer-new-err-info source-buffer (flymake-parse-err-lines | |
914 (flymake-get-buffer-new-err-info source-buffer) | |
915 source-buffer lines)) | |
916 ) | |
917 ) | |
918 ) | |
919 | |
920 (defun flymake-parse-residual(source-buffer) | |
921 "parse residual if it's non empty" | |
922 (save-excursion | |
923 (set-buffer source-buffer) | |
924 (when (flymake-get-buffer-output-residual source-buffer) | |
925 (flymake-set-buffer-new-err-info source-buffer (flymake-parse-err-lines | |
926 (flymake-get-buffer-new-err-info source-buffer) | |
927 source-buffer | |
928 (list (flymake-get-buffer-output-residual source-buffer)))) | |
929 (flymake-set-buffer-output-residual source-buffer nil) | |
930 ) | |
931 ) | |
932 ) | |
933 | |
934 (defvar flymake-err-info nil | |
935 "sorted list of line numbers and lists of err info in the form (file, err-text)." | |
936 ) | |
937 (make-variable-buffer-local 'flymake-err-info) | |
938 (defun flymake-get-buffer-err-info(buffer) | |
939 (flymake-get-buffer-var buffer 'flymake-err-info) | |
940 ) | |
941 (defun flymake-set-buffer-err-info(buffer err-info) | |
942 (flymake-set-buffer-var buffer 'flymake-err-info err-info) | |
943 ) | |
944 (defun flymake-er-make-er(line-no line-err-info-list) | |
945 (list line-no line-err-info-list) | |
946 ) | |
947 (defun flymake-er-get-line(err-info) | |
948 (nth 0 err-info) | |
949 ) | |
950 (defun flymake-er-get-line-err-info-list(err-info) | |
951 (nth 1 err-info) | |
952 ) | |
953 | |
954 (defvar flymake-new-err-info nil | |
955 "the same as flymake -err-info, effective when a syntax check is in progress" | |
956 ) | |
957 (make-variable-buffer-local 'flymake-new-err-info) | |
958 (defun flymake-get-buffer-new-err-info(buffer) | |
959 (flymake-get-buffer-var buffer 'flymake-new-err-info) | |
960 ) | |
961 (defun flymake-set-buffer-new-err-info(buffer new-err-info) | |
962 (flymake-set-buffer-var buffer 'flymake-new-err-info new-err-info) | |
963 ) | |
964 | |
965 ;; getters/setters for line-err-info: (file, line, type, text). | |
966 (defun flymake-ler-make-ler(file line type text &optional full-file) | |
967 (list file line type text full-file) | |
968 ) | |
969 (defun flymake-ler-get-file(line-err-info) | |
970 (nth 0 line-err-info) | |
971 ) | |
972 (defun flymake-ler-get-line(line-err-info) | |
973 (nth 1 line-err-info) | |
974 ) | |
975 (defun flymake-ler-get-type(line-err-info) | |
976 (nth 2 line-err-info) | |
977 ) | |
978 (defun flymake-ler-get-text(line-err-info) | |
979 (nth 3 line-err-info) | |
980 ) | |
981 (defun flymake-ler-get-full-file(line-err-info) | |
982 (nth 4 line-err-info) | |
983 ) | |
984 (defun flymake-ler-set-file(line-err-info file) | |
985 (flymake-ler-make-ler file | |
986 (flymake-ler-get-line line-err-info) | |
987 (flymake-ler-get-type line-err-info) | |
988 (flymake-ler-get-text line-err-info) | |
989 (flymake-ler-get-full-file line-err-info)) | |
990 ) | |
991 (defun flymake-ler-set-full-file(line-err-info full-file) | |
992 (flymake-ler-make-ler (flymake-ler-get-file line-err-info) | |
993 (flymake-ler-get-line line-err-info) | |
994 (flymake-ler-get-type line-err-info) | |
995 (flymake-ler-get-text line-err-info) | |
996 full-file) | |
997 ) | |
998 (defun flymake-ler-set-line(line-err-info line) | |
999 (flymake-ler-make-ler (flymake-ler-get-file line-err-info) | |
1000 line | |
1001 (flymake-ler-get-type line-err-info) | |
1002 (flymake-ler-get-text line-err-info) | |
1003 (flymake-ler-get-full-file line-err-info)) | |
1004 ) | |
1005 | |
1006 (defun flymake-get-line-err-count(line-err-info-list type) | |
1007 "return number of errors of specified type - e or w" | |
1008 (let* ((idx 0) | |
1009 (count (length line-err-info-list)) | |
1010 (err-count 0)) | |
1011 | |
1012 (while (< idx count) | |
1013 (when (equal type (flymake-ler-get-type (nth idx line-err-info-list))) | |
1014 (setq err-count (1+ err-count)) | |
1015 ) | |
1016 (setq idx (1+ idx)) | |
1017 ) | |
1018 err-count | |
1019 ) | |
1020 ) | |
1021 | |
1022 (defun flymake-get-err-count(err-info-list type) | |
1023 "return number of errors of specified type for the err-info-list" | |
1024 (let* ((idx 0) | |
1025 (count (length err-info-list)) | |
1026 (err-count 0)) | |
1027 (while (< idx count) | |
1028 (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type))) | |
1029 (setq idx (1+ idx)) | |
1030 ) | |
1031 err-count | |
1032 ) | |
1033 ) | |
1034 | |
1035 (defun flymake-fix-line-numbers(err-info-list min-line max-line) | |
1036 "replace line-numbers < min-line with min-line and > max-line with max-line - as some compilers might report line number outside the file being compiled" | |
1037 (let* ((count (length err-info-list)) | |
1038 (err-info nil) | |
1039 (line 0)) | |
1040 (while (> count 0) | |
1041 (setq err-info (nth (1- count) err-info-list)) | |
1042 (setq line (flymake-er-get-line err-info)) | |
1043 (when (or (< line min-line) (> line max-line)) | |
1044 (setq line (if (< line min-line) min-line max-line)) | |
1045 (setq err-info-list (flymake-set-at err-info-list (1- count) | |
1046 (flymake-er-make-er line | |
1047 (flymake-er-get-line-err-info-list err-info)))) | |
1048 ) | |
1049 (setq count (1- count)) | |
1050 ) | |
1051 ) | |
1052 err-info-list | |
1053 ) | |
1054 | |
1055 (defun flymake-highlight-err-lines(buffer err-info-list) | |
1056 "highlight err-lines in buffer using info from err-info-list" | |
1057 (save-excursion | |
1058 (set-buffer buffer) | |
1059 (let* ((idx 0) | |
1060 (count (length err-info-list))) | |
1061 (while (< idx count) | |
1062 (flymake-highlight-line (car (nth idx err-info-list)) (nth 1 (nth idx err-info-list))) | |
1063 (setq idx (1+ idx)) | |
1064 ) | |
1065 ) | |
1066 ) | |
1067 ) | |
1068 | |
1069 (defun flymake-overlay-p(ov) | |
1070 "Determine whether overlay was created by flymake" | |
1071 (and (overlayp ov) (overlay-get ov 'flymake-overlay)) | |
1072 ) | |
1073 | |
1074 (defun flymake-make-overlay(beg end tooltip-text face mouse-face) | |
1075 "Allocate a flymake overlay in range beg end" | |
1076 (when (not (flymake-region-has-flymake-overlays beg end)) | |
1077 (let ((ov (make-overlay beg end nil t t))) | |
1078 (overlay-put ov 'face face) | |
1079 (overlay-put ov 'mouse-face mouse-face) | |
1080 (overlay-put ov 'help-echo tooltip-text) | |
1081 (overlay-put ov 'flymake-overlay t) | |
1082 (overlay-put ov 'priority 100) | |
1083 ;+(flymake-log 3 "created overlay %s" ov) | |
1084 ov | |
1085 ) | |
1086 (flymake-log 3 "created an overlay at (%d-%d)" beg end) | |
1087 ) | |
1088 ) | |
1089 | |
1090 (defun flymake-delete-own-overlays(buffer) | |
1091 "Delete all flymake overlays in buffer" | |
1092 (save-excursion | |
1093 (set-buffer buffer) | |
1094 (let ((ov (overlays-in (point-min) (point-max)))) | |
1095 (while (consp ov) | |
1096 (when (flymake-overlay-p (car ov)) | |
1097 (delete-overlay (car ov)) | |
1098 ;+(flymake-log 3 "deleted overlay %s" ov) | |
1099 ) | |
1100 (setq ov (cdr ov)) | |
1101 ) | |
1102 ) | |
1103 ) | |
1104 ) | |
1105 | |
1106 (defun flymake-region-has-flymake-overlays(beg end) | |
1107 "t if specified regions has at least one flymake overlay, nil otrherwise" | |
1108 (let ((ov (overlays-in beg end)) | |
1109 (has-flymake-overlays nil)) | |
1110 (while (consp ov) | |
1111 (when (flymake-overlay-p (car ov)) | |
1112 (setq has-flymake-overlays t) | |
1113 ) | |
1114 (setq ov (cdr ov)) | |
1115 ) | |
1116 ) | |
1117 ) | |
1118 | |
1119 (defface flymake-errline-face | |
1120 ;+ '((((class color)) (:foreground "OrangeRed" :bold t :underline t)) | |
1121 ;+ '((((class color)) (:underline "OrangeRed")) | |
1122 '((((class color)) (:background "LightPink")) | |
1123 (t (:bold t))) | |
1124 "Face used for marking error lines" | |
1125 :group 'flymake | |
1126 ) | |
1127 | |
1128 (defface flymake-warnline-face | |
1129 '((((class color)) (:background "LightBlue2")) | |
1130 (t (:bold t))) | |
1131 "Face used for marking warning lines" | |
1132 :group 'flymake | |
1133 ) | |
1134 | |
1135 | |
1136 (defun flymake-highlight-line(line-no line-err-info-list) | |
1137 "highlight line line-no in current buffer, perhaps use text from line-err-info-list to enhance highlighting" | |
1138 (goto-line line-no) | |
1139 (let* ((line-beg (flymake-line-beginning-position)) | |
1140 (line-end (flymake-line-end-position)) | |
1141 (beg line-beg) | |
1142 (end line-end) | |
1143 (tooltip-text (flymake-ler-get-text (nth 0 line-err-info-list))) | |
1144 (face nil)) | |
1145 | |
1146 (goto-char line-beg) | |
1147 (while (looking-at "[ \t]") | |
1148 (forward-char) | |
1149 ) | |
1150 | |
1151 (setq beg (point)) | |
1152 | |
1153 (goto-char line-end) | |
1154 (while (and (looking-at "[ \t\r\n]") (> (point) 1)) | |
1155 (backward-char) | |
1156 ) | |
1157 | |
1158 (setq end (1+ (point))) | |
1159 | |
1160 (when (<= end beg) | |
1161 (setq beg line-beg) | |
1162 (setq end line-end) | |
1163 ) | |
1164 (when (= end beg) | |
1165 (goto-char end) | |
1166 (forward-line) | |
1167 (setq end (point)) | |
1168 ) | |
1169 (if (> (flymake-get-line-err-count line-err-info-list "e") 0) | |
1170 (setq face 'flymake-errline-face) | |
1171 ;else | |
1172 (setq face 'flymake-warnline-face) | |
1173 ) | |
1174 (flymake-make-overlay beg end tooltip-text face nil) | |
1175 ) | |
1176 ) | |
1177 | |
1178 (defun flymake-parse-err-lines(err-info-list source-buffer lines) | |
1179 "parse err lines, store info in err-info-list" | |
1180 (let* ((count (length lines)) | |
1181 (idx 0) | |
1182 (line-err-info nil) | |
1183 (real-file-name nil) | |
1184 (source-file-name (buffer-file-name source-buffer)) | |
1185 (get-real-file-name-f (flymake-get-real-file-name-function source-file-name))) | |
1186 | |
1187 (while (< idx count) | |
1188 (setq line-err-info (flymake-parse-line (nth idx lines))) | |
1189 (when line-err-info | |
1190 (setq real-file-name (funcall get-real-file-name-f source-buffer (flymake-ler-get-file line-err-info))) | |
1191 (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name)) | |
1192 | |
1193 (if (flymake-same-files real-file-name source-file-name) | |
1194 (setq line-err-info (flymake-ler-set-file line-err-info nil)) | |
1195 ;else | |
1196 (setq line-err-info (flymake-ler-set-file line-err-info (file-name-nondirectory real-file-name))) | |
1197 ) | |
1198 | |
1199 (setq err-info-list (flymake-add-err-info err-info-list line-err-info)) | |
1200 ) | |
1201 (flymake-log 3 "parsed '%s', %s line-err-info" (nth idx lines) (if line-err-info "got" "no")) | |
1202 (setq idx (1+ idx)) | |
1203 ) | |
1204 err-info-list | |
1205 ) | |
1206 ) | |
1207 | |
1208 (defun flymake-split-output(output) | |
1209 "split output into lines, return last one as residual if it does not end with newline char. Returns ((lines) residual)" | |
1210 (when (and output (> (length output) 0)) | |
1211 (let* ((lines (flymake-split-string output "[\n\r]+")) | |
1212 (complete (equal "\n" (char-to-string (aref output (1- (length output)))))) | |
1213 (residual nil)) | |
1214 (when (not complete) | |
1215 (setq residual (car (last lines))) | |
1216 (setq lines (butlast lines)) | |
1217 ) | |
1218 (list lines residual) | |
1219 ) | |
1220 ) | |
1221 ) | |
1222 | |
1223 (eval-when-compile (require 'compile)) | |
1224 (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 | |
1225 (append | |
1226 '( | |
1227 ; MS Visual C++ 6.0 | |
1228 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \: \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)" | |
1229 1 3 nil 4) | |
1230 ; jikes | |
1231 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[0-9]+\:[0-9]+\:[0-9]+\: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)" | |
1232 1 3 nil 4) | |
1233 ; MS midl | |
1234 ("midl[ ]*:[ ]*\\(command line error .*\\)" | |
1235 nil nil nil 1) | |
1236 ; MS C# | |
1237 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+)\: \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)" | |
1238 1 3 nil 4) | |
1239 ; perl | |
1240 ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1) | |
1241 ; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1) | |
1242 ; ant/javac | |
1243 (" *\\(\\[javac\\]\\)? *\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[ \t\n]*\\(.+\\)" | |
1244 2 4 nil 5) | |
1245 ) | |
1246 compilation-error-regexp-alist) | |
1247 "patterns for matching error/warning lines, (regexp file-idx line-idx err-text-idx)" | |
1248 ) | |
1249 ;(defcustom flymake-err-line-patterns | |
1250 ; '( | |
1251 ; ; MS Visual C++ 6.0 | |
1252 ; ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \: \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)" | |
1253 ; 1 3 4) | |
1254 ; ; jikes | |
1255 ; ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[0-9]+\:[0-9]+\:[0-9]+\: \\(\\(Error\\|Warning\\|Caution\\):[ \t\n]*\\(.+\\)\\)" | |
1256 ; 1 3 4)) | |
1257 ; "patterns for matching error/warning lines, (regexp file-idx line-idx err-text-idx)" | |
1258 ; :group 'flymake | |
1259 ; :type '(repeat (string number number number)) | |
1260 ;) | |
1261 | |
1262 (defun flymake-parse-line(line) | |
1263 "parse line to see whether it's an error of warning, return it's components or nil for no match" | |
1264 (let ((raw-file-name nil) | |
1265 (line-no 0) | |
1266 (err-type "e") | |
1267 (err-text nil) | |
1268 (count (length flymake-err-line-patterns)) | |
1269 (idx 0) | |
1270 (matched nil)) | |
1271 (while (and (< idx count) (not matched)) | |
1272 (when (string-match (car (nth idx flymake-err-line-patterns)) line) | |
1273 (let* ((file-idx (nth 1 (nth idx flymake-err-line-patterns))) | |
1274 (line-idx (nth 2 (nth idx flymake-err-line-patterns)))) | |
1275 | |
1276 (setq raw-file-name (if file-idx (match-string file-idx line) nil)) | |
1277 (setq line-no (if line-idx (string-to-int (match-string line-idx line)) 0)) | |
1278 (setq err-text (if (> (length (nth idx flymake-err-line-patterns)) 4) | |
1279 (match-string (nth 4 (nth idx flymake-err-line-patterns)) line) | |
1280 (flymake-patch-err-text (substring line (match-end 0))))) | |
1281 (or err-text (setq err-text "<no error text>")) | |
1282 (if (and err-text (string-match "^[wW]arning" err-text)) | |
1283 (setq err-type "w") | |
1284 ) | |
1285 (flymake-log 3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s" file-idx line-idx | |
1286 raw-file-name line-no err-text) | |
1287 (setq matched t) | |
1288 ) | |
1289 ) | |
1290 (setq idx (1+ idx)) | |
1291 ) | |
1292 (if matched | |
1293 (flymake-ler-make-ler raw-file-name line-no err-type err-text) | |
1294 ; else | |
1295 () | |
1296 ) | |
1297 ) | |
1298 ) | |
1299 | |
1300 (defun flymake-find-err-info(err-info-list line-no) | |
1301 "find (line-err-info-list pos) for specified line-no" | |
1302 (if err-info-list | |
1303 (let* ((line-err-info-list nil) | |
1304 (pos 0) | |
1305 (count (length err-info-list))) | |
1306 | |
1307 (while (and (< pos count) (< (car (nth pos err-info-list)) line-no)) | |
1308 (setq pos (1+ pos)) | |
1309 ) | |
1310 (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no)) | |
1311 (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list))) | |
1312 ) | |
1313 (list line-err-info-list pos) | |
1314 ) | |
1315 ;else | |
1316 '(nil 0) | |
1317 ) | |
1318 ) | |
1319 | |
1320 (defun flymake-line-err-info-is-less-or-equal(line-one line-two) | |
1321 (or (string< (flymake-ler-get-type line-one) (flymake-ler-get-type line-two)) | |
1322 (and (string= (flymake-ler-get-type line-one) (flymake-ler-get-type line-two)) | |
1323 (not (flymake-ler-get-file line-one)) (flymake-ler-get-file line-two) | |
1324 ) | |
1325 (and (string= (flymake-ler-get-type line-one) (flymake-ler-get-type line-two)) | |
1326 (or (and (flymake-ler-get-file line-one) (flymake-ler-get-file line-two)) | |
1327 (and (not (flymake-ler-get-file line-one)) (not (flymake-ler-get-file line-two))) | |
1328 ) | |
1329 ) | |
1330 ) | |
1331 ) | |
1332 | |
1333 (defun flymake-add-line-err-info(line-err-info-list line-err-info) | |
1334 "insert new err info favoring sorting: err-type e/w, filename nil/non-nill" | |
1335 (if (not line-err-info-list) | |
1336 (list line-err-info) | |
1337 ;else | |
1338 (let* ((count (length line-err-info-list)) | |
1339 (idx 0)) | |
1340 (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info)) | |
1341 (setq idx (1+ idx)) | |
1342 ) | |
1343 (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list))) | |
1344 (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info))) | |
1345 ) | |
1346 line-err-info-list | |
1347 ) | |
1348 ) | |
1349 ) | |
1350 | |
1351 (defun flymake-add-err-info(err-info-list line-err-info) | |
1352 "add error info (file line type text) to err info list preserving sort order" | |
1353 (let* ((count (length err-info-list)) | |
1354 (line-no (if (flymake-ler-get-file line-err-info) 1 (flymake-ler-get-line line-err-info))) | |
1355 (info-and-pos (flymake-find-err-info err-info-list line-no)) | |
1356 (exists (car info-and-pos)) | |
1357 (pos (nth 1 info-and-pos)) | |
1358 (line-err-info-list nil) | |
1359 (err-info nil)) | |
1360 | |
1361 (if exists | |
1362 (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list)))) | |
1363 ) | |
1364 (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info)) | |
1365 | |
1366 (setq err-info (flymake-er-make-er line-no line-err-info-list)) | |
1367 (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info))) | |
1368 ((equal 0 pos) (setq err-info-list (cons err-info err-info-list))) | |
1369 (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info))) | |
1370 ) | |
1371 err-info-list | |
1372 ) | |
1373 ) | |
1374 | |
1375 (defun flymake-get-project-include-dirs-imp(basedir) | |
1376 "include dirs for the project current file belongs to" | |
1377 (if (flymake-get-project-include-dirs-from-cache basedir) | |
1378 (progn | |
1379 (flymake-get-project-include-dirs-from-cache basedir) | |
1380 ) | |
1381 ;else | |
1382 (let* ((command-line (concat "make -C\"" basedir "\" DUMPVARS=INCLUDE_DIRS dumpvars")) | |
1383 (output (shell-command-to-string command-line)) | |
1384 (lines (flymake-split-string output "\n")) | |
1385 (count (length lines)) | |
1386 (idx 0) | |
1387 (inc-dirs nil)) | |
1388 (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx lines)))) | |
1389 (setq idx (1+ idx)) | |
1390 ) | |
1391 (when (< idx count) | |
1392 (let* ((inc-lines (flymake-split-string (nth idx lines) " *-I")) | |
1393 (inc-count (length inc-lines))) | |
1394 (while (> inc-count 0) | |
1395 (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines))) | |
1396 (setq inc-dirs (cons (flymake-replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs)) | |
1397 ) | |
1398 (setq inc-count (1- inc-count)) | |
1399 ) | |
1400 ) | |
1401 ) | |
1402 (flymake-add-project-include-dirs-to-cache basedir inc-dirs) | |
1403 inc-dirs | |
1404 ) | |
1405 ) | |
1406 ) | |
1407 | |
1408 (defcustom flymake-get-project-include-dirs-function 'flymake-get-project-include-dirs-imp | |
1409 "function used to get project inc dirs, one paramater: basedir name" | |
1410 :group 'flymake | |
1411 :type 'function | |
1412 ) | |
1413 | |
1414 (defun flymake-get-project-include-dirs(basedir) | |
1415 (funcall flymake-get-project-include-dirs-function basedir) | |
1416 ) | |
1417 | |
1418 (defun flymake-get-system-include-dirs() | |
1419 "system include dirs - from the 'INCLUDE' env setting" | |
1420 (let* ((includes (getenv "INCLUDE"))) | |
1421 (if includes (flymake-split-string includes path-separator) nil) | |
1422 ) | |
1423 ) | |
1424 | |
1425 (defvar flymake-project-include-dirs-cache (flymake-makehash 'equal)) | |
1426 (defun flymake-get-project-include-dirs-from-cache(base-dir) | |
1427 (gethash base-dir flymake-project-include-dirs-cache) | |
1428 ) | |
1429 (defun flymake-add-project-include-dirs-to-cache(base-dir include-dirs) | |
1430 (puthash base-dir include-dirs flymake-project-include-dirs-cache) | |
1431 ) | |
1432 (defun flymake-clear-project-include-dirs-cache() | |
1433 (clrhash flymake-project-include-dirs-cache) | |
1434 ) | |
1435 | |
1436 (defun flymake-get-include-dirs(base-dir) | |
1437 "dirs to use when resolving local filenames" | |
1438 (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs)))) | |
1439 include-dirs | |
1440 ) | |
1441 ) | |
1442 | |
1443 (defun flymake-find-file(rel-file-name include-dirs) | |
1444 "iterate through include-dirs, return first 'include-dir/rel-file-name' that exists, or just rel-file-name if not" | |
1445 (let* ((count (length include-dirs)) | |
1446 (idx 0) | |
1447 (found nil) | |
1448 (full-file-name rel-file-name)) | |
1449 | |
1450 (while (and (not found) (< idx count)) | |
1451 (let* ((dir (nth idx include-dirs))) | |
1452 (setq full-file-name (concat dir "/" rel-file-name)) | |
1453 (when (file-exists-p full-file-name) | |
1454 (setq done t) | |
1455 ) | |
1456 ) | |
1457 (setq idx (1+ idx)) | |
1458 ) | |
1459 (if found | |
1460 full-file-name | |
1461 ;else | |
1462 rel-file-name | |
1463 ) | |
1464 ) | |
1465 ) | |
1466 | |
1467 (defun flymake-restore-formatting(source-buffer) | |
1468 "Remove any formatting made by flymake" | |
1469 ) | |
1470 | |
1471 (defun flymake-get-program-dir(buffer) | |
1472 "dir to start profram in" | |
1473 (unless (bufferp buffer) | |
1474 (error "invlid buffer") | |
1475 ) | |
1476 (save-excursion | |
1477 (set-buffer buffer) | |
1478 default-directory | |
1479 ) | |
1480 ) | |
1481 | |
1482 (defun flymake-safe-delete-file(file-name) | |
1483 (when (and file-name (file-exists-p file-name)) | |
1484 (delete-file file-name) | |
1485 (flymake-log 1 "deleted file %s" file-name) | |
1486 ) | |
1487 ) | |
1488 | |
1489 (defun flymake-safe-delete-directory(dir-name) | |
1490 (condition-case err | |
1491 (progn | |
1492 (delete-directory dir-name) | |
1493 (flymake-log 1 "deleted dir %s" dir-name) | |
1494 ) | |
1495 (error | |
1496 (flymake-log 1 "failed to delete dir %s, error ignored" dir-name) | |
1497 ) | |
1498 ) | |
1499 ) | |
1500 | |
1501 (defcustom flymake-compilation-prevents-syntax-check t | |
1502 "if non-nil, syntax check won't be started in case compilation is running" | |
1503 :group 'flymake | |
1504 :type 'boolean | |
1505 ) | |
1506 | |
1507 (defun flymake-start-syntax-check(buffer) | |
1508 "start syntax checking for buffer" | |
1509 (unless (bufferp buffer) | |
1510 (error "expected a buffer") | |
1511 ) | |
1512 (save-excursion | |
1513 (set-buffer buffer) | |
1514 (flymake-log 3 "flymake is running: %s" (flymake-get-buffer-is-running buffer)) | |
1515 (when (and (not (flymake-get-buffer-is-running buffer)) | |
1516 (flymake-can-syntax-check-file (buffer-file-name buffer))) | |
1517 (when (or (not flymake-compilation-prevents-syntax-check) | |
1518 (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP") | |
1519 (flymake-clear-buildfile-cache) | |
1520 (flymake-clear-project-include-dirs-cache) | |
1521 | |
1522 (flymake-set-buffer-check-was-interrupted buffer nil) | |
1523 (flymake-set-buffer-data buffer (flymake-makehash 'equal)) | |
1524 | |
1525 (let* ((source-file-name (buffer-file-name buffer)) | |
1526 (init-f (flymake-get-init-function source-file-name)) | |
1527 (cleanup-f (flymake-get-cleanup-function source-file-name)) | |
1528 (cmd-and-args (funcall init-f buffer)) | |
1529 (cmd (nth 0 cmd-and-args)) | |
1530 (args (nth 1 cmd-and-args)) | |
1531 (dir (nth 2 cmd-and-args))) | |
1532 (if (not cmd-and-args) | |
1533 (progn | |
1534 (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name) | |
1535 (funcall cleanup-f buffer) | |
1536 ) | |
1537 ;else | |
1538 (progn | |
1539 (flymake-set-buffer-last-change-time buffer nil) | |
1540 (flymake-start-syntax-check-process buffer cmd args dir) | |
1541 ) | |
1542 ) | |
1543 ) | |
1544 ) | |
1545 ) | |
1546 ) | |
1547 ) | |
1548 | |
1549 (defun flymake-start-syntax-check-process(buffer cmd args dir) | |
1550 "start syntax check-process" | |
1551 | |
1552 (let* ((process nil)) | |
1553 (condition-case err | |
1554 (progn | |
1555 (when dir | |
1556 (let ((default-directory dir)) | |
1557 (flymake-log 3 "starting process on dir %s" default-directory) | |
1558 ) | |
1559 ) | |
1560 (setq process (get-process (apply 'start-process "flymake-proc" nil cmd args))) | |
1561 (set-process-sentinel process 'flymake-process-sentinel) | |
1562 (set-process-filter process 'flymake-process-filter) | |
1563 | |
1564 (flymake-reg-names (process-id process) (buffer-name buffer)) | |
1565 | |
1566 (flymake-set-buffer-is-running buffer t) | |
1567 (flymake-set-buffer-last-change-time buffer nil) | |
1568 (flymake-set-buffer-check-start-time buffer (flymake-float-time)) | |
1569 | |
1570 (flymake-report-status buffer nil "*") | |
1571 (flymake-log 2 "started process %d, command=%s, dir=%s" | |
1572 (process-id process) (process-command process) default-directory) | |
1573 process | |
1574 ) | |
1575 (error | |
1576 (let ((err-str (format "Failed to launch syntax check process '%s' with args %s: %s" | |
1577 cmd args (error-message-string err))) | |
1578 (source-file-name (buffer-file-name buffer)) | |
1579 (cleanup-f (flymake-get-cleanup-function source-file-name))) | |
1580 (flymake-log 0 err-str) | |
1581 (funcall cleanup-f buffer) | |
1582 (flymake-report-fatal-status buffer "PROCERR" err-str) | |
1583 ) | |
1584 ) | |
1585 ) | |
1586 ) | |
1587 ) | |
1588 | |
1589 (defun flymake-kill-process(pid &optional rest) | |
1590 "kill process pid" | |
1591 (signal-process pid 9) | |
1592 (let* ((buffer-name (flymake-get-source-buffer-name pid))) | |
1593 (when (and buffer-name (get-buffer buffer-name)) | |
1594 (flymake-set-buffer-check-was-interrupted (get-buffer buffer-name) t) | |
1595 ) | |
1596 ) | |
1597 (flymake-log 1 "killed process %d" pid) | |
1598 ) | |
1599 | |
1600 (defun flymake-stop-all-syntax-checks() | |
1601 "kill all syntax check processes" | |
1602 (interactive) | |
1603 (let ((pids (copy-hash-table flymake-pid-to-names))) | |
1604 (maphash 'flymake-kill-process pids) | |
1605 ) | |
1606 ) | |
1607 | |
1608 (defun flymake-compilation-is-running() | |
1609 (and (boundp 'compilation-in-progress) | |
1610 compilation-in-progress) | |
1611 ) | |
1612 | |
1613 (defun flymake-compile() | |
1614 "kill all flymake syntax checks, start compilation" | |
1615 (interactive) | |
1616 (flymake-stop-all-syntax-checks) | |
1617 (call-interactively 'compile) | |
1618 ) | |
1619 | |
1620 (defvar flymake-is-running nil | |
1621 "t if flymake syntax check process is running for the current buffer" | |
1622 ) | |
1623 (make-variable-buffer-local 'flymake-is-running) | |
1624 (defun flymake-get-buffer-is-running(buffer) | |
1625 (flymake-get-buffer-var buffer 'flymake-is-running) | |
1626 ) | |
1627 (defun flymake-set-buffer-is-running(buffer is-running) | |
1628 (flymake-set-buffer-var buffer 'flymake-is-running is-running) | |
1629 ) | |
1630 | |
1631 (defvar flymake-timer nil | |
1632 "timer for starting syntax checks" | |
1633 ) | |
1634 (make-variable-buffer-local 'flymake-timer) | |
1635 (defun flymake-get-buffer-timer(buffer) | |
1636 (flymake-get-buffer-var buffer 'flymake-timer) | |
1637 ) | |
1638 (defun flymake-set-buffer-timer(buffer timer) | |
1639 (flymake-set-buffer-var buffer 'flymake-timer timer) | |
1640 ) | |
1641 | |
1642 (defvar flymake-last-change-time nil | |
1643 "time of last buffer change" | |
1644 ) | |
1645 (make-variable-buffer-local 'flymake-last-change-time) | |
1646 (defun flymake-get-buffer-last-change-time(buffer) | |
1647 (flymake-get-buffer-var buffer 'flymake-last-change-time) | |
1648 ) | |
1649 (defun flymake-set-buffer-last-change-time(buffer change-time) | |
1650 (flymake-set-buffer-var buffer 'flymake-last-change-time change-time) | |
1651 ) | |
1652 | |
1653 (defvar flymake-check-start-time nil | |
1654 "time at which syntax check was started") | |
1655 (make-variable-buffer-local 'flymake-check-start-time) | |
1656 (defun flymake-get-buffer-check-start-time(buffer) | |
1657 (flymake-get-buffer-var buffer 'flymake-check-start-time) | |
1658 ) | |
1659 (defun flymake-set-buffer-check-start-time(buffer check-start-time) | |
1660 (flymake-set-buffer-var buffer 'flymake-check-start-time check-start-time) | |
1661 ) | |
1662 | |
1663 (defvar flymake-check-was-interrupted nil | |
1664 "t if syntax check was killed by flymake-compile" | |
1665 ) | |
1666 (make-variable-buffer-local 'flymake-check-was-interrupted) | |
1667 (defun flymake-get-buffer-check-was-interrupted(buffer) | |
1668 (flymake-get-buffer-var buffer 'flymake-check-was-interrupted) | |
1669 ) | |
1670 (defun flymake-set-buffer-check-was-interrupted(buffer interrupted) | |
1671 (flymake-set-buffer-var buffer 'flymake-check-was-interrupted interrupted) | |
1672 ) | |
1673 | |
1674 (defcustom flymake-no-changes-timeout 0.5 | |
1675 "time to wait after last change before starting compilation" | |
1676 :group 'flymake | |
1677 :type 'number | |
1678 ) | |
1679 | |
1680 (defun flymake-on-timer-event(buffer) | |
1681 "start a syntax check for buffer if necessary" | |
1682 ;+(flymake-log 3 "timer: running=%s, time=%s, cur-time=%s" (flymake-get-buffer-is-running buffer) (flymake-get-buffer-last-change-time buffer) (flymake-float-time)) | |
1683 | |
1684 (when (and (bufferp buffer) (not (flymake-get-buffer-is-running buffer))) | |
1685 (save-excursion | |
1686 (set-buffer buffer) | |
1687 (when (and (flymake-get-buffer-last-change-time buffer) | |
1688 (> (flymake-float-time) (+ flymake-no-changes-timeout (flymake-get-buffer-last-change-time buffer)))) | |
1689 (flymake-set-buffer-last-change-time buffer nil) | |
1690 (flymake-log 3 "starting syntax check as more than 1 second passed since last change") | |
1691 (flymake-start-syntax-check buffer) | |
1692 ) | |
1693 ) | |
1694 ) | |
1695 ) | |
1696 | |
1697 (defun flymake-start-syntax-check-for-current-buffer() | |
1698 "run flymake-start-syntax-check for current buffer if it isn't already running" | |
1699 (interactive) | |
1700 (flymake-start-syntax-check (current-buffer)) | |
1701 ) | |
1702 | |
1703 (defun flymake-current-line-no() | |
1704 "return number of current line in current buffer" | |
1705 (interactive) | |
1706 (let ((beg (point-min)) | |
1707 (end (if (= (point) (point-max)) (point) (1+ (point))))) | |
1708 (count-lines beg end) | |
1709 ) | |
1710 ) | |
1711 | |
1712 (defun flymake-get-line-count(buffer) | |
1713 "return number of lines in buffer" | |
1714 (unless (bufferp buffer) | |
1715 (error "invalid buffer") | |
1716 ) | |
1717 (save-excursion | |
1718 (set-buffer buffer) | |
1719 (count-lines (point-min) (point-max)) | |
1720 ) | |
1721 ) | |
1722 | |
1723 (defun flymake-count-lines(buffer) | |
1724 "return number of lines in buffer" | |
1725 (save-excursion | |
1726 (set-buffer buffer) | |
1727 (count-lines (point-min) (point-max)) | |
1728 ) | |
1729 ) | |
1730 | |
1731 (defun flymake-get-point-pixel-pos() | |
1732 "return point position in pixels: (x, y)" | |
1733 (let ((mouse-pos (mouse-position)) | |
1734 (pixel-pos nil) | |
1735 (ret nil)) | |
1736 (if (car (cdr mouse-pos)) | |
1737 (progn | |
1738 (set-mouse-position (flymake-selected-frame) (current-column) (flymake-current-row)) | |
1739 (setq pixel-pos (mouse-pixel-position)) | |
1740 (set-mouse-position (car mouse-pos) (car (cdr mouse-pos)) (cdr (cdr mouse-pos))) | |
1741 (setq ret (list (car (cdr pixel-pos)) (cdr (cdr pixel-pos)))) | |
1742 ) | |
1743 ;else | |
1744 (progn | |
1745 (setq ret '(0 0)) | |
1746 ) | |
1747 ) | |
1748 (flymake-log 3 "mouse pos is %s" ret) | |
1749 ret | |
1750 ) | |
1751 ) | |
1752 | |
1753 (defun flymake-display-err-menu-for-current-line() | |
1754 "Display a menu with errors/warnings for current line if it has errors and/or warnings" | |
1755 (interactive) | |
1756 (let* ((line-no (flymake-current-line-no)) | |
1757 (line-err-info-list (nth 0 (flymake-find-err-info (flymake-get-buffer-err-info (current-buffer)) line-no))) | |
1758 (menu-data (flymake-make-err-menu-data line-no line-err-info-list)) | |
1759 (choice nil) | |
1760 (mouse-pos (flymake-get-point-pixel-pos)) | |
1761 (moved-mouse-pos (list (car mouse-pos) (+ 10 (car (cdr mouse-pos))))) | |
1762 (menu-pos (list (flymake-get-point-pixel-pos) (selected-window)))) | |
1763 (if menu-data | |
1764 (progn | |
1765 (setq choice (flymake-popup-menu menu-pos menu-data)) | |
1766 (flymake-log 3 "choice=%s" choice) | |
1767 (when choice | |
1768 (eval choice) | |
1769 ) | |
1770 ) | |
1771 ;else | |
1772 (flymake-log 1 "no errors for line %d" line-no) | |
1773 ) | |
1774 ) | |
1775 ) | |
1776 | |
1777 (defun flymake-make-err-menu-data(line-no line-err-info-list) | |
1778 "Make a (menu-title (item-title item-action)*) list with errors/warnings from line-err-info" | |
1779 (let* ((menu-items nil)) | |
1780 (when line-err-info-list | |
1781 (let* ((count (length line-err-info-list)) | |
1782 (menu-item-text nil)) | |
1783 (while (> count 0) | |
1784 (setq menu-item-text (flymake-ler-get-text (nth (1- count) line-err-info-list))) | |
1785 (let* ((file (flymake-ler-get-file (nth (1- count) line-err-info-list))) | |
1786 (full-file (flymake-ler-get-full-file (nth (1- count) line-err-info-list))) | |
1787 (line (flymake-ler-get-line (nth (1- count) line-err-info-list)))) | |
1788 (if file | |
1789 (setq menu-item-text (concat menu-item-text " - " file "(" (format "%d" line) ")")) | |
1790 ) | |
1791 (setq menu-items (cons (list menu-item-text | |
1792 (if file (list 'flymake-goto-file-and-line full-file line) nil)) | |
1793 menu-items)) | |
1794 ) | |
1795 (setq count (1- count)) | |
1796 ) | |
1797 (flymake-log 3 "created menu-items with %d item(s)" (length menu-items)) | |
1798 ) | |
1799 ) | |
1800 (if menu-items | |
1801 (let* ((menu-title (format "Line %d: %d error(s), %d warning(s)" line-no | |
1802 (flymake-get-line-err-count line-err-info-list "e") | |
1803 (flymake-get-line-err-count line-err-info-list "w")))) | |
1804 (list menu-title menu-items) | |
1805 ) | |
1806 ;else | |
1807 nil | |
1808 ) | |
1809 ) | |
1810 ) | |
1811 | |
1812 (defun flymake-goto-file-and-line(file line) | |
1813 "try to get buffer for file and goto line line in it" | |
1814 (if (not (file-exists-p file)) | |
1815 (flymake-log 1 "file %s does not exists" file) | |
1816 ;else | |
1817 (progn | |
1818 (find-file file) | |
1819 (goto-line line) | |
1820 ) | |
1821 ) | |
1822 ) | |
1823 ;; flymake minor mode declarations | |
1824 | |
1825 (defvar flymake-mode nil) | |
1826 (make-variable-buffer-local 'flymake-mode) | |
1827 | |
1828 (defvar flymake-mode-line nil | |
1829 "" | |
1830 ) | |
1831 (make-variable-buffer-local 'flymake-mode-line) | |
1832 (defun flymake-get-buffer-mode-line(buffer) | |
1833 (flymake-get-buffer-var buffer 'flymake-mode-line) | |
1834 ) | |
1835 (defun flymake-set-buffer-mode-line(buffer mode-line-string) | |
1836 (flymake-set-buffer-var buffer 'flymake-mode-line mode-line-string) | |
1837 ) | |
1838 | |
1839 (defvar flymake-mode-line-e-w nil) | |
1840 (make-variable-buffer-local 'flymake-mode-line-e-w) | |
1841 (defun flymake-get-buffer-mode-line-e-w(buffer) | |
1842 (flymake-get-buffer-var buffer 'flymake-mode-line-e-w) | |
1843 ) | |
1844 (defun flymake-set-buffer-mode-line-e-w(buffer e-w) | |
1845 (flymake-set-buffer-var buffer 'flymake-mode-line-e-w e-w) | |
1846 ) | |
1847 | |
1848 (defvar flymake-mode-line-status nil) | |
1849 (make-variable-buffer-local 'flymake-mode-line-status) | |
1850 (defun flymake-get-buffer-mode-line-status(buffer) | |
1851 (flymake-get-buffer-var buffer 'flymake-mode-line-status) | |
1852 ) | |
1853 (defun flymake-set-buffer-mode-line-status(buffer status) | |
1854 (flymake-set-buffer-var buffer 'flymake-mode-line-status status) | |
1855 ) | |
1856 | |
1857 (defun flymake-report-status(buffer e-w &optional status) | |
1858 "show status in the mode line" | |
1859 (when (bufferp buffer) | |
1860 (save-excursion | |
1861 (set-buffer buffer) | |
1862 (when e-w | |
1863 (flymake-set-buffer-mode-line-e-w buffer e-w) | |
1864 ) | |
1865 (when status | |
1866 (flymake-set-buffer-mode-line-status buffer status) | |
1867 ) | |
1868 (let* ((mode-line " Flymake")) | |
1869 (when (> (length (flymake-get-buffer-mode-line-e-w buffer)) 0) | |
1870 (setq mode-line (concat mode-line ":" (flymake-get-buffer-mode-line-e-w buffer))) | |
1871 ) | |
1872 (setq mode-line (concat mode-line (flymake-get-buffer-mode-line-status buffer))) | |
1873 (flymake-set-buffer-mode-line buffer mode-line) | |
1874 (force-mode-line-update) | |
1875 ) | |
1876 ) | |
1877 ) | |
1878 ) | |
1879 | |
1880 (defun flymake-display-warning(warning) | |
1881 "display a warning to the user" | |
1882 (message-box warning) | |
1883 ) | |
1884 | |
1885 (defcustom flymake-gui-warnings-enabled t | |
1886 "enables/disables gui warnings" | |
1887 :group 'flymake | |
1888 :type 'boolean | |
1889 ) | |
1890 | |
1891 (defun flymake-report-fatal-status(buffer status warning) | |
1892 "display a warning and switch flymake mode OFF" | |
1893 (when flymake-gui-warnings-enabled | |
1894 (flymake-display-warning (format "Flymake: %s. Flymake will be switched OFF" warning)) | |
1895 ) | |
1896 (save-excursion | |
1897 (set-buffer buffer) | |
1898 (flymake-mode 0) | |
1899 (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s" | |
1900 (buffer-name buffer) status warning) | |
1901 ) | |
1902 ) | |
1903 | |
1904 (defun flymake-mode(&optional arg) | |
1905 "toggle flymake-mode" | |
1906 (interactive) | |
1907 (let ((old-flymake-mode flymake-mode)) | |
1908 | |
1909 (setq turn-on | |
1910 (if (null arg) | |
1911 (not flymake-mode) | |
1912 ;else | |
1913 (> (prefix-numeric-value arg) 0)) | |
1914 ) | |
1915 | |
1916 (if turn-on | |
1917 (if (flymake-can-syntax-check-file (buffer-file-name)) | |
1918 (flymake-mode-on) | |
1919 ;else | |
1920 (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name)) | |
1921 ) | |
1922 ;else | |
1923 (flymake-mode-off) | |
1924 ) | |
1925 (force-mode-line-update) | |
1926 ) | |
1927 ) | |
1928 | |
1929 ;;;###autoload | |
1930 (unless (assq 'flymake-mode minor-mode-alist) | |
1931 (setq minor-mode-alist (cons '(flymake-mode flymake-mode-line) minor-mode-alist)) | |
1932 ) | |
1933 | |
1934 ;;;###autoload | |
1935 (defun flymake-mode-on() | |
1936 "turn flymake mode on" | |
1937 (when (not flymake-mode) | |
1938 (make-local-variable 'after-change-functions) | |
1939 (setq after-change-functions (cons 'flymake-after-change-function after-change-functions)) | |
1940 (add-hook 'after-save-hook 'flymake-after-save-hook) | |
1941 (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook) | |
1942 ;+(add-hook 'find-file-hooks 'flymake-find-file-hook) | |
1943 | |
1944 (flymake-report-status (current-buffer) "" "") | |
1945 | |
1946 (flymake-set-buffer-timer (current-buffer) (run-at-time nil 1 'flymake-on-timer-event (current-buffer))) | |
1947 | |
1948 (setq flymake-mode t) | |
1949 (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name (current-buffer))) | |
1950 (when flymake-start-syntax-check-on-find-file | |
1951 (flymake-start-syntax-check-for-current-buffer) ; will be started by on-load hook | |
1952 ) | |
1953 ) | |
1954 ) | |
1955 | |
1956 ;;;###autoload | |
1957 (defun flymake-mode-off() | |
1958 "turn flymake mode off" | |
1959 (when flymake-mode | |
1960 (setq after-change-functions (delq 'flymake-after-change-function after-change-functions)) | |
1961 (remove-hook 'after-save-hook (function flymake-after-save-hook) t) | |
1962 (remove-hook 'kill-buffer-hook (function flymake-kill-buffer-hook) t) | |
1963 ;+(remove-hook 'find-file-hooks (function flymake-find-file-hook) t) | |
1964 | |
1965 (flymake-delete-own-overlays (current-buffer)) | |
1966 | |
1967 (when (flymake-get-buffer-timer (current-buffer)) | |
1968 (cancel-timer (flymake-get-buffer-timer (current-buffer))) | |
1969 (flymake-set-buffer-timer (current-buffer) nil) | |
1970 ) | |
1971 | |
1972 (flymake-set-buffer-is-running (current-buffer) nil) | |
1973 | |
1974 (setq flymake-mode nil) | |
1975 (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name (current-buffer))) | |
1976 ) | |
1977 ) | |
1978 | |
1979 (defcustom flymake-start-syntax-check-on-newline t | |
1980 "start syntax check if newline char was added/removed from the buffer" | |
1981 :group 'flymake | |
1982 :type 'boolean | |
1983 ) | |
1984 | |
1985 (defun flymake-after-change-function(start stop len) | |
1986 "Start syntax check for current buffer if it isn't already running" | |
1987 ;+(flymake-log 0 "setting change time to %s" (flymake-float-time)) | |
1988 (let((new-text (buffer-substring start stop))) | |
1989 (when (and flymake-start-syntax-check-on-newline (equal new-text "\n")) | |
1990 (flymake-log 3 "starting syntax check as new-line has been seen") | |
1991 (flymake-start-syntax-check-for-current-buffer) | |
1992 ) | |
1993 (flymake-set-buffer-last-change-time (current-buffer) (flymake-float-time)) | |
1994 ) | |
1995 ) | |
1996 | |
1997 (defun flymake-after-save-hook() | |
1998 (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved? | |
1999 (progn | |
2000 (flymake-log 3 "starting syntax check as buffer was saved") | |
2001 (flymake-start-syntax-check-for-current-buffer) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???) | |
2002 ) | |
2003 ) | |
2004 ) | |
2005 | |
2006 (defun flymake-kill-buffer-hook() | |
2007 (when (flymake-get-buffer-timer (current-buffer)) | |
2008 (cancel-timer (flymake-get-buffer-timer (current-buffer))) | |
2009 (flymake-set-buffer-timer (current-buffer) nil) | |
2010 ) | |
2011 ) | |
2012 | |
2013 (defcustom flymake-start-syntax-check-on-find-file t | |
2014 "statr syntax check on find file" | |
2015 :group 'flymake | |
2016 :type 'boolean | |
2017 ) | |
2018 | |
2019 (defun flymake-find-file-hook() | |
2020 ;+(when flymake-start-syntax-check-on-find-file | |
2021 ;+ (flymake-log 3 "starting syntax check on file open") | |
2022 ;+ (flymake-start-syntax-check-for-current-buffer) | |
2023 ;+) | |
2024 (when (and (not (local-variable-p 'flymake-mode (current-buffer))) | |
2025 (flymake-can-syntax-check-file (buffer-file-name (current-buffer)))) | |
2026 (flymake-mode) | |
2027 (flymake-log 3 "automatically turned ON flymake mode") | |
2028 ) | |
2029 ) | |
2030 | |
2031 (defun flymake-get-first-err-line-no(err-info-list) | |
2032 "return first line-no with error" | |
2033 (when err-info-list | |
2034 (flymake-er-get-line (car err-info-list)) | |
2035 ) | |
2036 ) | |
2037 | |
2038 (defun flymake-get-last-err-line-no(err-info-list) | |
2039 "return last line-no with error" | |
2040 (when err-info-list | |
2041 (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list)) | |
2042 ) | |
2043 ) | |
2044 | |
2045 (defun flymake-get-next-err-line-no(err-info-list line-no) | |
2046 "return next line with erroe" | |
2047 (when err-info-list | |
2048 (let* ((count (length err-info-list)) | |
2049 (idx 0)) | |
2050 (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list)))) | |
2051 (setq idx (1+ idx)) | |
2052 ) | |
2053 (if (< idx count) | |
2054 (flymake-er-get-line (nth idx err-info-list)) | |
2055 ) | |
2056 ) | |
2057 ) | |
2058 ) | |
2059 | |
2060 (defun flymake-get-prev-err-line-no(err-info-list line-no) | |
2061 "return prev line with error" | |
2062 (when err-info-list | |
2063 (let* ((count (length err-info-list))) | |
2064 (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list)))) | |
2065 (setq count (1- count)) | |
2066 ) | |
2067 (if (> count 0) | |
2068 (flymake-er-get-line (nth (1- count) err-info-list)) | |
2069 ) | |
2070 ) | |
2071 ) | |
2072 ) | |
2073 | |
2074 (defun flymake-skip-whitespace() | |
2075 "move forward until nonwhitespace is reached" | |
2076 (while (looking-at "[ \t]") | |
2077 (forward-char) | |
2078 ) | |
2079 ) | |
2080 | |
2081 (defun flymake-goto-line(line-no) | |
2082 "goto-line, then skip whitespace" | |
2083 (goto-line line-no) | |
2084 (flymake-skip-whitespace) | |
2085 ) | |
2086 | |
2087 (defun flymake-goto-next-error() | |
2088 "go to next error in err ring" | |
2089 (interactive) | |
2090 (let ((line-no (flymake-get-next-err-line-no (flymake-get-buffer-err-info (current-buffer)) (flymake-current-line-no)))) | |
2091 (when (not line-no) | |
2092 (setq line-no (flymake-get-first-err-line-no (flymake-get-buffer-err-info (current-buffer)))) | |
2093 (flymake-log 1 "passed end of file") | |
2094 ) | |
2095 (if line-no | |
2096 (flymake-goto-line line-no) | |
2097 ;else | |
2098 (flymake-log 1 "no errors in current buffer") | |
2099 ) | |
2100 ) | |
2101 ) | |
2102 | |
2103 (defun flymake-goto-prev-error() | |
2104 "go to prev error in err ring" | |
2105 (interactive) | |
2106 (let ((line-no (flymake-get-prev-err-line-no (flymake-get-buffer-err-info (current-buffer)) (flymake-current-line-no)))) | |
2107 (when (not line-no) | |
2108 (setq line-no (flymake-get-last-err-line-no (flymake-get-buffer-err-info (current-buffer)))) | |
2109 (flymake-log 1 "passed beginning of file") | |
2110 ) | |
2111 (if line-no | |
2112 (flymake-goto-line line-no) | |
2113 ;else | |
2114 (flymake-log 1 "no errors in current buffer") | |
2115 ) | |
2116 ) | |
2117 ) | |
2118 | |
2119 (defun flymake-patch-err-text(string) | |
2120 (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string) | |
2121 (match-string 1 string) | |
2122 ;else | |
2123 string | |
2124 ) | |
2125 ) | |
2126 | |
2127 ;;;; general init-cleanup and helper routines | |
2128 | |
2129 (defun flymake-create-temp-inplace(file-name prefix) | |
2130 (unless (stringp file-name) | |
2131 (error "invalid file-name") | |
2132 ) | |
2133 (or prefix | |
2134 (setq prefix "flymake") | |
2135 ) | |
2136 (let* ((temp-name (concat (file-name-sans-extension file-name) | |
2137 "_" prefix | |
2138 (and (file-name-extension file-name) | |
2139 (concat "." (file-name-extension file-name)))))) | |
2140 (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name) | |
2141 temp-name | |
2142 ) | |
2143 ) | |
2144 | |
2145 (defun flymake-create-temp-with-folder-structure(file-name prefix) | |
2146 (unless (stringp file-name) | |
2147 (error "invalid file-name") | |
2148 ) | |
2149 | |
2150 (let* ((dir (file-name-directory file-name)) | |
2151 (slash-pos (string-match "/" dir)) | |
2152 (temp-dir (concat (flymake-ensure-ends-with-slash (flymake-get-temp-dir)) (substring dir (1+ slash-pos))))) | |
2153 | |
2154 (file-truename (concat (flymake-ensure-ends-with-slash temp-dir) | |
2155 (file-name-nondirectory file-name))) | |
2156 ) | |
2157 ) | |
2158 | |
2159 (defun flymake-strrchr(str ch) | |
2160 (let* ((count (length str)) | |
2161 (pos nil)) | |
2162 (while (and (not pos) (> count 0)) | |
2163 (if (= ch (elt str (1- count))) | |
2164 (setq pos (1- count)) | |
2165 ) | |
2166 (setq count (1- count)) | |
2167 ) | |
2168 pos | |
2169 ) | |
2170 ) | |
2171 | |
2172 (defun flymake-delete-temp-directory(dir-name) | |
2173 "attempt to delete temp dir created by flymake-create-temp-with-folder-structure, do not fail on error" | |
2174 (let* ((temp-dir (flymake-get-temp-dir)) | |
2175 (suffix (substring dir-name (1+ (length temp-dir)))) | |
2176 (slash-pos nil)) | |
2177 | |
2178 (while (> (length suffix) 0) | |
2179 ;+(flymake-log 0 "suffix=%s" suffix) | |
2180 (flymake-safe-delete-directory (file-truename (concat (flymake-ensure-ends-with-slash temp-dir) suffix))) | |
2181 (setq slash-pos (flymake-strrchr suffix (string-to-char "/"))) | |
2182 (if slash-pos | |
2183 (setq suffix (substring suffix 0 slash-pos)) | |
2184 ;else | |
2185 (setq suffix "") | |
2186 ) | |
2187 ) | |
2188 ) | |
2189 ) | |
2190 | |
2191 (defun flymake-init-create-temp-buffer-copy(buffer create-temp-f) | |
2192 "make a temporary copy of the current buffer, save its name in buffer data and return the name" | |
2193 (let* ((source-file-name (buffer-file-name buffer)) | |
2194 (temp-source-file-name (funcall create-temp-f source-file-name "flymake"))) | |
2195 | |
2196 (flymake-save-buffer-in-file buffer temp-source-file-name) | |
2197 (flymake-set-buffer-value buffer "temp-source-file-name" temp-source-file-name) | |
2198 | |
2199 temp-source-file-name | |
2200 ) | |
2201 ) | |
2202 | |
2203 (defun flymake-simple-cleanup(buffer) | |
2204 "cleanup after flymake-init-create-temp-buffer-copy -- delete temp file" | |
2205 (let* ((temp-source-file-name (flymake-get-buffer-value buffer "temp-source-file-name"))) | |
2206 (flymake-safe-delete-file temp-source-file-name) | |
2207 (flymake-set-buffer-last-change-time buffer nil) | |
2208 ) | |
2209 ) | |
2210 | |
2211 (defun flymake-get-real-file-name(buffer file-name-from-err-msg) | |
2212 "Translate file name from error message to `real' file name. Return full-name. Names are real, not patched" | |
2213 (let* ((real-name nil) | |
2214 (source-file-name (buffer-file-name buffer)) | |
2215 (master-file-name (flymake-get-buffer-value buffer "master-file-name")) | |
2216 (temp-source-file-name (flymake-get-buffer-value buffer "temp-source-file-name")) | |
2217 (temp-master-file-name (flymake-get-buffer-value buffer "temp-master-file-name")) | |
2218 (base-dirs (list (flymake-get-buffer-value buffer "base-dir") | |
2219 (file-name-directory source-file-name) | |
2220 (if master-file-name (file-name-directory master-file-name) nil))) | |
2221 (files (list (list source-file-name source-file-name) | |
2222 (list temp-source-file-name source-file-name) | |
2223 (list master-file-name master-file-name) | |
2224 (list temp-master-file-name master-file-name)))) | |
2225 | |
2226 (when (equal 0 (length file-name-from-err-msg)) | |
2227 (setq file-name-from-err-msg source-file-name) | |
2228 ) | |
2229 | |
2230 (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files)) | |
2231 ; if real-name is nil, than file name from err msg is none of the files we've patched | |
2232 (if (not real-name) | |
2233 (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs)) | |
2234 ) | |
2235 (if (not real-name) | |
2236 (setq real-name file-name-from-err-msg) | |
2237 ) | |
2238 (setq real-name (flymake-fix-path-name real-name)) | |
2239 (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name) | |
2240 real-name | |
2241 ) | |
2242 ) | |
2243 | |
2244 (defun flymake-get-full-patched-file-name(file-name-from-err-msg base-dirs files) | |
2245 (let* ((base-dirs-count (length base-dirs)) | |
2246 (file-count (length files)) | |
2247 (real-name nil)) | |
2248 | |
2249 (while (and (not real-name) (> base-dirs-count 0)) | |
2250 (setq file-count (length files)) | |
2251 (while (and (not real-name) (> file-count 0)) | |
2252 (let* ((this-dir (nth (1- base-dirs-count) base-dirs)) | |
2253 (this-file (nth 0 (nth (1- file-count) files))) | |
2254 (this-real-name (nth 1 (nth (1- file-count) files)))) | |
2255 ;+(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) | |
2256 (when (and this-dir this-file (flymake-same-files | |
2257 (flymake-get-absolute-file-name-basedir file-name-from-err-msg this-dir) | |
2258 this-file)) | |
2259 (setq real-name this-real-name) | |
2260 ) | |
2261 ) | |
2262 (setq file-count (1- file-count)) | |
2263 ) | |
2264 (setq base-dirs-count (1- base-dirs-count)) | |
2265 ) | |
2266 real-name | |
2267 ) | |
2268 ) | |
2269 | |
2270 (defun flymake-get-full-nonpatched-file-name(file-name-from-err-msg base-dirs) | |
2271 (let* ((real-name nil)) | |
2272 (if (file-name-absolute-p file-name-from-err-msg) | |
2273 (setq real-name file-name-from-err-msg) | |
2274 ;else | |
2275 (let* ((base-dirs-count (length base-dirs))) | |
2276 (while (and (not real-name) (> base-dirs-count 0)) | |
2277 (let* ((full-name (flymake-get-absolute-file-name-basedir file-name-from-err-msg | |
2278 (nth (1- base-dirs-count) base-dirs)))) | |
2279 (if (file-exists-p full-name) | |
2280 (setq real-name full-name) | |
2281 ) | |
2282 (setq base-dirs-count (1- base-dirs-count)) | |
2283 ) | |
2284 ) | |
2285 ) | |
2286 ) | |
2287 real-name | |
2288 ) | |
2289 ) | |
2290 | |
2291 (defun flymake-get-absolute-file-name-basedir(file-name dir-name) | |
2292 (if (file-name-absolute-p file-name) | |
2293 file-name | |
2294 ;else | |
2295 (concat dir-name "/" file-name) | |
2296 ) | |
2297 ) | |
2298 | |
2299 (defun flymake-init-find-buildfile-dir(buffer source-file-name buildfile-name) | |
2300 "find buildfile, store its dir in buffer data and return its dir, if found" | |
2301 (let* ((buildfile-dir (flymake-find-buildfile buildfile-name | |
2302 (file-name-directory source-file-name) | |
2303 flymake-buildfile-dirs))) | |
2304 (if (not buildfile-dir) | |
2305 (progn | |
2306 (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name) | |
2307 (flymake-report-fatal-status buffer "NOMK" (format "No buildfile (%s) found for %s" buildfile-name source-file-name)) | |
2308 ) | |
2309 ;else | |
2310 (progn | |
2311 (flymake-set-buffer-value buffer "base-dir" buildfile-dir) | |
2312 ) | |
2313 ) | |
2314 buildfile-dir | |
2315 ) | |
2316 ) | |
2317 | |
2318 (defun flymake-init-create-temp-source-and-master-buffer-copy(buffer get-incl-dirs-f create-temp-f master-file-masks include-regexp-list) | |
2319 "find master file (or buffer), create it's copy along with a copy of the source file" | |
2320 (let* ((source-file-name (buffer-file-name buffer)) | |
2321 (temp-source-file-name (flymake-init-create-temp-buffer-copy buffer create-temp-f)) | |
2322 (master-file-name nil) | |
2323 (temp-master-file-name nil) | |
2324 (master-and-temp-master (flymake-create-master-file | |
2325 source-file-name temp-source-file-name | |
2326 get-incl-dirs-f create-temp-f | |
2327 master-file-masks include-regexp-list))) | |
2328 | |
2329 (if (not master-and-temp-master) | |
2330 (progn | |
2331 (flymake-log 1 "cannot find master file for %s" source-file-name) | |
2332 (flymake-report-status buffer "!" "") ; NOMASTER | |
2333 ) | |
2334 ;else | |
2335 (progn | |
2336 (setq master-file-name (nth 0 master-and-temp-master)) | |
2337 (setq temp-master-file-name (nth 1 master-and-temp-master)) | |
2338 (flymake-set-buffer-value buffer "master-file-name" master-file-name) | |
2339 (flymake-set-buffer-value buffer "temp-master-file-name" temp-master-file-name) | |
2340 ) | |
2341 ) | |
2342 temp-master-file-name | |
2343 ) | |
2344 ) | |
2345 | |
2346 (defun flymake-master-cleanup(buffer) | |
2347 (flymake-simple-cleanup buffer) | |
2348 (flymake-safe-delete-file (flymake-get-buffer-value buffer "temp-master-file-name")) | |
2349 ) | |
2350 | |
2351 ;;;; make-specific init-cleanup routines | |
2352 | |
2353 (defun flymake-get-syntax-check-program-args(source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f) | |
2354 "create a command line for the syntax check command, using get-cmd-line-f" | |
2355 (let* ((my-base-dir base-dir) | |
2356 (my-source source-file-name)) | |
2357 | |
2358 (when use-relative-base-dir | |
2359 (setq my-base-dir (flymake-build-relative-path (file-name-directory source-file-name) base-dir)) | |
2360 ) | |
2361 | |
2362 (when use-relative-source | |
2363 (setq my-source (concat (flymake-build-relative-path base-dir (file-name-directory source-file-name)) | |
2364 (file-name-nondirectory source-file-name))) | |
2365 ) | |
2366 | |
2367 (funcall get-cmd-line-f my-source my-base-dir) | |
2368 ) | |
2369 ) | |
2370 | |
2371 (defun flymake-get-make-cmdline(source base-dir) | |
2372 (list "make" | |
2373 (list "-s" | |
2374 "-C" | |
2375 base-dir | |
2376 (concat "CHK_SOURCES=" source) | |
2377 "SYNTAX_CHECK_MODE=1" | |
2378 "check-syntax")) | |
2379 ) | |
2380 | |
2381 (defun flymake-get-ant-cmdline(source base-dir) | |
2382 (list "ant" | |
2383 (list "-buildfile" | |
2384 (concat base-dir "/" "build.xml") | |
2385 (concat "-DCHK_SOURCES=" source) | |
2386 "check-syntax")) | |
2387 ) | |
2388 | |
2389 (defun flymake-simple-make-init-impl(buffer create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f) | |
2390 "create syntax check command line for a directly checked source file, use create-temp-f for creating temp copy" | |
2391 (let* ((args nil) | |
2392 (source-file-name (buffer-file-name buffer)) | |
2393 (buildfile-dir (flymake-init-find-buildfile-dir buffer source-file-name build-file-name))) | |
2394 (if buildfile-dir | |
2395 (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy buffer create-temp-f))) | |
2396 (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir | |
2397 use-relative-base-dir use-relative-source | |
2398 get-cmdline-f)) | |
2399 ) | |
2400 ) | |
2401 | |
2402 args | |
2403 ) | |
2404 ) | |
2405 | |
2406 (defun flymake-simple-make-init(buffer) | |
2407 (flymake-simple-make-init-impl buffer 'flymake-create-temp-inplace t t "Makefile" 'flymake-get-make-cmdline) | |
2408 ) | |
2409 | |
2410 (defun flymake-master-make-init(buffer get-incl-dirs-f master-file-masks include-regexp-list) | |
2411 "create make command line for a source file checked via master file compilation" | |
2412 (let* ((make-args nil) | |
2413 (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy | |
2414 buffer get-incl-dirs-f 'flymake-create-temp-inplace | |
2415 master-file-masks include-regexp-list))) | |
2416 (when temp-master-file-name | |
2417 (let* ((buildfile-dir (flymake-init-find-buildfile-dir buffer temp-master-file-name "Makefile"))) | |
2418 (if buildfile-dir | |
2419 (setq make-args (flymake-get-syntax-check-program-args | |
2420 temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline)) | |
2421 ) | |
2422 ) | |
2423 ) | |
2424 | |
2425 make-args | |
2426 ) | |
2427 ) | |
2428 | |
2429 (defun flymake-find-make-buildfile(source-dir) | |
2430 (flymake-find-buildfile "Makefile" source-dir flymake-buildfile-dirs) | |
2431 ) | |
2432 | |
2433 ;;;; .h/make specific | |
2434 (defun flymake-master-make-header-init(buffer) | |
2435 (flymake-master-make-init buffer | |
2436 'flymake-get-include-dirs | |
2437 '(".+\\.cpp$" ".+\\.c$") | |
2438 '("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2)) | |
2439 ) | |
2440 | |
2441 ;;;; .java/make specific | |
2442 (defun flymake-simple-make-java-init(buffer) | |
2443 (flymake-simple-make-init-impl buffer 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline) | |
2444 ) | |
2445 | |
2446 (defun flymake-simple-ant-java-init(buffer) | |
2447 (flymake-simple-make-init-impl buffer 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline) | |
2448 ) | |
2449 | |
2450 (defun flymake-simple-java-cleanup(buffer) | |
2451 "cleanup after flymake-simple-make-java-init -- delete temp file and dirs" | |
2452 (let* ((temp-source-file-name (flymake-get-buffer-value buffer "temp-source-file-name"))) | |
2453 (flymake-safe-delete-file temp-source-file-name) | |
2454 (when temp-source-file-name | |
2455 (flymake-delete-temp-directory (file-name-directory temp-source-file-name)) | |
2456 ) | |
2457 ) | |
2458 ) | |
2459 | |
2460 ;;;; perl-specific init-cleanup routines | |
2461 | |
2462 (defun flymake-perl-init(buffer) | |
2463 (let* ((temp-file (flymake-init-create-temp-buffer-copy buffer 'flymake-create-temp-inplace)) | |
2464 (local-file (concat (flymake-build-relative-path (file-name-directory (buffer-file-name (current-buffer))) | |
2465 (file-name-directory temp-file)) | |
2466 (file-name-nondirectory temp-file)))) | |
2467 (list "perl" (list "-wc " local-file)) | |
2468 ) | |
2469 ) | |
2470 | |
2471 ;;;; tex-specific init-cleanup routines | |
2472 | |
2473 (defun flymake-get-tex-args(file-name) | |
2474 ;(list "latex" (list "-c-style-errors" file-name)) | |
2475 (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name)) | |
2476 ) | |
2477 | |
2478 (defun flymake-simple-tex-init(buffer) | |
2479 (flymake-get-tex-args (flymake-init-create-temp-buffer-copy buffer 'flymake-create-temp-inplace)) | |
2480 ) | |
2481 | |
2482 (defun flymake-master-tex-init(buffer) | |
2483 (let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy | |
2484 buffer 'flymake-get-include-dirs-dot 'flymake-create-temp-inplace | |
2485 '(".+\\.tex$") | |
2486 '("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2)))) | |
2487 (when temp-master-file-name | |
2488 (flymake-get-tex-args temp-master-file-name) | |
2489 ) | |
2490 ) | |
2491 ) | |
2492 | |
2493 (defun flymake-get-include-dirs-dot(base-dir) | |
2494 '(".") | |
2495 ) | |
2496 | |
2497 ;;;; xml-specific init-cleanup routines | |
2498 | |
2499 (defun flymake-xml-init(buffer) | |
2500 (list "xml" (list "val" (flymake-init-create-temp-buffer-copy buffer 'flymake-create-temp-inplace))) | |
2501 ) | |
2502 | |
55843
26e0724718e2
Changes from arch/CVS synchronization
Miles Bader <miles@gnu.org>
parents:
55822
diff
changeset
|
2503 ;;; arch-tag: 8f0d6090-061d-4cac-8862-7c151c4a02dd |
55822 | 2504 ;;; flymake.el ends here |