summaryrefslogtreecommitdiff
path: root/lisp/progmodes/flymake.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/flymake.el')
-rw-r--r--lisp/progmodes/flymake.el276
1 files changed, 173 insertions, 103 deletions
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 40eacdd1888..fdb22ccaf34 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -3,8 +3,8 @@
;; Copyright (C) 2003-2018 Free Software Foundation, Inc.
;; Author: Pavel Kobyakov <pk_at_work@yahoo.com>
-;; Maintainer: Leo Liu <sdl.web@gmail.com>
-;; Version: 0.3
+;; Maintainer: João Távora <joaotavora@gmail.com>
+;; Version: 1.0
;; Keywords: c languages tools
;; This file is part of GNU Emacs.
@@ -34,13 +34,77 @@
;; 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 main interactive entry point is the `flymake-mode' minor mode,
+;; which periodically and automatically initiates checks as the user
+;; is editing the buffer. The variables `flymake-no-changes-timeout',
+;; `flymake-start-syntax-check-on-newline' and
+;; `flymake-start-on-flymake-mode' give finer control over the events
+;; triggering a check, as does the interactive command
+;; `flymake-start', which immediately starts a check.
;;
-;; The docstrings of these variables are relevant to understanding how
-;; Flymake works for both the user and the backend programmer:
+;; Shortly after each check, a summary of collected diagnostics should
+;; appear in the mode-line. If it doesn't, there might not be a
+;; suitable Flymake backend for the current buffer's major mode, in
+;; which case Flymake will indicate this in the mode-line. The
+;; indicator will be `!' (exclamation mark), if all the configured
+;; backends errored (or decided to disable themselves) and `?'
+;; (question mark) if no backends were even configured.
;;
-;; * `flymake-diagnostic-functions'
-;; * `flymake-diagnostic-types-alist'
+;; For programmers interested in writing a new Flymake backend, the
+;; docstring of `flymake-diagnostic-functions', the Flymake manual,
+;; and the code of existing backends are probably a good starting
+;; point.
+;;
+;; The user wishing to customize the appearance of error types should
+;; set properties on the symbols associated with each diagnostic type.
+;; The standard diagnostic symbols are `:error', `:warning' and
+;; `:note' (though a specific backend may define and use more). The
+;; following properties can be set:
+;;
+;; * `flymake-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.
+;;
+;; * `flymake-severity', a non-negative integer specifying the
+;; diagnostic's severity. The higher, the more serious. If the
+;; overlay property `priority' is not specified, `severity' is used to
+;; set it and help sort overlapping overlays.
+;;
+;; * `flymake-overlay-control', an alist ((OVPROP . VALUE) ...) of
+;; further properties used to affect the appearance of Flymake
+;; annotations. With the exception of `category' and `evaporate',
+;; these properties are applied directly to the created overlay. See
+;; Info Node `(elisp)Overlay Properties'.
+;;
+;; * `flymake-category', a symbol whose property list is considered 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. The category
+;; symbols `flymake-error', `flymake-warning' and `flymake-note' make
+;; good candidates for values of this property.
+;;
+;; For instance, to omit the fringe bitmap displayed for the standard
+;; `:note' type, set its `flymake-bitmap' property to nil:
+;;
+;; (put :note 'flymake-bitmap nil)
+;;
+;; To change the face for `:note' type, add a `face' entry to its
+;; `flymake-overlay-control' property.
+;;
+;; (push '(face . highlight) (get :note 'flymake-overlay-control))
+;;
+;; If you push another alist entry in front, it overrides the previous
+;; one. So this effectively removes the face from `:note'
+;; diagnostics.
+;;
+;; (push '(face . nil) (get :note 'flymake-overlay-control))
+;;
+;; To erase customizations and go back to the original look for
+;; `:note' types:
+;;
+;; (cl-remf (symbol-plist :note) 'flymake-overlay-control)
+;; (cl-remf (symbol-plist :note) 'flymake-bitmap)
;;
;;; Code:
@@ -132,11 +196,17 @@ If nil, never start checking buffer automatically like this."
'flymake-start-on-flymake-mode "26.1")
(defcustom flymake-start-on-flymake-mode t
- "Start syntax check when `flymake-mode' is enabled.
+ "If non-nil, start syntax check when `flymake-mode' is enabled.
Specifically, start it when the buffer is actually displayed."
:version "26.1"
:type 'boolean)
+(defcustom flymake-start-on-save-buffer t
+ "If non-nil start syntax check when a buffer is saved.
+Specifically, start it when the saved buffer is actually displayed."
+ :version "27.1"
+ :type 'boolean)
+
(defcustom flymake-log-level -1
"Obsolete and ignored variable."
:type 'integer)
@@ -222,18 +292,21 @@ generated it."
(cl-defstruct (flymake--diag
(:constructor flymake--diag-make))
- buffer beg end type text backend)
+ buffer beg end type text backend data)
;;;###autoload
(defun flymake-make-diagnostic (buffer
beg
end
type
- text)
+ text
+ &optional data)
"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))
+TYPE is a key to symbol and TEXT is a description of the problem
+detected in this region. DATA is any object that the caller
+wishes to attach to the created diagnostic for later retrieval."
+ (flymake--diag-make :buffer buffer :beg beg :end end
+ :type type :text text :data data))
;;;###autoload
(defun flymake-diagnostics (&optional beg end)
@@ -257,6 +330,7 @@ diagnostics at BEG."
(flymake--diag-accessor flymake-diagnostic-beg flymake--diag-beg beg)
(flymake--diag-accessor flymake-diagnostic-end flymake--diag-end end)
(flymake--diag-accessor flymake-diagnostic-backend flymake--diag-backend backend)
+(flymake--diag-accessor flymake-diagnostic-data flymake--diag-data backend)
(cl-defun flymake--overlays (&key beg end filter compare key)
"Get flymake-related overlays.
@@ -419,74 +493,63 @@ Currently accepted REPORT-KEY arguments are:
* `: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
- property `priority' is not specified, `severity' is used to set
- it and help sort overlapping overlays.
-
-* `flymake-category', a symbol whose property list is considered
- 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-diagnostic-functions 'safe-local-variable #'null)
+
+(put :error 'flymake-category 'flymake-error)
+(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 'bitmap 'flymake-error-bitmap)
+(put 'flymake-error 'flymake-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 'flymake-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 'flymake-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
+ "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."
- (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))))
+ ;; 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))))
+
+(defun flymake--severity (type)
+ "Get the severity for diagnostic TYPE."
+ (flymake--lookup-type-property type 'severity
+ (warning-numeric-level :error)))
(defun flymake--fringe-overlay-spec (bitmap &optional recursed)
(if (and (symbolp bitmap)
@@ -503,34 +566,38 @@ associated `flymake-category' return DEFAULT."
(list bitmap)))))))
(defun flymake--highlight-line (diagnostic)
- "Highlight buffer with info in DIAGNOSTIC."
- (when-let* ((ov (make-overlay
+ "Highlight buffer with info in DIGNOSTIC."
+ (when-let* ((type (flymake--diag-type diagnostic))
+ (ov (make-overlay
(flymake--diag-beg diagnostic)
(flymake--diag-end diagnostic))))
- ;; First set `category' in the overlay, then copy over every other
- ;; property.
+ ;; First set `category' in the overlay
;;
- (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)))
+ (overlay-put ov 'category
+ (flymake--lookup-type-property type 'flymake-category))
+ ;; Now "paint" the overlay with all the other non-category
+ ;; properties.
+ (cl-loop
+ for (ov-prop . value) in
+ (append (reverse ; ensure ealier props override later ones
+ (flymake--lookup-type-property type 'flymake-overlay-control))
+ (alist-get type flymake-diagnostic-types-alist))
+ do (overlay-put ov ov-prop value))
;; 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)
+ (unless (plist-member (overlay-properties ov) prop)
+ (overlay-put ov prop (flymake--lookup-type-property
+ type prop value)))))
(default-maybe 'face 'flymake-error)
(default-maybe 'before-string
(flymake--fringe-overlay-spec
- (overlay-get ov 'bitmap)))
+ (flymake--lookup-type-property
+ type
+ 'flymake-bitmap
+ (alist-get 'bitmap (alist-get type ; backward compat
+ flymake-diagnostic-types-alist)))))
(default-maybe 'help-echo
(lambda (window _ov pos)
(with-selected-window window
@@ -818,7 +885,9 @@ The commands `flymake-goto-next-error' and
diagnostics annotated in the buffer.
The visual appearance of each type of diagnostic can be changed
-in the variable `flymake-diagnostic-types-alist'.
+by setting properties `flymake-overlay-control', `flymake-bitmap'
+and `flymake-severity' on the symbols of diagnostic types (like
+`:error', `:warning' and `:note').
Activation or deactivation of backends used by Flymake in each
buffer happens via the special hook
@@ -899,7 +968,7 @@ Do it only if `flymake-no-changes-timeout' is non-nil."
(flymake--schedule-timer-maybe)))
(defun flymake-after-save-hook ()
- (when flymake-mode
+ (when flymake-start-on-save-buffer
(flymake-log :debug "starting syntax check as buffer was saved")
(flymake-start t)))
@@ -922,9 +991,9 @@ arg, skip any diagnostics with a severity less than `:warning'.
If `flymake-wrap-around' is non-nil and no more next diagnostics,
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."
+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
@@ -938,9 +1007,12 @@ applied."
ov
'flymake-diagnostic)))
(and diag
- (or (not filter)
- (memq (flymake--diag-type diag)
- filter)))))
+ (or
+ (not filter)
+ (cl-find
+ (flymake--severity
+ (flymake--diag-type diag))
+ filter :key #'flymake--severity)))))
:compare (if (cl-plusp n) #'< #'>)
:key #'overlay-start))
(tail (cl-member-if (lambda (ov)
@@ -964,10 +1036,10 @@ applied."
(funcall (overlay-get target 'help-echo)
(selected-window) target (point)))))
(interactive
- (user-error "No more Flymake errors%s"
+ (user-error "No more Flymake diagnostics%s"
(if filter
- (format " of types %s" 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.
@@ -978,9 +1050,9 @@ prefix arg, skip any diagnostics with a severity less than
If `flymake-wrap-around' is non-nil and no more previous
diagnostics, 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."
+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))
@@ -1063,12 +1135,10 @@ applied."
(cl-loop
for (type . severity)
in (cl-sort (mapcar (lambda (type)
- (cons type (flymake--lookup-type-property
- type
- 'severity
- (warning-numeric-level :error))))
+ (cons type (flymake--severity type)))
(cl-union (hash-table-keys diags-by-type)
- '(:error :warning)))
+ '(:error :warning)
+ :key #'flymake--severity))
#'>
:key #'cdr)
for diags = (gethash type diags-by-type)