;;; flymake.el -- a universal on-the-fly syntax checker
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
-;; Free Software Foundation, Inc.
+;; Copyright (C) 2003-2012 Free Software Foundation, Inc.
;; Author: Pavel Kobyakov <pk_at_work@yahoo.com>
;; Maintainer: Pavel Kobyakov <pk_at_work@yahoo.com>
'float-time
(if (featurep 'xemacs)
(lambda ()
- (multiple-value-bind (s0 s1 s2) (current-time)
+ (multiple-value-bind (s0 s1 s2) (values-list (current-time))
(+ (* (float (ash 1 16)) s0) (float s1) (* 0.0000001 s2)))))))
(defalias 'flymake-replace-regexp-in-string
'temp-directory
(lambda () temporary-file-directory)))
-(defalias 'flymake-line-beginning-position
- (if (fboundp 'line-beginning-position)
- 'line-beginning-position
- (lambda (&optional arg) (save-excursion (beginning-of-line arg) (point)))))
-
-(defalias 'flymake-line-end-position
- (if (fboundp 'line-end-position)
- 'line-end-position
- (lambda (&optional arg) (save-excursion (end-of-line arg) (point)))))
-
(defun flymake-posn-at-point-as-event (&optional position window dx dy)
"Return pixel position of top left corner of glyph at POSITION,
relative to top left corner of WINDOW, as a mouse-1 click
(make-variable-buffer-local 'flymake-output-residual)
+(defgroup flymake nil
+ "A universal on-the-fly syntax checker."
+ :version "23.1"
+ :group 'tools)
+
(defcustom flymake-allowed-file-name-masks
- '(("\\.c\\'" flymake-simple-make-init)
- ("\\.cpp\\'" flymake-simple-make-init)
+ '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init)
("\\.xml\\'" flymake-xml-init)
("\\.html?\\'" flymake-xml-init)
("\\.cs\\'" flymake-simple-make-init)
;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 ))
;; ("\\.tex\\'" 1)
)
- "*Files syntax checking is allowed for."
+ "Files syntax checking is allowed for."
:group 'flymake
:type '(repeat (string symbol symbol symbol)))
Buildfile includes Makefile, build.xml etc.
Return its file name if found, or nil if not found."
(or (flymake-get-buildfile-from-cache source-dir-name)
- (let* ((file (locate-dominating-file
- source-dir-name
- (concat "\\`" (regexp-quote buildfile-name) "\\'"))))
+ (let* ((file (locate-dominating-file source-dir-name buildfile-name)))
(if file
(progn
(flymake-log 3 "found buildfile at %s" file)
- (setq file (file-name-directory file))
(flymake-add-buildfile-to-cache source-dir-name file)
file)
(progn
(defun flymake-find-possible-master-files (file-name master-file-dirs masks)
"Find (by name and location) all possible master files.
-Master files are .cpp and .c for and .h. Files are searched for
+Master files include .cpp and .c for .h. Files are searched for
starting from the .h directory and max max-level parent dirs.
File contents are not checked."
(let* ((dirs master-file-dirs)
(not (equal file-one file-two))))
(defcustom flymake-check-file-limit 8192
- "Max number of chars to look at when checking possible master file."
+ "Maximum number of chars to look at when checking possible master file.
+Nil means search the entire file."
:group 'flymake
- :type 'integer)
+ :type '(choice (const :tag "No limit" nil)
+ (integer :tag "Characters")))
(defun flymake-check-patch-master-file-buffer
(master-file-temp-buffer
source-file-name patched-source-file-name
include-dirs regexp)
"Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME.
-For .cpp master file this means it includes SOURCE-FILE-NAME (.h).
If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME
instead of SOURCE-FILE-NAME.
+
+For example, foo.cpp is a master file if it includes foo.h.
+
Whether a buffer for MATER-FILE-NAME exists, use it as a source
instead of reading master file from disk."
(let* ((source-file-nondir (file-name-nondirectory source-file-name))
+ (source-file-extension (file-name-extension source-file-nondir))
+ (source-file-nonext (file-name-sans-extension source-file-nondir))
(found nil)
(inc-name nil)
(search-limit flymake-check-file-limit))
(setq regexp
(format regexp ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\""
- (regexp-quote source-file-nondir)))
+ ;; Hack for tex files, where \include often excludes .tex.
+ ;; Maybe this is safe generally.
+ (if (and (> (length source-file-extension) 1)
+ (string-equal source-file-extension "tex"))
+ (format "%s\\(?:\\.%s\\)?"
+ (regexp-quote source-file-nonext)
+ (regexp-quote source-file-extension))
+ (regexp-quote source-file-nondir))))
(unwind-protect
(with-current-buffer master-file-temp-buffer
- (when (> search-limit (point-max))
- (setq search-limit (point-max)))
+ (if (or (not search-limit)
+ (> search-limit (point-max)))
+ (setq search-limit (point-max)))
(flymake-log 3 "checking %s against regexp %s"
master-file-name regexp)
(goto-char (point-min))
(flymake-log 3 "found possible match for %s" source-file-nondir)
(setq inc-name (match-string 1))
+ (and (> (length source-file-extension) 1)
+ (string-equal source-file-extension "tex")
+ (not (string-match (format "\\.%s\\'" source-file-extension)
+ inc-name))
+ (setq inc-name (concat inc-name "." source-file-extension)))
(when (eq t (compare-strings
source-file-nondir nil nil
inc-name (- (length inc-name)
(with-current-buffer source-buffer
(flymake-parse-output-and-residual output)))))
-(defun flymake-process-sentinel (process event)
+(defun flymake-process-sentinel (process _event)
"Sentinel for syntax check buffers."
(when (memq (process-status process) '(signal exit))
(let* ((exit-status (process-exit-status process))
(flymake-report-status "" "") ; PASSED
(if (not flymake-check-was-interrupted)
(flymake-report-fatal-status "CFGERR"
- (format "Configuration error has occured while running %s" command))
+ (format "Configuration error has occurred while running %s" command))
(flymake-report-status nil ""))) ; "STOPPED"
(flymake-report-status (format "%d/%d" err-count warn-count) ""))))
(defun flymake-highlight-line (line-no line-err-info-list)
"Highlight line LINE-NO in current buffer.
Perhaps use text from LINE-ERR-INFO-LIST to enhance highlighting."
- (goto-line line-no)
- (let* ((line-beg (flymake-line-beginning-position))
- (line-end (flymake-line-end-position))
+ (goto-char (point-min))
+ (forward-line (1- line-no))
+ (let* ((line-beg (point-at-bol))
+ (line-end (point-at-eol))
(beg line-beg)
(end line-end)
(tooltip-text (flymake-ler-text (nth 0 line-err-info-list)))
;; PHP
("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 2 3 nil 1)
;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1)
- ;; ant/javac
- (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[ \t\n]*\\(.+\\)"
+ ;; ant/javac. Note this also matches gcc warnings!
+ (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\\(?:\:[0-9]+\\)?\:[ \t\n]*\\(.+\\)"
2 4 nil 5))
;; compilation-error-regexp-alist)
(flymake-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist))
(flymake-log 1 "deleted file %s" file-name)))
(defun flymake-safe-delete-directory (dir-name)
- (condition-case err
+ (condition-case nil
(progn
(delete-directory dir-name)
(flymake-log 1 "deleted dir %s" dir-name))
(flymake-log 1 "Failed to delete dir %s, error ignored" dir-name))))
(defcustom flymake-compilation-prevents-syntax-check t
- "If non-nil, syntax check won't be started in case compilation is running."
+ "If non-nil, don't start syntax check if compilation is running."
:group 'flymake
:type 'boolean)
(defun flymake-start-syntax-check-process (cmd args dir)
"Start syntax check process."
- (let* ((process nil))
- (condition-case err
- (progn
- (when dir
- (let ((default-directory dir))
- (flymake-log 3 "starting process on dir %s" default-directory)))
- (setq process (apply 'start-process "flymake-proc" (current-buffer) cmd args))
- (set-process-sentinel process 'flymake-process-sentinel)
- (set-process-filter process 'flymake-process-filter)
- (push process flymake-processes)
-
- (setq flymake-is-running t)
- (setq flymake-last-change-time nil)
- (setq flymake-check-start-time (flymake-float-time))
-
- (flymake-report-status nil "*")
- (flymake-log 2 "started process %d, command=%s, dir=%s"
- (process-id process) (process-command process)
- default-directory)
- process)
- (error
- (let* ((err-str (format "Failed to launch syntax check process '%s' with args %s: %s"
- cmd args (error-message-string err)))
- (source-file-name buffer-file-name)
- (cleanup-f (flymake-get-cleanup-function source-file-name)))
- (flymake-log 0 err-str)
- (funcall cleanup-f)
- (flymake-report-fatal-status "PROCERR" err-str))))))
+ (condition-case err
+ (let* ((process
+ (let ((default-directory (or dir default-directory)))
+ (when dir
+ (flymake-log 3 "starting process on dir %s" dir))
+ (apply 'start-file-process
+ "flymake-proc" (current-buffer) cmd args))))
+ (set-process-sentinel process 'flymake-process-sentinel)
+ (set-process-filter process 'flymake-process-filter)
+ (push process flymake-processes)
+
+ (setq flymake-is-running t)
+ (setq flymake-last-change-time nil)
+ (setq flymake-check-start-time (flymake-float-time))
+
+ (flymake-report-status nil "*")
+ (flymake-log 2 "started process %d, command=%s, dir=%s"
+ (process-id process) (process-command process)
+ default-directory)
+ process)
+ (error
+ (let* ((err-str (format "Failed to launch syntax check process '%s' with args %s: %s"
+ cmd args (error-message-string err)))
+ (source-file-name buffer-file-name)
+ (cleanup-f (flymake-get-cleanup-function source-file-name)))
+ (flymake-log 0 err-str)
+ (funcall cleanup-f)
+ (flymake-report-fatal-status "PROCERR" err-str)))))
(defun flymake-kill-process (proc)
"Kill process PROC."
(if (not (file-exists-p file))
(flymake-log 1 "File %s does not exist" file)
(find-file file)
- (goto-line line)))
+ (goto-char (point-min))
+ (forward-line (1- line))))
;; flymake minor mode declarations
(defvar flymake-mode-line nil)
;;;###autoload
(define-minor-mode flymake-mode
- "Minor mode to do on-the-fly syntax checking.
-When called interactively, toggles the minor mode.
-With arg, turn Flymake mode on if and only if arg is positive."
+ "Toggle on-the-fly syntax checking.
+With a prefix argument ARG, enable the mode if ARG is positive,
+and disable it otherwise. If called from Lisp, enable the mode
+if ARG is omitted or nil."
:group 'flymake :lighter flymake-mode-line
(cond
;; Turning the mode ON.
(flymake-mode
- (if (not (flymake-can-syntax-check-file buffer-file-name))
- (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name))
+ (cond
+ ((not buffer-file-name)
+ (message "Flymake unable to run without a buffer file name"))
+ ((not (flymake-can-syntax-check-file buffer-file-name))
+ (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name)))
+ (t
(add-hook 'after-change-functions 'flymake-after-change-function nil t)
(add-hook 'after-save-hook 'flymake-after-save-hook nil t)
(add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t)
(run-at-time nil 1 'flymake-on-timer-event (current-buffer)))
(when flymake-start-syntax-check-on-find-file
- (flymake-start-syntax-check))))
+ (flymake-start-syntax-check)))))
;; Turning the mode OFF.
(t
:group 'flymake
:type 'boolean)
-(defun flymake-after-change-function (start stop len)
+(defun flymake-after-change-function (start stop _len)
"Start syntax check for current buffer if it isn't already running."
;;+(flymake-log 0 "setting change time to %s" (flymake-float-time))
(let((new-text (buffer-substring start stop)))
(cancel-timer flymake-timer)
(setq flymake-timer nil)))
+;;;###autoload
(defun flymake-find-file-hook ()
;;+(when flymake-start-syntax-check-on-find-file
;;+ (flymake-log 3 "starting syntax check on file open")
(defun flymake-goto-line (line-no)
"Go to line LINE-NO, then skip whitespace."
- (goto-line line-no)
+ (goto-char (point-min))
+ (forward-line (1- line-no))
(flymake-skip-whitespace))
(defun flymake-goto-next-error ()
(flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name)
temp-name))
-(defun flymake-create-temp-with-folder-structure (file-name prefix)
+(defun flymake-create-temp-with-folder-structure (file-name _prefix)
(unless (stringp file-name)
(error "Invalid file-name"))
;;;; .h/make specific
(defun flymake-master-make-header-init ()
- (flymake-master-make-init 'flymake-get-include-dirs
- '("\\.cpp\\'" "\\.c\\'")
- "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\""))
+ (flymake-master-make-init
+ 'flymake-get-include-dirs
+ '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'")
+ "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\""))
;;;; .java/make specific
(defun flymake-simple-make-java-init ()
(defun flymake-simple-tex-init ()
(flymake-get-tex-args (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace)))
+;; Perhaps there should be a buffer-local variable flymake-master-file
+;; that people can set to override this stuff. Could inherit from
+;; the similar AUCTeX variable.
(defun flymake-master-tex-init ()
(let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
'flymake-get-include-dirs-dot 'flymake-create-temp-inplace
'("\\.tex\\'")
- "[ \t]*\\input[ \t]*{\\(.*%s\\)}")))
+ "[ \t]*\\in\\(?:put\\|clude\\)[ \t]*{\\(.*%s\\)}")))
(when temp-master-file-name
(flymake-get-tex-args temp-master-file-name))))
-(defun flymake-get-include-dirs-dot (base-dir)
+(defun flymake-get-include-dirs-dot (_base-dir)
'("."))
;;;; xml-specific init-cleanup routines
(provide 'flymake)
-;; arch-tag: 8f0d6090-061d-4cac-8862-7c151c4a02dd
;;; flymake.el ends here