summaryrefslogtreecommitdiff
path: root/lisp/progmodes
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2017-10-06 09:50:54 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2017-10-06 09:50:54 -0400
commit11f9cb522fed9aa6552f6315340ca7352661a1e8 (patch)
tree39facc48471c67b321c045e47d70ef030adbea44 /lisp/progmodes
parent92045f4546b9708dc9f69954799d211c1f56ff1e (diff)
parent9655937da4a339300c624addd97674c038a01bc9 (diff)
downloademacs-11f9cb522fed9aa6552f6315340ca7352661a1e8.tar.gz
Merge emacs-26
Diffstat (limited to 'lisp/progmodes')
-rw-r--r--lisp/progmodes/cc-engine.el54
-rw-r--r--lisp/progmodes/cc-langs.el5
-rw-r--r--lisp/progmodes/cc-mode.el4
-rw-r--r--lisp/progmodes/elisp-mode.el171
-rw-r--r--lisp/progmodes/flymake-proc.el1177
-rw-r--r--lisp/progmodes/flymake-ui.el634
-rw-r--r--lisp/progmodes/flymake.el960
-rw-r--r--lisp/progmodes/python.el6
8 files changed, 1806 insertions, 1205 deletions
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 05b391a3d38..37928357526 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -132,7 +132,7 @@
;;
;; 'c-not-decl
;; Put on the brace which introduces a brace list and on the commas
-;; which separate the element within it.
+;; which separate the elements within it.
;;
;; 'c-awk-NL-prop
;; Used in AWK mode to mark the various kinds of newlines. See
@@ -5403,15 +5403,14 @@ comment at the start of cc-engine.el for more info."
(min c-bs-cache-limit pos)))
(defun c-update-brace-stack (stack from to)
- ;; Give a brace-stack which has the value STACK at position FROM, update it
- ;; to it's value at position TO, where TO is after (or equal to) FROM.
+ ;; Given a brace-stack which has the value STACK at position FROM, update it
+ ;; to its value at position TO, where TO is after (or equal to) FROM.
;; Return a cons of either TO (if it is outside a literal) and this new
;; value, or of the next position after TO outside a literal and the new
;; value.
(let (match kwd-sym (prev-match-pos 1)
(s (cdr stack))
- (bound-<> (car stack))
- )
+ (bound-<> (car stack)))
(save-excursion
(cond
((and bound-<> (<= to bound-<>))
@@ -5472,6 +5471,9 @@ comment at the start of cc-engine.el for more info."
(setq s (cdr s))))
((c-keyword-member kwd-sym 'c-flat-decl-block-kwds)
(push 0 s))))
+ ;; The failing `c-syntactic-re-search-forward' may have left us in the
+ ;; middle of a token, which might be a significant token. Fix this!
+ (c-beginning-of-current-token)
(cons (point)
(cons bound-<> s)))))
@@ -5647,11 +5649,13 @@ comment at the start of cc-engine.el for more info."
;; Call CFD-FUN for each possible spot for a declaration, cast or
;; label from the point to CFD-LIMIT.
;;
- ;; CFD-FUN is called with point at the start of the spot. It's passed two
+ ;; CFD-FUN is called with point at the start of the spot. It's passed three
;; arguments: The first is the end position of the token preceding the spot,
;; or 0 for the implicit match at bob. The second is a flag that is t when
- ;; the match is inside a macro. Point should be moved forward by at least
- ;; one token.
+ ;; the match is inside a macro. The third is a flag that is t when the
+ ;; match is at "top level", i.e. outside any brace block, or directly inside
+ ;; a class or namespace, etc. Point should be moved forward by at least one
+ ;; token.
;;
;; If CFD-FUN adds `c-decl-end' properties somewhere below the current spot,
;; it should return non-nil to ensure that the next search will find them.
@@ -6038,6 +6042,8 @@ comment at the start of cc-engine.el for more info."
(setq cfd-macro-end 0)
nil)))) ; end of when condition
+ (when (> cfd-macro-end 0)
+ (setq cfd-top-level nil)) ; In a macro is "never" at top level.
(c-debug-put-decl-spot-faces cfd-match-pos (point))
(if (funcall cfd-fun cfd-match-pos (/= cfd-macro-end 0) cfd-top-level)
(setq cfd-prop-match nil))
@@ -8575,7 +8581,13 @@ comment at the start of cc-engine.el for more info."
(looking-at c-noise-macro-with-parens-name-re))
(c-forward-noise-clause))
- ((looking-at c-type-decl-suffix-key)
+ ((and (looking-at c-type-decl-suffix-key)
+ ;; We avoid recognizing foo(bar) or foo() at top level as a
+ ;; construct here in C, since we want to recognize this as a
+ ;; typeless function declaration.
+ (not (and (c-major-mode-is 'c-mode)
+ (eq context 'top)
+ (eq (char-after) ?\)))))
(if (eq (char-after) ?\))
(when (> paren-depth 0)
(setq paren-depth (1- paren-depth))
@@ -8618,7 +8630,12 @@ comment at the start of cc-engine.el for more info."
(save-excursion
(goto-char after-paren-pos)
(c-forward-syntactic-ws)
- (c-forward-type)))))
+ (or (c-forward-type)
+ ;; Recognize a top-level typeless
+ ;; function declaration in C.
+ (and (c-major-mode-is 'c-mode)
+ (eq context 'top)
+ (eq (char-after) ?\))))))))
(setq pos (c-up-list-forward (point)))
(eq (char-before pos) ?\)))
(c-fdoc-shift-type-backward)
@@ -9035,9 +9052,12 @@ comment at the start of cc-engine.el for more info."
;; (in at least C++) that anything that can be parsed as a declaration
;; is a declaration. Now we're being more defensive and prefer to
;; highlight things like "foo (bar);" as a declaration only if we're
- ;; inside an arglist that contains declarations.
- ;; CASE 19
- (eq context 'decl))))
+ ;; inside an arglist that contains declarations. Update (2017-09): We
+ ;; now recognize a top-level "foo(bar);" as a declaration in C.
+ ;; CASE 19
+ (or (eq context 'decl)
+ (and (c-major-mode-is 'c-mode)
+ (eq context 'top))))))
;; The point is now after the type decl expression.
@@ -9545,6 +9565,7 @@ Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
;; Note to maintainers: this function consumes a great mass of CPU cycles.
;; Its use should thus be minimized as far as possible.
+ ;; Consider instead using `c-bs-at-toplevel-p'.
(let ((paren-state (c-parse-state)))
(or (not (c-most-enclosing-brace paren-state))
(c-search-uplist-for-classkey paren-state))))
@@ -9574,8 +9595,15 @@ comment at the start of cc-engine.el for more info."
(not (and (c-major-mode-is 'objc-mode)
(c-forward-objc-directive)))
+ ;; Don't confuse #if .... defined(foo) for a function arglist.
+ (not (and (looking-at c-cpp-expr-functions-key)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (c-beginning-of-macro lim)))))
(setq id-start
(car-safe (c-forward-decl-or-cast-1 (c-point 'bosws) 'top nil)))
+ (numberp id-start)
(< id-start beg)
;; There should not be a '=' or ',' between beg and the
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index 9495d602e09..227b3e16485 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -952,6 +952,11 @@ expression, or nil if there aren't any in the language."
'("defined"))
pike '("defined" "efun" "constant"))
+(c-lang-defconst c-cpp-expr-functions-key
+ ;; Matches a function in a cpp expression.
+ t (c-make-keywords-re t (c-lang-const c-cpp-expr-functions)))
+(c-lang-defvar c-cpp-expr-functions-key (c-lang-const c-cpp-expr-functions-key))
+
(c-lang-defconst c-assignment-operators
"List of all assignment operators."
t '("=" "*=" "/=" "%=" "+=" "-=" ">>=" "<<=" "&=" "^=" "|=")
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 8867453e85c..b0e5fe47a7c 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -1571,6 +1571,8 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".")
(and (c-beginning-of-macro)
(progn (c-end-of-macro) (point))))))
(when (and (c-forward-declarator lim)
+ (or (not (eq (char-after) ?\())
+ (c-go-list-forward nil lim))
(eq (c-forward-token-2 1 nil lim) 0))
(c-backward-syntactic-ws)
(point))))))
@@ -1589,7 +1591,7 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".")
(or (c-fl-decl-start c-new-BEG) (c-point 'bol c-new-BEG))
c-new-END
(or (c-fl-decl-end c-new-END)
- (c-point 'bonl (max (1- c-new-END) (point-min)))))))
+ (c-point 'bonl c-new-END)))))
(defun c-context-expand-fl-region (beg end)
;; Return a cons (NEW-BEG . NEW-END), where NEW-BEG is the beginning of a
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 2f8e081a295..3690f673832 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -243,7 +243,9 @@ Blank lines separate paragraphs. Semicolons start comments.
(add-hook 'xref-backend-functions #'elisp--xref-backend nil t)
(setq-local project-vc-external-roots-function #'elisp-load-path-roots)
(add-hook 'completion-at-point-functions
- #'elisp-completion-at-point nil 'local))
+ #'elisp-completion-at-point nil 'local)
+ (add-hook 'flymake-diagnostic-functions #'elisp-flymake-checkdoc nil t)
+ (add-hook 'flymake-diagnostic-functions #'elisp-flymake-byte-compile nil t))
;; Font-locking support.
@@ -810,7 +812,7 @@ non-nil result supercedes the xrefs produced by
(apply #'nconc
(let (lst)
(dolist (sym (apropos-internal regexp))
- (push (elisp--xref-find-definitions sym) lst))
+ (push (elisp--xref-find-definitions sym) lst))
(nreverse lst))))
(defvar elisp--xref-identifier-completion-table
@@ -1109,7 +1111,7 @@ If CHAR is not a character, return nil."
;; interactive call would use it.
;; FIXME: Is it really the right place for this?
(when (eq (car-safe expr) 'interactive)
- (setq expr
+ (setq expr
`(call-interactively
(lambda (&rest args) ,expr args))))
expr)))))
@@ -1174,7 +1176,7 @@ POS specifies the starting position where EXP was found and defaults to point."
(and (not (special-variable-p var))
(save-excursion
(zerop (car (syntax-ppss (match-beginning 0)))))
- (push var vars))))
+ (push var vars))))
`(progn ,@(mapcar (lambda (v) `(defvar ,v)) vars) ,exp)))))
(defun eval-last-sexp (eval-last-sexp-arg-internal)
@@ -1379,7 +1381,7 @@ or elsewhere, return a 1-line docstring."
(t (help-function-arglist sym)))))
;; Stringify, and store before highlighting, downcasing, etc.
(elisp--last-data-store sym (elisp-function-argstring args)
- 'function))))))
+ 'function))))))
;; Highlight, truncate.
(if argstring
(elisp--highlight-function-argument
@@ -1588,5 +1590,164 @@ ARGLIST is either a string, or a list of strings or symbols."
(replace-match "(" t t str)
str)))
+;;; Flymake support
+
+;; Don't require checkdoc, but forward declare these checkdoc special
+;; variables. Autoloading them on `checkdoc-current-buffer' is too
+;; late, they won't be bound dynamically.
+(defvar checkdoc-create-error-function)
+(defvar checkdoc-autofix-flag)
+(defvar checkdoc-generate-compile-warnings-flag)
+(defvar checkdoc-diagnostic-buffer)
+(defun elisp-flymake--checkdoc-1 ()
+ "Do actual work for `elisp-flymake-checkdoc'."
+ (let (collected)
+ (let* ((checkdoc-create-error-function
+ (lambda (text start end &optional unfixable)
+ (push (list text start end unfixable) collected)
+ nil))
+ (checkdoc-autofix-flag nil)
+ (checkdoc-generate-compile-warnings-flag nil)
+ (buf (generate-new-buffer " *checkdoc-temp*"))
+ (checkdoc-diagnostic-buffer buf))
+ (unwind-protect
+ (save-excursion
+ (checkdoc-current-buffer t))
+ (kill-buffer buf)))
+ collected))
+
+;;;###autoload
+(defun elisp-flymake-checkdoc (report-fn &rest _args)
+ "A Flymake backend for `checkdoc'.
+Calls REPORT-FN directly."
+ (unless (derived-mode-p 'emacs-lisp-mode)
+ (error "Can only work on `emacs-lisp-mode' buffers"))
+ (funcall report-fn
+ (cl-loop for (text start end _unfixable) in
+ (elisp-flymake--checkdoc-1)
+ collect
+ (flymake-make-diagnostic
+ (current-buffer)
+ start end :note text))))
+
+(defun elisp-flymake--byte-compile-done (report-fn
+ origin-buffer
+ output-buffer
+ temp-file)
+ (unwind-protect
+ (with-current-buffer
+ origin-buffer
+ (save-excursion
+ (save-restriction
+ (widen)
+ (funcall
+ report-fn
+ (cl-loop with data =
+ (with-current-buffer output-buffer
+ (goto-char (point-min))
+ (search-forward ":elisp-flymake-output-start")
+ (read (point-marker)))
+ for (string pos _fill level) in data
+ do (goto-char pos)
+ for beg = (if (< (point) (point-max))
+ (point)
+ (line-beginning-position))
+ for end = (min
+ (line-end-position)
+ (or (cdr
+ (bounds-of-thing-at-point 'sexp))
+ (point-max)))
+ collect (flymake-make-diagnostic
+ (current-buffer)
+ (if (= beg end) (1- beg) beg)
+ end
+ level
+ string))))))
+ (kill-buffer output-buffer)
+ (ignore-errors (delete-file temp-file))))
+
+(defvar-local elisp-flymake--byte-compile-process nil
+ "Buffer-local process started for byte-compiling the buffer.")
+
+;;;###autoload
+(defun elisp-flymake-byte-compile (report-fn &rest _args)
+ "A Flymake backend for elisp byte compilation.
+Spawn an Emacs process that byte-compiles a file representing the
+current buffer state and calls REPORT-FN when done."
+ (interactive (list (lambda (stuff)
+ (message "aha %s" stuff))))
+ (unless (derived-mode-p 'emacs-lisp-mode)
+ (error "Can only work on `emacs-lisp-mode' buffers"))
+ (when elisp-flymake--byte-compile-process
+ (process-put elisp-flymake--byte-compile-process 'elisp-flymake--obsolete t)
+ (when (process-live-p elisp-flymake--byte-compile-process)
+ (kill-process elisp-flymake--byte-compile-process)))
+ (let ((temp-file (make-temp-file "elisp-flymake-byte-compile"))
+ (origin-buffer (current-buffer)))
+ (save-restriction
+ (widen)
+ (write-region (point-min) (point-max) temp-file nil 'nomessage))
+ (let* ((output-buffer (generate-new-buffer " *elisp-flymake-byte-compile*")))
+ (setq
+ elisp-flymake--byte-compile-process
+ (make-process
+ :name "elisp-flymake-byte-compile"
+ :buffer output-buffer
+ :command (list (expand-file-name invocation-name invocation-directory)
+ "-Q"
+ "--batch"
+ ;; "--eval" "(setq load-prefer-newer t)" ; for testing
+ "-L" default-directory
+ "-f" "elisp-flymake--batch-compile-for-flymake"
+ temp-file)
+ :connection-type 'pipe
+ :sentinel
+ (lambda (proc _event)
+ (unless (process-live-p proc)
+ (unwind-protect
+ (cond
+ ((zerop (process-exit-status proc))
+ (elisp-flymake--byte-compile-done report-fn
+ origin-buffer
+ output-buffer
+ temp-file))
+ ((process-get proc 'elisp-flymake--obsolete)
+ (flymake-log :warning "byte-compile process %s obsolete" proc))
+ (t
+ (funcall report-fn
+ :panic
+ :explanation
+ (format "byte-compile process %s died" proc)))))))))
+ :stderr null-device
+ :noquery t)))
+
+(defun elisp-flymake--batch-compile-for-flymake (&optional file)
+ "Helper for `elisp-flymake-byte-compile'.
+Runs in a batch-mode Emacs. Interactively use variable
+`buffer-file-name' for FILE."
+ (interactive (list buffer-file-name))
+ (let* ((file (or file
+ (car command-line-args-left)))
+ (dummy-elc-file)
+ (byte-compile-log-buffer
+ (generate-new-buffer " *dummy-byte-compile-log-buffer*"))
+ (byte-compile-dest-file-function
+ (lambda (source)
+ (setq dummy-elc-file (make-temp-file (file-name-nondirectory source)))))
+ (collected)
+ (byte-compile-log-warning-function
+ (lambda (string &optional position fill level)
+ (push (list string position fill level)
+ collected)
+ t)))
+ (unwind-protect
+ (byte-compile-file file)
+ (ignore-errors
+ (delete-file dummy-elc-file)
+ (kill-buffer byte-compile-log-buffer)))
+ (prin1 :elisp-flymake-output-start)
+ (terpri)
+ (pp collected)))
+
(provide 'elisp-mode)
;;; elisp-mode.el ends here
diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el
index df1a0750cfb..52cb1985327 100644
--- a/lisp/progmodes/flymake-proc.el
+++ b/lisp/progmodes/flymake-proc.el
@@ -1,4 +1,4 @@
-;;; flymake-proc.el --- Flymake for external syntax checker processes -*- lexical-binding: t; -*-
+;;; flymake-proc.el --- Flymake backend for external tools -*- lexical-binding: t; -*-
;; Copyright (C) 2003-2017 Free Software Foundation, Inc.
@@ -20,15 +20,19 @@
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Flymake is a minor Emacs mode performing on-the-fly syntax checks.
;;
-;; This file contains the most original implementation of flymake's
-;; main source of on-the-fly diagnostic info, the external syntax
-;; checker backend.
+;; This file contains a significant part of the original flymake's
+;; implementation, a buffer-checking mechanism that parses the output
+;; of an external syntax check tool with regular expressions.
+;;
+;; That work has been adapted into a flymake "backend" function,
+;; `flymake-proc-legacy-flymake' suitable for adding to the
+;; `flymake-diagnostic-functions' variable.
;;
;;; Bugs/todo:
@@ -37,42 +41,45 @@
;;; Code:
-(require 'flymake-ui)
+(require 'flymake)
-(defcustom flymake-compilation-prevents-syntax-check t
+(defcustom flymake-proc-compilation-prevents-syntax-check t
"If non-nil, don't start syntax check if compilation is running."
:group 'flymake
:type 'boolean)
-(defcustom flymake-xml-program
+(defcustom flymake-proc-xml-program
(if (executable-find "xmlstarlet") "xmlstarlet" "xml")
"Program to use for XML validation."
:type 'file
:group 'flymake
:version "24.4")
-(defcustom flymake-master-file-dirs '("." "./src" "./UnitTest")
+(defcustom flymake-proc-master-file-dirs '("." "./src" "./UnitTest")
"Dirs where to look for master files."
:group 'flymake
:type '(repeat (string)))
-(defcustom flymake-master-file-count-limit 32
+(defcustom flymake-proc-master-file-count-limit 32
"Max number of master files to check."
:group 'flymake
:type 'integer)
-(defcustom flymake-allowed-file-name-masks
- '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init)
- ("\\.xml\\'" flymake-xml-init)
- ("\\.html?\\'" flymake-xml-init)
- ("\\.cs\\'" flymake-simple-make-init)
- ("\\.p[ml]\\'" flymake-perl-init)
- ("\\.php[345]?\\'" flymake-php-init)
- ("\\.h\\'" flymake-master-make-header-init flymake-master-cleanup)
- ("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup)
- ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup)
- ("\\.tex\\'" flymake-simple-tex-init)
- ("\\.idl\\'" flymake-simple-make-init)
+(defcustom flymake-proc-allowed-file-name-masks
+ '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'"
+ flymake-proc-simple-make-init
+ nil
+ flymake-proc-real-file-name-considering-includes)
+ ("\\.xml\\'" flymake-proc-xml-init)
+ ("\\.html?\\'" flymake-proc-xml-init)
+ ("\\.cs\\'" flymake-proc-simple-make-init)
+ ("\\.p[ml]\\'" flymake-proc-perl-init)
+ ("\\.php[345]?\\'" flymake-proc-php-init)
+ ("\\.h\\'" flymake-proc-master-make-header-init flymake-proc-master-cleanup)
+ ("\\.java\\'" flymake-proc-simple-make-java-init flymake-proc-simple-java-cleanup)
+ ("[0-9]+\\.tex\\'" flymake-proc-master-tex-init flymake-proc-master-cleanup)
+ ("\\.tex\\'" flymake-proc-simple-tex-init)
+ ("\\.idl\\'" flymake-proc-simple-make-init)
;; ("\\.cpp\\'" 1)
;; ("\\.java\\'" 3)
;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'")
@@ -85,98 +92,161 @@
)
"Files syntax checking is allowed for.
This is an alist with elements of the form:
- REGEXP [INIT [CLEANUP [NAME]]]
+ REGEXP INIT [CLEANUP [NAME]]
REGEXP is a regular expression that matches a file name.
-INIT is the init function to use, missing means disable `flymake-mode'.
-CLEANUP is the cleanup function to use, default `flymake-simple-cleanup'.
-NAME is the file name function to use, default `flymake-get-real-file-name'."
+INIT is the init function to use.
+CLEANUP is the cleanup function to use, default `flymake-proc-simple-cleanup'.
+NAME is the file name function to use, default `flymake-proc-get-real-file-name'."
:group 'flymake
:type '(alist :key-type (regexp :tag "File regexp")
:value-type
(list :tag "Handler functions"
- (choice :tag "Init function"
- (const :tag "disable" nil)
- function)
+ (function :tag "Init function")
(choice :tag "Cleanup function"
- (const :tag "flymake-simple-cleanup" nil)
+ (const :tag "flymake-proc-simple-cleanup" nil)
function)
(choice :tag "Name function"
- (const :tag "flymake-get-real-file-name" nil)
+ (const :tag "flymake-proc-get-real-file-name" nil)
function))))
-(defvar flymake-processes nil
- "List of currently active flymake processes.")
+(defvar-local flymake-proc--current-process nil
+ "Currently active Flymake process for a buffer, if any.")
+
+(defvar flymake-proc--report-fn nil
+ "If bound, function used to report back to Flymake's UI.")
+
+(defun flymake-proc-reformat-err-line-patterns-from-compile-el (original-list)
+ "Grab error line patterns from ORIGINAL-LIST in compile.el format.
+Convert it to Flymake internal format."
+ (let* ((converted-list '()))
+ (dolist (item original-list)
+ (setq item (cdr item))
+ (let ((regexp (nth 0 item))
+ (file (nth 1 item))
+ (line (nth 2 item))
+ (col (nth 3 item)))
+ (if (consp file) (setq file (car file)))
+ (if (consp line) (setq line (car line)))
+ (if (consp col) (setq col (car col)))
-(defvar-local flymake-output-residual nil)
+ (when (not (functionp line))
+ (setq converted-list (cons (list regexp file line col) converted-list)))))
+ converted-list))
-(defun flymake-get-file-name-mode-and-masks (file-name)
- "Return the corresponding entry from `flymake-allowed-file-name-masks'."
+(defvar flymake-proc-err-line-patterns ; regexp file-idx line-idx col-idx (optional) text-idx(optional), match-end to end of string is error text
+ (append
+ '(
+ ;; MS Visual C++ 6.0
+ ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) : \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
+ 1 3 nil 4)
+ ;; jikes
+ ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:[0-9]+: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)"
+ 1 3 nil 4)
+ ;; MS midl
+ ("midl[ ]*:[ ]*\\(command line error .*\\)"
+ nil nil nil 1)
+ ;; MS C#
+ ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+): \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
+ 1 3 nil 4)
+ ;; perl
+ ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
+ ;; 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. Note this also matches gcc warnings!
+ (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?:[ \t\n]*\\(.+\\)"
+ 2 4 5 6))
+ ;; compilation-error-regexp-alist)
+ (flymake-proc-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist))
+ "Patterns for matching error/warning lines. Each pattern has the form
+\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX).
+Use `flymake-proc-reformat-err-line-patterns-from-compile-el' to add patterns
+from compile.el")
+
+(define-obsolete-variable-alias 'flymake-warning-re 'flymake-proc-diagnostic-type-pred "26.1")
+(defvar flymake-proc-diagnostic-type-pred
+ 'flymake-proc-default-guess
+ "Predicate matching against diagnostic text to detect its type.
+Takes a single argument, the diagnostic's text and should return
+a value suitable for indexing
+`flymake-diagnostic-types-alist' (which see). If the returned
+value is nil, a type of `:error' is assumed. For some backward
+compatibility, if a non-nil value is returned that that doesn't
+index that alist, a type of `:warning' is assumed.
+
+Instead of a function, it can also be a string, a regular
+expression. A match indicates `:warning' type, otherwise
+`:error'")
+
+(defun flymake-proc-default-guess (text)
+ "Guess if TEXT means a warning, a note or an error."
+ (cond ((string-match "^[wW]arning" text)
+ :warning)
+ ((string-match "^[nN]ote" text)
+ :note)
+ (t
+ :error)))
+
+(defun flymake-proc--get-file-name-mode-and-masks (file-name)
+ "Return the corresponding entry from `flymake-proc-allowed-file-name-masks'."
(unless (stringp file-name)
(error "Invalid file-name"))
- (let ((fnm flymake-allowed-file-name-masks)
+ (let ((fnm flymake-proc-allowed-file-name-masks)
(mode-and-masks nil))
(while (and (not mode-and-masks) fnm)
- (let ((item (pop fnm)))
- (when (string-match (car item) file-name)
- (setq mode-and-masks item)))) ; (cdr item) may be nil
- (setq mode-and-masks (cdr mode-and-masks))
+ (if (string-match (car (car fnm)) file-name)
+ (setq mode-and-masks (cdr (car fnm))))
+ (setq fnm (cdr fnm)))
(flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks))
mode-and-masks))
-(defun flymake-proc-can-syntax-check-buffer ()
- "Determine whether we can syntax check current buffer.
-Return nil if we cannot, non-nil if
-we can."
- (and buffer-file-name
- (if (flymake-get-init-function buffer-file-name) t nil)))
-
-(defun flymake-get-init-function (file-name)
+(defun flymake-proc--get-init-function (file-name)
"Return init function to be used for the file."
- (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name))))
+ (let* ((init-f (nth 0 (flymake-proc--get-file-name-mode-and-masks file-name))))
;;(flymake-log 0 "calling %s" init-f)
;;(funcall init-f (current-buffer))
init-f))
-(defun flymake-get-cleanup-function (file-name)
+(defun flymake-proc--get-cleanup-function (file-name)
"Return cleanup function to be used for the file."
- (or (nth 1 (flymake-get-file-name-mode-and-masks file-name))
- 'flymake-simple-cleanup))
+ (or (nth 1 (flymake-proc--get-file-name-mode-and-masks file-name))
+ 'flymake-proc-simple-cleanup))
-(defun flymake-get-real-file-name-function (file-name)
- (or (nth 2 (flymake-get-file-name-mode-and-masks file-name))
- 'flymake-get-real-file-name))
+(defun flymake-proc--get-real-file-name-function (file-name)
+ (or (nth 2 (flymake-proc--get-file-name-mode-and-masks file-name))
+ 'flymake-proc-get-real-file-name))
-(defvar flymake-find-buildfile-cache (make-hash-table :test #'equal))
+(defvar flymake-proc--find-buildfile-cache (make-hash-table :test #'equal))
-(defun flymake-get-buildfile-from-cache (dir-name)
+(defun flymake-proc--get-buildfile-from-cache (dir-name)
"Look up DIR-NAME in cache and return its associated value.
If DIR-NAME is not found, return nil."
- (gethash dir-name flymake-find-buildfile-cache))
+ (gethash dir-name flymake-proc--find-buildfile-cache))
-(defun flymake-add-buildfile-to-cache (dir-name buildfile)
+(defun flymake-proc--add-buildfile-to-cache (dir-name buildfile)
"Associate DIR-NAME with BUILDFILE in the buildfile cache."
- (puthash dir-name buildfile flymake-find-buildfile-cache))
+ (puthash dir-name buildfile flymake-proc--find-buildfile-cache))
-(defun flymake-clear-buildfile-cache ()
+(defun flymake-proc--clear-buildfile-cache ()
"Clear the buildfile cache."
- (clrhash flymake-find-buildfile-cache))
+ (clrhash flymake-proc--find-buildfile-cache))
-(defun flymake-find-buildfile (buildfile-name source-dir-name)
+(defun flymake-proc--find-buildfile (buildfile-name source-dir-name)
"Find buildfile starting from current directory.
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)
+ (or (flymake-proc--get-buildfile-from-cache source-dir-name)
(let* ((file (locate-dominating-file source-dir-name buildfile-name)))
(if file
(progn
(flymake-log 3 "found buildfile at %s" file)
- (flymake-add-buildfile-to-cache source-dir-name file)
+ (flymake-proc--add-buildfile-to-cache source-dir-name file)
file)
(progn
(flymake-log 3 "buildfile for %s not found" source-dir-name)
nil)))))
-(defun flymake-fix-file-name (name)
+(defun flymake-proc--fix-file-name (name)
"Replace all occurrences of `\\' with `/'."
(when name
(setq name (expand-file-name name))
@@ -184,18 +254,17 @@ Return its file name if found, or nil if not found."
(setq name (directory-file-name name))
name))
-(defun flymake-same-files (file-name-one file-name-two)
+(defun flymake-proc--same-files (file-name-one file-name-two)
"Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file.
Return t if so, nil if not."
- (equal (flymake-fix-file-name file-name-one)
- (flymake-fix-file-name file-name-two)))
+ (equal (flymake-proc--fix-file-name file-name-one)
+ (flymake-proc--fix-file-name file-name-two)))
;; This is bound dynamically to pass a parameter to a sort predicate below
-(defvar flymake-included-file-name)
+(defvar flymake-proc--included-file-name)
-(defun flymake-find-possible-master-files (file-name master-file-dirs masks)
+(defun flymake-proc--find-possible-master-files (file-name master-file-dirs masks)
"Find (by name and location) all possible master files.
-
Name is specified by FILE-NAME and location is specified by
MASTER-FILE-DIRS. Master files include .cpp and .c for .h.
Files are searched for starting from the .h directory and max
@@ -216,35 +285,35 @@ max-level parent dirs. File contents are not checked."
(while (and (not done) dir-files)
(when (not (file-directory-p (car dir-files)))
(setq files (cons (car dir-files) files))
- (when (>= (length files) flymake-master-file-count-limit)
- (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit)
+ (when (>= (length files) flymake-proc-master-file-count-limit)
+ (flymake-log 3 "master file count limit (%d) reached" flymake-proc-master-file-count-limit)
(setq done t)))
(setq dir-files (cdr dir-files))))
(setq masks (cdr masks))))
(setq dirs (cdr dirs)))
(when files
- (let ((flymake-included-file-name (file-name-nondirectory file-name)))
- (setq files (sort files 'flymake-master-file-compare))))
+ (let ((flymake-proc--included-file-name (file-name-nondirectory file-name)))
+ (setq files (sort files 'flymake-proc--master-file-compare))))
(flymake-log 3 "found %d possible master file(s)" (length files))
files))
-(defun flymake-master-file-compare (file-one file-two)
+(defun flymake-proc--master-file-compare (file-one file-two)
"Compare two files specified by FILE-ONE and FILE-TWO.
This function is used in sort to move most possible file names
to the beginning of the list (File.h -> File.cpp moved to top)."
- (and (equal (file-name-sans-extension flymake-included-file-name)
+ (and (equal (file-name-sans-extension flymake-proc--included-file-name)
(file-name-base file-one))
(not (equal file-one file-two))))
-(defvar flymake-check-file-limit 8192
+(defvar flymake-proc-check-file-limit 8192
"Maximum number of chars to look at when checking possible master file.
Nil means search the entire file.")
-(defun flymake-check-patch-master-file-buffer
- (master-file-temp-buffer
- master-file-name patched-master-file-name
- source-file-name patched-source-file-name
- include-dirs regexp)
+(defun flymake-proc--check-patch-master-file-buffer
+ (master-file-temp-buffer
+ master-file-name patched-master-file-name
+ source-file-name patched-source-file-name
+ include-dirs regexp)
"Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME.
If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME
instead of SOURCE-FILE-NAME.
@@ -258,7 +327,7 @@ instead of reading master file from disk."
(source-file-nonext (file-name-sans-extension source-file-nondir))
(found nil)
(inc-name nil)
- (search-limit flymake-check-file-limit))
+ (search-limit flymake-proc-check-file-limit))
(setq regexp
(format regexp ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\""
;; Hack for tex files, where \include often excludes .tex.
@@ -294,18 +363,18 @@ instead of reading master file from disk."
inc-name (- (length inc-name)
(length source-file-nondir)) nil))
(flymake-log 3 "inc-name=%s" inc-name)
- (when (flymake-check-include source-file-name inc-name
- include-dirs)
+ (when (flymake-proc--check-include source-file-name inc-name
+ include-dirs)
(setq found t)
;; replace-match is not used here as it fails in
;; XEmacs with 'last match not a buffer' error as
;; check-includes calls replace-in-string
- (flymake-replace-region
+ (flymake-proc--replace-region
match-beg match-end
(file-name-nondirectory patched-source-file-name))))
(forward-line 1)))
(when found
- (flymake-save-buffer-in-file patched-master-file-name)))
+ (flymake-proc--save-buffer-in-file patched-master-file-name)))
;;+(flymake-log 3 "killing buffer %s"
;; (buffer-name master-file-temp-buffer))
(kill-buffer master-file-temp-buffer))
@@ -315,7 +384,7 @@ instead of reading master file from disk."
found))
;;; XXX: remove
-(defun flymake-replace-region (beg end rep)
+(defun flymake-proc--replace-region (beg end rep)
"Replace text in BUFFER in region (BEG END) with REP."
(save-excursion
(goto-char end)
@@ -323,14 +392,14 @@ instead of reading master file from disk."
(insert rep)
(delete-region beg end)))
-(defun flymake-read-file-to-temp-buffer (file-name)
+(defun flymake-proc--read-file-to-temp-buffer (file-name)
"Insert contents of FILE-NAME into newly created temp buffer."
(let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name))))))
(with-current-buffer temp-buffer
(insert-file-contents file-name))
temp-buffer))
-(defun flymake-copy-buffer-to-temp-buffer (buffer)
+(defun flymake-proc--copy-buffer-to-temp-buffer (buffer)
"Copy contents of BUFFER into newly created temp buffer."
(with-current-buffer
(get-buffer-create (generate-new-buffer-name
@@ -338,13 +407,13 @@ instead of reading master file from disk."
(insert-buffer-substring buffer)
(current-buffer)))
-(defun flymake-check-include (source-file-name inc-name include-dirs)
+(defun flymake-proc--check-include (source-file-name inc-name include-dirs)
"Check if SOURCE-FILE-NAME can be found in include path.
Return t if it can be found via include path using INC-NAME."
(if (file-name-absolute-p inc-name)
- (flymake-same-files source-file-name inc-name)
+ (flymake-proc--same-files source-file-name inc-name)
(while (and include-dirs
- (not (flymake-same-files
+ (not (flymake-proc--same-files
source-file-name
(concat (file-name-directory source-file-name)
"/" (car include-dirs)
@@ -352,17 +421,17 @@ Return t if it can be found via include path using INC-NAME."
(setq include-dirs (cdr include-dirs)))
include-dirs))
-(defun flymake-find-buffer-for-file (file-name)
+(defun flymake-proc--find-buffer-for-file (file-name)
"Check if there exists a buffer visiting FILE-NAME.
Return t if so, nil if not."
(let ((buffer-name (get-file-buffer file-name)))
(if buffer-name
(get-buffer buffer-name))))
-(defun flymake-create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp)
+(defun flymake-proc--create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp)
"Save SOURCE-FILE-NAME with a different name.
Find master file, patch and save it."
- (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks))
+ (let* ((possible-master-files (flymake-proc--find-possible-master-files source-file-name flymake-proc-master-file-dirs masks))
(master-file-count (length possible-master-files))
(idx 0)
(temp-buffer nil)
@@ -373,11 +442,11 @@ Find master file, patch and save it."
(while (and (not found) (< idx master-file-count))
(setq master-file-name (nth idx possible-master-files))
(setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master"))
- (if (flymake-find-buffer-for-file master-file-name)
- (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name)))
- (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name)))
+ (if (flymake-proc--find-buffer-for-file master-file-name)
+ (setq temp-buffer (flymake-proc--copy-buffer-to-temp-buffer (flymake-proc--find-buffer-for-file master-file-name)))
+ (setq temp-buffer (flymake-proc--read-file-to-temp-buffer master-file-name)))
(setq found
- (flymake-check-patch-master-file-buffer
+ (flymake-proc--check-patch-master-file-buffer
temp-buffer
master-file-name
patched-master-file-name
@@ -393,260 +462,185 @@ Find master file, patch and save it."
(file-name-nondirectory source-file-name))
nil))))
-(defun flymake-save-buffer-in-file (file-name)
+(defun flymake-proc--save-buffer-in-file (file-name)
"Save the entire buffer contents into file FILE-NAME.
Create parent directories as needed."
(make-directory (file-name-directory file-name) 1)
(write-region nil nil file-name nil 566)
(flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name))
-(defun flymake-process-filter (process output)
- "Parse OUTPUT and highlight error lines.
-It's flymake process filter."
- (let ((source-buffer (process-buffer process)))
-
- (flymake-log 3 "received %d byte(s) of output from process %d"
- (length output) (process-id process))
- (when (buffer-live-p source-buffer)
- (with-current-buffer source-buffer
- (flymake-parse-output-and-residual output)))))
-
-(defun flymake-process-sentinel (process _event)
+(defun flymake-proc--diagnostics-for-pattern (proc pattern)
+ (cl-flet ((guess-type
+ (pred message)
+ (cond ((null message)
+ :error)
+ ((stringp pred)
+ (if (string-match pred message)
+ :warning
+ :error))
+ ((functionp pred)
+ (let ((probe (funcall pred message)))
+ (cond ((assoc-default probe
+ flymake-diagnostic-types-alist)
+ probe)
+ (probe
+ :warning)
+ (t
+ :error)))))))
+ (condition-case-unless-debug err
+ (cl-loop
+ with (regexp file-idx line-idx col-idx message-idx) = pattern
+ while (and
+ (search-forward-regexp regexp nil t)
+ ;; If the preceding search spanned more than one line,
+ ;; move to the start of the line we ended up in. This
+ ;; preserves the usefulness of the patterns in
+ ;; `flymake-proc-err-line-patterns', which were
+ ;; written primarily for flymake's original
+ ;; line-by-line parsing and thus never spanned
+ ;; multiple lines.
+ (if (/= (line-number-at-pos (match-beginning 0))
+ (line-number-at-pos))
+ (goto-char (line-beginning-position))
+ t))
+ for fname = (and file-idx (match-string file-idx))
+ for message = (and message-idx (match-string message-idx))
+ for line-string = (and line-idx (match-string line-idx))
+ for line-number = (or (and line-string
+ (string-to-number line-string))
+ 1)
+ for col-string = (and col-idx (match-string col-idx))
+ for col-number = (and col-string
+ (string-to-number col-string))
+ for full-file = (with-current-buffer (process-buffer proc)
+ (and fname
+ (funcall
+ (flymake-proc--get-real-file-name-function
+ fname)
+ fname)))
+ for buffer = (and full-file
+ (find-buffer-visiting full-file))
+ if (and (eq buffer (process-buffer proc)) message)
+ collect (pcase-let ((`(,beg . ,end)
+ (flymake-diag-region buffer line-number col-number)))
+ (flymake-make-diagnostic
+ buffer beg end
+ (with-current-buffer buffer
+ (guess-type flymake-proc-diagnostic-type-pred message))
+ message))
+ else
+ do (flymake-log 2 "Reference to file %s is out of scope" fname))
+ (error
+ (flymake-log 1 "Error parsing process output for pattern %s: %s"
+ pattern err)
+ nil))))
+
+(defun flymake-proc--process-filter (proc string)
+ "Parse STRING and collect diagnostics info."
+ (flymake-log 3 "received %d byte(s) of output from process %d"
+ (length string) (process-id proc))
+ (let ((output-buffer (process-get proc 'flymake-proc--output-buffer)))
+ (when (and (buffer-live-p (process-buffer proc))
+ output-buffer)
+ (with-current-buffer output-buffer
+ (let ((moving (= (point) (process-mark proc)))
+ (inhibit-read-only t)
+ (unprocessed-mark
+ (or (process-get proc 'flymake-proc--unprocessed-mark)
+ (set-marker (make-marker) (point-min)))))
+ (save-excursion
+ ;; Insert the text, advancing the process marker.
+ (goto-char (process-mark proc))
+ (insert string)
+ (set-marker (process-mark proc) (point)))
+ (if moving (goto-char (process-mark proc)))
+
+ ;; check for new diagnostics
+ ;;
+ (save-excursion
+ (goto-char unprocessed-mark)
+ (dolist (pattern flymake-proc-err-line-patterns)
+ (let ((new (flymake-proc--diagnostics-for-pattern proc pattern)))
+ (process-put
+ proc
+ 'flymake-proc--collected-diagnostics
+ (append new
+ (process-get proc
+ 'flymake-proc--collected-diagnostics)))))
+ (process-put proc 'flymake-proc--unprocessed-mark
+ (point-marker))))))))
+
+(defun flymake-proc--process-sentinel (proc _event)
"Sentinel for syntax check buffers."
- (when (memq (process-status process) '(signal exit))
- (let* ((exit-status (process-exit-status process))
- (command (process-command process))
- (source-buffer (process-buffer process))
- (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer))))
-
- (flymake-log 2 "process %d exited with code %d"
- (process-id process) exit-status)
- (condition-case err
- (progn
- (flymake-log 3 "cleaning up using %s" cleanup-f)
- (when (buffer-live-p source-buffer)
- (with-current-buffer source-buffer
- (funcall cleanup-f)))
-
- (delete-process process)
- (setq flymake-processes (delq process flymake-processes))
-
- (when (buffer-live-p source-buffer)
- (with-current-buffer source-buffer
-
- (flymake-parse-residual)
- (flymake-post-syntax-check exit-status command)
- (setq flymake-is-running nil))))
- (error
- (let ((err-str (format "Error in process sentinel for buffer %s: %s"
- source-buffer (error-message-string err))))
- (flymake-log 0 err-str)
- (with-current-buffer source-buffer
- (setq flymake-is-running nil))))))))
-
-(defun flymake-post-syntax-check (exit-status command)
- (save-restriction
- (widen)
- (setq flymake-err-info flymake-new-err-info)
- (setq flymake-new-err-info nil)
- (setq flymake-err-info
- (flymake-fix-line-numbers
- flymake-err-info 1 (count-lines (point-min) (point-max))))
- (flymake-delete-own-overlays)
- (flymake-highlight-err-lines flymake-err-info)
- (let (err-count warn-count)
- (setq err-count (flymake-get-err-count flymake-err-info "e"))
- (setq warn-count (flymake-get-err-count flymake-err-info "w"))
- (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)"
- (buffer-name) err-count warn-count
- (- (float-time) flymake-check-start-time))
- (setq flymake-check-start-time nil)
-
- (if (and (equal 0 err-count) (equal 0 warn-count))
- (if (equal 0 exit-status)
- (flymake-report-status "" "") ; PASSED
- (if (not flymake-check-was-interrupted)
- (flymake-report-fatal-status "CFGERR"
- (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-parse-output-and-residual (output)
- "Split OUTPUT into lines, merge in residual if necessary."
- (let* ((buffer-residual flymake-output-residual)
- (total-output (if buffer-residual (concat buffer-residual output) output))
- (lines-and-residual (flymake-split-output total-output))
- (lines (nth 0 lines-and-residual))
- (new-residual (nth 1 lines-and-residual)))
- (setq flymake-output-residual new-residual)
- (setq flymake-new-err-info
- (flymake-parse-err-lines
- flymake-new-err-info lines))))
-
-(defun flymake-parse-residual ()
- "Parse residual if it's non empty."
- (when flymake-output-residual
- (setq flymake-new-err-info
- (flymake-parse-err-lines
- flymake-new-err-info
- (list flymake-output-residual)))
- (setq flymake-output-residual nil)))
-
-(defun flymake-fix-line-numbers (err-info-list min-line max-line)
- "Replace line numbers with fixed value.
-If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE.
-If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE.
-The reason for this fix is because some compilers might report
-line number outside the file being compiled."
- (let* ((count (length err-info-list))
- (err-info nil)
- (line 0))
- (while (> count 0)
- (setq err-info (nth (1- count) err-info-list))
- (setq line (flymake-er-get-line err-info))
- (when (or (< line min-line) (> line max-line))
- (setq line (if (< line min-line) min-line max-line))
- (setq err-info-list (flymake-set-at err-info-list (1- count)
- (flymake-er-make-er line
- (flymake-er-get-line-err-info-list err-info)))))
- (setq count (1- count))))
- err-info-list)
-
-(defun flymake-parse-err-lines (err-info-list lines)
- "Parse err LINES, store info in ERR-INFO-LIST."
- (let* ((count (length lines))
- (idx 0)
- (line-err-info nil)
- (real-file-name nil)
- (source-file-name buffer-file-name)
- (get-real-file-name-f (flymake-get-real-file-name-function source-file-name)))
-
- (while (< idx count)
- (setq line-err-info (flymake-parse-line (nth idx lines)))
- (when line-err-info
- (setq real-file-name (funcall get-real-file-name-f
- (flymake-ler-file line-err-info)))
- (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name))
-
- (when (flymake-same-files real-file-name source-file-name)
- (setq line-err-info (flymake-ler-set-file line-err-info nil))
- (setq err-info-list (flymake-add-err-info err-info-list line-err-info))))
- (flymake-log 3 "parsed `%s', %s line-err-info" (nth idx lines) (if line-err-info "got" "no"))
- (setq idx (1+ idx)))
- err-info-list))
-
-(defun flymake-split-output (output)
- "Split OUTPUT into lines.
-Return last one as residual if it does not end with newline char.
-Returns ((LINES) RESIDUAL)."
- (when (and output (> (length output) 0))
- (let* ((lines (split-string output "[\n\r]+" t))
- (complete (equal "\n" (char-to-string (aref output (1- (length output))))))
- (residual nil))
- (when (not complete)
- (setq residual (car (last lines)))
- (setq lines (butlast lines)))
- (list lines residual))))
-
-(defun flymake-reformat-err-line-patterns-from-compile-el (original-list)
- "Grab error line patterns from ORIGINAL-LIST in compile.el format.
-Convert it to flymake internal format."
- (let* ((converted-list '()))
- (dolist (item original-list)
- (setq item (cdr item))
- (let ((regexp (nth 0 item))
- (file (nth 1 item))
- (line (nth 2 item))
- (col (nth 3 item)))
- (if (consp file) (setq file (car file)))
- (if (consp line) (setq line (car line)))
- (if (consp col) (setq col (car col)))
-
- (when (not (functionp line))
- (setq converted-list (cons (list regexp file line col) converted-list)))))
- converted-list))
+ (let (debug
+ (pid (process-id proc))
+ (source-buffer (process-buffer proc)))
+ (unwind-protect
+ (when (buffer-live-p source-buffer)
+ (with-current-buffer source-buffer
+ (cond ((process-get proc 'flymake-proc--obsolete)
+ (flymake-log 3 "proc %s considered obsolete"
+ pid))
+ ((process-get proc 'flymake-proc--interrupted)
+ (flymake-log 3 "proc %s interrupted by user"
+ pid))
+ ((not (process-live-p proc))
+ (let* ((exit-status (process-exit-status proc))
+ (command (process-command proc))
+ (diagnostics (process-get
+ proc
+ 'flymake-proc--collected-diagnostics)))
+ (flymake-log 2 "process %d exited with code %d"
+ pid exit-status)
+ (cond
+ ((equal 0 exit-status)
+ (funcall flymake-proc--report-fn diagnostics
+ :explanation (format "a gift from %s" (process-id proc))
+ ))
+ (diagnostics
+ ;; non-zero exit but some diagnostics is quite
+ ;; normal...
+ (funcall flymake-proc--report-fn diagnostics
+ :explanation (format "a gift from %s" (process-id proc))))
+ ((null diagnostics)
+ ;; ...but no diagnostics is strange, so panic.
+ (setq debug debug-on-error)
+ (flymake-proc--panic
+ :configuration-error
+ (format "Command %s errored, but no diagnostics"
+ command)))))))))
+ (let ((output-buffer (process-get proc 'flymake-proc--output-buffer)))
+ (cond (debug
+ (flymake-log 3 "Output buffer %s kept alive for debugging"
+ output-buffer))
+ (t
+ (when (buffer-live-p source-buffer)
+ (with-current-buffer source-buffer
+ (let ((cleanup-f (flymake-proc--get-cleanup-function
+ (buffer-file-name))))
+ (flymake-log 3 "cleaning up using %s" cleanup-f)
+ (funcall cleanup-f))))
+ (kill-buffer output-buffer)))))))
+
+(defun flymake-proc--panic (problem explanation)
+ "Tell Flymake UI about a fatal PROBLEM with this backend.
+May only be called in a dynamic environment where
+`flymake-proc--report-fn' is bound."
+ (flymake-log 0 "%s: %s" problem explanation)
+ (if (and (boundp 'flymake-proc--report-fn)
+ flymake-proc--report-fn)
+ (funcall flymake-proc--report-fn :panic
+ :explanation (format "%s: %s" problem explanation))
+ (flymake-error "Trouble telling flymake-ui about problem %s(%s)"
+ problem explanation)))
(require 'compile)
-(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
- (append
- '(
- ;; MS Visual C++ 6.0
- ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) : \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
- 1 3 nil 4)
- ;; jikes
- ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:[0-9]+: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)"
- 1 3 nil 4)
- ;; MS midl
- ("midl[ ]*:[ ]*\\(command line error .*\\)"
- nil nil nil 1)
- ;; MS C#
- ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+): \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
- 1 3 nil 4)
- ;; perl
- ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
- ;; 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. 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))
- "Patterns for matching error/warning lines. Each pattern has the form
-\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX).
-Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns
-from compile.el")
-
-(define-obsolete-variable-alias 'flymake-warning-re 'flymake-warning-predicate "24.4")
-(defvar flymake-warning-predicate "^[wW]arning"
- "Predicate matching against error text to detect a warning.
-Takes a single argument, the error's text and should return non-nil
-if it's a warning.
-Instead of a function, it can also be a regular expression.")
-
-(defun flymake-parse-line (line)
- "Parse LINE to see if it is an error or warning.
-Return its components if so, nil otherwise."
- (let ((raw-file-name nil)
- (line-no 0)
- (err-type "e")
- (err-text nil)
- (patterns flymake-err-line-patterns)
- (matched nil))
- (while (and patterns (not matched))
- (when (string-match (car (car patterns)) line)
- (let* ((file-idx (nth 1 (car patterns)))
- (line-idx (nth 2 (car patterns))))
-
- (setq raw-file-name (if file-idx (match-string file-idx line) nil))
- (setq line-no (if line-idx (string-to-number
- (match-string line-idx line)) 0))
- (setq err-text (if (> (length (car patterns)) 4)
- (match-string (nth 4 (car patterns)) line)
- (flymake-patch-err-text
- (substring line (match-end 0)))))
- (if (null err-text)
- (setq err-text "<no error text>")
- (when (cond ((stringp flymake-warning-predicate)
- (string-match flymake-warning-predicate err-text))
- ((functionp flymake-warning-predicate)
- (funcall flymake-warning-predicate err-text)))
- (setq err-type "w")))
- (flymake-log
- 3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s"
- file-idx line-idx raw-file-name line-no err-text)
- (setq matched t)))
- (setq patterns (cdr patterns)))
- (if matched
- (flymake-ler-make-ler raw-file-name line-no err-type err-text)
- ())))
-
-(defun flymake-get-project-include-dirs-imp (basedir)
+(defun flymake-proc-get-project-include-dirs-imp (basedir)
"Include dirs for the project current file belongs to."
- (if (flymake-get-project-include-dirs-from-cache basedir)
+ (if (flymake-proc--get-project-include-dirs-from-cache basedir)
(progn
- (flymake-get-project-include-dirs-from-cache basedir))
+ (flymake-proc--get-project-include-dirs-from-cache basedir))
;;else
(let* ((command-line (concat "make -C "
(shell-quote-argument basedir)
@@ -665,148 +659,170 @@ Return its components if so, nil otherwise."
(when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines)))
(push (replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs))
(setq inc-count (1- inc-count)))))
- (flymake-add-project-include-dirs-to-cache basedir inc-dirs)
+ (flymake-proc--add-project-include-dirs-to-cache basedir inc-dirs)
inc-dirs)))
-(defvar flymake-get-project-include-dirs-function #'flymake-get-project-include-dirs-imp
+(defvar flymake-proc-get-project-include-dirs-function #'flymake-proc-get-project-include-dirs-imp
"Function used to get project include dirs, one parameter: basedir name.")
-(defun flymake-get-project-include-dirs (basedir)
- (funcall flymake-get-project-include-dirs-function basedir))
+(defun flymake-proc--get-project-include-dirs (basedir)
+ (funcall flymake-proc-get-project-include-dirs-function basedir))
-(defun flymake-get-system-include-dirs ()
+(defun flymake-proc--get-system-include-dirs ()
"System include dirs - from the `INCLUDE' env setting."
(let* ((includes (getenv "INCLUDE")))
(if includes (split-string includes path-separator t) nil)))
-(defvar flymake-project-include-dirs-cache (make-hash-table :test #'equal))
+(defvar flymake-proc--project-include-dirs-cache (make-hash-table :test #'equal))
-(defun flymake-get-project-include-dirs-from-cache (base-dir)
- (gethash base-dir flymake-project-include-dirs-cache))
+(defun flymake-proc--get-project-include-dirs-from-cache (base-dir)
+ (gethash base-dir flymake-proc--project-include-dirs-cache))
-(defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs)
- (puthash base-dir include-dirs flymake-project-include-dirs-cache))
+(defun flymake-proc--add-project-include-dirs-to-cache (base-dir include-dirs)
+ (puthash base-dir include-dirs flymake-proc--project-include-dirs-cache))
-(defun flymake-clear-project-include-dirs-cache ()
- (clrhash flymake-project-include-dirs-cache))
+(defun flymake-proc--clear-project-include-dirs-cache ()
+ (clrhash flymake-proc--project-include-dirs-cache))
-(defun flymake-get-include-dirs (base-dir)
+(defun flymake-proc-get-include-dirs (base-dir)
"Get dirs to use when resolving local file names."
- (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs))))
+ (let* ((include-dirs (append '(".") (flymake-proc--get-project-include-dirs base-dir) (flymake-proc--get-system-include-dirs))))
include-dirs))
-;; (defun flymake-restore-formatting ()
+;; (defun flymake-proc--restore-formatting ()
;; "Remove any formatting made by flymake."
;; )
-;; (defun flymake-get-program-dir (buffer)
+;; (defun flymake-proc--get-program-dir (buffer)
;; "Get dir to start program in."
;; (unless (bufferp buffer)
;; (error "Invalid buffer"))
;; (with-current-buffer buffer
;; default-directory))
-(defun flymake-safe-delete-file (file-name)
+(defun flymake-proc--safe-delete-file (file-name)
(when (and file-name (file-exists-p file-name))
(delete-file file-name)
- (flymake-log 1 "deleted file %s" file-name)))
+ (flymake-log 2 "deleted file %s" file-name)))
-(defun flymake-safe-delete-directory (dir-name)
- (condition-case nil
+(defun flymake-proc--safe-delete-directory (dir-name)
+ (condition-case-unless-debug nil
(progn
(delete-directory dir-name)
- (flymake-log 1 "deleted dir %s" dir-name))
+ (flymake-log 2 "deleted dir %s" dir-name))
(error
(flymake-log 1 "Failed to delete dir %s, error ignored" dir-name))))
-(defun flymake-proc-start-syntax-check ()
- "Start syntax checking for current buffer."
- (interactive)
- (flymake-log 3 "flymake is running: %s" flymake-is-running)
- (when (not flymake-is-running)
- (when (or (not flymake-compilation-prevents-syntax-check)
- (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP")
- (flymake-clear-buildfile-cache)
- (flymake-clear-project-include-dirs-cache)
-
- (setq flymake-check-was-interrupted nil)
-
- (let* ((source-file-name buffer-file-name)
- (init-f (flymake-get-init-function source-file-name))
- (cleanup-f (flymake-get-cleanup-function source-file-name))
- (cmd-and-args (funcall init-f))
- (cmd (nth 0 cmd-and-args))
- (args (nth 1 cmd-and-args))
- (dir (nth 2 cmd-and-args)))
- (if (not cmd-and-args)
- (progn
- (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name)
- (funcall cleanup-f))
- (progn
- (setq flymake-last-change-time nil)
- (flymake-start-syntax-check-process cmd args dir)))))))
-
-(defun flymake-start-syntax-check-process (cmd args dir)
- "Start syntax check process."
- (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)
- (set-process-query-on-exit-flag process nil)
- (push process flymake-processes)
-
- (setq flymake-is-running t)
- (setq flymake-last-change-time nil)
- (setq flymake-check-start-time (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-message
- "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."
- (kill-process proc)
- (let* ((buf (process-buffer proc)))
- (when (buffer-live-p buf)
- (with-current-buffer buf
- (setq flymake-check-was-interrupted t))))
- (flymake-log 1 "killed process %d" (process-id proc)))
-
-(defun flymake-stop-all-syntax-checks ()
- "Kill all syntax check processes."
- (interactive)
- (while flymake-processes
- (flymake-kill-process (pop flymake-processes))))
-(defun flymake-compilation-is-running ()
+(defun flymake-proc-legacy-flymake (report-fn &rest args)
+ "Flymake backend based on the original Flymake implementation.
+This function is suitable for inclusion in
+`flymake-diagnostic-functions'. For backward compatibility, it
+can also be executed interactively independently of
+`flymake-mode'."
+ ;; Interactively, behave as if flymake had invoked us through its
+ ;; `flymake-diagnostic-functions' with a suitable ID so flymake can
+ ;; clean up consistently
+ (interactive (list
+ (lambda (diags &rest args)
+ (apply (flymake-make-report-fn 'flymake-proc-legacy-flymake)
+ diags
+ (append args '(:force t))))
+ :interactive t))
+ (let ((interactive (plist-get args :interactive))
+ (proc flymake-proc--current-process)
+ (flymake-proc--report-fn report-fn))
+ (when (processp proc)
+ (process-put proc 'flymake-proc--obsolete t)
+ (flymake-log 3 "marking %s obsolete" (process-id proc))
+ (when (process-live-p proc)
+ (when interactive
+ (user-error
+ "There's already a Flymake process running in this buffer")
+ (kill-process proc))))
+ (when
+ ;; This particular situation make us not want to error right
+ ;; away (and disable ourselves), in case the situation changes
+ ;; in the near future.
+ (and (or (not flymake-proc-compilation-prevents-syntax-check)
+ (not (flymake-proc--compilation-is-running))))
+ (let ((init-f
+ (and
+ buffer-file-name
+ ;; Since we write temp files in current dir, there's no point
+ ;; trying if the directory is read-only (bug#8954).
+ (file-writable-p (file-name-directory buffer-file-name))
+ (flymake-proc--get-init-function buffer-file-name))))
+ (unless init-f (error "Can find a suitable init function"))
+ (flymake-proc--clear-buildfile-cache)
+ (flymake-proc--clear-project-include-dirs-cache)
+
+ (let* ((cleanup-f (flymake-proc--get-cleanup-function buffer-file-name))
+ (cmd-and-args (funcall init-f))
+ (cmd (nth 0 cmd-and-args))
+ (args (nth 1 cmd-and-args))
+ (dir (nth 2 cmd-and-args))
+ (success nil))
+ (unwind-protect
+ (cond
+ ((not cmd-and-args)
+ (flymake-log 0 "init function %s for %s failed, cleaning up"
+ init-f buffer-file-name))
+ (t
+ (setq proc
+ (let ((default-directory (or dir default-directory)))
+ (when dir
+ (flymake-log 3 "starting process on dir %s" dir))
+ (make-process
+ :name "flymake-proc"
+ :buffer (current-buffer)
+ :command (cons cmd args)
+ :noquery t
+ :filter
+ (lambda (proc string)
+ (let ((flymake-proc--report-fn report-fn))
+ (flymake-proc--process-filter proc string)))
+ :sentinel
+ (lambda (proc event)
+ (let ((flymake-proc--report-fn report-fn))
+ (flymake-proc--process-sentinel proc event))))))
+ (process-put proc 'flymake-proc--output-buffer
+ (generate-new-buffer
+ (format " *flymake output for %s*" (current-buffer))))
+ (setq flymake-proc--current-process proc)
+ (flymake-log 2 "started process %d, command=%s, dir=%s"
+ (process-id proc) (process-command proc)
+ default-directory)
+ (setq success t)))
+ (unless success
+ (funcall cleanup-f))))))))
+
+(define-obsolete-function-alias 'flymake-start-syntax-check
+ 'flymake-proc-legacy-flymake "26.1")
+
+(defun flymake-proc-stop-all-syntax-checks (&optional reason)
+ "Kill all syntax check processes."
+ (interactive (list "Interrupted by user"))
+ (dolist (buf (buffer-list))
+ (with-current-buffer buf
+ (let (p flymake-proc--current-process)
+ (when (process-live-p p)
+ (kill-process p)
+ (process-put p 'flymake-proc--interrupted reason)
+ (flymake-log 2 "killed process %d" (process-id p)))))))
+
+(defun flymake-proc--compilation-is-running ()
(and (boundp 'compilation-in-progress)
compilation-in-progress))
-(defun flymake-compile ()
- "Kill all flymake syntax checks, start compilation."
+(defun flymake-proc-compile ()
+ "Kill all Flymake syntax checks, start compilation."
(interactive)
- (flymake-stop-all-syntax-checks)
+ (flymake-proc-stop-all-syntax-checks "Stopping for proper compilation")
(call-interactively 'compile))
;;;; general init-cleanup and helper routines
-(defun flymake-create-temp-inplace (file-name prefix)
+(defun flymake-proc-create-temp-inplace (file-name prefix)
(unless (stringp file-name)
(error "Invalid file-name"))
(or prefix
@@ -819,7 +835,7 @@ Return its components if so, nil otherwise."
(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-proc-create-temp-with-folder-structure (file-name _prefix)
(unless (stringp file-name)
(error "Invalid file-name"))
@@ -833,48 +849,47 @@ Return its components if so, nil otherwise."
(file-truename (expand-file-name (file-name-nondirectory file-name)
temp-dir))))
-(defun flymake-delete-temp-directory (dir-name)
- "Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error."
+(defun flymake-proc--delete-temp-directory (dir-name)
+ "Attempt to delete temp dir created by `flymake-proc-create-temp-with-folder-structure', do not fail on error."
(let* ((temp-dir temporary-file-directory)
(suffix (substring dir-name (1+ (length temp-dir)))))
(while (> (length suffix) 0)
(setq suffix (directory-file-name suffix))
;;+(flymake-log 0 "suffix=%s" suffix)
- (flymake-safe-delete-directory
+ (flymake-proc--safe-delete-directory
(file-truename (expand-file-name suffix temp-dir)))
(setq suffix (file-name-directory suffix)))))
-(defvar-local flymake-temp-source-file-name nil)
-(defvar-local flymake-master-file-name nil)
-(defvar-local flymake-temp-master-file-name nil)
-(defvar-local flymake-base-dir nil)
+(defvar-local flymake-proc--temp-source-file-name nil)
+(defvar-local flymake-proc--master-file-name nil)
+(defvar-local flymake-proc--temp-master-file-name nil)
+(defvar-local flymake-proc--base-dir nil)
-(defun flymake-init-create-temp-buffer-copy (create-temp-f)
+(defun flymake-proc-init-create-temp-buffer-copy (create-temp-f)
"Make a temporary copy of the current buffer, save its name in buffer data and return the name."
(let* ((source-file-name buffer-file-name)
(temp-source-file-name (funcall create-temp-f source-file-name "flymake")))
- (flymake-save-buffer-in-file temp-source-file-name)
- (setq flymake-temp-source-file-name temp-source-file-name)
+ (flymake-proc--save-buffer-in-file temp-source-file-name)
+ (setq flymake-proc--temp-source-file-name temp-source-file-name)
temp-source-file-name))
-(defun flymake-simple-cleanup ()
- "Do cleanup after `flymake-init-create-temp-buffer-copy'.
+(defun flymake-proc-simple-cleanup ()
+ "Do cleanup after `flymake-proc-init-create-temp-buffer-copy'.
Delete temp file."
- (flymake-safe-delete-file flymake-temp-source-file-name)
- (setq flymake-last-change-time nil))
+ (flymake-proc--safe-delete-file flymake-proc--temp-source-file-name))
-(defun flymake-get-real-file-name (file-name-from-err-msg)
+(defun flymake-proc-get-real-file-name (file-name-from-err-msg)
"Translate file name from error message to \"real\" file name.
Return full-name. Names are real, not patched."
(let* ((real-name nil)
(source-file-name buffer-file-name)
- (master-file-name flymake-master-file-name)
- (temp-source-file-name flymake-temp-source-file-name)
- (temp-master-file-name flymake-temp-master-file-name)
+ (master-file-name flymake-proc--master-file-name)
+ (temp-source-file-name flymake-proc--temp-source-file-name)
+ (temp-master-file-name flymake-proc--temp-master-file-name)
(base-dirs
- (list flymake-base-dir
+ (list flymake-proc--base-dir
(file-name-directory source-file-name)
(if master-file-name (file-name-directory master-file-name))))
(files (list (list source-file-name source-file-name)
@@ -885,17 +900,17 @@ Return full-name. Names are real, not patched."
(when (equal 0 (length file-name-from-err-msg))
(setq file-name-from-err-msg source-file-name))
- (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files))
+ (setq real-name (flymake-proc--get-full-patched-file-name file-name-from-err-msg base-dirs files))
;; if real-name is nil, than file name from err msg is none of the files we've patched
(if (not real-name)
- (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs)))
+ (setq real-name (flymake-proc--get-full-nonpatched-file-name file-name-from-err-msg base-dirs)))
(if (not real-name)
(setq real-name file-name-from-err-msg))
- (setq real-name (flymake-fix-file-name real-name))
+ (setq real-name (flymake-proc--fix-file-name real-name))
(flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name)
real-name))
-(defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs files)
+(defun flymake-proc--get-full-patched-file-name (file-name-from-err-msg base-dirs files)
(let* ((base-dirs-count (length base-dirs))
(file-count (length files))
(real-name nil))
@@ -907,7 +922,7 @@ Return full-name. Names are real, not patched."
(this-file (nth 0 (nth (1- file-count) files)))
(this-real-name (nth 1 (nth (1- file-count) files))))
;;+(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)
- (when (and this-dir this-file (flymake-same-files
+ (when (and this-dir this-file (flymake-proc--same-files
(expand-file-name file-name-from-err-msg this-dir)
this-file))
(setq real-name this-real-name)))
@@ -915,7 +930,7 @@ Return full-name. Names are real, not patched."
(setq base-dirs-count (1- base-dirs-count)))
real-name))
-(defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs)
+(defun flymake-proc--get-full-nonpatched-file-name (file-name-from-err-msg base-dirs)
(let* ((real-name nil))
(if (file-name-absolute-p file-name-from-err-msg)
(setq real-name file-name-from-err-msg)
@@ -928,41 +943,42 @@ Return full-name. Names are real, not patched."
(setq base-dirs-count (1- base-dirs-count))))))
real-name))
-(defun flymake-init-find-buildfile-dir (source-file-name buildfile-name)
+(defun flymake-proc--init-find-buildfile-dir (source-file-name buildfile-name)
"Find buildfile, store its dir in buffer data and return its dir, if found."
(let* ((buildfile-dir
- (flymake-find-buildfile buildfile-name
- (file-name-directory source-file-name))))
+ (flymake-proc--find-buildfile buildfile-name
+ (file-name-directory source-file-name))))
(if buildfile-dir
- (setq flymake-base-dir buildfile-dir)
- (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name)
- (flymake-report-fatal-status
+ (setq flymake-proc--base-dir buildfile-dir)
+ (flymake-proc--panic
"NOMK" (format "No buildfile (%s) found for %s"
buildfile-name source-file-name)))))
-(defun flymake-init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f create-temp-f master-file-masks include-regexp)
+(defun flymake-proc--init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f create-temp-f master-file-masks include-regexp)
"Find master file (or buffer), create its copy along with a copy of the source file."
(let* ((source-file-name buffer-file-name)
- (temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f))
- (master-and-temp-master (flymake-create-master-file
+ (temp-source-file-name (flymake-proc-init-create-temp-buffer-copy create-temp-f))
+ (master-and-temp-master (flymake-proc--create-master-file
source-file-name temp-source-file-name
get-incl-dirs-f create-temp-f
master-file-masks include-regexp)))
(if (not master-and-temp-master)
(progn
- (flymake-log 1 "cannot find master file for %s" source-file-name)
- (flymake-report-status "!" "") ; NOMASTER
+ (flymake-proc--panic
+ "NOMASTER"
+ (format-message "cannot find master file for %s"
+ source-file-name))
nil)
- (setq flymake-master-file-name (nth 0 master-and-temp-master))
- (setq flymake-temp-master-file-name (nth 1 master-and-temp-master)))))
+ (setq flymake-proc--master-file-name (nth 0 master-and-temp-master))
+ (setq flymake-proc--temp-master-file-name (nth 1 master-and-temp-master)))))
-(defun flymake-master-cleanup ()
- (flymake-simple-cleanup)
- (flymake-safe-delete-file flymake-temp-master-file-name))
+(defun flymake-proc-master-cleanup ()
+ (flymake-proc-simple-cleanup)
+ (flymake-proc--safe-delete-file flymake-proc--temp-master-file-name))
;;;; make-specific init-cleanup routines
-(defun flymake-get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f)
+(defun flymake-proc--get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f)
"Create a command line for syntax check using GET-CMD-LINE-F."
(funcall get-cmd-line-f
(if use-relative-source
@@ -973,7 +989,7 @@ Return full-name. Names are real, not patched."
(file-name-directory source-file-name))
base-dir)))
-(defun flymake-get-make-cmdline (source base-dir)
+(defun flymake-proc-get-make-cmdline (source base-dir)
(list "make"
(list "-s"
"-C"
@@ -982,119 +998,196 @@ Return full-name. Names are real, not patched."
"SYNTAX_CHECK_MODE=1"
"check-syntax")))
-(defun flymake-get-ant-cmdline (source base-dir)
+(defun flymake-proc-get-ant-cmdline (source base-dir)
(list "ant"
(list "-buildfile"
(concat base-dir "/" "build.xml")
(concat "-DCHK_SOURCES=" source)
"check-syntax")))
-(defun flymake-simple-make-init-impl (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f)
+(defun flymake-proc-simple-make-init-impl (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f)
"Create syntax check command line for a directly checked source file.
Use CREATE-TEMP-F for creating temp copy."
(let* ((args nil)
(source-file-name buffer-file-name)
- (buildfile-dir (flymake-init-find-buildfile-dir source-file-name build-file-name)))
+ (buildfile-dir (flymake-proc--init-find-buildfile-dir source-file-name build-file-name)))
(if buildfile-dir
- (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)))
- (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir
- use-relative-base-dir use-relative-source
- get-cmdline-f))))
+ (let* ((temp-source-file-name (flymake-proc-init-create-temp-buffer-copy create-temp-f)))
+ (setq args (flymake-proc--get-syntax-check-program-args temp-source-file-name buildfile-dir
+ use-relative-base-dir use-relative-source
+ get-cmdline-f))))
args))
-(defun flymake-simple-make-init ()
- (flymake-simple-make-init-impl 'flymake-create-temp-inplace t t "Makefile" 'flymake-get-make-cmdline))
+(defun flymake-proc-simple-make-init ()
+ (flymake-proc-simple-make-init-impl 'flymake-proc-create-temp-inplace t t "Makefile" 'flymake-proc-get-make-cmdline))
-(defun flymake-master-make-init (get-incl-dirs-f master-file-masks include-regexp)
+(defun flymake-proc-master-make-init (get-incl-dirs-f master-file-masks include-regexp)
"Create make command line for a source file checked via master file compilation."
(let* ((make-args nil)
- (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
- get-incl-dirs-f 'flymake-create-temp-inplace
+ (temp-master-file-name (flymake-proc--init-create-temp-source-and-master-buffer-copy
+ get-incl-dirs-f 'flymake-proc-create-temp-inplace
master-file-masks include-regexp)))
(when temp-master-file-name
- (let* ((buildfile-dir (flymake-init-find-buildfile-dir temp-master-file-name "Makefile")))
+ (let* ((buildfile-dir (flymake-proc--init-find-buildfile-dir temp-master-file-name "Makefile")))
(if buildfile-dir
- (setq make-args (flymake-get-syntax-check-program-args
- temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline)))))
+ (setq make-args (flymake-proc--get-syntax-check-program-args
+ temp-master-file-name buildfile-dir nil nil 'flymake-proc-get-make-cmdline)))))
make-args))
-(defun flymake-find-make-buildfile (source-dir)
- (flymake-find-buildfile "Makefile" source-dir))
+(defun flymake-proc--find-make-buildfile (source-dir)
+ (flymake-proc--find-buildfile "Makefile" source-dir))
;;;; .h/make specific
-(defun flymake-master-make-header-init ()
- (flymake-master-make-init
- 'flymake-get-include-dirs
+(defun flymake-proc-master-make-header-init ()
+ (flymake-proc-master-make-init
+ 'flymake-proc-get-include-dirs
'("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'")
"[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\""))
+(defun flymake-proc-real-file-name-considering-includes (scraped)
+ (flymake-proc-get-real-file-name
+ (let ((case-fold-search t))
+ (replace-regexp-in-string "^in file included from[ \t*]"
+ ""
+ scraped))))
+
;;;; .java/make specific
-(defun flymake-simple-make-java-init ()
- (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline))
+(defun flymake-proc-simple-make-java-init ()
+ (flymake-proc-simple-make-init-impl 'flymake-proc-create-temp-with-folder-structure nil nil "Makefile" 'flymake-proc-get-make-cmdline))
-(defun flymake-simple-ant-java-init ()
- (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline))
+(defun flymake-proc-simple-ant-java-init ()
+ (flymake-proc-simple-make-init-impl 'flymake-proc-create-temp-with-folder-structure nil nil "build.xml" 'flymake-proc-get-ant-cmdline))
-(defun flymake-simple-java-cleanup ()
- "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs."
- (flymake-safe-delete-file flymake-temp-source-file-name)
- (when flymake-temp-source-file-name
- (flymake-delete-temp-directory
- (file-name-directory flymake-temp-source-file-name))))
+(defun flymake-proc-simple-java-cleanup ()
+ "Cleanup after `flymake-proc-simple-make-java-init' -- delete temp file and dirs."
+ (flymake-proc--safe-delete-file flymake-proc--temp-source-file-name)
+ (when flymake-proc--temp-source-file-name
+ (flymake-proc--delete-temp-directory
+ (file-name-directory flymake-proc--temp-source-file-name))))
;;;; perl-specific init-cleanup routines
-(defun flymake-perl-init ()
- (let* ((temp-file (flymake-init-create-temp-buffer-copy
- 'flymake-create-temp-inplace))
+(defun flymake-proc-perl-init ()
+ (let* ((temp-file (flymake-proc-init-create-temp-buffer-copy
+ 'flymake-proc-create-temp-inplace))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
(list "perl" (list "-wc " local-file))))
;;;; php-specific init-cleanup routines
-(defun flymake-php-init ()
- (let* ((temp-file (flymake-init-create-temp-buffer-copy
- 'flymake-create-temp-inplace))
+(defun flymake-proc-php-init ()
+ (let* ((temp-file (flymake-proc-init-create-temp-buffer-copy
+ 'flymake-proc-create-temp-inplace))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
(list "php" (list "-f" local-file "-l"))))
;;;; tex-specific init-cleanup routines
-(defun flymake-get-tex-args (file-name)
+(defun flymake-proc--get-tex-args (file-name)
;;(list "latex" (list "-c-style-errors" file-name))
(list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name)))
-(defun flymake-simple-tex-init ()
- (flymake-get-tex-args (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace)))
+(defun flymake-proc-simple-tex-init ()
+ (flymake-proc--get-tex-args (flymake-proc-init-create-temp-buffer-copy 'flymake-proc-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
+(defun flymake-proc-master-tex-init ()
+ (let* ((temp-master-file-name (flymake-proc--init-create-temp-source-and-master-buffer-copy
+ 'flymake-proc-get-include-dirs-dot 'flymake-proc-create-temp-inplace
'("\\.tex\\'")
"[ \t]*\\in\\(?:put\\|clude\\)[ \t]*{\\(.*%s\\)}")))
(when temp-master-file-name
- (flymake-get-tex-args temp-master-file-name))))
+ (flymake-proc--get-tex-args temp-master-file-name))))
-(defun flymake-get-include-dirs-dot (_base-dir)
+(defun flymake-proc--get-include-dirs-dot (_base-dir)
'("."))
;;;; xml-specific init-cleanup routines
-(defun flymake-xml-init ()
- (list flymake-xml-program
- (list "val" (flymake-init-create-temp-buffer-copy
- 'flymake-create-temp-inplace))))
+(defun flymake-proc-xml-init ()
+ (list flymake-proc-xml-program
+ (list "val" (flymake-proc-init-create-temp-buffer-copy
+ 'flymake-proc-create-temp-inplace))))
;;;; Hook onto flymake-ui
+(add-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake)
+
+
+;;;;
+
+(progn
+ (define-obsolete-variable-alias 'flymake-compilation-prevents-syntax-check
+ 'flymake-proc-compilation-prevents-syntax-check "26.1")
+ (define-obsolete-variable-alias 'flymake-xml-program
+ 'flymake-proc-xml-program "26.1")
+ (define-obsolete-variable-alias 'flymake-master-file-dirs
+ 'flymake-proc-master-file-dirs "26.1")
+ (define-obsolete-variable-alias 'flymake-master-file-count-limit
+ 'flymake-proc-master-file-count-limit "26.1"
+ "Max number of master files to check.")
+ (define-obsolete-variable-alias 'flymake-allowed-file-name-masks
+ 'flymake-proc-allowed-file-name-masks "26.1")
+ (define-obsolete-variable-alias 'flymake-check-file-limit
+ 'flymake-proc-check-file-limit "26.1")
+ (define-obsolete-function-alias 'flymake-reformat-err-line-patterns-from-compile-el
+ 'flymake-proc-reformat-err-line-patterns-from-compile-el "26.1")
+ (define-obsolete-variable-alias 'flymake-err-line-patterns
+ 'flymake-proc-err-line-patterns "26.1")
+ (define-obsolete-function-alias 'flymake-parse-line
+ 'flymake-proc-parse-line "26.1")
+ (define-obsolete-function-alias 'flymake-get-include-dirs
+ 'flymake-proc-get-include-dirs "26.1")
+ (define-obsolete-function-alias 'flymake-stop-all-syntax-checks
+ 'flymake-proc-stop-all-syntax-checks "26.1")
+ (define-obsolete-function-alias 'flymake-compile
+ 'flymake-proc-compile "26.1")
+ (define-obsolete-function-alias 'flymake-create-temp-inplace
+ 'flymake-proc-create-temp-inplace "26.1")
+ (define-obsolete-function-alias 'flymake-create-temp-with-folder-structure
+ 'flymake-proc-create-temp-with-folder-structure "26.1")
+ (define-obsolete-function-alias 'flymake-init-create-temp-buffer-copy
+ 'flymake-proc-init-create-temp-buffer-copy "26.1")
+ (define-obsolete-function-alias 'flymake-simple-cleanup
+ 'flymake-proc-simple-cleanup "26.1")
+ (define-obsolete-function-alias 'flymake-get-real-file-name
+ 'flymake-proc-get-real-file-name "26.1")
+ (define-obsolete-function-alias 'flymake-master-cleanup
+ 'flymake-proc-master-cleanup "26.1")
+ (define-obsolete-function-alias 'flymake-get-make-cmdline
+ 'flymake-proc-get-make-cmdline "26.1")
+ (define-obsolete-function-alias 'flymake-get-ant-cmdline
+ 'flymake-proc-get-ant-cmdline "26.1")
+ (define-obsolete-function-alias 'flymake-simple-make-init-impl
+ 'flymake-proc-simple-make-init-impl "26.1")
+ (define-obsolete-function-alias 'flymake-simple-make-init
+ 'flymake-proc-simple-make-init "26.1")
+ (define-obsolete-function-alias 'flymake-master-make-init
+ 'flymake-proc-master-make-init "26.1")
+ (define-obsolete-function-alias 'flymake-find-make-buildfile
+ 'flymake-proc--find-make-buildfile "26.1")
+ (define-obsolete-function-alias 'flymake-master-make-header-init
+ 'flymake-proc-master-make-header-init "26.1")
+ (define-obsolete-function-alias 'flymake-simple-make-java-init
+ 'flymake-proc-simple-make-java-init "26.1")
+ (define-obsolete-function-alias 'flymake-simple-ant-java-init
+ 'flymake-proc-simple-ant-java-init "26.1")
+ (define-obsolete-function-alias 'flymake-simple-java-cleanup
+ 'flymake-proc-simple-java-cleanup "26.1")
+ (define-obsolete-function-alias 'flymake-perl-init
+ 'flymake-proc-perl-init "26.1")
+ (define-obsolete-function-alias 'flymake-php-init
+ 'flymake-proc-php-init "26.1")
+ (define-obsolete-function-alias 'flymake-simple-tex-init
+ 'flymake-proc-simple-tex-init "26.1")
+ (define-obsolete-function-alias 'flymake-master-tex-init
+ 'flymake-proc-master-tex-init "26.1")
+ (define-obsolete-function-alias 'flymake-xml-init
+ 'flymake-proc-xml-init "26.1"))
+
-(add-to-list 'flymake-backends
- `(flymake-proc-can-syntax-check-buffer
- .
- flymake-proc-start-syntax-check))
(provide 'flymake-proc)
;;; flymake-proc.el ends here
diff --git a/lisp/progmodes/flymake-ui.el b/lisp/progmodes/flymake-ui.el
deleted file mode 100644
index bf5218c41d2..00000000000
--- a/lisp/progmodes/flymake-ui.el
+++ /dev/null
@@ -1,634 +0,0 @@
-;;; flymake-ui.el --- A universal on-the-fly syntax checker -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2003-2017 Free Software Foundation, Inc.
-
-;; Author: Pavel Kobyakov <pk_at_work@yahoo.com>
-;; Maintainer: Leo Liu <sdl.web@gmail.com>
-;; Version: 0.3
-;; Keywords: c languages tools
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; Flymake is a minor Emacs mode performing on-the-fly syntax checks.xo
-;;
-;; This file contains the UI for displaying and interacting with the
-;; results of such checks, as well as entry points for backends to
-;; hook on to. Backends are sources of diagnostic info.
-;;
-;;; Code:
-
-(eval-when-compile (require 'cl-lib))
-
-(defgroup flymake nil
- "Universal on-the-fly syntax checker."
- :version "23.1"
- :link '(custom-manual "(flymake) Top")
- :group 'tools)
-
-(defcustom flymake-error-bitmap '(exclamation-mark error)
- "Bitmap (a symbol) used in the fringe for indicating errors.
-The value may also be a list of two elements where the second
-element specifies the face for the bitmap. For possible bitmap
-symbols, see `fringe-bitmaps'. See also `flymake-warning-bitmap'.
-
-The option `flymake-fringe-indicator-position' controls how and where
-this is used."
- :group 'flymake
- :version "24.3"
- :type '(choice (symbol :tag "Bitmap")
- (list :tag "Bitmap and face"
- (symbol :tag "Bitmap")
- (face :tag "Face"))))
-
-(defcustom flymake-warning-bitmap 'question-mark
- "Bitmap (a symbol) used in the fringe for indicating warnings.
-The value may also be a list of two elements where the second
-element specifies the face for the bitmap. For possible bitmap
-symbols, see `fringe-bitmaps'. See also `flymake-error-bitmap'.
-
-The option `flymake-fringe-indicator-position' controls how and where
-this is used."
- :group 'flymake
- :version "24.3"
- :type '(choice (symbol :tag "Bitmap")
- (list :tag "Bitmap and face"
- (symbol :tag "Bitmap")
- (face :tag "Face"))))
-
-(defcustom flymake-fringe-indicator-position 'left-fringe
- "The position to put flymake fringe indicator.
-The value can be nil (do not use indicators), `left-fringe' or `right-fringe'.
-See `flymake-error-bitmap' and `flymake-warning-bitmap'."
- :group 'flymake
- :version "24.3"
- :type '(choice (const left-fringe)
- (const right-fringe)
- (const :tag "No fringe indicators" nil)))
-
-(defcustom flymake-start-syntax-check-on-newline t
- "Start syntax check if newline char was added/removed from the buffer."
- :group 'flymake
- :type 'boolean)
-
-(defcustom flymake-no-changes-timeout 0.5
- "Time to wait after last change before starting compilation."
- :group 'flymake
- :type 'number)
-
-(defcustom flymake-gui-warnings-enabled t
- "Enables/disables GUI warnings."
- :group 'flymake
- :type 'boolean)
-(make-obsolete-variable 'flymake-gui-warnings-enabled
- "it no longer has any effect." "26.1")
-
-(defcustom flymake-start-syntax-check-on-find-file t
- "Start syntax check on find file."
- :group 'flymake
- :type 'boolean)
-
-(defcustom flymake-log-level -1
- "Logging level, only messages with level lower or equal will be logged.
--1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG"
- :group 'flymake
- :type 'integer)
-
-(defcustom flymake-backends '()
- "Ordered list of backends providing syntax check information for a buffer.
-Value is an alist of conses (PREDICATE . CHECKER). Both PREDICATE
-and CHECKER are functions called with a single argument, the
-buffer in which `flymake-mode' was enabled. PREDICATE is expected
-to (quickly) return t or nil if the buffer can be syntax checked
-by CHECKER, which in can performs more morose operations,
-possibly asynchronously."
- :group 'flymake
- :type 'alist)
-
-(defvar-local flymake-timer nil
- "Timer for starting syntax check.")
-
-(defvar-local flymake-last-change-time nil
- "Time of last buffer change.")
-
-(defvar-local flymake-check-start-time nil
- "Time at which syntax check was started.")
-
-(defvar-local flymake-check-was-interrupted nil
- "Non-nil if syntax check was killed by `flymake-compile'.")
-
-(defvar-local flymake-err-info nil
- "Sorted list of line numbers and lists of err info in the form (file, err-text).")
-
-(defvar-local flymake-new-err-info nil
- "Same as `flymake-err-info', effective when a syntax check is in progress.")
-
-(defun flymake-log (level text &rest args)
- "Log a message at level LEVEL.
-If LEVEL is higher than `flymake-log-level', the message is
-ignored. Otherwise, it is printed using `message'.
-TEXT is a format control string, and the remaining arguments ARGS
-are the string substitutions (see the function `format')."
- (if (<= level flymake-log-level)
- (let* ((msg (apply #'format-message text args)))
- (message "%s" msg))))
-
-(defun flymake-ins-after (list pos val)
- "Insert VAL into LIST after position POS.
-POS counts from zero."
- (let ((tmp (copy-sequence list)))
- (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp)))
- tmp))
-
-(defun flymake-set-at (list pos val)
- "Set VAL at position POS in LIST.
-POS counts from zero."
- (let ((tmp (copy-sequence list)))
- (setcar (nthcdr pos tmp) val)
- tmp))
-
-(defun flymake-er-make-er (line-no line-err-info-list)
- (list line-no line-err-info-list))
-
-(defun flymake-er-get-line (err-info)
- (nth 0 err-info))
-
-(defun flymake-er-get-line-err-info-list (err-info)
- (nth 1 err-info))
-
-(cl-defstruct (flymake-ler
- (:constructor nil)
- (:constructor flymake-ler-make-ler (file line type text &optional full-file)))
- file line type text full-file)
-
-(defun flymake-ler-set-file (line-err-info file)
- (flymake-ler-make-ler file
- (flymake-ler-line line-err-info)
- (flymake-ler-type line-err-info)
- (flymake-ler-text line-err-info)
- (flymake-ler-full-file line-err-info)))
-
-(defun flymake-ler-set-full-file (line-err-info full-file)
- (flymake-ler-make-ler (flymake-ler-file line-err-info)
- (flymake-ler-line line-err-info)
- (flymake-ler-type line-err-info)
- (flymake-ler-text line-err-info)
- full-file))
-
-(defun flymake-ler-set-line (line-err-info line)
- (flymake-ler-make-ler (flymake-ler-file line-err-info)
- line
- (flymake-ler-type line-err-info)
- (flymake-ler-text line-err-info)
- (flymake-ler-full-file line-err-info)))
-
-(defun flymake-get-line-err-count (line-err-info-list type)
- "Return number of errors of specified TYPE.
-Value of TYPE is either \"e\" or \"w\"."
- (let* ((idx 0)
- (count (length line-err-info-list))
- (err-count 0))
-
- (while (< idx count)
- (when (equal type (flymake-ler-type (nth idx line-err-info-list)))
- (setq err-count (1+ err-count)))
- (setq idx (1+ idx)))
- err-count))
-
-(defun flymake-get-err-count (err-info-list type)
- "Return number of errors of specified TYPE for ERR-INFO-LIST."
- (let* ((idx 0)
- (count (length err-info-list))
- (err-count 0))
- (while (< idx count)
- (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type)))
- (setq idx (1+ idx)))
- err-count))
-
-(defun flymake-highlight-err-lines (err-info-list)
- "Highlight error lines in BUFFER using info from ERR-INFO-LIST."
- (save-excursion
- (dolist (err err-info-list)
- (flymake-highlight-line (car err) (nth 1 err)))))
-
-(defun flymake-overlay-p (ov)
- "Determine whether overlay OV was created by flymake."
- (and (overlayp ov) (overlay-get ov 'flymake-overlay)))
-
-(defun flymake-make-overlay (beg end tooltip-text face bitmap)
- "Allocate a flymake overlay in range BEG and END."
- (when (not (flymake-region-has-flymake-overlays beg end))
- (let ((ov (make-overlay beg end nil t))
- (fringe (and flymake-fringe-indicator-position
- (propertize "!" 'display
- (cons flymake-fringe-indicator-position
- (if (listp bitmap)
- bitmap
- (list bitmap)))))))
- (overlay-put ov 'face face)
- (overlay-put ov 'help-echo tooltip-text)
- (overlay-put ov 'flymake-overlay t)
- (overlay-put ov 'priority 100)
- (overlay-put ov 'evaporate t)
- (overlay-put ov 'before-string fringe)
- ;;+(flymake-log 3 "created overlay %s" ov)
- ov)
- (flymake-log 3 "created an overlay at (%d-%d)" beg end)))
-
-(defun flymake-delete-own-overlays ()
- "Delete all flymake overlays in BUFFER."
- (dolist (ol (overlays-in (point-min) (point-max)))
- (when (flymake-overlay-p ol)
- (delete-overlay ol)
- ;;+(flymake-log 3 "deleted overlay %s" ol)
- )))
-
-(defun flymake-region-has-flymake-overlays (beg end)
- "Check if region specified by BEG and END has overlay.
-Return t if it has at least one flymake overlay, nil if no overlay."
- (let ((ov (overlays-in beg end))
- (has-flymake-overlays nil))
- (while (consp ov)
- (when (flymake-overlay-p (car ov))
- (setq has-flymake-overlays t))
- (setq ov (cdr ov)))
- has-flymake-overlays))
-
-(defface flymake-errline
- '((((supports :underline (:style wave)))
- :underline (:style wave :color "Red1"))
- (t
- :inherit error))
- "Face used for marking error lines."
- :version "24.4"
- :group 'flymake)
-
-(defface flymake-warnline
- '((((supports :underline (:style wave)))
- :underline (:style wave :color "DarkOrange"))
- (t
- :inherit warning))
- "Face used for marking warning lines."
- :version "24.4"
- :group 'flymake)
-
-(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-char (point-min))
- (forward-line (1- line-no))
- (pcase-let* ((beg (progn (back-to-indentation) (point)))
- (end (progn
- (end-of-line)
- (skip-chars-backward " \t\f\t\n" beg)
- (if (eq (point) beg)
- (line-beginning-position 2)
- (point))))
- (tooltip-text (mapconcat #'flymake-ler-text line-err-info-list "\n"))
- (`(,face ,bitmap)
- (if (> (flymake-get-line-err-count line-err-info-list "e") 0)
- (list 'flymake-errline flymake-error-bitmap)
- (list 'flymake-warnline flymake-warning-bitmap))))
- (flymake-make-overlay beg end tooltip-text face bitmap)))
-
-(defun flymake-find-err-info (err-info-list line-no)
- "Find (line-err-info-list pos) for specified LINE-NO."
- (if err-info-list
- (let* ((line-err-info-list nil)
- (pos 0)
- (count (length err-info-list)))
-
- (while (and (< pos count) (< (car (nth pos err-info-list)) line-no))
- (setq pos (1+ pos)))
- (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no))
- (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list))))
- (list line-err-info-list pos))
- '(nil 0)))
-
-(defun flymake-line-err-info-is-less-or-equal (line-one line-two)
- (or (string< (flymake-ler-type line-one) (flymake-ler-type line-two))
- (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
- (not (flymake-ler-file line-one)) (flymake-ler-file line-two))
- (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
- (or (and (flymake-ler-file line-one) (flymake-ler-file line-two))
- (and (not (flymake-ler-file line-one)) (not (flymake-ler-file line-two)))))))
-
-(defun flymake-add-line-err-info (line-err-info-list line-err-info)
- "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO.
-For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'.
-The new element is inserted in the proper position, according to
-the predicate `flymake-line-err-info-is-less-or-equal'.
-The updated value of LINE-ERR-INFO-LIST is returned."
- (if (not line-err-info-list)
- (list line-err-info)
- (let* ((count (length line-err-info-list))
- (idx 0))
- (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info))
- (setq idx (1+ idx)))
- (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list)))
- (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info))))
- line-err-info-list)))
-
-(defun flymake-add-err-info (err-info-list line-err-info)
- "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order.
-Returns the updated value of ERR-INFO-LIST.
-For the format of ERR-INFO-LIST, see `flymake-err-info'.
-For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'."
- (let* ((line-no (if (flymake-ler-file line-err-info) 1 (flymake-ler-line line-err-info)))
- (info-and-pos (flymake-find-err-info err-info-list line-no))
- (exists (car info-and-pos))
- (pos (nth 1 info-and-pos))
- (line-err-info-list nil)
- (err-info nil))
-
- (if exists
- (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list)))))
- (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info))
-
- (setq err-info (flymake-er-make-er line-no line-err-info-list))
- (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info)))
- ((equal 0 pos) (setq err-info-list (cons err-info err-info-list)))
- (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info))))
- err-info-list))
-
-(defvar-local flymake-is-running nil
- "If t, flymake syntax check process is running for the current buffer.")
-
-(defun flymake-on-timer-event (buffer)
- "Start a syntax check for buffer BUFFER if necessary."
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (when (and (not flymake-is-running)
- flymake-last-change-time
- (> (- (float-time) flymake-last-change-time)
- flymake-no-changes-timeout))
-
- (setq flymake-last-change-time nil)
- (flymake-log 3 "starting syntax check as more than 1 second passed since last change")
- (flymake--start-syntax-check)))))
-
-(define-obsolete-function-alias 'flymake-display-err-menu-for-current-line
- 'flymake-popup-current-error-menu "24.4")
-
-(defun flymake-popup-current-error-menu (&optional event)
- "Pop up a menu with errors/warnings for current line."
- (interactive (list last-nonmenu-event))
- (let* ((line-no (line-number-at-pos))
- (errors (or (car (flymake-find-err-info flymake-err-info line-no))
- (user-error "No errors for current line")))
- (menu (mapcar (lambda (x)
- (if (flymake-ler-file x)
- (cons (format "%s - %s(%d)"
- (flymake-ler-text x)
- (flymake-ler-file x)
- (flymake-ler-line x))
- x)
- (list (flymake-ler-text x))))
- errors))
- (event (if (mouse-event-p event)
- event
- (list 'mouse-1 (posn-at-point))))
- (title (format "Line %d: %d error(s), %d warning(s)"
- line-no
- (flymake-get-line-err-count errors "e")
- (flymake-get-line-err-count errors "w")))
- (choice (x-popup-menu event (list title (cons "" menu)))))
- (flymake-log 3 "choice=%s" choice)
- (when choice
- (flymake-goto-file-and-line (flymake-ler-full-file choice)
- (flymake-ler-line choice)))))
-
-(defun flymake-goto-file-and-line (file line)
- "Try to get buffer for FILE and goto line LINE in it."
- (if (not (file-exists-p file))
- (flymake-log 1 "File %s does not exist" file)
- (find-file file)
- (goto-char (point-min))
- (forward-line (1- line))))
-
-;; flymake minor mode declarations
-(defvar-local flymake-mode-line nil)
-(defvar-local flymake-mode-line-e-w nil)
-(defvar-local flymake-mode-line-status nil)
-
-(defun flymake-report-status (e-w &optional status)
- "Show status in mode line."
- (when e-w
- (setq flymake-mode-line-e-w e-w))
- (when status
- (setq flymake-mode-line-status status))
- (let* ((mode-line " Flymake"))
- (when (> (length flymake-mode-line-e-w) 0)
- (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
- (setq mode-line (concat mode-line flymake-mode-line-status))
- (setq flymake-mode-line mode-line)
- (force-mode-line-update)))
-
-;; Nothing in flymake uses this at all any more, so this is just for
-;; third-party compatibility.
-(define-obsolete-function-alias 'flymake-display-warning 'message-box "26.1")
-
-(defun flymake-report-fatal-status (status warning)
- "Display a warning and switch flymake mode off."
- ;; This first message was always shown by default, and flymake-log
- ;; does nothing by default, hence the use of message.
- ;; Another option is display-warning.
- (if (< flymake-log-level 0)
- (message "Flymake: %s. Flymake will be switched OFF" warning))
- (flymake-mode 0)
- (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s"
- (buffer-name) status warning))
-
-(defvar-local flymake--backend nil
- "The currently active backend selected by `flymake-mode'")
-
-(defun flymake--can-syntax-check-buffer (buffer)
- (let ((all flymake-backends)
- (candidate))
- (catch 'done
- (while (setq candidate (pop all))
- (when (with-current-buffer buffer (funcall (car candidate)))
- (throw 'done (cdr candidate)))))))
-
-(defun flymake--start-syntax-check ()
- (funcall flymake--backend))
-
-;;;###autoload
-(define-minor-mode flymake-mode nil
- :group 'flymake :lighter flymake-mode-line
- (cond
-
- ;; Turning the mode ON.
- (flymake-mode
- (let* ((backend (flymake--can-syntax-check-buffer (current-buffer))))
- (cond
- ((not backend)
- (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name)))
- (t
- (setq flymake--backend backend)
-
- (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)
- ;;+(add-hook 'find-file-hook 'flymake-find-file-hook)
-
- (flymake-report-status "" "")
-
- (setq flymake-timer
- (run-at-time nil 1 'flymake-on-timer-event (current-buffer)))
-
- (when (and flymake-start-syntax-check-on-find-file
- ;; Since we write temp files in current dir, there's no point
- ;; trying if the directory is read-only (bug#8954).
- (file-writable-p (file-name-directory buffer-file-name)))
- (with-demoted-errors
- (flymake--start-syntax-check)))))
- )
- )
-
- ;; Turning the mode OFF.
- (t
- (setq flymake--backend nil)
-
- (remove-hook 'after-change-functions 'flymake-after-change-function t)
- (remove-hook 'after-save-hook 'flymake-after-save-hook t)
- (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t)
- ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t)
-
- (flymake-delete-own-overlays)
-
- (when flymake-timer
- (cancel-timer flymake-timer)
- (setq flymake-timer nil))
-
- (setq flymake-is-running nil))))
-
-;; disabling flymake-mode is safe, enabling - not necessarily so
-(put 'flymake-mode 'safe-local-variable 'null)
-
-;;;###autoload
-(defun flymake-mode-on ()
- "Turn flymake mode on."
- (flymake-mode 1)
- (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name)))
-
-;;;###autoload
-(defun flymake-mode-off ()
- "Turn flymake mode off."
- (flymake-mode 0)
- (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name)))
-
-(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" (float-time))
- (let((new-text (buffer-substring start stop)))
- (when (and flymake-start-syntax-check-on-newline (equal new-text "\n"))
- (flymake-log 3 "starting syntax check as new-line has been seen")
- (flymake--start-syntax-check))
- (setq flymake-last-change-time (float-time))))
-
-(defun flymake-after-save-hook ()
- (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved?
- (progn
- (flymake-log 3 "starting syntax check as buffer was saved")
- (flymake--start-syntax-check)))) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???)
-
-(defun flymake-kill-buffer-hook ()
- (when flymake-timer
- (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")
- ;;+ (flymake--start-syntax-check)
- ;;+)
- (when (and (not (local-variable-p 'flymake-mode (current-buffer)))
- (flymake--can-syntax-check-buffer (current-buffer)))
- (flymake-mode)
- (flymake-log 3 "automatically turned ON flymake mode")))
-
-(defun flymake-get-first-err-line-no (err-info-list)
- "Return first line with error."
- (when err-info-list
- (flymake-er-get-line (car err-info-list))))
-
-(defun flymake-get-last-err-line-no (err-info-list)
- "Return last line with error."
- (when err-info-list
- (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list))))
-
-(defun flymake-get-next-err-line-no (err-info-list line-no)
- "Return next line with error."
- (when err-info-list
- (let* ((count (length err-info-list))
- (idx 0))
- (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list))))
- (setq idx (1+ idx)))
- (if (< idx count)
- (flymake-er-get-line (nth idx err-info-list))))))
-
-(defun flymake-get-prev-err-line-no (err-info-list line-no)
- "Return previous line with error."
- (when err-info-list
- (let* ((count (length err-info-list)))
- (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list))))
- (setq count (1- count)))
- (if (> count 0)
- (flymake-er-get-line (nth (1- count) err-info-list))))))
-
-(defun flymake-skip-whitespace ()
- "Move forward until non-whitespace is reached."
- (while (looking-at "[ \t]")
- (forward-char)))
-
-(defun flymake-goto-line (line-no)
- "Go to line LINE-NO, then skip whitespace."
- (goto-char (point-min))
- (forward-line (1- line-no))
- (flymake-skip-whitespace))
-
-(defun flymake-goto-next-error ()
- "Go to next error in err ring."
- (interactive)
- (let ((line-no (flymake-get-next-err-line-no flymake-err-info (line-number-at-pos))))
- (when (not line-no)
- (setq line-no (flymake-get-first-err-line-no flymake-err-info))
- (flymake-log 1 "passed end of file"))
- (if line-no
- (flymake-goto-line line-no)
- (flymake-log 1 "no errors in current buffer"))))
-
-(defun flymake-goto-prev-error ()
- "Go to previous error in err ring."
- (interactive)
- (let ((line-no (flymake-get-prev-err-line-no flymake-err-info (line-number-at-pos))))
- (when (not line-no)
- (setq line-no (flymake-get-last-err-line-no flymake-err-info))
- (flymake-log 1 "passed beginning of file"))
- (if line-no
- (flymake-goto-line line-no)
- (flymake-log 1 "no errors in current buffer"))))
-
-(defun flymake-patch-err-text (string)
- (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string)
- (match-string 1 string)
- string))
-
-(provide 'flymake-ui)
-;;; flymake-ui.el ends here
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 059bce95eed..45f0adfeba1 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -1,4 +1,4 @@
-;;; flymake.el --- a universal on-the-fly syntax checker -*- lexical-binding: t; -*-
+;;; flymake.el --- A universal on-the-fly syntax checker -*- lexical-binding: t; -*-
;; Copyright (C) 2003-2017 Free Software Foundation, Inc.
@@ -20,22 +20,964 @@
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Flymake is a minor Emacs mode performing on-the-fly syntax checks.
;;
-;; It collects diagnostic information for multiple sources and
-;; visually annotates the relevant lines in the buffer.
+;; Flymake collects diagnostic information for multiple sources,
+;; called backends, and visually annotates the relevant portions in
+;; the buffer.
+;;
+;; This file contains the UI for displaying and interacting with the
+;; results produced by these backends, as well as entry points for
+;; backends to hook on to.
+;;
+;; The main entry points are `flymake-mode' and `flymake-start'
+;;
+;; The docstrings of these variables are relevant to understanding how
+;; Flymake works for both the user and the backend programmer:
+;;
+;; * `flymake-diagnostic-functions'
+;; * `flymake-diagnostic-types-alist'
;;
-;; This file is just a stub for that loads the UI and backends, which
-;; could also be loaded separately.
-
;;; Code:
-(require 'flymake-ui)
-(require 'flymake-proc)
+(require 'cl-lib)
+(require 'thingatpt) ; end-of-thing
+(require 'warnings) ; warning-numeric-level, display-warning
+(require 'compile) ; for some faces
+(require 'subr-x) ; when-let*, if-let*, hash-table-keys, hash-table-values
+
+(defgroup flymake nil
+ "Universal on-the-fly syntax checker."
+ :version "23.1"
+ :link '(custom-manual "(flymake) Top")
+ :group 'tools)
+
+(defcustom flymake-error-bitmap '(flymake-double-exclamation-mark
+ compilation-error)
+ "Bitmap (a symbol) used in the fringe for indicating errors.
+The value may also be a list of two elements where the second
+element specifies the face for the bitmap. For possible bitmap
+symbols, see `fringe-bitmaps'. See also `flymake-warning-bitmap'.
+
+The option `flymake-fringe-indicator-position' controls how and where
+this is used."
+ :version "24.3"
+ :type '(choice (symbol :tag "Bitmap")
+ (list :tag "Bitmap and face"
+ (symbol :tag "Bitmap")
+ (face :tag "Face"))))
+
+(defcustom flymake-warning-bitmap '(exclamation-mark compilation-warning)
+ "Bitmap (a symbol) used in the fringe for indicating warnings.
+The value may also be a list of two elements where the second
+element specifies the face for the bitmap. For possible bitmap
+symbols, see `fringe-bitmaps'. See also `flymake-error-bitmap'.
+
+The option `flymake-fringe-indicator-position' controls how and where
+this is used."
+ :version "24.3"
+ :type '(choice (symbol :tag "Bitmap")
+ (list :tag "Bitmap and face"
+ (symbol :tag "Bitmap")
+ (face :tag "Face"))))
+
+(defcustom flymake-note-bitmap '(exclamation-mark compilation-info)
+ "Bitmap (a symbol) used in the fringe for indicating info notes.
+The value may also be a list of two elements where the second
+element specifies the face for the bitmap. For possible bitmap
+symbols, see `fringe-bitmaps'. See also `flymake-error-bitmap'.
+
+The option `flymake-fringe-indicator-position' controls how and where
+this is used."
+ :version "26.1"
+ :type '(choice (symbol :tag "Bitmap")
+ (list :tag "Bitmap and face"
+ (symbol :tag "Bitmap")
+ (face :tag "Face"))))
+
+(defcustom flymake-fringe-indicator-position 'left-fringe
+ "The position to put Flymake fringe indicator.
+The value can be nil (do not use indicators), `left-fringe' or `right-fringe'.
+See `flymake-error-bitmap' and `flymake-warning-bitmap'."
+ :version "24.3"
+ :type '(choice (const left-fringe)
+ (const right-fringe)
+ (const :tag "No fringe indicators" nil)))
+
+(defcustom flymake-start-syntax-check-on-newline t
+ "Start syntax check if newline char was added/removed from the buffer."
+ :type 'boolean)
+
+(defcustom flymake-no-changes-timeout 0.5
+ "Time to wait after last change before automatically checking buffer.
+If nil, never start checking buffer automatically like this."
+ :type 'number)
+
+(defcustom flymake-gui-warnings-enabled t
+ "Enables/disables GUI warnings."
+ :type 'boolean)
+(make-obsolete-variable 'flymake-gui-warnings-enabled
+ "it no longer has any effect." "26.1")
+
+(defcustom flymake-start-syntax-check-on-find-file t
+ "Start syntax check on find file."
+ :type 'boolean)
+
+(defcustom flymake-log-level -1
+ "Obsolete and ignored variable."
+ :type 'integer)
+(make-obsolete-variable 'flymake-log-level
+ "it is superseded by `warning-minimum-log-level.'"
+ "26.1")
+
+(defcustom flymake-wrap-around t
+ "If non-nil, moving to errors wraps around buffer boundaries."
+ :type 'boolean)
+
+(define-fringe-bitmap 'flymake-double-exclamation-mark
+ (vector #b00000000
+ #b00000000
+ #b00000000
+ #b00000000
+ #b01100110
+ #b01100110
+ #b01100110
+ #b01100110
+ #b01100110
+ #b01100110
+ #b01100110
+ #b01100110
+ #b00000000
+ #b01100110
+ #b00000000
+ #b00000000
+ #b00000000))
+
+(defvar-local flymake-timer nil
+ "Timer for starting syntax check.")
+
+(defvar-local flymake-check-start-time nil
+ "Time at which syntax check was started.")
+
+(defun flymake--log-1 (level sublog msg &rest args)
+ "Do actual work for `flymake-log'."
+ (let (;; never popup the log buffer
+ (warning-minimum-level :emergency)
+ (warning-type-format
+ (format " [%s %s]"
+ (or sublog 'flymake)
+ (current-buffer))))
+ (display-warning (list 'flymake sublog)
+ (apply #'format-message msg args)
+ (if (numberp level)
+ (or (nth level
+ '(:emergency :error :warning :debug :debug) )
+ :error)
+ level)
+ "*Flymake log*")))
+
+(defun flymake-switch-to-log-buffer ()
+ "Go to the *Flymake log* buffer."
+ (interactive)
+ (switch-to-buffer "*Flymake log*"))
+
+;;;###autoload
+(defmacro flymake-log (level msg &rest args)
+ "Log, at level LEVEL, the message MSG formatted with ARGS.
+LEVEL is passed to `display-warning', which is used to display
+the warning. If this form is included in a byte-compiled file,
+the generated warning contains an indication of the file that
+generated it."
+ (let* ((compile-file (and (boundp 'byte-compile-current-file)
+ (symbol-value 'byte-compile-current-file)))
+ (sublog (if (and
+ compile-file
+ (not load-file-name))
+ (intern
+ (file-name-nondirectory
+ (file-name-sans-extension compile-file))))))
+ `(flymake--log-1 ,level ',sublog ,msg ,@args)))
+
+(defun flymake-error (text &rest args)
+ "Format TEXT with ARGS and signal an error for Flymake."
+ (let ((msg (apply #'format-message text args)))
+ (flymake-log :error msg)
+ (error (concat "[Flymake] " msg))))
+
+(cl-defstruct (flymake--diag
+ (:constructor flymake--diag-make))
+ buffer beg end type text backend)
+
+;;;###autoload
+(defun flymake-make-diagnostic (buffer
+ beg
+ end
+ type
+ text)
+ "Make a Flymake diagnostic for BUFFER's region from BEG to END.
+TYPE is a key to `flymake-diagnostic-types-alist' and TEXT is a
+description of the problem detected in this region."
+ (flymake--diag-make :buffer buffer :beg beg :end end :type type :text text))
+
+(cl-defun flymake--overlays (&key beg end filter compare key)
+ "Get flymake-related overlays.
+If BEG is non-nil and END is nil, consider only `overlays-at'
+BEG. Otherwise consider `overlays-in' the region comprised by BEG
+and END, defaulting to the whole buffer. Remove all that do not
+verify FILTER, a function, and sort them by COMPARE (using KEY)."
+ (save-restriction
+ (widen)
+ (let ((ovs (cl-remove-if-not
+ (lambda (ov)
+ (and (overlay-get ov 'flymake)
+ (or (not filter)
+ (funcall filter ov))))
+ (if (and beg (null end))
+ (overlays-at beg t)
+ (overlays-in (or beg (point-min))
+ (or end (point-max)))))))
+ (if compare
+ (cl-sort ovs compare :key (or key
+ #'identity))
+ ovs))))
+
+(defun flymake-delete-own-overlays (&optional filter)
+ "Delete all Flymake overlays in BUFFER."
+ (mapc #'delete-overlay (flymake--overlays :filter filter)))
+
+(defface flymake-error
+ '((((supports :underline (:style wave)))
+ :underline (:style wave :color "Red1"))
+ (t
+ :inherit error))
+ "Face used for marking error regions."
+ :version "24.4")
+
+(defface flymake-warning
+ '((((supports :underline (:style wave)))
+ :underline (:style wave :color "deep sky blue"))
+ (t
+ :inherit warning))
+ "Face used for marking warning regions."
+ :version "24.4")
+
+(defface flymake-note
+ '((((supports :underline (:style wave)))
+ :underline (:style wave :color "yellow green"))
+ (t
+ :inherit warning))
+ "Face used for marking note regions."
+ :version "26.1")
+
+(define-obsolete-face-alias 'flymake-warnline 'flymake-warning "26.1")
+(define-obsolete-face-alias 'flymake-errline 'flymake-error "26.1")
+
+;;;###autoload
+(defun flymake-diag-region (buffer line &optional col)
+ "Compute BUFFER's region (BEG . END) corresponding to LINE and COL.
+If COL is nil, return a region just for LINE. Return nil if the
+region is invalid."
+ (condition-case-unless-debug _err
+ (with-current-buffer buffer
+ (let ((line (min (max line 1)
+ (line-number-at-pos (point-max) 'absolute))))
+ (save-excursion
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (cl-flet ((fallback-bol
+ () (progn (back-to-indentation) (point)))
+ (fallback-eol
+ (beg)
+ (progn
+ (end-of-line)
+ (skip-chars-backward " \t\f\t\n" beg)
+ (if (eq (point) beg)
+ (line-beginning-position 2)
+ (point)))))
+ (if (and col (cl-plusp col))
+ (let* ((beg (progn (forward-char (1- col))
+ (point)))
+ (sexp-end (ignore-errors (end-of-thing 'sexp)))
+ (end (or (and sexp-end
+ (not (= sexp-end beg))
+ sexp-end)
+ (ignore-errors (goto-char (1+ beg)))))
+ (safe-end (or end
+ (fallback-eol beg))))
+ (cons (if end beg (fallback-bol))
+ safe-end))
+ (let* ((beg (fallback-bol))
+ (end (fallback-eol beg)))
+ (cons beg end)))))))
+ (error (flymake-error "Invalid region line=%s col=%s" line col))))
+
+(defvar flymake-diagnostic-functions nil
+ "Special hook of Flymake backends that check a buffer.
+
+The functions in this hook diagnose problems in a buffer’s
+contents and provide information to the Flymake user interface
+about where and how to annotate problems diagnosed in a buffer.
+
+Whenever Flymake or the user decides to re-check the buffer, each
+function is called with an arbitrary number of arguments:
+
+* the first argument is always REPORT-FN, a callback function
+ detailed below;
+
+* the remaining arguments are keyword-value pairs in the
+ form (:KEY VALUE :KEY2 VALUE2...). Currently, Flymake provides
+ no such arguments, but backend functions must be prepared to
+ accept and possibly ignore any number of them.
+
+Backend functions are expected to initiate the buffer check, but
+aren't required to complete it check before exiting: if the
+computation involved is expensive, especially for large buffers,
+that task can be scheduled for the future using asynchronous
+processes or other asynchronous mechanisms.
+
+In any case, backend functions are expected to return quickly or
+signal an error, in which case the backend is disabled. Flymake
+will not try disabled backends again for any future checks of
+this buffer. Certain commands, like turning `flymake-mode' off
+and on again, reset the list of disabled backends.
+
+If the function returns, Flymake considers the backend to be
+\"running\". If it has not done so already, the backend is
+expected to call the function REPORT-FN with a single argument
+REPORT-ACTION also followed by an optional list of keyword-value
+pairs in the form (:REPORT-KEY VALUE :REPORT-KEY2 VALUE2...).
+
+Currently accepted values for REPORT-ACTION are:
+
+* A (possibly empty) list of diagnostic objects created with
+ `flymake-make-diagnostic', causing Flymake to annotate the
+ buffer with this information.
+
+ A backend may call REPORT-FN repeatedly in this manner, but
+ only until Flymake considers that the most recently requested
+ buffer check is now obsolete because, say, buffer contents have
+ changed in the meantime. The backend is only given notice of
+ this via a renewed call to the backend function. Thus, to
+ prevent making obsolete reports and wasting resources, backend
+ functions should first cancel any ongoing processing from
+ previous calls.
+
+* The symbol `:panic', signaling that the backend has encountered
+ an exceptional situation and should be disabled.
+
+Currently accepted REPORT-KEY arguments are:
+
+* ‘:explanation’: value should give user-readable details of
+ the situation encountered, if any.
+
+* ‘:force’: value should be a boolean suggesting that Flymake
+ consider the report even if it was somehow unexpected.")
+
+(defvar flymake-diagnostic-types-alist
+ `((:error
+ . ((flymake-category . flymake-error)))
+ (:warning
+ . ((flymake-category . flymake-warning)))
+ (:note
+ . ((flymake-category . flymake-note))))
+ "Alist ((KEY . PROPS)*) of properties of Flymake diagnostic types.
+KEY designates a kind of diagnostic can be anything passed as
+`:type' to `flymake-make-diagnostic'.
+
+PROPS is an alist of properties that are applied, in order, to
+the diagnostics of the type designated by KEY. The recognized
+properties are:
+
+* Every property pertaining to overlays, except `category' and
+ `evaporate' (see Info Node `(elisp)Overlay Properties'), used
+ to affect the appearance of Flymake annotations.
+
+* `bitmap', an image displayed in the fringe according to
+ `flymake-fringe-indicator-position'. The value actually
+ follows the syntax of `flymake-error-bitmap' (which see). It
+ is overridden by any `before-string' overlay property.
+
+* `severity', a non-negative integer specifying the diagnostic's
+ severity. The higher, the more serious. If the overlay
+ priority `priority' is not specified, `severity' is used to set
+ it and help sort overlapping overlays.
+
+* `flymake-category', a symbol whose property list is considered
+ as a default for missing values of any other properties. This
+ is useful to backend authors when creating new diagnostic types
+ that differ from an existing type by only a few properties.")
+
+(put 'flymake-error 'face 'flymake-error)
+(put 'flymake-error 'bitmap 'flymake-error-bitmap)
+(put 'flymake-error 'severity (warning-numeric-level :error))
+(put 'flymake-error 'mode-line-face 'compilation-error)
+
+(put 'flymake-warning 'face 'flymake-warning)
+(put 'flymake-warning 'bitmap 'flymake-warning-bitmap)
+(put 'flymake-warning 'severity (warning-numeric-level :warning))
+(put 'flymake-warning 'mode-line-face 'compilation-warning)
+
+(put 'flymake-note 'face 'flymake-note)
+(put 'flymake-note 'bitmap 'flymake-note-bitmap)
+(put 'flymake-note 'severity (warning-numeric-level :debug))
+(put 'flymake-note 'mode-line-face 'compilation-info)
+
+(defun flymake--lookup-type-property (type prop &optional default)
+ "Look up PROP for TYPE in `flymake-diagnostic-types-alist'.
+If TYPE doesn't declare PROP in either
+`flymake-diagnostic-types-alist' or in the symbol of its
+associated `flymake-category' return DEFAULT."
+ (let ((alist-probe (assoc type flymake-diagnostic-types-alist)))
+ (cond (alist-probe
+ (let* ((alist (cdr alist-probe))
+ (prop-probe (assoc prop alist)))
+ (if prop-probe
+ (cdr prop-probe)
+ (if-let* ((cat (assoc-default 'flymake-category alist))
+ (plist (and (symbolp cat)
+ (symbol-plist cat)))
+ (cat-probe (plist-member plist prop)))
+ (cadr cat-probe)
+ default))))
+ (t
+ default))))
+
+(defun flymake--fringe-overlay-spec (bitmap &optional recursed)
+ (if (and (symbolp bitmap)
+ (boundp bitmap)
+ (not recursed))
+ (flymake--fringe-overlay-spec
+ (symbol-value bitmap) t)
+ (and flymake-fringe-indicator-position
+ bitmap
+ (propertize "!" 'display
+ (cons flymake-fringe-indicator-position
+ (if (listp bitmap)
+ bitmap
+ (list bitmap)))))))
+
+(defun flymake--highlight-line (diagnostic)
+ "Highlight buffer with info in DIAGNOSTIC."
+ (when-let* ((ov (make-overlay
+ (flymake--diag-beg diagnostic)
+ (flymake--diag-end diagnostic))))
+ ;; First set `category' in the overlay, then copy over every other
+ ;; property.
+ ;;
+ (let ((alist (assoc-default (flymake--diag-type diagnostic)
+ flymake-diagnostic-types-alist)))
+ (overlay-put ov 'category (assoc-default 'flymake-category alist))
+ (cl-loop for (k . v) in alist
+ unless (eq k 'category)
+ do (overlay-put ov k v)))
+ ;; Now ensure some essential defaults are set
+ ;;
+ (cl-flet ((default-maybe
+ (prop value)
+ (unless (or (plist-member (overlay-properties ov) prop)
+ (let ((cat (overlay-get ov
+ 'flymake-category)))
+ (and cat
+ (plist-member (symbol-plist cat) prop))))
+ (overlay-put ov prop value))))
+ (default-maybe 'bitmap 'flymake-error-bitmap)
+ (default-maybe 'face 'flymake-error)
+ (default-maybe 'before-string
+ (flymake--fringe-overlay-spec
+ (overlay-get ov 'bitmap)))
+ (default-maybe 'help-echo
+ (lambda (_window _ov pos)
+ (mapconcat
+ (lambda (ov)
+ (let ((diag (overlay-get ov 'flymake--diagnostic)))
+ (flymake--diag-text diag)))
+ (flymake--overlays :beg pos)
+ "\n")))
+ (default-maybe 'severity (warning-numeric-level :error))
+ (default-maybe 'priority (+ 100 (overlay-get ov 'severity))))
+ ;; Some properties can't be overridden.
+ ;;
+ (overlay-put ov 'evaporate t)
+ (overlay-put ov 'flymake t)
+ (overlay-put ov 'flymake--diagnostic diagnostic)))
+
+;; Nothing in Flymake uses this at all any more, so this is just for
+;; third-party compatibility.
+(define-obsolete-function-alias 'flymake-display-warning 'message-box "26.1")
+
+(defvar-local flymake--backend-state nil
+ "Buffer-local hash table of a Flymake backend's state.
+The keys to this hash table are functions as found in
+`flymake-diagnostic-functions'. The values are structures
+of the type `flymake--backend-state', with these slots:
+
+`running', a symbol to keep track of a backend's replies via its
+REPORT-FN argument. A backend is running if this key is
+present. If nil, Flymake isn't expecting any replies from the
+backend.
+
+`diags', a (possibly empty) list of recent diagnostic objects
+created by the backend with `flymake-make-diagnostic'.
+
+`reported-p', a boolean indicating if the backend has replied
+since it last was contacted.
+
+`disabled', a string with the explanation for a previous
+exceptional situation reported by the backend, nil if the
+backend is operating normally.")
+
+(cl-defstruct (flymake--backend-state
+ (:constructor flymake--make-backend-state))
+ running reported-p disabled diags)
+
+(defmacro flymake--with-backend-state (backend state-var &rest body)
+ "Bind BACKEND's STATE-VAR to its state, run BODY."
+ (declare (indent 2) (debug (sexp sexp &rest form)))
+ (let ((b (make-symbol "b")))
+ `(let* ((,b ,backend)
+ (,state-var
+ (or (gethash ,b flymake--backend-state)
+ (puthash ,b (flymake--make-backend-state)
+ flymake--backend-state))))
+ ,@body)))
+
+(defun flymake-is-running ()
+ "Tell if Flymake has running backends in this buffer"
+ (flymake-running-backends))
+
+(cl-defun flymake--handle-report (backend token report-action
+ &key explanation force
+ &allow-other-keys)
+ "Handle reports from BACKEND identified by TOKEN.
+BACKEND, REPORT-ACTION and EXPLANATION, and FORCE conform to the calling
+convention described in `flymake-diagnostic-functions' (which
+see). Optional FORCE says to handle a report even if TOKEN was
+not expected."
+ (let* ((state (gethash backend flymake--backend-state))
+ (first-report (not (flymake--backend-state-reported-p state))))
+ (setf (flymake--backend-state-reported-p state) t)
+ (let (expected-token
+ new-diags)
+ (cond
+ ((null state)
+ (flymake-error
+ "Unexpected report from unknown backend %s" backend))
+ ((flymake--backend-state-disabled state)
+ (flymake-error
+ "Unexpected report from disabled backend %s" backend))
+ ((progn
+ (setq expected-token (flymake--backend-state-running state))
+ (null expected-token))
+ ;; should never happen
+ (flymake-error "Unexpected report from stopped backend %s" backend))
+ ((and (not (eq expected-token token))
+ (not force))
+ (flymake-error "Obsolete report from backend %s with explanation %s"
+ backend explanation))
+ ((eq :panic report-action)
+ (flymake--disable-backend backend explanation))
+ ((not (listp report-action))
+ (flymake--disable-backend backend
+ (format "Unknown action %S" report-action))
+ (flymake-error "Expected report, but got unknown key %s" report-action))
+ (t
+ (setq new-diags report-action)
+ (save-restriction
+ (widen)
+ ;; only delete overlays if this is the first report
+ (when first-report
+ (flymake-delete-own-overlays
+ (lambda (ov)
+ (eq backend
+ (flymake--diag-backend
+ (overlay-get ov 'flymake--diagnostic))))))
+ (mapc (lambda (diag)
+ (flymake--highlight-line diag)
+ (setf (flymake--diag-backend diag) backend))
+ new-diags)
+ (setf (flymake--backend-state-diags state)
+ (append new-diags (flymake--backend-state-diags state)))
+ (when flymake-check-start-time
+ (flymake-log :debug "backend %s reported %d diagnostics in %.2f second(s)"
+ backend
+ (length new-diags)
+ (- (float-time) flymake-check-start-time)))))))))
+
+(defun flymake-make-report-fn (backend &optional token)
+ "Make a suitable anonymous report function for BACKEND.
+BACKEND is used to help Flymake distinguish different diagnostic
+sources. If provided, TOKEN helps Flymake distinguish between
+different runs of the same backend."
+ (let ((buffer (current-buffer)))
+ (lambda (&rest args)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (apply #'flymake--handle-report backend token args))))))
+
+(defun flymake--collect (fn)
+ (let (retval)
+ (maphash (lambda (backend state)
+ (when (funcall fn state) (push backend retval)))
+ flymake--backend-state)
+ retval))
+
+(defun flymake-running-backends ()
+ "Compute running Flymake backends in current buffer."
+ (flymake--collect #'flymake--backend-state-running))
+
+(defun flymake-disabled-backends ()
+ "Compute disabled Flymake backends in current buffer."
+ (flymake--collect #'flymake--backend-state-disabled))
+
+(defun flymake-reporting-backends ()
+ "Compute reporting Flymake backends in current buffer."
+ (flymake--collect #'flymake--backend-state-reported-p))
+
+(defun flymake--disable-backend (backend &optional explanation)
+ "Disable BACKEND because EXPLANATION.
+If it is running also stop it."
+ (flymake-log :warning "Disabling backend %s because %s" backend explanation)
+ (flymake--with-backend-state backend state
+ (setf (flymake--backend-state-running state) nil
+ (flymake--backend-state-disabled state) explanation
+ (flymake--backend-state-reported-p state) t)))
+
+(defun flymake--run-backend (backend)
+ "Run the backend BACKEND, reenabling if necessary."
+ (flymake-log :debug "Running backend %s" backend)
+ (let ((run-token (cl-gensym "backend-token")))
+ (flymake--with-backend-state backend state
+ (setf (flymake--backend-state-running state) run-token
+ (flymake--backend-state-disabled state) nil
+ (flymake--backend-state-diags state) nil
+ (flymake--backend-state-reported-p state) nil))
+ ;; FIXME: Should use `condition-case-unless-debug' here, but don't
+ ;; for two reasons: (1) that won't let me catch errors from inside
+ ;; `ert-deftest' where `debug-on-error' appears to be always
+ ;; t. (2) In cases where the user is debugging elisp somewhere
+ ;; else, and using flymake, the presence of a frequently
+ ;; misbehaving backend in the global hook (most likely the legacy
+ ;; backend) will trigger an annoying backtrace.
+ ;;
+ (condition-case err
+ (funcall backend
+ (flymake-make-report-fn backend run-token))
+ (error
+ (flymake--disable-backend backend err)))))
+
+(defun flymake-start (&optional deferred force)
+ "Start a syntax check.
+Start it immediately, or after current command if DEFERRED is
+non-nil. With optional FORCE run even disabled backends.
+
+Interactively, with a prefix arg, FORCE is t."
+ (interactive (list nil current-prefix-arg))
+ (cl-labels
+ ((start
+ ()
+ (remove-hook 'post-command-hook #'start 'local)
+ (setq flymake-check-start-time (float-time))
+ (run-hook-wrapped
+ 'flymake-diagnostic-functions
+ (lambda (backend)
+ (cond
+ ((and (not force)
+ (flymake--with-backend-state backend state
+ (flymake--backend-state-disabled state)))
+ (flymake-log :debug "Backend %s is disabled, not starting"
+ backend))
+ (t
+ (flymake--run-backend backend)))
+ nil))))
+ (if (and deferred
+ this-command)
+ (add-hook 'post-command-hook #'start 'append 'local)
+ (start))))
+
+(defvar flymake-mode-map
+ (let ((map (make-sparse-keymap))) map)
+ "Keymap for `flymake-mode'")
+
+;;;###autoload
+(define-minor-mode flymake-mode nil
+ :group 'flymake :lighter flymake--mode-line-format :keymap flymake-mode-map
+ (cond
+ ;; Turning the mode ON.
+ (flymake-mode
+ (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)
+
+ (setq flymake--backend-state (make-hash-table))
+
+ (when flymake-start-syntax-check-on-find-file
+ (flymake-start)))
+
+ ;; Turning the mode OFF.
+ (t
+ (remove-hook 'after-change-functions 'flymake-after-change-function t)
+ (remove-hook 'after-save-hook 'flymake-after-save-hook t)
+ (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t)
+ ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t)
+
+ (flymake-delete-own-overlays)
+
+ (when flymake-timer
+ (cancel-timer flymake-timer)
+ (setq flymake-timer nil)))))
+
+(defun flymake--schedule-timer-maybe ()
+ "(Re)schedule an idle timer for checking the buffer.
+Do it only if `flymake-no-changes-timeout' is non-nil."
+ (when flymake-timer (cancel-timer flymake-timer))
+ (when flymake-no-changes-timeout
+ (setq
+ flymake-timer
+ (run-with-idle-timer
+ (seconds-to-time flymake-no-changes-timeout)
+ nil
+ (lambda (buffer)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (when (and flymake-mode
+ flymake-no-changes-timeout)
+ (flymake-log
+ :debug "starting syntax check after idle for %s seconds"
+ flymake-no-changes-timeout)
+ (flymake-start))
+ (setq flymake-timer nil))))
+ (current-buffer)))))
+
+;;;###autoload
+(defun flymake-mode-on ()
+ "Turn Flymake mode on."
+ (flymake-mode 1))
+
+;;;###autoload
+(defun flymake-mode-off ()
+ "Turn Flymake mode off."
+ (flymake-mode 0))
+
+(make-obsolete 'flymake-mode-on 'flymake-mode "26.1")
+(make-obsolete 'flymake-mode-off 'flymake-mode "26.1")
+
+(defun flymake-after-change-function (start stop _len)
+ "Start syntax check for current buffer if it isn't already running."
+ (let((new-text (buffer-substring start stop)))
+ (when (and flymake-start-syntax-check-on-newline (equal new-text "\n"))
+ (flymake-log :debug "starting syntax check as new-line has been seen")
+ (flymake-start 'deferred))
+ (flymake--schedule-timer-maybe)))
+
+(defun flymake-after-save-hook ()
+ (when flymake-mode
+ (flymake-log :debug "starting syntax check as buffer was saved")
+ (flymake-start)))
+
+(defun flymake-kill-buffer-hook ()
+ (when flymake-timer
+ (cancel-timer flymake-timer)
+ (setq flymake-timer nil)))
+
+(defun flymake-find-file-hook ()
+ (unless (or flymake-mode
+ (null flymake-diagnostic-functions))
+ (flymake-mode)
+ (flymake-log :warning "Turned on in `flymake-find-file-hook'")))
+
+(defun flymake-goto-next-error (&optional n filter interactive)
+ "Go to Nth next Flymake error in buffer matching FILTER.
+Interactively, always move to the next error. With a prefix arg,
+skip any diagnostics with a severity less than ‘:warning’.
+
+If ‘flymake-wrap-around’ is non-nil and no more next errors,
+resumes search from top
+
+FILTER is a list of diagnostic types found in
+`flymake-diagnostic-types-alist', or nil, if no filter is to be
+applied."
+ ;; TODO: let filter be a number, a severity below which diags are
+ ;; skipped.
+ (interactive (list 1
+ (if current-prefix-arg
+ '(:error :warning))
+ t))
+ (let* ((n (or n 1))
+ (ovs (flymake--overlays :filter
+ (lambda (ov)
+ (let ((diag (overlay-get
+ ov
+ 'flymake--diagnostic)))
+ (and diag
+ (or (not filter)
+ (memq (flymake--diag-type diag)
+ filter)))))
+ :compare (if (cl-plusp n) #'< #'>)
+ :key #'overlay-start))
+ (tail (cl-member-if (lambda (ov)
+ (if (cl-plusp n)
+ (> (overlay-start ov)
+ (point))
+ (< (overlay-start ov)
+ (point))))
+ ovs))
+ (chain (if flymake-wrap-around
+ (if tail
+ (progn (setcdr (last tail) ovs) tail)
+ (and ovs (setcdr (last ovs) ovs)))
+ tail))
+ (target (nth (1- n) chain)))
+ (cond (target
+ (goto-char (overlay-start target))
+ (when interactive
+ (message
+ (funcall (overlay-get target 'help-echo)
+ nil nil (point)))))
+ (interactive
+ (user-error "No more Flymake errors%s"
+ (if filter
+ (format " of types %s" filter)
+ ""))))))
+
+(defun flymake-goto-prev-error (&optional n filter interactive)
+ "Go to Nth previous Flymake error in buffer matching FILTER.
+Interactively, always move to the previous error. With a prefix
+arg, skip any diagnostics with a severity less than ‘:warning’.
+
+If ‘flymake-wrap-around’ is non-nil and no more previous errors,
+resumes search from bottom.
+
+FILTER is a list of diagnostic types found in
+`flymake-diagnostic-types-alist', or nil, if no filter is to be
+applied."
+ (interactive (list 1 (if current-prefix-arg
+ '(:error :warning))
+ t))
+ (flymake-goto-next-error (- (or n 1)) filter interactive))
+
+
+;;; Mode-line and menu
+;;;
+(easy-menu-define flymake-menu flymake-mode-map "Flymake"
+ `("Flymake"
+ [ "Go to next error" flymake-goto-next-error t ]
+ [ "Go to previous error" flymake-goto-prev-error t ]
+ [ "Check now" flymake-start t ]
+ [ "Go to log buffer" flymake-switch-to-log-buffer t ]
+ "--"
+ [ "Turn off Flymake" flymake-mode t ]))
+
+(defvar flymake--mode-line-format `(:eval (flymake--mode-line-format)))
+
+(put 'flymake--mode-line-format 'risky-local-variable t)
+
+(defun flymake--mode-line-format ()
+ "Produce a pretty minor mode indicator."
+ (let* ((known (hash-table-keys flymake--backend-state))
+ (running (flymake-running-backends))
+ (disabled (flymake-disabled-backends))
+ (reported (flymake-reporting-backends))
+ (diags-by-type (make-hash-table))
+ (all-disabled (and disabled (null running)))
+ (some-waiting (cl-set-difference running reported)))
+ (maphash (lambda (_b state)
+ (mapc (lambda (diag)
+ (push diag
+ (gethash (flymake--diag-type diag)
+ diags-by-type)))
+ (flymake--backend-state-diags state)))
+ flymake--backend-state)
+ `((:propertize " Flymake"
+ mouse-face mode-line-highlight
+ help-echo
+ ,(concat (format "%s known backends\n" (length known))
+ (format "%s running\n" (length running))
+ (format "%s disabled\n" (length disabled))
+ "mouse-1: go to log buffer ")
+ keymap
+ ,(let ((map (make-sparse-keymap)))
+ (define-key map [mode-line down-mouse-1]
+ flymake-menu)
+ map))
+ ,@(pcase-let ((`(,ind ,face ,explain)
+ (cond ((null known)
+ `("?" mode-line "No known backends"))
+ (some-waiting
+ `("Wait" compilation-mode-line-run
+ ,(format "Waiting for %s running backend(s)"
+ (length some-waiting))))
+ (all-disabled
+ `("!" compilation-mode-line-run
+ "All backends disabled"))
+ (t
+ `(nil nil nil)))))
+ (when ind
+ `((":"
+ (:propertize ,ind
+ face ,face
+ help-echo ,explain
+ keymap
+ ,(let ((map (make-sparse-keymap)))
+ (define-key map [mode-line mouse-1]
+ 'flymake-switch-to-log-buffer)
+ map))))))
+ ,@(unless (or all-disabled
+ (null known))
+ (cl-loop
+ for (type . severity)
+ in (cl-sort (mapcar (lambda (type)
+ (cons type (flymake--lookup-type-property
+ type
+ 'severity
+ (warning-numeric-level :error))))
+ (cl-union (hash-table-keys diags-by-type)
+ '(:error :warning)))
+ #'>
+ :key #'cdr)
+ for diags = (gethash type diags-by-type)
+ for face = (flymake--lookup-type-property type
+ 'mode-line-face
+ 'compilation-error)
+ when (or diags
+ (>= severity (warning-numeric-level :warning)))
+ collect `(:propertize
+ ,(format "%d" (length diags))
+ face ,face
+ mouse-face mode-line-highlight
+ keymap
+ ,(let ((map (make-sparse-keymap))
+ (type type))
+ (define-key map [mode-line mouse-4]
+ (lambda (_event)
+ (interactive "e")
+ (flymake-goto-prev-error 1 (list type) t)))
+ (define-key map [mode-line mouse-5]
+ (lambda (_event)
+ (interactive "e")
+ (flymake-goto-next-error 1 (list type) t)))
+ map)
+ help-echo
+ ,(concat (format "%s diagnostics of type %s\n"
+ (propertize (format "%d"
+ (length diags))
+ 'face face)
+ (propertize (format "%s" type)
+ 'face face))
+ "mouse-4/mouse-5: previous/next of this type\n"))
+ into forms
+ finally return
+ `((:propertize "[")
+ ,@(cl-loop for (a . rest) on forms by #'cdr
+ collect a when rest collect
+ '(:propertize " "))
+ (:propertize "]")))))))
(provide 'flymake)
+
+(require 'flymake-proc)
+
;;; flymake.el ends here
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 365191c56b0..9aa5134ca0d 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -3442,6 +3442,8 @@ def __PYTHON_EL_native_completion_setup():
instance.rlcomplete = new_completer
if readline.__doc__ and 'libedit' in readline.__doc__:
+ raise Exception('''libedit based readline is known not to work,
+ see etc/PROBLEMS under \"In Inferior Python mode, input is echoed\".''')
readline.parse_and_bind('bind ^I rl_complete')
else:
readline.parse_and_bind('tab: complete')
@@ -3450,7 +3452,9 @@ def __PYTHON_EL_native_completion_setup():
print ('python.el: native completion setup loaded')
except:
- print ('python.el: native completion setup failed')
+ import sys
+ print ('python.el: native completion setup failed, %s: %s'
+ % sys.exc_info()[:2])
__PYTHON_EL_native_completion_setup()" process)
(when (and