aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/progmodes/flymake-proc.el2
-rw-r--r--lisp/progmodes/flymake.el289
2 files changed, 198 insertions, 93 deletions
diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el
index 0395fff3224..abda259e898 100644
--- a/lisp/progmodes/flymake-proc.el
+++ b/lisp/progmodes/flymake-proc.el
@@ -409,7 +409,7 @@ Create parent directories as needed."
409 (string-to-number col-string)))) 409 (string-to-number col-string))))
410 (with-current-buffer (process-buffer proc) 410 (with-current-buffer (process-buffer proc)
411 (push 411 (push
412 (flymake-ler-make 412 (flymake-make-diagnostic
413 :file fname 413 :file fname
414 :line line-number 414 :line line-number
415 :col col-number 415 :col col-number
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index f00915a6846..72acc3a9204 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -33,6 +33,8 @@
33;;; Code: 33;;; Code:
34 34
35(require 'cl-lib) 35(require 'cl-lib)
36(require 'thingatpt) ; end-of-thing
37(require 'warnings) ; warning-numeric-level
36 38
37(defgroup flymake nil 39(defgroup flymake nil
38 "Universal on-the-fly syntax checker." 40 "Universal on-the-fly syntax checker."
@@ -136,57 +138,18 @@ are the string substitutions (see the function `format')."
136 (let* ((msg (apply #'format-message text args))) 138 (let* ((msg (apply #'format-message text args)))
137 (message "%s" msg)))) 139 (message "%s" msg))))
138 140
139(cl-defstruct (flymake-ler 141(cl-defstruct (flymake--diag
140 (:constructor flymake-ler-make)) 142 (:constructor flymake-make-diagnostic))
141 file line col type text full-file) 143 file line col type text full-file)
142 144(define-obsolete-function-alias 'flymake-ler-make 'flymake-make-diagnostic "26.1"
143(defun flymake-ler-errorp (diag) 145 "Constructor for objects of type `flymake--diag'")
144 "Tell if DIAG is a flymake error or something else" 146
145 (string= "e" (flymake-ler-type diag))) 147(cl-defun flymake--overlays (&key beg end filter compare key)
146 148 "Get flymake-related overlays.
147(defun flymake--place-overlay (beg end tooltip-text face bitmap diag) 149If BEG is non-nil and END is nil, consider only `overlays-at'
148 "Place a flymake overlay in range BEG and END. 150BEG. Otherwise consider `overlays-in' the region comprised by BEG
149Make a flymake fringe overlay for the line at BEG, if needed." 151and END, defaulting to the whole buffer. Remove all that do not
150 (let* ((fringe-overlay 152verify FILTER, sort them by COMPARE (using KEY)."
151 (or (cl-find-if (lambda (ov)
152 (overlay-get ov 'flymake--fringe-overlay))
153 (overlays-at beg))
154 (make-overlay beg (1+ beg)))))
155 (let ((ov fringe-overlay))
156 (overlay-put ov 'help-echo
157 (concat tooltip-text "\n"
158 (overlay-get ov 'help-echo)))
159 (overlay-put ov 'before-string
160 (and flymake-fringe-indicator-position
161 (propertize "!" 'display
162 (cons flymake-fringe-indicator-position
163 (if (listp bitmap)
164 bitmap
165 (list bitmap))
166 ))))
167 (overlay-put ov 'evaporate t)
168 (overlay-put ov 'flymake-overlay t)
169 (overlay-put ov 'priority 100)
170 ov)
171 (let ((ov (make-overlay beg end)))
172 (overlay-put ov 'face face)
173 (overlay-put ov 'help-echo
174 (concat tooltip-text "\n"
175 (overlay-get ov 'help-echo)))
176 (overlay-put ov 'evaporate t)
177 (overlay-put ov 'flymake-overlay t)
178 (overlay-put ov 'flymake--diagnostic diag))
179 (cl-loop for i from 0
180 for overlay in
181 (flymake--overlays
182 'flymake--diagnostic
183 (lambda (_ov1 ov2)
184 (flymake-ler-errorp
185 (overlay-get ov2 'flymake--diagnostic)))
186 beg end)
187 do (overlay-put overlay 'priority (+ 100 i)))))
188
189(defun flymake--overlays (&optional filter compare beg end)
190 (cl-remove-if-not 153 (cl-remove-if-not
191 (lambda (ov) 154 (lambda (ov)
192 (and (overlay-get ov 'flymake-overlay) 155 (and (overlay-get ov 'flymake-overlay)
@@ -195,12 +158,13 @@ Make a flymake fringe overlay for the line at BEG, if needed."
195 ((symbolp filter) (overlay-get ov filter)))))) 158 ((symbolp filter) (overlay-get ov filter))))))
196 (save-restriction 159 (save-restriction
197 (widen) 160 (widen)
198 (let ((ovs (overlays-in (or beg (point-min)) 161 (let ((ovs (if (and beg (null end))
199 (or end (point-max))))) 162 (overlays-at beg t)
163 (overlays-in (or beg (point-min))
164 (or end (point-max))))))
200 (if compare 165 (if compare
201 (cl-sort ovs 166 (cl-sort ovs compare :key (or key
202 compare 167 #'identity))
203 :key #'overlay-start)
204 ovs))))) 168 ovs)))))
205 169
206(defun flymake-delete-own-overlays () 170(defun flymake-delete-own-overlays ()
@@ -228,27 +192,167 @@ Make a flymake fringe overlay for the line at BEG, if needed."
228(define-obsolete-face-alias 'flymake-warnline 'flymake-warning "26.1") 192(define-obsolete-face-alias 'flymake-warnline 'flymake-warning "26.1")
229(define-obsolete-face-alias 'flymake-errline 'flymake-error "26.1") 193(define-obsolete-face-alias 'flymake-errline 'flymake-error "26.1")
230 194
195(defun flymake--diag-region (diagnostic)
196 "Return the region (BEG . END) for DIAGNOSTIC.
197Or nil if the region is invalid."
198 ;; FIXME: make this a generic function
199 (condition-case-unless-debug _err
200 (save-excursion
201 (goto-char (point-min))
202 (let ((line (flymake--diag-line diagnostic))
203 (col (flymake--diag-col diagnostic)))
204 (forward-line (1- line))
205 (cl-flet ((fallback-bol
206 () (progn (back-to-indentation) (point)))
207 (fallback-eol
208 (beg)
209 (progn
210 (end-of-line)
211 (skip-chars-backward " \t\f\t\n" beg)
212 (if (eq (point) beg)
213 (line-beginning-position 2)
214 (point)))))
215 (if col
216 (let* ((beg (progn (forward-char (1- col)) (point)))
217 (sexp-end (ignore-errors (end-of-thing 'sexp)))
218 (end (or sexp-end
219 (fallback-eol beg))))
220 (cons (if sexp-end beg (fallback-bol))
221 end))
222 (let* ((beg (fallback-bol))
223 (end (fallback-eol beg)))
224 (cons beg end))))))
225 (error (flymake-log 4 "Invalid region for diagnostic %s")
226 nil)))
227
228(defvar flymake-diagnostic-types-alist
229 `((("e" :error error)
230 . ((flymake-category . flymake-error)))
231 (("w" :warning warning)
232 . ((flymake-category . flymake-warning))))
233 "Alist ((KEY . PROPS)*) of properties of flymake error types.
234KEY can be anything passed as `:type' to `flymake-diag-make', or
235a list of these objects.
236
237PROPS is an alist of properties that are applied, in order, to
238the diagnostics of each type. The recognized properties are:
239
240* Every property pertaining to overlays, except `category' and
241 `evaporate' (see Info Node `(elisp)Overlay Properties'), used
242 affect the appearance of Flymake annotations.
243
244* `bitmap', an image displayed in the fringe according to
245 `flymake-fringe-indicator-position'. The value actually
246 follows the syntax of `flymake-error-bitmap' (which see). It
247 is overriden by any `before-string' overlay property.
248
249* `severity', a non-negative integer specifying the diagnostic's
250 severity. The higher, the more serious. If the overlay
251 priority `priority' is not specified, `severity' is used to set
252 it and help sort overlapping overlays.
253
254* `flymake-category', a symbol whose property list is considered
255 as a default for missing values of any other properties. This
256 is useful to backend authors when creating new diagnostic types
257 that differ from an existing type by only a few properties.")
258
259(put 'flymake-error 'face 'flymake-error)
260(put 'flymake-error 'bitmap flymake-error-bitmap)
261(put 'flymake-error 'severity (warning-numeric-level :error))
262(put 'flymake-error 'mode-line-face 'compilation-error)
263
264(put 'flymake-warning 'face 'flymake-warning)
265(put 'flymake-warning 'bitmap flymake-warning-bitmap)
266(put 'flymake-warning 'severity (warning-numeric-level :warning))
267(put 'flymake-warning 'mode-line-face 'compilation-warning)
268
269(put 'flymake-note 'face 'flymake-note)
270(put 'flymake-note 'bitmap flymake-warning-bitmap)
271(put 'flymake-note 'severity (warning-numeric-level :debug))
272(put 'flymake-note 'mode-line-face 'compilation-info)
273
274(defun flymake--lookup-type-property (type prop &optional default)
275 "Look up PROP for TYPE in `flymake-diagnostic-types-alist'.
276If TYPE doesn't declare PROP in either
277`flymake-diagnostic-types-alist' or its associated category,
278return DEFAULT."
279 (let ((alist-probe (assoc type flymake-diagnostic-types-alist
280 (lambda (entry key)
281 (or (equal key entry)
282 (member key entry))))))
283 (cond (alist-probe
284 (let* ((alist (cdr alist-probe))
285 (prop-probe (assoc prop alist)))
286 (if prop-probe
287 (cdr prop-probe)
288 (if-let* ((cat (assoc-default 'flymake-category alist))
289 (plist (and (symbolp cat)
290 (symbol-plist cat)))
291 (cat-probe (plist-member plist prop)))
292 (cadr cat-probe)
293 default))))
294 (t
295 default))))
296
297(defun flymake--diag-errorp (diag)
298 "Tell if DIAG is a flymake error or something else"
299 (let ((sev (flymake--lookup-type-property 'severity
300 (flymake--diag-type diag)
301 (warning-numeric-level :error))))
302 (>= sev (warning-numeric-level :error))))
303
304(defun flymake--fringe-overlay-spec (bitmap)
305 (and flymake-fringe-indicator-position
306 bitmap
307 (propertize "!" 'display
308 (cons flymake-fringe-indicator-position
309 (if (listp bitmap)
310 bitmap
311 (list bitmap))))))
312
231(defun flymake--highlight-line (diagnostic) 313(defun flymake--highlight-line (diagnostic)
232 "Highlight buffer with info in DIAGNOSTIC. 314 "Highlight buffer with info in DIAGNOSTIC."
233Reuse overlays if necessary 315 (when-let* ((region (flymake--diag-region diagnostic))
234Perhaps use the message text as a hint to enhance highlighting." 316 (ov (make-overlay (car region) (cdr region))))
235 (save-excursion 317 ;; First set `category' in the overlay, then copy over every other
236 (goto-char (point-min)) 318 ;; property.
237 (let ((line-no (flymake-ler-line diagnostic))) 319 ;;
238 (forward-line (1- line-no)) 320 (let ((alist (assoc-default (flymake--diag-type diagnostic)
239 (pcase-let* ((beg (progn (back-to-indentation) (point))) 321 flymake-diagnostic-types-alist)))
240 (end (progn 322 (overlay-put ov 'category (assoc-default 'flymake-category alist))
241 (end-of-line) 323 (cl-loop for (k . v) in alist
242 (skip-chars-backward " \t\f\t\n" beg) 324 unless (eq k 'category)
243 (if (eq (point) beg) 325 do (overlay-put ov k v)))
244 (line-beginning-position 2) 326 ;; Now ensure some essential defaults are set
245 (point)))) 327 ;;
246 (tooltip-text (flymake-ler-text diagnostic)) 328 (cl-flet ((default-maybe
247 (`(,face ,bitmap) 329 (prop value)
248 (if (equal "e" (flymake-ler-type diagnostic)) 330 (unless (or (plist-member (overlay-properties ov) prop)
249 (list 'flymake-errline flymake-error-bitmap) 331 (let ((cat (overlay-get ov
250 (list 'flymake-warnline flymake-warning-bitmap)))) 332 'flymake-category)))
251 (flymake--place-overlay beg end tooltip-text face bitmap diagnostic))))) 333 (and cat
334 (plist-member (symbol-plist cat) prop))))
335 (overlay-put ov prop value))))
336 (default-maybe 'bitmap flymake-error-bitmap)
337 (default-maybe 'before-string
338 (flymake--fringe-overlay-spec
339 (overlay-get ov 'bitmap)))
340 (default-maybe 'help-echo
341 (lambda (_window _ov pos)
342 (mapconcat
343 (lambda (ov)
344 (let ((diag (overlay-get ov 'flymake--diagnostic)))
345 (flymake--diag-text diag)))
346 (flymake--overlays :beg pos)
347 "\n")))
348 (default-maybe 'severity (warning-numeric-level :error))
349 (default-maybe 'priority (+ 100 (overlay-get ov 'severity))))
350 ;; Some properties can't be overriden
351 ;;
352 (overlay-put ov 'evaporate t)
353 (overlay-put ov 'flymake-overlay t)
354 (overlay-put ov 'flymake--diagnostic diagnostic)))
355
252 356
253(defvar-local flymake-is-running nil 357(defvar-local flymake-is-running nil
254 "If t, flymake syntax check process is running for the current buffer.") 358 "If t, flymake syntax check process is running for the current buffer.")
@@ -273,17 +377,17 @@ Perhaps use the message text as a hint to enhance highlighting."
273 "Pop up a menu with errors/warnings for current line." 377 "Pop up a menu with errors/warnings for current line."
274 (interactive (list last-nonmenu-event)) 378 (interactive (list last-nonmenu-event))
275 (let* ((diag-overlays (or 379 (let* ((diag-overlays (or
276 (flymake--overlays 'flymake--diagnostic nil 380 (flymake--overlays :filter 'flymake--diagnostic
277 (line-beginning-position) 381 :beg (line-beginning-position)
278 (line-end-position)) 382 :end (line-end-position))
279 (user-error "No flymake problem for current line"))) 383 (user-error "No flymake problem for current line")))
280 (menu (mapcar (lambda (ov) 384 (menu (mapcar (lambda (ov)
281 (let ((diag (overlay-get ov 'flymake--diagnostic))) 385 (let ((diag (overlay-get ov 'flymake--diagnostic)))
282 (cons (format "%s - %s(%s)" 386 (cons (format "%s - %s(%s)"
283 (flymake-ler-text diag) 387 (flymake--diag-text diag)
284 (or (flymake-ler-file diag) 388 (or (flymake--diag-file diag)
285 "(no file)") 389 "(no file)")
286 (or (flymake-ler-line diag) 390 (or (flymake--diag-line diag)
287 "?")) 391 "?"))
288 ov))) 392 ov)))
289 diag-overlays)) 393 diag-overlays))
@@ -294,8 +398,8 @@ Perhaps use the message text as a hint to enhance highlighting."
294 diag-overlays)) 398 diag-overlays))
295 (title (format "Line %d: %d error(s), %d other(s)" 399 (title (format "Line %d: %d error(s), %d other(s)"
296 (line-number-at-pos) 400 (line-number-at-pos)
297 (cl-count-if #'flymake-ler-errorp diagnostics) 401 (cl-count-if #'flymake--diag-errorp diagnostics)
298 (cl-count-if-not #'flymake-ler-errorp diagnostics))) 402 (cl-count-if-not #'flymake--diag-errorp diagnostics)))
299 (choice (x-popup-menu event (list title (cons "" menu))))) 403 (choice (x-popup-menu event (list title (cons "" menu)))))
300 (flymake-log 3 "choice=%s" choice) 404 (flymake-log 3 "choice=%s" choice)
301 ;; FIXME: What is the point of going to the problem locus if we're 405 ;; FIXME: What is the point of going to the problem locus if we're
@@ -338,8 +442,8 @@ Perhaps use the message text as a hint to enhance highlighting."
338 442
339(defun flymake--fix-line-numbers (diagnostic) 443(defun flymake--fix-line-numbers (diagnostic)
340 "Ensure DIAGNOSTIC has sensible error lines" 444 "Ensure DIAGNOSTIC has sensible error lines"
341 (setf (flymake-ler-line diagnostic) 445 (setf (flymake--diag-line diagnostic)
342 (min (max (flymake-ler-line diagnostic) 446 (min (max (flymake--diag-line diagnostic)
343 1) 447 1)
344 (line-number-at-pos (point-max) 'absolute)))) 448 (line-number-at-pos (point-max) 'absolute))))
345 449
@@ -349,8 +453,8 @@ Perhaps use the message text as a hint to enhance highlighting."
349 (flymake-delete-own-overlays) 453 (flymake-delete-own-overlays)
350 (mapc #'flymake--fix-line-numbers diagnostics) 454 (mapc #'flymake--fix-line-numbers diagnostics)
351 (mapc #'flymake--highlight-line diagnostics) 455 (mapc #'flymake--highlight-line diagnostics)
352 (let ((err-count (cl-count-if #'flymake-ler-errorp diagnostics)) 456 (let ((err-count (cl-count-if #'flymake--diag-errorp diagnostics))
353 (warn-count (cl-count-if-not #'flymake-ler-errorp diagnostics))) 457 (warn-count (cl-count-if-not #'flymake--diag-errorp diagnostics)))
354 (when flymake-check-start-time 458 (when flymake-check-start-time
355 (flymake-log 2 "%s: %d error(s), %d other(s) in %.2f second(s)" 459 (flymake-log 2 "%s: %d error(s), %d other(s) in %.2f second(s)"
356 (buffer-name) err-count warn-count 460 (buffer-name) err-count warn-count
@@ -447,11 +551,12 @@ Perhaps use the message text as a hint to enhance highlighting."
447 "Go to next, or Nth next, flymake error in buffer." 551 "Go to next, or Nth next, flymake error in buffer."
448 (interactive (list 1 t)) 552 (interactive (list 1 t))
449 (let* ((n (or n 1)) 553 (let* ((n (or n 1))
450 (ovs (flymake--overlays 'flymake--diagnostic 554 (ovs (flymake--overlays :filter 'flymake--diagnostic
451 (if (cl-plusp n) #'< #'>))) 555 :compare (if (cl-plusp n) #'< #'>)
452 (chain (cl-member-if (lambda (ov) 556 :key #'overlay-start))
453 (if (cl-plusp n) 557 (chain (cl-member-if (lambda (ov)
454 (> (overlay-start ov) 558 (if (cl-plusp n)
559 (> (overlay-start ov)
455 (point)) 560 (point))
456 (< (overlay-start ov) 561 (< (overlay-start ov)
457 (point)))) 562 (point))))