;; Copyright (C) 2003-2025 Free Software Foundation, Inc.
;; Author: Pavel Kobyakov <pk_at_work@yahoo.com>
-;; Maintainer: João Távora <joaotavora@gmail.com>
-;; Version: 1.3.7
-;; Keywords: c languages tools
-;; Package-Requires: ((emacs "26.1") (eldoc "1.14.0") (project "0.7.1"))
+;; Keywords: languages tools
;; This is a GNU ELPA :core package. Avoid functionality that is not
;; compatible with the version of Emacs recorded above.
(require 'thingatpt) ; end-of-thing
(require 'warnings) ; warning-numeric-level, display-warning
(require 'compile) ; for some faces
-;; We need the next `require' to avoid compiler warnings and run-time
-;; errors about mouse-wheel-up/down-event in builds --without-x, where
-;; mwheel is not preloaded.
-(require 'mwheel)
(require 'project)
(defgroup flymake nil
(const right-margin)
(const :tag "No margin indicators" nil)))
-(make-obsolete-variable 'flymake-start-syntax-check-on-newline
- "can check on newline in post-self-insert-hook"
- "27.1")
-
(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 '(choice (number :tag "Timeout in seconds")
(const :tag "No check on timeout" nil)))
-(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")
-
-(define-obsolete-variable-alias 'flymake-start-syntax-check-on-find-file
- 'flymake-start-on-flymake-mode "26.1")
-
(defcustom flymake-start-on-flymake-mode t
"If non-nil, start syntax check when `flymake-mode' is enabled.
Specifically, start it when the buffer is actually displayed."
:version "27.1"
: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."
:version "26.1"
(defvar-local flymake-timer nil
"Timer for starting syntax check.")
-(defvar-local flymake-check-start-time nil
- "Time at which syntax check was started.")
-
(defvar-local flymake--original-margin-width nil
"Store original margin width.
Used by `flymake--resize-margins' for restoring original margin width
when flymake is turned off.")
-(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)
- ;; Handle file names with "%" correctly. (Bug#51549)
- (replace-regexp-in-string "%" "%%"
- (buffer-name (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 file,
-the generated warning contains an indication of the file that
-generated it."
- (let* ((file (if (fboundp 'macroexp-file-name)
- (macroexp-file-name)
- (and (not load-file-name)
- (bound-and-true-p byte-compile-current-file))))
- (sublog (if (stringp file)
- (intern
- (file-name-nondirectory
- (file-name-sans-extension 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 "%s" msg)
- (error (concat "[Flymake] " msg))))
-
(cl-defstruct (flymake--diag
(:constructor flymake--diag-make))
locus beg end type text backend data overlay-properties overlay
(const :tag "Don't display diagnostics at end-of-line" nil))
:package-version '(Flymake . "1.3.6"))
-(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.
(save-match-data
(goto-char (point-min))
(forward-line (1- line))
- (cl-flet ((fallback-bol
- ()
- (back-to-indentation)
- (if (eobp)
- (line-beginning-position 0)
- (point)))
- (fallback-eol
- (beg)
- (progn
- (end-of-line)
- (skip-chars-backward " \t\f\n" beg)
- (if (eq (point) beg)
- (line-beginning-position 2)
- (point)))))
+ (cl-flet ((fallback-bol ()
+ (back-to-indentation)
+ (if (eobp)
+ (line-beginning-position 0)
+ (point)))
+ (fallback-eol (beg)
+ (end-of-line)
+ (skip-chars-backward " \t\f\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)))
(let* ((beg (fallback-bol))
(end (fallback-eol beg)))
(cons beg end))))))))
- (error (flymake-log :warning "Invalid region line=%s col=%s" line col)
- nil)))
+ (error nil)))
(defvar flymake-diagnostic-functions nil
"Special hook of Flymake backends that check a buffer.
(put :warning 'flymake-category 'flymake-warning)
(put :note 'flymake-category 'flymake-note)
-(defvar flymake-diagnostic-types-alist '())
-(make-obsolete-variable
- 'flymake-diagnostic-types-alist
- "Set properties on the diagnostic symbols instead. See Info
-Node `(Flymake)Flymake error types'"
- "27.1")
-
(put 'flymake-error 'face 'flymake-error)
(put 'flymake-error 'flymake-bitmap 'flymake-error-bitmap)
(put 'flymake-error 'flymake-margin-string (alist-get 'error flymake-margin-indicators-string))
"Look up PROP for diagnostic TYPE.
If TYPE doesn't declare PROP in its plist or in the symbol of its
associated `flymake-category' return DEFAULT."
- ;; This function also consults `flymake-diagnostic-types-alist' for
- ;; backward compatibility.
- ;;
- (if (plist-member (symbol-plist type) prop)
- ;; allow nil values to survive
- (get type prop)
- (let (alist)
- (or
- (alist-get
- prop (setq
- alist
- (alist-get type flymake-diagnostic-types-alist)))
- (when-let* ((cat (or
- (get type 'flymake-category)
- (alist-get 'flymake-category alist)))
- (plist (and (symbolp cat)
- (symbol-plist cat)))
- (cat-probe (plist-member plist prop)))
- (cadr cat-probe))
- default))))
+ (if-let ((probe (plist-member (symbol-plist type) prop))) (cadr probe)
+ (if-let ((cat (get type 'flymake-category))
+ (plist (and (symbolp cat) (symbol-plist cat)))
+ (cat-probe (plist-member plist prop)))
+ (cadr cat-probe)
+ default)))
(defun flymake--severity (type)
"Get the severity for diagnostic TYPE."
(append (reverse
(flymake--diag-overlay-properties diagnostic))
(reverse ; ensure earlier props override later ones
- (flymake--lookup-type-property type 'flymake-overlay-control))
- (alist-get type flymake-diagnostic-types-alist))
+ (flymake--lookup-type-property type 'flymake-overlay-control)))
do (overlay-put ov ov-prop value))
;; Now ensure some essential defaults are set
;;
(cond ((eq flymake-indicator-type 'fringes)
'flymake-bitmap)
((eq flymake-indicator-type 'margins)
- 'flymake-margin-string))
- (alist-get 'bitmap (alist-get type ; backward compat
- flymake-diagnostic-types-alist)))))
+ 'flymake-margin-string)))))
;; (default-maybe 'after-string
;; (flymake--diag-text diagnostic))
(default-maybe 'help-echo
(overlay-put ov 'eol-ov eolov))))
ov))
-;; 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--state nil
"State of a buffer's multiple Flymake backends.
The keys to this hash table are functions as found in
expected-token)
(cond
((null state)
- (flymake-error
- "Unexpected report from unknown backend %s" backend))
+ (error "Unexpected report from unknown Flymake backend %s" backend))
((flymake--state-disabled state)
- (flymake-error
- "Unexpected report from disabled backend %s" backend))
+ (error "Unexpected report from disabled Flymake backend %s" backend))
((progn
(setq expected-token (flymake--state-running state))
(null expected-token))
;; should never happen
- (flymake-error "Unexpected report from stopped backend %s" backend))
+ (error "Unexpected report from stopped Flymake backend %s" backend))
((not (or (eq expected-token token)
force))
- (flymake-error "Obsolete report from backend %s with explanation %s"
- backend explanation))
+ (error "Obsolete report from Flymake 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))
+ (error "Expected Flymake report, but got unknown key %s" report-action))
(t
(flymake--publish-diagnostics report-action
:backend backend
:state state
- :region region)
- (when flymake-check-start-time
- (flymake-log :debug "backend %s reported %d diagnostics in %.2f second(s)"
- backend
- (length report-action)
- (float-time
- (time-since flymake-check-start-time))))))
+ :region region)))
(setf (flymake--state-reported-p state) t)
;; All of the above might have touched the eol overlays, so issue
;; a call to update them. But check running and reporting
(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--state-running state) nil
(flymake--state-disabled state) explanation
"Run the backend BACKEND, re-enabling if necessary.
ARGS is a keyword-value plist passed to the backend along
with a report function."
- (flymake-log :debug "Running backend %s" backend)
(let ((run-token (gensym "backend-token")))
(flymake--with-backend-state backend state
(setf (flymake--state-running state) run-token
#'start-on-display
'append 'local))
(flymake-mode
- (setq flymake-check-start-time (float-time))
(let ((backend-args
(and
flymake--recent-changes
(cond
((and (not force)
(flymake--with-backend-state backend state
- (flymake--state-disabled state)))
- (flymake-log :debug "Backend %s is disabled, not starting"
- backend))
+ (flymake--state-disabled state))))
(t
(flymake--run-backend backend backend-args)))
nil)))
and some may decide to disable themselves if they are not
suitable for the current buffer. The commands
`flymake-running-backends', `flymake-disabled-backends' and
-`flymake-reporting-backends' summarize the situation, as does the
-special *Flymake log* buffer." :group 'flymake :lighter
- flymake-mode-line-format :keymap flymake-mode-map
+`flymake-reporting-backends' summarize the situation."
+ :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)
- (add-hook 'eldoc-documentation-functions 'flymake-eldoc-function t t)
(add-hook 'dwim-hook 'flymake-dwim-fix nil t)
;; AutoResize margins.
;; 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)
- (remove-hook 'eldoc-documentation-functions 'flymake-eldoc-function t)
(remove-hook 'dwim-hook 'flymake-dwim-fix t)
;; return margin to original size
(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)
+ (when (and flymake-mode flymake-no-changes-timeout)
(flymake-start t))
(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 pre-change-len)
"Start syntax check for current buffer if it isn't already running.
START and STOP and LEN are as in `after-change-functions'."
(let ((newend (line-end-position)))
(dolist (ov eolovs) (move-overlay ov newend (1+ newend))))))))
-(defun flymake-after-save-hook ()
- (when flymake-start-on-save-buffer
- (flymake-log :debug "starting syntax check as buffer was saved")
- (flymake-start t)))
-
-(defun flymake-kill-buffer-hook ()
- ;; Explicitly set flymake off, because that does a lot of useful
- ;; cleanup.
- (flymake-mode -1))
-
-(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-eldoc-function (report-doc &rest _)
- "Document diagnostics at point.
-Intended for `eldoc-documentation-functions' (which see)."
- (when-let ((diags (flymake-diagnostics (point))))
- (funcall report-doc
- (mapconcat #'flymake-diagnostic-text diags "\n")
- :echo (mapconcat #'flymake-diagnostic-oneliner
- diags "\n"))))
-
-(defun flymake-goto-next-error (&optional n filter interactive)
- "Go to Nth next Flymake diagnostic that matches FILTER.
-Interactively, always move to the next diagnostic. With a prefix
-arg, skip any diagnostics with a severity less than `:warning'.
-
+(defun flymake-goto-next-error (&optional n interactive)
+ "Go to Nth next Flymake diagnostic.
If `flymake-wrap-around' is non-nil and no more next diagnostics,
-resumes search from top.
-
-FILTER is a list of diagnostic types. Only diagnostics with
-matching severities matching are considered. If nil (the
-default) no filter is applied."
- ;; TODO: let filter be a number, a severity below which diags are
- ;; skipped.
- (interactive (list 1
- (if current-prefix-arg
- '(:error :warning))
- t))
+resumes search from top."
+ (interactive "p\np")
(let* ((n (or n 1))
(ovs (cl-loop
for o in (overlays-in (point-min) (point-max))
for diag = (overlay-get o 'flymake-diagnostic)
- when (and diag (or (not filter) (cl-find
- (flymake--severity
- (flymake-diagnostic-type diag))
- filter :key #'flymake--severity)))
+ when diag
collect o into retval
finally return (cl-sort retval (if (cl-plusp n) #'< #'>)
:key #'overlay-start)))
(funcall (overlay-get target 'help-echo)
(selected-window) target (point)))))
(interactive
- (user-error "No more Flymake diagnostics%s"
- (if filter
- (format " of %s severity"
- (mapconcat #'symbol-name filter ", "))
- ""))))))
-
-(defun flymake-goto-prev-error (&optional n filter interactive)
- "Go to Nth previous Flymake diagnostic that matches FILTER.
-Interactively, always move to the previous diagnostic. With a
-prefix arg, skip any diagnostics with a severity less than
-`:warning'.
+ (user-error "No more Flymake diagnostics")))))
+(defun flymake-goto-prev-error (&optional n interactive)
+ "Go to Nth previous Flymake diagnostic.
If `flymake-wrap-around' is non-nil and no more previous
-diagnostics, resumes search from bottom.
-
-FILTER is a list of diagnostic types. Only diagnostics with
-matching severities matching are considered. If nil (the
-default) no filter is applied."
- (interactive (list 1 (if current-prefix-arg
- '(:error :warning))
- t))
- (flymake-goto-next-error (- (or n 1)) filter interactive))
+diagnostics, resumes search from bottom."
+ (interactive "p\np")
+ (flymake-goto-next-error (- (or n 1)) interactive))
\f
;;; Mode-line and menu
[ "Check now" flymake-start t ]
[ "List all problems" flymake-list-diagnostics t ]
"--"
- [ "Go to log buffer" flymake-switch-to-log-buffer t ]
[ "Turn off Flymake" flymake-mode t ]))
(defcustom flymake-mode-line-format
`(:propertize
,flymake-mode-line-lighter
mouse-face mode-line-highlight
+ follow-link t
help-echo
,(lambda (w &rest _)
(with-current-buffer (window-buffer w)
;; `flymake--state' is buffer local and is null when line
;; lighter appears in *Help* `describe-mode'.
(concat
+ "mouse-2: Display minor mode menu"
(unless (null flymake--state)
(concat
+ "\n"
(format "%s known backends\n" (hash-table-count flymake--state))
(format "%s running\n" (length (flymake-running-backends)))
- (format "%s disabled\n" (length (flymake-disabled-backends)))))
- "mouse-1: Display minor mode menu\n"
- "mouse-2: Show help for minor mode")))
+ (format "%s disabled\n" (length (flymake-disabled-backends))))))))
keymap
,(let ((map (make-sparse-keymap)))
- (define-key map [mode-line down-mouse-1]
- flymake-menu)
- (define-key map [mode-line down-mouse-3]
- flymake-menu)
- (define-key map [mode-line mouse-2]
- (lambda ()
- (interactive)
- (describe-function 'flymake-mode)))
+ (define-key map [mode-line mouse-2] flymake-menu)
+ (define-key map [mode-line follow-link] 'mouse-face)
map)))
(defun flymake--mode-line-exception ()
(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))))))
+ help-echo ,explain)))))
(defun flymake--mode-line-counters ()
(when (flymake-running-backends) flymake-mode-line-counter-format))
-(defun flymake--mode-line-counter-scroll-prev (event)
- (interactive "e")
- (let* ((event-start (event-start event))
- (posn-string (posn-string event-start))
- (type (get-text-property
- (cdr posn-string) 'flymake--diagnostic-type (car posn-string))))
- (with-selected-window (posn-window event-start)
- (flymake-goto-prev-error 1 (list type) t))))
-
-(defun flymake--mode-line-counter-scroll-next (event)
- (interactive "e")
- (let* ((event-start (event-start event))
- (posn-string (posn-string event-start))
- (type (get-text-property
- (cdr posn-string) 'flymake--diagnostic-type (car posn-string))))
- (with-selected-window (posn-window event-start)
- (flymake-goto-next-error 1 (list type) t))))
-
-(defvar flymake--mode-line-counter-map
- (let ((map (make-sparse-keymap)))
- ;; BEWARE: `mouse-wheel-UP-event' corresponds to `wheel-DOWN' events
- ;; and vice versa!!
- (with-suppressed-warnings
- ((obsolete mouse-wheel-up-event mouse-wheel-down-event))
- (define-key map (vector 'mode-line mouse-wheel-down-event)
- #'flymake--mode-line-counter-scroll-prev)
- (define-key map [mode-line wheel-down]
- #'flymake--mode-line-counter-scroll-next)
- (define-key map (vector 'mode-line mouse-wheel-up-event)
- #'flymake--mode-line-counter-scroll-next)
- (define-key map [mode-line wheel-up]
- #'flymake--mode-line-counter-scroll-prev))
- map))
-
(defun flymake--mode-line-counter-1 (type)
"Helper for `flymake--mode-line-counter'."
(let ((count 0)
,(format "%d" count)
face ,face
mouse-face mode-line-highlight
- help-echo ,(format "Number of %s; scroll mouse to view."
+ help-echo ,(format "Number of %s"
(cond
((eq type :error) "errors")
((eq type :warning) "warnings")
((eq type :note) "notes")
- (t (format "%s diagnostics" type))))
- flymake--diagnostic-type ,type
- keymap ,flymake--mode-line-counter-map)))))
+ (t (format "%s diagnostics" type)))))))))
(defun flymake--mode-line-counter (type)
"Compute number of diagnostics in buffer with TYPE's severity.