final tt updates
[emacs-init.git] / elpa / flycheck-20190503.853 / flycheck.el
1 ;;; flycheck.el --- On-the-fly syntax checking -*- lexical-binding: t; -*-
2
3 ;; Copyright (C) 2017-2019 Flycheck contributors
4 ;; Copyright (C) 2012-2016 Sebastian Wiesner and Flycheck contributors
5 ;; Copyright (C) 2013, 2014 Free Software Foundation, Inc.
6 ;;
7 ;; Author: Sebastian Wiesner <swiesner@lunaryorn.com>
8 ;; Maintainer: Clément Pit-Claudel <clement.pitclaudel@live.com>
9 ;;             fmdkdd <fmdkdd@gmail.com>
10 ;; URL: http://www.flycheck.org
11 ;; Keywords: convenience, languages, tools
12 ;; Version: 32-cvs
13 ;; Package-Requires: ((dash "2.12.1") (pkg-info "0.4") (let-alist "1.0.4") (seq "1.11") (emacs "24.3"))
14
15 ;; This file is not part of GNU Emacs.
16
17 ;; This program is free software: you can redistribute it and/or modify
18 ;; it under the terms of the GNU General Public License as published by
19 ;; the Free Software Foundation, either version 3 of the License, or
20 ;; (at your option) any later version.
21
22 ;; This program is distributed in the hope that it will be useful,
23 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
24 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 ;; GNU General Public License for more details.
26
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
29
30 ;;; Commentary:
31
32 ;; On-the-fly syntax checking for GNU Emacs 24.
33 ;;
34 ;; Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs,
35 ;; intended as replacement for the older Flymake extension which is part of GNU
36 ;; Emacs.
37 ;;
38 ;; Flycheck automatically checks buffers for errors while you type, and reports
39 ;; warnings and errors directly in the buffer and in an optional IDE-like error
40 ;; list.
41 ;;
42 ;; It comes with a rich interface for custom syntax checkers and other
43 ;; extensions, and has already many 3rd party extensions adding new features.
44 ;;
45 ;; Please read the online manual at http://www.flycheck.org for more
46 ;; information.  You can open the manual directly from Emacs with `M-x
47 ;; flycheck-manual'.
48 ;;
49 ;; # Setup
50 ;;
51 ;; Flycheck works best on Unix systems.  It does not officially support Windows,
52 ;; but tries to maintain Windows compatibility and should generally work fine on
53 ;; Windows, too.
54 ;;
55 ;; To enable Flycheck add the following to your init file:
56 ;;
57 ;;    (add-hook 'after-init-hook #'global-flycheck-mode)
58 ;;
59 ;; Flycheck will then automatically check buffers in supported languages, as
60 ;; long as all necessary tools are present.  Use `flycheck-verify-setup' to
61 ;; troubleshoot your Flycheck setup.
62
63 ;;; Code:
64
65 (eval-when-compile
66   (require 'let-alist)      ; `let-alist'
67   (require 'compile)        ; Compile Mode integration
68   (require 'jka-compr)      ; To inhibit compression of temp files
69   (require 'pcase)          ; `pcase-dolist' (`pcase' itself is autoloaded)
70   )
71
72 (require 'dash)
73
74 (require 'seq)                   ; Sequence functions
75 (require 'subr-x nil 'no-error)  ; Additional utilities, Emacs 24.4 and upwards
76 (require 'cl-lib)                ; `cl-defstruct' and CL utilities
77 (require 'tabulated-list)        ; To list errors
78 (require 'easymenu)              ; Flycheck Mode menu definition
79 (require 'rx)                    ; Regexp fanciness in `flycheck-define-checker'
80 (require 'help-mode)             ; `define-button-type'
81 (require 'find-func)             ; `find-function-regexp-alist'
82 (require 'json)                  ; `flycheck-parse-tslint'
83
84
85 ;; Declare a bunch of dynamic variables that we need from other modes
86 (defvar sh-shell)                       ; For shell script checker predicates
87 (defvar ess-language)                   ; For r-lintr predicate
88
89 ;; Tell the byte compiler about autoloaded functions from packages
90 (declare-function pkg-info-version-info "pkg-info" (package))
91
92 \f
93 ;;; Compatibility
94 (eval-and-compile
95   (unless (fboundp 'string-suffix-p)
96     ;; TODO: Remove when dropping support for Emacs 24.3 and earlier
97     (defun string-suffix-p (suffix string &optional ignore-case)
98       "Return non-nil if SUFFIX is a suffix of STRING.
99 If IGNORE-CASE is non-nil, the comparison is done without paying
100 attention to case differences."
101       (let ((start-pos (- (length string) (length suffix))))
102         (and (>= start-pos 0)
103              (eq t (compare-strings suffix nil nil
104                                     string start-pos nil ignore-case))))))
105
106   ;; TODO: Remove when dropping support for Emacs 24.3 and earlier
107   (unless (featurep 'subr-x)
108     ;; `subr-x' function for Emacs 24.3 and below
109     (defsubst string-join (strings &optional separator)
110       "Join all STRINGS using SEPARATOR."
111       (mapconcat 'identity strings separator))
112
113     (defsubst string-trim-left (string)
114       "Remove leading whitespace from STRING."
115       (if (string-match "\\`[ \t\n\r]+" string)
116           (replace-match "" t t string)
117         string))
118
119     (defsubst string-trim-right (string)
120       "Remove trailing whitespace from STRING."
121       (if (string-match "[ \t\n\r]+\\'" string)
122           (replace-match "" t t string)
123         string))
124
125     (defsubst string-trim (string)
126       "Remove leading and trailing whitespace from STRING."
127       (string-trim-left (string-trim-right string)))
128
129     (defsubst string-empty-p (string)
130       "Check whether STRING is empty."
131       (string= string ""))))
132
133 \f
134 ;;; Customization
135 (defgroup flycheck nil
136   "Modern on-the-fly syntax checking for GNU Emacs."
137   :prefix "flycheck-"
138   :group 'tools
139   :link '(url-link :tag "Website" "http://www.flycheck.org")
140   :link '(url-link :tag "Github" "https://github.com/flycheck/flycheck"))
141
142 (defgroup flycheck-config-files nil
143   "Configuration files for on-the-fly syntax checkers."
144   :prefix "flycheck-"
145   :group 'flycheck)
146
147 (defgroup flycheck-options nil
148   "Options for on-the-fly syntax checkers."
149   :prefix "flycheck-"
150   :group 'flycheck)
151
152 (defgroup flycheck-executables nil
153   "Executables of syntax checkers."
154   :prefix "flycheck-"
155   :group 'flycheck)
156
157 (defgroup flycheck-faces nil
158   "Faces used by on-the-fly syntax checking."
159   :prefix "flycheck-"
160   :group 'flycheck)
161
162 (defcustom flycheck-checkers
163   '(ada-gnat
164     asciidoctor
165     asciidoc
166     c/c++-clang
167     c/c++-gcc
168     c/c++-cppcheck
169     cfengine
170     chef-foodcritic
171     coffee
172     coffee-coffeelint
173     coq
174     css-csslint
175     css-stylelint
176     cuda-nvcc
177     cwl
178     d-dmd
179     dockerfile-hadolint
180     emacs-lisp
181     emacs-lisp-checkdoc
182     erlang-rebar3
183     erlang
184     eruby-erubis
185     fortran-gfortran
186     go-gofmt
187     go-golint
188     go-vet
189     go-build
190     go-test
191     go-errcheck
192     go-unconvert
193     go-megacheck
194     go-staticcheck
195     groovy
196     haml
197     handlebars
198     haskell-stack-ghc
199     haskell-ghc
200     haskell-hlint
201     html-tidy
202     javascript-eslint
203     javascript-jshint
204     javascript-standard
205     json-jsonlint
206     json-python-json
207     json-jq
208     jsonnet
209     less
210     less-stylelint
211     llvm-llc
212     lua-luacheck
213     lua
214     markdown-markdownlint-cli
215     markdown-mdl
216     nix
217     nix-linter
218     opam
219     perl
220     perl-perlcritic
221     php
222     php-phpmd
223     php-phpcs
224     processing
225     proselint
226     protobuf-protoc
227     pug
228     puppet-parser
229     puppet-lint
230     python-flake8
231     python-pylint
232     python-pycompile
233     python-mypy
234     r-lintr
235     racket
236     rpm-rpmlint
237     rst-sphinx
238     rst
239     ruby-rubocop
240     ruby-reek
241     ruby-rubylint
242     ruby
243     ruby-jruby
244     rust-cargo
245     rust
246     rust-clippy
247     scala
248     scala-scalastyle
249     scheme-chicken
250     scss-lint
251     scss-stylelint
252     sass/scss-sass-lint
253     sass
254     scss
255     sh-bash
256     sh-posix-dash
257     sh-posix-bash
258     sh-zsh
259     sh-shellcheck
260     slim
261     slim-lint
262     sql-sqlint
263     systemd-analyze
264     tcl-nagelfar
265     tex-chktex
266     tex-lacheck
267     texinfo
268     textlint
269     typescript-tslint
270     verilog-verilator
271     vhdl-ghdl
272     xml-xmlstarlet
273     xml-xmllint
274     yaml-jsyaml
275     yaml-ruby)
276   "Syntax checkers available for automatic selection.
277
278 A list of Flycheck syntax checkers to choose from when syntax
279 checking a buffer.  Flycheck will automatically select a suitable
280 syntax checker from this list, unless `flycheck-checker' is set,
281 either directly or with `flycheck-select-checker'.
282
283 You should not need to change this variable normally.  In order
284 to disable syntax checkers, please use
285 `flycheck-disabled-checkers'.  This variable is intended for 3rd
286 party extensions to tell Flycheck about new syntax checkers.
287
288 Syntax checkers in this list must be defined with
289 `flycheck-define-checker'."
290   :group 'flycheck
291   :type '(repeat (symbol :tag "Checker"))
292   :risky t)
293
294 (defcustom flycheck-disabled-checkers nil
295   "Syntax checkers excluded from automatic selection.
296
297 A list of Flycheck syntax checkers to exclude from automatic
298 selection.  Flycheck will never automatically select a syntax
299 checker in this list, regardless of the value of
300 `flycheck-checkers'.
301
302 However, syntax checkers in this list are still available for
303 manual selection with `flycheck-select-checker'.
304
305 Use this variable to disable syntax checkers, instead of removing
306 the syntax checkers from `flycheck-checkers'.  You may also use
307 this option as a file or directory local variable to disable
308 specific checkers in individual files and directories
309 respectively."
310   :group 'flycheck
311   :type '(repeat (symbol :tag "Checker"))
312   :package-version '(flycheck . "0.16")
313   :safe #'flycheck-symbol-list-p)
314 (make-variable-buffer-local 'flycheck-disabled-checkers)
315
316 (defvar-local flycheck-checker nil
317   "Syntax checker to use for the current buffer.
318
319 If unset or nil, automatically select a suitable syntax checker
320 from `flycheck-checkers' on every syntax check.
321
322 If set to a syntax checker only use this syntax checker and never
323 select one from `flycheck-checkers' automatically.  The syntax
324 checker is used regardless of whether it is contained in
325 `flycheck-checkers' or `flycheck-disabled-checkers'.  If the
326 syntax checker is unusable in the current buffer an error is
327 signaled.
328
329 A syntax checker assigned to this variable must be defined with
330 `flycheck-define-checker'.
331
332 Use the command `flycheck-select-checker' to select a syntax
333 checker for the current buffer, or set this variable as file
334 local variable to always use a specific syntax checker for a
335 file.  See Info Node `(emacs)Specifying File Variables' for more
336 information about file variables.")
337 (put 'flycheck-checker 'safe-local-variable 'flycheck-registered-checker-p)
338
339 (defcustom flycheck-locate-config-file-functions nil
340   "Functions to locate syntax checker configuration files.
341
342 Each function in this hook must accept two arguments: The value
343 of the configuration file variable, and the syntax checker
344 symbol.  It must return either a string with an absolute path to
345 the configuration file, or nil, if it cannot locate the
346 configuration file.
347
348 The functions in this hook are called in order of appearance, until a
349 function returns non-nil.  The configuration file returned by that
350 function is then given to the syntax checker if it exists.
351
352 This variable is an abnormal hook.  See Info
353 node `(elisp)Hooks'."
354   :group 'flycheck
355   :type 'hook
356   :risky t)
357
358 (defcustom flycheck-checker-error-threshold 400
359   "Maximum errors allowed per syntax checker.
360
361 The value of this variable is either an integer denoting the
362 maximum number of errors per syntax checker and buffer, or nil to
363 not limit the errors reported from a syntax checker.
364
365 If this variable is a number and a syntax checker reports more
366 errors than the value of this variable, its errors are not
367 discarded, and not highlighted in the buffer or available in the
368 error list.  The affected syntax checker is also disabled for
369 future syntax checks of the buffer."
370   :group 'flycheck
371   :type '(choice (const :tag "Do not limit reported errors" nil)
372                  (integer :tag "Maximum number of errors"))
373   :risky t
374   :package-version '(flycheck . "0.22"))
375
376 (defcustom flycheck-process-error-functions nil
377   "Functions to process errors.
378
379 Each function in this hook must accept a single argument: A
380 Flycheck error to process.
381
382 All functions in this hook are called in order of appearance,
383 until a function returns non-nil.  Thus, a function in this hook
384 may return nil, to allow for further processing of the error, or
385 any non-nil value, to indicate that the error was fully processed
386 and inhibit any further processing.
387
388 The functions are called for each newly parsed error immediately
389 after the corresponding syntax checker finished.  At this stage,
390 the overlays from the previous syntax checks are still present,
391 and there may be further syntax checkers in the chain.
392
393 This variable is an abnormal hook.  See Info
394 node `(elisp)Hooks'."
395   :group 'flycheck
396   :type 'hook
397   :package-version '(flycheck . "0.13")
398   :risky t)
399
400 (defcustom flycheck-display-errors-delay 0.9
401   "Delay in seconds before displaying errors at point.
402
403 Use floating point numbers to express fractions of seconds."
404   :group 'flycheck
405   :type 'number
406   :package-version '(flycheck . "0.15")
407   :safe #'numberp)
408
409 (defcustom flycheck-display-errors-function #'flycheck-display-error-messages
410   "Function to display error messages.
411
412 If set to a function, call the function with the list of errors
413 to display as single argument.  Each error is an instance of the
414 `flycheck-error' struct.
415
416 If set to nil, do not display errors at all."
417   :group 'flycheck
418   :type '(choice (const :tag "Display error messages"
419                         flycheck-display-error-messages)
420                  (const :tag "Display error messages only if no error list"
421                         flycheck-display-error-messages-unless-error-list)
422                  (function :tag "Error display function"))
423   :package-version '(flycheck . "0.13")
424   :risky t)
425
426 (defcustom flycheck-help-echo-function #'flycheck-help-echo-all-error-messages
427   "Function to compute the contents of the error tooltips.
428
429 If set to a function, call the function with the list of errors
430 to display as single argument.  Each error is an instance of the
431 `flycheck-error' struct.  The function is used to set the
432 help-echo property of flycheck error overlays.  It should return
433 a string, which is displayed when the user hovers over an error
434 or presses \\[display-local-help].
435
436 If set to nil, do not show error tooltips."
437   :group 'flycheck
438   :type '(choice (const :tag "Concatenate error messages to form a tooltip"
439                         flycheck-help-echo-all-error-messages)
440                  (function :tag "Help echo function"))
441   :package-version '(flycheck . "0.25")
442   :risky t)
443
444 (defcustom flycheck-command-wrapper-function #'identity
445   "Function to modify checker commands before execution.
446
447 The value of this option is a function which is given a list
448 containing the full command of a syntax checker after
449 substitution through `flycheck-substitute-argument' but before
450 execution.  The function may return a new command for Flycheck to
451 execute.
452
453 The default value is `identity' which does not change the
454 command.  You may provide your own function to run Flycheck
455 commands through `bundle exec', `nix-shell' or similar wrappers."
456   :group 'flycheck
457   :type '(choice (const :tag "Do not modify commands" identity)
458                  (function :tag "Modify command with a custom function"))
459   :package-version '(flycheck . "0.25")
460   :risky t)
461
462 (defcustom flycheck-executable-find #'flycheck-default-executable-find
463   "Function to search for executables.
464
465 The value of this option is a function which is given the name or
466 path of an executable and shall return the full path to the
467 executable, or nil if the executable does not exit.
468
469 The default is `flycheck-default-executable-find', which searches
470 `exec-path' when given a command name, and resolves paths to
471 absolute ones.  You can customize this option to search for
472 checkers in other environments such as bundle or NixOS
473 sandboxes."
474   :group 'flycheck
475   :type '(choice
476           (const :tag "Search executables in `exec-path'"
477                  flycheck-default-executable-find)
478           (function :tag "Search executables with a custom function"))
479   :package-version '(flycheck . "32")
480   :risky t)
481
482 (defun flycheck-default-executable-find (executable)
483   "Resolve EXECUTABLE to a full path.
484
485 Like `executable-find', but supports relative paths.
486
487 Attempts invoking `executable-find' first; if that returns nil,
488 and EXECUTABLE contains a directory component, expands to a full
489 path and tries invoking `executable-find' again."
490   ;; file-name-directory returns non-nil iff the given path has a
491   ;; directory component.
492   (or
493    (executable-find executable)
494    (when (file-name-directory executable)
495      (executable-find (expand-file-name executable)))))
496
497 (defcustom flycheck-indication-mode 'left-fringe
498   "The indication mode for Flycheck errors and warnings.
499
500 This variable controls how Flycheck indicates errors in buffers.
501 May either be `left-fringe', `right-fringe', or nil.
502
503 If set to `left-fringe' or `right-fringe', indicate errors and
504 warnings via icons in the left and right fringe respectively.
505
506 If set to nil, do not indicate errors and warnings, but just
507 highlight them according to `flycheck-highlighting-mode'."
508   :group 'flycheck
509   :type '(choice (const :tag "Indicate in the left fringe" left-fringe)
510                  (const :tag "Indicate in the right fringe" right-fringe)
511                  (const :tag "Do not indicate" nil))
512   :safe #'symbolp)
513
514 (defcustom flycheck-highlighting-mode 'symbols
515   "The highlighting mode for Flycheck errors and warnings.
516
517 The highlighting mode controls how Flycheck highlights errors in
518 buffers.  The following modes are known:
519
520 `columns'
521      Highlight the error column.  If the error does not have a column,
522      highlight the whole line.
523
524 `symbols'
525      Highlight the symbol at the error column, if there is any,
526      otherwise behave like `columns'.  This is the default.
527
528 `sexps'
529      Highlight the expression at the error column, if there is
530      any, otherwise behave like `columns'.  Note that this mode
531      can be *very* slow in some major modes.
532
533 `lines'
534      Highlight the whole line.
535
536 nil
537      Do not highlight errors at all.  However, errors will still
538      be reported in the mode line and in error message popups,
539      and indicated according to `flycheck-indication-mode'."
540   :group 'flycheck
541   :type '(choice (const :tag "Highlight columns only" columns)
542                  (const :tag "Highlight symbols" symbols)
543                  (const :tag "Highlight expressions" sexps)
544                  (const :tag "Highlight whole lines" lines)
545                  (const :tag "Do not highlight errors" nil))
546   :package-version '(flycheck . "0.14")
547   :safe #'symbolp)
548
549 (defcustom flycheck-check-syntax-automatically '(save
550                                                  idle-change
551                                                  new-line
552                                                  mode-enabled)
553   "When Flycheck should check syntax automatically.
554
555 This variable is a list of events that may trigger syntax checks.
556 The following events are known:
557
558 `save'
559      Check syntax immediately after the buffer was saved.
560
561 `idle-change'
562      Check syntax a short time (see `flycheck-idle-change-delay')
563      after the last change to the buffer.
564
565 `idle-buffer-switch'
566      Check syntax a short time (see `flycheck-idle-buffer-switch-delay')
567      after the user switches to a buffer.
568
569 `new-line'
570      Check syntax immediately after a new line was inserted into
571      the buffer.
572
573 `mode-enabled'
574      Check syntax immediately when variable `flycheck-mode' is
575      non-nil.
576
577 Flycheck performs a syntax checks only on events, which are
578 contained in this list.  For instance, if the value of this
579 variable is `(mode-enabled save)', Flycheck will only check if
580 the mode is enabled or the buffer was saved, but never after
581 changes to the buffer contents.
582
583 If nil, never check syntax automatically.  In this case, use
584 `flycheck-buffer' to start a syntax check manually."
585   :group 'flycheck
586   :type '(set (const :tag "After the buffer was saved" save)
587               (const :tag "After the buffer was changed and idle" idle-change)
588               (const
589                :tag "After switching the current buffer" idle-buffer-switch)
590               (const :tag "After a new line was inserted" new-line)
591               (const :tag "After `flycheck-mode' was enabled" mode-enabled))
592   :package-version '(flycheck . "0.12")
593   :safe #'flycheck-symbol-list-p)
594
595 (defcustom flycheck-idle-change-delay 0.5
596   "How many seconds to wait after a change before checking syntax.
597
598 After the buffer was changed, Flycheck will wait as many seconds
599 as the value of this variable before starting a syntax check.  If
600 the buffer is modified during this time, Flycheck will wait
601 again.
602
603 This variable has no effect, if `idle-change' is not contained in
604 `flycheck-check-syntax-automatically'."
605   :group 'flycheck
606   :type 'number
607   :package-version '(flycheck . "0.13")
608   :safe #'numberp)
609
610 (defcustom flycheck-idle-buffer-switch-delay 0.5
611   "How many seconds to wait after switching buffers before checking syntax.
612
613 After the user switches to a new buffer, Flycheck will wait as
614 many seconds as the value of this variable before starting a
615 syntax check.  If the user switches to another buffer during this
616 time, whether a syntax check is still performed depends on the
617 value of `flycheck-buffer-switch-check-intermediate-buffers'.
618
619 This variable has no effect if `idle-buffer-switch' is not
620 contained in `flycheck-check-syntax-automatically'."
621   :group 'flycheck
622   :type 'number
623   :package-version '(flycheck . "32")
624   :safe #'numberp)
625
626 (defcustom flycheck-buffer-switch-check-intermediate-buffers nil
627   "Whether to check syntax in a buffer you only visit briefly.
628
629 If nil, then when you switch to a buffer but switch to another
630 buffer before the syntax check is performed, then the check is
631 canceled.  If non-nil, then syntax checks due to switching
632 buffers are always performed.  This only affects buffer switches
633 that happen less than `flycheck-idle-buffer-switch-delay' seconds
634 apart.
635
636 This variable has no effect if `idle-buffer-switch' is not
637 contained in `flycheck-check-syntax-automatically'."
638   :group 'flycheck
639   :type 'boolean
640   :package-version '(flycheck . "32")
641   :safe #'booleanp)
642
643 (defcustom flycheck-standard-error-navigation t
644   "Whether to support error navigation with `next-error'.
645
646 If non-nil, enable navigation of Flycheck errors with
647 `next-error', `previous-error' and `first-error'.  Otherwise,
648 these functions just navigate errors from compilation modes.
649
650 Flycheck error navigation with `flycheck-next-error',
651 `flycheck-previous-error' and `flycheck-first-error' is always
652 enabled, regardless of the value of this variable.
653
654 Note that this setting only takes effect when variable
655 `flycheck-mode' is non-nil.  Changing it will not affect buffers
656 where variable `flycheck-mode' is already non-nil."
657   :group 'flycheck
658   :type 'boolean
659   :package-version '(flycheck . "0.15")
660   :safe #'booleanp)
661
662 (define-widget 'flycheck-minimum-level 'lazy
663   "A radio-type choice of minimum error levels.
664
665 See `flycheck-navigation-minimum-level' and
666 `flycheck-error-list-minimum-level'."
667   :type '(radio (const :tag "All locations" nil)
668                 (const :tag "Informational messages" info)
669                 (const :tag "Warnings" warning)
670                 (const :tag "Errors" error)
671                 (symbol :tag "Custom error level")))
672
673 (defcustom flycheck-navigation-minimum-level nil
674   "The minimum level of errors to navigate.
675
676 If set to an error level, only navigate errors whose error level
677 is at least as severe as this one.  If nil, navigate all errors."
678   :group 'flycheck
679   :type 'flycheck-minimum-level
680   :safe #'flycheck-error-level-p
681   :package-version '(flycheck . "0.21"))
682
683 (defcustom flycheck-error-list-minimum-level nil
684   "The minimum level of errors to display in the error list.
685
686 If set to an error level, only display errors whose error level
687 is at least as severe as this one in the error list.  If nil,
688 display all errors.
689
690 This is the default level, used when the error list is opened.
691 You can temporarily change the level using
692 \\[flycheck-error-list-set-filter], or reset it to this value
693 using \\[flycheck-error-list-reset-filter]."
694   :group 'flycheck
695   :type 'flycheck-minimum-level
696   :safe #'flycheck-error-level-p
697   :package-version '(flycheck . "0.24"))
698
699 (defcustom flycheck-relevant-error-other-file-minimum-level 'error
700   "The minimum level of errors from other files to display in this buffer.
701
702 If set to an error level, only display errors from other files
703 whose error level is at least as severe as this one.  If nil,
704 display all errors from other files."
705   :group 'flycheck
706   :type 'flycheck-minimum-level
707   :safe #'flycheck-error-level-p
708   :package-version '(flycheck . "32"))
709
710 (defcustom flycheck-completing-read-function #'completing-read
711   "Function to read from minibuffer with completion.
712
713 The function must be compatible to the built-in `completing-read'
714 function."
715   :group 'flycheck
716   :type '(choice (const :tag "Default" completing-read)
717                  (const :tag "IDO" ido-completing-read)
718                  (function :tag "Custom function"))
719   :risky t
720   :package-version '(flycheck . "26"))
721
722 (defcustom flycheck-temp-prefix "flycheck"
723   "Prefix for temporary files created by Flycheck."
724   :group 'flycheck
725   :type 'string
726   :package-version '(flycheck . "0.19")
727   :risky t)
728
729 (defcustom flycheck-mode-hook nil
730   "Hooks to run after command `flycheck-mode' is toggled."
731   :group 'flycheck
732   :type 'hook
733   :risky t)
734
735 (defcustom flycheck-after-syntax-check-hook nil
736   "Functions to run after each syntax check.
737
738 This hook is run after a syntax check was finished.
739
740 At this point, *all* chained checkers were run, and all errors
741 were parsed, highlighted and reported.  The variable
742 `flycheck-current-errors' contains all errors from all syntax
743 checkers run during the syntax check, so you can apply any error
744 analysis functions.
745
746 Note that this hook does *not* run after each individual syntax
747 checker in the syntax checker chain, but only after the *last
748 checker*.
749
750 This variable is a normal hook.  See Info node `(elisp)Hooks'."
751   :group 'flycheck
752   :type 'hook
753   :risky t)
754
755 (defcustom flycheck-before-syntax-check-hook nil
756   "Functions to run before each syntax check.
757
758 This hook is run right before a syntax check starts.
759
760 Error information from the previous syntax check is *not*
761 cleared before this hook runs.
762
763 Note that this hook does *not* run before each individual syntax
764 checker in the syntax checker chain, but only before the *first
765 checker*.
766
767 This variable is a normal hook.  See Info node `(elisp)Hooks'."
768   :group 'flycheck
769   :type 'hook
770   :risky t)
771
772 (defcustom flycheck-syntax-check-failed-hook nil
773   "Functions to run if a syntax check failed.
774
775 This hook is run whenever an error occurs during Flycheck's
776 internal processing.  No information about the error is given to
777 this hook.
778
779 You should use this hook to conduct additional cleanup actions
780 when Flycheck failed.
781
782 This variable is a normal hook.  See Info node `(elisp)Hooks'."
783   :group 'flycheck
784   :type 'hook
785   :risky t)
786
787 (defcustom flycheck-status-changed-functions nil
788   "Functions to run if the Flycheck status changed.
789
790 This hook is run whenever the status of Flycheck changes.  Each
791 hook function takes the status symbol as single argument, as
792 given to `flycheck-report-status', which see.
793
794 This variable is an abnormal hook.  See Info
795 node `(elisp)Hooks'."
796   :group 'flycheck
797   :type 'hook
798   :risky t
799   :package-version '(flycheck . "0.20"))
800
801 (defcustom flycheck-error-list-after-refresh-hook nil
802   "Functions to run after the error list was refreshed.
803
804 This hook is run whenever the error list is refreshed.
805
806 This variable is a normal hook.  See Info node `(elisp)Hooks'."
807   :group 'flycheck
808   :type 'hook
809   :risky t
810   :package-version '(flycheck . "0.21"))
811
812 (defface flycheck-error
813   '((((supports :underline (:style wave)))
814      :underline (:style wave :color "Red1"))
815     (t
816      :underline t :inherit error))
817   "Flycheck face for errors."
818   :package-version '(flycheck . "0.13")
819   :group 'flycheck-faces)
820
821 (defface flycheck-warning
822   '((((supports :underline (:style wave)))
823      :underline (:style wave :color "DarkOrange"))
824     (t
825      :underline t :inherit warning))
826   "Flycheck face for warnings."
827   :package-version '(flycheck . "0.13")
828   :group 'flycheck-faces)
829
830 (defface flycheck-info
831   '((((supports :underline (:style wave)))
832      :underline (:style wave :color "ForestGreen"))
833     (t
834      :underline t :inherit success))
835   "Flycheck face for informational messages."
836   :package-version '(flycheck . "0.15")
837   :group 'flycheck-faces)
838
839 (defface flycheck-fringe-error
840   '((t :inherit error))
841   "Flycheck face for fringe error indicators."
842   :package-version '(flycheck . "0.13")
843   :group 'flycheck-faces)
844
845 (defface flycheck-fringe-warning
846   '((t :inherit warning))
847   "Flycheck face for fringe warning indicators."
848   :package-version '(flycheck . "0.13")
849   :group 'flycheck-faces)
850
851 (defface flycheck-fringe-info
852   ;; Semantically `success' is probably not the right face, but it looks nice as
853   ;; a base face
854   '((t :inherit success))
855   "Flycheck face for fringe info indicators."
856   :package-version '(flycheck . "0.15")
857   :group 'flycheck-faces)
858
859 (defface flycheck-error-list-error
860   '((t :inherit error))
861   "Flycheck face for error messages in the error list."
862   :package-version '(flycheck . "0.16")
863   :group 'flycheck-faces)
864
865 (defface flycheck-error-list-warning
866   '((t :inherit warning))
867   "Flycheck face for warning messages in the error list."
868   :package-version '(flycheck . "0.16")
869   :group 'flycheck-faces)
870
871 (defface flycheck-error-list-info
872   '((t :inherit success))
873   "Flycheck face for info messages in the error list."
874   :package-version '(flycheck . "0.16")
875   :group 'flycheck-faces)
876
877 ;; The base faces for the following two faces are inspired by Compilation Mode
878 (defface flycheck-error-list-line-number
879   '((t :inherit font-lock-constant-face))
880   "Face for line numbers in the error list."
881   :group 'flycheck-faces
882   :package-version '(flycheck . "0.16"))
883
884 (defface flycheck-error-list-column-number
885   '((t :inherit font-lock-constant-face))
886   "Face for line numbers in the error list."
887   :group 'flycheck-faces
888   :package-version '(flycheck . "0.16"))
889
890 (defface flycheck-error-list-filename
891   '((t :inherit font-lock-variable-name-face))
892   "Face for filenames in the error list."
893   :group 'flycheck-faces
894   :package-version '(flycheck . "32"))
895
896 (defface flycheck-error-list-id
897   '((t :inherit font-lock-type-face))
898   "Face for the error ID in the error list."
899   :group 'flycheck-faces
900   :package-version '(flycheck . "0.22"))
901
902 (defface flycheck-error-list-id-with-explainer
903   '((t :inherit flycheck-error-list-id
904        :box (:style released-button)))
905   "Face for the error ID in the error list, for errors that have an explainer."
906   :group 'flycheck-faces
907   :package-version '(flycheck . "30"))
908
909 (defface flycheck-error-list-checker-name
910   '((t :inherit font-lock-function-name-face))
911   "Face for the syntax checker name in the error list."
912   :group 'flycheck-faces
913   :package-version '(flycheck . "0.21"))
914
915 (defface flycheck-error-list-highlight
916   '((t :inherit highlight))
917   "Flycheck face to highlight errors in the error list."
918   :package-version '(flycheck . "0.15")
919   :group 'flycheck-faces)
920
921 (defface flycheck-verify-select-checker
922   '((t :box (:style released-button)))
923   "Flycheck face for the 'select' button in the verify setup buffer."
924   :package-version '(flycheck . "32")
925   :group 'flycheck-faces)
926
927 (defvar flycheck-command-map
928   (let ((map (make-sparse-keymap)))
929     (define-key map "c"         #'flycheck-buffer)
930     (define-key map "C"         #'flycheck-clear)
931     (define-key map (kbd "C-c") #'flycheck-compile)
932     (define-key map "n"         #'flycheck-next-error)
933     (define-key map "p"         #'flycheck-previous-error)
934     (define-key map "l"         #'flycheck-list-errors)
935     (define-key map (kbd "C-w") #'flycheck-copy-errors-as-kill)
936     (define-key map "s"         #'flycheck-select-checker)
937     (define-key map "?"         #'flycheck-describe-checker)
938     (define-key map "h"         #'flycheck-display-error-at-point)
939     (define-key map "e"         #'flycheck-explain-error-at-point)
940     (define-key map "H"         #'display-local-help)
941     (define-key map "i"         #'flycheck-manual)
942     (define-key map "V"         #'flycheck-version)
943     (define-key map "v"         #'flycheck-verify-setup)
944     (define-key map "x"         #'flycheck-disable-checker)
945     map)
946   "Keymap of Flycheck interactive commands.")
947
948 (defcustom flycheck-keymap-prefix (kbd "C-c !")
949   "Prefix for key bindings of Flycheck.
950
951 Changing this variable outside Customize does not have any
952 effect.  To change the keymap prefix from Lisp, you need to
953 explicitly re-define the prefix key:
954
955     (define-key flycheck-mode-map flycheck-keymap-prefix nil)
956     (setq flycheck-keymap-prefix (kbd \"C-c f\"))
957     (define-key flycheck-mode-map flycheck-keymap-prefix
958                 flycheck-command-map)
959
960 Please note that Flycheck's manual documents the default
961 keybindings.  Changing this variable is at your own risk."
962   :group 'flycheck
963   :package-version '(flycheck . "0.19")
964   :type 'string
965   :risky t
966   :set
967   (lambda (variable key)
968     (when (and (boundp variable) (boundp 'flycheck-mode-map))
969       (define-key flycheck-mode-map (symbol-value variable) nil)
970       (define-key flycheck-mode-map key flycheck-command-map))
971     (set-default variable key)))
972
973 (defcustom flycheck-mode-line '(:eval (flycheck-mode-line-status-text))
974   "Mode line lighter for Flycheck.
975
976 The value of this variable is a mode line template as in
977 `mode-line-format'.  See Info Node `(elisp)Mode Line Format' for
978 more information.  Note that it should contain a _single_ mode
979 line construct only.
980
981 Customize this variable to change how Flycheck reports its status
982 in the mode line.  You may use `flycheck-mode-line-status-text'
983 to obtain a human-readable status text, including an
984 error/warning count.
985
986 You may also assemble your own status text.  The current status
987 of Flycheck is available in `flycheck-last-status-change'.  The
988 errors in the current buffer are stored in
989 `flycheck-current-errors', and the function
990 `flycheck-count-errors' may be used to obtain the number of
991 errors grouped by error level.
992
993 Set this variable to nil to disable the mode line completely."
994   :group 'flycheck
995   :type 'sexp
996   :risky t
997   :package-version '(flycheck . "0.20"))
998
999 (defcustom flycheck-mode-line-prefix "FlyC"
1000   "Base mode line lighter for Flycheck.
1001
1002 This will have an effect only with the default
1003 `flycheck-mode-line'.
1004
1005 If you've customized `flycheck-mode-line' then the customized
1006 function must be updated to use this variable."
1007   :group 'flycheck
1008   :type 'string
1009   :package-version '(flycheck . "26"))
1010
1011 (defcustom flycheck-error-list-mode-line
1012   `(,(propertized-buffer-identification "%12b")
1013     " for buffer "
1014     (:eval (flycheck-error-list-propertized-source-name))
1015     (:eval (flycheck-error-list-mode-line-filter-indicator)))
1016   "Mode line construct for Flycheck error list.
1017
1018 The value of this variable is a mode line template as in
1019 `mode-line-format', to be used as
1020 `mode-line-buffer-identification' in `flycheck-error-list-mode'.
1021 See Info Node `(elisp)Mode Line Format' for more information.
1022
1023 Customize this variable to change how the error list appears in
1024 the mode line.  The default shows the name of the buffer and the
1025 name of the source buffer, i.e. the buffer whose errors are
1026 currently listed."
1027   :group 'flycheck
1028   :type 'sexp
1029   :risky t
1030   :package-version '(flycheck . "0.20"))
1031
1032 (defcustom flycheck-global-modes t
1033   "Modes for which option `flycheck-mode' is turned on.
1034
1035 If t, Flycheck Mode is turned on for all major modes.  If a list,
1036 Flycheck Mode is turned on for all `major-mode' symbols in that
1037 list.  If the `car' of the list is `not', Flycheck Mode is turned
1038 on for all `major-mode' symbols _not_ in that list.  If nil,
1039 Flycheck Mode is never turned on by command
1040 `global-flycheck-mode'.
1041
1042 Note that Flycheck is never turned on for modes whose
1043 `mode-class' property is `special' (see Info node `(elisp)Major
1044 Mode Conventions'), regardless of the value of this option.
1045
1046 Only has effect when variable `global-flycheck-mode' is non-nil."
1047   :group 'flycheck
1048   :type '(choice (const :tag "none" nil)
1049                  (const :tag "all" t)
1050                  (set :menu-tag "mode specific" :tag "modes"
1051                       :value (not)
1052                       (const :tag "Except" not)
1053                       (repeat :inline t (symbol :tag "mode"))))
1054   :risky t
1055   :package-version '(flycheck . "0.23"))
1056
1057 ;; Add built-in functions to our hooks, via `add-hook', to make sure that our
1058 ;; functions are really present, even if the variable was implicitly defined by
1059 ;; another call to `add-hook' that occurred before Flycheck was loaded.  See
1060 ;; http://lists.gnu.org/archive/html/emacs-devel/2015-02/msg01271.html for why
1061 ;; we don't initialize the hook variables right away.  We append our own
1062 ;; functions, because a user likely expects that their functions come first,
1063 ;; even if the added them before Flycheck was loaded.
1064 (dolist (hook (list #'flycheck-locate-config-file-by-path
1065                     #'flycheck-locate-config-file-ancestor-directories
1066                     #'flycheck-locate-config-file-home))
1067   (add-hook 'flycheck-locate-config-file-functions hook 'append))
1068
1069 (add-hook 'flycheck-process-error-functions #'flycheck-add-overlay 'append)
1070
1071 \f
1072 ;;; Global Flycheck menu
1073 (defvar flycheck-mode-menu-map
1074   (easy-menu-create-menu
1075    "Syntax Checking"
1076    '(["Enable on-the-fly syntax checking" flycheck-mode
1077       :style toggle :selected flycheck-mode
1078       :enable (or flycheck-mode
1079                   ;; Don't let users toggle the mode if there is no syntax
1080                   ;; checker for this buffer
1081                   (seq-find #'flycheck-checker-supports-major-mode-p
1082                             flycheck-checkers))]
1083      ["Check current buffer" flycheck-buffer flycheck-mode]
1084      ["Clear errors in buffer" flycheck-clear t]
1085      "---"
1086      ["Go to next error" flycheck-next-error flycheck-mode]
1087      ["Go to previous error" flycheck-previous-error flycheck-mode]
1088      ["Show all errors" flycheck-list-errors flycheck-mode]
1089      "---"
1090      ["Copy messages at point" flycheck-copy-errors-as-kill
1091       (flycheck-overlays-at (point))]
1092      ["Explain error at point" flycheck-explain-error-at-point]
1093      "---"
1094      ["Select syntax checker" flycheck-select-checker flycheck-mode]
1095      ["Disable syntax checker" flycheck-disable-checker flycheck-mode]
1096      ["Set executable of syntax checker" flycheck-set-checker-executable
1097       flycheck-mode]
1098      "---"
1099      ["Describe syntax checker" flycheck-describe-checker t]
1100      ["Show Flycheck version" flycheck-version t]
1101      ["Read the Flycheck manual" flycheck-info t]))
1102   "Menu of command `flycheck-mode'.")
1103
1104 (easy-menu-add-item nil '("Tools") flycheck-mode-menu-map "Spell Checking")
1105
1106 \f
1107 ;;; Version information, manual and loading of Flycheck
1108 (defun flycheck-version (&optional show-version)
1109   "Get the Flycheck version as string.
1110
1111 If called interactively or if SHOW-VERSION is non-nil, show the
1112 version in the echo area and the messages buffer.
1113
1114 The returned string includes both, the version from package.el
1115 and the library version, if both a present and different.
1116
1117 If the version number could not be determined, signal an error,
1118 if called interactively, or if SHOW-VERSION is non-nil, otherwise
1119 just return nil."
1120   (interactive (list t))
1121   (let ((version (pkg-info-version-info 'flycheck)))
1122     (when show-version
1123       (message "Flycheck version: %s" version))
1124     version))
1125
1126 (defun flycheck-unload-function ()
1127   "Unload function for Flycheck."
1128   (global-flycheck-mode -1)
1129   (easy-menu-remove-item nil '("Tools") (cadr flycheck-mode-menu-map))
1130   (remove-hook 'kill-emacs-hook #'flycheck-global-teardown)
1131   (setq find-function-regexp-alist
1132         (assq-delete-all 'flycheck-checker find-function-regexp-alist)))
1133
1134 ;;;###autoload
1135 (defun flycheck-manual ()
1136   "Open the Flycheck manual."
1137   (interactive)
1138   (browse-url "http://www.flycheck.org"))
1139
1140 (define-obsolete-function-alias 'flycheck-info
1141   'flycheck-manual "26" "Open the Flycheck manual.")
1142
1143 \f
1144 ;;; Utility functions
1145 (defun flycheck-sexp-to-string (sexp)
1146   "Convert SEXP to a string.
1147
1148 Like `prin1-to-string' but ensure that the returned string
1149 is loadable."
1150   (let ((print-quoted t)
1151         (print-length nil)
1152         (print-level nil))
1153     (prin1-to-string sexp)))
1154
1155 (defun flycheck-string-to-number-safe (string)
1156   "Safely convert STRING to a number.
1157
1158 If STRING is of string type and a numeric string, convert STRING
1159 to a number and return it.  Otherwise return nil."
1160   (let ((number-re (rx string-start (one-or-more (any digit)) string-end)))
1161     (when (and (stringp string) (string-match-p number-re string))
1162       (string-to-number string))))
1163
1164 (defun flycheck-string-list-p (obj)
1165   "Determine if OBJ is a list of strings."
1166   (and (listp obj) (seq-every-p #'stringp obj)))
1167
1168 (defun flycheck-symbol-list-p (obj)
1169   "Determine if OBJ is a list of symbols."
1170   (and (listp obj) (seq-every-p #'symbolp obj)))
1171
1172 (defun flycheck-same-files-p (file-a file-b)
1173   "Determine whether FILE-A and FILE-B refer to the same file."
1174   (let ((file-a (expand-file-name file-a))
1175         (file-b (expand-file-name file-b)))
1176     ;; We must resolve symbolic links here, since some syntax checker always
1177     ;; output canonical file names with all symbolic links resolved.  However,
1178     ;; we still do a simple path compassion first, to avoid the comparatively
1179     ;; expensive file system call if possible.  See
1180     ;; https://github.com/flycheck/flycheck/issues/561
1181     (or (string= (directory-file-name file-a) (directory-file-name file-b))
1182         (string= (directory-file-name (file-truename file-a))
1183                  (directory-file-name (file-truename file-b))))))
1184
1185 (defvar-local flycheck-temporaries nil
1186   "Temporary files and directories created by Flycheck.")
1187
1188 (defun flycheck-temp-dir-system ()
1189   "Create a unique temporary directory.
1190
1191 Use `flycheck-temp-prefix' as prefix, and add the directory to
1192 `flycheck-temporaries'.
1193
1194 Return the path of the directory"
1195   (let* ((tempdir (make-temp-file flycheck-temp-prefix 'directory)))
1196     (push tempdir flycheck-temporaries)
1197     tempdir))
1198
1199 (defun flycheck-temp-file-system (filename)
1200   "Create a temporary file named after FILENAME.
1201
1202 If FILENAME is non-nil, this function creates a temporary
1203 directory with `flycheck-temp-dir-system', and creates a file
1204 with the same name as FILENAME in this directory.
1205
1206 Otherwise this function creates a temporary file with
1207 `flycheck-temp-prefix' and a random suffix.  The path of the file
1208 is added to `flycheck-temporaries'.
1209
1210 Return the path of the file."
1211   (let ((tempfile (convert-standard-filename
1212                    (if filename
1213                        (expand-file-name (file-name-nondirectory filename)
1214                                          (flycheck-temp-dir-system))
1215                      (make-temp-file flycheck-temp-prefix)))))
1216     (push tempfile flycheck-temporaries)
1217     tempfile))
1218
1219 (defun flycheck-temp-file-inplace (filename)
1220   "Create an in-place copy of FILENAME.
1221
1222 Prefix the file with `flycheck-temp-prefix' and add the path of
1223 the file to `flycheck-temporaries'.
1224
1225 If FILENAME is nil, fall back to `flycheck-temp-file-system'.
1226
1227 Return the path of the file."
1228   (if filename
1229       (let* ((tempname (format "%s_%s"
1230                                flycheck-temp-prefix
1231                                (file-name-nondirectory filename)))
1232              (tempfile (convert-standard-filename
1233                         (expand-file-name tempname
1234                                           (file-name-directory filename)))))
1235         (push tempfile flycheck-temporaries)
1236         tempfile)
1237     (flycheck-temp-file-system filename)))
1238
1239 (defun flycheck-temp-directory (checker)
1240   "Return the directory where CHECKER writes temporary files.
1241
1242 Return nil if the CHECKER does not write temporary files."
1243   (let ((args (flycheck-checker-arguments checker)))
1244     (cond
1245      ((memq 'source args) temporary-file-directory)
1246      ((memq 'source-inplace args)
1247       (if buffer-file-name (file-name-directory buffer-file-name)
1248         temporary-file-directory))
1249      (t nil))))
1250
1251 (defun flycheck-temp-files-writable-p (checker)
1252   "Whether CHECKER can write temporary files.
1253
1254 If CHECKER has `source' or `source-inplace' in its `:command',
1255 return whether flycheck has the permissions to create the
1256 respective temporary files.
1257
1258 Return t if CHECKER does not use temporary files."
1259   (let ((dir (flycheck-temp-directory checker)))
1260     (or (not dir) (file-writable-p dir))))
1261
1262 (defun flycheck-save-buffer-to-file (file-name)
1263   "Save the contents of the current buffer to FILE-NAME."
1264   (make-directory (file-name-directory file-name) t)
1265   (let ((jka-compr-inhibit t))
1266     (write-region nil nil file-name nil 0)))
1267
1268 (defun flycheck-save-buffer-to-temp (temp-file-fn)
1269   "Save buffer to temp file returned by TEMP-FILE-FN.
1270
1271 Return the name of the temporary file."
1272   (let ((filename (funcall temp-file-fn (buffer-file-name))))
1273     ;; Do not flush short-lived temporary files onto disk
1274     (let ((write-region-inhibit-fsync t))
1275       (flycheck-save-buffer-to-file filename))
1276     filename))
1277
1278 (defun flycheck-prepend-with-option (option items &optional prepend-fn)
1279   "Prepend OPTION to each item in ITEMS, using PREPEND-FN.
1280
1281 Prepend OPTION to each item in ITEMS.
1282
1283 ITEMS is a list of strings to pass to the syntax checker.  OPTION
1284 is the option, as string.  PREPEND-FN is a function called to
1285 prepend OPTION to each item in ITEMS.  It receives the option and
1286 a single item from ITEMS as argument, and must return a string or
1287 a list of strings with OPTION prepended to the item.  If
1288 PREPEND-FN is nil or omitted, use `list'.
1289
1290 Return a list of strings where OPTION is prepended to each item
1291 in ITEMS using PREPEND-FN.  If PREPEND-FN returns a list, it is
1292 spliced into the resulting list."
1293   (unless (stringp option)
1294     (error "Option %S is not a string" option))
1295   (unless prepend-fn
1296     (setq prepend-fn #'list))
1297   (let ((prepend
1298          (lambda (item)
1299            (let ((result (funcall prepend-fn option item)))
1300              (cond
1301               ((and (listp result) (seq-every-p #'stringp result)) result)
1302               ((stringp result) (list result))
1303               (t (error "Invalid result type for option: %S" result)))))))
1304     (apply #'append (seq-map prepend items))))
1305
1306 (defun flycheck-find-in-buffer (pattern)
1307   "Find PATTERN in the current buffer.
1308
1309 Return the result of the first matching group of PATTERN, or nil,
1310 if PATTERN did not match."
1311   (save-restriction
1312     (widen)
1313     (save-excursion
1314       (goto-char (point-min))
1315       (when (re-search-forward pattern nil 'no-error)
1316         (match-string-no-properties 1)))))
1317
1318 (defun flycheck-buffer-empty-p (&optional buffer)
1319   "Whether a BUFFER is empty.
1320
1321 If buffer is nil or omitted check the current buffer.
1322
1323 Return non-nil if so, or nil if the buffer has content."
1324   (<= (buffer-size buffer) 0))
1325
1326 (defun flycheck-ephemeral-buffer-p ()
1327   "Determine whether the current buffer is an ephemeral buffer.
1328
1329 See Info node `(elisp)Buffer Names' for information about
1330 ephemeral buffers."
1331   (string-prefix-p " " (buffer-name)))
1332
1333 (defun flycheck-encrypted-buffer-p ()
1334   "Determine whether the current buffer is an encrypted file.
1335
1336 See Info node `(epa)Top' for Emacs' interface to encrypted
1337 files."
1338   ;; The EPA file handler sets this variable locally to remember the recipients
1339   ;; of the encrypted file for re-encryption.  Hence, a local binding of this
1340   ;; variable is a good indication that the buffer is encrypted.  I haven't
1341   ;; found any better indicator anyway.
1342   (local-variable-p 'epa-file-encrypt-to))
1343
1344 (defun flycheck-autoloads-file-p ()
1345   "Determine whether the current buffer is an autoloads file.
1346
1347 Autoloads are generated by package.el during installation."
1348   (string-suffix-p "-autoloads.el" (buffer-name)))
1349
1350 (defun flycheck-in-user-emacs-directory-p (filename)
1351   "Whether FILENAME is in `user-emacs-directory'."
1352   (string-prefix-p (file-name-as-directory (file-truename user-emacs-directory))
1353                    (file-truename filename)))
1354
1355 (defun flycheck-safe-delete (file-or-dir)
1356   "Safely delete FILE-OR-DIR."
1357   (ignore-errors
1358     (if (file-directory-p file-or-dir)
1359         (delete-directory file-or-dir 'recursive)
1360       (delete-file file-or-dir))))
1361
1362 (defun flycheck-safe-delete-temporaries ()
1363   "Safely delete all temp files and directories of Flycheck.
1364
1365 Safely delete all files and directories listed in
1366 `flycheck-temporaries' and set the variable's value to nil."
1367   (seq-do #'flycheck-safe-delete flycheck-temporaries)
1368   (setq flycheck-temporaries nil))
1369
1370 (defun flycheck-rx-file-name (form)
1371   "Translate the `(file-name)' FORM into a regular expression."
1372   (let ((body (or (cdr form) '((minimal-match
1373                                 (one-or-more not-newline))))))
1374     (rx-submatch-n `(group-n 1 ,@body))))
1375
1376 (defun flycheck-rx-message (form)
1377   "Translate the `(message)' FORM into a regular expression."
1378   (let ((body (or (cdr form) '((one-or-more not-newline)))))
1379     (rx-submatch-n `(group-n 4 ,@body))))
1380
1381 (defun flycheck-rx-id (form)
1382   "Translate the `(id)' FORM into a regular expression."
1383   (rx-submatch-n `(group-n 5 ,@(cdr form))))
1384
1385 (defun flycheck-rx-to-string (form &optional no-group)
1386   "Like `rx-to-string' for FORM, but with special keywords:
1387
1388 `line'
1389      matches the line number.
1390
1391 `column'
1392      matches the column number.
1393
1394 `(file-name SEXP ...)'
1395      matches the file name.  SEXP describes the file name.  If no
1396      SEXP is given, use a default body of `(minimal-match
1397      (one-or-more not-newline))'.
1398
1399 `(message SEXP ...)'
1400      matches the message.  SEXP constitutes the body of the
1401      message.  If no SEXP is given, use a default body
1402      of `(one-or-more not-newline)'.
1403
1404 `(id SEXP ...)'
1405      matches an error ID.  SEXP describes the ID.
1406
1407 NO-GROUP is passed to `rx-to-string'.
1408
1409 See `rx' for a complete list of all built-in `rx' forms."
1410   (let ((rx-constituents
1411          (append
1412           `((line . ,(rx (group-n 2 (one-or-more digit))))
1413             (column . ,(rx (group-n 3 (one-or-more digit))))
1414             (file-name flycheck-rx-file-name 0 nil)
1415             (message flycheck-rx-message 0 nil)
1416             (id flycheck-rx-id 0 nil))
1417           rx-constituents nil)))
1418     (rx-to-string form no-group)))
1419
1420 (defun flycheck-current-load-file ()
1421   "Get the source file currently being loaded.
1422
1423 Always return the name of the corresponding source file, never
1424 any byte-compiled file.
1425
1426 Return nil, if the currently loaded file cannot be determined."
1427   (-when-let* ((this-file (cond
1428                            (load-in-progress load-file-name)
1429                            ((bound-and-true-p byte-compile-current-file))
1430                            (t (buffer-file-name))))
1431                ;; A best guess for the source file of a compiled library. Works
1432                ;; well in most cases, and especially for ELPA packages
1433                (source-file (concat (file-name-sans-extension this-file)
1434                                     ".el")))
1435     (when (file-exists-p source-file)
1436       source-file)))
1437
1438 (defun flycheck-module-root-directory (module &optional file-name)
1439   "Get the root directory for a MODULE in FILE-NAME.
1440
1441 MODULE is a qualified module name, either a string with
1442 components separated by a dot, or as list of components.
1443 FILE-NAME is the name of the file or directory containing the
1444 module as string.  When nil or omitted, defaults to the return
1445 value of function `buffer-file-name'.
1446
1447 Return the root directory of the module, that is, the directory,
1448 from which FILE-NAME can be reached by descending directories
1449 along each part of MODULE.
1450
1451 If the MODULE name does not match the directory hierarchy upwards
1452 from FILE-NAME, return the directory containing FILE-NAME.  When
1453 FILE-NAME is nil, return `default-directory'."
1454   (let ((file-name (or file-name (buffer-file-name)))
1455         (module-components (if (stringp module)
1456                                (split-string module (rx "."))
1457                              (copy-sequence module))))
1458     (if (and module-components file-name)
1459         (let ((parts (nreverse module-components))
1460               (base-directory (directory-file-name
1461                                (file-name-sans-extension file-name))))
1462           (while (and parts
1463                       (string= (file-name-nondirectory base-directory)
1464                                (car parts)))
1465             (pop parts)
1466             (setq base-directory (directory-file-name
1467                                   (file-name-directory base-directory))))
1468           (file-name-as-directory base-directory))
1469       (if file-name
1470           (file-name-directory file-name)
1471         (expand-file-name default-directory)))))
1472
1473 \f
1474 ;;; Minibuffer tools
1475 (defvar read-flycheck-checker-history nil
1476   "`completing-read' history of `read-flycheck-checker'.")
1477
1478 (defun flycheck-completing-read (prompt candidates default &optional history)
1479   "Read a value from the minibuffer.
1480
1481 Use `flycheck-completing-read-function' to read input from the
1482 minibuffer with completion.
1483
1484 Show PROMPT and read one of CANDIDATES, defaulting to DEFAULT.
1485 HISTORY is passed to `flycheck-completing-read-function'."
1486   (funcall flycheck-completing-read-function
1487            prompt candidates nil 'require-match nil history default))
1488
1489 (defun read-flycheck-checker (prompt &optional default property candidates)
1490   "Read a flycheck checker from minibuffer with PROMPT and DEFAULT.
1491
1492 PROMPT is a string to show in the minibuffer as prompt.  It
1493 should end with a single space.  DEFAULT is a symbol denoting the
1494 default checker to use, if the user did not select any checker.
1495 PROPERTY is a symbol denoting a syntax checker property.  If
1496 non-nil, only complete syntax checkers which have a non-nil value
1497 for PROPERTY.  CANDIDATES is an optional list of all syntax
1498 checkers available for completion, defaulting to all defined
1499 checkers.  If given, PROPERTY is ignored.
1500
1501 Return the checker as symbol, or DEFAULT if no checker was
1502 chosen.  If DEFAULT is nil and no checker was chosen, signal a
1503 `user-error' if the underlying completion system does not provide
1504 a default on its own."
1505   (when (and default (not (flycheck-valid-checker-p default)))
1506     (error "%S is no valid Flycheck checker" default))
1507   (let* ((candidates (seq-map #'symbol-name
1508                               (or candidates
1509                                   (flycheck-defined-checkers property))))
1510          (default (and default (symbol-name default)))
1511          (input (flycheck-completing-read
1512                  prompt candidates default
1513                  'read-flycheck-checker-history)))
1514     (when (string-empty-p input)
1515       (unless default
1516         (user-error "No syntax checker selected"))
1517       (setq input default))
1518     (let ((checker (intern input)))
1519       (unless (flycheck-valid-checker-p checker)
1520         (error "%S is not a valid Flycheck syntax checker" checker))
1521       checker)))
1522
1523 (defun read-flycheck-error-level (prompt)
1524   "Read an error level from the user with PROMPT.
1525
1526 Only offers level for which errors currently exist, in addition
1527 to the default levels."
1528   (let* ((levels (seq-map #'flycheck-error-level
1529                           (flycheck-error-list-current-errors)))
1530          (levels-with-defaults (append '(info warning error) levels))
1531          (uniq-levels (seq-uniq levels-with-defaults))
1532          (level (flycheck-completing-read prompt uniq-levels nil)))
1533     (and (stringp level) (intern level))))
1534
1535 \f
1536 ;;; Checker API
1537 (defun flycheck-defined-checkers (&optional property)
1538   "Find all defined syntax checkers, optionally with PROPERTY.
1539
1540 PROPERTY is a symbol.  If given, only return syntax checkers with
1541 a non-nil value for PROPERTY.
1542
1543 The returned list is sorted alphapetically by the symbol name of
1544 the syntax checkers."
1545   (let (defined-checkers)
1546     (mapatoms (lambda (symbol)
1547                 (when (and (flycheck-valid-checker-p symbol)
1548                            (or (null property)
1549                                (flycheck-checker-get symbol property)))
1550                   (push symbol defined-checkers))))
1551     (sort defined-checkers #'string<)))
1552
1553 (defun flycheck-registered-checker-p (checker)
1554   "Determine whether CHECKER is registered.
1555
1556 A checker is registered if it is contained in
1557 `flycheck-checkers'."
1558   (and (flycheck-valid-checker-p checker)
1559        (memq checker flycheck-checkers)))
1560
1561 (defun flycheck-disabled-checker-p (checker)
1562   "Determine whether CHECKER is disabled.
1563
1564 A checker is disabled if it is contained in
1565 `flycheck-disabled-checkers'."
1566   (memq checker flycheck-disabled-checkers))
1567
1568 \f
1569 ;;; Generic syntax checkers
1570 (defconst flycheck-generic-checker-version 2
1571   "The internal version of generic syntax checker declarations.
1572
1573 Flycheck will not use syntax checkers whose generic version is
1574 less than this constant.")
1575
1576 (defsubst flycheck--checker-property-name (property)
1577   "Return the SYMBOL property for checker PROPERTY."
1578   (intern (concat "flycheck-" (symbol-name property))))
1579
1580 (defun flycheck-checker-get (checker property)
1581   "Get the value of CHECKER's PROPERTY."
1582   (get checker (flycheck--checker-property-name property)))
1583
1584 (gv-define-setter flycheck-checker-get (value checker property)
1585   `(setf (get ,checker (flycheck--checker-property-name ,property)) ,value))
1586
1587 (defun flycheck-validate-next-checker (next &optional strict)
1588   "Validate NEXT checker.
1589
1590 With STRICT non-nil, also check whether the syntax checker and
1591 the error level in NEXT are valid.  Otherwise just check whether
1592 these are symbols.
1593
1594 Signal an error if NEXT is not a valid entry for
1595 `:next-checkers'."
1596   (when (symbolp next)
1597     (setq next (cons t next)))
1598   (pcase next
1599     (`(,level . ,checker)
1600      (if strict
1601          (progn
1602            (unless (or (eq level t) (flycheck-error-level-p level))
1603              (error "%S is not a valid Flycheck error level" level))
1604            (unless (flycheck-valid-checker-p checker)
1605              (error "%s is not a valid Flycheck syntax checker" checker)))
1606        (unless (symbolp level)
1607          (error "Error level %S must be a symbol" level))
1608        (unless (symbolp checker)
1609          (error "Checker %S must be a symbol" checker))))
1610     (_ (error "%S must be a symbol or cons cell" next)))
1611   t)
1612
1613 (defun flycheck-define-generic-checker (symbol docstring &rest properties)
1614   "Define SYMBOL as generic syntax checker.
1615
1616 Any syntax checker defined with this macro is eligible for manual
1617 syntax checker selection with `flycheck-select-checker'.  To make
1618 the new syntax checker available for automatic selection, it must
1619 be registered in `flycheck-checkers'.
1620
1621 DOCSTRING is the documentation of the syntax checker, for
1622 `flycheck-describe-checker'.  The following PROPERTIES constitute
1623 a generic syntax checker.  Unless otherwise noted, all properties
1624 are mandatory.
1625
1626 `:start FUNCTION'
1627      A function to start the syntax checker.
1628
1629      FUNCTION shall take two arguments and return a context
1630      object if the checker is started successfully.  Otherwise it
1631      shall signal an error.
1632
1633      The first argument is the syntax checker being started.  The
1634      second is a callback function to report state changes to
1635      Flycheck.  The callback takes two arguments STATUS DATA,
1636      where STATUS is a symbol denoting the syntax checker status
1637      and DATA an optional argument with additional data for the
1638      status report.  See `flycheck-report-buffer-checker-status'
1639      for more information about STATUS and DATA.
1640
1641      FUNCTION may be synchronous or asynchronous, i.e. it may
1642      call the given callback either immediately, or at some later
1643      point (e.g. from a process sentinel).
1644
1645      A syntax checker _must_ call CALLBACK at least once with a
1646      STATUS that finishes the current syntax checker.  Otherwise
1647      Flycheck gets stuck at the current syntax check with this
1648      syntax checker.
1649
1650      The context object returned by FUNCTION is passed to
1651      `:interrupt'.
1652
1653 `:interrupt FUNCTION'
1654      A function to interrupt the syntax check.
1655
1656      FUNCTION is called with the syntax checker and the context
1657      object returned by the `:start' function and shall try to
1658      interrupt the syntax check.  The context may be nil, if the
1659      syntax check is interrupted before actually started.
1660      FUNCTION should handle this situation.
1661
1662      If it cannot interrupt the syntax check, it may either
1663      signal an error or silently ignore the attempt to interrupt
1664      the syntax checker, depending on the severity of the
1665      situation.
1666
1667      If interrupting the syntax check failed, Flycheck will let
1668      the syntax check continue, but ignore any status reports.
1669      Notably, it won't highlight any errors reported by the
1670      syntax check in the buffer.
1671
1672      This property is optional.  If omitted, Flycheck won't
1673      attempt to interrupt syntax checks wit this syntax checker,
1674      and simply ignore their results.
1675
1676 `:print-doc FUNCTION'
1677      A function to print additional documentation into the Help
1678      buffer of this checker.
1679
1680      FUNCTION is called when creating the Help buffer for the
1681      syntax checker, with the syntax checker as single argument,
1682      after printing the name of the syntax checker and its modes
1683      and predicate, but before printing DOCSTRING.  It may insert
1684      additional documentation into the current buffer.
1685
1686      The call occurs within `with-help-window'.  Hence
1687      `standard-output' points to the current buffer, so you may
1688      use `princ' and friends to add content.  Also, the current
1689      buffer is put into Help mode afterwards, which automatically
1690      turns symbols into references, if possible.
1691
1692      This property is optional.  If omitted, no additional
1693      documentation is printed for this syntax checker.
1694
1695 :verify FUNCTION
1696      A function to verify the checker for the current buffer.
1697
1698      FUNCTION is called with the syntax checker as single
1699      argument, and shall return a list of
1700      `flycheck-verification-result' objects indicating whether
1701      the syntax checker could be used in the current buffer, and
1702      highlighting potential setup problems.
1703
1704      This property is optional.  If omitted, no additional
1705      verification occurs for this syntax checker.  It is however
1706      absolutely recommended that you add a `:verify' function to
1707      your syntax checker, because it will help users to spot
1708      potential setup problems.
1709
1710 `:modes MODES'
1711      A major mode symbol or a list thereof, denoting major modes
1712      to use this syntax checker in.
1713
1714      This syntax checker will only be used in buffers whose
1715      `major-mode' is contained in MODES.
1716
1717      If `:predicate' is also given the syntax checker will only
1718      be used in buffers for which the `:predicate' returns
1719      non-nil.
1720
1721 `:predicate FUNCTION'
1722      A function to determine whether to use the syntax checker in
1723      the current buffer.
1724
1725      FUNCTION is called without arguments and shall return
1726      non-nil if this syntax checker shall be used to check the
1727      current buffer.  Otherwise it shall return nil.
1728
1729      If this checker has a `:working-directory' FUNCTION is
1730      called with `default-directory' bound to the checker's
1731      working directory.
1732
1733      FUNCTION is only called in matching major modes.
1734
1735      This property is optional.
1736
1737 `:enabled FUNCTION'
1738      A function to determine whether to use the syntax checker in
1739      the current buffer.
1740
1741      This property behaves as `:predicate', except that it's only
1742      called the first time a syntax checker is to be used in a buffer.
1743
1744      FUNCTION is called without arguments and shall return
1745      non-nil if this syntax checker shall be used to check the
1746      current buffer.  Otherwise it shall return nil.
1747
1748      If FUNCTION returns a non-nil value the checker is put in a
1749      whitelist in `flycheck-enabled-checkers' to prevent further
1750      invocations of `:enabled'.  Otherwise it is disabled via
1751      `flycheck-disabled-checkers' to prevent any further use of
1752      it.
1753
1754      If this checker has a `:working-directory' FUNCTION is
1755      called with `default-directory' bound to the checker's
1756      working directory.
1757
1758      FUNCTION is only called in matching major modes.
1759
1760      This property is optional.
1761
1762 `:error-filter FUNCTION'
1763      A function to filter the errors returned by this checker.
1764
1765      FUNCTION is called with the list of `flycheck-error' objects
1766      returned by the syntax checker and shall return another list
1767      of `flycheck-error' objects, which is considered the final
1768      result of this syntax checker.
1769
1770      FUNCTION is free to add, remove or modify errors, whether in
1771      place or by copying.
1772
1773      This property is optional.  The default filter is
1774      `identity'.
1775
1776 `:error-explainer FUNCTION'
1777      A function to return an explanation text for errors
1778      generated by this checker.
1779
1780      FUNCTION is called with a `flycheck-error' object and shall
1781      return an explanation message for this error as a string, or
1782      nil if there is no explanation for this error.
1783
1784      This property is optional.
1785
1786 `:next-checkers NEXT-CHECKERS'
1787      A list denoting syntax checkers to apply after this syntax
1788      checker, in what we call \"chaining\" of syntax checkers.
1789
1790      Each ITEM is a cons cell `(LEVEL . CHECKER)'.  CHECKER is a
1791      syntax checker to run after this syntax checker.  LEVEL is
1792      an error level.  CHECKER will only be used if there are no
1793      current errors of at least LEVEL.  LEVEL may also be t, in
1794      which case CHECKER is used regardless of the current errors.
1795
1796      ITEM may also be a syntax checker symbol, which is
1797      equivalent to `(t . ITEM)'.
1798
1799      Flycheck tries all items in order of declaration, and uses
1800      the first whose LEVEL matches and whose CHECKER is
1801      registered and can be used for the current buffer.
1802
1803      This feature is typically used to apply more than one syntax
1804      checker to a buffer.  For instance, you might first use a
1805      compiler to check a buffer for syntax and type errors, and
1806      then run a linting tool that checks for insecure code, or
1807      questionable style.
1808
1809      This property is optional.  If omitted, it defaults to the
1810      nil, i.e. no other syntax checkers are applied after this
1811      syntax checker.
1812
1813 `:working-directory FUNCTION'
1814      The value of `default-directory' when invoking `:start'.
1815
1816      FUNCTION is a function taking the syntax checker as sole
1817      argument.  It shall return the absolute path to an existing
1818      directory to use as `default-directory' for `:start' or
1819      nil to fall back to the `default-directory' of the current
1820      buffer.
1821
1822      This property is optional.  If omitted, invoke `:start'
1823      from the `default-directory' of the buffer being checked.
1824
1825 Signal an error, if any property has an invalid value."
1826   (declare (indent 1)
1827            (doc-string 2))
1828   (let ((start (plist-get properties :start))
1829         (interrupt (plist-get properties :interrupt))
1830         (print-doc (plist-get properties :print-doc))
1831         (modes (plist-get properties :modes))
1832         (predicate (plist-get properties :predicate))
1833         (verify (plist-get properties :verify))
1834         (enabled (plist-get properties :enabled))
1835         (filter (or (plist-get properties :error-filter) #'identity))
1836         (explainer (plist-get properties :error-explainer))
1837         (next-checkers (plist-get properties :next-checkers))
1838         (file (flycheck-current-load-file))
1839         (working-directory (plist-get properties :working-directory)))
1840
1841     (unless (listp modes)
1842       (setq modes (list modes)))
1843
1844     (unless (functionp start)
1845       (error ":start %S of syntax checker %s is not a function" start symbol))
1846     (unless (or (null interrupt) (functionp interrupt))
1847       (error ":interrupt %S of syntax checker %s is not a function"
1848              interrupt symbol))
1849     (unless (or (null print-doc) (functionp print-doc))
1850       (error ":print-doc %S of syntax checker %s is not a function"
1851              print-doc symbol))
1852     (unless (or (null verify) (functionp verify))
1853       (error ":verify %S of syntax checker %S is not a function"
1854              verify symbol))
1855     (unless (or (null enabled) (functionp enabled))
1856       (error ":enabled %S of syntax checker %S is not a function"
1857              enabled symbol))
1858     (unless modes
1859       (error "Missing :modes in syntax checker %s" symbol))
1860     (dolist (mode modes)
1861       (unless (symbolp mode)
1862         (error "Invalid :modes %s in syntax checker %s, %s must be a symbol"
1863                modes symbol mode)))
1864     (unless (or (null predicate) (functionp predicate))
1865       (error ":predicate %S of syntax checker %s  is not a function"
1866              predicate symbol))
1867     (unless (functionp filter)
1868       (error ":error-filter %S of syntax checker %s is not a function"
1869              filter symbol))
1870     (unless (or (null explainer) (functionp explainer))
1871       (error ":error-explainer %S of syntax checker %S is not a function"
1872              explainer symbol))
1873     (dolist (checker next-checkers)
1874       (flycheck-validate-next-checker checker))
1875
1876     (let ((real-predicate
1877            (and predicate
1878                 (lambda ()
1879                   ;; Run predicate in the checker's default directory
1880                   (let ((default-directory
1881                           (flycheck-compute-working-directory symbol)))
1882                     (funcall predicate)))))
1883           (real-enabled
1884            (lambda ()
1885              (if (flycheck-valid-checker-p symbol)
1886                  (or (null enabled)
1887                      ;; Run enabled in the checker's default directory
1888                      (let ((default-directory
1889                              (flycheck-compute-working-directory symbol)))
1890                        (funcall enabled)))
1891                (lwarn 'flycheck
1892                       :warning "%S is no valid Flycheck syntax checker.
1893 Try to reinstall the package defining this syntax checker." symbol)
1894                nil))))
1895       (pcase-dolist (`(,prop . ,value)
1896                      `((start             . ,start)
1897                        (interrupt         . ,interrupt)
1898                        (print-doc         . ,print-doc)
1899                        (modes             . ,modes)
1900                        (predicate         . ,real-predicate)
1901                        (verify            . ,verify)
1902                        (enabled           . ,real-enabled)
1903                        (error-filter      . ,filter)
1904                        (error-explainer   . ,explainer)
1905                        (next-checkers     . ,next-checkers)
1906                        (documentation     . ,docstring)
1907                        (file              . ,file)
1908                        (working-directory . ,working-directory)))
1909         (setf (flycheck-checker-get symbol prop) value)))
1910
1911     ;; Track the version, to avoid breakage if the internal format changes
1912     (setf (flycheck-checker-get symbol 'generic-checker-version)
1913           flycheck-generic-checker-version)))
1914
1915 (defun flycheck-valid-checker-p (checker)
1916   "Check whether a CHECKER is valid.
1917
1918 A valid checker is a symbol defined as syntax checker with
1919 `flycheck-define-checker'."
1920   (and (symbolp checker)
1921        (= (or (get checker 'flycheck-generic-checker-version) 0)
1922           flycheck-generic-checker-version)))
1923
1924 (defun flycheck-checker-supports-major-mode-p (checker &optional mode)
1925   "Whether CHECKER supports the given major MODE.
1926
1927 CHECKER is a syntax checker symbol and MODE a major mode symbol.
1928 Look at the `modes' property of CHECKER to determine whether
1929 CHECKER supports buffers in the given major MODE.
1930
1931 MODE defaults to the value of `major-mode' if omitted or nil.
1932
1933 Return non-nil if CHECKER supports MODE and nil otherwise."
1934   (let ((mode (or mode major-mode)))
1935     (memq mode (flycheck-checker-get checker 'modes))))
1936
1937 (defvar-local flycheck-enabled-checkers nil
1938   "Syntax checkers included in automatic selection.
1939
1940 A list of Flycheck syntax checkers included in automatic
1941 selection for current buffer.")
1942
1943 (defun flycheck-may-enable-checker (checker)
1944   "Whether a generic CHECKER may be enabled for current buffer.
1945
1946 Return non-nil if CHECKER may be used for the current buffer, and
1947 nil otherwise."
1948   (let* ((enabled (flycheck-checker-get checker 'enabled))
1949          (shall-enable (and (not (flycheck-disabled-checker-p checker))
1950                             (or (memq checker flycheck-enabled-checkers)
1951                                 (null enabled)
1952                                 (funcall enabled)))))
1953     (if shall-enable
1954         (cl-pushnew checker flycheck-enabled-checkers)
1955       (cl-pushnew checker flycheck-disabled-checkers))
1956     shall-enable))
1957
1958 (defun flycheck-may-use-checker (checker)
1959   "Whether a generic CHECKER may be used.
1960
1961 Return non-nil if CHECKER may be used for the current buffer, and
1962 nil otherwise."
1963   (let ((predicate (flycheck-checker-get checker 'predicate)))
1964     (and (flycheck-valid-checker-p checker)
1965          (flycheck-checker-supports-major-mode-p checker)
1966          (flycheck-may-enable-checker checker)
1967          (or (null predicate) (funcall predicate)))))
1968
1969 (defun flycheck-may-use-next-checker (next-checker)
1970   "Determine whether NEXT-CHECKER may be used."
1971   (when (symbolp next-checker)
1972     (push t next-checker))
1973   (let ((level (car next-checker))
1974         (next-checker (cdr next-checker)))
1975     (and (or (eq level t)
1976              (flycheck-has-max-current-errors-p level))
1977          (flycheck-registered-checker-p next-checker)
1978          (flycheck-may-use-checker next-checker))))
1979
1980 \f
1981 ;;; Help for generic syntax checkers
1982 (define-button-type 'help-flycheck-checker-def
1983   :supertype 'help-xref
1984   'help-function #'flycheck-goto-checker-definition
1985   'help-echo "mouse-1, RET: find Flycheck checker definition")
1986
1987 (defconst flycheck-find-checker-regexp
1988   (rx line-start (zero-or-more (syntax whitespace))
1989       "(" symbol-start "flycheck-define-checker" symbol-end
1990       (eval (list 'regexp find-function-space-re))
1991       symbol-start
1992       "%s"
1993       symbol-end
1994       (or (syntax whitespace) line-end))
1995   "Regular expression to find a checker definition.")
1996
1997 (add-to-list 'find-function-regexp-alist
1998              '(flycheck-checker . flycheck-find-checker-regexp))
1999
2000 (defun flycheck-goto-checker-definition (checker file)
2001   "Go to to the definition of CHECKER in FILE."
2002   (let ((location (find-function-search-for-symbol
2003                    checker 'flycheck-checker file)))
2004     (pop-to-buffer (car location))
2005     (if (cdr location)
2006         (goto-char (cdr location))
2007       (message "Unable to find checker location in file"))))
2008
2009 (defun flycheck-checker-at-point ()
2010   "Return the Flycheck checker found at or before point.
2011
2012 Return nil if there is no checker."
2013   (let ((symbol (variable-at-point 'any-symbol)))
2014     (when (flycheck-valid-checker-p symbol)
2015       symbol)))
2016
2017 (defun flycheck-describe-checker (checker)
2018   "Display the documentation of CHECKER.
2019
2020 CHECKER is a checker symbol.
2021
2022 Pop up a help buffer with the documentation of CHECKER."
2023   (interactive
2024    (let* ((enable-recursive-minibuffers t)
2025           (default (or (flycheck-checker-at-point)
2026                        (ignore-errors (flycheck-get-checker-for-buffer))))
2027           (prompt (if default
2028                       (format "Describe syntax checker (default %s): " default)
2029                     "Describe syntax checker: ")))
2030      (list (read-flycheck-checker prompt default))))
2031   (unless (flycheck-valid-checker-p checker)
2032     (user-error "You didn't specify a Flycheck syntax checker"))
2033   (help-setup-xref (list #'flycheck-describe-checker checker)
2034                    (called-interactively-p 'interactive))
2035   (save-excursion
2036     (with-help-window (help-buffer)
2037       (let ((filename (flycheck-checker-get checker 'file))
2038             (modes (flycheck-checker-get checker 'modes))
2039             (predicate (flycheck-checker-get checker 'predicate))
2040             (print-doc (flycheck-checker-get checker 'print-doc))
2041             (next-checkers (flycheck-checker-get checker 'next-checkers)))
2042         (princ (format "%s is a Flycheck syntax checker" checker))
2043         (when filename
2044           (princ (format " in `%s'" (file-name-nondirectory filename)))
2045           (with-current-buffer standard-output
2046             (save-excursion
2047               (re-search-backward "`\\([^`']+\\)'" nil t)
2048               (help-xref-button 1 'help-flycheck-checker-def
2049                                 checker filename))))
2050         (princ ".\n\n")
2051
2052         (let ((modes-start (with-current-buffer standard-output (point-max))))
2053           ;; Track the start of the modes documentation, to properly re-fill
2054           ;; it later
2055           (princ "  This syntax checker checks syntax in the major mode(s) ")
2056           (princ (string-join
2057                   (seq-map (apply-partially #'format "`%s'") modes)
2058                   ", "))
2059           (when predicate
2060             (princ ", and uses a custom predicate"))
2061           (princ ".")
2062           (when next-checkers
2063             (princ "  It runs the following checkers afterwards:"))
2064           (with-current-buffer standard-output
2065             (save-excursion
2066               (fill-region-as-paragraph modes-start (point-max))))
2067           (princ "\n")
2068
2069           ;; Print the list of next checkers
2070           (when next-checkers
2071             (princ "\n")
2072             (let ((beg-checker-list (with-current-buffer standard-output
2073                                       (point))))
2074               (dolist (next-checker next-checkers)
2075                 (if (symbolp next-checker)
2076                     (princ (format "     * `%s'\n" next-checker))
2077                   (princ (format "     * `%s' (maximum level `%s')\n"
2078                                  (cdr next-checker) (car next-checker)))))
2079               ;;
2080               (with-current-buffer standard-output
2081                 (save-excursion
2082                   (while (re-search-backward "`\\([^`']+\\)'"
2083                                              beg-checker-list t)
2084                     (when (flycheck-valid-checker-p
2085                            (intern-soft (match-string 1)))
2086                       (help-xref-button 1 'help-flycheck-checker-def checker
2087                                         filename))))))))
2088         ;; Call the custom print-doc function of the checker, if present
2089         (when print-doc
2090           (funcall print-doc checker))
2091         ;; Ultimately, print the docstring
2092         (princ "\nDocumentation:\n")
2093         (princ (flycheck-checker-get checker 'documentation))))))
2094
2095 \f
2096 ;;; Syntax checker verification
2097 (cl-defstruct (flycheck-verification-result
2098                (:constructor flycheck-verification-result-new))
2099   "Structure for storing a single verification result.
2100
2101 Slots:
2102
2103 `label'
2104      A label for this result, as string
2105
2106 `message'
2107      A message for this result, as string
2108
2109 `face'
2110      The face to use for the `message'.
2111
2112      You can either use a face symbol, or a list of face symbols."
2113   label message face)
2114
2115 (defun flycheck-verify-generic-checker (checker)
2116   "Verify a generic CHECKER in the current buffer.
2117
2118 Return a list of `flycheck-verification-result' objects."
2119   (let (results
2120         (predicate (flycheck-checker-get checker 'predicate))
2121         (enabled (flycheck-checker-get checker 'enabled))
2122         (verify (flycheck-checker-get checker 'verify)))
2123     (when enabled
2124       (let ((result (funcall enabled)))
2125         (push (flycheck-verification-result-new
2126                :label "may enable"
2127                :message (if result "yes" "Automatically disabled!")
2128                :face (if result 'success '(bold warning)))
2129               results)))
2130     (when predicate
2131       (let ((result (funcall predicate)))
2132         (push (flycheck-verification-result-new
2133                :label "predicate"
2134                :message (prin1-to-string (not (null result)))
2135                :face (if result 'success '(bold warning)))
2136               results)))
2137     (append (nreverse results)
2138             (and verify (funcall verify checker)))))
2139
2140 (define-button-type 'help-flycheck-checker-doc
2141   :supertype 'help-xref
2142   'help-function #'flycheck-describe-checker
2143   'help-echo "mouse-1, RET: describe Flycheck checker")
2144
2145 (define-button-type 'flycheck-checker-select
2146   :supertype 'help-xref
2147   'help-function (lambda (buffer checker)
2148                    (with-current-buffer buffer
2149                      (flycheck-select-checker checker))
2150                    ;; Revert the verify-setup buffer since it is now stale
2151                    (revert-buffer))
2152   'help-echo "mouse-1, RET: select Flycheck checker"
2153   'face 'flycheck-verify-select-checker)
2154
2155 (defun flycheck--verify-princ-checker (checker buffer
2156                                                &optional with-mm with-select)
2157   "Print verification result of CHECKER for BUFFER.
2158
2159 When WITH-MM is given and non-nil, also include the major mode
2160 into the verification results.
2161
2162 When WITH-SELECT is non-nil, add a button to select this checker."
2163   (princ "  ")
2164   (insert-button (symbol-name checker)
2165                  'type 'help-flycheck-checker-doc
2166                  'help-args (list checker))
2167   (when (with-current-buffer buffer (flycheck-disabled-checker-p checker))
2168     (insert (propertize " (disabled)" 'face '(bold error))))
2169   (when (eq checker (buffer-local-value 'flycheck-checker buffer))
2170     (insert (propertize " (explicitly selected)" 'face 'bold)))
2171   (when with-select
2172     (princ "  ")
2173     (insert-text-button "select"
2174                         'type 'flycheck-checker-select
2175                         'help-args (list buffer checker)))
2176   (princ "\n")
2177   (let ((results (with-current-buffer buffer
2178                    (append (flycheck-verify-generic-checker checker)
2179                            (flycheck--verify-next-checkers checker)))))
2180     (when with-mm
2181       (with-current-buffer buffer
2182         (let ((message-and-face
2183                (if (flycheck-checker-supports-major-mode-p checker)
2184                    (cons (format "`%s' supported" major-mode) 'success)
2185                  (cons (format "`%s' not supported" major-mode) 'error))))
2186           (push (flycheck-verification-result-new
2187                  :label "major mode"
2188                  :message (car message-and-face)
2189                  :face (cdr message-and-face))
2190                 results))))
2191     (let* ((label-length
2192             (seq-max (mapcar
2193                       (lambda (res)
2194                         (length (flycheck-verification-result-label res)))
2195                       results)))
2196            (message-column (+ 8 label-length)))
2197       (dolist (result results)
2198         (princ "    - ")
2199         (princ (flycheck-verification-result-label result))
2200         (princ ": ")
2201         (princ (make-string (- message-column (current-column)) ?\ ))
2202         (let ((message (flycheck-verification-result-message result))
2203               (face (flycheck-verification-result-face result)))
2204           ;; If face is nil, using propertize erases the face already contained
2205           ;; by the message.  We don't want that, since this would remove the
2206           ;; button face from the checker chain result.
2207           (insert (if face (propertize message 'face face) message)))
2208         (princ "\n"))))
2209   (princ "\n"))
2210
2211 (defun flycheck-get-next-checkers (checker)
2212   "Return the immediate next checkers of CHECKER.
2213
2214 This is a list of checker symbols.  The error levels of the
2215 `:next-checker' property are ignored."
2216   (mapcar (lambda (c) (if (consp c) (cdr c) c))
2217           (flycheck-checker-get checker 'next-checkers)))
2218
2219 (defun flycheck-all-next-checkers (checker)
2220   "Return all checkers that may follow CHECKER.
2221
2222 Return the transitive closure of the next-checker relation.  The
2223 return value is a list of checkers, not including CHECKER."
2224   (let ((next-checkers)
2225         (visited)
2226         (queue (list checker)))
2227     (while queue
2228       (let ((c (pop queue)))
2229         (push c visited)
2230         (dolist (n (flycheck-get-next-checkers c))
2231           (push n next-checkers)
2232           (unless (memq n visited)
2233             (cl-pushnew n queue)))))
2234     (seq-uniq next-checkers)))
2235
2236 (defun flycheck--verify-next-checkers (checker)
2237   "Return a verification result for the next checkers of CHECKER."
2238   (-when-let (next (flycheck-get-next-checkers checker))
2239     (list
2240      (flycheck-verification-result-new
2241       :label "next checkers"
2242       ;; We use `make-text-button' to preserve the button properties in the
2243       ;; string
2244       :message (mapconcat
2245                 (lambda (checker)
2246                   (make-text-button (symbol-name checker) nil
2247                                     'type 'help-flycheck-checker-doc
2248                                     'help-args (list checker)))
2249                 next
2250                 ", ")))))
2251
2252 (defun flycheck--verify-print-header (desc buffer)
2253   "Print a title with DESC for BUFFER in the current buffer.
2254
2255 DESC is an arbitrary string containing a description, and BUFFER
2256 is the buffer being verified.  The name and the major mode mode
2257 of BUFFER are printed.
2258
2259 DESC and information about BUFFER are printed in the current
2260 buffer."
2261   (princ desc)
2262   (insert (propertize (buffer-name buffer) 'face 'bold))
2263   (princ " in ")
2264   (let ((mode (buffer-local-value 'major-mode buffer)))
2265     (insert-button (symbol-name mode)
2266                    'type 'help-function
2267                    'help-args (list mode)))
2268   (princ ":\n\n"))
2269
2270 (defun flycheck--verify-print-footer (buffer)
2271   "Print a footer for BUFFER in the current buffer.
2272
2273 BUFFER is the buffer being verified."
2274   (princ "Flycheck Mode is ")
2275   (let ((enabled (buffer-local-value 'flycheck-mode buffer)))
2276     (insert (propertize (if enabled "enabled" "disabled")
2277                         'face (if enabled 'success '(warning bold)))))
2278   (princ
2279    (with-current-buffer buffer
2280      ;; Use key binding state in the verified buffer to print the help.
2281      (substitute-command-keys
2282       ".  Use \\[universal-argument] \\[flycheck-disable-checker] \
2283 to enable disabled checkers.")))
2284   (save-excursion
2285     (let ((end (point)))
2286       (backward-paragraph)
2287       (fill-region-as-paragraph (point) end)))
2288
2289   (princ "\n\n--------------------\n\n")
2290   (princ (format "Flycheck version: %s\n" (flycheck-version)))
2291   (princ (format "Emacs version:    %s\n" emacs-version))
2292   (princ (format "System:           %s\n" system-configuration))
2293   (princ (format "Window system:    %S\n" window-system)))
2294
2295 (defun flycheck-verify-checker (checker)
2296   "Check whether a CHECKER can be used in this buffer.
2297
2298 Show a buffer listing possible problems that prevent CHECKER from
2299 being used for the current buffer.
2300
2301 Note: Do not use this function to check whether a syntax checker
2302 is applicable from Emacs Lisp code.  Use
2303 `flycheck-may-use-checker' instead."
2304   (interactive (list (read-flycheck-checker "Checker to verify: ")))
2305   (unless (flycheck-valid-checker-p checker)
2306     (user-error "%s is not a syntax checker" checker))
2307
2308   ;; Save the buffer to make sure that all predicates are good
2309   ;; FIXME: this may be surprising to users, with unintended side-effects.
2310   (when (and (buffer-file-name) (buffer-modified-p))
2311     (save-buffer))
2312
2313   (let ((buffer (current-buffer)))
2314     (with-help-window (get-buffer-create " *Flycheck checker*")
2315       (with-current-buffer standard-output
2316         (flycheck--verify-print-header "Syntax checker in buffer " buffer)
2317         (flycheck--verify-princ-checker checker buffer 'with-mm)
2318         (if (with-current-buffer buffer (flycheck-may-use-checker checker))
2319             (insert (propertize
2320                      "Flycheck can use this syntax checker for this buffer.\n"
2321                      'face 'success))
2322           (insert (propertize
2323                    "Flycheck cannot use this syntax checker for this buffer.\n"
2324                    'face 'error)))
2325         (insert "\n")
2326         (flycheck--verify-print-footer buffer)))))
2327
2328 (defun flycheck-verify-setup ()
2329   "Check whether Flycheck can be used in this buffer.
2330
2331 Display a new buffer listing all syntax checkers that could be
2332 applicable in the current buffer.  For each syntax checkers,
2333 possible problems are shown."
2334   (interactive)
2335   ;; Save to make sure checkers that only work on saved buffers will pass the
2336   ;; verification
2337   (when (and (buffer-file-name) (buffer-modified-p))
2338     (save-buffer))
2339
2340   (let* ((buffer (current-buffer))
2341          (first-checker (flycheck-get-checker-for-buffer))
2342          (valid-checkers
2343           (remq first-checker
2344                 (seq-filter #'flycheck-may-use-checker flycheck-checkers)))
2345          (valid-next-checkers
2346           (when first-checker
2347             (seq-intersection valid-checkers
2348                               (flycheck-all-next-checkers first-checker))))
2349          (valid-remaining (seq-difference valid-checkers valid-next-checkers))
2350          (other-checkers
2351           (seq-difference (seq-filter #'flycheck-checker-supports-major-mode-p
2352                                       flycheck-checkers)
2353                           (cons first-checker valid-checkers)))
2354          (help-buffer (get-buffer-create " *Flycheck checkers*")))
2355
2356     ;; Print all applicable checkers for this buffer
2357     (with-help-window help-buffer
2358       (with-current-buffer standard-output
2359         (flycheck--verify-print-header "Syntax checkers for buffer " buffer)
2360
2361         (if first-checker
2362             (progn
2363               (princ "First checker to run:\n\n")
2364               (flycheck--verify-princ-checker first-checker buffer))
2365           (insert (propertize
2366                    "No checker to run in this buffer.\n\n"
2367                    'face '(bold error))))
2368
2369         (when valid-next-checkers
2370           (princ
2371            "Checkers that may run as part of the first checker's chain:\n\n")
2372           (dolist (checker valid-next-checkers)
2373             (flycheck--verify-princ-checker checker buffer)))
2374
2375         (when valid-remaining
2376           (princ "Checkers that could run if selected:\n\n")
2377           (dolist (checker valid-remaining)
2378             (flycheck--verify-princ-checker checker buffer nil 'with-select)))
2379
2380         (when other-checkers
2381           (princ
2382            "Checkers that are compatible with this mode, \
2383 but will not run until properly configured:\n\n")
2384           (dolist (checker other-checkers)
2385             (flycheck--verify-princ-checker checker buffer)))
2386
2387         ;; If we have no checkers at all, that's worth mentioning
2388         (unless (or first-checker valid-checkers other-checkers)
2389           (insert (propertize
2390                    "No checkers are available for this buffer.\n\n"
2391                    'face '(bold error))))
2392
2393         (let ((unregistered-checkers
2394                (seq-difference (flycheck-defined-checkers) flycheck-checkers)))
2395           (when unregistered-checkers
2396             (insert (propertize
2397                      "\nThe following syntax checkers are not registered:\n\n"
2398                      'face '(bold warning)))
2399             (dolist (checker unregistered-checkers)
2400               (princ "  - ")
2401               (princ checker)
2402               (princ "\n"))
2403             (princ
2404              "\nTry adding these syntax checkers to `flycheck-checkers'.\n")))
2405
2406         (flycheck--verify-print-footer buffer)))
2407
2408     (with-current-buffer help-buffer
2409       (setq-local revert-buffer-function
2410                   (lambda (_ignore-auto _noconfirm)
2411                     (with-current-buffer buffer (flycheck-verify-setup)))))))
2412
2413 \f
2414 ;;; Predicates for generic syntax checkers
2415 (defun flycheck-buffer-saved-p (&optional buffer)
2416   "Determine whether BUFFER is saved to a file.
2417
2418 BUFFER is the buffer to check.  If omitted or nil, use the
2419 current buffer as BUFFER.
2420
2421 Return non-nil if the BUFFER is backed by a file, and not
2422 modified, or nil otherwise."
2423   (let ((file-name (buffer-file-name buffer)))
2424     (and file-name (file-exists-p file-name) (not (buffer-modified-p buffer)))))
2425
2426 \f
2427 ;;; Extending generic checkers
2428 (defun flycheck-add-next-checker (checker next &optional append)
2429   "After CHECKER add a NEXT checker.
2430
2431 CHECKER is a syntax checker symbol, to which to add NEXT checker.
2432
2433 NEXT is a cons cell `(LEVEL . NEXT-CHECKER)'.  NEXT-CHECKER is a
2434 symbol denoting the syntax checker to run after CHECKER.  LEVEL
2435 is an error level.  NEXT-CHECKER will only be used if there is no
2436 current error whose level is more severe than LEVEL.  LEVEL may
2437 also be t, in which case NEXT-CHECKER is used regardless of the
2438 current errors.
2439
2440 NEXT can also be a syntax checker symbol only, which is
2441 equivalent to `(t . NEXT)'.
2442
2443 NEXT-CHECKER is prepended before other next checkers, unless
2444 APPEND is non-nil."
2445   (unless (flycheck-valid-checker-p checker)
2446     (error "%s is not a valid syntax checker" checker))
2447   (flycheck-validate-next-checker next 'strict)
2448   (if append
2449       (setf (flycheck-checker-get checker 'next-checkers)
2450             (append (flycheck-checker-get checker 'next-checkers) (list next)))
2451     (push next (flycheck-checker-get checker 'next-checkers))))
2452
2453 (defun flycheck-add-mode (checker mode)
2454   "To CHECKER add a new major MODE.
2455
2456 CHECKER and MODE are symbols denoting a syntax checker and a
2457 major mode respectively.
2458
2459 Add MODE to the `:modes' property of CHECKER, so that CHECKER
2460 will be used in buffers with MODE."
2461   (unless (flycheck-valid-checker-p checker)
2462     (error "%s is not a valid syntax checker" checker))
2463   (unless (symbolp mode)
2464     (error "%s is not a symbol" mode))
2465   (push mode (flycheck-checker-get checker 'modes)))
2466
2467 \f
2468 ;;; Generic syntax checks
2469 (cl-defstruct (flycheck-syntax-check
2470                (:constructor flycheck-syntax-check-new))
2471   "Structure for storing syntax check state.
2472
2473 Slots:
2474
2475 `buffer'
2476      The buffer being checked.
2477
2478 `checker'
2479      The syntax checker being used.
2480
2481 `context'
2482      The context object.
2483
2484 `working-directory'
2485      Working directory for the syntax checker. Serve as a value for
2486      `default-directory' for a checker."
2487   buffer checker context working-directory)
2488
2489 (defun flycheck-syntax-check-start (syntax-check callback)
2490   "Start a SYNTAX-CHECK with CALLBACK."
2491   (let ((checker (flycheck-syntax-check-checker syntax-check))
2492         (default-directory
2493           (flycheck-syntax-check-working-directory syntax-check)))
2494     (setf (flycheck-syntax-check-context syntax-check)
2495           (funcall (flycheck-checker-get checker 'start) checker callback))))
2496
2497 (defun flycheck-syntax-check-interrupt (syntax-check)
2498   "Interrupt a SYNTAX-CHECK."
2499   (let* ((checker (flycheck-syntax-check-checker syntax-check))
2500          (interrupt-fn (flycheck-checker-get checker 'interrupt))
2501          (context (flycheck-syntax-check-context syntax-check)))
2502     (when interrupt-fn
2503       (funcall interrupt-fn checker context))))
2504
2505 \f
2506 ;;; Syntax checking mode
2507
2508 (defvar flycheck-mode-map
2509   (let ((map (make-sparse-keymap)))
2510     (define-key map flycheck-keymap-prefix flycheck-command-map)
2511     ;; We place the menu under a custom menu key.  Since this menu key is not
2512     ;; present in the menu of the global map, no top-level menu entry is added
2513     ;; to the global menu bar.  However, it still appears on the mode line
2514     ;; lighter.
2515     (define-key map [menu-bar flycheck] flycheck-mode-menu-map)
2516     map)
2517   "Keymap of command `flycheck-mode'.")
2518
2519 (defvar-local flycheck-old-next-error-function nil
2520   "Remember the old `next-error-function'.")
2521
2522 (defconst flycheck-hooks-alist
2523   '(
2524     ;; Handle events that may start automatic syntax checks
2525     (after-save-hook        . flycheck-handle-save)
2526     (after-change-functions . flycheck-handle-change)
2527     ;; Handle events that may triggered pending deferred checks
2528     (window-configuration-change-hook . flycheck-perform-deferred-syntax-check)
2529     (post-command-hook                . flycheck-perform-deferred-syntax-check)
2530     ;; Teardown Flycheck whenever the buffer state is about to get lost, to
2531     ;; clean up temporary files and directories.
2532     (kill-buffer-hook       . flycheck-teardown)
2533     (change-major-mode-hook . flycheck-teardown)
2534     (before-revert-hook     . flycheck-teardown)
2535     ;; Update the error list if necessary
2536     (post-command-hook . flycheck-error-list-update-source)
2537     (post-command-hook . flycheck-error-list-highlight-errors)
2538     ;; Display errors.  Show errors at point after commands (like movements) and
2539     ;; when Emacs gets focus.  Cancel the display timer when Emacs looses focus
2540     ;; (as there's no need to display errors if the user can't see them), and
2541     ;; hide the error buffer (for large error messages) if necessary.  Note that
2542     ;; the focus hooks only work on Emacs 24.4 and upwards, but since undefined
2543     ;; hooks are perfectly ok we don't need a version guard here.  They'll just
2544     ;; not work silently.
2545     (post-command-hook . flycheck-display-error-at-point-soon)
2546     (focus-in-hook     . flycheck-display-error-at-point-soon)
2547     (focus-out-hook    . flycheck-cancel-error-display-error-at-point-timer)
2548     (post-command-hook . flycheck-hide-error-buffer)
2549     ;; Immediately show error popups when navigating to an error
2550     (next-error-hook . flycheck-display-error-at-point))
2551   "Hooks which Flycheck needs to hook in.
2552
2553 The `car' of each pair is a hook variable, the `cdr' a function
2554 to be added or removed from the hook variable if Flycheck mode is
2555 enabled and disabled respectively.")
2556
2557 ;;;###autoload
2558 (define-minor-mode flycheck-mode
2559   "Minor mode for on-the-fly syntax checking.
2560
2561 When called interactively, toggle `flycheck-mode'.  With prefix
2562 ARG, enable `flycheck-mode' if ARG is positive, otherwise disable
2563 it.
2564
2565 When called from Lisp, enable `flycheck-mode' if ARG is omitted,
2566 nil or positive.  If ARG is `toggle', toggle `flycheck-mode'.
2567 Otherwise behave as if called interactively.
2568
2569 In `flycheck-mode' the buffer is automatically syntax-checked
2570 using the first suitable syntax checker from `flycheck-checkers'.
2571 Use `flycheck-select-checker' to select a checker for the current
2572 buffer manually.
2573
2574 \\{flycheck-mode-map}"
2575   :init-value nil
2576   :keymap flycheck-mode-map
2577   :lighter flycheck-mode-line
2578   :after-hook (flycheck-buffer-automatically 'mode-enabled 'force-deferred)
2579   (cond
2580    (flycheck-mode
2581     (flycheck-clear)
2582
2583     (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist)
2584       (add-hook hook fn nil 'local))
2585
2586     (setq flycheck-old-next-error-function
2587           (if flycheck-standard-error-navigation
2588               next-error-function
2589             :unset))
2590     (when flycheck-standard-error-navigation
2591       (setq next-error-function #'flycheck-next-error-function))
2592
2593     ;; This hook must be added globally since otherwise we cannot
2594     ;; detect a change from a buffer where Flycheck is enabled to a
2595     ;; buffer where Flycheck is not enabled, and therefore cannot
2596     ;; notice that there has been any change when the user switches
2597     ;; back to the buffer where Flycheck is enabled.
2598     (add-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch))
2599    (t
2600     (unless (eq flycheck-old-next-error-function :unset)
2601       (setq next-error-function flycheck-old-next-error-function))
2602
2603     (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist)
2604       (remove-hook hook fn 'local))
2605
2606     (flycheck-teardown))))
2607
2608 \f
2609 ;;; Syntax checker selection for the current buffer
2610 (defun flycheck-get-checker-for-buffer ()
2611   "Find the checker for the current buffer.
2612
2613 Use the selected checker for the current buffer, if any,
2614 otherwise search for the best checker from `flycheck-checkers'.
2615
2616 Return checker if there is a checker for the current buffer, or
2617 nil otherwise."
2618   (if flycheck-checker
2619       (when (flycheck-may-use-checker flycheck-checker)
2620         flycheck-checker)
2621     (seq-find #'flycheck-may-use-checker flycheck-checkers)))
2622
2623 (defun flycheck-get-next-checker-for-buffer (checker)
2624   "Get the checker to run after CHECKER for the current buffer."
2625   (let ((next (seq-find #'flycheck-may-use-next-checker
2626                         (flycheck-checker-get checker 'next-checkers))))
2627     (when next
2628       (if (symbolp next) next (cdr next)))))
2629
2630 (defun flycheck-select-checker (checker)
2631   "Select CHECKER for the current buffer.
2632
2633 CHECKER is a syntax checker symbol (see `flycheck-checkers') or
2634 nil.  In the former case, use CHECKER for the current buffer,
2635 otherwise deselect the current syntax checker (if any) and use
2636 automatic checker selection via `flycheck-checkers'.
2637
2638 If called interactively prompt for CHECKER.  With prefix arg
2639 deselect the current syntax checker and enable automatic
2640 selection again.
2641
2642 Set `flycheck-checker' to CHECKER and automatically start a new
2643 syntax check if the syntax checker changed.
2644
2645 CHECKER will be used, even if it is not contained in
2646 `flycheck-checkers', or if it is disabled via
2647 `flycheck-disabled-checkers'."
2648   (interactive
2649    (if current-prefix-arg
2650        (list nil)
2651      (list (read-flycheck-checker "Select checker: "
2652                                   (flycheck-get-checker-for-buffer)))))
2653   (when (not (eq checker flycheck-checker))
2654     (unless (or (not checker) (flycheck-may-use-checker checker))
2655       (flycheck-verify-checker checker)
2656       (user-error "Can't use syntax checker %S in this buffer" checker))
2657     (setq flycheck-checker checker)
2658     (when flycheck-mode
2659       (flycheck-buffer))))
2660
2661 (defun flycheck-disable-checker (checker &optional enable)
2662   "Interactively disable CHECKER for the current buffer.
2663
2664 Interactively, prompt for a syntax checker to disable, and add
2665 the syntax checker to the buffer-local value of
2666 `flycheck-disabled-checkers'.
2667
2668 With non-nil ENABLE or with prefix arg, prompt for a disabled
2669 syntax checker and re-enable it by removing it from the
2670 buffer-local value of `flycheck-disabled-checkers'."
2671   (declare
2672    (interactive-only "Directly set `flycheck-disabled-checkers' instead"))
2673   (interactive
2674    (let* ((enable current-prefix-arg)
2675           (candidates (if enable flycheck-disabled-checkers flycheck-checkers))
2676           (prompt (if enable "Enable syntax checker: "
2677                     "Disable syntax checker: ")))
2678      (when (and enable (not candidates))
2679        (user-error "No syntax checkers disabled in this buffer"))
2680      (list (read-flycheck-checker prompt nil nil candidates) enable)))
2681   (unless checker
2682     (user-error "No syntax checker given"))
2683   (if enable
2684       ;; We must use `remq' instead of `delq', because we must _not_ modify the
2685       ;; list.  Otherwise we could potentially modify the global default value,
2686       ;; in case the list is the global default.
2687       (when (memq checker flycheck-disabled-checkers)
2688         (setq flycheck-disabled-checkers
2689               (remq checker flycheck-disabled-checkers))
2690         (flycheck-buffer))
2691     (unless (memq checker flycheck-disabled-checkers)
2692       (push checker flycheck-disabled-checkers)
2693       (flycheck-buffer))))
2694
2695 \f
2696 ;;; Syntax checks for the current buffer
2697 (defvar-local flycheck-current-syntax-check nil
2698   "The current syntax check in the this buffer.")
2699 (put 'flycheck-current-syntax-check 'permanent-local t)
2700
2701 (defun flycheck-start-current-syntax-check (checker)
2702   "Start a syntax check in the current buffer with CHECKER.
2703
2704 Set `flycheck-current-syntax-check' accordingly."
2705   ;; Allocate the current syntax check *before* starting it.  This allows for
2706   ;; synchronous checks, which call the status callback immediately in their
2707   ;; start function.
2708   (let* ((check
2709           (flycheck-syntax-check-new
2710            :buffer (current-buffer)
2711            :checker checker
2712            :context nil
2713            :working-directory (flycheck-compute-working-directory checker)))
2714          (callback (flycheck-buffer-status-callback check)))
2715     (setq flycheck-current-syntax-check check)
2716     (flycheck-report-status 'running)
2717     (flycheck-syntax-check-start check callback)))
2718
2719 (defun flycheck-running-p ()
2720   "Determine whether a syntax check is running in the current buffer."
2721   (not (null flycheck-current-syntax-check)))
2722
2723 (defun flycheck-stop ()
2724   "Stop any ongoing syntax check in the current buffer."
2725   (when (flycheck-running-p)
2726     (flycheck-syntax-check-interrupt flycheck-current-syntax-check)
2727     ;; Remove the current syntax check, to reset Flycheck into a non-running
2728     ;; state, and to make `flycheck-report-buffer-checker-status' ignore any
2729     ;; status reports from the current syntax check.
2730     (setq flycheck-current-syntax-check nil)
2731     (flycheck-report-status 'interrupted)))
2732
2733 (defun flycheck-buffer-status-callback (syntax-check)
2734   "Create a status callback for SYNTAX-CHECK in the current buffer."
2735   (lambda (&rest args)
2736     (apply #'flycheck-report-buffer-checker-status
2737            syntax-check args)))
2738
2739 (defun flycheck-buffer ()
2740   "Start checking syntax in the current buffer.
2741
2742 Get a syntax checker for the current buffer with
2743 `flycheck-get-checker-for-buffer', and start it."
2744   (interactive)
2745   (flycheck-clean-deferred-check)
2746   (if flycheck-mode
2747       (unless (flycheck-running-p)
2748         ;; Clear error list and mark all overlays for deletion.  We do not
2749         ;; delete all overlays immediately to avoid excessive re-displays and
2750         ;; flickering, if the same errors gets highlighted again after the check
2751         ;; completed.
2752         (run-hooks 'flycheck-before-syntax-check-hook)
2753         (flycheck-clear-errors)
2754         (flycheck-mark-all-overlays-for-deletion)
2755         (condition-case err
2756             (let* ((checker (flycheck-get-checker-for-buffer)))
2757               (if checker
2758                   (flycheck-start-current-syntax-check checker)
2759                 (flycheck-clear)
2760                 (flycheck-report-status 'no-checker)))
2761           (error
2762            (flycheck-report-failed-syntax-check)
2763            (signal (car err) (cdr err)))))
2764     (user-error "Flycheck mode disabled")))
2765
2766 (defun flycheck-report-buffer-checker-status
2767     (syntax-check status &optional data)
2768   "In BUFFER, report a SYNTAX-CHECK STATUS with DATA.
2769
2770 SYNTAX-CHECK is the `flycheck-syntax-check' which reported
2771 STATUS.  STATUS denotes the status of CHECKER, with an optional
2772 DATA.  STATUS may be one of the following symbols:
2773
2774 `errored'
2775      The syntax checker has errored.  DATA is an optional error
2776      message.
2777
2778      This report finishes the current syntax check.
2779
2780 `interrupted'
2781      The syntax checker was interrupted.  DATA is ignored.
2782
2783      This report finishes the current syntax check.
2784
2785 `finished'
2786      The syntax checker has finished with a proper error report
2787      for the current buffer.  DATA is the (potentially empty)
2788      list of `flycheck-error' objects reported by the syntax
2789      check.
2790
2791      This report finishes the current syntax check.
2792
2793 `suspicious'
2794      The syntax checker encountered a suspicious state, which the
2795      user needs to be informed about.  DATA is an optional
2796      message.
2797
2798 A syntax checker _must_ report a status at least once with any
2799 symbol that finishes the current syntax checker.  Otherwise
2800 Flycheck gets stuck with the current syntax check.
2801
2802 If CHECKER is not the currently used syntax checker in
2803 `flycheck-current-syntax-check', the status report is largely
2804 ignored.  Notably, any errors reported by the checker are
2805 discarded."
2806   (let ((buffer (flycheck-syntax-check-buffer syntax-check)))
2807     ;; Ignore the status report if the buffer is gone, or if this syntax check
2808     ;; isn't the current one in buffer (which can happen if this is an old
2809     ;; report of an interrupted syntax check, and a new syntax check was started
2810     ;; since this check was interrupted)
2811     (when (and (buffer-live-p buffer)
2812                (eq syntax-check
2813                    (buffer-local-value 'flycheck-current-syntax-check buffer)))
2814       (with-current-buffer buffer
2815         (let ((checker (flycheck-syntax-check-checker syntax-check)))
2816           (pcase status
2817             ((or `errored `interrupted)
2818              (flycheck-report-failed-syntax-check status)
2819              (when (eq status 'errored)
2820                ;; In case of error, show the error message
2821                (message "Error from syntax checker %s: %s"
2822                         checker (or data "UNKNOWN!"))))
2823             (`suspicious
2824              (when flycheck-mode
2825                (message "Suspicious state from syntax checker %s: %s"
2826                         checker (or data "UNKNOWN!")))
2827              (flycheck-report-status 'suspicious))
2828             (`finished
2829              (when flycheck-mode
2830                ;; Only report errors from the checker if Flycheck Mode is
2831                ;; still enabled.
2832                (flycheck-finish-current-syntax-check
2833                 data
2834                 (flycheck-syntax-check-working-directory syntax-check))))
2835             (_
2836              (error "Unknown status %s from syntax checker %s"
2837                     status checker))))))))
2838
2839 (defun flycheck-finish-current-syntax-check (errors working-dir)
2840   "Finish the current syntax-check in the current buffer with ERRORS.
2841
2842 ERRORS is a list of `flycheck-error' objects reported by the
2843 current syntax check in `flycheck-current-syntax-check'.
2844
2845 Report all ERRORS and potentially start any next syntax checkers.
2846
2847 If the current syntax checker reported excessive errors, it is
2848 disabled via `flycheck-disable-excessive-checker' for subsequent
2849 syntax checks.
2850
2851 Relative file names in ERRORS will be expanded relative to
2852 WORKING-DIR."
2853   (let* ((syntax-check flycheck-current-syntax-check)
2854          (checker (flycheck-syntax-check-checker syntax-check))
2855          (errors (flycheck-relevant-errors
2856                   (flycheck-fill-and-expand-error-file-names
2857                    (flycheck-filter-errors
2858                     (flycheck-assert-error-list-p errors) checker)
2859                    working-dir))))
2860     (unless (flycheck-disable-excessive-checker checker errors)
2861       (flycheck-report-current-errors errors))
2862     (let ((next-checker (flycheck-get-next-checker-for-buffer checker)))
2863       (if next-checker
2864           (flycheck-start-current-syntax-check next-checker)
2865         (setq flycheck-current-syntax-check nil)
2866         (flycheck-report-status 'finished)
2867         ;; Delete overlays only after the very last checker has run, to avoid
2868         ;; flickering on intermediate re-displays
2869         (flycheck-delete-marked-overlays)
2870         (flycheck-error-list-refresh)
2871         (run-hooks 'flycheck-after-syntax-check-hook)
2872         (when (eq (current-buffer) (window-buffer))
2873           (flycheck-display-error-at-point))
2874         ;; Immediately try to run any pending deferred syntax check, which
2875         ;; were triggered by intermediate automatic check event, to make sure
2876         ;; that we quickly refine outdated error information
2877         (flycheck-perform-deferred-syntax-check)))))
2878
2879 (defun flycheck-disable-excessive-checker (checker errors)
2880   "Disable CHECKER if it reported excessive ERRORS.
2881
2882 If ERRORS has more items than `flycheck-checker-error-threshold',
2883 add CHECKER to `flycheck-disabled-checkers', and show a warning.
2884
2885 Return t when CHECKER was disabled, or nil otherwise."
2886   (when (and flycheck-checker-error-threshold
2887              (> (length errors) flycheck-checker-error-threshold))
2888     ;; Disable CHECKER for this buffer (`flycheck-disabled-checkers' is a local
2889     ;; variable).
2890     (lwarn '(flycheck syntax-checker) :warning
2891            "Syntax checker %s reported too many errors (%s) and is disabled."
2892            checker (length errors))
2893     (push checker flycheck-disabled-checkers)
2894     t))
2895
2896 (defun flycheck-clear (&optional shall-interrupt)
2897   "Clear all errors in the current buffer.
2898
2899 With prefix arg or SHALL-INTERRUPT non-nil, also interrupt the
2900 current syntax check."
2901   (interactive "P")
2902   (when shall-interrupt
2903     (flycheck-stop))
2904   (flycheck-delete-all-overlays)
2905   (flycheck-clear-errors)
2906   (flycheck-error-list-refresh)
2907   (flycheck-hide-error-buffer))
2908
2909 (defun flycheck--empty-variables ()
2910   "Empty variables used by Flycheck."
2911   (kill-local-variable 'flycheck--idle-trigger-timer)
2912   (kill-local-variable 'flycheck--idle-trigger-conditions))
2913
2914 (defun flycheck-teardown (&optional ignore-global)
2915   "Teardown Flycheck in the current buffer.
2916
2917 Completely clear the whole Flycheck state.  Remove overlays, kill
2918 running checks, and empty all variables used by Flycheck.
2919
2920 Unless optional argument IGNORE-GLOBAL is non-nil, check to see
2921 if no more Flycheck buffers remain (aside from the current
2922 buffer), and if so then clean up global hooks."
2923   (flycheck-safe-delete-temporaries)
2924   (flycheck-stop)
2925   (flycheck-clean-deferred-check)
2926   (flycheck-clear)
2927   (flycheck-cancel-error-display-error-at-point-timer)
2928   (flycheck--clear-idle-trigger-timer)
2929   (flycheck--empty-variables)
2930   (unless (or ignore-global
2931               (seq-some (lambda (buf)
2932                           (and (not (equal buf (current-buffer)))
2933                                (buffer-local-value 'flycheck-mode buf)))
2934                         (buffer-list)))
2935     (flycheck-global-teardown 'ignore-local)))
2936
2937 \f
2938 ;;; Automatic syntax checking in a buffer
2939 (defun flycheck-may-check-automatically (&rest conditions)
2940   "Determine whether the buffer may be checked under one of CONDITIONS.
2941
2942 Read-only buffers may never be checked automatically.
2943
2944 If CONDITIONS are given, determine whether syntax may be checked
2945 under at least one of them, according to
2946 `flycheck-check-syntax-automatically'."
2947   (and (not (or buffer-read-only (flycheck-ephemeral-buffer-p)))
2948        (file-exists-p default-directory)
2949        (or (not conditions)
2950            (seq-some
2951             (lambda (condition)
2952               (memq condition flycheck-check-syntax-automatically))
2953             conditions))))
2954
2955 (defvar-local flycheck--idle-trigger-timer nil
2956   "Timer used to trigger a syntax check after an idle delay.")
2957
2958 (defvar-local flycheck--idle-trigger-conditions nil
2959   "List of conditions under which an idle syntax check will be triggered.
2960 This will be some subset of the allowable values for
2961 `flycheck-check-syntax-automatically'.
2962
2963 For example, if the user switches to a buffer and then makes an
2964 edit, this list will have the values `idle-change' and
2965 `idle-buffer-switch' in it, at least until the idle timer
2966 expires.")
2967
2968 (defun flycheck-buffer-automatically (&optional condition force-deferred)
2969   "Automatically check syntax at CONDITION.
2970
2971 Syntax is not checked if `flycheck-may-check-automatically'
2972 returns nil for CONDITION.  (CONDITION may be a single condition
2973 or a list of them.)
2974
2975 The syntax check is deferred if FORCE-DEFERRED is non-nil, or if
2976 `flycheck-must-defer-check' returns t."
2977   (when (and flycheck-mode (if (listp condition)
2978                                (apply #'flycheck-may-check-automatically
2979                                       condition)
2980                              (flycheck-may-check-automatically condition)))
2981     (flycheck--clear-idle-trigger-timer)
2982     (setq flycheck--idle-trigger-conditions nil)
2983     (if (or force-deferred (flycheck-must-defer-check))
2984         (flycheck-buffer-deferred)
2985       (with-demoted-errors "Error while checking syntax automatically: %S"
2986         (flycheck-buffer)))))
2987
2988 (defun flycheck--clear-idle-trigger-timer ()
2989   "Clear the idle trigger timer."
2990   (when flycheck--idle-trigger-timer
2991     (cancel-timer flycheck--idle-trigger-timer)
2992     (setq flycheck--idle-trigger-timer nil)))
2993
2994 (defun flycheck--handle-idle-trigger (buffer)
2995   "Run a syntax check in BUFFER if appropriate.
2996 This function is called by `flycheck--idle-trigger-timer'."
2997   (let ((current-buffer (current-buffer)))
2998     (when (buffer-live-p buffer)
2999       (with-current-buffer buffer
3000         (unless (or flycheck-buffer-switch-check-intermediate-buffers
3001                     (eq buffer current-buffer))
3002           (setq flycheck--idle-trigger-conditions
3003                 (delq 'idle-buffer-switch
3004                       flycheck--idle-trigger-conditions)))
3005         (when flycheck--idle-trigger-conditions
3006           (flycheck-buffer-automatically flycheck--idle-trigger-conditions)
3007           (setq flycheck--idle-trigger-conditions nil))))))
3008
3009 (defun flycheck-handle-change (beg end _len)
3010   "Handle a buffer change between BEG and END.
3011
3012 BEG and END mark the beginning and end of the change text.  _LEN
3013 is ignored.
3014
3015 Start a syntax check if a new line has been inserted into the
3016 buffer."
3017   ;; Save and restore the match data, as recommended in (elisp)Change Hooks
3018   (save-match-data
3019     (when flycheck-mode
3020       (if (string-match-p (rx "\n") (buffer-substring beg end))
3021           (flycheck-buffer-automatically 'new-line 'force-deferred)
3022         (when (memq 'idle-change flycheck-check-syntax-automatically)
3023           (flycheck--clear-idle-trigger-timer)
3024           (cl-pushnew 'idle-change flycheck--idle-trigger-conditions)
3025           (setq flycheck--idle-trigger-timer
3026                 (run-at-time flycheck-idle-change-delay nil
3027                              #'flycheck--handle-idle-trigger
3028                              (current-buffer))))))))
3029
3030 (defvar flycheck--last-buffer (current-buffer)
3031   "The current buffer or the buffer that was previously current.
3032 This is usually equal to the current buffer, unless the user just
3033 switched buffers.  After a buffer switch, it is the previous
3034 buffer.")
3035
3036 (defun flycheck-handle-buffer-switch ()
3037   "Handle a possible switch to another buffer.
3038
3039 If a buffer switch actually happened, schedule a syntax check."
3040   ;; Switching buffers here is weird, but unfortunately necessary.  It
3041   ;; turns out that `with-temp-buffer' triggers
3042   ;; `buffer-list-update-hook' twice, and the value of
3043   ;; `current-buffer' is bogus in one of those triggers (the one just
3044   ;; after the temp buffer is killed).  If we rely on the bogus value,
3045   ;; Flycheck will think that the user is switching back and forth
3046   ;; between different buffers during the `with-temp-buffer' call
3047   ;; (note: two different normal buffers, not the current buffer and
3048   ;; the temp buffer!), and that would trigger spurious syntax checks.
3049   ;; It seems that reading (window-buffer) gets us the correct current
3050   ;; buffer in all important real-life situations (although it doesn't
3051   ;; necessarily catch uses of `set-buffer').
3052   (with-current-buffer (window-buffer)
3053     (unless (or (equal flycheck--last-buffer (current-buffer))
3054                 ;; Don't bother keeping track of changes to and from
3055                 ;; the minibuffer, as they will never require us to
3056                 ;; run a syntax check.
3057                 (minibufferp))
3058       (setq flycheck--last-buffer (current-buffer))
3059       (when (and flycheck-mode
3060                  (memq 'idle-buffer-switch flycheck-check-syntax-automatically))
3061         (flycheck--clear-idle-trigger-timer)
3062         (cl-pushnew 'idle-buffer-switch flycheck--idle-trigger-conditions)
3063         (setq flycheck--idle-trigger-timer
3064               (run-at-time flycheck-idle-buffer-switch-delay nil
3065                            #'flycheck--handle-idle-trigger
3066                            (current-buffer)))))))
3067
3068 (defun flycheck-handle-save ()
3069   "Handle a save of the buffer."
3070   (flycheck-buffer-automatically 'save))
3071
3072 \f
3073 ;;; Deferred syntax checking
3074 (defvar-local flycheck-deferred-syntax-check nil
3075   "If non-nil, a deferred syntax check is pending.")
3076
3077 (defun flycheck-must-defer-check ()
3078   "Determine whether the syntax check has to be deferred.
3079
3080 A check has to be deferred if the buffer is not visible, or if the buffer is
3081 currently being reverted.
3082
3083 Return t if the check is to be deferred, or nil otherwise."
3084   (or (not (get-buffer-window))
3085       ;; We defer the syntax check if Flycheck is already running, to
3086       ;; immediately start a new syntax check after the current one finished,
3087       ;; because the result of the current check will most likely be outdated by
3088       ;; the time it is finished.
3089       (flycheck-running-p)
3090       ;; We must defer checks while a buffer is being reverted, to avoid race
3091       ;; conditions while the buffer contents are being restored.
3092       revert-buffer-in-progress-p))
3093
3094 (defun flycheck-deferred-check-p ()
3095   "Determine whether the current buffer has a deferred check.
3096
3097 Return t if so, or nil otherwise."
3098   flycheck-deferred-syntax-check)
3099
3100 (defun flycheck-buffer-deferred ()
3101   "Defer syntax check for the current buffer."
3102   (setq flycheck-deferred-syntax-check t))
3103
3104 (defun flycheck-clean-deferred-check ()
3105   "Clean a deferred syntax checking state."
3106   (setq flycheck-deferred-syntax-check nil))
3107
3108 (defun flycheck-perform-deferred-syntax-check ()
3109   "Perform the deferred syntax check."
3110   (when (flycheck-deferred-check-p)
3111     (flycheck-clean-deferred-check)
3112     (flycheck-buffer-automatically)))
3113
3114 \f
3115 ;;; Syntax checking in all buffers
3116 (defun flycheck-may-enable-mode ()
3117   "Determine whether Flycheck mode may be enabled.
3118
3119 Flycheck mode is not enabled for
3120
3121 - the minibuffer,
3122 - `fundamental-mode'
3123 - major modes whose `mode-class' property is `special',
3124 - ephemeral buffers (see `flycheck-ephemeral-buffer-p'),
3125 - encrypted buffers (see `flycheck-encrypted-buffer-p'),
3126 - remote files (see `file-remote-p'),
3127 - and major modes excluded by `flycheck-global-modes'.
3128
3129 Return non-nil if Flycheck mode may be enabled, and nil
3130 otherwise."
3131   (and (pcase flycheck-global-modes
3132          ;; Whether `major-mode' is disallowed by `flycheck-global-modes'
3133          (`t t)
3134          (`(not . ,modes) (not (memq major-mode modes)))
3135          (modes (memq major-mode modes)))
3136        (not (or (minibufferp)
3137                 (eq major-mode 'fundamental-mode)
3138                 (eq (get major-mode 'mode-class) 'special)
3139                 (flycheck-ephemeral-buffer-p)
3140                 (flycheck-encrypted-buffer-p)
3141                 (and (buffer-file-name)
3142                      (file-remote-p (buffer-file-name) 'method))))))
3143
3144 (defun flycheck-mode-on-safe ()
3145   "Enable command `flycheck-mode' if it is safe to do so.
3146
3147 Command `flycheck-mode' is only enabled if
3148 `flycheck-may-enable-mode' returns a non-nil result."
3149   (when (flycheck-may-enable-mode)
3150     (flycheck-mode)))
3151
3152 ;;;###autoload
3153 (define-globalized-minor-mode global-flycheck-mode flycheck-mode
3154   flycheck-mode-on-safe
3155   :init-value nil
3156   ;; Do not expose Global Flycheck Mode on customize interface, because the
3157   ;; interaction between package.el and customize is currently broken.  See
3158   ;; https://github.com/flycheck/flycheck/issues/595
3159
3160   ;; :require 'flycheck :group
3161   ;; 'flycheck
3162   )
3163
3164 (defun flycheck-global-teardown (&optional ignore-local)
3165   "Teardown Flycheck in all buffers.
3166
3167 Completely clear the whole Flycheck state in all buffers, stop
3168 all running checks, remove all temporary files, and empty all
3169 variables of Flycheck.
3170
3171 Also remove global hooks.  (If optional argument IGNORE-LOCAL is
3172 non-nil, then only do this and skip per-buffer teardown.)"
3173   (unless ignore-local
3174     (dolist (buffer (buffer-list))
3175       (with-current-buffer buffer
3176         (when flycheck-mode
3177           (flycheck-teardown 'ignore-global)))))
3178   (remove-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch))
3179
3180 ;; Clean up the entire state of Flycheck when Emacs is killed, to get rid of any
3181 ;; pending temporary files.
3182 (add-hook 'kill-emacs-hook #'flycheck-global-teardown)
3183
3184 \f
3185 ;;; Errors from syntax checks
3186 (cl-defstruct (flycheck-error
3187                (:constructor flycheck-error-new)
3188                (:constructor flycheck-error-new-at
3189                              (line column
3190                                    &optional level message
3191                                    &key checker id group
3192                                    (filename (buffer-file-name))
3193                                    (buffer (current-buffer)))))
3194   "Structure representing an error reported by a syntax checker.
3195 Slots:
3196
3197 `buffer'
3198      The buffer that the error was reported for, as buffer object.
3199
3200 `checker'
3201      The syntax checker which reported this error, as symbol.
3202
3203 `filename'
3204      The file name the error refers to, as string.
3205
3206 `line'
3207      The line number the error refers to, as number.
3208
3209 `column' (optional)
3210      The column number the error refers to, as number.
3211
3212      For compatibility with external tools and unlike Emacs
3213      itself (e.g. in Compile Mode) Flycheck uses _1-based_
3214      columns: The first character on a line is column 1.
3215
3216      Occasionally some tools try to proactively adapt to Emacs
3217      and emit 0-based columns automatically.  In these cases, the
3218      columns must be adjusted for Flycheck, see
3219      `flycheck-increment-error-columns'.
3220
3221 `message' (optional)
3222      The error message as a string, if any.
3223
3224 `level'
3225      The error level, as either `info', `warning' or `error'.
3226
3227 `id' (optional)
3228      An ID identifying the kind of error.
3229
3230 `group` (optional)
3231      A symbol identifying the group the error belongs to.
3232
3233      Some tools will emit multiple errors that relate to the same
3234      issue (e.g., lifetime errors in Rust).  All related errors
3235      collected by a checker should have the same `group` value,
3236      in order to be able to present them to the user.
3237
3238      See `flycheck-related-errors`."
3239   buffer checker filename line column message level id group)
3240
3241 (defmacro flycheck-error-with-buffer (err &rest forms)
3242   "Switch to the buffer of ERR and evaluate FORMS.
3243
3244 If the buffer of ERR is not live, FORMS are not evaluated."
3245   (declare (indent 1) (debug t))
3246   `(when (buffer-live-p (flycheck-error-buffer ,err))
3247      (with-current-buffer (flycheck-error-buffer ,err)
3248        ,@forms)))
3249
3250 (defun flycheck-error-line-region (err)
3251   "Get the line region of ERR.
3252
3253 ERR is a Flycheck error whose region to get.
3254
3255 Return a cons cell `(BEG . END)' where BEG is the first
3256 non-whitespace character on the line ERR refers to, and END the
3257 end of the line."
3258   (flycheck-error-with-buffer err
3259     (save-restriction
3260       (save-excursion
3261         (widen)
3262         (goto-char (point-min))
3263         (forward-line (- (flycheck-error-line err) 1))
3264         ;; We are at the beginning of the line now, so move to the beginning of
3265         ;; its indentation, similar to `back-to-indentation'
3266         (let ((end (line-end-position)))
3267           (skip-syntax-forward " " end)
3268           (backward-prefix-chars)
3269           ;; If the current line is empty, include the previous line break
3270           ;; character(s) to have any region at all.  When called with 0,
3271           ;; `line-end-position' gives us the end of the previous line
3272           (cons (if (eolp) (line-end-position 0) (point)) end))))))
3273
3274 (defun flycheck-error-column-region (err)
3275   "Get the error column region of ERR.
3276
3277 ERR is a Flycheck error whose region to get.
3278
3279 Return a cons cell `(BEG . END)' where BEG is the character
3280 before the error column, and END the actual error column, or nil
3281 if ERR has no column."
3282   (flycheck-error-with-buffer err
3283     (save-restriction
3284       (save-excursion
3285         (-when-let (column (flycheck-error-column err))
3286           (widen)
3287           (goto-char (point-min))
3288           (forward-line (- (flycheck-error-line err) 1))
3289           (cond
3290            ((eobp)                    ; Line beyond EOF
3291             ;; If we are at the end of the file (i.e. the line was beyond the
3292             ;; end of the file), use the very last column in the file.
3293             (cons (- (point-max) 1) (point-max)))
3294            ((eolp)                    ; Empty line
3295             ;; If the target line is empty, there's no column to highlight on
3296             ;; this line, so return the last column of the previous line.
3297             (cons (line-end-position 0) (point)))
3298            (t
3299             ;; The end is either the column offset of the line, or the end of
3300             ;; the line, if the column offset points beyond the end of the
3301             ;; line.
3302             (let ((end (min (+ (point) column)
3303                             (+ (line-end-position) 1))))
3304               (cons (- end 1) end)))))))))
3305
3306 (defun flycheck-error-thing-region (thing err)
3307   "Get the region of THING at the column of ERR.
3308
3309 ERR is a Flycheck error whose region to get.  THING is a
3310 understood by `thing-at-point'.
3311
3312 Return a cons cell `(BEG . END)' where BEG is the beginning of
3313 the THING at the error column, and END the end of the symbol.  If
3314 ERR has no error column, or if there is no THING at this column,
3315 return nil."
3316   (-when-let (column (car (flycheck-error-column-region err)))
3317     (flycheck-error-with-buffer err
3318       (save-excursion
3319         (save-restriction
3320           (widen)
3321           (goto-char column)
3322           (bounds-of-thing-at-point thing))))))
3323
3324 (defun flycheck-error-region-for-mode (err mode)
3325   "Get the region of ERR for the highlighting MODE.
3326
3327 ERR is a Flycheck error.  MODE may be one of the following symbols:
3328
3329 `columns'
3330      Get the column region of ERR, or the line region if ERR
3331      has no column.
3332
3333 `symbols'
3334      Get the symbol region of ERR, or the result of `columns', if
3335      there is no sexp at the error column.
3336
3337 `sexps'
3338      Get the sexp region of ERR, or the result of `columns', if
3339      there is no sexp at the error column.
3340
3341 `lines'
3342      Return the line region.
3343
3344 Otherwise signal an error."
3345   ;; Ignoring fields speeds up calls to `line-end-position' in
3346   ;; `flycheck-error-column-region' and `flycheck-error-line-region'.
3347   (let ((inhibit-field-text-motion t))
3348     (pcase mode
3349       (`columns (or (flycheck-error-column-region err)
3350                     (flycheck-error-line-region err)))
3351       (`symbols (or (flycheck-error-thing-region 'symbol err)
3352                     (flycheck-error-region-for-mode err 'columns)))
3353       (`sexps (or (flycheck-error-thing-region 'sexp err)
3354                   (flycheck-error-region-for-mode err 'columns)))
3355       (`lines (flycheck-error-line-region err))
3356       (_ (error "Invalid mode %S" mode)))))
3357
3358 (defun flycheck-error-pos (err)
3359   "Get the buffer position of ERR.
3360
3361 ERR is a Flycheck error whose position to get.
3362
3363 The error position is the error column, or the first
3364 non-whitespace character of the error line, if ERR has no error column."
3365   (car (or (flycheck-error-column-region err)
3366            (flycheck-error-line-region err))))
3367
3368 (defun flycheck-error-format-message-and-id (err)
3369   "Format the message and id of ERR as human-readable string."
3370   (let ((id (flycheck-error-id err))
3371         (filename (flycheck-error-filename err)))
3372     (concat (when (and filename (not (equal filename (buffer-file-name))))
3373               (format "In \"%s\":\n"
3374                       (file-relative-name filename default-directory)))
3375             (flycheck-error-message err)
3376             (when id
3377               (format " [%s]" id)))))
3378
3379 (defun flycheck-error-format (err &optional with-file-name)
3380   "Format ERR as human-readable string, optionally WITH-FILE-NAME.
3381
3382 Return a string that represents the given ERR.  If WITH-FILE-NAME
3383 is given and non-nil, include the file-name as well, otherwise
3384 omit it."
3385   (let* ((line (flycheck-error-line err))
3386          (column (flycheck-error-column err))
3387          (level (symbol-name (flycheck-error-level err)))
3388          (checker (symbol-name (flycheck-error-checker err)))
3389          (format `(,@(when with-file-name
3390                        (list (flycheck-error-filename err) ":"))
3391                    ,(number-to-string line) ":"
3392                    ,@(when column (list (number-to-string column) ":"))
3393                    ,level ": "
3394                    ,(flycheck-error-format-message-and-id err)
3395                    " (" ,checker ")")))
3396     (apply #'concat format)))
3397
3398 (defun flycheck-error-< (err1 err2)
3399   "Determine whether ERR1 is less than ERR2 by location.
3400
3401 Compare by line numbers and then by column numbers."
3402   (let ((line1 (flycheck-error-line err1))
3403         (line2 (flycheck-error-line err2)))
3404     (if (= line1 line2)
3405         (let ((col1 (flycheck-error-column err1))
3406               (col2 (flycheck-error-column err2)))
3407           (and col2
3408                ;; Sort errors for the whole line first
3409                (or (not col1) (< col1 col2))))
3410       (< line1 line2))))
3411
3412 (defun flycheck-error-level-< (err1 err2)
3413   "Determine whether ERR1 is less than ERR2 by error level.
3414
3415 Like `flycheck-error-<', but compares by error level severity
3416 first.  Levels of the same severity are compared by name."
3417   (let* ((level1 (flycheck-error-level err1))
3418          (level2 (flycheck-error-level err2))
3419          (severity1 (flycheck-error-level-severity level1))
3420          (severity2 (flycheck-error-level-severity level2)))
3421     (cond
3422      ((= severity1 severity2)
3423       (if (string= level1 level2)
3424           (flycheck-error-< err1 err2)
3425         (string< level1 level2)))
3426      (t (< severity1 severity2)))))
3427
3428 (defun flycheck-assert-error-list-p (errors)
3429   "Assert that all items in ERRORS are of `flycheck-error' type.
3430
3431 Signal an error if any item in ERRORS is not a `flycheck-error'
3432 object, as by `flycheck-error-p'.  Otherwise return ERRORS
3433 again."
3434   (unless (listp errors)
3435     (signal 'wrong-type-argument (list 'listp errors)))
3436   (dolist (err errors)
3437     (unless (flycheck-error-p err)
3438       (signal 'wrong-type-argument (list 'flycheck-error-p err))))
3439   errors)
3440
3441 \f
3442 ;;; Errors in the current buffer
3443 (defvar-local flycheck-current-errors nil
3444   "A list of all errors and warnings in the current buffer.")
3445
3446 (defun flycheck-report-current-errors (errors)
3447   "Report ERRORS in the current buffer.
3448
3449 Add ERRORS to `flycheck-current-errors' and process each error
3450 with `flycheck-process-error-functions'."
3451   (setq flycheck-current-errors (sort (append errors flycheck-current-errors)
3452                                       #'flycheck-error-<))
3453   (overlay-recenter (point-max))
3454   (seq-do (lambda (err)
3455             (run-hook-with-args-until-success 'flycheck-process-error-functions
3456                                               err))
3457           errors))
3458
3459 (defun flycheck-clear-errors ()
3460   "Remove all error information from the current buffer."
3461   (setq flycheck-current-errors nil)
3462   (flycheck-report-status 'not-checked))
3463
3464 (defun flycheck-fill-and-expand-error-file-names (errors directory)
3465   "Fill and expand file names in ERRORS relative to DIRECTORY.
3466
3467 Expand all file names of ERRORS against DIRECTORY.  If the file
3468 name of an error is nil fill in the result of function
3469 `buffer-file-name' in the current buffer.
3470
3471 Return ERRORS, modified in-place."
3472   (seq-do (lambda (err)
3473             (setf (flycheck-error-filename err)
3474                   (-if-let (filename (flycheck-error-filename err))
3475                       (expand-file-name filename directory)
3476                     (buffer-file-name))))
3477           errors)
3478   errors)
3479
3480 (defun flycheck-relevant-error-other-file-p (err)
3481   "Determine whether ERR is a relevant error for another file."
3482   (let ((file-name (flycheck-error-filename err)))
3483     (and file-name
3484          (or (null buffer-file-name)
3485              (not (flycheck-same-files-p buffer-file-name file-name)))
3486          (<= (flycheck-error-level-severity
3487               flycheck-relevant-error-other-file-minimum-level)
3488              (flycheck-error-level-severity (flycheck-error-level err))))))
3489
3490 (defun flycheck-relevant-error-p (err)
3491   "Determine whether ERR is relevant for the current buffer.
3492
3493 Return t if ERR may be shown for the current buffer, or nil
3494 otherwise."
3495   (flycheck-error-with-buffer err
3496     (let ((file-name (flycheck-error-filename err))
3497           (message (flycheck-error-message err)))
3498       (and
3499        (or
3500         ;; Neither the error nor buffer have a file name
3501         (and (not file-name) (not buffer-file-name))
3502         ;; Both have files, and they match
3503         (and buffer-file-name file-name
3504              (flycheck-same-files-p file-name buffer-file-name))
3505         ;; This is a significant error from another file
3506         (flycheck-relevant-error-other-file-p err))
3507        message
3508        (not (string-empty-p message))
3509        (flycheck-error-line err)))))
3510
3511 (defun flycheck-relevant-errors (errors)
3512   "Filter the relevant errors from ERRORS.
3513
3514 Return a list of all errors that are relevant for their
3515 corresponding buffer."
3516   (seq-filter #'flycheck-relevant-error-p errors))
3517
3518 (defun flycheck-related-errors (err &optional error-set)
3519   "Get all the errors that are in the same group as ERR.
3520
3521 Return a list of all errors (from ERROR-SET) that have the same
3522 `flycheck-error-group' as ERR, including ERR itself.
3523
3524 If ERROR-SET is nil, `flycheck-current-errors' is used instead."
3525   (let ((group (flycheck-error-group err))
3526         (checker (flycheck-error-checker err)))
3527     (if group
3528         (seq-filter (lambda (e)
3529                       (and (eq (flycheck-error-checker e) checker)
3530                            (eq (flycheck-error-group e) group)))
3531                     (or error-set flycheck-current-errors))
3532       (list err))))
3533
3534 \f
3535 ;;; Status reporting for the current buffer
3536 (defvar-local flycheck-last-status-change 'not-checked
3537   "The last status change in the current buffer.")
3538
3539 (defun flycheck-report-failed-syntax-check (&optional status)
3540   "Report a failed Flycheck syntax check with STATUS.
3541
3542 STATUS is a status symbol for `flycheck-report-status',
3543 defaulting to `errored'.
3544
3545 Clear Flycheck state, run `flycheck-syntax-check-failed-hook' and
3546 report an error STATUS."
3547   (flycheck-clear)
3548   (setq flycheck-current-syntax-check nil)
3549   (run-hooks 'flycheck-syntax-check-failed-hook)
3550   (flycheck-report-status (or status 'errored)))
3551
3552 (defun flycheck-report-status (status)
3553   "Report Flycheck STATUS.
3554
3555 STATUS is one of the following symbols:
3556
3557 `not-checked'
3558      The current buffer was not checked.
3559
3560 `no-checker'
3561      Automatic syntax checker selection did not find a suitable
3562      syntax checker.
3563
3564 `running'
3565      A syntax check is now running in the current buffer.
3566
3567 `errored'
3568      The current syntax check has errored.
3569
3570 `finished'
3571      The current syntax check was finished normally.
3572
3573 `interrupted'
3574      The current syntax check was interrupted.
3575
3576 `suspicious'
3577      The last syntax check had a suspicious result.
3578
3579 Set `flycheck-last-status-change' and call
3580 `flycheck-status-changed-functions' with STATUS.  Afterwards
3581 refresh the mode line."
3582   (setq flycheck-last-status-change status)
3583   (run-hook-with-args 'flycheck-status-changed-functions status)
3584   (force-mode-line-update))
3585
3586 (defun flycheck-mode-line-status-text (&optional status)
3587   "Get a text describing STATUS for use in the mode line.
3588
3589 STATUS defaults to `flycheck-last-status-change' if omitted or
3590 nil."
3591   (let ((text (pcase (or status flycheck-last-status-change)
3592                 (`not-checked "")
3593                 (`no-checker "-")
3594                 (`running "*")
3595                 (`errored "!")
3596                 (`finished
3597                  (let-alist (flycheck-count-errors flycheck-current-errors)
3598                    (if (or .error .warning)
3599                        (format ":%s/%s" (or .error 0) (or .warning 0))
3600                      "")))
3601                 (`interrupted ".")
3602                 (`suspicious "?"))))
3603     (concat " " flycheck-mode-line-prefix text)))
3604
3605 \f
3606 ;;; Error levels
3607 ;;;###autoload
3608 (defun flycheck-define-error-level (level &rest properties)
3609   "Define a new error LEVEL with PROPERTIES.
3610
3611 The following PROPERTIES constitute an error level:
3612
3613 `:severity SEVERITY'
3614      A number denoting the severity of this level.  The higher
3615      the number, the more severe is this level compared to other
3616      levels.  Defaults to 0.
3617
3618      The severity is used by `flycheck-error-level-<' to
3619      determine the ordering of errors according to their levels.
3620
3621 `:compilation-level LEVEL'
3622
3623      A number indicating the broad class of messages that errors
3624      at this level belong to: one of 0 (info), 1 (warning), or
3625      2 or nil (error).  Defaults to nil.
3626
3627      This is used by `flycheck-checker-pattern-to-error-regexp'
3628      to map error levels into `compilation-mode''s hierarchy and
3629      to get proper highlighting of errors in `compilation-mode'.
3630
3631 `:overlay-category CATEGORY'
3632      A symbol denoting the overlay category to use for error
3633      highlight overlays for this level.  See Info
3634      node `(elisp)Overlay Properties' for more information about
3635      overlay categories.
3636
3637      A category for an error level overlay should at least define
3638      the `face' property, for error highlighting.  Another useful
3639      property for error level categories is `priority', to
3640      influence the stacking of multiple error level overlays.
3641
3642 `:fringe-bitmap BITMAP'
3643      A fringe bitmap symbol denoting the bitmap to use for fringe
3644      indicators for this level.  See Info node `(elisp)Fringe
3645      Bitmaps' for more information about fringe bitmaps,
3646      including a list of built-in fringe bitmaps.
3647
3648 `:fringe-face FACE'
3649      A face symbol denoting the face to use for fringe indicators
3650      for this level.
3651
3652 `:error-list-face FACE'
3653      A face symbol denoting the face to use for messages of this
3654      level in the error list.  See `flycheck-list-errors'."
3655   (declare (indent 1))
3656   (setf (get level 'flycheck-error-level) t)
3657   (setf (get level 'flycheck-error-severity)
3658         (or (plist-get properties :severity) 0))
3659   (setf (get level 'flycheck-compilation-level)
3660         (plist-get properties :compilation-level))
3661   (setf (get level 'flycheck-overlay-category)
3662         (plist-get properties :overlay-category))
3663   (setf (get level 'flycheck-fringe-bitmap-double-arrow)
3664         (plist-get properties :fringe-bitmap))
3665   (setf (get level 'flycheck-fringe-face)
3666         (plist-get properties :fringe-face))
3667   (setf (get level 'flycheck-error-list-face)
3668         (plist-get properties :error-list-face)))
3669
3670 (defun flycheck-error-level-p (level)
3671   "Determine whether LEVEL is a Flycheck error level."
3672   (get level 'flycheck-error-level))
3673
3674 (defun flycheck-error-level-severity (level)
3675   "Get the numeric severity of LEVEL."
3676   (or (get level 'flycheck-error-severity) 0))
3677
3678 (defun flycheck-error-level-compilation-level (level)
3679   "Get the compilation level for LEVEL."
3680   (get level 'flycheck-compilation-level))
3681
3682 (defun flycheck-error-level-overlay-category (level)
3683   "Get the overlay category for LEVEL."
3684   (get level 'flycheck-overlay-category))
3685
3686 (defun flycheck-error-level-fringe-bitmap (level)
3687   "Get the fringe bitmap for LEVEL."
3688   (get level 'flycheck-fringe-bitmap-double-arrow))
3689
3690 (defun flycheck-error-level-fringe-face (level)
3691   "Get the fringe face for LEVEL."
3692   (get level 'flycheck-fringe-face))
3693
3694 (defun flycheck-error-level-error-list-face (level)
3695   "Get the error list face for LEVEL."
3696   (get level 'flycheck-error-list-face))
3697
3698 (defun flycheck-error-level-make-fringe-icon (level side)
3699   "Create the fringe icon for LEVEL at SIDE.
3700
3701 Return a propertized string that shows a fringe bitmap according
3702 to LEVEL and the given fringe SIDE.
3703
3704 LEVEL is a Flycheck error level defined with
3705 `flycheck-define-error-level', and SIDE is either `left-fringe'
3706 or `right-fringe'.
3707
3708 Return a propertized string representing the fringe icon,
3709 intended for use as `before-string' of an overlay to actually
3710 show the icon."
3711   (unless (memq side '(left-fringe right-fringe))
3712     (error "Invalid fringe side: %S" side))
3713   (propertize "!" 'display
3714               (list side
3715                     (flycheck-error-level-fringe-bitmap level)
3716                     (flycheck-error-level-fringe-face level))))
3717
3718 \f
3719 ;;; Built-in error levels
3720 (when (fboundp 'define-fringe-bitmap)
3721   (define-fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
3722     (vector #b00000000
3723             #b00000000
3724             #b00000000
3725             #b00000000
3726             #b00000000
3727             #b10011000
3728             #b01101100
3729             #b00110110
3730             #b00011011
3731             #b00110110
3732             #b01101100
3733             #b10011000
3734             #b00000000
3735             #b00000000
3736             #b00000000
3737             #b00000000
3738             #b00000000)))
3739
3740 (setf (get 'flycheck-error-overlay 'face) 'flycheck-error)
3741 (setf (get 'flycheck-error-overlay 'priority) 110)
3742
3743 (flycheck-define-error-level 'error
3744   :severity 100
3745   :compilation-level 2
3746   :overlay-category 'flycheck-error-overlay
3747   :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
3748   :fringe-face 'flycheck-fringe-error
3749   :error-list-face 'flycheck-error-list-error)
3750
3751 (setf (get 'flycheck-warning-overlay 'face) 'flycheck-warning)
3752 (setf (get 'flycheck-warning-overlay 'priority) 100)
3753
3754 (flycheck-define-error-level 'warning
3755   :severity 10
3756   :compilation-level 1
3757   :overlay-category 'flycheck-warning-overlay
3758   :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
3759   :fringe-face 'flycheck-fringe-warning
3760   :error-list-face 'flycheck-error-list-warning)
3761
3762 (setf (get 'flycheck-info-overlay 'face) 'flycheck-info)
3763 (setf (get 'flycheck-info-overlay 'priority) 90)
3764
3765 (flycheck-define-error-level 'info
3766   :severity -10
3767   :compilation-level 0
3768   :overlay-category 'flycheck-info-overlay
3769   :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
3770   :fringe-face 'flycheck-fringe-info
3771   :error-list-face 'flycheck-error-list-info)
3772
3773 \f
3774 ;;; Error filtering
3775 (defun flycheck-filter-errors (errors checker)
3776   "Filter ERRORS from CHECKER.
3777
3778 Apply the error filter of CHECKER to ERRORs and return the
3779 result.  If CHECKER has no error filter, fall back to
3780 `flycheck-sanitize-errors'."
3781   (let ((filter (or (flycheck-checker-get checker 'error-filter)
3782                     #'flycheck-sanitize-errors)))
3783     (funcall filter errors)))
3784
3785 (defun flycheck-sanitize-errors (errors)
3786   "Sanitize ERRORS.
3787
3788 Sanitize ERRORS by trimming leading and trailing whitespace in
3789 all error messages, and by replacing 0 columns and empty error
3790 messages with nil.
3791
3792 Returns sanitized ERRORS."
3793   (dolist (err errors)
3794     (flycheck-error-with-buffer err
3795       (let ((message (flycheck-error-message err))
3796             (column (flycheck-error-column err))
3797             (id (flycheck-error-id err)))
3798         (when message
3799           (setq message (string-trim message))
3800           (setf (flycheck-error-message err)
3801                 (if (string-empty-p message) nil message)))
3802         (when (and id (string-empty-p id))
3803           (setf (flycheck-error-id err) nil))
3804         (when (eq column 0)
3805           (setf (flycheck-error-column err) nil)))))
3806   errors)
3807
3808 (defun flycheck-remove-error-file-names (file-name errors)
3809   "Remove matching FILE-NAME from ERRORS.
3810
3811 Use as `:error-filter' for syntax checkers that output faulty
3812 filenames.  Flycheck will later fill in the buffer file name.
3813
3814 Return ERRORS."
3815   (seq-do (lambda (err)
3816             (when (and (flycheck-error-filename err)
3817                        (string= (flycheck-error-filename err) file-name))
3818               (setf (flycheck-error-filename err) nil)))
3819           errors)
3820   errors)
3821
3822 (defun flycheck-increment-error-columns (errors &optional offset)
3823   "Increment all columns of ERRORS by OFFSET.
3824
3825 Use this as `:error-filter' if a syntax checker outputs 0-based
3826 columns."
3827   (seq-do (lambda (err)
3828             (let ((column (flycheck-error-column err)))
3829               (when column
3830                 (setf (flycheck-error-column err)
3831                       (+ column (or offset 1))))))
3832           errors)
3833   errors)
3834
3835 (defun flycheck-collapse-error-message-whitespace (errors)
3836   "Collapse whitespace in all messages of ERRORS.
3837
3838 Return ERRORS."
3839   (dolist (err errors)
3840     (-when-let (message (flycheck-error-message err))
3841       (setf (flycheck-error-message err)
3842             (replace-regexp-in-string (rx (one-or-more (any space "\n" "\r")))
3843                                       " " message 'fixed-case 'literal))))
3844   errors)
3845
3846 (defun flycheck-dedent-error-messages (errors)
3847   "Dedent all messages of ERRORS.
3848
3849 For each error in ERRORS, determine the indentation offset from
3850 the leading whitespace of the first line, and dedent all further
3851 lines accordingly.
3852
3853 Return ERRORS, with in-place modifications."
3854   (dolist (err errors)
3855     (-when-let (message (flycheck-error-message err))
3856       (with-temp-buffer
3857         (insert message)
3858         ;; Determine the indentation offset
3859         (goto-char (point-min))
3860         (back-to-indentation)
3861         (let* ((indent-offset (- (point) (point-min))))
3862           ;; Now iterate over all lines and dedent each according to
3863           ;; `indent-offset'
3864           (while (not (eobp))
3865             (back-to-indentation)
3866             ;; If the current line starts with sufficient whitespace, delete the
3867             ;; indendation offset.  Otherwise keep the line intact, as we might
3868             ;; loose valuable information
3869             (when (>= (- (point) (line-beginning-position)) indent-offset)
3870               (delete-char (- indent-offset)))
3871             (forward-line 1)))
3872         (delete-trailing-whitespace (point-min) (point-max))
3873         (setf (flycheck-error-message err)
3874               (buffer-substring-no-properties (point-min) (point-max))))))
3875   errors)
3876
3877 (defun flycheck-fold-include-levels (errors sentinel-message)
3878   "Fold levels of ERRORS from included files.
3879
3880 ERRORS is a list of `flycheck-error' objects.  SENTINEL-MESSAGE
3881 is a regular expression matched against the error message to
3882 determine whether the errror denotes errors from an included
3883 file.  Alternatively, it is a function that is given an error and
3884 shall return non-nil, if the error denotes errors from an
3885 included file."
3886   (unless (or (stringp sentinel-message) (functionp sentinel-message))
3887     (error "Sentinel must be string or function: %S" sentinel-message))
3888   (let ((sentinel (if (functionp sentinel-message)
3889                       sentinel-message
3890                     (lambda (err)
3891                       (string-match-p sentinel-message
3892                                       (flycheck-error-message err)))))
3893         (remaining-errors errors))
3894     (while remaining-errors
3895       (let* ((current-error (pop remaining-errors)))
3896         (when (funcall sentinel current-error)
3897           ;; We found an error denoting errors in the included file:
3898           ;; 1. process all subsequent errors until faulty include file is found
3899           ;; 2. process again all subsequent errors until an error has the
3900           ;;    current file name again
3901           ;; 3. find the most severe error level
3902           (let ((current-filename (flycheck-error-filename current-error))
3903                 (current-level nil)
3904                 (faulty-include-filename nil)
3905                 (filename nil)
3906                 (done (null remaining-errors)))
3907
3908             (while (not done)
3909               (setq filename (flycheck-error-filename (car remaining-errors)))
3910               (unless faulty-include-filename
3911                 (unless (string= filename current-filename)
3912                   (setq faulty-include-filename filename)))
3913
3914               (let* ((error-in-include (pop remaining-errors))
3915                      (in-include-level (flycheck-error-level error-in-include)))
3916                 (unless (funcall sentinel error-in-include)
3917                   ;; Ignore nested "included file" errors, we are only
3918                   ;; interested in real errors because these define our level
3919                   (when (or (not current-level)
3920                             (> (flycheck-error-level-severity in-include-level)
3921                                (flycheck-error-level-severity current-level)))
3922                     (setq current-level in-include-level))))
3923
3924               (setq done (or (null remaining-errors)
3925                              (and faulty-include-filename
3926                                   (string= filename current-filename)))))
3927
3928             (setf (flycheck-error-level current-error) current-level
3929                   (flycheck-error-message current-error)
3930                   (format "In include %s" faulty-include-filename))))))
3931     errors))
3932
3933 (defun flycheck-dequalify-error-ids (errors)
3934   "De-qualify error ids in ERRORS.
3935
3936 Remove all qualifications from error ids in ERRORS, by stripping
3937 all leading dotted components from error IDs.  For instance, if
3938 the error ID is com.foo.E100, replace it with E100.
3939
3940 This error filter is mainly useful to simplify error IDs obtained
3941 from parsing Checkstyle XML, which frequently has very verbose
3942 IDs, that include the name of the tool."
3943   (seq-do (lambda (err)
3944             (let ((id (flycheck-error-id err)))
3945               (when id
3946                 (setf (flycheck-error-id err)
3947                       (replace-regexp-in-string
3948                        (rx string-start
3949                            (group
3950                             (optional (zero-or-more not-newline) "."))
3951                            (one-or-more (not (any ".")))
3952                            string-end)
3953                        "" id 'fixedcase 'literal 1)))))
3954           errors)
3955   errors)
3956
3957 (defun flycheck-remove-error-ids (errors)
3958   "Remove all error ids from ERRORS."
3959   (seq-do (lambda (err) (setf (flycheck-error-id err) nil)) errors)
3960   errors)
3961
3962 (defun flycheck-fill-empty-line-numbers (errors)
3963   "Set ERRORS without lines to line 0.
3964
3965 Use as `:error-filter' for syntax checkers that output errors
3966 without line numbers.
3967
3968 Return ERRORS."
3969   (seq-do (lambda (err)
3970             (unless (flycheck-error-line err)
3971               (setf (flycheck-error-line err) 0)))
3972           errors)
3973   errors)
3974
3975 \f
3976 ;;; Error analysis
3977 (defun flycheck-count-errors (errors)
3978   "Count the number of ERRORS, grouped by level..
3979
3980 Return an alist, where each ITEM is a cons cell whose `car' is an
3981 error level, and whose `cdr' is the number of errors of that
3982 level."
3983   (let (counts-by-level)
3984     (dolist (err errors)
3985       (let* ((level (flycheck-error-level err))
3986              (item (assq level counts-by-level)))
3987         (if item
3988             (cl-incf (cdr item))
3989           (push (cons level 1) counts-by-level))))
3990     counts-by-level))
3991
3992 (defun flycheck-has-max-errors-p (errors level)
3993   "Check if there is no error in ERRORS more severe than LEVEL."
3994   (let ((severity (flycheck-error-level-severity level)))
3995     (seq-every-p (lambda (e) (<= (flycheck-error-level-severity
3996                                   (flycheck-error-level e))
3997                                  severity))
3998                  errors)))
3999
4000 (defun flycheck-has-max-current-errors-p (level)
4001   "Check if there is no current error more severe than LEVEL."
4002   (flycheck-has-max-errors-p flycheck-current-errors level))
4003
4004 (defun flycheck-has-errors-p (errors level)
4005   "Determine if there are any ERRORS with LEVEL."
4006   (seq-some (lambda (e) (eq (flycheck-error-level e) level)) errors))
4007
4008 (defun flycheck-has-current-errors-p (&optional level)
4009   "Determine if the current buffer has errors with LEVEL.
4010
4011 If LEVEL is omitted if the current buffer has any errors at all."
4012   (if level
4013       (flycheck-has-errors-p flycheck-current-errors level)
4014     (and flycheck-current-errors t)))
4015
4016 \f
4017 ;;; Error overlays in the current buffer
4018 (defun flycheck-add-overlay (err)
4019   "Add overlay for ERR.
4020
4021 Return the created overlay."
4022   ;; We must have a proper error region for the sake of fringe indication,
4023   ;; error display and error navigation, even if the highlighting is disabled.
4024   ;; We erase the highlighting later on in this case
4025   (pcase-let* ((`(,beg . ,end)
4026                 (if (flycheck-relevant-error-other-file-p err)
4027                     ;; Display overlays for other-file errors on the first line
4028                     (cons (point-min)
4029                           (save-excursion (goto-char (point-min))
4030                                           (point-at-eol)))
4031                   (flycheck-error-region-for-mode
4032                    err (or flycheck-highlighting-mode 'lines))))
4033                (overlay (make-overlay beg end))
4034                (level (flycheck-error-level err))
4035                (category (flycheck-error-level-overlay-category level)))
4036     (unless (flycheck-error-level-p level)
4037       (error "Undefined error level: %S" level))
4038     (setf (overlay-get overlay 'flycheck-overlay) t)
4039     (setf (overlay-get overlay 'flycheck-error) err)
4040     (setf (overlay-get overlay 'category) category)
4041     (unless flycheck-highlighting-mode
4042       ;; Erase the highlighting from the overlay if requested by the user
4043       (setf (overlay-get overlay 'face) nil))
4044     (when flycheck-indication-mode
4045       (setf (overlay-get overlay 'before-string)
4046             (flycheck-error-level-make-fringe-icon
4047              level flycheck-indication-mode)))
4048     (setf (overlay-get overlay 'help-echo) #'flycheck-help-echo)
4049     overlay))
4050
4051 (defun flycheck-help-echo (_window object pos)
4052   "Construct a tooltip message.
4053
4054 Most of the actual work is done by calling
4055 `flycheck-help-echo-function' with the appropriate list of
4056 errors.  Arguments WINDOW, OBJECT and POS are as described in
4057 info node `(elisp)Special properties', as this function is
4058 intended to be used as the 'help-echo property of flycheck error
4059 overlays."
4060   (-when-let (buf (cond ((bufferp object) object)
4061                         ((overlayp object) (overlay-buffer object))))
4062     (with-current-buffer buf
4063       (-when-let* ((fn flycheck-help-echo-function)
4064                    (errs (flycheck-overlay-errors-at pos)))
4065         (funcall fn errs)))))
4066
4067 (defun flycheck-help-echo-all-error-messages (errs)
4068   "Concatenate error messages and ids from ERRS."
4069   (mapconcat
4070    (lambda (err)
4071      (when err
4072        (if (flycheck-error-message err)
4073            (flycheck-error-format-message-and-id err)
4074          (format "Unknown %s" (flycheck-error-level err)))))
4075    (reverse errs) "\n\n"))
4076
4077 (defun flycheck-filter-overlays (overlays)
4078   "Get all Flycheck overlays from OVERLAYS."
4079   (seq-filter (lambda (o) (overlay-get o 'flycheck-overlay)) overlays))
4080
4081 (defun flycheck-overlays-at (pos)
4082   "Get all Flycheck overlays at POS."
4083   (flycheck-filter-overlays (overlays-at pos)))
4084
4085 (defun flycheck-overlays-in (beg end)
4086   "Get all Flycheck overlays between BEG and END."
4087   (flycheck-filter-overlays (overlays-in beg end)))
4088
4089 (defun flycheck-overlay-errors-at (pos)
4090   "Return a list of all flycheck errors overlayed at POS."
4091   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
4092            (flycheck-overlays-at pos)))
4093
4094 (defun flycheck-overlay-errors-in (beg end)
4095   "Return a list of all flycheck errors overlayed between BEG and END."
4096   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
4097            (flycheck-overlays-in beg end)))
4098
4099 (defvar-local flycheck-overlays-to-delete nil
4100   "Overlays mark for deletion after all syntax checks completed.")
4101 (put 'flycheck-overlays-to-delete 'permanent-local t)
4102
4103 (defun flycheck-delete-all-overlays ()
4104   "Remove all flycheck overlays in the current buffer."
4105   (overlay-recenter (point-max))
4106   (flycheck-delete-marked-overlays)
4107   (save-restriction
4108     (widen)
4109     (seq-do #'delete-overlay (flycheck-overlays-in (point-min) (point-max)))))
4110
4111 (defun flycheck-mark-all-overlays-for-deletion ()
4112   "Mark all current overlays for deletion."
4113   (setq flycheck-overlays-to-delete
4114         (append (flycheck-overlays-in (point-min) (point-max))
4115                 flycheck-overlays-to-delete)))
4116
4117 (defun flycheck-delete-marked-overlays ()
4118   "Delete all overlays marked for deletion."
4119   (overlay-recenter (point-max))
4120   (seq-do #'delete-overlay flycheck-overlays-to-delete)
4121   (setq flycheck-overlays-to-delete nil))
4122
4123 \f
4124 ;;; Error navigation in the current buffer
4125 (defun flycheck-error-level-interesting-at-pos-p (pos)
4126   "Check if error severity at POS passes `flycheck-error-level-interesting-p'."
4127   (flycheck-error-level-interesting-p (get-char-property pos 'flycheck-error)))
4128
4129 (defun flycheck-error-level-interesting-p (err)
4130   "Check if ERR severity is >= `flycheck-navigation-minimum-level'."
4131   (when (flycheck-error-p err)
4132     (-if-let (min-level flycheck-navigation-minimum-level)
4133         (<= (flycheck-error-level-severity min-level)
4134             (flycheck-error-level-severity (flycheck-error-level err)))
4135       t)))
4136
4137 (defun flycheck-next-error-pos (n &optional reset)
4138   "Get the position of the N-th next error.
4139
4140 With negative N, get the position of the (-N)-th previous error
4141 instead.  With non-nil RESET, search from `point-min', otherwise
4142 search from the current point.
4143
4144 Return the position of the next or previous error, or nil if
4145 there is none.  If N is zero, return `point', or `point-min' if
4146 RESET is non-nil."
4147   (let ((n (or n 1))
4148         (pos (if reset (point-min) (point))))
4149     (if (>= n 0)
4150         ;; Search forwards
4151         (while (and pos (> n 0))
4152           (setq n (1- n))
4153           (when (get-char-property pos 'flycheck-error)
4154             ;; Move beyond from the current error if any
4155             (setq pos (next-single-char-property-change pos 'flycheck-error)))
4156           (while (not (or (= pos (point-max))
4157                           (flycheck-error-level-interesting-at-pos-p pos)))
4158             ;; Scan for the next error
4159             (setq pos (next-single-char-property-change pos 'flycheck-error)))
4160           (when (and (= pos (point-max))
4161                      (not (flycheck-error-level-interesting-at-pos-p pos)))
4162             ;; If we reached the end of the buffer, but no error, we didn't find
4163             ;; any
4164             (setq pos nil)))
4165       ;; Search backwards
4166       (while (and pos (< n 0))
4167         (setq n (1+ n))
4168         ;; Loop until we find an error.  We need to check the position *before*
4169         ;; the current one, because `previous-single-char-property-change'
4170         ;; always moves to the position *of* the change.
4171         (while (not (or (= pos (point-min))
4172                         (flycheck-error-level-interesting-at-pos-p (1- pos))))
4173           (setq pos (previous-single-char-property-change pos 'flycheck-error)))
4174         (when (and (= pos (point-min))
4175                    (not (flycheck-error-level-interesting-at-pos-p pos)))
4176           ;; We didn't find any error.
4177           (setq pos nil))
4178         (when pos
4179           ;; We found an error, so move to its beginning
4180           (setq pos (previous-single-char-property-change pos
4181                                                           'flycheck-error)))))
4182     pos))
4183
4184 (defun flycheck-next-error-function (n reset)
4185   "Visit the N-th error from the current point.
4186
4187 N is the number of errors to advance by, where a negative N
4188 advances backwards.  With non-nil RESET, advance from the
4189 beginning of the buffer, otherwise advance from the current
4190 position.
4191
4192 Intended for use with `next-error-function'."
4193   (-if-let* ((pos (flycheck-next-error-pos n reset))
4194              (err (get-char-property pos 'flycheck-error)))
4195       (flycheck-jump-to-error err)
4196     (user-error "No more Flycheck errors")))
4197
4198 (defun flycheck-next-error (&optional n reset)
4199   "Visit the N-th error from the current point.
4200
4201 N is the number of errors to advance by, where a negative N
4202 advances backwards.  With non-nil RESET, advance from the
4203 beginning of the buffer, otherwise advance from the current
4204 position."
4205   (interactive "P")
4206   (when (consp n)
4207     ;; Universal prefix argument means reset
4208     (setq reset t n nil))
4209   (flycheck-next-error-function n reset)
4210   (flycheck-display-error-at-point))
4211
4212 (defun flycheck-previous-error (&optional n)
4213   "Visit the N-th previous error.
4214
4215 If given, N specifies the number of errors to move backwards by.
4216 If N is negative, move forwards instead."
4217   (interactive "P")
4218   (flycheck-next-error (- (or n 1))))
4219
4220 (defun flycheck-first-error (&optional n)
4221   "Visit the N-th error from beginning of the buffer.
4222
4223 If given, N specifies the number of errors to move forward from
4224 the beginning of the buffer."
4225   (interactive "P")
4226   (flycheck-next-error n 'reset))
4227
4228 \f
4229 ;;; Listing errors in buffers
4230 (defconst flycheck-error-list-buffer "*Flycheck errors*"
4231   "The name of the buffer to show error lists.")
4232
4233 (defvar flycheck-error-list-mode-map
4234   (let ((map (make-sparse-keymap)))
4235     (define-key map (kbd "f") #'flycheck-error-list-set-filter)
4236     (define-key map (kbd "F") #'flycheck-error-list-reset-filter)
4237     (define-key map (kbd "n") #'flycheck-error-list-next-error)
4238     (define-key map (kbd "p") #'flycheck-error-list-previous-error)
4239     (define-key map (kbd "g") #'flycheck-error-list-check-source)
4240     (define-key map (kbd "e") #'flycheck-error-list-explain-error)
4241     (define-key map (kbd "RET") #'flycheck-error-list-goto-error)
4242     map)
4243   "The keymap of `flycheck-error-list-mode'.")
4244
4245 (defun flycheck-error-list-make-last-column (message checker)
4246   "Compute contents of the last error list cell.
4247
4248 MESSAGE and CHECKER are displayed in a single column to allow the
4249 message to stretch arbitrarily far."
4250   (let ((checker-name (propertize (symbol-name checker)
4251                                   'face 'flycheck-error-list-checker-name)))
4252     (format "%s (%s)" message checker-name)))
4253
4254 (defconst flycheck-error-list-format
4255   `[("File" 6)
4256     ("Line" 5 flycheck-error-list-entry-< :right-align t)
4257     ("Col" 3 nil :right-align t)
4258     ("Level" 8 flycheck-error-list-entry-level-<)
4259     ("ID" 6 t)
4260     (,(flycheck-error-list-make-last-column "Message" 'Checker) 0 t)]
4261   "Table format for the error list.")
4262
4263 (defconst flycheck-error-list-padding 1
4264   "Padding used in error list.")
4265
4266 (defconst flycheck--error-list-msg-offset
4267   (seq-reduce
4268    (lambda (offset fmt)
4269      (pcase-let* ((`(,_ ,width ,_ . ,props) fmt)
4270                   (padding (or (plist-get props :pad-right) 1)))
4271        (+ offset width padding)))
4272    (seq-subseq flycheck-error-list-format 0 -1)
4273    flycheck-error-list-padding)
4274   "Amount of space to use in `flycheck-flush-multiline-message'.")
4275
4276 (define-derived-mode flycheck-error-list-mode tabulated-list-mode
4277   "Flycheck errors"
4278   "Major mode for listing Flycheck errors.
4279
4280 \\{flycheck-error-list-mode-map}"
4281   (setq tabulated-list-format flycheck-error-list-format
4282         ;; Sort by location initially
4283         tabulated-list-sort-key (cons "Line" nil)
4284         tabulated-list-padding flycheck-error-list-padding
4285         tabulated-list-entries #'flycheck-error-list-entries
4286         ;; `revert-buffer' updates the mode line for us, so all we need to do is
4287         ;; set the corresponding mode line construct.
4288         mode-line-buffer-identification flycheck-error-list-mode-line)
4289   ;; Guard `truncate-string-ellipsis' for Emacs 24.
4290   ;; TODO: Remove when dropping Emacs 24 compatibility
4291   (when (boundp 'truncate-string-ellipsis)
4292     ;; See https://github.com/flycheck/flycheck/issues/1101
4293     (setq-local truncate-string-ellipsis "…"))
4294   (tabulated-list-init-header))
4295
4296 (defvar-local flycheck-error-list-source-buffer nil
4297   "The current source buffer of the error list.")
4298 ;; Needs to permanently local to preserve the source buffer across buffer
4299 ;; reversions
4300 (put 'flycheck-error-list-source-buffer 'permanent-local t)
4301
4302 (defun flycheck-error-list-set-source (buffer)
4303   "Set BUFFER as the source buffer of the error list."
4304   (when (get-buffer flycheck-error-list-buffer)
4305     (with-current-buffer flycheck-error-list-buffer
4306       ;; Only update the source when required
4307       (unless (eq buffer flycheck-error-list-source-buffer)
4308         (setq flycheck-error-list-source-buffer buffer)
4309         (flycheck-error-list-refresh)))))
4310
4311 (defun flycheck-error-list-update-source ()
4312   "Update the source buffer of the error list."
4313   (when (not (eq (current-buffer) (get-buffer flycheck-error-list-buffer)))
4314     ;; We must not update the source buffer, if the current buffer is the error
4315     ;; list itself.
4316     (flycheck-error-list-set-source (current-buffer))))
4317
4318 (defun flycheck-error-list-check-source ()
4319   "Trigger a syntax check in the source buffer of the error list."
4320   (interactive)
4321   (let ((buffer (get-buffer flycheck-error-list-source-buffer)))
4322     (when (buffer-live-p buffer)
4323       (with-current-buffer buffer
4324         (flycheck-buffer)))))
4325
4326 (define-button-type 'flycheck-error-list
4327   'action #'flycheck-error-list-button-goto-error
4328   'help-echo "mouse-1, RET: goto error"
4329   'face nil)
4330
4331 (defun flycheck-error-list-button-goto-error (button)
4332   "Go to the error at BUTTON."
4333   (flycheck-error-list-goto-error (button-start button)))
4334
4335 (define-button-type 'flycheck-error-list-explain-error
4336   'action #'flycheck-error-list-button-explain-error
4337   'help-echo "mouse-1, RET: explain error")
4338
4339 (defun flycheck-error-list-button-explain-error (button)
4340   "Explain the error at BUTTON."
4341   (flycheck-error-list-explain-error (button-start button)))
4342
4343 (defsubst flycheck-error-list-make-cell (text &optional face help-echo type)
4344   "Make an error list cell with TEXT and FACE.
4345
4346 If FACE is nil don't set a FACE on TEXT.  If TEXT already has
4347 face properties, do not specify a FACE.  Note though, that if
4348 TEXT gets truncated it will not inherit any previous face
4349 properties.  If you expect TEXT to be truncated in the error
4350 list, do specify a FACE explicitly!
4351
4352 If HELP-ECHO is non-nil, set a help-echo property on TEXT, with
4353 value HELP-ECHO.  This is convenient if you expect TEXT to be
4354 truncated.
4355
4356 The cell will have the type TYPE unless TYPE is nil, and the
4357 default type `flycheck-error-list' will be used instead."
4358   (append (list text 'type (if type type
4359                              'flycheck-error-list))
4360           (and face (list 'face face))
4361           (and help-echo (list 'help-echo help-echo))))
4362
4363 (defsubst flycheck-error-list-make-number-cell (number face)
4364   "Make a table cell for a NUMBER with FACE.
4365
4366 Convert NUMBER to string, fontify it with FACE and return the
4367 string with attached text properties."
4368   (flycheck-error-list-make-cell
4369    (if (numberp number) (number-to-string number) "")
4370    face))
4371
4372 (defun flycheck-error-list-make-entry (error)
4373   "Make a table cell for the given ERROR.
4374
4375 Return a list with the contents of the table cell."
4376   (let* ((level (flycheck-error-level error))
4377          (level-face (flycheck-error-level-error-list-face level))
4378          (filename (flycheck-error-filename error))
4379          (line (flycheck-error-line error))
4380          (column (flycheck-error-column error))
4381          (message (or (flycheck-error-message error)
4382                       (format "Unknown %s" (symbol-name level))))
4383          (flushed-msg (flycheck-flush-multiline-message message))
4384          (id (flycheck-error-id error))
4385          (id-str (if id (format "%s" id) ""))
4386          (checker (flycheck-error-checker error))
4387          (msg-and-checker
4388           (flycheck-error-list-make-last-column flushed-msg checker))
4389          (explainer (flycheck-checker-get checker 'error-explainer)))
4390     (list error
4391           (vector (flycheck-error-list-make-cell
4392                    (if filename
4393                        (file-name-nondirectory filename)
4394                      "")
4395                    'flycheck-error-list-filename)
4396                   (flycheck-error-list-make-number-cell
4397                    line 'flycheck-error-list-line-number)
4398                   (flycheck-error-list-make-number-cell
4399                    column 'flycheck-error-list-column-number)
4400                   (flycheck-error-list-make-cell
4401                    (symbol-name (flycheck-error-level error)) level-face)
4402                   ;; Error ID use a different face when an error-explainer is
4403                   ;; present
4404                   (flycheck-error-list-make-cell
4405                    id-str (if explainer 'flycheck-error-list-id-with-explainer
4406                             'flycheck-error-list-id)
4407                    id-str 'flycheck-error-list-explain-error)
4408                   (flycheck-error-list-make-cell
4409                    msg-and-checker nil msg-and-checker)))))
4410
4411 (defun flycheck-flush-multiline-message (msg)
4412   "Prepare error message MSG for display in the error list.
4413
4414 Prepend all lines of MSG except the first with enough space to
4415 ensure that they line up properly once the message is displayed."
4416   (let* ((spc-spec `(space . (:width ,flycheck--error-list-msg-offset)))
4417          (spc (propertize " " 'display spc-spec))
4418          (rep (concat "\\1" spc "\\2")))
4419     (replace-regexp-in-string "\\([\r\n]+\\)\\(.\\)" rep msg)))
4420
4421 (defun flycheck-error-list-current-errors ()
4422   "Read the list of errors in `flycheck-error-list-source-buffer'."
4423   (when (buffer-live-p flycheck-error-list-source-buffer)
4424     (buffer-local-value 'flycheck-current-errors
4425                         flycheck-error-list-source-buffer)))
4426
4427 (defun flycheck-error-list-entries ()
4428   "Create the entries for the error list."
4429   (-when-let* ((errors (flycheck-error-list-current-errors))
4430                (filtered (flycheck-error-list-apply-filter errors)))
4431     (seq-map #'flycheck-error-list-make-entry filtered)))
4432
4433 (defun flycheck-error-list-entry-< (entry1 entry2)
4434   "Determine whether ENTRY1 is before ENTRY2 by location.
4435
4436 See `flycheck-error-<'."
4437   (flycheck-error-< (car entry1) (car entry2)))
4438
4439 (defun flycheck-error-list-entry-level-< (entry1 entry2)
4440   "Determine whether ENTRY1 is before ENTRY2 by level.
4441
4442 See `flycheck-error-level-<'."
4443   (not (flycheck-error-level-< (car entry1) (car entry2))))
4444
4445 (defvar flycheck-error-list-mode-line-map
4446   (let ((map (make-sparse-keymap)))
4447     (define-key map [mode-line mouse-1]
4448       #'flycheck-error-list-mouse-switch-to-source)
4449     map)
4450   "Keymap for error list mode line.")
4451
4452 (defun flycheck-error-list-propertized-source-name ()
4453   "Get the name of the current source buffer for the mode line.
4454
4455 Propertize the name of the current source buffer for use in the
4456 mode line indication of `flycheck-error-list-mode'."
4457   (let ((name (replace-regexp-in-string
4458                (rx "%") "%%"
4459                (buffer-name flycheck-error-list-source-buffer)
4460                'fixed-case 'literal)))
4461     (propertize name 'face 'mode-line-buffer-id
4462                 'mouse-face 'mode-line-highlight
4463                 'help-echo "mouse-1: switch to source"
4464                 'local-map flycheck-error-list-mode-line-map)))
4465
4466 (defun flycheck-error-list-mouse-switch-to-source (event)
4467   "Switch to the error list source buffer of the EVENT window."
4468   (interactive "e")
4469   (save-selected-window
4470     (when (eventp event)
4471       (select-window (posn-window (event-start event))))
4472     (when (buffer-live-p flycheck-error-list-source-buffer)
4473       (switch-to-buffer flycheck-error-list-source-buffer))))
4474
4475 (defun flycheck-get-error-list-window-list (&optional all-frames)
4476   "Get all windows displaying the error list.
4477
4478 ALL-FRAMES specifies the frames to consider, as in
4479 `get-buffer-window-list'."
4480   (-when-let (buf (get-buffer flycheck-error-list-buffer))
4481     (get-buffer-window-list buf nil all-frames)))
4482
4483 (defun flycheck-get-error-list-window (&optional all-frames)
4484   "Get a window displaying the error list, or nil if none.
4485
4486 ALL-FRAMES specifies the frames to consider, as in
4487 `get-buffer-window'."
4488   (-when-let (buf (get-buffer flycheck-error-list-buffer))
4489     (get-buffer-window buf all-frames)))
4490
4491 (defun flycheck-error-list-recenter-at (pos)
4492   "Recenter the error list at POS."
4493   (dolist (window (flycheck-get-error-list-window-list t))
4494     (with-selected-window window
4495       (goto-char pos)
4496       (let ((recenter-redisplay nil))
4497         (recenter)))))
4498
4499 (defun flycheck-error-list-refresh ()
4500   "Refresh the current error list.
4501
4502 Add all errors currently reported for the current
4503 `flycheck-error-list-source-buffer', and recenter the error
4504 list."
4505   ;; We only refresh the error list, when it is visible in a window, and we
4506   ;; select this window while reverting, because Tabulated List mode attempts to
4507   ;; recenter the error at the old location, so it must have the proper window
4508   ;; selected.
4509   (-when-let (window (flycheck-get-error-list-window t))
4510     (with-selected-window window
4511       (revert-buffer))
4512     (run-hooks 'flycheck-error-list-after-refresh-hook)
4513     (let ((preserve-pos (eq (current-buffer)
4514                             (get-buffer flycheck-error-list-buffer))))
4515       ;; If the error list is the current buffer, don't recenter when
4516       ;; highlighting
4517       (flycheck-error-list-highlight-errors preserve-pos))))
4518
4519 (defun flycheck-error-list-mode-line-filter-indicator ()
4520   "Create a string representing the current error list filter."
4521   (if flycheck-error-list-minimum-level
4522       (format " [>= %s]" flycheck-error-list-minimum-level)
4523     ""))
4524
4525 (defun flycheck-error-list-set-filter (level)
4526   "Restrict the error list to errors at level LEVEL or higher.
4527
4528 LEVEL is either an error level symbol, or nil, to remove the filter."
4529   (interactive
4530    (list (read-flycheck-error-level
4531           "Minimum error level (errors at lower levels will be hidden): ")))
4532   (when (and level (not (flycheck-error-level-p level)))
4533     (user-error "Invalid level: %s" level))
4534   (-when-let (buf (get-buffer flycheck-error-list-buffer))
4535     (with-current-buffer buf
4536       (setq-local flycheck-error-list-minimum-level level))
4537     (flycheck-error-list-refresh)
4538     (flycheck-error-list-recenter-at (point-min))))
4539
4540 (defun flycheck-error-list-reset-filter ()
4541   "Remove filters and show all errors in the error list."
4542   (interactive)
4543   (kill-local-variable 'flycheck-error-list-minimum-level))
4544
4545 (defun flycheck-error-list-apply-filter (errors)
4546   "Filter ERRORS according to `flycheck-error-list-minimum-level'."
4547   (-if-let* ((min-level flycheck-error-list-minimum-level)
4548              (min-severity (flycheck-error-level-severity min-level)))
4549       (seq-filter (lambda (err) (>= (flycheck-error-level-severity
4550                                      (flycheck-error-level err))
4551                                     min-severity))
4552                   errors)
4553     errors))
4554
4555 (defun flycheck-error-list-goto-error (&optional pos)
4556   "Go to the location of the error at POS in the error list.
4557
4558 POS defaults to `point'."
4559   (interactive)
4560   (-when-let* ((error (tabulated-list-get-id pos)))
4561     (flycheck-jump-to-error error)))
4562
4563 (defun flycheck-jump-to-error (error)
4564   "Go to the location of ERROR."
4565   (let* ((error-copy (copy-flycheck-error error))
4566          (filename (flycheck-error-filename error))
4567          (other-file-error (flycheck-relevant-error-other-file-p error))
4568          (buffer (if filename
4569                      (find-file-noselect filename)
4570                    (flycheck-error-buffer error))))
4571     (when (buffer-live-p buffer)
4572       (setf (flycheck-error-buffer error-copy) buffer)
4573       (flycheck-jump-in-buffer buffer error-copy)
4574       ;; When jumping to an error in another file, it may not have
4575       ;; this error available for highlighting yet, so we trigger a check
4576       ;; if necessary.
4577       (when other-file-error
4578         (with-current-buffer buffer
4579           (unless (seq-contains flycheck-current-errors error-copy 'equal)
4580             (when flycheck-mode
4581               (flycheck-buffer))))))))
4582
4583 (defun flycheck-jump-in-buffer (buffer error)
4584   "In BUFFER, jump to ERROR."
4585   ;; FIXME: we assume BUFFER and the buffer of ERROR are the same.  We don't
4586   ;; need the first argument then.
4587   (if (eq (window-buffer) (get-buffer flycheck-error-list-buffer))
4588       ;; When called from within the error list, keep the error list,
4589       ;; otherwise replace the current buffer.
4590       (pop-to-buffer buffer 'other-window)
4591     (switch-to-buffer buffer))
4592   (let ((pos (flycheck-error-pos error)))
4593     (unless (eq (goto-char pos) (point))
4594       ;; If widening gets in the way of moving to the right place, remove it
4595       ;; and try again
4596       (widen)
4597       (goto-char pos)))
4598   ;; Re-highlight the errors
4599   (flycheck-error-list-highlight-errors 'preserve-pos))
4600
4601 (defun flycheck-error-list-explain-error (&optional pos)
4602   "Explain the error at POS in the error list.
4603
4604 POS defaults to `point'."
4605   (interactive)
4606   (-when-let* ((error (tabulated-list-get-id pos))
4607                (explainer (flycheck-checker-get (flycheck-error-checker error)
4608                                                 'error-explainer))
4609                (explanation (funcall explainer error)))
4610     (flycheck-display-error-explanation explanation)))
4611
4612 (defun flycheck-error-list-next-error-pos (pos &optional n)
4613   "Starting from POS get the N'th next error in the error list.
4614
4615 N defaults to 1.  If N is negative, search for the previous error
4616 instead.
4617
4618 Get the beginning position of the N'th next error from POS, or
4619 nil, if there is no next error."
4620   (let ((n (or n 1)))
4621     (if (>= n 0)
4622         ;; Search forward
4623         (while (and pos (/= n 0))
4624           (setq n (1- n))
4625           (setq pos (next-single-property-change pos 'tabulated-list-id)))
4626       ;; Search backwards
4627       (while (/= n 0)
4628         (setq n (1+ n))
4629         ;; We explicitly give the limit here to explicitly have the minimum
4630         ;; point returned, to be able to move to the first error (which starts
4631         ;; at `point-min')
4632         (setq pos (previous-single-property-change pos 'tabulated-list-id
4633                                                    nil (point-min)))))
4634     pos))
4635
4636 (defun flycheck-error-list-previous-error (n)
4637   "Go to the N'th previous error in the error list."
4638   (interactive "P")
4639   (flycheck-error-list-next-error (- (or n 1))))
4640
4641 (defun flycheck-error-list-next-error (n)
4642   "Go to the N'th next error in the error list."
4643   (interactive "P")
4644   (let ((pos (flycheck-error-list-next-error-pos (point) n)))
4645     (when (and pos (/= pos (point)))
4646       (goto-char pos)
4647       (save-selected-window
4648         ;; Keep the error list selected, so that the user can navigate errors by
4649         ;; repeatedly pressing n/p, without having to re-select the error list
4650         ;; window.
4651         (flycheck-error-list-goto-error)))))
4652
4653 (defvar-local flycheck-error-list-highlight-overlays nil
4654   "Error highlight overlays in the error list buffer.")
4655 (put 'flycheck-error-list-highlight-overlays 'permanent-local t)
4656
4657 (defun flycheck-error-list-highlight-errors (&optional preserve-pos)
4658   "Highlight errors in the error list.
4659
4660 Highlight all errors in the error lists that are at point in the
4661 source buffer, and on the same line as point.  Then recenter the
4662 error list to the highlighted error, unless PRESERVE-POS is
4663 non-nil."
4664   (when (get-buffer flycheck-error-list-buffer)
4665     (let ((current-errors (flycheck-overlay-errors-in (line-beginning-position)
4666                                                       (line-end-position))))
4667       (with-current-buffer flycheck-error-list-buffer
4668         (let ((old-overlays flycheck-error-list-highlight-overlays)
4669               (min-point (point-max))
4670               (max-point (point-min)))
4671           ;; Display the new overlays first, to avoid re-display flickering
4672           (setq flycheck-error-list-highlight-overlays nil)
4673           (when current-errors
4674             (let ((next-error-pos (point-min)))
4675               (while next-error-pos
4676                 (let* ((beg next-error-pos)
4677                        (end (flycheck-error-list-next-error-pos beg))
4678                        (err (tabulated-list-get-id beg)))
4679                   (when (member err current-errors)
4680                     (setq min-point (min min-point beg)
4681                           max-point (max max-point beg))
4682                     (let ((ov (make-overlay beg
4683                                             ;; Extend overlay to the beginning
4684                                             ;; of the next line, to highlight
4685                                             ;; the whole line
4686                                             (or end (point-max)))))
4687                       (push ov flycheck-error-list-highlight-overlays)
4688                       (setf (overlay-get ov 'flycheck-error-highlight-overlay)
4689                             t)
4690                       (setf (overlay-get ov 'face)
4691                             'flycheck-error-list-highlight)))
4692                   (setq next-error-pos end)))))
4693           ;; Delete the old overlays
4694           (seq-do #'delete-overlay old-overlays)
4695           (when (and (not preserve-pos) current-errors)
4696             ;; Move point to the middle error
4697             (goto-char (+ min-point (/ (- max-point min-point) 2)))
4698             (beginning-of-line)
4699             ;; And recenter the error list at this position
4700             (flycheck-error-list-recenter-at (point))))))))
4701
4702 (defun flycheck-list-errors ()
4703   "Show the error list for the current buffer."
4704   (interactive)
4705   (unless flycheck-mode
4706     (user-error "Flycheck mode not enabled"))
4707   ;; Create and initialize the error list
4708   (unless (get-buffer flycheck-error-list-buffer)
4709     (with-current-buffer (get-buffer-create flycheck-error-list-buffer)
4710       (flycheck-error-list-mode)))
4711   (flycheck-error-list-set-source (current-buffer))
4712   ;; Reset the error filter
4713   (flycheck-error-list-reset-filter)
4714   ;; Show the error list in a window, and re-select the old window
4715   (display-buffer flycheck-error-list-buffer)
4716   ;; Finally, refresh the error list to show the most recent errors
4717   (flycheck-error-list-refresh))
4718
4719 (defalias 'list-flycheck-errors 'flycheck-list-errors)
4720
4721 \f
4722 ;;; Displaying errors in the current buffer
4723 (defun flycheck-display-errors (errors)
4724   "Display ERRORS using `flycheck-display-errors-function'."
4725   (when flycheck-display-errors-function
4726     (funcall flycheck-display-errors-function errors)))
4727
4728 (defvar-local flycheck-display-error-at-point-timer nil
4729   "Timer to automatically show the error at point in minibuffer.")
4730
4731 (defun flycheck-cancel-error-display-error-at-point-timer ()
4732   "Cancel the error display timer for the current buffer."
4733   (when flycheck-display-error-at-point-timer
4734     (cancel-timer flycheck-display-error-at-point-timer)
4735     (setq flycheck-display-error-at-point-timer nil)))
4736
4737 (defun flycheck-display-error-at-point ()
4738   "Display the all error messages at point in minibuffer."
4739   (interactive)
4740   ;; This function runs from a timer, so we must take care to not ignore any
4741   ;; errors
4742   (with-demoted-errors "Flycheck error display error: %s"
4743     (flycheck-cancel-error-display-error-at-point-timer)
4744     (when flycheck-mode
4745       (-when-let (errors (flycheck-overlay-errors-at (point)))
4746         (flycheck-display-errors errors)))))
4747
4748 (defun flycheck-display-error-at-point-soon ()
4749   "Display the first error message at point in minibuffer delayed."
4750   (flycheck-cancel-error-display-error-at-point-timer)
4751   (when (flycheck-overlays-at (point))
4752     (setq flycheck-display-error-at-point-timer
4753           (run-at-time flycheck-display-errors-delay nil
4754                        'flycheck-display-error-at-point))))
4755
4756 \f
4757 ;;; Functions to display errors
4758 (defconst flycheck-error-message-buffer "*Flycheck error messages*"
4759   "The name of the buffer to show long error messages in.")
4760
4761 (defun flycheck-error-message-buffer ()
4762   "Get the buffer object to show long error messages in.
4763
4764 Get the buffer named by variable `flycheck-error-message-buffer',
4765 or nil if the buffer does not exist."
4766   (get-buffer flycheck-error-message-buffer))
4767
4768 (defun flycheck-may-use-echo-area-p ()
4769   "Determine whether the echo area may be used.
4770
4771 The echo area may be used if the cursor is not in the echo area,
4772 and if the echo area is not occupied by minibuffer input."
4773   (not (or cursor-in-echo-area (active-minibuffer-window))))
4774
4775 (defun flycheck-display-error-messages (errors)
4776   "Display the messages of ERRORS.
4777
4778 Concatenate all non-nil messages of ERRORS separated by empty
4779 lines, and display them with `display-message-or-buffer', which
4780 shows the messages either in the echo area or in a separate
4781 buffer, depending on the number of lines.  See Info
4782 node `(elisp)Displaying Messages' for more information.
4783
4784 In the latter case, show messages in the buffer denoted by
4785 variable `flycheck-error-message-buffer'."
4786   (when (and errors (flycheck-may-use-echo-area-p))
4787     (let ((messages (seq-map #'flycheck-error-format-message-and-id errors)))
4788       (display-message-or-buffer (string-join messages "\n\n")
4789                                  flycheck-error-message-buffer
4790                                  'not-this-window))))
4791
4792 (defun flycheck-display-error-messages-unless-error-list (errors)
4793   "Show messages of ERRORS unless the error list is visible.
4794
4795 Like `flycheck-display-error-messages', but only if the error
4796 list (see `flycheck-list-errors') is not visible in any window in
4797 the current frame."
4798   (unless (flycheck-get-error-list-window 'current-frame)
4799     (flycheck-display-error-messages errors)))
4800
4801 (defun flycheck-hide-error-buffer ()
4802   "Hide the Flycheck error buffer if necessary.
4803
4804 Hide the error buffer if there is no error under point."
4805   (-when-let* ((buffer (flycheck-error-message-buffer))
4806                (window (get-buffer-window buffer)))
4807     (unless (flycheck-overlays-at (point))
4808       ;; save-selected-window prevents `quit-window' from changing the current
4809       ;; buffer (see https://github.com/flycheck/flycheck/issues/648).
4810       (save-selected-window
4811         (quit-window nil window)))))
4812
4813 \f
4814 ;;; Working with errors
4815 (defun flycheck-copy-errors-as-kill (pos &optional formatter)
4816   "Copy each error at POS into kill ring, using FORMATTER.
4817
4818 FORMATTER is a function to turn an error into a string,
4819 defaulting to `flycheck-error-message'.
4820
4821 Interactively, use `flycheck-error-format-message-and-id' as
4822 FORMATTER with universal prefix arg, and `flycheck-error-id' with
4823 normal prefix arg, i.e. copy the message and the ID with
4824 universal prefix arg, and only the id with normal prefix arg."
4825   (interactive (list (point)
4826                      (pcase current-prefix-arg
4827                        ((pred not) #'flycheck-error-message)
4828                        ((pred consp) #'flycheck-error-format-message-and-id)
4829                        (_ #'flycheck-error-id))))
4830   (let ((messages (delq nil (seq-map (or formatter #'flycheck-error-message)
4831                                      (flycheck-overlay-errors-at pos)))))
4832     (when messages
4833       (seq-do #'kill-new (reverse messages))
4834       (message (string-join messages "\n")))))
4835
4836 (defun flycheck-explain-error-at-point ()
4837   "Display an explanation for the first explainable error at point.
4838
4839 The first explainable error at point is the first error at point
4840 with a non-nil `:error-explainer' function defined in its
4841 checker.  The `:error-explainer' function is then called with
4842 this error to produce the explanation to display."
4843   (interactive)
4844   (-when-let* ((first-error
4845                 ;; Get the first error at point that has an `error-explainer'.
4846                 (seq-find (lambda (error)
4847                             (flycheck-checker-get
4848                              (flycheck-error-checker error) 'error-explainer))
4849                           (flycheck-overlay-errors-at (point))))
4850                (explainer
4851                 (flycheck-checker-get (flycheck-error-checker first-error)
4852                                       'error-explainer))
4853                (explanation (funcall explainer first-error)))
4854     (flycheck-display-error-explanation explanation)))
4855
4856 (defconst flycheck-explain-error-buffer "*Flycheck error explanation*"
4857   "The name of the buffer to show error explanations.")
4858
4859 (defun flycheck-display-error-explanation (explanation)
4860   "Display the EXPLANATION string in a help buffer."
4861   (with-help-window (get-buffer-create flycheck-explain-error-buffer)
4862     (princ explanation)))
4863
4864 \f
4865 ;;; Syntax checkers using external commands
4866 (defun flycheck-command-argument-p (arg)
4867   "Check whether ARG is a valid command argument."
4868   (pcase arg
4869     ((pred stringp) t)
4870     ((or `source `source-inplace `source-original) t)
4871     ((or `temporary-directory `temporary-file-name) t)
4872     (`null-device t)
4873     (`(config-file ,option-name ,config-file-var)
4874      (and (stringp option-name)
4875           (symbolp config-file-var)))
4876     (`(config-file ,option-name ,config-file-var ,prepender)
4877      (and (stringp option-name)
4878           (symbolp config-file-var)
4879           (symbolp prepender)))
4880     (`(,(or `option `option-list) ,option-name ,option-var)
4881      (and (stringp option-name)
4882           (symbolp option-var)))
4883     (`(,(or `option `option-list) ,option-name ,option-var ,prepender)
4884      (and (stringp option-name)
4885           (symbolp option-var)
4886           (symbolp prepender)))
4887     (`(,(or `option `option-list) ,option-name ,option-var ,prepender ,filter)
4888      (and (stringp option-name)
4889           (symbolp option-var)
4890           (symbolp prepender)
4891           (symbolp filter)))
4892     (`(option-flag ,option-name ,option-var)
4893      (and (stringp option-name)
4894           (symbolp option-var)))
4895     (`(eval ,_) t)
4896     (_ nil)))
4897
4898 (defun flycheck-compute-working-directory (checker)
4899   "Get the default working directory for CHECKER.
4900
4901 Compute the value of `default-directory' for the invocation of
4902 the syntax checker command, by calling the function in the
4903 `working-directory' property of CHECKER, with CHECKER as sole
4904 argument, and returning its value.  Signal an error if the
4905 function returns a non-existing working directory.
4906
4907 If the property is undefined or if the function returns nil
4908 return the `default-directory' of the current buffer."
4909   (let* ((def-directory-fn (flycheck-checker-get checker 'working-directory))
4910          (directory (or (and def-directory-fn
4911                              (funcall def-directory-fn checker))
4912                         ;; Default to the `default-directory' of the current
4913                         ;; buffer
4914                         default-directory)))
4915     (unless (file-exists-p directory)
4916       (error ":working-directory %s of syntax checker %S does not exist"
4917              directory checker))
4918     directory))
4919
4920 ;;;###autoload
4921 (defun flycheck-define-command-checker (symbol docstring &rest properties)
4922   "Define SYMBOL as syntax checker to run a command.
4923
4924 Define SYMBOL as generic syntax checker via
4925 `flycheck-define-generic-checker', which uses an external command
4926 to check the buffer.  SYMBOL and DOCSTRING are the same as for
4927 `flycheck-define-generic-checker'.
4928
4929 In addition to the properties understood by
4930 `flycheck-define-generic-checker', the following PROPERTIES
4931 constitute a command syntax checker.  Unless otherwise noted, all
4932 properties are mandatory.  Note that the default `:error-filter'
4933 of command checkers is `flycheck-sanitize-errors'.
4934
4935 `:command COMMAND'
4936      The command to run for syntax checking.
4937
4938      COMMAND is a list of the form `(EXECUTABLE [ARG ...])'.
4939
4940      EXECUTABLE is a string with the executable of this syntax
4941      checker.  It can be overridden with the variable
4942      `flycheck-SYMBOL-executable'.  Note that this variable is
4943      NOT implicitly defined by this function.  Use
4944      `flycheck-def-executable-var' to define this variable.
4945
4946      Each ARG is an argument to the executable, either as string,
4947      or as special symbol or form for
4948      `flycheck-substitute-argument', which see.
4949
4950 `:error-patterns PATTERNS'
4951      A list of patterns to parse the output of the `:command'.
4952
4953      Each ITEM in PATTERNS is a list `(LEVEL SEXP ...)', where
4954      LEVEL is a Flycheck error level (see
4955      `flycheck-define-error-level'), followed by one or more RX
4956      `SEXP's which parse an error of that level and extract line,
4957      column, file name and the message.
4958
4959      See `rx' for general information about RX, and
4960      `flycheck-rx-to-string' for some special RX forms provided
4961      by Flycheck.
4962
4963      All patterns are applied in the order of declaration to the
4964      whole output of the syntax checker.  Output already matched
4965      by a pattern will not be matched by subsequent patterns.  In
4966      other words, the first pattern wins.
4967
4968      This property is optional.  If omitted, however, an
4969      `:error-parser' is mandatory.
4970
4971 `:error-parser FUNCTION'
4972      A function to parse errors with.
4973
4974      The function shall accept three arguments OUTPUT CHECKER
4975      BUFFER.  OUTPUT is the syntax checker output as string,
4976      CHECKER the syntax checker that was used, and BUFFER a
4977      buffer object representing the checked buffer.  The function
4978      must return a list of `flycheck-error' objects parsed from
4979      OUTPUT.
4980
4981      This property is optional.  If omitted, it defaults to
4982      `flycheck-parse-with-patterns'.  In this case,
4983      `:error-patterns' is mandatory.
4984
4985 `:standard-input t'
4986      Whether to send the buffer contents on standard input.
4987
4988      If this property is given and has a non-nil value, send the
4989      contents of the buffer on standard input.
4990
4991      Defaults to nil.
4992
4993 Note that you may not give `:start', `:interrupt', and
4994 `:print-doc' for a command checker.  You can give a custom
4995 `:verify' function, though, whose results will be appended to the
4996 default `:verify' function of command checkers."
4997   (declare (indent 1)
4998            (doc-string 2))
4999   (dolist (prop '(:start :interrupt :print-doc))
5000     (when (plist-get properties prop)
5001       (error "%s not allowed in definition of command syntax checker %s"
5002              prop symbol)))
5003
5004   (unless (plist-get properties :error-filter)
5005     ;; Default to `flycheck-sanitize-errors' as error filter
5006     (setq properties (plist-put properties :error-filter
5007                                 #'flycheck-sanitize-errors)))
5008   (let ((verify-fn (plist-get properties :verify)))
5009     (setq properties
5010           (plist-put properties :verify
5011                      (lambda (checker)
5012                        (append (flycheck-verify-command-checker checker)
5013                                (and verify-fn
5014                                     (funcall verify-fn checker)))))))
5015
5016   (let ((command (plist-get properties :command))
5017         (patterns (plist-get properties :error-patterns))
5018         (parser (or (plist-get properties :error-parser)
5019                     #'flycheck-parse-with-patterns))
5020         (enabled (plist-get properties :enabled))
5021         (standard-input (plist-get properties :standard-input)))
5022     (unless command
5023       (error "Missing :command in syntax checker %s" symbol))
5024     (unless (stringp (car command))
5025       (error "Command executable for syntax checker %s must be a string: %S"
5026              symbol (car command)))
5027     (dolist (arg (cdr command))
5028       (unless (flycheck-command-argument-p arg)
5029         (error "Invalid command argument %S in syntax checker %s" arg symbol)))
5030     (when (and (eq parser 'flycheck-parse-with-patterns)
5031                (not patterns))
5032       (error "Missing :error-patterns in syntax checker %s" symbol))
5033
5034     (setq properties
5035           ;; Automatically disable command checkers if the executable does not
5036           ;; exist.
5037           (plist-put properties :enabled
5038                      (lambda ()
5039                        (and (flycheck-find-checker-executable symbol)
5040                             (flycheck-temp-files-writable-p symbol)
5041                             (or (not enabled) (funcall enabled))))))
5042
5043     (apply #'flycheck-define-generic-checker symbol docstring
5044            :start #'flycheck-start-command-checker
5045            :interrupt #'flycheck-interrupt-command-checker
5046            :print-doc #'flycheck-command-checker-print-doc
5047            properties)
5048
5049     ;; Pre-compile all errors patterns into strings, so that we don't need to do
5050     ;; that on each error parse
5051     (let ((patterns (seq-map (lambda (p)
5052                                (cons (flycheck-rx-to-string `(and ,@(cdr p))
5053                                                             'no-group)
5054                                      (car p)))
5055                              patterns)))
5056       (pcase-dolist (`(,prop . ,value)
5057                      `((command        . ,command)
5058                        (error-parser   . ,parser)
5059                        (error-patterns . ,patterns)
5060                        (standard-input . ,standard-input)))
5061         (setf (flycheck-checker-get symbol prop) value)))))
5062
5063 (eval-and-compile
5064   ;; Make this function available during byte-compilation, since we need it
5065   ;; at macro expansion of `flycheck-def-executable-var'.
5066   (defun flycheck-checker-executable-variable (checker)
5067     "Get the executable variable of CHECKER.
5068
5069 The executable variable is named `flycheck-CHECKER-executable'."
5070     (intern (format "flycheck-%s-executable" checker))))
5071
5072 (defun flycheck-checker-default-executable (checker)
5073   "Get the default executable of CHECKER."
5074   (car (flycheck-checker-get checker 'command)))
5075
5076 (defun flycheck-checker-executable (checker)
5077   "Get the command executable of CHECKER.
5078
5079 The executable is either the value of the variable
5080 `flycheck-CHECKER-executable', or the default executable given in
5081 the syntax checker definition, if the variable is nil."
5082   (let ((var (flycheck-checker-executable-variable checker)))
5083     (or (and (boundp var) (symbol-value var))
5084         (flycheck-checker-default-executable checker))))
5085
5086 (defun flycheck-find-checker-executable (checker)
5087   "Get the full path of the executable of CHECKER.
5088
5089 Return the full absolute path to the executable of CHECKER, or
5090 nil if the executable does not exist."
5091   (funcall flycheck-executable-find (flycheck-checker-executable checker)))
5092
5093 (defun flycheck-checker-arguments (checker)
5094   "Get the command arguments of CHECKER."
5095   (cdr (flycheck-checker-get checker 'command)))
5096
5097 (defun flycheck-substitute-argument (arg checker)
5098   "Substitute ARG for CHECKER.
5099
5100 Return a list of real arguments for the executable of CHECKER,
5101 substituted for the symbolic argument ARG.  Single arguments,
5102 e.g. if ARG is a literal strings, are wrapped in a list.
5103
5104 ARG may be one of the following forms:
5105
5106 STRING
5107      Return ARG unchanged.
5108
5109 `source', `source-inplace'
5110      Create a temporary file to check and return its path.  With
5111      `source-inplace' create the temporary file in the same
5112      directory as the original file.  The value of
5113      `flycheck-temp-prefix' is used as prefix of the file name.
5114
5115      With `source', try to retain the non-directory component of
5116      the buffer's file name in the temporary file.
5117
5118      `source' is the preferred way to pass the input file to a
5119      syntax checker.  `source-inplace' should only be used if the
5120      syntax checker needs other files from the source directory,
5121      such as include files in C.
5122
5123 `source-original'
5124      Return the path of the actual file to check, or an empty
5125      string if the buffer has no file name.
5126
5127      Note that the contents of the file may not be up to date
5128      with the contents of the buffer to check.  Do not use this
5129      as primary input to a checker, unless absolutely necessary.
5130
5131      When using this symbol as primary input to the syntax
5132      checker, add `flycheck-buffer-saved-p' to the `:predicate'.
5133
5134 `temporary-directory'
5135      Create a unique temporary directory and return its path.
5136
5137 `temporary-file-name'
5138      Return a unique temporary filename.  The file is *not*
5139      created.
5140
5141      To ignore the output of syntax checkers, try `null-device'
5142      first.
5143
5144 `null-device'
5145      Return the value of `null-device', i.e the system null
5146      device.
5147
5148      Use this option to ignore the output of a syntax checker.
5149      If the syntax checker cannot handle the null device, or
5150      won't write to an existing file, try `temporary-file-name'
5151      instead.
5152
5153 `(config-file OPTION VARIABLE [PREPEND-FN])'
5154      Search the configuration file bound to VARIABLE with
5155      `flycheck-locate-config-file' and return a list of arguments
5156      that pass this configuration file to the syntax checker, or
5157      nil if the configuration file was not found.
5158
5159      PREPEND-FN is called with the OPTION and the located
5160      configuration file, and should return OPTION prepended
5161      before the file, either a string or as list.  If omitted,
5162      PREPEND-FN defaults to `list'.
5163
5164 `(option OPTION VARIABLE [PREPEND-FN [FILTER]])'
5165      Retrieve the value of VARIABLE and return a list of
5166      arguments that pass this value as value for OPTION to the
5167      syntax checker.
5168
5169      PREPEND-FN is called with the OPTION and the value of
5170      VARIABLE, and should return OPTION prepended before the
5171      file, either a string or as list.  If omitted, PREPEND-FN
5172      defaults to `list'.
5173
5174      FILTER is an optional function to be applied to the value of
5175      VARIABLE before prepending.  This function must return nil
5176      or a string.  In the former case, return nil.  In the latter
5177      case, return a list of arguments as described above.
5178
5179 `(option-list OPTION VARIABLE [PREPEND-FN [FILTER]])'
5180      Retrieve the value of VARIABLE, which must be a list,
5181      and prepend OPTION before each item in this list, using
5182      PREPEND-FN.
5183
5184      PREPEND-FN is called with the OPTION and each item of the
5185      list as second argument, and should return OPTION prepended
5186      before the item, either as string or as list.  If omitted,
5187      PREPEND-FN defaults to `list'.
5188
5189      FILTER is an optional function to be applied to each item in
5190      the list before prepending OPTION.  It shall return the
5191      option value for each item as string, or nil, if the item is
5192      to be ignored.
5193
5194 `(option-flag OPTION VARIABLE)'
5195      Retrieve the value of VARIABLE and return OPTION, if the
5196      value is non-nil.  Otherwise return nil.
5197
5198 `(eval FORM)'
5199      Return the result of evaluating FORM in the buffer to be
5200      checked.  FORM must either return a string or a list of
5201      strings, or nil to indicate that nothing should be
5202      substituted for CELL.  For all other return types, signal an
5203      error
5204
5205      _No_ further substitutions are performed, neither in FORM
5206      before it is evaluated, nor in the result of evaluating
5207      FORM.
5208
5209 In all other cases, signal an error.
5210
5211 Note that substitution is *not* recursive.  No symbols or cells
5212 are substituted within the body of cells!"
5213   (pcase arg
5214     ((pred stringp) (list arg))
5215     (`source
5216      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-system)))
5217     (`source-inplace
5218      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)))
5219     (`source-original (list (or (buffer-file-name) "")))
5220     (`temporary-directory (list (flycheck-temp-dir-system)))
5221     (`temporary-file-name
5222      (let ((directory (flycheck-temp-dir-system)))
5223        (list (make-temp-name (expand-file-name "flycheck" directory)))))
5224     (`null-device (list null-device))
5225     (`(config-file ,option-name ,file-name-var)
5226      (-when-let* ((value (symbol-value file-name-var))
5227                   (file-name (flycheck-locate-config-file value checker)))
5228        (flycheck-prepend-with-option option-name (list file-name))))
5229     (`(config-file ,option-name ,file-name-var ,prepend-fn)
5230      (-when-let* ((value (symbol-value file-name-var))
5231                   (file-name (flycheck-locate-config-file value checker)))
5232        (flycheck-prepend-with-option option-name (list file-name) prepend-fn)))
5233     (`(option ,option-name ,variable)
5234      (-when-let (value (symbol-value variable))
5235        (unless (stringp value)
5236          (error "Value %S of %S for option %s is not a string"
5237                 value variable option-name))
5238        (flycheck-prepend-with-option option-name (list value))))
5239     (`(option ,option-name ,variable ,prepend-fn)
5240      (-when-let (value (symbol-value variable))
5241        (unless (stringp value)
5242          (error "Value %S of %S for option %s is not a string"
5243                 value variable option-name))
5244        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
5245     (`(option ,option-name ,variable ,prepend-fn ,filter)
5246      (-when-let (value (funcall filter (symbol-value variable)))
5247        (unless (stringp value)
5248          (error "Value %S of %S (filter: %S) for option %s is not a string"
5249                 value variable filter option-name))
5250        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
5251     (`(option-list ,option-name ,variable)
5252      (let ((value (symbol-value variable)))
5253        (unless (and (listp value) (seq-every-p #'stringp value))
5254          (error "Value %S of %S for option %S is not a list of strings"
5255                 value variable option-name))
5256        (flycheck-prepend-with-option option-name value)))
5257     (`(option-list ,option-name ,variable ,prepend-fn)
5258      (let ((value (symbol-value variable)))
5259        (unless (and (listp value) (seq-every-p #'stringp value))
5260          (error "Value %S of %S for option %S is not a list of strings"
5261                 value variable option-name))
5262        (flycheck-prepend-with-option option-name value prepend-fn)))
5263     (`(option-list ,option-name ,variable ,prepend-fn ,filter)
5264      (let ((value (delq nil (seq-map filter (symbol-value variable)))))
5265        (unless (and (listp value) (seq-every-p #'stringp value))
5266          (error "Value %S of %S for option %S is not a list of strings"
5267                 value variable option-name))
5268        (flycheck-prepend-with-option option-name value prepend-fn)))
5269     (`(option-flag ,option-name ,variable)
5270      (when (symbol-value variable)
5271        (list option-name)))
5272     (`(eval ,form)
5273      (let ((result (eval form)))
5274        (cond
5275         ((and (listp result) (seq-every-p #'stringp result)) result)
5276         ((stringp result) (list result))
5277         (t (error "Invalid result from evaluation of %S: %S" form result)))))
5278     (_ (error "Unsupported argument %S" arg))))
5279
5280 (defun flycheck-checker-substituted-arguments (checker)
5281   "Get the substituted arguments of a CHECKER.
5282
5283 Substitute each argument of CHECKER using
5284 `flycheck-substitute-argument'.  This replaces any special
5285 symbols in the command."
5286   (apply #'append
5287          (seq-map (lambda (arg) (flycheck-substitute-argument arg checker))
5288                   (flycheck-checker-arguments checker))))
5289
5290 (defun flycheck--process-send-buffer-contents-chunked (process)
5291   "Send contents of current buffer to PROCESS in small batches.
5292
5293 Send the entire buffer to the standard input of PROCESS in chunks
5294 of 4096 characters.  Chunking is done in Emacs Lisp, hence this
5295 function is probably far less efficient than
5296 `send-process-region'.  Use only when required."
5297   (let ((from (point-min)))
5298     (while (< from (point-max))
5299       (let ((to (min (+ from 4096) (point-max))))
5300         (process-send-region process from to)
5301         (setq from to)))))
5302
5303 (defvar flycheck-chunked-process-input
5304   ;; Chunk process output on Windows to work around
5305   ;; https://github.com/flycheck/flycheck/issues/794 and
5306   ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22344.  The presence of
5307   ;; `w32-pipe-buffer-size' denotes an Emacs version (> Emacs 25.1 )where pipe
5308   ;; writes on Windows are fixed.
5309   ;;
5310   ;; TODO: Remove option and chunking when dropping Emacs 24 support, see
5311   ;; https://github.com/flycheck/flycheck/issues/856
5312   (and (eq system-type 'windows-nt) (not (boundp 'w32-pipe-buffer-size)))
5313   "If non-nil send process input in small chunks.
5314
5315 If this variable is non-nil `flycheck-process-send-buffer' sends
5316 buffer contents in small chunks.
5317
5318 Defaults to nil, except on Windows to work around Emacs bug
5319 #22344.")
5320
5321 (defun flycheck-process-send-buffer (process)
5322   "Send all contents of current buffer to PROCESS.
5323
5324 Sends all contents of the current buffer to the standard input of
5325 PROCESS, and terminates standard input with EOF.
5326
5327 If `flycheck-chunked-process-input' is non-nil, send buffer
5328 contents in chunks via
5329 `flycheck--process-send-buffer-contents-chunked', which see.
5330 Otherwise use `process-send-region' to send all contents at once
5331 and rely on Emacs' own buffering and chunking."
5332   (save-restriction
5333     (widen)
5334     (if flycheck-chunked-process-input
5335         (flycheck--process-send-buffer-contents-chunked process)
5336       (process-send-region process (point-min) (point-max))))
5337   (process-send-eof process))
5338
5339 (defun flycheck-start-command-checker (checker callback)
5340   "Start a command CHECKER with CALLBACK."
5341   (let (process)
5342     (condition-case err
5343         (let* ((program (flycheck-find-checker-executable checker))
5344                (args (flycheck-checker-substituted-arguments checker))
5345                (command (funcall flycheck-command-wrapper-function
5346                                  (cons program args)))
5347                ;; Use pipes to receive output from the syntax checker.  They are
5348                ;; more efficient and more robust than PTYs, which Emacs uses by
5349                ;; default, and since we don't need any job control features, we
5350                ;; can easily use pipes.
5351                (process-connection-type nil))
5352           ;; We pass do not associate the process with any buffer, by
5353           ;; passing nil for the BUFFER argument of `start-process'.
5354           ;; Instead, we just remember the buffer being checked in a
5355           ;; process property (see below).  This neatly avoids all
5356           ;; side-effects implied by attached a process to a buffer, which
5357           ;; may cause conflicts with other packages.
5358           ;;
5359           ;; See https://github.com/flycheck/flycheck/issues/298 for an
5360           ;; example for such a conflict.
5361           (setq process (apply 'start-process (format "flycheck-%s" checker)
5362                                nil command))
5363           (setf (process-sentinel process) #'flycheck-handle-signal)
5364           (setf (process-filter process) #'flycheck-receive-checker-output)
5365           (set-process-query-on-exit-flag process nil)
5366           ;; Remember the syntax checker, the buffer and the callback
5367           (process-put process 'flycheck-checker checker)
5368           (process-put process 'flycheck-callback callback)
5369           (process-put process 'flycheck-buffer (current-buffer))
5370           ;; The default directory is bound in the `flycheck-syntax-check-start'
5371           ;; function.
5372           (process-put process 'flycheck-working-directory default-directory)
5373           ;; Track the temporaries created by argument substitution in the
5374           ;; process itself, to get rid of the global state ASAP.
5375           (process-put process 'flycheck-temporaries flycheck-temporaries)
5376           (setq flycheck-temporaries nil)
5377           ;; Send the buffer to the process on standard input, if enabled.
5378           (when (flycheck-checker-get checker 'standard-input)
5379             (flycheck-process-send-buffer process))
5380           ;; Return the process.
5381           process)
5382       (error
5383        ;; In case of error, clean up our resources, and report the error back to
5384        ;; Flycheck.
5385        (flycheck-safe-delete-temporaries)
5386        (when process
5387          ;; No need to explicitly delete the temporary files of the process,
5388          ;; because deleting runs the sentinel, which will delete them anyway.
5389          (delete-process process))
5390        (signal (car err) (cdr err))))))
5391
5392 (defun flycheck-interrupt-command-checker (_checker process)
5393   "Interrupt a PROCESS."
5394   ;; Deleting the process always triggers the sentinel, which does the cleanup
5395   (when process
5396     (delete-process process)))
5397
5398 (defun flycheck-command-checker-print-doc (checker)
5399   "Print additional documentation for a command CHECKER."
5400   (let ((executable (flycheck-checker-default-executable checker))
5401         (config-file-var (flycheck-checker-get checker 'config-file-var))
5402         (option-vars (seq-sort #'string<
5403                                (flycheck-checker-get checker 'option-vars))))
5404     (princ "\n")
5405
5406     (let ((doc-start (with-current-buffer standard-output (point-max))))
5407       ;; Track the start of our documentation so that we can re-indent it
5408       ;; properly
5409       (princ "  This syntax checker executes \"")
5410       (princ executable)
5411       (princ "\"")
5412       (when config-file-var
5413         (princ ", using a configuration file from `")
5414         (princ (symbol-name config-file-var))
5415         (princ "'"))
5416       (princ ". The executable can be overridden with `")
5417       (princ (symbol-name (flycheck-checker-executable-variable checker)))
5418       (princ "'.")
5419
5420       (with-current-buffer standard-output
5421         (save-excursion
5422           (fill-region-as-paragraph doc-start (point-max)))))
5423     (princ "\n")
5424     (when option-vars
5425       (princ
5426        "\n  This syntax checker can be configured with these options:\n\n")
5427       (dolist (var option-vars)
5428         (princ (format "     * `%s'\n" var))))))
5429
5430 (defun flycheck-verify-command-checker (checker)
5431   "Verify a command CHECKER in the current buffer.
5432
5433 Return a list of `flycheck-verification-result' objects for
5434 CHECKER."
5435   (let ((executable (flycheck-find-checker-executable checker))
5436         (config-file-var (flycheck-checker-get checker 'config-file-var)))
5437     `(
5438       ,(flycheck-verification-result-new
5439         :label "executable"
5440         :message (if executable (format "Found at %s" executable) "Not found")
5441         :face (if executable 'success '(bold error)))
5442       ,@(when config-file-var
5443           (let* ((value (symbol-value config-file-var))
5444                  (path (and value (flycheck-locate-config-file value checker))))
5445             (list (flycheck-verification-result-new
5446                    :label "configuration file"
5447                    :message (if path (format "Found at %S" path) "Not found")
5448                    :face (if path 'success 'warning)))))
5449       ,@(when (not (flycheck-temp-files-writable-p checker))
5450           (list (flycheck-verification-result-new
5451                  :label "temp directory"
5452                  :message (format "%s is not writable"
5453                                   (flycheck-temp-directory checker))
5454                  :face 'error))))))
5455
5456 \f
5457 ;;; Process management for command syntax checkers
5458 (defun flycheck-receive-checker-output (process output)
5459   "Receive a syntax checking PROCESS OUTPUT."
5460   (push output (process-get process 'flycheck-pending-output)))
5461
5462 (defun flycheck-get-output (process)
5463   "Get the complete output of PROCESS."
5464   (with-demoted-errors "Error while retrieving process output: %S"
5465     (let ((pending-output (process-get process 'flycheck-pending-output)))
5466       (apply #'concat (nreverse pending-output)))))
5467
5468 (defun flycheck-handle-signal (process _event)
5469   "Handle a signal from the syntax checking PROCESS.
5470
5471 _EVENT is ignored."
5472   (when (memq (process-status process) '(signal exit))
5473     (let ((files (process-get process 'flycheck-temporaries))
5474           (buffer (process-get process 'flycheck-buffer))
5475           (callback (process-get process 'flycheck-callback))
5476           (cwd (process-get process 'flycheck-working-directory)))
5477       ;; Delete the temporary files
5478       (seq-do #'flycheck-safe-delete files)
5479       (when (buffer-live-p buffer)
5480         (with-current-buffer buffer
5481           (condition-case err
5482               (pcase (process-status process)
5483                 (`signal
5484                  (funcall callback 'interrupted))
5485                 (`exit
5486                  (flycheck-finish-checker-process
5487                   (process-get process 'flycheck-checker)
5488                   (process-exit-status process)
5489                   files
5490                   (flycheck-get-output process) callback cwd)))
5491             ((debug error)
5492              (funcall callback 'errored (error-message-string err)))))))))
5493
5494 (defun flycheck-finish-checker-process
5495     (checker exit-status files output callback cwd)
5496   "Finish a checker process from CHECKER with EXIT-STATUS.
5497
5498 FILES is a list of files given as input to the checker.  OUTPUT
5499 is the output of the syntax checker.  CALLBACK is the status
5500 callback to use for reporting.
5501
5502 Parse the OUTPUT and report an appropriate error status.
5503
5504 Resolve all errors in OUTPUT using CWD as working directory."
5505   (let ((errors (flycheck-parse-output output checker (current-buffer))))
5506     (when (and (/= exit-status 0) (not errors))
5507       ;; Warn about a suspicious result from the syntax checker.  We do right
5508       ;; after parsing the errors, before filtering, because a syntax checker
5509       ;; might report errors from other files (e.g. includes) even if there
5510       ;; are no errors in the file being checked.
5511       (funcall callback 'suspicious
5512                (format "Flycheck checker %S returned non-zero \
5513 exit code %s, but its output contained no errors: %s\nTry \
5514 installing a more recent version of %S, and please open a bug \
5515 report if the issue persists in the latest release.  Thanks!"
5516                        checker exit-status output checker)))
5517     (funcall callback 'finished
5518              ;; Fix error file names, by substituting them backwards from the
5519              ;; temporaries.
5520              (seq-map (lambda (e) (flycheck-fix-error-filename e files cwd))
5521                       errors))))
5522
5523 \f
5524 ;;; Executables of command checkers.
5525 (defmacro flycheck-def-executable-var (checker default-executable)
5526   "Define the executable variable for CHECKER.
5527
5528 DEFAULT-EXECUTABLE is the default executable.  It is only used in
5529 the docstring of the variable.
5530
5531 The variable is defined with `defcustom' in the
5532 `flycheck-executables' group.  It's also defined to be risky as
5533 file-local variable, to avoid arbitrary executables being used
5534 for syntax checking."
5535   (let ((executable-var (flycheck-checker-executable-variable checker)))
5536     `(progn
5537        (defcustom ,executable-var nil
5538          ,(format "The executable of the %s syntax checker.
5539
5540 Either a string containing the name or the path of the
5541 executable, or nil to use the default executable from the syntax
5542 checker declaration.
5543
5544 The default executable is %S." checker default-executable)
5545          :type '(choice (const :tag "Default executable" nil)
5546                         (string :tag "Name or path"))
5547          :group 'flycheck-executables
5548          :risky t))))
5549
5550 (defun flycheck-set-checker-executable (checker &optional executable)
5551   "Set the executable of CHECKER in the current buffer.
5552
5553 CHECKER is a syntax checker symbol.  EXECUTABLE is a string with
5554 the name of an executable or the path to an executable file, which
5555 is to be used as executable for CHECKER.  If omitted or nil,
5556 reset the executable of CHECKER.
5557
5558 Interactively, prompt for a syntax checker and an executable
5559 file, and set the executable of the selected syntax checker.
5560 With prefix arg, prompt for a syntax checker only, and reset the
5561 executable of the select checker to the default.
5562
5563 Set the executable variable of CHECKER, that is,
5564 `flycheck-CHECKER-executable' to EXECUTABLE.  Signal
5565 `user-error', if EXECUTABLE does not denote a command or an
5566 executable file.
5567
5568 This command is intended for interactive use only.  In Lisp, just
5569 `let'-bind the corresponding variable, or set it directly.  Use
5570 `flycheck-checker-executable-variable' to obtain the executable
5571 variable symbol for a syntax checker."
5572   (declare (interactive-only "Set the executable variable directly instead"))
5573   (interactive
5574    (let* ((checker (read-flycheck-checker "Syntax checker: "))
5575           (default-executable (flycheck-checker-default-executable checker))
5576           (executable (if current-prefix-arg
5577                           nil
5578                         (read-file-name "Executable: " nil default-executable
5579                                         nil nil flycheck-executable-find))))
5580      (list checker executable)))
5581   (when (and executable (not (funcall flycheck-executable-find executable)))
5582     (user-error "%s is no executable" executable))
5583   (let ((variable (flycheck-checker-executable-variable checker)))
5584     (set (make-local-variable variable) executable)))
5585
5586 \f
5587 ;;; Configuration files and options for command checkers
5588 (defun flycheck-register-config-file-var (var checkers)
5589   "Register VAR as config file var for CHECKERS.
5590
5591 CHECKERS is a single syntax checker or a list thereof."
5592   (when (symbolp checkers)
5593     (setq checkers (list checkers)))
5594   (dolist (checker checkers)
5595     (setf (flycheck-checker-get checker 'config-file-var) var)))
5596
5597 ;;;###autoload
5598 (defmacro flycheck-def-config-file-var (symbol checker &optional file-name
5599                                                &rest custom-args)
5600   "Define SYMBOL as config file variable for CHECKER, with default FILE-NAME.
5601
5602 SYMBOL is declared as customizable variable using `defcustom', to
5603 provide a configuration file for the given syntax CHECKER.
5604 CUSTOM-ARGS are forwarded to `defcustom'.
5605
5606 FILE-NAME is the initial value of the new variable.  If omitted,
5607 the default value is nil.
5608
5609 Use this together with the `config-file' form in the `:command'
5610 argument to `flycheck-define-checker'."
5611   ;; FIXME: We should allow multiple config files per checker as well as
5612   ;; multiple checkers per config file
5613   (declare (indent 3))
5614   `(progn
5615      (defcustom ,symbol ,file-name
5616        ,(format "Configuration file for `%s'.
5617
5618 If set to a string, locate the configuration file using the
5619 functions from `flycheck-locate-config-file-functions'.  If the
5620 file is found pass it to the syntax checker as configuration
5621 file.
5622
5623 If no configuration file is found, or if this variable is set to
5624 nil, invoke the syntax checker without a configuration file.
5625
5626 Use this variable as file-local variable if you need a specific
5627 configuration file a buffer." checker)
5628        :type '(choice (const :tag "No configuration file" nil)
5629                       (string :tag "File name or path"))
5630        :group 'flycheck-config-files
5631        ,@custom-args)
5632      (flycheck-register-config-file-var ',symbol ',checker)))
5633
5634 (defun flycheck-locate-config-file (filename checker)
5635   "Locate the configuration file FILENAME for CHECKER.
5636
5637 Locate the configuration file using
5638 `flycheck-locate-config-file-functions'.
5639
5640 Return the absolute path of the configuration file, or nil if no
5641 configuration file was found."
5642   (-when-let (filepath (run-hook-with-args-until-success
5643                         'flycheck-locate-config-file-functions
5644                         filename checker))
5645     (when (file-exists-p filepath)
5646       filepath)))
5647
5648 (defun flycheck-locate-config-file-by-path (filepath _checker)
5649   "Locate a configuration file by a FILEPATH.
5650
5651 If FILEPATH is a contains a path separator, expand it against the
5652 default directory and return it if it points to an existing file.
5653 Otherwise return nil.
5654
5655 _CHECKER is ignored."
5656   ;; If the path is just a plain file name, skip it.
5657   (unless (string= (file-name-nondirectory filepath) filepath)
5658     (let ((file-name (expand-file-name filepath)))
5659       (and (file-exists-p file-name) file-name))))
5660
5661 (defun flycheck-locate-config-file-ancestor-directories (filename _checker)
5662   "Locate a configuration FILENAME in ancestor directories.
5663
5664 If the current buffer has a file name, search FILENAME in the
5665 directory of the current buffer and all ancestors thereof (see
5666 `locate-dominating-file').  If the file is found, return its
5667 absolute path.  Otherwise return nil.
5668
5669 _CHECKER is ignored."
5670   (-when-let* ((basefile (buffer-file-name))
5671                (directory (locate-dominating-file basefile filename)))
5672     (expand-file-name filename directory)))
5673
5674 (defun flycheck-locate-config-file-home (filename _checker)
5675   "Locate a configuration FILENAME in the home directory.
5676
5677 Return the absolute path, if FILENAME exists in the user's home
5678 directory, or nil otherwise."
5679   (let ((path (expand-file-name filename "~")))
5680     (when (file-exists-p path)
5681       path)))
5682
5683 (seq-do (apply-partially #'custom-add-frequent-value
5684                          'flycheck-locate-config-file-functions)
5685         '(flycheck-locate-config-file-by-path
5686           flycheck-locate-config-file-ancestor-directories
5687           flycheck-locate-config-file-home))
5688
5689 (defun flycheck-register-option-var (var checkers)
5690   "Register an option VAR with CHECKERS.
5691
5692 VAR is an option symbol, and CHECKERS a syntax checker symbol or
5693 a list thereof.  Register VAR with all CHECKERS so that it
5694 appears in the help output."
5695   (when (symbolp checkers)
5696     (setq checkers (list checkers)))
5697   (dolist (checker checkers)
5698     (cl-pushnew var (flycheck-checker-get checker 'option-vars))))
5699
5700 ;;;###autoload
5701 (defmacro flycheck-def-option-var (symbol init-value checkers docstring
5702                                           &rest custom-args)
5703   "Define SYMBOL as option variable with INIT-VALUE for CHECKER.
5704
5705 SYMBOL is declared as customizable variable using `defcustom', to
5706 provide an option for the given syntax CHECKERS (a checker or a
5707 list of checkers).  INIT-VALUE is the initial value of the
5708 variable, and DOCSTRING is its docstring.  CUSTOM-ARGS are
5709 forwarded to `defcustom'.
5710
5711 Use this together with the `option', `option-list' and
5712 `option-flag' forms in the `:command' argument to
5713 `flycheck-define-checker'."
5714   (declare (indent 3)
5715            (doc-string 4))
5716   `(progn
5717      (defcustom ,symbol ,init-value
5718        ,(concat docstring "
5719
5720 This variable is an option for the following syntax checkers:
5721
5722 "
5723                 (mapconcat (lambda (c) (format "  - `%s'" c))
5724                            (if (symbolp checkers) (list checkers) checkers)
5725                            "\n"))
5726        :group 'flycheck-options
5727        ,@custom-args)
5728      (flycheck-register-option-var ',symbol ',checkers)))
5729
5730 (defun flycheck-option-int (value)
5731   "Convert an integral option VALUE to a string.
5732
5733 If VALUE is nil, return nil.  Otherwise return VALUE converted to
5734 a string."
5735   (and value (number-to-string value)))
5736
5737 (defun flycheck-option-symbol (value)
5738   "Convert a symbol option VALUE to string.
5739
5740 If VALUE is nil return nil.  Otherwise return VALUE converted to
5741 a string."
5742   (and value (symbol-name value)))
5743
5744 (defun flycheck-option-comma-separated-list (value &optional separator filter)
5745   "Convert VALUE into a list separated by SEPARATOR.
5746
5747 SEPARATOR is a string to separate items in VALUE, defaulting to
5748 \",\".  FILTER is an optional function, which takes a single
5749 argument and returns either a string or nil.
5750
5751 If VALUE is a list, apply FILTER to each item in VALUE, remove
5752 all nil items, and return a single string of all remaining items
5753 separated by SEPARATOR.
5754
5755 Otherwise, apply FILTER to VALUE and return the result.
5756 SEPARATOR is ignored in this case."
5757   (let ((filter (or filter #'identity))
5758         (separator (or separator ",")))
5759     (if (listp value)
5760         (-when-let (value (delq nil (seq-map filter value)))
5761           (string-join value separator))
5762       (funcall filter value))))
5763
5764 (defmacro flycheck-def-args-var (symbol checkers &rest custom-args)
5765   "Define SYMBOL as argument variable for CHECKERS.
5766
5767 SYMBOL is declared as customizable, risky and buffer-local
5768 variable using `defcustom' to provide an option for arbitrary
5769 arguments for the given syntax CHECKERS (either a single checker
5770 or a list of checkers).  CUSTOM-ARGS is forwarded to `defcustom'.
5771
5772 Use the `eval' form to splice this variable into the
5773 `:command'."
5774   (declare (indent 2))
5775   `(flycheck-def-option-var ,symbol nil ,checkers
5776      "A list of additional command line arguments.
5777
5778 The value of this variable is a list of strings with additional
5779 command line arguments."
5780      :risky t
5781      :type '(repeat (string :tag "Argument"))
5782      ,@custom-args))
5783
5784 \f
5785 ;;; Command syntax checkers as compile commands
5786 (defun flycheck-checker-pattern-to-error-regexp (pattern)
5787   "Convert PATTERN into an error regexp for compile.el.
5788
5789 Return a list representing PATTERN, suitable as element in
5790 `compilation-error-regexp-alist'."
5791   (let* ((regexp (car pattern))
5792          (level (cdr pattern))
5793          (level-no (flycheck-error-level-compilation-level level)))
5794     (list regexp 1 2 3 level-no)))
5795
5796 (defun flycheck-checker-compilation-error-regexp-alist (checker)
5797   "Convert error patterns of CHECKER for use with compile.el.
5798
5799 Return an alist of all error patterns of CHECKER, suitable for
5800 use with `compilation-error-regexp-alist'."
5801   (seq-map #'flycheck-checker-pattern-to-error-regexp
5802            (flycheck-checker-get checker 'error-patterns)))
5803
5804 (defun flycheck-checker-shell-command (checker)
5805   "Get a shell command for CHECKER.
5806
5807 Perform substitution in the arguments of CHECKER, but with
5808 `flycheck-substitute-shell-argument'.
5809
5810 Return the command of CHECKER as single string, suitable for
5811 shell execution."
5812   ;; Note: Do NOT use `combine-and-quote-strings' here.  Despite it's name it
5813   ;; does not properly quote shell arguments, and actually breaks for special
5814   ;; characters.  See https://github.com/flycheck/flycheck/pull/522
5815   (let* ((args (apply #'append
5816                       (seq-map
5817                        (lambda (arg)
5818                          (if (memq arg '(source source-inplace source-original))
5819                              (list (buffer-file-name))
5820                            (flycheck-substitute-argument arg checker)))
5821                        (flycheck-checker-arguments checker))))
5822          (command (mapconcat
5823                    #'shell-quote-argument
5824                    (funcall flycheck-command-wrapper-function
5825                             (cons (flycheck-checker-executable checker) args))
5826                    " ")))
5827     (if (flycheck-checker-get checker 'standard-input)
5828         ;; If the syntax checker expects the source from standard input add an
5829         ;; appropriate shell redirection
5830         (concat command " < " (shell-quote-argument (buffer-file-name)))
5831       command)))
5832
5833 (defun flycheck-compile-name (_name)
5834   "Get a name for a Flycheck compilation buffer.
5835
5836 _NAME is ignored."
5837   (format "*Flycheck %s*" (buffer-file-name)))
5838
5839 (defun flycheck-compile (checker)
5840   "Run CHECKER via `compile'.
5841
5842 CHECKER must be a valid syntax checker.  Interactively, prompt
5843 for a syntax checker to run.
5844
5845 Instead of highlighting errors in the buffer, this command pops
5846 up a separate buffer with the entire output of the syntax checker
5847 tool, just like `compile' (\\[compile])."
5848   (interactive
5849    (let ((default (flycheck-get-checker-for-buffer)))
5850      (list (read-flycheck-checker "Run syntax checker as compile command: "
5851                                   (when (flycheck-checker-get default 'command)
5852                                     default)
5853                                   'command))))
5854   (unless (flycheck-valid-checker-p checker)
5855     (user-error "%S is not a valid syntax checker" checker))
5856   (unless (buffer-file-name)
5857     (user-error "Cannot compile buffers without backing file"))
5858   (unless (flycheck-may-use-checker checker)
5859     (user-error "Cannot use syntax checker %S in this buffer" checker))
5860   (unless (flycheck-checker-executable checker)
5861     (user-error "Cannot run checker %S as shell command" checker))
5862   (let* ((default-directory (flycheck-compute-working-directory checker))
5863          (command (flycheck-checker-shell-command checker))
5864          (buffer (compilation-start command nil #'flycheck-compile-name)))
5865     (with-current-buffer buffer
5866       (setq-local compilation-error-regexp-alist
5867                   (flycheck-checker-compilation-error-regexp-alist checker)))))
5868
5869 \f
5870 ;;; General error parsing for command checkers
5871 (defun flycheck-parse-output (output checker buffer)
5872   "Parse OUTPUT from CHECKER in BUFFER.
5873
5874 OUTPUT is a string with the output from the checker symbol
5875 CHECKER.  BUFFER is the buffer which was checked.
5876
5877 Return the errors parsed with the error patterns of CHECKER."
5878   (funcall (flycheck-checker-get checker 'error-parser) output checker buffer))
5879
5880 (defun flycheck-fix-error-filename (err buffer-files cwd)
5881   "Fix the file name of ERR from BUFFER-FILES.
5882
5883 Resolves error file names relative to CWD directory.
5884
5885 Make the file name of ERR absolute.  If the absolute file name of
5886 ERR is in BUFFER-FILES, replace it with the return value of the
5887 function `buffer-file-name'."
5888   (flycheck-error-with-buffer err
5889     (-when-let (filename (flycheck-error-filename err))
5890       (when (seq-some (apply-partially #'flycheck-same-files-p
5891                                        (expand-file-name filename cwd))
5892                       buffer-files)
5893         (setf (flycheck-error-filename err) buffer-file-name)
5894         (when (and buffer-file-name (flycheck-error-message err))
5895           (setf (flycheck-error-message err)
5896                 (replace-regexp-in-string
5897                  (regexp-quote filename) buffer-file-name
5898                  (flycheck-error-message err) 'fixed-case 'literal))))))
5899   err)
5900
5901 \f
5902 ;;; Error parsers for command syntax checkers
5903 (defun flycheck-parse-xml-region (beg end)
5904   "Parse the xml region between BEG and END.
5905
5906 Wrapper around `xml-parse-region' which transforms the return
5907 value of this function into one compatible to
5908 `libxml-parse-xml-region' by simply returning the first element
5909 from the node list."
5910   (ignore-errors (car (xml-parse-region beg end))))
5911
5912 (defun flycheck-parse-xml-region-with-fallback (beg end)
5913   "Parse the xml region between BEG and END.
5914
5915 Try parsing with libxml first; if that fails, revert to
5916 `flycheck-parse-xml-region'.  Failures can be caused by incorrect
5917 XML (see URL `https://github.com/flycheck/flycheck/issues/1298'),
5918 or on Windows by a missing libxml DLL with a libxml-enabled Emacs
5919 \(see URL `https://github.com/flycheck/flycheck/issues/1330')."
5920   ;; FIXME use `libxml-available-p' when it gets implemented.
5921   (or (and (fboundp 'libxml-parse-xml-region)
5922            (libxml-parse-xml-region beg end))
5923       (flycheck-parse-xml-region beg end)))
5924
5925 (defvar flycheck-xml-parser 'flycheck-parse-xml-region-with-fallback
5926   "Function used to parse an xml string from a region.
5927
5928 The default uses libxml if available, and falls back to
5929 `flycheck-parse-xml-region' otherwise.")
5930
5931 (defun flycheck-parse-xml-string (xml)
5932   "Parse an XML string.
5933
5934 Return the document tree parsed from XML in the form `(ROOT ATTRS
5935 BODY...)'.  ROOT is a symbol identifying the name of the root
5936 element.  ATTRS is an alist of the attributes of the root node.
5937 BODY is zero or more body elements, either as strings (in case of
5938 text nodes) or as XML nodes, in the same for as the root node."
5939   (with-temp-buffer
5940     (insert xml)
5941     (funcall flycheck-xml-parser (point-min) (point-max))))
5942
5943 (defun flycheck-parse-checkstyle (output checker buffer)
5944   "Parse Checkstyle errors from OUTPUT.
5945
5946 Parse Checkstyle-like XML output.  Use this error parser for
5947 checkers that have an option to output errors in this format.
5948
5949 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
5950 the BUFFER that was checked respectively.
5951
5952 See URL `http://checkstyle.sourceforge.net/' for information
5953 about Checkstyle."
5954   (pcase (flycheck-parse-xml-string output)
5955     (`(checkstyle ,_ . ,file-nodes)
5956      (let (errors)
5957        (dolist (node file-nodes)
5958          (pcase node
5959            (`(file ,file-attrs . ,error-nodes)
5960             (dolist (node error-nodes)
5961               (pcase node
5962                 (`(error ,error-attrs . ,_)
5963                  (let-alist error-attrs
5964                    (push (flycheck-error-new-at
5965                           (flycheck-string-to-number-safe .line)
5966                           (flycheck-string-to-number-safe .column)
5967                           (pcase .severity
5968                             (`"error"   'error)
5969                             (`"warning" 'warning)
5970                             (`"info"    'info)
5971                             ;; Default to error for unknown .severity
5972                             (_          'error))
5973                           .message
5974                           :checker checker :id .source
5975                           :buffer buffer
5976                           :filename (cdr (assq 'name file-attrs)))
5977                          errors))))))))
5978        (nreverse errors)))))
5979
5980 (defun flycheck-parse-cppcheck (output checker buffer)
5981   "Parse Cppcheck errors from OUTPUT.
5982
5983 Parse Cppcheck XML v2 output.
5984
5985 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
5986 the BUFFER that was checked respectively.
5987
5988 See URL `http://cppcheck.sourceforge.net/' for more information
5989 about Cppcheck."
5990   (pcase (flycheck-parse-xml-string output)
5991     (`(results ,_ . ,body)
5992      (let (errors)
5993        (dolist (node body)
5994          (pcase node
5995            (`(errors ,_ . ,error-nodes)
5996             (dolist (node error-nodes)
5997               (pcase node
5998                 (`(error ,error-attrs . ,loc-nodes)
5999                  (let ((id (cdr (assq 'id error-attrs)))
6000                        (message (cdr (assq 'verbose error-attrs)))
6001                        (level (pcase (cdr (assq 'severity error-attrs))
6002                                 (`"error" 'error)
6003                                 (`"style" 'info)
6004                                 (`"information" 'info)
6005                                 (_ 'warning))))
6006                    (dolist (node loc-nodes)
6007                      (pcase node
6008                        (`(location ,loc-attrs . ,_)
6009                         (let-alist loc-attrs
6010                           (push (flycheck-error-new-at
6011                                  (flycheck-string-to-number-safe .line)
6012                                  nil
6013                                  level
6014                                  ;; cppcheck return newline characters as "\012"
6015                                  (replace-regexp-in-string "\\\\012" "\n"
6016                                                            message)
6017                                  :id id
6018                                  :checker checker
6019                                  :buffer buffer
6020                                  :filename .file)
6021                                 errors))))))))))))
6022        (nreverse errors)))))
6023
6024 (defun flycheck-parse-phpmd (output checker buffer)
6025   "Parse phpmd errors from OUTPUT.
6026
6027 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
6028 the BUFFER that was checked respectively.
6029
6030 See URL `http://phpmd.org/' for more information about phpmd."
6031   (pcase (flycheck-parse-xml-string output)
6032     (`(pmd ,_ . ,body)
6033      (let (errors)
6034        (dolist (node body)
6035          (pcase node
6036            (`(file ,file-attrs . ,violation-nodes)
6037             (let ((filename (cdr (assq 'name file-attrs))))
6038               (dolist (node violation-nodes)
6039                 (pcase node
6040                   (`(violation ,vio-attrs ,(and message (pred stringp)))
6041                    (let-alist vio-attrs
6042                      (push
6043                       (flycheck-error-new-at
6044                        (flycheck-string-to-number-safe .beginline)
6045                        nil
6046                        'warning (string-trim message)
6047                        :id .rule
6048                        :checker checker
6049                        :buffer buffer
6050                        :filename filename)
6051                       errors)))))))))
6052        (nreverse errors)))))
6053
6054 (defun flycheck-parse-reek (output checker buffer)
6055   "Parse Reek warnings from JSON OUTPUT.
6056
6057 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
6058 the BUFFER that was checked respectively.
6059
6060 See URL `https://github.com/troessner/reek' for more information
6061 about Reek."
6062   (let ((errors nil))
6063     (dolist (message (car (flycheck-parse-json output)))
6064       (let-alist message
6065         (dolist (line (delete-dups .lines))
6066           (push
6067            (flycheck-error-new-at
6068             line
6069             nil
6070             'warning (concat .context " " .message)
6071             :id .smell_type
6072             :checker checker
6073             :buffer buffer
6074             :filename .source)
6075            errors))))
6076     (nreverse errors)))
6077
6078 (defun flycheck-parse-go-staticcheck (output checker buffer)
6079   "Parse staticheck warnings from JSON OUTPUT.
6080
6081 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
6082 the BUFFER that was checked respectively.
6083
6084 See URL `https://staticcheck.io/docs/formatters' for more
6085 information about staticheck."
6086   (let ((errors nil))
6087     (dolist (msg (flycheck-parse-json output))
6088       (let-alist msg
6089         (push
6090          (flycheck-error-new-at
6091           .location.line
6092           .location.column
6093           (pcase .severity
6094             (`"error"   'error)
6095             (`"warning" 'warning)
6096             (`"ignored" 'info)
6097             ;; Default to warning for unknown .severity
6098             (_          'warning))
6099           .message
6100           :id .code
6101           :checker checker
6102           :buffer buffer
6103           :filename .location.file)
6104          errors)))
6105     (nreverse errors)))
6106
6107 (defun flycheck-parse-tslint (output checker buffer)
6108   "Parse TSLint errors from JSON OUTPUT.
6109
6110 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
6111 the BUFFER that was checked respectively.
6112
6113 See URL `https://palantir.github.io/tslint/' for more information
6114 about TSLint."
6115   (let ((json-array-type 'list))
6116     (seq-map (lambda (message)
6117                (let-alist message
6118                  (flycheck-error-new-at
6119                   (+ 1 .startPosition.line)
6120                   (+ 1 .startPosition.character)
6121                   'warning .failure
6122                   :id .ruleName
6123                   :checker checker
6124                   :buffer buffer
6125                   :filename .name)))
6126              ;; Don't try to parse empty output as JSON
6127              (and (not (string-empty-p output))
6128                   (car (flycheck-parse-json output))))))
6129
6130 (defun flycheck-parse-rust-collect-spans (span)
6131   "Return a list of spans contained in a SPAN object."
6132   (let ((spans))
6133     (let-alist span
6134       ;; With macro expansion errors, some spans will point to phony file names
6135       ;; to indicate an error inside the std rust lib.  We skip these spans as
6136       ;; they won't appear in flycheck anyway.
6137       (unless (string= .file_name "<std macros>")
6138         (push span spans))
6139
6140       ;; Macro expansion errors will have a span in the 'expansion' field, so we
6141       ;; recursively collect it.
6142       (if .expansion.span
6143           (append (flycheck-parse-rust-collect-spans .expansion.span)
6144                   spans)
6145         spans))))
6146
6147 (defun flycheck-parse-rustc-diagnostic (diagnostic checker buffer)
6148   "Turn a rustc DIAGNOSTIC into a `flycheck-error'.
6149
6150 CHECKER and BUFFER denote the CHECKER that returned DIAGNOSTIC
6151 and the BUFFER that was checked respectively.
6152
6153 DIAGNOSTIC should be a parsed JSON object describing a rustc
6154 diagnostic, following the format described there:
6155
6156 https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139"
6157   (let ((error-message)
6158         (error-level)
6159         (error-code)
6160         (primary-filename)
6161         (primary-line)
6162         (primary-column)
6163         (group (make-symbol "group"))
6164         (spans)
6165         (children)
6166         (errors))
6167     ;; The diagnostic format is described in the link above.  The gist of it is
6168     ;; that a diagnostic can have several causes in the source text; these
6169     ;; causes are represented by spans.  The diagnostic has a message and a
6170     ;; level (error, warning), while the spans have a filename, line, column,
6171     ;; and an optional label.  The primary span points to the root cause of the
6172     ;; error in the source text, while non-primary spans point to related
6173     ;; causes.  Spans may have an 'expansion' field for macro expansion errors;
6174     ;; these expansion fields will contain another span (and so on).  In
6175     ;; addition, a diagnostic can also have children diagnostics that are used
6176     ;; to provide additional information through their message field, but do not
6177     ;; seem to contain any spans (yet).
6178     ;;
6179     ;; We first gather spans in order to turn every span into a flycheck error
6180     ;; object, that we collect into the `errors' list.
6181
6182     ;; Nested `let-alist' cause compilation warnings, hence we `setq' all
6183     ;; these values here first to avoid nesting.
6184     (let-alist diagnostic
6185       (setq error-message .message
6186             error-level (pcase .level
6187                           (`"error" 'error)
6188                           (`"warning" 'warning)
6189                           (`"note" 'info)
6190                           (_ 'error))
6191             ;; The 'code' field of the diagnostic contains the actual error
6192             ;; code and an optional explanation that we ignore
6193             error-code .code.code
6194             ;; Collect all spans recursively
6195             spans (seq-mapcat #'flycheck-parse-rust-collect-spans .spans)
6196             children .children))
6197
6198     ;; Turn each span into a flycheck error
6199     (dolist (span spans)
6200       (let-alist span
6201         ;; Children may not have filename/line/column information, so we use
6202         ;; those from the primary span
6203         (when .is_primary
6204           (setq primary-filename .file_name
6205                 primary-line .line_start
6206                 primary-column .column_start))
6207         (push
6208          (flycheck-error-new-at
6209           .line_start
6210           .column_start
6211           ;; Non-primary spans are used for notes
6212           (if .is_primary error-level 'info)
6213           (if .is_primary
6214               ;; Primary spans may have labels with additional information
6215               (concat error-message (when .label
6216                                       (format " (%s)" .label)))
6217             ;; If the label is empty, fallback on the error message,
6218             ;; otherwise we won't be able to display anything
6219             (or .label error-message))
6220           :id error-code
6221           :checker checker
6222           :buffer buffer
6223           :filename .file_name
6224           :group group)
6225          errors)))
6226
6227     ;; Then we turn children messages into flycheck errors pointing to the
6228     ;; location of the primary span.
6229     (dolist (child children)
6230       (let-alist child
6231         (push
6232          (flycheck-error-new-at
6233           ;; Use the line/column from the first span if there is one, or
6234           ;; fallback to the line/column information from the primary span of
6235           ;; the diagnostic.
6236           (or (cdr (assq 'line_start (car .spans)))
6237               primary-line)
6238           (or (cdr (assq 'column_start (car .spans)))
6239               primary-column)
6240           'info
6241           ;; Messages from `cargo clippy' may suggest replacement code.  In
6242           ;; these cases, the `message' field itself is an unhelpful `try' or
6243           ;; `change this to'.  We add the `suggested_replacement' field in
6244           ;; these cases.
6245           (-if-let (replacement
6246                     (cdr (assq 'suggested_replacement (car .spans))))
6247               (format "%s: `%s`" .message replacement)
6248             .message)
6249           :id error-code
6250           :checker checker
6251           :buffer buffer
6252           :filename primary-filename
6253           :group group)
6254          errors)))
6255
6256     ;; If there are no spans, the error is not associated with a specific
6257     ;; file but with the project as a whole.  We still need to report it to
6258     ;; the user by emitting a corresponding flycheck-error object.
6259     (unless spans
6260       (push (flycheck-error-new-at
6261              ;; We have no specific position to attach the error to, so
6262              ;; let's use the top of the file.
6263              1 1
6264              error-level
6265              error-message
6266              :id error-code
6267              :checker checker
6268              :buffer buffer
6269              :group group)
6270             errors))
6271     (nreverse errors)))
6272
6273 (defun flycheck-parse-json (output)
6274   "Return parsed JSON data from OUTPUT.
6275
6276 OUTPUT is a string that contains JSON data.  Each line of OUTPUT
6277 may be either plain text, a JSON array (starting with `['), or a
6278 JSON object (starting with `{').
6279
6280 This function ignores the plain text lines, parses the JSON
6281 lines, and returns the parsed JSON lines in a list."
6282   (let ((objects nil)
6283         (json-array-type 'list)
6284         (json-false nil))
6285     (with-temp-buffer
6286       (insert output)
6287       (goto-char (point-min))
6288       (while (not (eobp))
6289         (when (memq (char-after) '(?\{ ?\[))
6290           (push (json-read) objects))
6291         (forward-line)))
6292     (nreverse objects)))
6293
6294 (defun flycheck-parse-rustc (output checker buffer)
6295   "Parse rustc errors from OUTPUT and return a list of `flycheck-error'.
6296
6297 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
6298 the BUFFER that was checked respectively.
6299
6300 The expected format for OUTPUT is a mix of plain text lines and
6301 JSON lines.  This function ignores the plain text lines and
6302 parses only JSON lines.  Each JSON line is expected to be a JSON
6303 object that corresponds to a diagnostic from the compiler.  The
6304 expected diagnostic format is described there:
6305
6306 https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139"
6307   (seq-mapcat (lambda (msg)
6308                 (flycheck-parse-rustc-diagnostic msg checker buffer))
6309               (flycheck-parse-json output)))
6310
6311 (defun flycheck-parse-cargo-rustc (output checker buffer)
6312   "Parse Cargo errors from OUTPUT and return a list of `flycheck-error'.
6313
6314 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
6315 the BUFFER that was checked respectively.
6316
6317 The expected format for OUTPUT is a mix of plain text lines and
6318 JSON lines.  This function ignores the plain text lines and
6319 parses only JSON lines.  Each JSON line is expected to be a JSON
6320 object that represents a message from Cargo.  The format of
6321 messages emitted by Cargo is described in cargo's
6322 machine_message.rs at URL `https://git.io/vh24R'."
6323   (let ((errors))
6324     (dolist (msg (flycheck-parse-json output))
6325       (let-alist msg
6326         ;; Errors and warnings from rustc are wrapped by cargo, so we filter and
6327         ;; unwrap them, and delegate the actual construction of `flycheck-error'
6328         ;; objects to `flycheck-parse-rustc-diagnostic'.
6329         (when (string= .reason "compiler-message")
6330           (push (flycheck-parse-rustc-diagnostic .message checker buffer)
6331                 errors))))
6332     (apply #'nconc errors)))
6333
6334 \f
6335 ;;; Error parsing with regular expressions
6336 (defun flycheck-get-regexp (patterns)
6337   "Create a single regular expression from PATTERNS."
6338   (rx-to-string `(or ,@(seq-map (lambda (p) (list 'regexp (car p))) patterns))
6339                 'no-group))
6340
6341 (defun flycheck-tokenize-output-with-patterns (output patterns)
6342   "Tokenize OUTPUT with PATTERNS.
6343
6344 Split the output into error tokens, using all regular expressions
6345 from the error PATTERNS.  An error token is simply a string
6346 containing a single error from OUTPUT.  Such a token can then be
6347 parsed into a structured error by applying the PATTERNS again,
6348 see `flycheck-parse-errors-with-patterns'.
6349
6350 Return a list of error tokens."
6351   (let ((regexp (flycheck-get-regexp patterns))
6352         (last-match 0)
6353         errors)
6354     (while (string-match regexp output last-match)
6355       (push (match-string 0 output) errors)
6356       (setq last-match (match-end 0)))
6357     (reverse errors)))
6358
6359 (defun flycheck-try-parse-error-with-pattern (err pattern checker)
6360   "Try to parse a single ERR with a PATTERN for CHECKER.
6361
6362 Return the parsed error if PATTERN matched ERR, or nil
6363 otherwise."
6364   (let ((regexp (car pattern))
6365         (level (cdr pattern)))
6366     (when (string-match regexp err)
6367       (let ((filename (match-string 1 err))
6368             (line (match-string 2 err))
6369             (column (match-string 3 err))
6370             (message (match-string 4 err))
6371             (id (match-string 5 err)))
6372         (flycheck-error-new-at
6373          (flycheck-string-to-number-safe line)
6374          (flycheck-string-to-number-safe column)
6375          level
6376          (unless (string-empty-p message) message)
6377          :id (unless (string-empty-p id) id)
6378          :checker checker
6379          :filename (if (or (null filename) (string-empty-p filename))
6380                        (buffer-file-name)
6381                      filename))))))
6382
6383 (defun flycheck-parse-error-with-patterns (err patterns checker)
6384   "Parse a single ERR with error PATTERNS for CHECKER.
6385
6386 Apply each pattern in PATTERNS to ERR, in the given order, and
6387 return the first parsed error."
6388   ;; Try to parse patterns in the order of declaration to make sure that the
6389   ;; first match wins.
6390   (let (parsed-error)
6391     (while (and patterns
6392                 (not (setq parsed-error
6393                            (flycheck-try-parse-error-with-pattern
6394                             err (car patterns) checker))))
6395       (setq patterns (cdr patterns)))
6396     parsed-error))
6397
6398 (defun flycheck-parse-with-patterns (output checker buffer)
6399   "Parse OUTPUT from CHECKER with error patterns.
6400
6401 Uses the error patterns of CHECKER to tokenize the output and
6402 tries to parse each error token with all patterns, in the order
6403 of declaration.  Hence an error is never matched twice by two
6404 different patterns.  The pattern declared first always wins.
6405
6406 _BUFFER is ignored.
6407
6408 Return a list of parsed errors and warnings (as `flycheck-error'
6409 objects)."
6410   (with-current-buffer buffer
6411     (let ((patterns (flycheck-checker-get checker 'error-patterns)))
6412       (seq-map (lambda (err)
6413                  (flycheck-parse-error-with-patterns err patterns checker))
6414                (flycheck-tokenize-output-with-patterns output patterns)))))
6415
6416 \f
6417 ;;; Convenience definition of command-syntax checkers
6418 (defmacro flycheck-define-checker (symbol docstring &rest properties)
6419   "Define SYMBOL as command syntax checker with DOCSTRING and PROPERTIES.
6420
6421 Like `flycheck-define-command-checker', but PROPERTIES must not
6422 be quoted.  Also, implicitly define the executable variable for
6423 SYMBOL with `flycheck-def-executable-var'."
6424   (declare (indent 1)
6425            (doc-string 2))
6426   (let ((command (plist-get properties :command))
6427         (parser (plist-get properties :error-parser))
6428         (filter (plist-get properties :error-filter))
6429         (explainer (plist-get properties :error-explainer))
6430         (predicate (plist-get properties :predicate))
6431         (enabled-fn (plist-get properties :enabled))
6432         (verify-fn (plist-get properties :verify)))
6433
6434     `(progn
6435        (flycheck-def-executable-var ,symbol ,(car command))
6436
6437        (flycheck-define-command-checker ',symbol
6438          ,docstring
6439          :command ',command
6440          ,@(when parser
6441              `(:error-parser #',parser))
6442          :error-patterns ',(plist-get properties :error-patterns)
6443          ,@(when filter
6444              `(:error-filter #',filter))
6445          ,@(when explainer
6446              `(:error-explainer #',explainer))
6447          :modes ',(plist-get properties :modes)
6448          ,@(when predicate
6449              `(:predicate #',predicate))
6450          :next-checkers ',(plist-get properties :next-checkers)
6451          ,@(when enabled-fn
6452              `(:enabled #',enabled-fn))
6453          ,@(when verify-fn
6454              `(:verify #',verify-fn))
6455          :standard-input ',(plist-get properties :standard-input)
6456          :working-directory ',(plist-get properties :working-directory)))))
6457
6458 \f
6459 ;;; Built-in checkers
6460 (flycheck-def-args-var flycheck-gnat-args ada-gnat
6461   :package-version '(flycheck . "0.20"))
6462
6463 (flycheck-def-option-var flycheck-gnat-include-path nil ada-gnat
6464   "A list of include directories for GNAT.
6465
6466 The value of this variable is a list of strings, where each
6467 string is a directory to add to the include path of gcc.
6468 Relative paths are relative to the file being checked."
6469   :type '(repeat (directory :tag "Include directory"))
6470   :safe #'flycheck-string-list-p
6471   :package-version '(flycheck . "0.20"))
6472
6473 (flycheck-def-option-var flycheck-gnat-language-standard "2012" ada-gnat
6474   "The language standard to use in GNAT.
6475
6476 The value of this variable is either a string denoting a language
6477 standard, or nil, to use the default standard. When non-nil, pass
6478 the language standard via the `-std' option."
6479   :type '(choice (const :tag "Default standard" nil)
6480                  (string :tag "Language standard"))
6481   :safe #'stringp
6482   :package-version '(flycheck . "0.20"))
6483
6484 (flycheck-def-option-var flycheck-gnat-warnings
6485     '("wa") ada-gnat
6486   "A list of additional Ada warnings to enable in GNAT.
6487
6488 The value of this variable is a list of strings, where each
6489 string is the name of a warning category to enable. By default,
6490 most optional warnings are recommended, as in `-gnata'.
6491
6492 Refer to Info Node `(gnat_ugn_unw)Warning Message Control' for
6493 more information about GNAT warnings."
6494   :type '(repeat :tag "Warnings" (string :tag "Warning name"))
6495   :safe #'flycheck-string-list-p
6496   :package-version '(flycheck . "0.20"))
6497
6498 (flycheck-define-checker ada-gnat
6499   "An Ada syntax checker using GNAT.
6500
6501 Uses the GNAT compiler from GCC.  See URL
6502 `https://www.adacore.com/community/'."
6503   :command ("gnatmake"
6504             "-c"                        ; Just compile, don't bind
6505             "-f"                        ; Force re-compilation
6506             "-u"                        ; Compile the main file only
6507             "-gnatf"                    ; Full error information
6508             "-gnatef"                   ; Full source file name
6509             "-D" temporary-directory
6510             (option-list "-gnat" flycheck-gnat-warnings concat)
6511             (option-list "-I" flycheck-gnat-include-path concat)
6512             (option "-gnat" flycheck-gnat-language-standard concat)
6513             (eval flycheck-gnat-args)
6514             source)
6515   :error-patterns
6516   ((error line-start
6517           (message "In file included from") " " (file-name) ":" line ":"
6518           column ":"
6519           line-end)
6520    (info line-start (file-name) ":" line ":" column
6521          ": note: " (message) line-end)
6522    (warning line-start (file-name) ":" line ":" column
6523             ": warning: " (message) line-end)
6524    ;; no specific error prefix in Ada
6525    (error line-start (file-name) ":" line ":" column
6526           ": " (message) line-end))
6527   :modes ada-mode)
6528
6529 (flycheck-define-checker asciidoc
6530   "A AsciiDoc syntax checker using the AsciiDoc compiler.
6531
6532 See URL `http://www.methods.co.nz/asciidoc'."
6533   :command ("asciidoc" "-o" null-device "-")
6534   :standard-input t
6535   :error-patterns
6536   ((error line-start
6537           "asciidoc: ERROR: <stdin>: Line " line ": " (message)
6538           line-end)
6539    (warning line-start
6540             "asciidoc: WARNING: <stdin>: Line " line ": " (message)
6541             line-end)
6542    (info line-start
6543          "asciidoc: DEPRECATED: <stdin>: Line " line ": " (message)
6544          line-end))
6545   :modes adoc-mode)
6546
6547 (flycheck-define-checker asciidoctor
6548   "An AsciiDoc syntax checker using the Asciidoctor compiler.
6549
6550 See URL `http://asciidoctor.org'."
6551   :command ("asciidoctor" "-o" null-device "-")
6552   :standard-input t
6553   :error-patterns
6554   ((error line-start
6555           "asciidoctor: ERROR: <stdin>: Line " line ": " (message)
6556           line-end)
6557    (warning line-start
6558             "asciidoctor: WARNING: <stdin>: Line " line ": " (message)
6559             line-end))
6560   :modes adoc-mode)
6561
6562 (flycheck-def-args-var flycheck-clang-args c/c++-clang
6563   :package-version '(flycheck . "0.22"))
6564
6565 (flycheck-def-option-var flycheck-clang-blocks nil c/c++-clang
6566   "Enable blocks in Clang.
6567
6568 When non-nil, enable blocks in Clang with `-fblocks'.  See URL
6569 `http://clang.llvm.org/docs/BlockLanguageSpec.html' for more
6570 information about blocks."
6571   :type 'boolean
6572   :safe #'booleanp
6573   :package-version '(flycheck . "0.20"))
6574
6575 (flycheck-def-option-var flycheck-clang-definitions nil c/c++-clang
6576   "Additional preprocessor definitions for Clang.
6577
6578 The value of this variable is a list of strings, where each
6579 string is an additional definition to pass to Clang, via the `-D'
6580 option."
6581   :type '(repeat (string :tag "Definition"))
6582   :safe #'flycheck-string-list-p
6583   :package-version '(flycheck . "0.15"))
6584
6585 (flycheck-def-option-var flycheck-clang-include-path nil c/c++-clang
6586   "A list of include directories for Clang.
6587
6588 The value of this variable is a list of strings, where each
6589 string is a directory to add to the include path of Clang.
6590 Relative paths are relative to the file being checked."
6591   :type '(repeat (directory :tag "Include directory"))
6592   :safe #'flycheck-string-list-p
6593   :package-version '(flycheck . "0.14"))
6594
6595 (flycheck-def-option-var flycheck-clang-includes nil c/c++-clang
6596   "A list of additional include files for Clang.
6597
6598 The value of this variable is a list of strings, where each
6599 string is a file to include before syntax checking.  Relative
6600 paths are relative to the file being checked."
6601   :type '(repeat (file :tag "Include file"))
6602   :safe #'flycheck-string-list-p
6603   :package-version '(flycheck . "0.15"))
6604
6605 (flycheck-def-option-var flycheck-clang-language-standard nil c/c++-clang
6606   "The language standard to use in Clang.
6607
6608 The value of this variable is either a string denoting a language
6609 standard, or nil, to use the default standard.  When non-nil,
6610 pass the language standard via the `-std' option."
6611   :type '(choice (const :tag "Default standard" nil)
6612                  (string :tag "Language standard"))
6613   :safe #'stringp
6614   :package-version '(flycheck . "0.15"))
6615 (make-variable-buffer-local 'flycheck-clang-language-standard)
6616
6617 (flycheck-def-option-var flycheck-clang-ms-extensions nil c/c++-clang
6618   "Whether to enable Microsoft extensions to C/C++ in Clang.
6619
6620 When non-nil, enable Microsoft extensions to C/C++ via
6621 `-fms-extensions'."
6622   :type 'boolean
6623   :safe #'booleanp
6624   :package-version '(flycheck . "0.16"))
6625
6626 (flycheck-def-option-var flycheck-clang-no-exceptions nil c/c++-clang
6627   "Whether to disable exceptions in Clang.
6628
6629 When non-nil, disable exceptions for syntax checks, via
6630 `-fno-exceptions'."
6631   :type 'boolean
6632   :safe #'booleanp
6633   :package-version '(flycheck . "0.20"))
6634
6635 (flycheck-def-option-var flycheck-clang-no-rtti nil c/c++-clang
6636   "Whether to disable RTTI in Clang.
6637
6638 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
6639   :type 'boolean
6640   :safe #'booleanp
6641   :package-version '(flycheck . "0.15"))
6642
6643 (flycheck-def-option-var flycheck-clang-pedantic nil c/c++-clang
6644   "Whether to warn about language extensions in Clang.
6645
6646 For ISO C, follows the version specified by any -std option used.
6647 When non-nil, disable non-ISO extensions to C/C++ via
6648 `-pedantic'."
6649   :type 'boolean
6650   :safe #'booleanp
6651   :package-version '(flycheck . "0.23"))
6652
6653 (flycheck-def-option-var flycheck-clang-pedantic-errors nil c/c++-clang
6654   "Whether to error on language extensions in Clang.
6655
6656 For ISO C, follows the version specified by any -std option used.
6657 When non-nil, disable non-ISO extensions to C/C++ via
6658 `-pedantic-errors'."
6659   :type 'boolean
6660   :safe #'booleanp
6661   :package-version '(flycheck . "0.23"))
6662
6663 (flycheck-def-option-var flycheck-clang-standard-library nil c/c++-clang
6664   "The standard library to use for Clang.
6665
6666 The value of this variable is the name of a standard library as
6667 string, or nil to use the default standard library.
6668
6669 Refer to the Clang manual at URL
6670 `http://clang.llvm.org/docs/UsersManual.html' for more
6671 information about the standard library."
6672   :type '(choice (const "libc++")
6673                  (const :tag "GNU libstdc++" "libstdc++")
6674                  (string :tag "Library name"))
6675   :safe #'stringp
6676   :package-version '(flycheck . "0.15"))
6677
6678 (flycheck-def-option-var flycheck-clang-warnings '("all" "extra") c/c++-clang
6679   "A list of additional warnings to enable in Clang.
6680
6681 The value of this variable is a list of strings, where each string
6682 is the name of a warning category to enable.  By default, all
6683 recommended warnings and some extra warnings are enabled (as by
6684 `-Wall' and `-Wextra' respectively).
6685
6686 Refer to the Clang manual at URL
6687 `http://clang.llvm.org/docs/UsersManual.html' for more
6688 information about warnings."
6689   :type '(choice (const :tag "No additional warnings" nil)
6690                  (repeat :tag "Additional warnings"
6691                          (string :tag "Warning name")))
6692   :safe #'flycheck-string-list-p
6693   :package-version '(flycheck . "0.14"))
6694
6695 (defun flycheck-c/c++-quoted-include-directory ()
6696   "Get the directory for quoted includes.
6697
6698 C/C++ compiles typicall look up includes with quotation marks in
6699 the directory of the file being compiled.  However, since
6700 Flycheck uses temporary copies for syntax checking, it needs to
6701 explicitly determine the directory for quoted includes.
6702
6703 This function determines the directory by looking at function
6704 `buffer-file-name', or if that is nil, at `default-directory'."
6705   (-if-let (fn (buffer-file-name))
6706       (file-name-directory fn)
6707     ;; If the buffer has no file name, fall back to its default directory
6708     default-directory))
6709
6710 (flycheck-define-checker c/c++-clang
6711   "A C/C++ syntax checker using Clang.
6712
6713 See URL `http://clang.llvm.org/'."
6714   :command ("clang"
6715             "-fsyntax-only"
6716             "-fno-color-diagnostics"    ; Do not include color codes in output
6717             "-fno-caret-diagnostics"    ; Do not visually indicate the source
6718                                         ; location
6719             "-fno-diagnostics-show-option" ; Do not show the corresponding
6720                                         ; warning group
6721             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
6722             (option "-std=" flycheck-clang-language-standard concat)
6723             (option-flag "-pedantic" flycheck-clang-pedantic)
6724             (option-flag "-pedantic-errors" flycheck-clang-pedantic-errors)
6725             (option "-stdlib=" flycheck-clang-standard-library concat)
6726             (option-flag "-fms-extensions" flycheck-clang-ms-extensions)
6727             (option-flag "-fno-exceptions" flycheck-clang-no-exceptions)
6728             (option-flag "-fno-rtti" flycheck-clang-no-rtti)
6729             (option-flag "-fblocks" flycheck-clang-blocks)
6730             (option-list "-include" flycheck-clang-includes)
6731             (option-list "-W" flycheck-clang-warnings concat)
6732             (option-list "-D" flycheck-clang-definitions concat)
6733             (option-list "-I" flycheck-clang-include-path)
6734             (eval flycheck-clang-args)
6735             "-x" (eval
6736                   (pcase major-mode
6737                     (`c++-mode "c++")
6738                     (`c-mode "c")))
6739             ;; Read from standard input
6740             "-")
6741   :standard-input t
6742   :error-patterns
6743   ((info line-start (or "<stdin>" (file-name)) ":" line ":" column
6744          ": note: " (optional (message)) line-end)
6745    (warning line-start (or "<stdin>" (file-name)) ":" line ":" column
6746             ": warning: " (optional (message)) line-end)
6747    (error line-start (or "<stdin>" (file-name)) ":" line ":" column
6748           ": " (or "fatal error" "error") ": " (optional (message)) line-end))
6749   :error-filter
6750   (lambda (errors)
6751     (let ((errors (flycheck-sanitize-errors errors)))
6752       (dolist (err errors)
6753         ;; Clang will output empty messages for #error/#warning pragmas without
6754         ;; messages.  We fill these empty errors with a dummy message to get
6755         ;; them past our error filtering
6756         (setf (flycheck-error-message err)
6757               (or (flycheck-error-message err) "no message")))
6758       errors))
6759   :modes (c-mode c++-mode)
6760   :next-checkers ((warning . c/c++-cppcheck)))
6761
6762 (flycheck-def-args-var flycheck-gcc-args c/c++-gcc
6763   :package-version '(flycheck . "0.22"))
6764
6765 (flycheck-def-option-var flycheck-gcc-definitions nil c/c++-gcc
6766   "Additional preprocessor definitions for GCC.
6767
6768 The value of this variable is a list of strings, where each
6769 string is an additional definition to pass to GCC, via the `-D'
6770 option."
6771   :type '(repeat (string :tag "Definition"))
6772   :safe #'flycheck-string-list-p
6773   :package-version '(flycheck . "0.20"))
6774
6775 (flycheck-def-option-var flycheck-gcc-include-path nil c/c++-gcc
6776   "A list of include directories for GCC.
6777
6778 The value of this variable is a list of strings, where each
6779 string is a directory to add to the include path of gcc.
6780 Relative paths are relative to the file being checked."
6781   :type '(repeat (directory :tag "Include directory"))
6782   :safe #'flycheck-string-list-p
6783   :package-version '(flycheck . "0.20"))
6784
6785 (flycheck-def-option-var flycheck-gcc-includes nil c/c++-gcc
6786   "A list of additional include files for GCC.
6787
6788 The value of this variable is a list of strings, where each
6789 string is a file to include before syntax checking.  Relative
6790 paths are relative to the file being checked."
6791   :type '(repeat (file :tag "Include file"))
6792   :safe #'flycheck-string-list-p
6793   :package-version '(flycheck . "0.20"))
6794
6795 (flycheck-def-option-var flycheck-gcc-language-standard nil c/c++-gcc
6796   "The language standard to use in GCC.
6797
6798 The value of this variable is either a string denoting a language
6799 standard, or nil, to use the default standard.  When non-nil,
6800 pass the language standard via the `-std' option."
6801   :type '(choice (const :tag "Default standard" nil)
6802                  (string :tag "Language standard"))
6803   :safe #'stringp
6804   :package-version '(flycheck . "0.20"))
6805 (make-variable-buffer-local 'flycheck-gcc-language-standard)
6806
6807 (flycheck-def-option-var flycheck-gcc-no-exceptions nil c/c++-gcc
6808   "Whether to disable exceptions in GCC.
6809
6810 When non-nil, disable exceptions for syntax checks, via
6811 `-fno-exceptions'."
6812   :type 'boolean
6813   :safe #'booleanp
6814   :package-version '(flycheck . "0.20"))
6815
6816 (flycheck-def-option-var flycheck-gcc-no-rtti nil c/c++-gcc
6817   "Whether to disable RTTI in GCC.
6818
6819 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
6820   :type 'boolean
6821   :safe #'booleanp
6822   :package-version '(flycheck . "0.20"))
6823
6824 (flycheck-def-option-var flycheck-gcc-openmp nil c/c++-gcc
6825   "Whether to enable OpenMP in GCC.
6826
6827 When non-nil, enable OpenMP for syntax checkers, via
6828 `-fopenmp'."
6829   :type 'boolean
6830   :safe #'booleanp
6831   :package-version '(flycheck . "0.21"))
6832
6833 (flycheck-def-option-var flycheck-gcc-pedantic nil c/c++-gcc
6834   "Whether to warn about language extensions in GCC.
6835
6836 For ISO C, follows the version specified by any -std option used.
6837 When non-nil, disable non-ISO extensions to C/C++ via
6838 `-pedantic'."
6839   :type 'boolean
6840   :safe #'booleanp
6841   :package-version '(flycheck . "0.23"))
6842
6843 (flycheck-def-option-var flycheck-gcc-pedantic-errors nil c/c++-gcc
6844   "Whether to error on language extensions in GCC.
6845
6846 For ISO C, follows the version specified by any -std option used.
6847 When non-nil, disable non-ISO extensions to C/C++ via
6848 `-pedantic-errors'."
6849   :type 'boolean
6850   :safe #'booleanp
6851   :package-version '(flycheck . "0.23"))
6852
6853 (flycheck-def-option-var flycheck-gcc-warnings '("all" "extra") c/c++-gcc
6854   "A list of additional warnings to enable in GCC.
6855
6856 The value of this variable is a list of strings, where each string
6857 is the name of a warning category to enable.  By default, all
6858 recommended warnings and some extra warnings are enabled (as by
6859 `-Wall' and `-Wextra' respectively).
6860
6861 Refer to the gcc manual at URL
6862 `https://gcc.gnu.org/onlinedocs/gcc/' for more information about
6863 warnings."
6864   :type '(choice (const :tag "No additional warnings" nil)
6865                  (repeat :tag "Additional warnings"
6866                          (string :tag "Warning name")))
6867   :safe #'flycheck-string-list-p
6868   :package-version '(flycheck . "0.20"))
6869
6870 (flycheck-define-checker c/c++-gcc
6871   "A C/C++ syntax checker using GCC.
6872
6873 Requires GCC 4.4 or newer.  See URL `https://gcc.gnu.org/'."
6874   :command ("gcc"
6875             "-fshow-column"
6876             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
6877             (option "-std=" flycheck-gcc-language-standard concat)
6878             (option-flag "-pedantic" flycheck-gcc-pedantic)
6879             (option-flag "-pedantic-errors" flycheck-gcc-pedantic-errors)
6880             (option-flag "-fno-exceptions" flycheck-gcc-no-exceptions)
6881             (option-flag "-fno-rtti" flycheck-gcc-no-rtti)
6882             (option-flag "-fopenmp" flycheck-gcc-openmp)
6883             (option-list "-include" flycheck-gcc-includes)
6884             (option-list "-W" flycheck-gcc-warnings concat)
6885             (option-list "-D" flycheck-gcc-definitions concat)
6886             (option-list "-I" flycheck-gcc-include-path)
6887             (eval flycheck-gcc-args)
6888             "-x" (eval
6889                   (pcase major-mode
6890                     (`c++-mode "c++")
6891                     (`c-mode "c")))
6892             ;; GCC performs full checking only when actually compiling, so
6893             ;; `-fsyntax-only' is not enough. Just let it generate assembly
6894             ;; code.
6895             "-S" "-o" null-device
6896             ;; Read from standard input
6897             "-")
6898   :standard-input t
6899   :error-patterns
6900   ((info line-start (or "<stdin>" (file-name)) ":" line ":" column
6901          ": note: " (message) line-end)
6902    (warning line-start (or "<stdin>" (file-name)) ":" line ":" column
6903             ": warning: " (message (one-or-more (not (any "\n["))))
6904             (optional "[" (id (one-or-more not-newline)) "]") line-end)
6905    (error line-start (or "<stdin>" (file-name)) ":" line ":" column
6906           ": " (or "fatal error" "error") ": " (message) line-end))
6907   :modes (c-mode c++-mode)
6908   :next-checkers ((warning . c/c++-cppcheck)))
6909
6910 (flycheck-def-option-var flycheck-cppcheck-checks '("style") c/c++-cppcheck
6911   "Enabled checks for Cppcheck.
6912
6913 The value of this variable is a list of strings, where each
6914 string is the name of an additional check to enable.  By default,
6915 all coding style checks are enabled.
6916
6917 See section \"Enable message\" in the Cppcheck manual at URL
6918 `http://cppcheck.sourceforge.net/manual.pdf', and the
6919 documentation of the `--enable' option for more information,
6920 including a list of supported checks."
6921   :type '(repeat :tag "Additional checks"
6922                  (string :tag "Check name"))
6923   :safe #'flycheck-string-list-p
6924   :package-version '(flycheck . "0.14"))
6925
6926 (flycheck-def-option-var flycheck-cppcheck-standards nil c/c++-cppcheck
6927   "The standards to use in cppcheck.
6928
6929 The value of this variable is either a list of strings denoting
6930 the standards to use, or nil to pass nothing to cppcheck.  When
6931 non-nil, pass the standards via one or more `--std=' options."
6932   :type '(choice (const :tag "Default" nil)
6933                  (repeat :tag "Custom standards"
6934                          (string :tag "Standard name")))
6935   :safe #'flycheck-string-list-p
6936   :package-version '(flycheck . "28"))
6937 (make-variable-buffer-local 'flycheck-cppcheck-standards)
6938
6939 (flycheck-def-option-var flycheck-cppcheck-suppressions-file nil c/c++-cppcheck
6940   "The suppressions file to use in cppcheck.
6941
6942 The value of this variable is a file with the suppressions to
6943 use, or nil to pass nothing to cppcheck.  When non-nil, pass the
6944 suppressions file via the `--suppressions-list=' option."
6945   :type '(choice (const :tag "Default" nil)
6946                  (file :tag "Suppressions file"))
6947   :safe #'stringp
6948   :package-version '(flycheck . "32"))
6949 (make-variable-buffer-local 'flycheck-cppcheck-suppressions-file)
6950
6951 (flycheck-def-option-var flycheck-cppcheck-suppressions nil c/c++-cppcheck
6952   "The suppressions to use in cppcheck.
6953
6954 The value of this variable is either a list of strings denoting
6955 the suppressions to use, or nil to pass nothing to cppcheck.
6956 When non-nil, pass the suppressions via one or more `--suppress='
6957 options."
6958   :type '(choice (const :tag "Default" nil)
6959                  (repeat :tag "Additional suppressions"
6960                          (string :tag "Suppression")))
6961   :safe #'flycheck-string-list-p
6962   :package-version '(flycheck . "28"))
6963
6964 (flycheck-def-option-var flycheck-cppcheck-inconclusive nil c/c++-cppcheck
6965   "Whether to enable Cppcheck inconclusive checks.
6966
6967 When non-nil, enable Cppcheck inconclusive checks.  This allows Cppcheck to
6968 report warnings it's not certain of, but it may result in false positives.
6969
6970 This will have no effect when using Cppcheck 1.53 and older."
6971   :type 'boolean
6972   :safe #'booleanp
6973   :package-version '(flycheck . "0.19"))
6974
6975 (flycheck-def-option-var flycheck-cppcheck-include-path nil c/c++-cppcheck
6976   "A list of include directories for cppcheck.
6977
6978 The value of this variable is a list of strings, where each
6979 string is a directory to add to the include path of cppcheck.
6980 Relative paths are relative to the file being checked."
6981   :type '(repeat (directory :tag "Include directory"))
6982   :safe #'flycheck-string-list-p
6983   :package-version '(flycheck . "0.24"))
6984
6985 (flycheck-define-checker c/c++-cppcheck
6986   "A C/C++ checker using cppcheck.
6987
6988 See URL `http://cppcheck.sourceforge.net/'."
6989   :command ("cppcheck" "--quiet" "--xml-version=2" "--inline-suppr"
6990             (option "--enable=" flycheck-cppcheck-checks concat
6991                     flycheck-option-comma-separated-list)
6992             (option-flag "--inconclusive" flycheck-cppcheck-inconclusive)
6993             (option-list "-I" flycheck-cppcheck-include-path)
6994             (option-list "--std=" flycheck-cppcheck-standards concat)
6995             (option-list "--suppress=" flycheck-cppcheck-suppressions concat)
6996             (option "--suppressions-list="
6997                     flycheck-cppcheck-suppressions-file concat)
6998             "-x" (eval
6999                   (pcase major-mode
7000                     (`c++-mode "c++")
7001                     (`c-mode "c")))
7002             source)
7003   :error-parser flycheck-parse-cppcheck
7004   :modes (c-mode c++-mode))
7005
7006 (flycheck-define-checker cfengine
7007   "A CFEngine syntax checker using cf-promises.
7008
7009 See URL `https://cfengine.com/'."
7010   :command ("cf-promises" "-Wall" "-f"
7011             ;; We must stay in the same directory to resolve @include
7012             source-inplace)
7013   :error-patterns
7014   ((warning line-start (file-name) ":" line ":" column
7015             ": warning: " (message) line-end)
7016    (error line-start (file-name) ":" line ":" column
7017           ": error: " (message) line-end))
7018   :modes (cfengine-mode cfengine3-mode))
7019
7020 (flycheck-def-option-var flycheck-foodcritic-tags nil chef-foodcritic
7021   "A list of tags to select for Foodcritic.
7022
7023 The value of this variable is a list of strings where each string
7024 is a tag expression describing Foodcritic rules to enable or
7025 disable, via the `--tags' option.  To disable a tag, prefix it
7026 with `~'."
7027   :type '(repeat :tag "Tags" (string :tag "Tag expression"))
7028   :safe #'flycheck-string-list-p
7029   :package-version '(flycheck . "0.23"))
7030
7031 (flycheck-define-checker chef-foodcritic
7032   "A Chef cookbooks syntax checker using Foodcritic.
7033
7034 See URL `http://www.foodcritic.io'."
7035   ;; Use `source-inplace' to allow resource discovery with relative paths.
7036   ;; foodcritic interprets these as relative to the source file, so we need to
7037   ;; stay within the source tree.  See
7038   ;; https://github.com/flycheck/flycheck/pull/556
7039   :command ("foodcritic"
7040             (option-list "--tags" flycheck-foodcritic-tags)
7041             source-inplace)
7042   :error-patterns
7043   ((error line-start (id (one-or-more alnum)) ": "
7044           (message) ": " (file-name) ":" line line-end))
7045   :modes (enh-ruby-mode ruby-mode)
7046   :predicate
7047   (lambda ()
7048     (let ((parent-dir (file-name-directory
7049                        (directory-file-name
7050                         (expand-file-name default-directory)))))
7051       (or
7052        ;; Chef CookBook
7053        ;; http://docs.opscode.com/chef/knife.html#id38
7054        (locate-dominating-file parent-dir "recipes")
7055        ;; Knife Solo
7056        ;; http://matschaffer.github.io/knife-solo/#label-Init+command
7057        (locate-dominating-file parent-dir "cookbooks")))))
7058
7059 (flycheck-define-checker coffee
7060   "A CoffeeScript syntax checker using coffee.
7061
7062 See URL `https://coffeescript.org/'."
7063   ;; --print suppresses generation of compiled .js files
7064   :command ("coffee" "--compile" "--print" "--stdio")
7065   :standard-input t
7066   :error-patterns
7067   ((error line-start "[stdin]:" line ":" column
7068           ": error: " (message) line-end))
7069   :modes coffee-mode
7070   :next-checkers ((warning . coffee-coffeelint)))
7071
7072 (flycheck-def-config-file-var flycheck-coffeelintrc coffee-coffeelint
7073                               ".coffeelint.json"
7074   :safe #'stringp)
7075
7076 (flycheck-define-checker coffee-coffeelint
7077   "A CoffeeScript style checker using coffeelint.
7078
7079 See URL `http://www.coffeelint.org/'."
7080   :command
7081   ("coffeelint"
7082    (config-file "--file" flycheck-coffeelintrc)
7083    "--stdin" "--reporter" "checkstyle")
7084   :standard-input t
7085   :error-parser flycheck-parse-checkstyle
7086   :error-filter (lambda (errors)
7087                   (flycheck-remove-error-file-names
7088                    "stdin" (flycheck-remove-error-ids
7089                             (flycheck-sanitize-errors errors))))
7090   :modes coffee-mode)
7091
7092 (flycheck-define-checker coq
7093   "A Coq syntax checker using the Coq compiler.
7094
7095 See URL `https://coq.inria.fr/'."
7096   ;; We use coqtop in batch mode, because coqc is picky about file names.
7097   :command ("coqtop" "-batch" "-load-vernac-source" source)
7098   :error-patterns
7099   ((error line-start "File \"" (file-name) "\", line " line
7100           ;; TODO: Parse the end column, once Flycheck supports that
7101           ", characters " column "-" (one-or-more digit) ":\n"
7102           (or "Syntax error:" "Error:")
7103           ;; Most Coq error messages span multiple lines, and end with a dot.
7104           ;; There are simple one-line messages, too, though.
7105           (message (or (and (one-or-more (or not-newline "\n")) ".")
7106                        (one-or-more not-newline)))
7107           line-end))
7108   :error-filter
7109   (lambda (errors)
7110     (dolist (err (flycheck-sanitize-errors errors))
7111       (setf (flycheck-error-message err)
7112             (replace-regexp-in-string (rx (1+ (syntax whitespace)) line-end)
7113                                       "" (flycheck-error-message err)
7114                                       'fixedcase 'literal)))
7115     (flycheck-increment-error-columns errors))
7116   :modes coq-mode)
7117
7118 (flycheck-define-checker css-csslint
7119   "A CSS syntax and style checker using csslint.
7120
7121 See URL `https://github.com/CSSLint/csslint'."
7122   :command ("csslint" "--format=checkstyle-xml" source)
7123   :error-parser flycheck-parse-checkstyle
7124   :error-filter flycheck-dequalify-error-ids
7125   :modes css-mode)
7126
7127 (defconst flycheck-stylelint-args '("--formatter" "json")
7128   "Common arguments to stylelint invocations.")
7129
7130 (flycheck-def-config-file-var flycheck-stylelintrc
7131     (css-stylelint scss-stylelint less-stylelint) nil
7132   :safe #'stringp)
7133
7134 (flycheck-def-option-var flycheck-stylelint-quiet
7135     nil (css-stylelint scss-stylelint less-stylelint)
7136   "Whether to run stylelint in quiet mode.
7137
7138 When non-nil, enable quiet mode, via `--quiet'."
7139   :type 'boolean
7140   :safe #'booleanp
7141   :package-version '(flycheck . 26))
7142
7143 (defconst flycheck-stylelint-error-re
7144   (flycheck-rx-to-string
7145    '(: line-start (id (one-or-more word)) ": " (message) line-end)))
7146
7147 (defun flycheck-parse-stylelint (output checker buffer)
7148   "Parse stylelint errors from OUTPUT.
7149
7150 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
7151 the BUFFER that was checked respectively.
7152
7153 The CHECKER usually returns the errors as JSON.
7154
7155 If the CHECKER throws an Error it returns an Error message with a stacktrace."
7156   (condition-case nil
7157       (flycheck-parse-stylelint-json output checker buffer)
7158
7159     ;; The output could not be parsed as JSON
7160     (json-error
7161
7162      ;; Extract a flycheck error from the output (with a regular expression)
7163      ;; For match-string 4/5 see flycheck-rx-message/flycheck-rx-id
7164      (when (string-match flycheck-stylelint-error-re output)
7165        (list (flycheck-error-new-at
7166               1 nil 'error
7167               (match-string 4 output)
7168               :id (match-string 5 output)
7169               :checker checker
7170               :buffer buffer
7171               :filename (buffer-file-name buffer)))))))
7172
7173 (defun flycheck-parse-stylelint-json (output checker buffer)
7174   "Parse stylelint JSON errors from OUTPUT.
7175
7176 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
7177 the BUFFER that was checked respectively.
7178
7179 See URL `http://stylelint.io/developer-guide/formatters/' for information
7180 about the JSON format of stylelint."
7181   (let ((json-object-type 'plist))
7182
7183     ;; stylelint returns a vector of result objects
7184     ;; Since we only passed one file, the first element is enough
7185     (let* ((stylelint-output (elt (json-read-from-string output) 0))
7186            (filename (buffer-file-name buffer))
7187
7188            ;; Turn all deprecations into warnings
7189            (deprecations
7190             (mapcar (lambda (d)
7191                       (flycheck-error-new-at
7192                        1 nil 'warning
7193                        (plist-get d :text)
7194                        :id "Deprecation Warning"
7195                        :checker checker
7196                        :buffer buffer
7197                        :filename filename))
7198                     (plist-get stylelint-output :deprecations)))
7199
7200            ;; Turn all invalid options into errors
7201            (invalid-options
7202             (mapcar (lambda (io)
7203                       (flycheck-error-new-at
7204                        1 nil 'error
7205                        (plist-get io :text)
7206                        :id "Invalid Option"
7207                        :checker checker
7208                        :buffer buffer
7209                        :filename filename))
7210                     (plist-get stylelint-output :invalidOptionWarnings)))
7211
7212            ;; Read all linting warnings
7213            (warnings
7214             (mapcar (lambda (w)
7215                       (flycheck-error-new-at
7216                        (plist-get w :line) (plist-get w :column)
7217                        (pcase (plist-get w :severity)
7218                          (`"error"   'error)
7219                          (`"warning" 'warning)
7220                          ;; Default to info for unknown .severity
7221                          (_          'info))
7222                        (plist-get w :text)
7223                        :id (plist-get w :rule)
7224                        :checker checker
7225                        :buffer buffer
7226                        :filename filename))
7227                     (plist-get stylelint-output :warnings))))
7228
7229       ;; Return the combined errors (deprecations, invalid options, warnings)
7230       (append deprecations invalid-options warnings))))
7231
7232 (flycheck-define-checker css-stylelint
7233   "A CSS syntax and style checker using stylelint.
7234
7235 See URL `http://stylelint.io/'."
7236   :command ("stylelint"
7237             (eval flycheck-stylelint-args)
7238             (option-flag "--quiet" flycheck-stylelint-quiet)
7239             (config-file "--config" flycheck-stylelintrc))
7240   :standard-input t
7241   :error-parser flycheck-parse-stylelint
7242   :modes (css-mode))
7243
7244 (flycheck-def-option-var flycheck-cuda-language-standard nil cuda-nvcc
7245   "Our CUDA Language Standard."
7246   :type '(choice (const :tag "Default standard" nil)
7247                  (string :tag "Language standard"))
7248   :safe #'stringp
7249   :package-version '(flycheck . "32"))
7250 (make-variable-buffer-local 'flycheck-cuda-language-standard)
7251
7252 (flycheck-def-option-var flycheck-cuda-includes nil cuda-nvcc
7253   "Our include directories to pass to nvcc."
7254   :type '(repeat (file :tag "Include file"))
7255   :safe #'flycheck-string-list-p
7256   :package-version '(flycheck . "32"))
7257
7258 (flycheck-def-option-var flycheck-cuda-definitions nil cuda-nvcc
7259   "Additional preprocessor definitions for nvcc.
7260 A list of strings to pass to cuda, a la flycheck-clang"
7261   :type '(repeat (string :tag "Definitions"))
7262   :safe #'flycheck-string-list-p
7263   :package-version '(flycheck . "32"))
7264
7265 (flycheck-def-option-var flycheck-cuda-include-path nil cuda-nvcc
7266   "A list of include directories for nvcc."
7267   :type '(repeat (directory :tag "Include directory"))
7268   :safe #'flycheck-string-list-p
7269   :package-version '(flycheck . "32"))
7270
7271 (flycheck-define-checker cuda-nvcc
7272   "A CUDA C/C++ syntax checker using nvcc.
7273
7274 See URL `https://developer.nvidia.com/cuda-llvm-compiler'."
7275   :command ("nvcc"
7276             "-c" ;; Compile Only
7277             (option "-std=" flycheck-cuda-language-standard concat)
7278             (option-list "-include" flycheck-cuda-includes)
7279             (option-list "-D" flycheck-cuda-definitions concat)
7280             (option-list "-I" flycheck-cuda-include-path)
7281             source)
7282   :error-patterns
7283   ((error line-start
7284           (message "In file included from")
7285           " " (or "<stdin>" (file-name))
7286           ":" line ":" line-end)
7287    (error line-start (or "<stdin>" (file-name))
7288           "(" line "): error: " (message) line-end)
7289    (error line-start (or "<stdin>" (file-name))
7290           ":" line ":" column
7291           ": fatal error: " (optional (message)) line-end)
7292    (warning line-start (or "<stdin>" (file-name))
7293             "(" line "): warning: " (message) line-end))
7294   :modes cuda-mode)
7295
7296
7297 (flycheck-def-option-var flycheck-cwl-schema-path nil cwl
7298   "A path for the schema file for Common Workflow Language.
7299
7300 The value of this variable is a string that denotes a path for
7301 the schema file of Common Workflow Language."
7302   :type 'string
7303   :safe #'stringp)
7304
7305 (flycheck-define-checker cwl
7306   "A CWL syntax checker using Schema Salad validator.
7307
7308 Requires Schema Salad 2.6.20171101113912 or newer.
7309 See URL `https://www.commonwl.org/v1.0/SchemaSalad.html'."
7310   :command ("schema-salad-tool"
7311             "--quiet"
7312             "--print-oneline"
7313             (eval flycheck-cwl-schema-path)
7314             source-inplace)
7315   :error-patterns
7316   ((error line-start
7317           (file-name) ":" line ":" column ":" (zero-or-more blank)
7318           (message (one-or-more not-newline))
7319           line-end))
7320   :modes cwl-mode)
7321
7322 (defconst flycheck-d-module-re
7323   (rx "module" (one-or-more (syntax whitespace))
7324       (group (one-or-more (not (syntax whitespace))))
7325       (zero-or-more (syntax whitespace))
7326       ";")
7327   "Regular expression to match a D module declaration.")
7328
7329 (defun flycheck-d-base-directory ()
7330   "Get the relative base directory path for this module."
7331   (let* ((file-name (buffer-file-name))
7332          (module-file (if (string= (file-name-nondirectory file-name)
7333                                    "package.d")
7334                           (directory-file-name (file-name-directory file-name))
7335                         file-name)))
7336     (flycheck-module-root-directory
7337      (flycheck-find-in-buffer flycheck-d-module-re)
7338      module-file)))
7339
7340 (flycheck-def-option-var flycheck-dmd-include-path nil d-dmd
7341   "A list of include directories for dmd.
7342
7343 The value of this variable is a list of strings, where each
7344 string is a directory to add to the include path of dmd.
7345 Relative paths are relative to the file being checked."
7346   :type '(repeat (directory :tag "Include directory"))
7347   :safe #'flycheck-string-list-p
7348   :package-version '(flycheck . "0.18"))
7349
7350 (flycheck-def-args-var flycheck-dmd-args d-dmd
7351   :package-version '(flycheck . "0.24"))
7352
7353 (flycheck-define-checker d-dmd
7354   "A D syntax checker using the DMD compiler.
7355
7356 Requires DMD 2.066 or newer.  See URL `https://dlang.org/'."
7357   :command ("dmd"
7358             "-debug"                    ; Compile in debug mode
7359             "-o-"                       ; Don't generate an object file
7360             "-vcolumns"                 ; Add columns in output
7361             "-wi" ; Compilation will continue even if there are warnings
7362             (eval (concat "-I" (flycheck-d-base-directory)))
7363             (option-list "-I" flycheck-dmd-include-path concat)
7364             (eval flycheck-dmd-args)
7365             source)
7366   :error-patterns
7367   ((error line-start
7368           (file-name) "(" line "," column "): Error: " (message)
7369           line-end)
7370    (warning line-start (file-name) "(" line "," column "): "
7371             (or "Warning" "Deprecation") ": " (message) line-end)
7372    (info line-start (file-name) "(" line "," column "): "
7373          (one-or-more " ") (message) line-end))
7374   :modes d-mode)
7375
7376 (flycheck-define-checker dockerfile-hadolint
7377   "A Dockerfile syntax checker using the hadolint.
7378
7379 See URL `http://github.com/hadolint/hadolint/'."
7380   :command ("hadolint" "-")
7381   :standard-input t
7382   :error-patterns
7383   ((error line-start
7384           (file-name) ":" line ":" column " " (message)
7385           line-end)
7386    (warning line-start
7387             (file-name) ":" line " " (id (one-or-more alnum)) " " (message)
7388             line-end))
7389   :error-filter
7390   (lambda (errors)
7391     (flycheck-sanitize-errors
7392      (flycheck-remove-error-file-names "/dev/stdin" errors)))
7393   :modes dockerfile-mode)
7394
7395 (defconst flycheck-this-emacs-executable
7396   (concat invocation-directory invocation-name)
7397   "The path to the currently running Emacs executable.")
7398
7399 (defconst flycheck-emacs-args '("-Q" "--batch")
7400   "Common arguments to Emacs invocations.")
7401
7402 (defmacro flycheck-prepare-emacs-lisp-form (&rest body)
7403   "Prepare BODY for use as check form in a subprocess."
7404   (declare (indent 0))
7405   `(flycheck-sexp-to-string
7406     '(progn
7407        (defvar jka-compr-inhibit)
7408        (unwind-protect
7409            ;; Flycheck inhibits compression of temporary files, thus we
7410            ;; must not attempt to decompress.
7411            (let ((jka-compr-inhibit t))
7412              ;; Strip option-argument separator from arguments, if present
7413              (when (equal (car command-line-args-left) "--")
7414                (setq command-line-args-left (cdr command-line-args-left)))
7415              ,@body)
7416          ;; Prevent Emacs from processing the arguments on its own, see
7417          ;; https://github.com/flycheck/flycheck/issues/319
7418          (setq command-line-args-left nil)))))
7419
7420 (defconst flycheck-emacs-lisp-check-form
7421   (flycheck-prepare-emacs-lisp-form
7422     ;; Keep track of the generated bytecode files, to delete them after byte
7423     ;; compilation.
7424     (defvar flycheck-byte-compiled-files nil)
7425     (let ((byte-compile-dest-file-function
7426            (lambda (source)
7427              (let ((temp-file (make-temp-file (file-name-nondirectory source))))
7428                (push temp-file flycheck-byte-compiled-files)
7429                temp-file))))
7430       (unwind-protect
7431           (byte-compile-file (car command-line-args-left))
7432         (mapc (lambda (f) (ignore-errors (delete-file f)))
7433               flycheck-byte-compiled-files))
7434       (when (bound-and-true-p flycheck-emacs-lisp-check-declare)
7435         (check-declare-file (car command-line-args-left))))))
7436
7437 (flycheck-def-option-var flycheck-emacs-lisp-load-path nil emacs-lisp
7438   "Load path to use in the Emacs Lisp syntax checker.
7439
7440 When set to `inherit', use the `load-path' of the current Emacs
7441 session during syntax checking.
7442
7443 When set to a list of strings, add each directory in this list to
7444 the `load-path' before invoking the byte compiler.  Relative
7445 paths in this list are expanded against the `default-directory'
7446 of the buffer to check.
7447
7448 When nil, do not explicitly set the `load-path' during syntax
7449 checking.  The syntax check only uses the built-in `load-path' of
7450 Emacs in this case.
7451
7452 Note that changing this variable can lead to wrong results of the
7453 syntax check, e.g. if an unexpected version of a required library
7454 is used."
7455   :type '(choice (const :tag "Inherit current `load-path'" inherit)
7456                  (repeat :tag "Load path" directory))
7457   :risky t
7458   :package-version '(flycheck . "0.14"))
7459
7460 (flycheck-def-option-var flycheck-emacs-lisp-initialize-packages
7461     'auto emacs-lisp
7462   "Whether to initialize packages in the Emacs Lisp syntax checker.
7463
7464 When nil, never initialize packages.  When `auto', initialize
7465 packages only when checking `user-init-file' or files from
7466 `user-emacs-directory'.  For any other non-nil value, always
7467 initialize packages.
7468
7469 When initializing packages is enabled the `emacs-lisp' syntax
7470 checker calls `package-initialize' before byte-compiling the file
7471 to be checked.  It also sets `package-user-dir' according to
7472 `flycheck-emacs-lisp-package-user-dir'."
7473   :type '(choice (const :tag "Do not initialize packages" nil)
7474                  (const :tag "Initialize packages for configuration only" auto)
7475                  (const :tag "Always initialize packages" t))
7476   :risky t
7477   :package-version '(flycheck . "0.14"))
7478
7479 (defconst flycheck-emacs-lisp-package-initialize-form
7480   (flycheck-sexp-to-string
7481    '(with-demoted-errors "Error during package initialization: %S"
7482       (package-initialize)))
7483   "Form used to initialize packages.")
7484
7485 (defun flycheck-option-emacs-lisp-package-initialize (value)
7486   "Option VALUE filter for `flycheck-emacs-lisp-initialize-packages'."
7487   (let ((shall-initialize
7488          (if (eq value 'auto)
7489              (or (flycheck-in-user-emacs-directory-p (buffer-file-name))
7490                  ;; `user-init-file' is nil in non-interactive sessions.  Now,
7491                  ;; no user would possibly use Flycheck in a non-interactive
7492                  ;; session, but our unit tests run non-interactively, so we
7493                  ;; have to handle this case anyway
7494                  (and user-init-file
7495                       (flycheck-same-files-p (buffer-file-name)
7496                                              user-init-file)))
7497            value)))
7498     (when shall-initialize
7499       ;; If packages shall be initialized, return the corresponding form,
7500       ;; otherwise make Flycheck ignore the option by returning nil.
7501       flycheck-emacs-lisp-package-initialize-form)))
7502
7503 (flycheck-def-option-var flycheck-emacs-lisp-package-user-dir nil emacs-lisp
7504   "Package directory for the Emacs Lisp syntax checker.
7505
7506 If set to a string set `package-user-dir' to the value of this
7507 variable before initializing packages. If set to nil just inherit
7508 the value of `package-user-dir' from the running Emacs session.
7509
7510 This variable has no effect, if
7511 `flycheck-emacs-lisp-initialize-packages' is nil."
7512   :type '(choice (const :tag "Default package directory" nil)
7513                  (directory :tag "Custom package directory"))
7514   :risky t
7515   :package-version '(flycheck . "0.14"))
7516
7517 (defun flycheck-option-emacs-lisp-package-user-dir (value)
7518   "Option VALUE filter for `flycheck-emacs-lisp-package-user-dir'."
7519   ;; Inherit the package directory from our Emacs session
7520   (let ((value (or value (bound-and-true-p package-user-dir))))
7521     (when value
7522       (flycheck-sexp-to-string `(setq package-user-dir ,value)))))
7523
7524 (flycheck-def-option-var flycheck-emacs-lisp-check-declare nil emacs-lisp
7525   "If non-nil, check ‘declare-function’ forms using ‘check-declare-file’."
7526   :type '(choice (const :tag "Do not check declare forms" nil)
7527                  (const :tag "Check declare forms" t))
7528   :risky t
7529   :package-version '(flycheck . "31"))
7530
7531 (defun flycheck-option-emacs-lisp-check-declare (value)
7532   "Option VALUE filter for `flycheck-emacs-lisp-check-declare'."
7533   (when value
7534     (flycheck-sexp-to-string
7535      `(progn
7536         (defvar flycheck-emacs-lisp-check-declare)
7537         (setq flycheck-emacs-lisp-check-declare ,value)))))
7538
7539 (flycheck-define-checker emacs-lisp
7540   "An Emacs Lisp syntax checker using the Emacs Lisp Byte compiler.
7541
7542 See Info Node `(elisp)Byte Compilation'."
7543   :command ("emacs" (eval flycheck-emacs-args)
7544             (eval
7545              (let ((path (pcase flycheck-emacs-lisp-load-path
7546                            (`inherit load-path)
7547                            (p (seq-map #'expand-file-name p)))))
7548                (flycheck-prepend-with-option "--directory" path)))
7549             (option "--eval" flycheck-emacs-lisp-package-user-dir nil
7550                     flycheck-option-emacs-lisp-package-user-dir)
7551             (option "--eval" flycheck-emacs-lisp-initialize-packages nil
7552                     flycheck-option-emacs-lisp-package-initialize)
7553             (option "--eval" flycheck-emacs-lisp-check-declare nil
7554                     flycheck-option-emacs-lisp-check-declare)
7555             "--eval" (eval flycheck-emacs-lisp-check-form)
7556             "--"
7557             source-inplace)
7558   :error-patterns
7559   ((error line-start (file-name) ":" line ":" column ":Error:"
7560           (message (zero-or-more not-newline)
7561                    (zero-or-more "\n    " (zero-or-more not-newline)))
7562           line-end)
7563    (warning line-start (file-name) ":" line ":" column ":Warning:"
7564             (message (zero-or-more not-newline)
7565                      (zero-or-more "\n    " (zero-or-more not-newline)))
7566             line-end)
7567    (warning line-start (file-name) ":" line (optional ":" column)
7568             ":Warning (check-declare): said\n"
7569             (message (zero-or-more "    " (zero-or-more not-newline))
7570                      (zero-or-more "\n    " (zero-or-more not-newline)))
7571             line-end)
7572    ;; The following is for Emacs 24 ‘check-declare-file’, which uses a
7573    ;; less informative format.
7574    (warning line-start "Warning (check-declare): " (file-name) " said "
7575             (message (zero-or-more not-newline))
7576             line-end))
7577   :error-filter
7578   (lambda (errors)
7579     (flycheck-fill-empty-line-numbers
7580      (flycheck-collapse-error-message-whitespace
7581       (flycheck-sanitize-errors errors))))
7582   :modes (emacs-lisp-mode lisp-interaction-mode)
7583   :predicate
7584   (lambda ()
7585     (and
7586      ;; Ensure that we only check buffers with a backing file.  For buffers
7587      ;; without a backing file we cannot guarantee that file names in error
7588      ;; messages are properly resolved, because `byte-compile-file' emits file
7589      ;; names *relative to the directory of the checked file* instead of the
7590      ;; working directory.  Hence our backwards-substitution will fail, because
7591      ;; the checker process has a different base directory to resolve relative
7592      ;; file names than the Flycheck code working on the buffer to check.
7593      (buffer-file-name)
7594      ;; Do not check buffers which should not be byte-compiled.  The checker
7595      ;; process will refuse to compile these, which would confuse Flycheck
7596      (not (bound-and-true-p no-byte-compile))
7597      ;; Do not check buffers used for autoloads generation during package
7598      ;; installation.  These buffers are too short-lived for being checked, and
7599      ;; doing so causes spurious errors.  See
7600      ;; https://github.com/flycheck/flycheck/issues/45 and
7601      ;; https://github.com/bbatsov/prelude/issues/248.  We must also not check
7602      ;; compilation buffers, but as these are ephemeral, Flycheck won't check
7603      ;; them anyway.
7604      (not (flycheck-autoloads-file-p))))
7605   :next-checkers (emacs-lisp-checkdoc))
7606
7607 (defconst flycheck-emacs-lisp-checkdoc-form
7608   (flycheck-prepare-emacs-lisp-form
7609     (unless (require 'elisp-mode nil 'no-error)
7610       ;; TODO: Fallback for Emacs 24, remove when dropping support for 24
7611       (require 'lisp-mode))
7612     (require 'checkdoc)
7613
7614     (let ((source (car command-line-args-left))
7615           ;; Remember the default directory of the process
7616           (process-default-directory default-directory))
7617       ;; Note that we deliberately use our custom approach even despite of
7618       ;; `checkdoc-file' which was added to Emacs 25.1.  While it's conceptually
7619       ;; the better thing, its implementation has too many flaws to be of use
7620       ;; for us.
7621       (with-temp-buffer
7622         (insert-file-contents source 'visit)
7623         (setq buffer-file-name source)
7624         ;; And change back to the process default directory to make file-name
7625         ;; back-substutition work
7626         (setq default-directory process-default-directory)
7627         (with-demoted-errors "Error in checkdoc: %S"
7628           ;; Checkdoc needs the Emacs Lisp syntax table and comment syntax to
7629           ;; parse sexps and identify docstrings correctly; see
7630           ;; https://github.com/flycheck/flycheck/issues/833
7631           (delay-mode-hooks (emacs-lisp-mode))
7632           (setq delayed-mode-hooks nil)
7633           (checkdoc-current-buffer t)
7634           (with-current-buffer checkdoc-diagnostic-buffer
7635             (princ (buffer-substring-no-properties (point-min) (point-max)))
7636             (kill-buffer)))))))
7637
7638 (defconst flycheck-emacs-lisp-checkdoc-variables
7639   '(checkdoc-symbol-words
7640     checkdoc-arguments-in-order-flag
7641     checkdoc-force-history-flag
7642     checkdoc-permit-comma-termination-flag
7643     checkdoc-force-docstrings-flag
7644     checkdoc-package-keywords-flag
7645     checkdoc-spellcheck-documentation-flag
7646     checkdoc-verb-check-experimental-flag
7647     checkdoc-max-keyref-before-warn
7648     sentence-end-double-space)
7649   "Variables inherited by the checkdoc subprocess.")
7650
7651 (defun flycheck-emacs-lisp-checkdoc-variables-form ()
7652   "Make a sexp to pass relevant variables to a checkdoc subprocess.
7653
7654 Variables are taken from `flycheck-emacs-lisp-checkdoc-variables'."
7655   `(progn
7656      ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt)))
7657                 (seq-filter #'boundp flycheck-emacs-lisp-checkdoc-variables))))
7658
7659 (flycheck-define-checker emacs-lisp-checkdoc
7660   "An Emacs Lisp style checker using CheckDoc.
7661
7662 The checker runs `checkdoc-current-buffer'."
7663   :command ("emacs" (eval flycheck-emacs-args)
7664             "--eval" (eval (flycheck-sexp-to-string
7665                             (flycheck-emacs-lisp-checkdoc-variables-form)))
7666             "--eval" (eval flycheck-emacs-lisp-checkdoc-form)
7667             "--" source)
7668   :error-patterns
7669   ((warning line-start (file-name) ":" line ": " (message) line-end))
7670   :modes (emacs-lisp-mode)
7671   :predicate
7672   (lambda ()
7673     ;; Do not check Autoloads, Cask/Carton and dir-locals files.  These files
7674     ;; really don't need to follow Checkdoc conventions.
7675     (not (or (flycheck-autoloads-file-p)
7676              (and (buffer-file-name)
7677                   (member (file-name-nondirectory (buffer-file-name))
7678                           '("Cask" "Carton" ".dir-locals.el")))))))
7679
7680 (dolist (checker '(emacs-lisp emacs-lisp-checkdoc))
7681   (setf (car (flycheck-checker-get checker 'command))
7682         flycheck-this-emacs-executable))
7683
7684 (flycheck-def-option-var flycheck-erlang-include-path nil erlang
7685   "A list of include directories for Erlang.
7686
7687 The value of this variable is a list of strings, where each
7688 string is a directory to add to the include path of erlc.
7689 Relative paths are relative to the file being checked."
7690   :type '(repeat (directory :tag "Include directory"))
7691   :safe #'flycheck-string-list-p
7692   :package-version '(flycheck . "0.24"))
7693
7694 (flycheck-def-option-var flycheck-erlang-library-path nil erlang
7695   "A list of library directories for Erlang.
7696
7697 The value of this variable is a list of strings, where each
7698 string is a directory to add to the library path of erlc.
7699 Relative paths are relative to the file being checked."
7700   :type '(repeat (directory :tag "Library directory"))
7701   :safe #'flycheck-string-list-p
7702   :package-version '(flycheck . "0.24"))
7703
7704 (flycheck-define-checker erlang
7705   "An Erlang syntax checker using the Erlang interpreter.
7706
7707 See URL `http://www.erlang.org/'."
7708   :command ("erlc"
7709             "-o" temporary-directory
7710             (option-list "-I" flycheck-erlang-include-path)
7711             (option-list "-pa" flycheck-erlang-library-path)
7712             "-Wall"
7713             source)
7714   :error-patterns
7715   ((warning line-start (file-name) ":" line ": Warning:" (message) line-end)
7716    (error line-start (file-name) ":" line ": " (message) line-end))
7717   :modes erlang-mode
7718   :enabled (lambda () (string-suffix-p ".erl" (buffer-file-name))))
7719
7720 (defun contains-rebar-config (dir-name)
7721   "Return DIR-NAME if DIR-NAME/rebar.config exists, nil otherwise."
7722   (when (file-exists-p (expand-file-name "rebar.config" dir-name))
7723     dir-name))
7724
7725 (defun locate-rebar3-project-root (file-name &optional prev-file-name acc)
7726   "Find the top-most rebar project root for source FILE-NAME.
7727
7728 A project root directory is any directory containing a
7729 rebar.config file.  Find the top-most directory to move out of any
7730 nested dependencies.
7731
7732 FILE-NAME is a source file for which to find the project.
7733
7734 PREV-FILE-NAME helps us prevent infinite looping
7735
7736 ACC is an accumulator that keeps the list of results, the first
7737 non-nil of which will be our project root.
7738
7739 Return the absolute path to the directory"
7740   (if (string= file-name prev-file-name)
7741       (car (remove nil acc))
7742     (let ((current-dir (file-name-directory file-name)))
7743       (locate-rebar3-project-root
7744        (directory-file-name current-dir)
7745        file-name
7746        (cons (contains-rebar-config current-dir) acc)))))
7747
7748 (defun flycheck-rebar3-project-root (&optional _checker)
7749   "Return directory where rebar.config is located."
7750   (locate-rebar3-project-root buffer-file-name))
7751
7752 (flycheck-def-option-var flycheck-erlang-rebar3-profile nil erlang-rebar3
7753   "The rebar3 profile to use.
7754
7755 The profile used when compiling, if VALUE is nil \"test\" will be used
7756 when the file is located in test directory, otherwise \"default\" will be
7757 used as profile."
7758   :type 'string
7759   :safe #'stringp
7760   :package-version '(flycheck . "32"))
7761
7762 (defun flycheck-erlang-rebar3-get-profile ()
7763   "Return rebar3 profile.
7764
7765 Use flycheck-erlang-rebar3-profile if set, otherwise use test profile if
7766 dirname is test or else default."
7767   (cond
7768    (flycheck-erlang-rebar3-profile flycheck-erlang-rebar3-profile)
7769    ((and buffer-file-name
7770          (string= "test"
7771                   (file-name-base
7772                    (directory-file-name
7773                     (file-name-directory buffer-file-name)))))
7774     "test")
7775    (t "default")))
7776
7777 (flycheck-define-checker erlang-rebar3
7778   "An Erlang syntax checker using the rebar3 build tool."
7779   :command ("rebar3" "as" (eval (flycheck-erlang-rebar3-get-profile)) "compile")
7780   :error-parser
7781   (lambda (output checker buffer)
7782     ;; rebar3 outputs ANSI terminal colors, which don't match up with
7783     ;; :error-patterns, so we strip those color codes from the output
7784     ;; here before passing it along to the default behavior. The
7785     ;; relevant discussion can be found at
7786     ;; https://github.com/flycheck/flycheck/pull/1144
7787     (require 'ansi-color)
7788     (flycheck-parse-with-patterns
7789      (and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output))
7790      checker buffer))
7791   :error-patterns
7792   ((warning line-start
7793             (file-name) ":" line ": Warning:" (message) line-end)
7794    (error line-start
7795           (file-name) ":" line ": " (message) line-end))
7796   :modes erlang-mode
7797   :enabled flycheck-rebar3-project-root
7798   :predicate flycheck-buffer-saved-p
7799   :working-directory flycheck-rebar3-project-root)
7800
7801 (flycheck-define-checker eruby-erubis
7802   "An eRuby syntax checker using the `erubis' command.
7803
7804 See URL `http://www.kuwata-lab.com/erubis/'."
7805   :command ("erubis" "-z" source)
7806   :error-patterns
7807   ((error line-start (file-name) ":" line ": " (message) line-end))
7808   :modes (html-erb-mode rhtml-mode))
7809
7810 (flycheck-def-args-var flycheck-gfortran-args fortran-gfortran
7811   :package-version '(flycheck . "0.22"))
7812
7813 (flycheck-def-option-var flycheck-gfortran-include-path nil fortran-gfortran
7814   "A list of include directories for GCC Fortran.
7815
7816 The value of this variable is a list of strings, where each
7817 string is a directory to add to the include path of gcc.
7818 Relative paths are relative to the file being checked."
7819   :type '(repeat (directory :tag "Include directory"))
7820   :safe #'flycheck-string-list-p
7821   :package-version '(flycheck . "0.20"))
7822
7823 (flycheck-def-option-var flycheck-gfortran-language-standard "f95"
7824                          fortran-gfortran
7825   "The language standard to use in GFortran.
7826
7827 The value of this variable is either a string denoting a language
7828 standard, or nil, to use the default standard.  When non-nil,
7829 pass the language standard via the `-std' option."
7830   :type '(choice (const :tag "Default standard" nil)
7831                  (string :tag "Language standard"))
7832   :safe #'stringp
7833   :package-version '(flycheck . "0.20"))
7834
7835 (flycheck-def-option-var flycheck-gfortran-layout nil fortran-gfortran
7836   "The source code layout to use in GFortran.
7837
7838 The value of this variable is one of the following symbols:
7839
7840 nil
7841      Let gfortran determine the layout from the extension
7842
7843 `free'
7844      Use free form layout
7845
7846
7847 `fixed'
7848      Use fixed form layout
7849
7850 In any other case, an error is signaled."
7851   :type '(choice (const :tag "Guess layout from extension" nil)
7852                  (const :tag "Free form layout" free)
7853                  (const :tag "Fixed form layout" fixed))
7854   :safe (lambda (value) (or (not value) (memq value '(free fixed))))
7855   :package-version '(flycheck . "0.20"))
7856
7857 (defun flycheck-option-gfortran-layout (value)
7858   "Option VALUE filter for `flycheck-gfortran-layout'."
7859   (pcase value
7860     (`nil nil)
7861     (`free "free-form")
7862     (`fixed "fixed-form")
7863     (_ (error "Invalid value for flycheck-gfortran-layout: %S" value))))
7864
7865 (flycheck-def-option-var flycheck-gfortran-warnings '("all" "extra")
7866                          fortran-gfortran
7867   "A list of warnings for GCC Fortran.
7868
7869 The value of this variable is a list of strings, where each string
7870 is the name of a warning category to enable.  By default, all
7871 recommended warnings and some extra warnings are enabled (as by
7872 `-Wall' and `-Wextra' respectively).
7873
7874 Refer to the gfortran manual at URL
7875 `https://gcc.gnu.org/onlinedocs/gfortran/' for more information
7876 about warnings"
7877   :type '(choice (const :tag "No additional warnings" nil)
7878                  (repeat :tag "Additional warnings"
7879                          (string :tag "Warning name")))
7880   :safe #'flycheck-string-list-p
7881   :package-version '(flycheck . "0.20"))
7882
7883 (flycheck-define-checker fortran-gfortran
7884   "An Fortran syntax checker using GCC.
7885
7886 Uses GCC's Fortran compiler gfortran.  See URL
7887 `https://gcc.gnu.org/onlinedocs/gfortran/'."
7888   :command ("gfortran"
7889             "-fsyntax-only"
7890             "-fshow-column"
7891             ;; Do not visually indicate the source location
7892             "-fno-diagnostics-show-caret"
7893             ;; Do not show the corresponding warning group
7894             "-fno-diagnostics-show-option"
7895             ;; Fortran has similar include processing as C/C++
7896             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
7897             (option "-std=" flycheck-gfortran-language-standard concat)
7898             (option "-f" flycheck-gfortran-layout concat
7899                     flycheck-option-gfortran-layout)
7900             (option-list "-W" flycheck-gfortran-warnings concat)
7901             (option-list "-I" flycheck-gfortran-include-path concat)
7902             (eval flycheck-gfortran-args)
7903             source)
7904   :error-patterns
7905   ((error line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
7906           (or (= 3 (zero-or-more not-newline) "\n") "")
7907           (or "Error" "Fatal Error") ": "
7908           (message) line-end)
7909    (warning line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
7910             (or (= 3 (zero-or-more not-newline) "\n") "")
7911             "Warning: " (message) line-end))
7912   :modes (fortran-mode f90-mode))
7913
7914 (flycheck-define-checker go-gofmt
7915   "A Go syntax and style checker using the gofmt utility.
7916
7917 See URL `https://golang.org/cmd/gofmt/'."
7918   :command ("gofmt")
7919   :standard-input t
7920   :error-patterns
7921   ((error line-start "<standard input>:" line ":" column ": "
7922           (message) line-end))
7923   :modes go-mode
7924   :next-checkers ((warning . go-golint)
7925                   ;; Fall back, if go-golint doesn't exist
7926                   (warning . go-vet)
7927                   ;; Fall back, if go-vet doesn't exist
7928                   (warning . go-build) (warning . go-test)
7929                   (warning . go-errcheck)
7930                   (warning . go-unconvert)
7931                   (warning . go-staticcheck)
7932                   (warning . go-megacheck)))
7933
7934 (flycheck-define-checker go-golint
7935   "A Go style checker using Golint.
7936
7937 See URL `https://github.com/golang/lint'."
7938   :command ("golint" source)
7939   :error-patterns
7940   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
7941   :modes go-mode
7942   :next-checkers (go-vet
7943                   ;; Fall back, if go-vet doesn't exist
7944                   go-build go-test go-errcheck go-unconvert go-megacheck))
7945
7946 (flycheck-def-option-var flycheck-go-vet-print-functions nil go-vet
7947   "A list of print-like functions for `go vet'.
7948
7949 Go vet will check these functions for format string problems and
7950 issues, such as a mismatch between the number of formats used,
7951 and the number of arguments given.
7952
7953 Each entry is in the form Name:N where N is the zero-based
7954 argument position of the first argument involved in the print:
7955 either the format or the first print argument for non-formatted
7956 prints.  For example, if you have Warn and Warnf functions that
7957 take an io.Writer as their first argument, like Fprintf,
7958 -printfuncs=Warn:1,Warnf:1 "
7959   :type '(repeat :tag "print-like functions"
7960                  (string :tag "function"))
7961   :safe #'flycheck-string-list-p)
7962
7963 (flycheck-def-option-var flycheck-go-megacheck-disabled-checkers nil
7964                          go-megacheck
7965   "A list of checkers to disable when running `megacheck'.
7966
7967 The value of this variable is a list of strings, where each
7968 string is a checker to be disabled. Valid checkers are `simple',
7969 `staticcheck' and `unused'. When nil, all checkers will be
7970 enabled. "
7971   :type '(set (const :tag "Disable simple" "simple")
7972               (const :tag "Disable staticcheck" "staticcheck")
7973               (const :tag "Disable unused" "unused"))
7974   :safe #'flycheck-string-list-p)
7975
7976 (flycheck-define-checker go-vet
7977   "A Go syntax checker using the `go vet' command.
7978
7979 See URL `https://golang.org/cmd/go/' and URL
7980 `https://golang.org/cmd/vet/'."
7981   :command ("go" "vet"
7982             (option "-printf.funcs=" flycheck-go-vet-print-functions concat
7983                     flycheck-option-comma-separated-list)
7984             source)
7985   :error-patterns
7986   ((warning line-start (file-name) ":" line ": " (message) line-end))
7987   :modes go-mode
7988   :next-checkers (go-build
7989                   go-test
7990                   ;; Fall back if `go build' or `go test' can be used
7991                   go-errcheck
7992                   go-unconvert
7993                   go-staticcheck
7994                   go-megacheck)
7995   :verify (lambda (_)
7996             (let* ((go (flycheck-checker-executable 'go-vet))
7997                    (have-vet (member "vet" (ignore-errors
7998                                              (process-lines go "tool")))))
7999               (list
8000                (flycheck-verification-result-new
8001                 :label "go tool vet"
8002                 :message (if have-vet "present" "missing")
8003                 :face (if have-vet 'success '(bold error)))))))
8004
8005 (flycheck-def-option-var flycheck-go-build-install-deps nil (go-build go-test)
8006   "Whether to install dependencies in `go build' and `go test'.
8007
8008 If non-nil automatically install dependencies with `go build'
8009 while syntax checking."
8010   :type 'boolean
8011   :safe #'booleanp
8012   :package-version '(flycheck . "0.25"))
8013
8014 (flycheck-def-option-var flycheck-go-build-tags nil
8015                          (go-build go-test go-errcheck
8016                                    go-megacheck go-staticcheck)
8017   "A list of tags for `go build'.
8018
8019 Each item is a string with a tag to be given to `go build'."
8020   :type '(repeat (string :tag "Tag"))
8021   :safe #'flycheck-string-list-p
8022   :package-version '(flycheck . "0.25"))
8023
8024
8025 (flycheck-def-option-var flycheck-go-version nil go-staticcheck
8026   "The version of go that should be targeted by `staticcheck'.
8027
8028 Should be a string representing a version, like 1.6 or 1.11.4.
8029 See `https://staticcheck.io/docs/#targeting-go-versions' for
8030 details."
8031   :type 'string
8032   :safe #'stringp
8033   :package-version '(flycheck . "0.32"))
8034
8035 (flycheck-define-checker go-build
8036   "A Go syntax and type checker using the `go build' command.
8037
8038 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
8039   :command ("go" "build"
8040             (option-flag "-i" flycheck-go-build-install-deps)
8041             ;; multiple tags are listed as "dev debug ..."
8042             (option-list "-tags=" flycheck-go-build-tags concat)
8043             "-o" null-device)
8044   :error-patterns
8045   ((error line-start (file-name) ":" line ":"
8046           (optional column ":") " "
8047           (message (one-or-more not-newline)
8048                    (zero-or-more "\n\t" (one-or-more not-newline)))
8049           line-end)
8050    ;; Catch error message about multiple packages in a directory, which doesn't
8051    ;; follow the standard error message format.
8052    (info line-start
8053          (message "can't load package: package "
8054                   (one-or-more (not (any ?: ?\n)))
8055                   ": found packages "
8056                   (one-or-more not-newline))
8057          line-end))
8058   :error-filter
8059   (lambda (errors)
8060     (dolist (error errors)
8061       (unless (flycheck-error-line error)
8062         ;; Flycheck ignores errors without line numbers, but the error
8063         ;; message about multiple packages in a directory doesn't come with a
8064         ;; line number, so inject a fake one.
8065         (setf (flycheck-error-line error) 1)))
8066     errors)
8067   :modes go-mode
8068   :predicate (lambda ()
8069                (and (flycheck-buffer-saved-p)
8070                     (not (string-suffix-p "_test.go" (buffer-file-name)))))
8071   :next-checkers ((warning . go-errcheck)
8072                   (warning . go-unconvert)
8073                   (warning . go-staticcheck)
8074                   (warning . go-megacheck)))
8075
8076 (flycheck-define-checker go-test
8077   "A Go syntax and type checker using the `go test' command.
8078
8079 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
8080   :command ("go" "test"
8081             (option-flag "-i" flycheck-go-build-install-deps)
8082             (option-list "-tags=" flycheck-go-build-tags concat)
8083             "-c" "-o" null-device)
8084   :error-patterns
8085   ((error line-start (file-name) ":" line ":"
8086           (optional column ":") " "
8087           (message (one-or-more not-newline)
8088                    (zero-or-more "\n\t" (one-or-more not-newline)))
8089           line-end))
8090   :modes go-mode
8091   :predicate
8092   (lambda () (and (flycheck-buffer-saved-p)
8093                   (string-suffix-p "_test.go" (buffer-file-name))))
8094   :next-checkers ((warning . go-errcheck)
8095                   (warning . go-unconvert)
8096                   (warning . go-staticcheck)
8097                   (warning . go-megacheck)))
8098
8099 (flycheck-define-checker go-errcheck
8100   "A Go checker for unchecked errors.
8101
8102 Requires errcheck newer than commit 8515d34 (Aug 28th, 2015).
8103
8104 See URL `https://github.com/kisielk/errcheck'."
8105   :command ("errcheck"
8106             "-abspath"
8107             (option-list "-tags=" flycheck-go-build-tags concat)
8108             ".")
8109   :error-patterns
8110   ((warning line-start
8111             (file-name) ":" line ":" column (or (one-or-more "\t") ": " ":\t")
8112             (message)
8113             line-end))
8114   :error-filter
8115   (lambda (errors)
8116     (let ((errors (flycheck-sanitize-errors errors)))
8117       (dolist (err errors)
8118         (-when-let (message (flycheck-error-message err))
8119           ;; Improve the messages reported by errcheck to make them more clear.
8120           (setf (flycheck-error-message err)
8121                 (format "Ignored `error` returned from `%s`" message)))))
8122     errors)
8123   :modes go-mode
8124   :predicate (lambda () (flycheck-buffer-saved-p))
8125   :next-checkers ((warning . go-unconvert)
8126                   (warning . go-staticcheck)
8127                   (warning . go-megacheck)))
8128
8129 (flycheck-define-checker go-unconvert
8130   "A Go checker looking for unnecessary type conversions.
8131
8132 See URL `https://github.com/mdempsky/unconvert'."
8133   :command ("unconvert" ".")
8134   :error-patterns
8135   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
8136   :modes go-mode
8137   :predicate (lambda () (flycheck-buffer-saved-p))
8138   :next-checkers ((warning . go-megacheck)))
8139
8140 (flycheck-define-checker go-megacheck
8141   "A Go checker that performs static analysis and linting using the `megacheck'
8142 command.
8143
8144 Requires Go 1.6 or newer. See URL
8145 `https://github.com/dominikh/go-tools'."
8146   :command ("megacheck"
8147             (option-list "-tags=" flycheck-go-build-tags concat)
8148             (eval (mapcar (lambda (checker) (concat "-" checker
8149                                                     ".enabled=false"))
8150                           flycheck-go-megacheck-disabled-checkers))
8151             ;; Run in current directory to make megacheck aware of symbols
8152             ;; declared in other files.
8153             ".")
8154   :error-patterns
8155   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
8156   :modes go-mode)
8157
8158 (flycheck-define-checker go-staticcheck
8159   "A Go checker that performs static analysis and linting using
8160 the `staticcheck' command. `staticcheck' is the successor to
8161 `megacheck'; while the latter isn't fully deprecated yet, it's
8162 recommended to migrate to `staticcheck'.
8163
8164 `staticcheck' is explicitly fully compatible with \"the last two
8165 versions of go\". `staticheck' can target earlier versions (with
8166 limited features) if `flycheck-go-version' is set. See URL
8167 `https://staticcheck.io/'."
8168   :command ("staticcheck" "-f" "json"
8169             (option-list "-tags" flycheck-go-build-tags concat)
8170             (option "-go" flycheck-go-version))
8171
8172   :error-parser flycheck-parse-go-staticcheck
8173   :modes go-mode)
8174
8175 (flycheck-define-checker groovy
8176   "A groovy syntax checker using groovy compiler API.
8177
8178 See URL `http://www.groovy-lang.org'."
8179   :command ("groovy" "-e"
8180             "import org.codehaus.groovy.control.*
8181
8182 unit = new CompilationUnit()
8183 unit.addSource(\"input\", System.in)
8184
8185 try {
8186     unit.compile(Phases.CONVERSION)
8187 } catch (MultipleCompilationErrorsException e) {
8188     e.errorCollector.write(new PrintWriter(System.out, true), null)
8189 }")
8190   :standard-input t
8191   :error-patterns
8192   ((error line-start "input: " line ":" (message)
8193           " @ line " line ", column " column "." line-end))
8194   :modes groovy-mode)
8195
8196 (flycheck-define-checker haml
8197   "A Haml syntax checker using the Haml compiler.
8198
8199 See URL `http://haml.info'."
8200   :command ("haml" "-c" "--stdin")
8201   :standard-input t
8202   :error-patterns
8203   ((error line-start "Syntax error on line " line ": " (message) line-end)
8204    (error line-start ":" line ": syntax error, " (message) line-end))
8205   :modes haml-mode)
8206
8207 (flycheck-define-checker handlebars
8208   "A Handlebars syntax checker using the Handlebars compiler.
8209
8210 See URL `http://handlebarsjs.com/'."
8211   :command ("handlebars" "-i-")
8212   :standard-input t
8213   :error-patterns
8214   ((error line-start
8215           "Error: Parse error on line " line ":" (optional "\r") "\n"
8216           (zero-or-more not-newline) "\n" (zero-or-more not-newline) "\n"
8217           (message) line-end))
8218   :modes (handlebars-mode handlebars-sgml-mode web-mode)
8219   :predicate
8220   (lambda ()
8221     (if (eq major-mode 'web-mode)
8222         ;; Check if this is a handlebars file since web-mode does not store the
8223         ;; non-canonical engine name
8224         (let* ((regexp-alist (bound-and-true-p web-mode-engine-file-regexps))
8225                (pattern (cdr (assoc "handlebars" regexp-alist))))
8226           (and pattern (buffer-file-name)
8227                (string-match-p pattern (buffer-file-name))))
8228       t)))
8229
8230 (defconst flycheck-haskell-module-re
8231   (rx line-start (zero-or-more (or "\n" (any space)))
8232       "module" (one-or-more (or "\n" (any space)))
8233       (group (one-or-more (not (any space "(" "\n")))))
8234   "Regular expression for a Haskell module name.")
8235
8236 (flycheck-def-args-var flycheck-ghc-args (haskell-stack-ghc haskell-ghc)
8237   :package-version '(flycheck . "0.22"))
8238
8239 (flycheck-def-option-var flycheck-ghc-stack-use-nix nil haskell-stack-ghc
8240   "Whether to enable nix support in stack.
8241
8242 When non-nil, stack will append '--nix' flag to any call."
8243   :type 'boolean
8244   :safe #'booleanp
8245   :package-version '(flycheck . "26"))
8246
8247 (flycheck-def-option-var flycheck-ghc-stack-project-file nil haskell-stack-ghc
8248   "Override project stack.yaml file.
8249
8250 The value of this variable is a file path that refers to a yaml
8251 file for the current stack project. Relative file paths are
8252 resolved against the checker's working directory. When non-nil,
8253 stack will get overridden value via `--stack-yaml'."
8254   :type 'string
8255   :safe #'stringp
8256   :package-version '(flycheck . "32"))
8257
8258 (flycheck-def-option-var flycheck-ghc-no-user-package-database nil haskell-ghc
8259   "Whether to disable the user package database in GHC.
8260
8261 When non-nil, disable the user package database in GHC, via
8262 `-no-user-package-db'."
8263   :type 'boolean
8264   :safe #'booleanp
8265   :package-version '(flycheck . "0.16"))
8266
8267 (flycheck-def-option-var flycheck-ghc-package-databases nil haskell-ghc
8268   "Additional module databases for GHC.
8269
8270 The value of this variable is a list of strings, where each
8271 string is a directory of a package database.  Each package
8272 database is given to GHC via `-package-db'."
8273   :type '(repeat (directory :tag "Package database"))
8274   :safe #'flycheck-string-list-p
8275   :package-version '(flycheck . "0.16"))
8276
8277 (flycheck-def-option-var flycheck-ghc-search-path nil
8278                          (haskell-stack-ghc haskell-ghc)
8279   "Module search path for (Stack) GHC.
8280
8281 The value of this variable is a list of strings, where each
8282 string is a directory containing Haskell modules.  Each directory
8283 is added to the GHC search path via `-i'."
8284   :type '(repeat (directory :tag "Module directory"))
8285   :safe #'flycheck-string-list-p
8286   :package-version '(flycheck . "0.16"))
8287
8288 (flycheck-def-option-var flycheck-ghc-language-extensions nil
8289                          (haskell-stack-ghc haskell-ghc)
8290   "Language extensions for (Stack) GHC.
8291
8292 The value of this variable is a list of strings, where each
8293 string is a Haskell language extension, as in the LANGUAGE
8294 pragma.  Each extension is enabled via `-X'."
8295   :type '(repeat (string :tag "Language extension"))
8296   :safe #'flycheck-string-list-p
8297   :package-version '(flycheck . "0.19"))
8298
8299 (defvar flycheck-haskell-ghc-cache-directory nil
8300   "The cache directory for `ghc' output.")
8301
8302 (defun flycheck-haskell-ghc-cache-directory ()
8303   "Get the cache location for `ghc' output.
8304
8305 If no cache directory exists yet, create one and return it.
8306 Otherwise return the previously used cache directory."
8307   (setq flycheck-haskell-ghc-cache-directory
8308         (or flycheck-haskell-ghc-cache-directory
8309             (make-temp-file "flycheck-haskell-ghc-cache" 'directory))))
8310
8311 (defun flycheck--locate-dominating-file-matching (directory regexp)
8312   "Search for a file in directory hierarchy starting at DIRECTORY.
8313
8314 Look up the directory hierarchy from DIRECTORY for a directory
8315 containing a file that matches REGEXP."
8316   (locate-dominating-file
8317    directory
8318    (lambda (dir)
8319      (directory-files dir nil regexp t))))
8320
8321 (defun flycheck-haskell--find-default-directory (checker)
8322   "Come up with a suitable default directory for Haskell to run CHECKER in.
8323
8324 In case of `haskell-stack-ghc' checker it is directory with
8325 stack.yaml file.  If there's no stack.yaml file in any parent
8326 directory, it will be the directory that \"stack path --project-root\"
8327 command returns.
8328
8329 For all other checkers, it is the closest parent directory that
8330 contains a cabal file."
8331   (pcase checker
8332     (`haskell-stack-ghc
8333      (or
8334       (when (buffer-file-name)
8335         (flycheck--locate-dominating-file-matching
8336          (file-name-directory (buffer-file-name))
8337          "stack.*\\.yaml\\'"))
8338       (-when-let* ((stack (funcall flycheck-executable-find "stack"))
8339                    (output (ignore-errors
8340                              (process-lines stack
8341                                             "--no-install-ghc"
8342                                             "path" "--project-root")))
8343                    (stack-dir (car output)))
8344         (and (file-directory-p stack-dir) stack-dir))))
8345     (_
8346      (when (buffer-file-name)
8347        (flycheck--locate-dominating-file-matching
8348         (file-name-directory (buffer-file-name))
8349         "\\.cabal\\'\\|\\`package\\.yaml\\'")))))
8350
8351 (flycheck-define-checker haskell-stack-ghc
8352   "A Haskell syntax and type checker using `stack ghc'.
8353
8354 See URL `https://github.com/commercialhaskell/stack'."
8355   :command ("stack"
8356             "--no-install-ghc"
8357             (option "--stack-yaml" flycheck-ghc-stack-project-file)
8358             (option-flag "--nix" flycheck-ghc-stack-use-nix)
8359             "ghc" "--" "-Wall" "-no-link"
8360             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
8361             (option-list "-X" flycheck-ghc-language-extensions concat)
8362             (option-list "-i" flycheck-ghc-search-path concat)
8363             (eval (concat
8364                    "-i"
8365                    (flycheck-module-root-directory
8366                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
8367             (eval flycheck-ghc-args)
8368             "-x" (eval
8369                   (pcase major-mode
8370                     (`haskell-mode "hs")
8371                     (`literate-haskell-mode "lhs")))
8372             source)
8373   :error-patterns
8374   ((warning line-start (file-name) ":" line ":" column ":"
8375             (or " " "\n    ") (in "Ww") "arning:"
8376             (optional " " "[" (id (one-or-more not-newline)) "]")
8377             (optional "\n")
8378             (message
8379              (one-or-more " ") (one-or-more not-newline)
8380              (zero-or-more "\n"
8381                            (one-or-more " ")
8382                            (one-or-more (not (any ?\n ?|)))))
8383             line-end)
8384    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
8385           (or (message (one-or-more not-newline))
8386               (and "\n"
8387                    (message
8388                     (one-or-more " ") (one-or-more not-newline)
8389                     (zero-or-more "\n"
8390                                   (one-or-more " ")
8391                                   (one-or-more (not (any ?\n ?|)))))))
8392           line-end))
8393   :error-filter
8394   (lambda (errors)
8395     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
8396   :modes (haskell-mode literate-haskell-mode)
8397   :next-checkers ((warning . haskell-hlint))
8398   :working-directory flycheck-haskell--find-default-directory)
8399
8400 (flycheck-define-checker haskell-ghc
8401   "A Haskell syntax and type checker using ghc.
8402
8403 See URL `https://www.haskell.org/ghc/'."
8404   :command ("ghc" "-Wall" "-no-link"
8405             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
8406             (option-flag "-no-user-package-db"
8407                          flycheck-ghc-no-user-package-database)
8408             (option-list "-package-db" flycheck-ghc-package-databases)
8409             (option-list "-i" flycheck-ghc-search-path concat)
8410             ;; Include the parent directory of the current module tree, to
8411             ;; properly resolve local imports
8412             (eval (concat
8413                    "-i"
8414                    (flycheck-module-root-directory
8415                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
8416             (option-list "-X" flycheck-ghc-language-extensions concat)
8417             (eval flycheck-ghc-args)
8418             "-x" (eval
8419                   (pcase major-mode
8420                     (`haskell-mode "hs")
8421                     (`literate-haskell-mode "lhs")))
8422             source)
8423   :error-patterns
8424   ((warning line-start (file-name) ":" line ":" column ":"
8425             (or " " "\n    ") (in "Ww") "arning:"
8426             (optional " " "[" (id (one-or-more not-newline)) "]")
8427             (optional "\n")
8428             (message
8429              (one-or-more " ") (one-or-more not-newline)
8430              (zero-or-more "\n"
8431                            (one-or-more " ")
8432                            (one-or-more (not (any ?\n ?|)))))
8433             line-end)
8434    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
8435           (or (message (one-or-more not-newline))
8436               (and "\n"
8437                    (message
8438                     (one-or-more " ") (one-or-more not-newline)
8439                     (zero-or-more "\n"
8440                                   (one-or-more " ")
8441                                   (one-or-more (not (any ?\n ?|)))))))
8442           line-end))
8443   :error-filter
8444   (lambda (errors)
8445     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
8446   :modes (haskell-mode literate-haskell-mode)
8447   :next-checkers ((warning . haskell-hlint))
8448   :working-directory flycheck-haskell--find-default-directory)
8449
8450 (flycheck-def-config-file-var flycheck-hlintrc haskell-hlint "HLint.hs"
8451   :safe #'stringp)
8452
8453 (flycheck-def-args-var flycheck-hlint-args haskell-hlint
8454   :package-version '(flycheck . "0.25"))
8455
8456 (flycheck-def-option-var flycheck-hlint-language-extensions
8457     nil haskell-hlint
8458   "Extensions list to enable for hlint.
8459
8460 The value of this variable is a list of strings, where each
8461 string is a name of extension to enable in
8462 hlint (e.g. \"QuasiQuotes\")."
8463   :type '(repeat :tag "Extensions" (string :tag "Extension"))
8464   :safe #'flycheck-string-list-p
8465   :package-version '(flycheck . "0.24"))
8466
8467 (flycheck-def-option-var flycheck-hlint-ignore-rules
8468     nil haskell-hlint
8469   "Ignore rules list for hlint checks.
8470
8471 The value of this variable is a list of strings, where each
8472 string is an ignore rule (e.g. \"Use fmap\")."
8473   :type '(repeat :tag "Ignore rules" (string :tag "Ignore rule"))
8474   :safe #'flycheck-string-list-p
8475   :package-version '(flycheck . "0.24"))
8476
8477 (flycheck-def-option-var flycheck-hlint-hint-packages
8478     nil haskell-hlint
8479   "Hint packages to include for hlint checks.
8480
8481 The value of this variable is a list of strings, where each
8482 string is a default hint package (e.g. (\"Generalise\"
8483 \"Default\" \"Dollar\"))."
8484   :type '(repeat :tag "Hint packages" (string :tag "Hint package"))
8485   :safe #'flycheck-string-list-p
8486   :package-version '(flycheck . "0.24"))
8487
8488 (flycheck-define-checker haskell-hlint
8489   "A Haskell style checker using hlint.
8490
8491 See URL `https://github.com/ndmitchell/hlint'."
8492   :command ("hlint"
8493             (option-list "-X" flycheck-hlint-language-extensions concat)
8494             (option-list "-i=" flycheck-hlint-ignore-rules concat)
8495             (option-list "-h" flycheck-hlint-hint-packages concat)
8496             (config-file "-h" flycheck-hlintrc)
8497             (eval flycheck-hlint-args)
8498             source-inplace)
8499   :error-patterns
8500   ((info line-start
8501          (file-name) ":" line ":" column
8502          ": Suggestion: "
8503          (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
8504          line-end)
8505    (warning line-start
8506             (file-name) ":" line ":" column
8507             ": Warning: "
8508             (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
8509             line-end)
8510    (error line-start
8511           (file-name) ":" line ":" column
8512           ": Error: "
8513           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
8514           line-end))
8515   :modes (haskell-mode literate-haskell-mode))
8516
8517 (flycheck-def-config-file-var flycheck-tidyrc html-tidy ".tidyrc"
8518   :safe #'stringp)
8519
8520 (flycheck-define-checker html-tidy
8521   "A HTML syntax and style checker using Tidy.
8522
8523 See URL `https://github.com/htacg/tidy-html5'."
8524   :command ("tidy" (config-file "-config" flycheck-tidyrc)
8525             "-lang" "en"
8526             "-e" "-q")
8527   :standard-input t
8528   :error-patterns
8529   ((error line-start
8530           "line " line
8531           " column " column
8532           " - Error: " (message) line-end)
8533    (warning line-start
8534             "line " line
8535             " column " column
8536             " - Warning: " (message) line-end))
8537   :modes (html-mode mhtml-mode nxhtml-mode))
8538
8539 (flycheck-def-config-file-var flycheck-jshintrc javascript-jshint ".jshintrc"
8540   :safe #'stringp)
8541
8542 (flycheck-def-option-var flycheck-jshint-extract-javascript nil
8543                          javascript-jshint
8544   "Whether jshint should extract Javascript from HTML.
8545
8546 If nil no extract rule is given to jshint.  If `auto' only
8547 extract Javascript if a HTML file is detected.  If `always' or
8548 `never' extract Javascript always or never respectively.
8549
8550 Refer to the jshint manual at the URL
8551 `http://jshint.com/docs/cli/#flags' for more information."
8552   :type
8553   '(choice (const :tag "No extraction rule" nil)
8554            (const :tag "Try to extract Javascript when detecting HTML files"
8555                   auto)
8556            (const :tag "Always try to extract Javascript" always)
8557            (const :tag "Never try to extract Javascript" never))
8558   :safe #'symbolp
8559   :package-version '(flycheck . "26"))
8560
8561 (flycheck-define-checker javascript-jshint
8562   "A Javascript syntax and style checker using jshint.
8563
8564 See URL `http://www.jshint.com'."
8565   :command ("jshint" "--reporter=checkstyle"
8566             "--filename" source-original
8567             (config-file "--config" flycheck-jshintrc)
8568             (option "--extract=" flycheck-jshint-extract-javascript
8569                     concat flycheck-option-symbol)
8570             "-")
8571   :standard-input t
8572   :error-parser flycheck-parse-checkstyle
8573   :error-filter
8574   (lambda (errors)
8575     (flycheck-remove-error-file-names
8576      "stdin" (flycheck-dequalify-error-ids errors)))
8577   :modes (js-mode js2-mode js3-mode rjsx-mode))
8578
8579 (flycheck-def-args-var flycheck-eslint-args javascript-eslint
8580   :package-version '(flycheck . "32"))
8581
8582 (flycheck-def-option-var flycheck-eslint-rules-directories nil javascript-eslint
8583   "A list of directories with custom rules for ESLint.
8584
8585 The value of this variable is a list of strings, where each
8586 string is a directory with custom rules for ESLint.
8587
8588 Refer to the ESLint manual at URL
8589 `http://eslint.org/docs/user-guide/command-line-interface#--rulesdir'
8590 for more information about the custom directories."
8591   :type '(repeat (directory :tag "Custom rules directory"))
8592   :safe #'flycheck-string-list-p
8593   :package-version '(flycheck . "29"))
8594
8595 (defun flycheck-eslint-config-exists-p ()
8596   "Whether there is a valid eslint config for the current buffer."
8597   (let* ((executable (flycheck-find-checker-executable 'javascript-eslint))
8598          (exitcode (and executable (call-process executable nil nil nil
8599                                                  "--print-config" "."))))
8600     (eq exitcode 0)))
8601
8602 (defun flycheck-parse-eslint (output checker buffer)
8603   "Parse ESLint errors/warnings from JSON OUTPUT.
8604
8605 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
8606 the BUFFER that was checked respectively.
8607
8608 See URL `https://eslint.org' for more information about ESLint."
8609   (mapcar (lambda (err)
8610             (let-alist err
8611               (flycheck-error-new-at
8612                .line
8613                .column
8614                (pcase .severity
8615                  (2 'error)
8616                  (1 'warning)
8617                  (_ 'warning))
8618                .message
8619                :id .ruleId
8620                :checker checker
8621                :buffer buffer
8622                :filename (buffer-file-name buffer))))
8623           (let-alist (caar (flycheck-parse-json output))
8624             .messages)))
8625
8626 (defun flycheck-eslint--find-working-directory (_checker)
8627   "Look for a working directory to run ESLint CHECKER in.
8628
8629 This will be the directory that contains the `node_modules'
8630 directory.  If no such directory is found in the directory
8631 hierarchy, it looks first for `.eslintignore' and then for
8632 `.eslintrc' files to detect the project root."
8633   (let* ((regex-config (concat "\\`\\.eslintrc"
8634                                "\\(\\.\\(js\\|ya?ml\\|json\\)\\)?\\'")))
8635     (when buffer-file-name
8636       (or (locate-dominating-file buffer-file-name "node_modules")
8637           (locate-dominating-file buffer-file-name ".eslintignore")
8638           (locate-dominating-file
8639            (file-name-directory buffer-file-name)
8640            (lambda (directory)
8641              (> (length (directory-files directory nil regex-config t)) 0)))))))
8642
8643 (flycheck-define-checker javascript-eslint
8644   "A Javascript syntax and style checker using eslint.
8645
8646 See URL `https://eslint.org/'."
8647   :command ("eslint" "--format=json"
8648             (option-list "--rulesdir" flycheck-eslint-rules-directories)
8649             (eval flycheck-eslint-args)
8650             "--stdin" "--stdin-filename" source-original)
8651   :standard-input t
8652   :error-parser flycheck-parse-eslint
8653   :enabled (lambda () (flycheck-eslint-config-exists-p))
8654   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode
8655                   typescript-mode)
8656   :working-directory flycheck-eslint--find-working-directory
8657   :verify
8658   (lambda (_)
8659     (let* ((default-directory
8660              (flycheck-compute-working-directory 'javascript-eslint))
8661            (have-config (flycheck-eslint-config-exists-p)))
8662       (list
8663        (flycheck-verification-result-new
8664         :label "config file"
8665         :message (if have-config "found" "missing or incorrect")
8666         :face (if have-config 'success '(bold error)))))))
8667
8668 (flycheck-define-checker javascript-standard
8669   "A Javascript code and style checker for the (Semi-)Standard Style.
8670
8671 This checker works with `standard' and `semistandard', defaulting
8672 to the former.  To use it with the latter, set
8673 `flycheck-javascript-standard-executable' to `semistandard'.
8674
8675 See URL `https://github.com/standard/standard' and URL
8676 `https://github.com/Flet/semistandard'."
8677   :command ("standard" "--stdin")
8678   :standard-input t
8679   :error-patterns
8680   ((error line-start "  <text>:" line ":" column ":" (message) line-end))
8681   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode))
8682
8683 (flycheck-define-checker json-jsonlint
8684   "A JSON syntax and style checker using jsonlint.
8685
8686 See URL `https://github.com/zaach/jsonlint'."
8687   ;; We can't use standard input for jsonlint, because it doesn't output errors
8688   ;; anymore when using -c -q with standard input :/
8689   :command ("jsonlint" "-c" "-q" source)
8690   :error-patterns
8691   ((error line-start
8692           (file-name)
8693           ": line " line
8694           ", col " column ", "
8695           (message) line-end))
8696   :error-filter
8697   (lambda (errors)
8698     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
8699   :modes json-mode)
8700
8701 (flycheck-define-checker json-python-json
8702   "A JSON syntax checker using Python json.tool module.
8703
8704 See URL `https://docs.python.org/3.5/library/json.html#command-line-interface'."
8705   :command ("python" "-m" "json.tool" source
8706             ;; Send the pretty-printed output to the null device
8707             null-device)
8708   :error-patterns
8709   ((error line-start
8710           (message) ": line " line " column " column
8711           ;; Ignore the rest of the line which shows the char position.
8712           (one-or-more not-newline)
8713           line-end))
8714   :modes json-mode
8715   ;; The JSON parser chokes if the buffer is empty and has no JSON inside
8716   :predicate (lambda () (not (flycheck-buffer-empty-p))))
8717
8718 (flycheck-define-checker json-jq
8719   "JSON checker using the jq tool.
8720
8721 This checker accepts multiple consecutive JSON values in a
8722 single input, which is useful for jsonlines data.
8723
8724 See URL `https://stedolan.github.io/jq/'."
8725   :command ("jq" "." source null-device)
8726   ;; Example error message:
8727   ;;   parse error: Expected another key-value pair at line 3, column 1
8728   :error-patterns
8729   ((error line-start
8730           (optional "parse error: ")
8731           (message) "at line " line ", column " column
8732           (zero-or-more not-newline) line-end))
8733   :modes json-mode)
8734
8735 (flycheck-define-checker jsonnet
8736   "A Jsonnet syntax checker using the jsonnet binary.
8737
8738 See URL `https://jsonnet.org'."
8739   :command ("jsonnet" source-inplace)
8740   :error-patterns
8741   ((error line-start "STATIC ERROR: " (file-name) ":" line ":" column
8742           (zero-or-one (group "-" (one-or-more digit))) ": "
8743           (message) line-end)
8744    (error line-start "RUNTIME ERROR: " (message) "\n"
8745           (one-or-more space) (file-name) ":" (zero-or-one "(")
8746           line ":" column (zero-or-more not-newline) line-end))
8747   :modes jsonnet-mode)
8748
8749 (flycheck-define-checker less
8750   "A LESS syntax checker using lessc.
8751
8752 Requires lessc 1.4 or newer.
8753
8754 See URL `http://lesscss.org'."
8755   :command ("lessc" "--lint" "--no-color"
8756             "-")
8757   :standard-input t
8758   :error-patterns
8759   ((error line-start (one-or-more word) ":"
8760           (message)
8761           " in - on line " line
8762           ", column " column ":"
8763           line-end))
8764   :modes less-css-mode)
8765
8766 (flycheck-define-checker less-stylelint
8767   "A LESS syntax and style checker using stylelint.
8768
8769 See URL `http://stylelint.io/'."
8770   :command ("stylelint"
8771             (eval flycheck-stylelint-args)
8772             "--syntax" "less"
8773             (option-flag "--quiet" flycheck-stylelint-quiet)
8774             (config-file "--config" flycheck-stylelintrc))
8775   :standard-input t
8776   :error-parser flycheck-parse-stylelint
8777   :modes (less-css-mode))
8778
8779 (flycheck-define-checker llvm-llc
8780   "Flycheck LLVM IR checker using llc.
8781
8782 See URL `http://llvm.org/docs/CommandGuide/llc.html'."
8783   :command ("llc" "-o" null-device source)
8784   :error-patterns
8785   ((error line-start
8786           ;; llc prints the executable path
8787           (zero-or-one (minimal-match (one-or-more not-newline)) ": ")
8788           (file-name) ":" line ":" column ": error: " (message)
8789           line-end))
8790   :error-filter
8791   (lambda (errors)
8792     ;; sanitize errors occurring in inline assembly
8793     (flycheck-sanitize-errors
8794      (flycheck-remove-error-file-names "<inline asm>" errors)))
8795   :modes llvm-mode)
8796
8797 (flycheck-def-config-file-var flycheck-luacheckrc lua-luacheck ".luacheckrc"
8798   :safe #'stringp)
8799
8800 (flycheck-def-option-var flycheck-luacheck-standards nil lua-luacheck
8801   "The standards to use in luacheck.
8802
8803 The value of this variable is either a list of strings denoting
8804 the standards to use, or nil to pass nothing to luacheck.  When
8805 non-nil, pass the standards via one or more `--std' options."
8806   :type '(choice (const :tag "Default" nil)
8807                  (repeat :tag "Custom standards"
8808                          (string :tag "Standard name")))
8809   :safe #'flycheck-string-list-p)
8810 (make-variable-buffer-local 'flycheck-luacheck-standards)
8811
8812 (flycheck-define-checker lua-luacheck
8813   "A Lua syntax checker using luacheck.
8814
8815 See URL `https://github.com/mpeterv/luacheck'."
8816   :command ("luacheck"
8817             "--formatter" "plain"
8818             "--codes"                   ; Show warning codes
8819             "--no-color"
8820             (option-list "--std" flycheck-luacheck-standards)
8821             (config-file "--config" flycheck-luacheckrc)
8822             "--filename" source-original
8823             ;; Read from standard input
8824             "-")
8825   :standard-input t
8826   :error-patterns
8827   ((warning line-start
8828             (optional (file-name))
8829             ":" line ":" column
8830             ": (" (id "W" (one-or-more digit)) ") "
8831             (message) line-end)
8832    (error line-start
8833           (optional (file-name))
8834           ":" line ":" column ":"
8835           ;; `luacheck' before 0.11.0 did not output codes for errors, hence
8836           ;; the ID is optional here
8837           (optional " (" (id "E" (one-or-more digit)) ") ")
8838           (message) line-end))
8839   :modes lua-mode)
8840
8841 (flycheck-define-checker lua
8842   "A Lua syntax checker using the Lua compiler.
8843
8844 See URL `http://www.lua.org/'."
8845   :command ("luac" "-p" "-")
8846   :standard-input t
8847   :error-patterns
8848   ((error line-start
8849           ;; Skip the name of the luac executable.
8850           (minimal-match (zero-or-more not-newline))
8851           ": stdin:" line ": " (message) line-end))
8852   :modes lua-mode)
8853
8854 (flycheck-define-checker opam
8855   "A Opam syntax and style checker using opam lint.
8856
8857 See URL `https://opam.ocaml.org/doc/man/opam-lint.html'."
8858   :command ("opam" "lint" "-")
8859   :standard-input t
8860   :error-patterns
8861   ((error line-start                    ; syntax error
8862           (one-or-more space) "error  " (id ?2)
8863           ": File format error"
8864           (or (and " at line " line ", column " column ": " (message))
8865               (and ": " (message)))
8866           line-end)
8867    (error line-start
8868           (one-or-more space) "error  " (id ?3)
8869           (minimal-match (zero-or-more not-newline))
8870           "at line " line ", column " column ": " (message)
8871           line-end)
8872    (error line-start
8873           (one-or-more space) "error " (id (one-or-more num))
8874           ": " (message (one-or-more not-newline))
8875           line-end)
8876    (warning line-start
8877             (one-or-more space) "warning " (id (one-or-more num))
8878             ": " (message)
8879             line-end))
8880   :error-filter
8881   (lambda (errors)
8882     (flycheck-increment-error-columns
8883      (flycheck-fill-empty-line-numbers errors)))
8884   :modes tuareg-opam-mode)
8885
8886 (flycheck-def-option-var flycheck-perl-include-path nil perl
8887   "A list of include directories for Perl.
8888
8889 The value of this variable is a list of strings, where each
8890 string is a directory to add to the include path of Perl.
8891 Relative paths are relative to the file being checked."
8892   :type '(repeat (directory :tag "Include directory"))
8893   :safe #'flycheck-string-list-p
8894   :package-version '(flycheck . "0.24"))
8895
8896 (flycheck-def-option-var flycheck-perl-module-list nil perl
8897   "A list of modules to use for Perl.
8898
8899 The value of this variable is a list of strings, where each
8900 string is a module to 'use' in Perl."
8901   :type '(repeat :tag "Module")
8902   :safe #'flycheck-string-list-p
8903   :package-version '(flycheck . "32"))
8904
8905 (flycheck-define-checker perl
8906   "A Perl syntax checker using the Perl interpreter.
8907
8908 See URL `https://www.perl.org'."
8909   :command ("perl" "-w" "-c"
8910             (option-list "-I" flycheck-perl-include-path)
8911             (option-list "-M" flycheck-perl-module-list concat))
8912   :standard-input t
8913   :error-patterns
8914   ((error line-start (minimal-match (message))
8915           " at - line " line
8916           (or "." (and ", " (zero-or-more not-newline))) line-end))
8917   :modes (perl-mode cperl-mode)
8918   :next-checkers (perl-perlcritic))
8919
8920 (flycheck-def-option-var flycheck-perlcritic-severity nil perl-perlcritic
8921   "The message severity for Perl Critic.
8922
8923 The value of this variable is a severity level as integer, for
8924 the `--severity' option to Perl Critic."
8925   :type '(integer :tag "Severity level")
8926   :safe #'integerp
8927   :package-version '(flycheck . "0.18"))
8928
8929 (flycheck-def-option-var flycheck-perlcritic-theme nil perl-perlcritic
8930   "The theme expression for Perl Critic.
8931
8932 The value of this variable is passed as the `--theme' option to
8933 `Perl::Critic'.  See the documentation of `Perl::Critic' for
8934 details."
8935   :type '(string :tag "Theme expression")
8936   :safe #'stringp
8937   :package-version '(flycheck . "32-csv"))
8938
8939 (flycheck-def-config-file-var flycheck-perlcriticrc perl-perlcritic
8940                               ".perlcriticrc"
8941   :safe #'stringp
8942   :package-version '(flycheck . "26"))
8943
8944 (flycheck-define-checker perl-perlcritic
8945   "A Perl syntax checker using Perl::Critic.
8946
8947 See URL `https://metacpan.org/pod/Perl::Critic'."
8948   :command ("perlcritic" "--no-color" "--verbose" "%f/%l/%c/%s/%p/%m (%e)\n"
8949             (config-file "--profile" flycheck-perlcriticrc)
8950             (option "--severity" flycheck-perlcritic-severity nil
8951                     flycheck-option-int)
8952             (option "--theme" flycheck-perlcritic-theme))
8953   :standard-input t
8954   :error-patterns
8955   ((info line-start
8956          "STDIN/" line "/" column "/" (any "1") "/"
8957          (id (one-or-more (not (any "/")))) "/" (message)
8958          line-end)
8959    (warning line-start
8960             "STDIN/" line "/" column "/" (any "234") "/"
8961             (id (one-or-more (not (any "/")))) "/" (message)
8962             line-end)
8963    (error line-start
8964           "STDIN/" line "/" column "/" (any "5") "/"
8965           (id (one-or-more (not (any "/")))) "/" (message)
8966           line-end))
8967   :modes (cperl-mode perl-mode))
8968
8969 (flycheck-define-checker php
8970   "A PHP syntax checker using the PHP command line interpreter.
8971
8972 See URL `http://php.net/manual/en/features.commandline.php'."
8973   :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1"
8974             "-d" "log_errors=0" source)
8975   :error-patterns
8976   ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") " "
8977           (message) " in " (file-name) " on line " line line-end))
8978   :modes (php-mode php+-mode)
8979   :next-checkers ((warning . php-phpmd)
8980                   (warning . php-phpcs)))
8981
8982 (flycheck-def-option-var flycheck-phpmd-rulesets
8983     '("cleancode" "codesize" "controversial" "design" "naming" "unusedcode")
8984     php-phpmd
8985   "The rule sets for PHP Mess Detector.
8986
8987 Set default rule sets and custom rule set files.
8988
8989 See section \"Using multiple rule sets\" in the PHP Mess Detector
8990 manual at URL `https://phpmd.org/documentation/index.html'."
8991   :type '(repeat :tag "rule sets"
8992                  (string :tag "A filename or rule set"))
8993   :safe #'flycheck-string-list-p)
8994
8995 (flycheck-define-checker php-phpmd
8996   "A PHP style checker using PHP Mess Detector.
8997
8998 See URL `https://phpmd.org/'."
8999   :command ("phpmd" source "xml"
9000             (eval (flycheck-option-comma-separated-list
9001                    flycheck-phpmd-rulesets)))
9002   :error-parser flycheck-parse-phpmd
9003   :modes (php-mode php+-mode)
9004   :next-checkers (php-phpcs))
9005
9006 (flycheck-def-option-var flycheck-phpcs-standard nil php-phpcs
9007   "The coding standard for PHP CodeSniffer.
9008
9009 When nil, use the default standard from the global PHP
9010 CodeSniffer configuration.  When set to a string, pass the string
9011 to PHP CodeSniffer which will interpret it as name as a standard,
9012 or as path to a standard specification."
9013   :type '(choice (const :tag "Default standard" nil)
9014                  (string :tag "Standard name or file"))
9015   :safe #'stringp)
9016
9017 (flycheck-define-checker php-phpcs
9018   "A PHP style checker using PHP Code Sniffer.
9019
9020 Needs PHP Code Sniffer 2.6 or newer.
9021
9022 See URL `http://pear.php.net/package/PHP_CodeSniffer/'."
9023   :command ("phpcs" "--report=checkstyle"
9024             ;; Use -q flag to force quiet mode
9025             ;; Quiet mode prevents errors from extra output when phpcs has
9026             ;; been configured with show_progress enabled
9027             "-q"
9028             (option "--standard=" flycheck-phpcs-standard concat)
9029             ;; Pass original file name to phpcs.  We need to concat explicitly
9030             ;; here, because phpcs really insists to get option and argument as
9031             ;; a single command line argument :|
9032             (eval (when (buffer-file-name)
9033                     (concat "--stdin-path=" (buffer-file-name))))
9034             ;; Read from standard input
9035             "-")
9036   :standard-input t
9037   :error-parser flycheck-parse-checkstyle
9038   :error-filter
9039   (lambda (errors)
9040     (flycheck-sanitize-errors
9041      (flycheck-remove-error-file-names "STDIN" errors)))
9042   :modes (php-mode php+-mode)
9043   ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
9044   ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
9045   :predicate (lambda () (not (flycheck-buffer-empty-p))))
9046
9047 (flycheck-define-checker processing
9048   "Processing command line tool.
9049
9050 See https://github.com/processing/processing/wiki/Command-Line"
9051   :command ("processing-java" "--force"
9052             ;; Don't change the order of these arguments, processing is pretty
9053             ;; picky
9054             (eval (concat "--sketch=" (file-name-directory (buffer-file-name))))
9055             (eval (concat "--output=" (flycheck-temp-dir-system)))
9056             "--build")
9057   :error-patterns
9058   ((error line-start (file-name) ":" line ":" column
9059           (zero-or-more (or digit ":")) (message) line-end))
9060   :modes processing-mode
9061   ;; This syntax checker needs a file name
9062   :predicate (lambda () (buffer-file-name)))
9063
9064 (defun flycheck-proselint-parse-errors (output checker buffer)
9065   "Parse proselint json output errors from OUTPUT.
9066
9067 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
9068 the BUFFER that was checked respectively.
9069
9070 See URL `http://proselint.com/' for more information about proselint."
9071   (mapcar (lambda (err)
9072             (let-alist err
9073               (flycheck-error-new-at
9074                .line
9075                .column
9076                (pcase .severity
9077                  (`"suggestion" 'info)
9078                  (`"warning"    'warning)
9079                  (`"error"      'error)
9080                  ;; Default to error
9081                  (_             'error))
9082                .message
9083                :id .check
9084                :buffer buffer
9085                :checker checker)))
9086           (let-alist (car (flycheck-parse-json output))
9087             .data.errors)))
9088
9089 (flycheck-define-checker proselint
9090   "Flycheck checker using Proselint.
9091
9092 See URL `http://proselint.com/'."
9093   :command ("proselint" "--json" "-")
9094   :standard-input t
9095   :error-parser flycheck-proselint-parse-errors
9096   :modes (text-mode markdown-mode gfm-mode message-mode org-mode))
9097
9098 (flycheck-define-checker protobuf-protoc
9099   "A protobuf syntax checker using the protoc compiler.
9100
9101 See URL `https://developers.google.com/protocol-buffers/'."
9102   :command ("protoc" "--error_format" "gcc"
9103             (eval (concat "--java_out=" (flycheck-temp-dir-system)))
9104             ;; Add the file directory of protobuf path to resolve import
9105             ;; directives
9106             (eval (concat "--proto_path="
9107                           (file-name-directory (buffer-file-name))))
9108             source-inplace)
9109   :error-patterns
9110   ((info line-start (file-name) ":" line ":" column
9111          ": note: " (message) line-end)
9112    (error line-start (file-name) ":" line ":" column
9113           ": " (message) line-end)
9114    (error line-start
9115           (message "In file included from") " " (file-name) ":" line ":"
9116           column ":" line-end))
9117   :modes protobuf-mode
9118   :predicate (lambda () (buffer-file-name)))
9119
9120 (flycheck-define-checker pug
9121   "A Pug syntax checker using the pug compiler.
9122
9123 See URL `https://pugjs.org/'."
9124   :command ("pug" "-p" (eval (expand-file-name (buffer-file-name))))
9125   :standard-input t
9126   :error-patterns
9127   ;; errors with includes/extends (e.g. missing files)
9128   ((error "Error: " (message) (zero-or-more not-newline) "\n"
9129           (zero-or-more not-newline) "at "
9130           (zero-or-more not-newline) " line " line)
9131    ;; syntax/runtime errors (e.g. type errors, bad indentation, etc.)
9132    (error line-start
9133           (optional "Type") "Error: "  (file-name) ":"
9134           line (optional ":" column)
9135           (zero-or-more not-newline) "\n"
9136           (one-or-more (or (zero-or-more not-newline) "|"
9137                            (zero-or-more not-newline) "\n")
9138                        (zero-or-more "-")  (zero-or-more not-newline) "|"
9139                        (zero-or-more not-newline) "\n")
9140           (zero-or-more not-newline) "\n"
9141           (one-or-more
9142            (zero-or-more not-newline) "|"
9143            (zero-or-more not-newline) "\n")
9144           (zero-or-more not-newline) "\n"
9145           (message)
9146           line-end))
9147   :modes pug-mode)
9148
9149 (flycheck-define-checker puppet-parser
9150   "A Puppet DSL syntax checker using puppet's own parser.
9151
9152 See URL `https://puppet.com/'."
9153   :command ("puppet" "parser" "validate" "--color=false")
9154   :standard-input t
9155   :error-patterns
9156   (
9157    ;; Patterns for Puppet 4
9158    (error line-start "Error: Could not parse for environment "
9159           (one-or-more (in "a-z" "0-9" "_")) ":"
9160           (message) "(line: " line ", column: " column ")" line-end)
9161    ;; Errors from Puppet < 4
9162    (error line-start "Error: Could not parse for environment "
9163           (one-or-more (in "a-z" "0-9" "_")) ":"
9164           (message (minimal-match (one-or-more anything)))
9165           " at line " line line-end)
9166    (error line-start
9167           ;; Skip over the path of the Puppet executable
9168           (minimal-match (zero-or-more not-newline))
9169           ": Could not parse for environment " (one-or-more word)
9170           ": " (message (minimal-match (zero-or-more anything)))
9171           " at " (file-name "/" (zero-or-more not-newline)) ":" line line-end))
9172   :modes puppet-mode
9173   :next-checkers ((warning . puppet-lint)))
9174
9175 (flycheck-def-config-file-var flycheck-puppet-lint-rc puppet-lint
9176                               ".puppet-lint.rc"
9177   :safe #'stringp
9178   :package-version '(flycheck . "26"))
9179
9180 (flycheck-def-option-var flycheck-puppet-lint-disabled-checks nil puppet-lint
9181   "Disabled checkers for `puppet-lint'.
9182
9183 The value of this variable is a list of strings, where each
9184 string is the name of a check to disable (e.g. \"80chars\" or
9185 \"double_quoted_strings\").
9186
9187 See URL `http://puppet-lint.com/checks/' for a list of all checks
9188 and their names."
9189   :type '(repeat (string :tag "Check Name"))
9190   :package-version '(flycheck . "26"))
9191
9192 (defun flycheck-puppet-lint-disabled-arg-name (check)
9193   "Create an argument to disable a puppetlint CHECK."
9194   (concat "--no-" check "-check"))
9195
9196 (flycheck-define-checker puppet-lint
9197   "A Puppet DSL style checker using puppet-lint.
9198
9199 See URL `http://puppet-lint.com/'."
9200   ;; We must check the original file, because Puppetlint is quite picky on the
9201   ;; names of files and there place in the directory structure, to comply with
9202   ;; Puppet's autoload directory layout.  For instance, a class foo::bar is
9203   ;; required to be in a file foo/bar.pp.  Any other place, such as a Flycheck
9204   ;; temporary file will cause an error.
9205   :command ("puppet-lint"
9206             (config-file "--config" flycheck-puppet-lint-rc)
9207             "--log-format"
9208             "%{path}:%{line}:%{kind}: %{message} (%{check})"
9209             (option-list "" flycheck-puppet-lint-disabled-checks concat
9210                          flycheck-puppet-lint-disabled-arg-name)
9211             source-original)
9212   :error-patterns
9213   ((warning line-start (file-name) ":" line ":warning: " (message) line-end)
9214    (error line-start (file-name) ":" line ":error: " (message) line-end))
9215   :modes puppet-mode
9216   ;; Since we check the original file, we can only use this syntax checker if
9217   ;; the buffer is actually linked to a file, and if it is not modified.
9218   :predicate flycheck-buffer-saved-p)
9219
9220 (defun flycheck-python-find-module (checker module)
9221   "Check if a Python MODULE is available.
9222 CHECKER's executable is assumed to be a Python REPL."
9223   (-when-let* ((py (flycheck-find-checker-executable checker))
9224                (script (concat "import sys; sys.path.pop(0);"
9225                                (format "import %s; print(%s.__file__)"
9226                                        module module))))
9227     (with-temp-buffer
9228       (and (eq (ignore-errors (call-process py nil t nil "-c" script)) 0)
9229            (string-trim (buffer-string))))))
9230
9231 (defun flycheck-python-needs-module-p (checker)
9232   "Determines whether CHECKER needs to be invoked through Python.
9233 Previous versions of Flycheck called pylint and flake8 directly;
9234 this check ensures that we don't break existing code."
9235   (not (string-match-p (rx (or "pylint" "flake8")
9236                            (or "-script.pyw" ".exe" ".bat" "")
9237                            eos)
9238                        (flycheck-checker-executable checker))))
9239
9240 (defun flycheck-python-verify-module (checker module)
9241   "Verify that a Python MODULE is available.
9242 Return nil if CHECKER's executable is not a Python REPL.  This
9243 function's is suitable for a checker's :verify."
9244   (when (flycheck-python-needs-module-p checker)
9245     (let ((mod-path (flycheck-python-find-module checker module)))
9246       (list (flycheck-verification-result-new
9247              :label (format "`%s' module" module)
9248              :message (if mod-path (format "Found at %S" mod-path) "Missing")
9249              :face (if mod-path 'success '(bold error)))))))
9250
9251 (defun flycheck-python-module-args (checker module-name)
9252   "Compute arguments to pass to CHECKER's executable to run MODULE-NAME.
9253 Return nil if CHECKER's executable is not a Python REPL.
9254 Otherwise, return a list starting with -c (-m is not enough
9255 because it adds the current directory to Python's path)."
9256   (when (flycheck-python-needs-module-p checker)
9257     `("-c" ,(concat "import sys,runpy;sys.path.pop(0);"
9258                     (format "runpy.run_module(%S)" module-name)))))
9259
9260 (flycheck-def-config-file-var flycheck-flake8rc python-flake8 ".flake8rc"
9261   :safe #'stringp)
9262
9263 (flycheck-def-option-var flycheck-flake8-error-level-alist
9264     '(("^E9.*$"  . error)               ; Syntax errors from pep8
9265       ("^F82.*$" . error)               ; undefined variables from pyflakes
9266       ("^F83.*$" . error)               ; Duplicate arguments from flake8
9267       ("^D.*$"   . info)                ; Docstring issues from flake8-pep257
9268       ("^N.*$"   . info)                ; Naming issues from pep8-naming
9269       )
9270     python-flake8
9271   "An alist mapping flake8 error IDs to Flycheck error levels.
9272
9273 Each item in this list is a cons cell `(PATTERN . LEVEL)' where
9274 PATTERN is a regular expression matched against the error ID, and
9275 LEVEL is a Flycheck error level symbol.
9276
9277 Each PATTERN is matched in the order of appearance in this list
9278 against the error ID.  If it matches the ID, the level of the
9279 corresponding error is set to LEVEL.  An error that is not
9280 matched by any PATTERN defaults to warning level.
9281
9282 The default value of this option matches errors from flake8
9283 itself and from the following flake8 plugins:
9284
9285 - pep8-naming
9286 - flake8-pep257
9287
9288 You may add your own mappings to this option in order to support
9289 further flake8 plugins."
9290   :type '(repeat (cons (regexp :tag "Error ID pattern")
9291                        (symbol :tag "Error level")))
9292   :package-version '(flycheck . "0.22"))
9293
9294 (flycheck-def-option-var flycheck-flake8-maximum-complexity nil python-flake8
9295   "The maximum McCabe complexity of methods.
9296
9297 If nil, do not check the complexity of methods.  If set to an
9298 integer, report any complexity greater than the value of this
9299 variable as warning.
9300
9301 If set to an integer, this variable overrules any similar setting
9302 in the configuration file denoted by `flycheck-flake8rc'."
9303   :type '(choice (const :tag "Do not check McCabe complexity" nil)
9304                  (integer :tag "Maximum complexity"))
9305   :safe #'integerp)
9306
9307 (flycheck-def-option-var flycheck-flake8-maximum-line-length nil python-flake8
9308   "The maximum length of lines.
9309
9310 If set to an integer, the value of this variable denotes the
9311 maximum length of lines, overruling any similar setting in the
9312 configuration file denoted by `flycheck-flake8rc'.  An error will
9313 be reported for any line longer than the value of this variable.
9314
9315 If set to nil, use the maximum line length from the configuration
9316 file denoted by `flycheck-flake8rc', or the PEP 8 recommendation
9317 of 79 characters if there is no configuration with this setting."
9318   :type '(choice (const :tag "Default value")
9319                  (integer :tag "Maximum line length in characters"))
9320   :safe #'integerp)
9321
9322 (defun flycheck-flake8-fix-error-level (err)
9323   "Fix the error level of ERR.
9324
9325 Update the error level of ERR according to
9326 `flycheck-flake8-error-level-alist'."
9327   (pcase-dolist (`(,pattern . ,level) flycheck-flake8-error-level-alist)
9328     (when (string-match-p pattern (flycheck-error-id err))
9329       (setf (flycheck-error-level err) level)))
9330   err)
9331
9332 (flycheck-define-checker python-flake8
9333   "A Python syntax and style checker using Flake8.
9334
9335 Requires Flake8 3.0 or newer. See URL
9336 `https://flake8.readthedocs.io/'."
9337   ;; Not calling flake8 directly makes it easier to switch between different
9338   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
9339   :command ("python"
9340             (eval (flycheck-python-module-args 'python-flake8 "flake8"))
9341             "--format=default"
9342             (config-file "--config" flycheck-flake8rc)
9343             (option "--max-complexity" flycheck-flake8-maximum-complexity nil
9344                     flycheck-option-int)
9345             (option "--max-line-length" flycheck-flake8-maximum-line-length nil
9346                     flycheck-option-int)
9347             "-")
9348   :standard-input t
9349   :error-filter (lambda (errors)
9350                   (let ((errors (flycheck-sanitize-errors errors)))
9351                     (seq-map #'flycheck-flake8-fix-error-level errors)))
9352   :error-patterns
9353   ((warning line-start
9354             "stdin:" line ":" (optional column ":") " "
9355             (id (one-or-more (any alpha)) (one-or-more digit)) " "
9356             (message (one-or-more not-newline))
9357             line-end))
9358   :enabled (lambda ()
9359              (or (not (flycheck-python-needs-module-p 'python-flake8))
9360                  (flycheck-python-find-module 'python-flake8 "flake8")))
9361   :verify (lambda (_) (flycheck-python-verify-module 'python-flake8 "flake8"))
9362   :modes python-mode)
9363
9364 (flycheck-def-config-file-var flycheck-pylintrc python-pylint ".pylintrc"
9365   :safe #'stringp)
9366
9367 (flycheck-def-option-var flycheck-pylint-use-symbolic-id t python-pylint
9368   "Whether to use pylint message symbols or message codes.
9369
9370 A pylint message has both an opaque identifying code (such as `F0401') and a
9371 more meaningful symbolic code (such as `import-error').  This option governs
9372 which should be used and reported to the user."
9373   :type 'boolean
9374   :safe #'booleanp
9375   :package-version '(flycheck . "0.25"))
9376
9377 (flycheck-define-checker python-pylint
9378   "A Python syntax and style checker using Pylint.
9379
9380 This syntax checker requires Pylint 1.0 or newer.
9381
9382 See URL `https://www.pylint.org/'."
9383   ;; --reports=n disables the scoring report.
9384   ;; Not calling pylint directly makes it easier to switch between different
9385   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
9386   :command ("python"
9387             (eval (flycheck-python-module-args 'python-pylint "pylint"))
9388             "--reports=n"
9389             "--output-format=text"
9390             (eval (if flycheck-pylint-use-symbolic-id
9391                       "--msg-template={path}:{line}:{column}:{C}:{symbol}:{msg}"
9392                     "--msg-template={path}:{line}:{column}:{C}:{msg_id}:{msg}"))
9393             (config-file "--rcfile=" flycheck-pylintrc concat)
9394             ;; Need `source-inplace' for relative imports (e.g. `from .foo
9395             ;; import bar'), see https://github.com/flycheck/flycheck/issues/280
9396             source-inplace)
9397   :error-filter
9398   (lambda (errors)
9399     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
9400   :error-patterns
9401   ((error line-start (file-name) ":" line ":" column ":"
9402           (or "E" "F") ":"
9403           (id (one-or-more (not (any ":")))) ":"
9404           (message) line-end)
9405    (warning line-start (file-name) ":" line ":" column ":"
9406             (or "W" "R") ":"
9407             (id (one-or-more (not (any ":")))) ":"
9408             (message) line-end)
9409    (info line-start (file-name) ":" line ":" column ":"
9410          (or "C" "I") ":"
9411          (id (one-or-more (not (any ":")))) ":"
9412          (message) line-end))
9413   :enabled (lambda ()
9414              (or (not (flycheck-python-needs-module-p 'python-pylint))
9415                  (flycheck-python-find-module 'python-pylint "pylint")))
9416   :verify (lambda (_) (flycheck-python-verify-module 'python-pylint "pylint"))
9417   :modes python-mode)
9418
9419 (flycheck-define-checker python-pycompile
9420   "A Python syntax checker using Python's builtin compiler.
9421
9422 See URL `https://docs.python.org/3.4/library/py_compile.html'."
9423   :command ("python" "-m" "py_compile" source)
9424   :error-patterns
9425   ;; Python 2.7
9426   ((error line-start "  File \"" (file-name) "\", line " line "\n"
9427           (>= 2 (zero-or-more not-newline) "\n")
9428           "SyntaxError: " (message) line-end)
9429    (error line-start "Sorry: IndentationError: "
9430           (message) "(" (file-name) ", line " line ")"
9431           line-end)
9432    ;; 2.6
9433    (error line-start "SyntaxError: ('" (message (one-or-more (not (any "'"))))
9434           "', ('" (file-name (one-or-more (not (any "'")))) "', "
9435           line ", " column ", " (one-or-more not-newline) line-end))
9436   :modes python-mode)
9437
9438 (flycheck-def-config-file-var flycheck-python-mypy-ini python-mypy
9439                               "mypy.ini"
9440   :safe #'stringp)
9441
9442 (flycheck-def-option-var flycheck-python-mypy-cache-dir nil python-mypy
9443   "Directory used to write .mypy_cache directories."
9444   :safe #'stringp
9445   :type '(choice
9446           (const :tag "Write to the working directory" nil)
9447           (const :tag "Never write .mypy_cache directories" null-device)
9448           (string :tag "Path"))
9449   :package-version '(flycheck . "32"))
9450
9451 (flycheck-define-checker python-mypy
9452   "Mypy syntax and type checker.  Requires mypy>=0.580.
9453
9454 See URL `http://mypy-lang.org/'."
9455   :command ("mypy"
9456             "--show-column-numbers"
9457             (config-file "--config-file" flycheck-python-mypy-ini)
9458             (option "--cache-dir" flycheck-python-mypy-cache-dir)
9459             source-original)
9460   :error-patterns
9461   ((error line-start (file-name) ":" line (optional ":" column)
9462           ": error:" (message) line-end)
9463    (warning line-start (file-name) ":" line (optional ":" column)
9464             ": warning:" (message) line-end))
9465   :modes python-mode
9466   ;; Ensure the file is saved, to work around
9467   ;; https://github.com/python/mypy/issues/4746.
9468   :predicate flycheck-buffer-saved-p
9469   :next-checkers (python-flake8))
9470
9471 (flycheck-def-option-var flycheck-lintr-caching t r-lintr
9472   "Whether to enable caching in lintr.
9473
9474 By default, lintr caches all expressions in a file and re-checks
9475 only those that have changed.  Setting this option to nil
9476 disables caching in case there are problems."
9477   :type 'boolean
9478   :safe #'booleanp
9479   :package-version '(flycheck . "0.23"))
9480
9481 (flycheck-def-option-var flycheck-lintr-linters "default_linters" r-lintr
9482   "Linters to use with lintr.
9483
9484 The value of this variable is a string containing an R
9485 expression, which selects linters for lintr."
9486   :type 'string
9487   :risky t
9488   :package-version '(flycheck . "0.23"))
9489
9490 (defun flycheck-r-has-lintr (R)
9491   "Whether R has installed the `lintr' library."
9492   (with-temp-buffer
9493     (let ((process-environment (append '("LC_ALL=C") process-environment)))
9494       (call-process R nil t nil
9495                     "--slave" "--restore" "--no-save" "-e"
9496                     "library('lintr')")
9497       (goto-char (point-min))
9498       (not (re-search-forward "there is no package called 'lintr'"
9499                               nil 'no-error)))))
9500
9501 (flycheck-define-checker r-lintr
9502   "An R style and syntax checker using the lintr package.
9503
9504 See URL `https://github.com/jimhester/lintr'."
9505   :command ("R" "--slave" "--restore" "--no-save" "-e"
9506             (eval (concat
9507                    "library(lintr);"
9508                    "try(lint(commandArgs(TRUE)"
9509                    ", cache=" (if flycheck-lintr-caching "TRUE" "FALSE")
9510                    ", " flycheck-lintr-linters
9511                    "))"))
9512             "--args" source)
9513   :error-patterns
9514   ((info line-start (file-name) ":" line ":" column ": style: " (message)
9515          line-end)
9516    (warning line-start (file-name) ":" line ":" column ": warning: " (message)
9517             line-end)
9518    (error line-start (file-name) ":" line ":" column ": error: " (message)
9519           line-end))
9520   :modes (ess-mode ess-r-mode)
9521   :predicate
9522   ;; Don't check ESS files which do not contain R, and make sure that lintr is
9523   ;; actually available
9524   (lambda ()
9525     (and (equal ess-language "S")
9526          (flycheck-r-has-lintr (flycheck-checker-executable 'r-lintr))))
9527   :verify (lambda (checker)
9528             (let ((has-lintr (flycheck-r-has-lintr
9529                               (flycheck-checker-executable checker))))
9530               (list
9531                (flycheck-verification-result-new
9532                 :label "lintr library"
9533                 :message (if has-lintr "present" "missing")
9534                 :face (if has-lintr 'success '(bold error)))))))
9535
9536 (defun flycheck-racket-has-expand-p (checker)
9537   "Whether the executable of CHECKER provides the `expand' command."
9538   (let ((raco (flycheck-find-checker-executable checker)))
9539     (when raco
9540       (with-temp-buffer
9541         (call-process raco nil t nil "expand")
9542         (goto-char (point-min))
9543         (not (looking-at-p (rx bol (1+ not-newline)
9544                                "Unrecognized command: expand"
9545                                eol)))))))
9546
9547 (flycheck-define-checker racket
9548   "A Racket syntax checker with `raco expand'.
9549
9550 The `compiler-lib' racket package is required for this syntax
9551 checker.
9552
9553 See URL `https://racket-lang.org/'."
9554   :command ("raco" "expand" source-inplace)
9555   :predicate
9556   (lambda ()
9557     (and (or (not (eq major-mode 'scheme-mode))
9558              ;; In `scheme-mode' we must check the current Scheme implementation
9559              ;; being used
9560              (and (boundp 'geiser-impl--implementation)
9561                   (eq geiser-impl--implementation 'racket)))
9562          (flycheck-racket-has-expand-p 'racket)))
9563   :verify
9564   (lambda (checker)
9565     (let ((has-expand (flycheck-racket-has-expand-p checker))
9566           (in-scheme-mode (eq major-mode 'scheme-mode))
9567           (geiser-impl (bound-and-true-p geiser-impl--implementation)))
9568       (list
9569        (flycheck-verification-result-new
9570         :label "compiler-lib package"
9571         :message (if has-expand "present" "missing")
9572         :face (if has-expand 'success '(bold error)))
9573        (flycheck-verification-result-new
9574         :label "Geiser Implementation"
9575         :message (cond
9576                   ((not in-scheme-mode) "Using Racket Mode")
9577                   ((eq geiser-impl 'racket) "Racket")
9578                   (geiser-impl (format "Other: %s" geiser-impl))
9579                   (t "Geiser not active"))
9580         :face (cond
9581                ((or (not in-scheme-mode) (eq geiser-impl 'racket)) 'success)
9582                (t '(bold error)))))))
9583   :error-filter
9584   (lambda (errors)
9585     (flycheck-sanitize-errors
9586      (flycheck-increment-error-columns
9587       (seq-remove
9588        (lambda (err)
9589          (string=
9590           "/usr/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt"
9591           (flycheck-error-filename err)))
9592        errors))))
9593   :error-patterns
9594   ((error line-start (zero-or-more space)
9595           (file-name) ":" line ":" column ":" (message) line-end))
9596   :modes (racket-mode scheme-mode))
9597
9598 (flycheck-define-checker rpm-rpmlint
9599   "A RPM SPEC file syntax checker using rpmlint.
9600
9601 See URL `https://sourceforge.net/projects/rpmlint/'."
9602   :command ("rpmlint" source)
9603   :error-patterns
9604   ((error line-start
9605           (file-name) ":" (optional line ":") " E: " (message)
9606           line-end)
9607    (warning line-start
9608             (file-name) ":" (optional line ":") " W: " (message)
9609             line-end))
9610   :error-filter
9611   ;; Add fake line numbers if they are missing in the lint output
9612   (lambda (errors)
9613     (dolist (err errors)
9614       (unless (flycheck-error-line err)
9615         (setf (flycheck-error-line err) 1)))
9616     errors)
9617   :error-explainer
9618   (lambda (error)
9619     (-when-let* ((error-message (flycheck-error-message error))
9620                  (message-id (save-match-data
9621                                (string-match "\\([^ ]+\\)" error-message)
9622                                (match-string 1 error-message))))
9623       (with-output-to-string
9624         (call-process "rpmlint" nil standard-output nil "-I" message-id))))
9625   :modes (sh-mode rpm-spec-mode)
9626   :predicate (lambda () (or (not (eq major-mode 'sh-mode))
9627                             ;; In `sh-mode', we need the proper shell
9628                             (eq sh-shell 'rpm))))
9629
9630 (flycheck-def-config-file-var flycheck-markdown-markdownlint-cli-config
9631     markdown-markdownlint-cli nil
9632   :safe #'stringp
9633   :package-version '(flycheck . "32"))
9634
9635 (flycheck-define-checker markdown-markdownlint-cli
9636   "Markdown checker using markdownlint-cli.
9637
9638 See URL `https://github.com/igorshubovych/markdownlint-cli'."
9639   :command ("markdownlint"
9640             (config-file "--config" flycheck-markdown-markdownlint-cli-config)
9641             source)
9642   :error-patterns
9643   ((error line-start
9644           (file-name) ": " line ": " (id (one-or-more (not (any space))))
9645           " " (message) line-end))
9646   :error-filter
9647   (lambda (errors)
9648     (flycheck-sanitize-errors
9649      (flycheck-remove-error-file-names "(string)" errors)))
9650   :modes (markdown-mode gfm-mode))
9651
9652 (flycheck-def-option-var flycheck-markdown-mdl-rules nil markdown-mdl
9653   "Rules to enable for mdl.
9654
9655 The value of this variable is a list of strings each of which is
9656 the name of a rule to enable.
9657
9658 By default all rules are enabled.
9659
9660 See URL `https://git.io/vhi2t'."
9661   :type '(repeat :tag "Enabled rules"
9662                  (string :tag "rule name"))
9663   :safe #'flycheck-string-list-p
9664   :package-version '(flycheck . "27"))
9665
9666 (flycheck-def-option-var flycheck-markdown-mdl-tags nil markdown-mdl
9667   "Rule tags to enable for mdl.
9668
9669 The value of this variable is a list of strings each of which is
9670 the name of a rule tag.  Only rules with these tags are enabled.
9671
9672 By default all rules are enabled.
9673
9674 See URL `https://git.io/vhi2t'."
9675   :type '(repeat :tag "Enabled tags"
9676                  (string :tag "tag name"))
9677   :safe #'flycheck-string-list-p
9678   :package-version '(flycheck . "27"))
9679
9680 (flycheck-def-config-file-var flycheck-markdown-mdl-style markdown-mdl nil
9681   :safe #'stringp
9682   :package-version '(flycheck . "27"))
9683
9684 (flycheck-define-checker markdown-mdl
9685   "Markdown checker using mdl.
9686
9687 See URL `https://github.com/markdownlint/markdownlint'."
9688   :command ("mdl"
9689             (config-file "--style" flycheck-markdown-mdl-style)
9690             (option "--tags=" flycheck-markdown-mdl-rules concat
9691                     flycheck-option-comma-separated-list)
9692             (option "--rules=" flycheck-markdown-mdl-rules concat
9693                     flycheck-option-comma-separated-list))
9694   :standard-input t
9695   :error-patterns
9696   ((error line-start
9697           (file-name) ":" line ": " (id (one-or-more alnum)) " " (message)
9698           line-end))
9699   :error-filter
9700   (lambda (errors)
9701     (flycheck-sanitize-errors
9702      (flycheck-remove-error-file-names "(stdin)" errors)))
9703   :modes (markdown-mode gfm-mode))
9704
9705 (flycheck-define-checker nix
9706   "Nix checker using nix-instantiate.
9707
9708 See URL `https://nixos.org/nix/manual/#sec-nix-instantiate'."
9709   :command ("nix-instantiate" "--parse" "-")
9710   :standard-input t
9711   :error-patterns
9712   ((error line-start
9713           "error: " (message) " at " (file-name) ":" line ":" column
9714           line-end))
9715   :error-filter
9716   (lambda (errors)
9717     (flycheck-sanitize-errors
9718      (flycheck-remove-error-file-names "(string)" errors)))
9719   :next-checkers ((warning . nix-linter))
9720   :modes nix-mode)
9721
9722 (defun flycheck-parse-nix-linter (output checker buffer)
9723   "Parse nix-linter warnings from JSON OUTPUT.
9724
9725 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
9726 the BUFFER that was checked respectively.
9727
9728 See URL `https://github.com/Synthetica9/nix-linter' for more
9729 information about nix-linter."
9730   (mapcar (lambda (err)
9731             (let-alist err
9732               (flycheck-error-new-at
9733                .pos.spanBegin.sourceLine
9734                .pos.spanBegin.sourceColumn
9735                'warning
9736                .description
9737                :id .offense
9738                :checker checker
9739                :buffer buffer
9740                :filename (buffer-file-name buffer))))
9741           (flycheck-parse-json output)))
9742
9743 (flycheck-define-checker nix-linter
9744   "Nix checker using nix-linter.
9745
9746 See URL `https://github.com/Synthetica9/nix-linter'."
9747   :command ("nix-linter" "--json-stream" "-")
9748   :standard-input t
9749   :error-parser flycheck-parse-nix-linter
9750   :modes nix-mode)
9751
9752 (defun flycheck-locate-sphinx-source-directory ()
9753   "Locate the Sphinx source directory for the current buffer.
9754
9755 Return the source directory, or nil, if the current buffer is not
9756 part of a Sphinx project."
9757   (-when-let* ((filename (buffer-file-name))
9758                (dir (locate-dominating-file filename "conf.py")))
9759     (expand-file-name dir)))
9760
9761 (flycheck-define-checker rst
9762   "A ReStructuredText (RST) syntax checker using Docutils.
9763
9764 See URL `http://docutils.sourceforge.net/'."
9765   ;; We need to use source-inplace to properly resolve relative paths in
9766   ;; include:: directives
9767   :command ("rst2pseudoxml.py" "--report=2" "--halt=5"
9768             ;; Read from standard input and throw output away
9769             "-" null-device)
9770   :standard-input t
9771   :error-patterns
9772   ((warning line-start "<stdin>:" line ": (WARNING/2) " (message) line-end)
9773    (error line-start "<stdin>:" line
9774           ": (" (or "ERROR/3" "SEVERE/4") ") "
9775           (message) line-end))
9776   :modes rst-mode)
9777
9778 (flycheck-def-option-var flycheck-sphinx-warn-on-missing-references t rst-sphinx
9779   "Whether to warn about missing references in Sphinx.
9780
9781 When non-nil (the default), warn about all missing references in
9782 Sphinx via `-n'."
9783   :type 'boolean
9784   :safe #'booleanp
9785   :package-version '(flycheck . "0.17"))
9786
9787 (flycheck-define-checker rst-sphinx
9788   "A ReStructuredText (RST) syntax checker using Sphinx.
9789
9790 Requires Sphinx 1.2 or newer.  See URL `http://sphinx-doc.org'."
9791   :command ("sphinx-build" "-b" "pseudoxml"
9792             "-q" "-N"                   ; Reduced output and no colors
9793             (option-flag "-n" flycheck-sphinx-warn-on-missing-references)
9794             (eval (flycheck-locate-sphinx-source-directory))
9795             temporary-directory         ; Redirect the output to a temporary
9796                                         ; directory
9797             source-original)            ; Sphinx needs the original document
9798   :error-patterns
9799   ((warning line-start (file-name) ":" line ": WARNING: " (message) line-end)
9800    (error line-start
9801           (file-name) ":" line
9802           ": " (or "ERROR" "SEVERE") ": "
9803           (message) line-end))
9804   :modes rst-mode
9805   :predicate (lambda () (and (flycheck-buffer-saved-p)
9806                              (flycheck-locate-sphinx-source-directory))))
9807
9808 (defun flycheck-ruby--find-project-root (_checker)
9809   "Compute an appropriate working-directory for flycheck-ruby.
9810
9811 This is either a parent directory containing a Gemfile, or nil."
9812   (and
9813    buffer-file-name
9814    (locate-dominating-file buffer-file-name "Gemfile")))
9815
9816 (flycheck-def-config-file-var flycheck-rubocoprc ruby-rubocop ".rubocop.yml"
9817   :safe #'stringp)
9818
9819 (flycheck-def-option-var flycheck-rubocop-lint-only nil ruby-rubocop
9820   "Whether to only report code issues in Rubocop.
9821
9822 When non-nil, only report code issues in Rubocop, via `--lint'.
9823 Otherwise report style issues as well."
9824   :safe #'booleanp
9825   :type 'boolean
9826   :package-version '(flycheck . "0.16"))
9827
9828 (flycheck-define-checker ruby-rubocop
9829   "A Ruby syntax and style checker using the RuboCop tool.
9830
9831 You need at least RuboCop 0.34 for this syntax checker.
9832
9833 See URL `http://batsov.com/rubocop/'."
9834   :command ("rubocop"
9835             "--display-cop-names"
9836             "--force-exclusion"
9837             "--format" "emacs"
9838             ;; Explicitly disable caching to prevent Rubocop 0.35.1 and earlier
9839             ;; from caching standard input.  Later versions of Rubocop
9840             ;; automatically disable caching with --stdin, see
9841             ;; https://github.com/flycheck/flycheck/issues/844 and
9842             ;; https://github.com/bbatsov/rubocop/issues/2576
9843             "--cache" "false"
9844             (config-file "--config" flycheck-rubocoprc)
9845             (option-flag "--lint" flycheck-rubocop-lint-only)
9846             ;; Rubocop takes the original file name as argument when reading
9847             ;; from standard input
9848             "--stdin" source-original)
9849   :standard-input t
9850   :working-directory flycheck-ruby--find-project-root
9851   :error-patterns
9852   ((info line-start (file-name) ":" line ":" column ": C: "
9853          (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end)
9854    (warning line-start (file-name) ":" line ":" column ": W: "
9855             (optional (id (one-or-more (not (any ":")))) ": ") (message)
9856             line-end)
9857    (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": "
9858           (optional (id (one-or-more (not (any ":")))) ": ") (message)
9859           line-end))
9860   :modes (enh-ruby-mode ruby-mode)
9861   :next-checkers ((warning . ruby-reek)
9862                   (warning . ruby-rubylint)))
9863
9864 ;; Default to `nil' to let Reek find its configuration file by itself
9865 (flycheck-def-config-file-var flycheck-reekrc ruby-reek nil
9866   :safe #'string-or-null-p
9867   :package-version '(flycheck . "30"))
9868
9869 (flycheck-define-checker ruby-reek
9870   "A Ruby smell checker using reek.
9871
9872 See URL `https://github.com/troessner/reek'."
9873   :command ("reek" "--format" "json"
9874             (config-file "--config" flycheck-reekrc)
9875             source)
9876   :error-parser flycheck-parse-reek
9877   :modes (enh-ruby-mode ruby-mode)
9878   :next-checkers ((warning . ruby-rubylint)))
9879
9880 ;; Default to `nil' to let Rubylint find its configuration file by itself, and
9881 ;; to maintain backwards compatibility with older Rubylint and Flycheck releases
9882 (flycheck-def-config-file-var flycheck-rubylintrc ruby-rubylint nil
9883   :safe #'stringp)
9884
9885 (flycheck-define-checker ruby-rubylint
9886   "A Ruby syntax and code analysis checker using ruby-lint.
9887
9888 Requires ruby-lint 2.0.2 or newer.  See URL
9889 `https://github.com/YorickPeterse/ruby-lint'."
9890   :command ("ruby-lint" "--presenter=syntastic"
9891             (config-file "--config" flycheck-rubylintrc)
9892             source)
9893   ;; Ruby Lint can't read from standard input
9894   :error-patterns
9895   ((info line-start
9896          (file-name) ":I:" line ":" column ": " (message) line-end)
9897    (warning line-start
9898             (file-name) ":W:" line ":" column ": " (message) line-end)
9899    (error line-start
9900           (file-name) ":E:" line ":" column ": " (message) line-end))
9901   :modes (enh-ruby-mode ruby-mode))
9902
9903 (flycheck-define-checker ruby
9904   "A Ruby syntax checker using the standard Ruby interpreter.
9905
9906 Please note that the output of different Ruby versions and
9907 implementations varies wildly.  This syntax checker supports
9908 current versions of MRI and JRuby, but may break when used with
9909 other implementations or future versions of these
9910 implementations.
9911
9912 Please consider using `ruby-rubocop' or `ruby-reek' instead.
9913
9914 See URL `https://www.ruby-lang.org/'."
9915   :command ("ruby" "-w" "-c")
9916   :standard-input t
9917   :error-patterns
9918   ;; These patterns support output from JRuby, too, to deal with RVM or Rbenv
9919   ((error line-start "SyntaxError in -:" line ": " (message) line-end)
9920    (warning line-start "-:" line ":" (optional column ":")
9921             " warning: " (message) line-end)
9922    (error line-start "-:" line ": " (message) line-end))
9923   :modes (enh-ruby-mode ruby-mode)
9924   :next-checkers ((warning . ruby-rubylint)))
9925
9926 (flycheck-define-checker ruby-jruby
9927   "A Ruby syntax checker using the JRuby interpreter.
9928
9929 This syntax checker is very primitive, and may break on future
9930 versions of JRuby.
9931
9932 Please consider using `ruby-rubocop' or `ruby-rubylint' instead.
9933
9934 See URL `http://jruby.org/'."
9935   :command ("jruby" "-w" "-c")
9936   :standard-input t
9937   :error-patterns
9938   ((error   line-start "SyntaxError in -:" line ": " (message) line-end)
9939    (warning line-start "-:" line ": warning: " (message) line-end)
9940    (error   line-start "-:" line ": "          (message) line-end))
9941   :modes (enh-ruby-mode ruby-mode)
9942   :next-checkers ((warning . ruby-rubylint)))
9943
9944 (flycheck-def-args-var flycheck-cargo-check-args (rust-cargo)
9945   :package-version '(flycheck . "32"))
9946
9947 (flycheck-def-args-var flycheck-rust-args (rust)
9948   :package-version '(flycheck . "0.24"))
9949
9950 (flycheck-def-option-var flycheck-rust-check-tests t (rust-cargo rust)
9951   "Whether to check test code in Rust.
9952
9953 For the `rust' checker: When non-nil, `rustc' is passed the
9954 `--test' flag, which will check any code marked with the
9955 `#[cfg(test)]' attribute and any functions marked with
9956 `#[test]'. Otherwise, `rustc' is not passed `--test' and test
9957 code will not be checked.  Skipping `--test' is necessary when
9958 using `#![no_std]', because compiling the test runner requires
9959 `std'.
9960
9961 For the `rust-cargo' checker: When non-nil, calls `cargo test
9962 --no-run' instead of `cargo check'."
9963   :type 'boolean
9964   :safe #'booleanp
9965   :package-version '("flycheck" . "0.19"))
9966
9967 (flycheck-def-option-var flycheck-rust-crate-root nil rust
9968   "A path to the crate root for the current buffer.
9969
9970 The value of this variable is either a string with the path to
9971 the crate root for the current buffer, or nil if the current buffer
9972 is a crate.  A relative path is relative to the current buffer.
9973
9974 If this variable is non nil the current buffer will only be checked
9975 if it is not modified, i.e. after it has been saved."
9976   :type 'string
9977   :package-version '(flycheck . "0.20")
9978   :safe #'stringp)
9979 (make-variable-buffer-local 'flycheck-rust-crate-root)
9980
9981 (flycheck-def-option-var flycheck-rust-crate-type "lib" (rust-cargo rust)
9982   "The type of the Rust Crate to check.
9983
9984 For `rust-cargo', the value should be a string denoting the
9985 target type passed to Cargo.  See
9986 `flycheck-rust-valid-crate-type-p' for the list of allowed
9987 values.
9988
9989 For `rust', the value should be a string denoting the crate type
9990 for the `--crate-type' flag of rustc."
9991   :type '(choice (const :tag "nil (rust/rust-cargo)" nil)
9992                  (const :tag "lib (rust/rust-cargo)" "lib")
9993                  (const :tag "bin (rust/rust-cargo)" "bin")
9994                  (const :tag "example (rust-cargo)" "example")
9995                  (const :tag "test (rust-cargo)" "test")
9996                  (const :tag "bench (rust-cargo)" "bench")
9997                  (const :tag "rlib (rust)" "rlib")
9998                  (const :tag "dylib (rust)" "dylib")
9999                  (const :tag "cdylib (rust)" "cdylib")
10000                  (const :tag "staticlib (rust)" "staticlib")
10001                  (const :tag "metadata (rust)" "metadata"))
10002   :safe #'stringp
10003   :package-version '(flycheck . "0.20"))
10004 (make-variable-buffer-local 'flycheck-rust-crate-type)
10005
10006 (flycheck-def-option-var flycheck-rust-binary-name nil rust-cargo
10007   "The name of the binary to pass to `cargo check --CRATE-TYPE'.
10008
10009 The value of this variable is a string denoting the name of the
10010 target to check: usually the name of the crate, or the name of
10011 one of the files under `src/bin', `tests', `examples' or
10012 `benches'.
10013
10014 This always requires a non-nil value, unless
10015 `flycheck-rust-crate-type' is `lib' or nil, in which case it is
10016 ignored."
10017   :type 'string
10018   :safe #'stringp
10019   :package-version '(flycheck . "28"))
10020 (make-variable-buffer-local 'flycheck-rust-binary-name)
10021
10022 (flycheck-def-option-var flycheck-rust-features nil rust-cargo
10023   "List of features to activate during build or check.
10024
10025 The value of this variable is a list of strings denoting features
10026 that will be activated to build the target to check. Features will
10027 be passed to `cargo check --features=FEATURES'."
10028   :type '(repeat :tag "Features to activate"
10029                  (string :tag "Feature"))
10030   :safe #'flycheck-string-list-p
10031   :package-version '(flycheck . "32"))
10032 (make-variable-buffer-local 'flycheck-rust-features)
10033
10034 (flycheck-def-option-var flycheck-rust-library-path nil rust
10035   "A list of library directories for Rust.
10036
10037 The value of this variable is a list of strings, where each
10038 string is a directory to add to the library path of Rust.
10039 Relative paths are relative to the file being checked."
10040   :type '(repeat (directory :tag "Library directory"))
10041   :safe #'flycheck-string-list-p
10042   :package-version '(flycheck . "0.18"))
10043
10044 (defun flycheck-rust-error-explainer (error)
10045   "Return an explanation text for the given `flycheck-error' ERROR."
10046   (-when-let (error-code (flycheck-error-id error))
10047     (with-output-to-string
10048       (call-process "rustc" nil standard-output nil "--explain" error-code))))
10049
10050 (defun flycheck-rust-error-filter (errors)
10051   "Filter ERRORS from rustc output that have no explanatory value."
10052   (seq-remove
10053    (lambda (err)
10054      (or
10055       ;; Macro errors emit a diagnostic in a phony file,
10056       ;; e.g. "<println macros>".
10057       (-when-let (filename (flycheck-error-filename err))
10058         (string-match-p (rx "macros>" line-end) filename))
10059       ;; Redundant message giving the number of failed errors
10060       (-when-let (msg (flycheck-error-message err))
10061         (string-match-p
10062          (rx
10063           (or (: "aborting due to " (optional (one-or-more num) " ")
10064                  "previous error")
10065               (: "For more information about this error, try `rustc --explain "
10066                  (one-or-more alnum) "`.")))
10067          msg))))
10068    errors))
10069
10070 (defun flycheck-rust-manifest-directory ()
10071   "Return the nearest directory holding the Cargo manifest.
10072
10073 Return the nearest directory containing the `Cargo.toml' manifest
10074 file, starting from the current buffer and using
10075 `locate-dominating-file'.  Return nil if there is no such file,
10076 or if the current buffer has no file name."
10077   (and buffer-file-name
10078        (locate-dominating-file buffer-file-name "Cargo.toml")))
10079
10080 (defun flycheck-rust-cargo-metadata ()
10081   "Run 'cargo metadata' and return the result as parsed JSON object."
10082   (car (flycheck-parse-json
10083         (with-output-to-string
10084           (call-process "cargo" nil standard-output nil
10085                         "metadata" "--no-deps" "--format-version" "1")))))
10086
10087 (defun flycheck-rust-cargo-workspace-root ()
10088   "Return the path to the workspace root of a Rust Cargo project.
10089
10090 Return nil if the workspace root does not exist (for Rust
10091 versions inferior to 1.25)."
10092   (let-alist (flycheck-rust-cargo-metadata)
10093     .workspace_root))
10094
10095 (defun flycheck-rust-cargo-has-command-p (command)
10096   "Whether Cargo has COMMAND in its list of commands.
10097
10098 Execute `cargo --list' to find out whether COMMAND is present."
10099   (let ((cargo (funcall flycheck-executable-find "cargo")))
10100     (member command (mapcar #'string-trim-left
10101                             (ignore-errors (process-lines cargo "--list"))))))
10102
10103 (defun flycheck-rust-valid-crate-type-p (crate-type)
10104   "Whether CRATE-TYPE is a valid target type for Cargo.
10105
10106 A valid Cargo target type is one of `lib', `bin', `example',
10107 `test' or `bench'."
10108   (member crate-type '(nil "lib" "bin" "example" "test" "bench")))
10109
10110 (flycheck-define-checker rust-cargo
10111   "A Rust syntax checker using Cargo.
10112
10113 This syntax checker requires Rust 1.17 or newer.  See URL
10114 `https://www.rust-lang.org'."
10115   :command ("cargo"
10116             (eval (if flycheck-rust-check-tests
10117                       "test"
10118                     "check"))
10119             (eval (when flycheck-rust-check-tests
10120                     "--no-run"))
10121             (eval (when flycheck-rust-crate-type
10122                     (concat "--" flycheck-rust-crate-type)))
10123             ;; All crate targets except "lib" need a binary name
10124             (eval (when (and flycheck-rust-crate-type
10125                              (not (string= flycheck-rust-crate-type "lib")))
10126                     flycheck-rust-binary-name))
10127             (option "--features=" flycheck-rust-features concat
10128                     flycheck-option-comma-separated-list)
10129             (eval flycheck-cargo-check-args)
10130             "--message-format=json")
10131   :error-parser flycheck-parse-cargo-rustc
10132   :error-filter (lambda (errors)
10133                   ;; In Rust 1.25+, filenames are relative to the workspace
10134                   ;; root.
10135                   (let ((root (flycheck-rust-cargo-workspace-root)))
10136                     (seq-do (lambda (err)
10137                               ;; Some errors are crate level and do not have a
10138                               ;; filename
10139                               (when (flycheck-error-filename err)
10140                                 (setf (flycheck-error-filename err)
10141                                       (expand-file-name
10142                                        (flycheck-error-filename err) root))))
10143                             (flycheck-rust-error-filter errors))))
10144   :error-explainer flycheck-rust-error-explainer
10145   :modes rust-mode
10146   :predicate flycheck-buffer-saved-p
10147   :enabled flycheck-rust-manifest-directory
10148   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
10149   :verify
10150   (lambda (_)
10151     (and buffer-file-name
10152          (let* ((has-toml (flycheck-rust-manifest-directory))
10153                 (valid-crate-type (flycheck-rust-valid-crate-type-p
10154                                    flycheck-rust-crate-type))
10155                 (need-binary-name
10156                  (and flycheck-rust-crate-type
10157                       (not (string= flycheck-rust-crate-type "lib")))))
10158            (list
10159             (flycheck-verification-result-new
10160              :label "Cargo.toml"
10161              :message (if has-toml "Found" "Missing")
10162              :face (if has-toml 'success '(bold warning)))
10163             (flycheck-verification-result-new
10164              :label "Crate type"
10165              :message (if valid-crate-type
10166                           (format "%s" flycheck-rust-crate-type)
10167                         (format "%s (invalid, should be one of 'lib', 'bin', \
10168 'test', 'example' or 'bench')"
10169                                 flycheck-rust-crate-type))
10170              :face (if valid-crate-type 'success '(bold error)))
10171             (flycheck-verification-result-new
10172              :label "Binary name"
10173              :message (cond
10174                        ((not need-binary-name) "Not required")
10175                        ((not flycheck-rust-binary-name) "Required")
10176                        (t (format "%s" flycheck-rust-binary-name)))
10177              :face (cond
10178                     ((not need-binary-name) 'success)
10179                     ((not flycheck-rust-binary-name) '(bold error))
10180                     (t 'success))))))))
10181
10182 (flycheck-define-checker rust
10183   "A Rust syntax checker using Rust compiler.
10184
10185 This syntax checker needs Rust 1.18 or newer.  See URL
10186 `https://www.rust-lang.org'."
10187   :command ("rustc"
10188             (option "--crate-type" flycheck-rust-crate-type)
10189             "--emit=mir" "-o" "/dev/null" ; avoid creating binaries
10190             "--error-format=json"
10191             (option-flag "--test" flycheck-rust-check-tests)
10192             (option-list "-L" flycheck-rust-library-path concat)
10193             (eval flycheck-rust-args)
10194             (eval (or flycheck-rust-crate-root
10195                       (flycheck-substitute-argument 'source-original 'rust))))
10196   :error-parser flycheck-parse-rustc
10197   :error-filter flycheck-rust-error-filter
10198   :error-explainer flycheck-rust-error-explainer
10199   :modes rust-mode
10200   :predicate flycheck-buffer-saved-p)
10201
10202 (flycheck-define-checker rust-clippy
10203   "A Rust syntax checker using clippy.
10204
10205 See URL `https://github.com/rust-lang-nursery/rust-clippy'."
10206   :command ("cargo" "clippy" "--message-format=json")
10207   :error-parser flycheck-parse-cargo-rustc
10208   :error-filter flycheck-rust-error-filter
10209   :error-explainer flycheck-rust-error-explainer
10210   :modes rust-mode
10211   :predicate flycheck-buffer-saved-p
10212   :enabled (lambda ()
10213              (and (flycheck-rust-cargo-has-command-p "clippy")
10214                   (flycheck-rust-manifest-directory)))
10215   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
10216   :verify
10217   (lambda (_)
10218     (and buffer-file-name
10219          (let ((has-toml (flycheck-rust-manifest-directory))
10220                (has-clippy (flycheck-rust-cargo-has-command-p "clippy")))
10221            (list
10222             (flycheck-verification-result-new
10223              :label "Clippy"
10224              :message (if has-clippy "Found"
10225                         "Cannot find the `cargo clippy' command")
10226              :face (if has-clippy 'success '(bold warning)))
10227             (flycheck-verification-result-new
10228              :label "Cargo.toml"
10229              :message (if has-toml "Found" "Missing")
10230              :face (if has-toml 'success '(bold warning))))))))
10231
10232 (defvar flycheck-sass-scss-cache-directory nil
10233   "The cache directory for `sass' and `scss'.")
10234
10235 (defun flycheck-sass-scss-cache-location ()
10236   "Get the cache location for `sass' and `scss'.
10237
10238 If no cache directory exists yet, create one and return it.
10239 Otherwise return the previously used cache directory."
10240   (setq flycheck-sass-scss-cache-directory
10241         (or flycheck-sass-scss-cache-directory
10242             (make-temp-file "flycheck-sass-scss-cache" 'directory))))
10243
10244 (flycheck-def-option-var flycheck-sass-compass nil sass
10245   "Whether to enable the Compass CSS framework.
10246
10247 When non-nil, enable the Compass CSS framework, via `--compass'."
10248   :type 'boolean
10249   :safe #'booleanp
10250   :package-version '(flycheck . "0.16"))
10251
10252 (flycheck-define-checker sass
10253   "A Sass syntax checker using the Sass compiler.
10254
10255 See URL `http://sass-lang.com'."
10256   :command ("sass"
10257             "--cache-location" (eval (flycheck-sass-scss-cache-location))
10258             (option-flag "--compass" flycheck-sass-compass)
10259             "--check" "--stdin")
10260   :standard-input t
10261   :error-patterns
10262   ((error line-start
10263           (or "Syntax error: " "Error: ")
10264           (message (one-or-more not-newline)
10265                    (zero-or-more "\n"
10266                                  (one-or-more " ")
10267                                  (one-or-more not-newline)))
10268           (optional "\r") "\n" (one-or-more " ") "on line " line
10269           " of standard input"
10270           line-end)
10271    (warning line-start
10272             "WARNING: "
10273             (message (one-or-more not-newline)
10274                      (zero-or-more "\n"
10275                                    (one-or-more " ")
10276                                    (one-or-more not-newline)))
10277             (optional "\r") "\n" (one-or-more " ") "on line " line
10278             " of " (one-or-more not-newline)
10279             line-end))
10280   :modes sass-mode)
10281
10282 (flycheck-def-config-file-var flycheck-sass-lintrc sass/scss-sass-lint
10283                               ".sass-lint.yml"
10284   :safe #'stringp
10285   :package-version '(flycheck . "30"))
10286
10287 (flycheck-define-checker sass/scss-sass-lint
10288   "A SASS/SCSS syntax checker using sass-Lint.
10289
10290 See URL `https://github.com/sasstools/sass-lint'."
10291   :command ("sass-lint"
10292             "--verbose"
10293             "--no-exit"
10294             "--format" "Checkstyle"
10295             (config-file "--config" flycheck-sass-lintrc)
10296             source)
10297   :error-parser flycheck-parse-checkstyle
10298   :modes (sass-mode scss-mode))
10299
10300 (flycheck-define-checker scala
10301   "A Scala syntax checker using the Scala compiler.
10302
10303 See URL `https://www.scala-lang.org/'."
10304   :command ("scalac" "-Ystop-after:parser" source)
10305   :error-patterns
10306   ((error line-start (file-name) ":" line ": error: " (message) line-end))
10307   :modes scala-mode
10308   :next-checkers ((warning . scala-scalastyle)))
10309
10310 (flycheck-def-config-file-var flycheck-scalastylerc scala-scalastyle nil
10311   :safe #'stringp
10312   :package-version '(flycheck . "0.20"))
10313
10314 (flycheck-define-checker scala-scalastyle
10315   "A Scala style checker using scalastyle.
10316
10317 Note that this syntax checker is not used if
10318 `flycheck-scalastylerc' is nil or refers to a non-existing file.
10319
10320 See URL `http://www.scalastyle.org'."
10321   :command ("scalastyle"
10322             (config-file "-c" flycheck-scalastylerc)
10323             source)
10324   :error-patterns
10325   ((error line-start "error file=" (file-name) " message="
10326           (message) " line=" line (optional " column=" column) line-end)
10327    (warning line-start "warning file=" (file-name) " message="
10328             (message) " line=" line (optional " column=" column) line-end))
10329   :error-filter (lambda (errors)
10330                   (flycheck-sanitize-errors
10331                    (flycheck-increment-error-columns errors)))
10332   :modes scala-mode
10333   :predicate
10334   ;; Inhibit this syntax checker if the JAR or the configuration are unset or
10335   ;; missing
10336   (lambda () (and flycheck-scalastylerc
10337                   (flycheck-locate-config-file flycheck-scalastylerc
10338                                                'scala-scalastyle)))
10339   :verify (lambda (checker)
10340             (let ((config-file (and flycheck-scalastylerc
10341                                     (flycheck-locate-config-file
10342                                      flycheck-scalastylerc checker))))
10343               (list
10344                (flycheck-verification-result-new
10345                 :label "Configuration file"
10346                 :message (cond
10347                           ((not flycheck-scalastylerc)
10348                            "`flycheck-scalastyletrc' not set")
10349                           ((not config-file)
10350                            (format "file %s not found" flycheck-scalastylerc))
10351                           (t (format "found at %s" config-file)))
10352                 :face (cond
10353                        ((not flycheck-scalastylerc) '(bold warning))
10354                        ((not config-file) '(bold error))
10355                        (t 'success)))))))
10356
10357 (flycheck-def-args-var flycheck-scheme-chicken-args scheme-chicken
10358   :package-version '(flycheck . "32"))
10359
10360 (flycheck-define-checker scheme-chicken
10361   "A CHICKEN Scheme syntax checker using the CHICKEN compiler `csc'.
10362
10363 See URL `http://call-cc.org/'."
10364   :command ("csc" "-analyze-only" "-local"
10365             (eval flycheck-scheme-chicken-args)
10366             source)
10367   :error-patterns
10368   ((info line-start
10369          "Note: " (zero-or-more not-newline) ":\n"
10370          (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
10371          line-end)
10372    (warning line-start
10373             "Warning: " (zero-or-more not-newline) ",\n"
10374             (one-or-more (any space)) (zero-or-more not-newline) ":\n"
10375             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
10376             line-end)
10377    (warning line-start
10378             "Warning: " (zero-or-more not-newline) ":\n"
10379             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
10380             line-end)
10381    (error line-start "Error: (line " line ") " (message) line-end)
10382    (error line-start "Syntax error: (" (file-name) ":" line ")"
10383           (zero-or-more not-newline) " - "
10384           (message (one-or-more not-newline)
10385                    (zero-or-more "\n"
10386                                  (zero-or-more space)
10387                                  (zero-or-more not-newline))
10388                    (one-or-more space) "<--")
10389           line-end)
10390    ;; A of version 4.12.0, the chicken compiler doesn't provide a
10391    ;; line number for this error.
10392    (error line-start "Syntax error: "
10393           (message (one-or-more not-newline)
10394                    (zero-or-more "\n"
10395                                  (zero-or-more space)
10396                                  (zero-or-more not-newline))
10397                    (one-or-more space) "<--")
10398           line-end)
10399    (error line-start
10400           "Error: " (zero-or-more not-newline) ":\n"
10401           (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
10402           line-end)
10403    ;; A of version 4.12.0, the chicken compiler doesn't provide a
10404    ;; line number for this error.
10405    (error line-start "Error: "
10406           (message (one-or-more not-newline)
10407                    (zero-or-more "\n"
10408                                  (zero-or-more space)
10409                                  (zero-or-more not-newline))
10410                    (one-or-more space) "<--")))
10411   :error-filter flycheck-fill-empty-line-numbers
10412   :predicate
10413   (lambda ()
10414     ;; In `scheme-mode' we must check the current Scheme implementation
10415     ;; being used
10416     (and (boundp 'geiser-impl--implementation)
10417          (eq geiser-impl--implementation 'chicken)))
10418   :verify
10419   (lambda (_checker)
10420     (let ((geiser-impl (bound-and-true-p geiser-impl--implementation)))
10421       (list
10422        (flycheck-verification-result-new
10423         :label "Geiser Implementation"
10424         :message (cond
10425                   ((eq geiser-impl 'chicken) "Chicken Scheme")
10426                   (geiser-impl (format "Other: %s" geiser-impl))
10427                   (t "Geiser not active"))
10428         :face (cond
10429                ((eq geiser-impl 'chicken) 'success)
10430                (t '(bold error)))))))
10431   :modes scheme-mode)
10432
10433 (defconst flycheck-scss-lint-checkstyle-re
10434   (rx "cannot load such file" (1+ not-newline) "scss_lint_reporter_checkstyle")
10435   "Regular expression to parse missing checkstyle error.")
10436
10437 (defun flycheck-parse-scss-lint (output checker buffer)
10438   "Parse SCSS-Lint OUTPUT from CHECKER and BUFFER.
10439
10440 Like `flycheck-parse-checkstyle', but catches errors about
10441 missing checkstyle reporter from SCSS-Lint."
10442   (if (string-match-p flycheck-scss-lint-checkstyle-re output)
10443       (list (flycheck-error-new-at
10444              1 nil 'error "Checkstyle reporter for SCSS-Lint missing.
10445 Please run gem install scss_lint_reporter_checkstyle"
10446              :checker checker
10447              :buffer buffer
10448              :filename (buffer-file-name buffer)))
10449     (flycheck-parse-checkstyle output checker buffer)))
10450
10451 (flycheck-def-config-file-var flycheck-scss-lintrc scss-lint ".scss-lint.yml"
10452   :safe #'stringp
10453   :package-version '(flycheck . "0.23"))
10454
10455 (flycheck-define-checker scss-lint
10456   "A SCSS syntax checker using SCSS-Lint.
10457
10458 Needs SCSS-Lint 0.43.2 or newer.
10459
10460 See URL `https://github.com/brigade/scss-lint'."
10461   :command ("scss-lint"
10462             "--require=scss_lint_reporter_checkstyle"
10463             "--format=Checkstyle"
10464             (config-file "--config" flycheck-scss-lintrc)
10465             "--stdin-file-path" source-original "-")
10466   :standard-input t
10467   ;; We cannot directly parse Checkstyle XML, since for some mysterious reason
10468   ;; SCSS-Lint doesn't have a built-in Checkstyle reporter, and instead ships it
10469   ;; as an addon which might not be installed.  We use a custom error parser to
10470   ;; check whether the addon is missing and turn that into a special kind of
10471   ;; Flycheck error.
10472   :error-parser flycheck-parse-scss-lint
10473   :modes scss-mode
10474   :verify
10475   (lambda (checker)
10476     (let* ((executable (flycheck-find-checker-executable checker))
10477            (reporter-missing
10478             (and executable
10479                  (with-temp-buffer
10480                    (call-process executable nil t nil
10481                                  "--require=scss_lint_reporter_checkstyle")
10482                    (goto-char (point-min))
10483                    (re-search-forward
10484                     flycheck-scss-lint-checkstyle-re
10485                     nil 'no-error)))))
10486       (when executable
10487         (list
10488          (flycheck-verification-result-new
10489           :label "checkstyle reporter"
10490           :message (if reporter-missing
10491                        "scss_lint_reporter_checkstyle missing"
10492                      "present")
10493           :face (if reporter-missing
10494                     '(bold error)
10495                   'success)))))))
10496
10497 (flycheck-define-checker scss-stylelint
10498   "A SCSS syntax and style checker using stylelint.
10499
10500 See URL `http://stylelint.io/'."
10501   :command ("stylelint"
10502             (eval flycheck-stylelint-args)
10503             "--syntax" "scss"
10504             (option-flag "--quiet" flycheck-stylelint-quiet)
10505             (config-file "--config" flycheck-stylelintrc))
10506   :standard-input t
10507   :error-parser flycheck-parse-stylelint
10508   :modes (scss-mode))
10509
10510 (flycheck-def-option-var flycheck-scss-compass nil scss
10511   "Whether to enable the Compass CSS framework.
10512
10513 When non-nil, enable the Compass CSS framework, via `--compass'."
10514   :type 'boolean
10515   :safe #'booleanp
10516   :package-version '(flycheck . "0.16"))
10517
10518 (flycheck-define-checker scss
10519   "A SCSS syntax checker using the SCSS compiler.
10520
10521 See URL `http://sass-lang.com'."
10522   :command ("scss"
10523             "--cache-location" (eval (flycheck-sass-scss-cache-location))
10524             (option-flag "--compass" flycheck-scss-compass)
10525             "--check" "--stdin")
10526   :standard-input t
10527   :error-patterns
10528   ((error line-start
10529           (or "Syntax error: " "Error: ")
10530           (message (one-or-more not-newline)
10531                    (zero-or-more "\n"
10532                                  (one-or-more " ")
10533                                  (one-or-more not-newline)))
10534           (optional "\r") "\n" (one-or-more " ") "on line " line
10535           " of standard input"
10536           line-end)
10537    (warning line-start
10538             "WARNING: "
10539             (message (one-or-more not-newline)
10540                      (zero-or-more "\n"
10541                                    (one-or-more " ")
10542                                    (one-or-more not-newline)))
10543             (optional "\r") "\n" (one-or-more " ") "on line " line
10544             " of an unknown file"
10545             line-end))
10546   :modes scss-mode)
10547
10548 (flycheck-def-args-var flycheck-sh-bash-args (sh-bash)
10549   :package-version '(flycheck . "32"))
10550
10551 (flycheck-define-checker sh-bash
10552   "A Bash syntax checker using the Bash shell.
10553
10554 See URL `http://www.gnu.org/software/bash/'."
10555   :command ("bash" "--norc" "-n"
10556             (eval flycheck-sh-bash-args)
10557             "--")
10558   :standard-input t
10559   :error-patterns
10560   ((error line-start
10561           ;; The name/path of the bash executable
10562           (one-or-more (not (any ":"))) ":"
10563           ;; A label "line", possibly localized
10564           (one-or-more (not (any digit)))
10565           line (zero-or-more " ") ":" (zero-or-more " ")
10566           (message) line-end))
10567   :modes sh-mode
10568   :predicate (lambda () (eq sh-shell 'bash))
10569   :next-checkers ((warning . sh-shellcheck)))
10570
10571 (flycheck-define-checker sh-posix-dash
10572   "A POSIX Shell syntax checker using the Dash shell.
10573
10574 See URL `http://gondor.apana.org.au/~herbert/dash/'."
10575   :command ("dash" "-n")
10576   :standard-input t
10577   :error-patterns
10578   ((error line-start (one-or-more (not (any ":"))) ": " line ": " (message)))
10579   :modes sh-mode
10580   :predicate (lambda () (eq sh-shell 'sh))
10581   :next-checkers ((warning . sh-shellcheck)))
10582
10583 (flycheck-define-checker sh-posix-bash
10584   "A POSIX Shell syntax checker using the Bash shell.
10585
10586 See URL `http://www.gnu.org/software/bash/'."
10587   :command ("bash" "--posix" "--norc" "-n" "--")
10588   :standard-input t
10589   :error-patterns
10590   ((error line-start
10591           ;; The name/path of the bash executable
10592           (one-or-more (not (any ":"))) ":"
10593           ;; A label "line", possibly localized
10594           (one-or-more (not (any digit)))
10595           line (zero-or-more " ") ":" (zero-or-more " ")
10596           (message) line-end))
10597   :modes sh-mode
10598   :predicate (lambda () (eq sh-shell 'sh))
10599   :next-checkers ((warning . sh-shellcheck)))
10600
10601 (flycheck-define-checker sh-zsh
10602   "A Zsh syntax checker using the Zsh shell.
10603
10604 See URL `http://www.zsh.org/'."
10605   :command ("zsh" "--no-exec" "--no-globalrcs" "--no-rcs" source)
10606   :error-patterns
10607   ((error line-start (file-name) ":" line ": " (message) line-end))
10608   :modes sh-mode
10609   :predicate (lambda () (eq sh-shell 'zsh))
10610   :next-checkers ((warning . sh-shellcheck)))
10611
10612 (defconst flycheck-shellcheck-supported-shells '(bash ksh88 sh)
10613   "Shells supported by ShellCheck.")
10614
10615 (flycheck-def-option-var flycheck-shellcheck-excluded-warnings nil sh-shellcheck
10616   "A list of excluded warnings for ShellCheck.
10617
10618 The value of this variable is a list of strings, where each
10619 string is a warning code to be excluded from ShellCheck reports.
10620 By default, no warnings are excluded."
10621   :type '(repeat :tag "Excluded warnings"
10622                  (string :tag "Warning code"))
10623   :safe #'flycheck-string-list-p
10624   :package-version '(flycheck . "0.21"))
10625
10626 (flycheck-def-option-var flycheck-shellcheck-follow-sources t sh-shellcheck
10627   "Whether to follow external sourced files in scripts.
10628
10629 Shellcheck will follow and parse sourced files so long as a
10630 pre-runtime resolvable path to the file is present.  This can
10631 either be part of the source command itself:
10632    source /full/path/to/file.txt
10633 or added as a shellcheck directive before the source command:
10634    # shellcheck source=/full/path/to/file.txt."
10635   :type 'boolean
10636   :safe #'booleanp
10637   :package-version '(flycheck . "31"))
10638
10639 (flycheck-define-checker sh-shellcheck
10640   "A shell script syntax and style checker using Shellcheck.
10641
10642 See URL `https://github.com/koalaman/shellcheck/'."
10643   :command ("shellcheck"
10644             "--format" "checkstyle"
10645             "--shell" (eval (symbol-name sh-shell))
10646             (option-flag "--external-sources"
10647                          flycheck-shellcheck-follow-sources)
10648             (option "--exclude" flycheck-shellcheck-excluded-warnings list
10649                     flycheck-option-comma-separated-list)
10650             "-")
10651   :standard-input t
10652   :error-parser flycheck-parse-checkstyle
10653   :error-filter
10654   (lambda (errors)
10655     (flycheck-remove-error-file-names
10656      "-" (flycheck-dequalify-error-ids errors)))
10657   :modes sh-mode
10658   :predicate (lambda () (memq sh-shell flycheck-shellcheck-supported-shells))
10659   :verify (lambda (_)
10660             (let ((supports-shell (memq sh-shell
10661                                         flycheck-shellcheck-supported-shells)))
10662               (list
10663                (flycheck-verification-result-new
10664                 :label (format "Shell %s supported" sh-shell)
10665                 :message (if supports-shell "yes" "no")
10666                 :face (if supports-shell 'success '(bold warning)))))))
10667
10668 (flycheck-define-checker slim
10669   "A Slim syntax checker using the Slim compiler.
10670
10671 See URL `http://slim-lang.com'."
10672   :command ("slimrb" "--compile")
10673   :standard-input t
10674   :error-patterns
10675   ((error line-start
10676           "Slim::Parser::SyntaxError:" (message) (optional "\r") "\n  "
10677           "STDIN, Line " line (optional ", Column " column)
10678           line-end))
10679   :modes slim-mode
10680   :next-checkers ((warning . slim-lint)))
10681
10682 (flycheck-define-checker slim-lint
10683   "A Slim linter.
10684
10685 See URL `https://github.com/sds/slim-lint'."
10686   :command ("slim-lint" "--reporter=checkstyle" source)
10687   :error-parser flycheck-parse-checkstyle
10688   :modes slim-mode)
10689
10690 (flycheck-define-checker sql-sqlint
10691   "A SQL syntax checker using the sqlint tool.
10692
10693 See URL `https://github.com/purcell/sqlint'."
10694   :command ("sqlint")
10695   :standard-input t
10696   :error-patterns
10697   ((warning line-start "stdin:" line ":" column ":WARNING "
10698             (message (one-or-more not-newline)
10699                      (zero-or-more "\n"
10700                                    (one-or-more "  ")
10701                                    (one-or-more not-newline)))
10702             line-end)
10703    (error line-start "stdin:" line ":" column ":ERROR "
10704           (message (one-or-more not-newline)
10705                    (zero-or-more "\n"
10706                                  (one-or-more "  ")
10707                                  (one-or-more not-newline)))
10708           line-end))
10709   :modes (sql-mode))
10710
10711 (flycheck-define-checker systemd-analyze
10712   "A systemd unit checker using systemd-analyze(1).
10713
10714 See URL
10715 `https://www.freedesktop.org/software/systemd/man/systemd-analyze.html'."
10716   :command ("systemd-analyze" "verify" source)
10717   :error-patterns
10718   ((error line-start "[" (file-name) ":" line "] " (message) line-end))
10719   :modes (systemd-mode))
10720
10721 (flycheck-def-config-file-var flycheck-chktexrc tex-chktex ".chktexrc"
10722   :safe #'stringp)
10723
10724 (flycheck-define-checker tcl-nagelfar
10725   "An extensible tcl syntax checker
10726
10727 See URL `http://nagelfar.sourceforge.net/'."
10728   :command ("nagelfar" "-H" source)
10729   :error-patterns
10730   ;; foo.tcl: 29: E Wrong number of arguments (4) to "set"
10731   ;; foo.tcl: 29: W Expr without braces
10732   ((info    line-start (file-name) ": " line ": N " (message) line-end)
10733    (warning line-start (file-name) ": " line ": W " (message) line-end)
10734    (error   line-start (file-name) ": " line ": E " (message) line-end))
10735   :modes tcl-mode)
10736
10737 (flycheck-define-checker tex-chktex
10738   "A TeX and LaTeX syntax and style checker using chktex.
10739
10740 See URL `http://www.nongnu.org/chktex/'."
10741   :command ("chktex"
10742             (config-file "--localrc" flycheck-chktexrc)
10743             ;; Compact error messages, and no version information, and execute
10744             ;; \input statements
10745             "--verbosity=0" "--quiet" "--inputfiles")
10746   :standard-input t
10747   :error-patterns
10748   ((warning line-start "stdin:" line ":" column ":"
10749             (id (one-or-more digit)) ":" (message) line-end))
10750   :error-filter
10751   (lambda (errors)
10752     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
10753   :modes (latex-mode plain-tex-mode))
10754
10755 (flycheck-define-checker tex-lacheck
10756   "A LaTeX syntax and style checker using lacheck.
10757
10758 See URL `http://www.ctan.org/pkg/lacheck'."
10759   :command ("lacheck" source-inplace)
10760   :error-patterns
10761   ((warning line-start
10762             "\"" (file-name) "\", line " line ": " (message)
10763             line-end))
10764   :modes latex-mode)
10765
10766 (flycheck-define-checker texinfo
10767   "A Texinfo syntax checker using makeinfo.
10768
10769 See URL `http://www.gnu.org/software/texinfo/'."
10770   :command ("makeinfo" "-o" null-device "-")
10771   :standard-input t
10772   :error-patterns
10773   ((warning line-start
10774             "-:" line (optional ":" column) ": " "warning: " (message)
10775             line-end)
10776    (error line-start
10777           "-:" line (optional ":" column) ": " (message)
10778           line-end))
10779   :modes texinfo-mode)
10780
10781 (flycheck-def-config-file-var flycheck-textlint-config
10782     textlint "textlintrc.json"
10783   :safe #'stringp)
10784
10785 ;; This needs to be set because textlint plugins are installed seperately,
10786 ;; and there is no way to check their installation status -- textlint simply
10787 ;; prints a backtrace.
10788 (flycheck-def-option-var flycheck-textlint-plugin-alist
10789     '((markdown-mode . "@textlint/markdown")
10790       (gfm-mode . "@textlint/markdown")
10791       (t . "@textlint/text"))
10792     textlint
10793   "An alist mapping major modes to textlint plugins.
10794
10795 Each item is a cons cell `(MAJOR-MODE . PLUGIN)', where MAJOR-MODE is a mode
10796 `flycheck-textlint' supports and PLUGIN is a textlint plugin. As a catch-all,
10797 when MAJOR-MODE is t, that PLUGIN will be used for any supported mode that
10798 isn't specified.
10799
10800 See URL `https://npms.io/search?q=textlint-plugin' for all textlint plugins
10801 published on NPM."
10802   :type '(repeat (choice (cons symbol string)
10803                          (cons (const t) string))))
10804
10805 (defun flycheck--textlint-get-plugin ()
10806   "Return the textlint plugin for the current mode."
10807   (cdr (-first
10808         (lambda (arg)
10809           (pcase-let ((`(,mode . _) arg))
10810             (or (and (booleanp mode) mode) ; mode is t
10811                 (derived-mode-p mode))))
10812         flycheck-textlint-plugin-alist)))
10813
10814 (flycheck-define-checker textlint
10815   "A text prose linter using textlint.
10816
10817 See URL `https://textlint.github.io/'."
10818   :command ("textlint"
10819             (config-file "--config" flycheck-textlint-config)
10820             "--format" "json"
10821             ;; get the first matching plugin from plugin-alist
10822             "--plugin"
10823             (eval (flycheck--textlint-get-plugin))
10824             source)
10825   ;; textlint seems to say that its json output is compatible with ESLint.
10826   ;; https://textlint.github.io/docs/formatter.html
10827   :error-parser flycheck-parse-eslint
10828   ;; textlint can support different formats with textlint plugins, but
10829   ;; only text and markdown formats are installed by default. Ask the
10830   ;; user to add mode->plugin mappings manually in
10831   ;; `flycheck-textlint-plugin-alist'.
10832   :modes
10833   (text-mode markdown-mode gfm-mode message-mode adoc-mode
10834              mhtml-mode latex-mode org-mode rst-mode)
10835   :enabled
10836   (lambda () (flycheck--textlint-get-plugin))
10837   :verify
10838   (lambda (_)
10839     (let ((plugin (flycheck--textlint-get-plugin)))
10840       (list
10841        (flycheck-verification-result-new
10842         :label "textlint plugin"
10843         :message plugin
10844         :face 'success)))))
10845
10846 (flycheck-def-config-file-var flycheck-typescript-tslint-config
10847     typescript-tslint "tslint.json"
10848   :safe #'stringp
10849   :package-version '(flycheck . "27"))
10850
10851 (flycheck-def-option-var flycheck-typescript-tslint-rulesdir
10852     nil typescript-tslint
10853   "The directory of custom rules for TSLint.
10854
10855 The value of this variable is either a string containing the path
10856 to a directory with custom rules, or nil, to not give any custom
10857 rules to TSLint.
10858
10859 Refer to the TSLint manual at URL
10860 `http://palantir.github.io/tslint/usage/cli/'
10861 for more information about the custom directory."
10862   :type '(choice (const :tag "No custom rules directory" nil)
10863                  (directory :tag "Custom rules directory"))
10864   :safe #'stringp
10865   :package-version '(flycheck . "27"))
10866
10867 (flycheck-def-args-var flycheck-tslint-args (typescript-tslint)
10868   :package-version '(flycheck . "31"))
10869
10870 (flycheck-define-checker typescript-tslint
10871   "TypeScript style checker using TSLint.
10872
10873 Note that this syntax checker is not used if
10874 `flycheck-typescript-tslint-config' is nil or refers to a
10875 non-existing file.
10876
10877 See URL `https://github.com/palantir/tslint'."
10878   :command ("tslint" "--format" "json"
10879             (config-file "--config" flycheck-typescript-tslint-config)
10880             (option "--rules-dir" flycheck-typescript-tslint-rulesdir)
10881             (eval flycheck-tslint-args)
10882             source-inplace)
10883   :error-parser flycheck-parse-tslint
10884   :modes (typescript-mode))
10885
10886 (flycheck-def-option-var flycheck-verilator-include-path nil verilog-verilator
10887   "A list of include directories for Verilator.
10888
10889 The value of this variable is a list of strings, where each
10890 string is a directory to add to the include path of Verilator.
10891 Relative paths are relative to the file being checked."
10892   :type '(repeat (directory :tag "Include directory"))
10893   :safe #'flycheck-string-list-p
10894   :package-version '(flycheck . "0.24"))
10895
10896 (flycheck-define-checker verilog-verilator
10897   "A Verilog syntax checker using the Verilator Verilog HDL simulator.
10898
10899 See URL `https://www.veripool.org/wiki/verilator'."
10900   :command ("verilator" "--lint-only" "-Wall"
10901             (option-list "-I" flycheck-verilator-include-path concat)
10902             source)
10903   :error-patterns
10904   ((warning line-start "%Warning-" (zero-or-more not-newline) ": "
10905             (file-name) ":" line ": " (message) line-end)
10906    (error line-start "%Error: " (file-name) ":"
10907           line ": " (message) line-end))
10908   :modes verilog-mode)
10909
10910 (flycheck-def-option-var flycheck-ghdl-language-standard nil vhdl-ghdl
10911   "The language standard to use in GHDL.
10912
10913 The value of this variable is either a string denoting a language
10914 standard, or nil, to use the default standard.  When non-nil,
10915 pass the language standard via the `--std' option."
10916   :type '(choice (const :tag "Default standard" nil)
10917                  (string :tag "Language standard"))
10918   :safe #'stringp
10919   :package-version '(flycheck . "32"))
10920 (make-variable-buffer-local 'flycheck-ghdl-language-standard)
10921
10922 (flycheck-def-option-var flycheck-ghdl-workdir nil vhdl-ghdl
10923   "The directory to use for the file library.
10924
10925 The value of this variable is either a string with the directory
10926 to use for the file library, or nil, to use the default value.
10927 When non-nil, pass the directory via the `--workdir' option."
10928   :type '(choice (const :tag "Default directory" nil)
10929                  (string :tag "Directory for the file library"))
10930   :safe #'stringp
10931   :package-version '(flycheck . "32"))
10932 (make-variable-buffer-local 'flycheck-ghdl-workdir)
10933
10934 (flycheck-def-option-var flycheck-ghdl-ieee-library nil vhdl-ghdl
10935   "The standard to use for the IEEE library.
10936
10937 The value of this variable is either a string denoting an ieee library
10938 standard, or nil, to use the default standard.  When non-nil,
10939 pass the ieee library standard via the `--ieee' option."
10940   :type '(choice (const :tag "Default standard" nil)
10941                  (const :tag "No IEEE Library" "none")
10942                  (const :tag "IEEE standard" "standard")
10943                  (const :tag "Synopsys standard" "synopsys")
10944                  (const :tag "Mentor standard" "mentor"))
10945   :safe #'stringp
10946   :package-version '(flycheck . "32"))
10947 (make-variable-buffer-local 'flycheck-ghdl-ieee-library)
10948
10949 (flycheck-define-checker vhdl-ghdl
10950   "A VHDL syntax checker using GHDL.
10951
10952 See URL `https://github.com/ghdl/ghdl'."
10953   :command ("ghdl"
10954             "-s" ; only do the syntax checking
10955             (option "--std=" flycheck-ghdl-language-standard concat)
10956             (option "--workdir=" flycheck-ghdl-workdir concat)
10957             (option "--ieee=" flycheck-ghdl-ieee-library concat)
10958             source)
10959   :error-patterns
10960   ((error line-start (file-name) ":" line ":" column ": " (message) line-end))
10961   :modes vhdl-mode)
10962
10963 (flycheck-def-option-var flycheck-xml-xmlstarlet-xsd-path nil xml-xmlstarlet
10964   "An XSD schema to validate against."
10965   :type '(file :tag "XSD schema")
10966   :safe #'stringp
10967   :package-version '(flycheck . "31"))
10968
10969 (flycheck-define-checker xml-xmlstarlet
10970   "A XML syntax checker and validator using the xmlstarlet utility.
10971
10972 See URL `http://xmlstar.sourceforge.net/'."
10973   ;; Validate standard input with verbose error messages, and do not dump
10974   ;; contents to standard output
10975   :command ("xmlstarlet" "val" "--err" "--quiet"
10976             (option "--xsd" flycheck-xml-xmlstarlet-xsd-path)
10977             "-")
10978   :standard-input t
10979   :error-patterns
10980   ((error line-start "-:" line "." column ": " (message) line-end))
10981   :modes (xml-mode nxml-mode))
10982
10983 (flycheck-def-option-var flycheck-xml-xmllint-xsd-path nil xml-xmllint
10984   "An XSD schema to validate against."
10985   :type '(file :tag "XSD schema")
10986   :safe #'stringp
10987   :package-version '(flycheck . "31"))
10988
10989 (flycheck-define-checker xml-xmllint
10990   "A XML syntax checker and validator using the xmllint utility.
10991
10992 The xmllint is part of libxml2, see URL
10993 `http://www.xmlsoft.org/'."
10994   :command ("xmllint" "--noout"
10995             (option "--schema" flycheck-xml-xmllint-xsd-path)
10996             "-")
10997   :standard-input t
10998   :error-patterns
10999   ((error line-start "-:" line ": " (message) line-end))
11000   :modes (xml-mode nxml-mode))
11001
11002 (flycheck-define-checker yaml-jsyaml
11003   "A YAML syntax checker using JS-YAML.
11004
11005 See URL `https://github.com/nodeca/js-yaml'."
11006   :command ("js-yaml")
11007   :standard-input t
11008   :error-patterns
11009   ((error line-start
11010           (or "JS-YAML" "YAMLException") ": "
11011           (message) " at line " line ", column " column ":"
11012           line-end))
11013   :modes yaml-mode
11014   :next-checkers ((warning . cwl)))
11015
11016 (flycheck-define-checker yaml-ruby
11017   "A YAML syntax checker using Ruby's YAML parser.
11018
11019 This syntax checker uses the YAML parser from Ruby's standard
11020 library.
11021
11022 See URL `http://www.ruby-doc.org/stdlib-2.0.0/libdoc/yaml/rdoc/YAML.html'."
11023   :command ("ruby" "-ryaml" "-e" "begin;
11024    YAML.load(STDIN); \
11025  rescue Exception => e; \
11026    STDERR.puts \"stdin:#{e}\"; \
11027  end")
11028   :standard-input t
11029   :error-patterns
11030   ((error line-start "stdin:" (zero-or-more not-newline) ":" (message)
11031           "at line " line " column " column line-end))
11032   :modes yaml-mode
11033   :next-checkers ((warning . cwl)))
11034
11035 (provide 'flycheck)
11036
11037 ;; Local Variables:
11038 ;; coding: utf-8
11039 ;; indent-tabs-mode: nil
11040 ;; End:
11041
11042 ;;; flycheck.el ends here