mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-17 c4001ccd1864293b64aa37d83a9d9457eb875e70
commit | author | age
5cb5f7 1 ;;; flycheck.el --- On-the-fly syntax checking -*- lexical-binding: t; -*-
C 2
3 ;; Copyright (C) 2017-2018 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
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
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     cwl
177     d-dmd
178     dockerfile-hadolint
179     emacs-lisp
180     emacs-lisp-checkdoc
181     erlang-rebar3
182     erlang
183     eruby-erubis
184     fortran-gfortran
185     go-gofmt
186     go-golint
187     go-vet
188     go-build
189     go-test
190     go-errcheck
191     go-unconvert
192     go-megacheck
193     groovy
194     haml
195     handlebars
196     haskell-stack-ghc
197     haskell-ghc
198     haskell-hlint
199     html-tidy
200     javascript-eslint
201     javascript-jshint
202     javascript-standard
203     json-jsonlint
204     json-python-json
205     jsonnet
206     less
207     less-stylelint
208     llvm-llc
209     lua-luacheck
210     lua
211     markdown-markdownlint-cli
212     markdown-mdl
213     nix
214     perl
215     perl-perlcritic
216     php
217     php-phpmd
218     php-phpcs
219     processing
220     proselint
221     protobuf-protoc
222     pug
223     puppet-parser
224     puppet-lint
225     python-flake8
226     python-pylint
227     python-pycompile
228     python-mypy
229     r-lintr
230     racket
231     rpm-rpmlint
232     rst-sphinx
233     rst
234     ruby-rubocop
235     ruby-reek
236     ruby-rubylint
237     ruby
238     ruby-jruby
239     rust-cargo
240     rust
241     rust-clippy
242     scala
243     scala-scalastyle
244     scheme-chicken
245     scss-lint
246     scss-stylelint
247     sass/scss-sass-lint
248     sass
249     scss
250     sh-bash
251     sh-posix-dash
252     sh-posix-bash
253     sh-zsh
254     sh-shellcheck
255     slim
256     slim-lint
257     sql-sqlint
258     systemd-analyze
259     tcl-nagelfar
260     tex-chktex
261     tex-lacheck
262     texinfo
263     typescript-tslint
264     verilog-verilator
265     vhdl-ghdl
266     xml-xmlstarlet
267     xml-xmllint
268     yaml-jsyaml
269     yaml-ruby)
270   "Syntax checkers available for automatic selection.
271
272 A list of Flycheck syntax checkers to choose from when syntax
273 checking a buffer.  Flycheck will automatically select a suitable
274 syntax checker from this list, unless `flycheck-checker' is set,
275 either directly or with `flycheck-select-checker'.
276
277 You should not need to change this variable normally.  In order
278 to disable syntax checkers, please use
279 `flycheck-disabled-checkers'.  This variable is intended for 3rd
280 party extensions to tell Flycheck about new syntax checkers.
281
282 Syntax checkers in this list must be defined with
283 `flycheck-define-checker'."
284   :group 'flycheck
285   :type '(repeat (symbol :tag "Checker"))
286   :risky t)
287
288 (defcustom flycheck-disabled-checkers nil
289   "Syntax checkers excluded from automatic selection.
290
291 A list of Flycheck syntax checkers to exclude from automatic
292 selection.  Flycheck will never automatically select a syntax
293 checker in this list, regardless of the value of
294 `flycheck-checkers'.
295
296 However, syntax checkers in this list are still available for
297 manual selection with `flycheck-select-checker'.
298
299 Use this variable to disable syntax checkers, instead of removing
300 the syntax checkers from `flycheck-checkers'.  You may also use
301 this option as a file or directory local variable to disable
302 specific checkers in individual files and directories
303 respectively."
304   :group 'flycheck
305   :type '(repeat (symbol :tag "Checker"))
306   :package-version '(flycheck . "0.16")
307   :safe #'flycheck-symbol-list-p)
308 (make-variable-buffer-local 'flycheck-disabled-checkers)
309
310 (defvar-local flycheck-checker nil
311   "Syntax checker to use for the current buffer.
312
313 If unset or nil, automatically select a suitable syntax checker
314 from `flycheck-checkers' on every syntax check.
315
316 If set to a syntax checker only use this syntax checker and never
317 select one from `flycheck-checkers' automatically.  The syntax
318 checker is used regardless of whether it is contained in
319 `flycheck-checkers' or `flycheck-disabled-checkers'.  If the
320 syntax checker is unusable in the current buffer an error is
321 signaled.
322
323 A syntax checker assigned to this variable must be defined with
324 `flycheck-define-checker'.
325
326 Use the command `flycheck-select-checker' to select a syntax
327 checker for the current buffer, or set this variable as file
328 local variable to always use a specific syntax checker for a
329 file.  See Info Node `(emacs)Specifying File Variables' for more
330 information about file variables.")
331 (put 'flycheck-checker 'safe-local-variable 'flycheck-registered-checker-p)
332
333 (defcustom flycheck-locate-config-file-functions nil
334   "Functions to locate syntax checker configuration files.
335
336 Each function in this hook must accept two arguments: The value
337 of the configuration file variable, and the syntax checker
338 symbol.  It must return either a string with an absolute path to
339 the configuration file, or nil, if it cannot locate the
340 configuration file.
341
342 The functions in this hook are called in order of appearance, until a
343 function returns non-nil.  The configuration file returned by that
344 function is then given to the syntax checker if it exists.
345
346 This variable is an abnormal hook.  See Info
347 node `(elisp)Hooks'."
348   :group 'flycheck
349   :type 'hook
350   :risky t)
351
352 (defcustom flycheck-checker-error-threshold 400
353   "Maximum errors allowed per syntax checker.
354
355 The value of this variable is either an integer denoting the
356 maximum number of errors per syntax checker and buffer, or nil to
357 not limit the errors reported from a syntax checker.
358
359 If this variable is a number and a syntax checker reports more
360 errors than the value of this variable, its errors are not
361 discarded, and not highlighted in the buffer or available in the
362 error list.  The affected syntax checker is also disabled for
363 future syntax checks of the buffer."
364   :group 'flycheck
365   :type '(choice (const :tag "Do not limit reported errors" nil)
366                  (integer :tag "Maximum number of errors"))
367   :risky t
368   :package-version '(flycheck . "0.22"))
369
370 (defcustom flycheck-process-error-functions nil
371   "Functions to process errors.
372
373 Each function in this hook must accept a single argument: A
374 Flycheck error to process.
375
376 All functions in this hook are called in order of appearance,
377 until a function returns non-nil.  Thus, a function in this hook
378 may return nil, to allow for further processing of the error, or
379 any non-nil value, to indicate that the error was fully processed
380 and inhibit any further processing.
381
382 The functions are called for each newly parsed error immediately
383 after the corresponding syntax checker finished.  At this stage,
384 the overlays from the previous syntax checks are still present,
385 and there may be further syntax checkers in the chain.
386
387 This variable is an abnormal hook.  See Info
388 node `(elisp)Hooks'."
389   :group 'flycheck
390   :type 'hook
391   :package-version '(flycheck . "0.13")
392   :risky t)
393
394 (defcustom flycheck-display-errors-delay 0.9
395   "Delay in seconds before displaying errors at point.
396
397 Use floating point numbers to express fractions of seconds."
398   :group 'flycheck
399   :type 'number
400   :package-version '(flycheck . "0.15")
401   :safe #'numberp)
402
403 (defcustom flycheck-display-errors-function #'flycheck-display-error-messages
404   "Function to display error messages.
405
406 If set to a function, call the function with the list of errors
407 to display as single argument.  Each error is an instance of the
408 `flycheck-error' struct.
409
410 If set to nil, do not display errors at all."
411   :group 'flycheck
412   :type '(choice (const :tag "Display error messages"
413                         flycheck-display-error-messages)
414                  (const :tag "Display error messages only if no error list"
415                         flycheck-display-error-messages-unless-error-list)
416                  (function :tag "Error display function"))
417   :package-version '(flycheck . "0.13")
418   :risky t)
419
420 (defcustom flycheck-help-echo-function #'flycheck-help-echo-all-error-messages
421   "Function to compute the contents of the error tooltips.
422
423 If set to a function, call the function with the list of errors
424 to display as single argument.  Each error is an instance of the
425 `flycheck-error' struct.  The function is used to set the
426 help-echo property of flycheck error overlays.  It should return
427 a string, which is displayed when the user hovers over an error
428 or presses \\[display-local-help].
429
430 If set to nil, do not show error tooltips."
431   :group 'flycheck
432   :type '(choice (const :tag "Concatenate error messages to form a tooltip"
433                         flycheck-help-echo-all-error-messages)
434                  (function :tag "Help echo function"))
435   :package-version '(flycheck . "0.25")
436   :risky t)
437
438 (defcustom flycheck-command-wrapper-function #'identity
439   "Function to modify checker commands before execution.
440
441 The value of this option is a function which is given a list
442 containing the full command of a syntax checker after
443 substitution through `flycheck-substitute-argument' but before
444 execution.  The function may return a new command for Flycheck to
445 execute.
446
447 The default value is `identity' which does not change the
448 command.  You may provide your own function to run Flycheck
449 commands through `bundle exec', `nix-shell' or similar wrappers."
450   :group 'flycheck
451   :type '(choice (const :tag "Do not modify commands" identity)
452                  (function :tag "Modify command with a custom function"))
453   :package-version '(flycheck . "0.25")
454   :risky t)
455
456 (defcustom flycheck-executable-find #'flycheck-default-executable-find
457   "Function to search for executables.
458
459 The value of this option is a function which is given the name or
460 path of an executable and shall return the full path to the
461 executable, or nil if the executable does not exit.
462
463 The default is `flycheck-default-executable-find', which searches
464 `exec-path' when given a command name, and resolves paths to
465 absolute ones.  You can customize this option to search for
466 checkers in other environments such as bundle or NixOS
467 sandboxes."
468   :group 'flycheck
469   :type '(choice
470           (const :tag "Search executables in `exec-path'"
471                  flycheck-default-executable-find)
472           (function :tag "Search executables with a custom function"))
473   :package-version '(flycheck . "32")
474   :risky t)
475
476 (defun flycheck-default-executable-find (executable)
477   "Resolve EXECUTABLE to a full path.
478
479 Like `executable-find', but supports relative paths.
480
481 Attempts invoking `executable-find' first; if that returns nil,
482 and EXECUTABLE contains a directory component, expands to a full
483 path and tries invoking `executable-find' again."
484   ;; file-name-directory returns non-nil iff the given path has a
485   ;; directory component.
486   (or
487    (executable-find executable)
488    (when (file-name-directory executable)
489      (executable-find (expand-file-name executable)))))
490
491 (defcustom flycheck-indication-mode 'left-fringe
492   "The indication mode for Flycheck errors and warnings.
493
494 This variable controls how Flycheck indicates errors in buffers.
495 May either be `left-fringe', `right-fringe', or nil.
496
497 If set to `left-fringe' or `right-fringe', indicate errors and
498 warnings via icons in the left and right fringe respectively.
499
500 If set to nil, do not indicate errors and warnings, but just
501 highlight them according to `flycheck-highlighting-mode'."
502   :group 'flycheck
503   :type '(choice (const :tag "Indicate in the left fringe" left-fringe)
504                  (const :tag "Indicate in the right fringe" right-fringe)
505                  (const :tag "Do not indicate" nil))
506   :safe #'symbolp)
507
508 (defcustom flycheck-highlighting-mode 'symbols
509   "The highlighting mode for Flycheck errors and warnings.
510
511 The highlighting mode controls how Flycheck highlights errors in
512 buffers.  The following modes are known:
513
514 `columns'
515      Highlight the error column.  If the error does not have a column,
516      highlight the whole line.
517
518 `symbols'
519      Highlight the symbol at the error column, if there is any,
520      otherwise behave like `columns'.  This is the default.
521
522 `sexps'
523      Highlight the expression at the error column, if there is
524      any, otherwise behave like `columns'.  Note that this mode
525      can be *very* slow in some major modes.
526
527 `lines'
528      Highlight the whole line.
529
530 nil
531      Do not highlight errors at all.  However, errors will still
532      be reported in the mode line and in error message popups,
533      and indicated according to `flycheck-indication-mode'."
534   :group 'flycheck
535   :type '(choice (const :tag "Highlight columns only" columns)
536                  (const :tag "Highlight symbols" symbols)
537                  (const :tag "Highlight expressions" sexps)
538                  (const :tag "Highlight whole lines" lines)
539                  (const :tag "Do not highlight errors" nil))
540   :package-version '(flycheck . "0.14")
541   :safe #'symbolp)
542
543 (defcustom flycheck-check-syntax-automatically '(save
544                                                  idle-change
545                                                  new-line
546                                                  mode-enabled)
547   "When Flycheck should check syntax automatically.
548
549 This variable is a list of events that may trigger syntax checks.
550 The following events are known:
551
552 `save'
553      Check syntax immediately after the buffer was saved.
554
555 `idle-change'
556      Check syntax a short time (see `flycheck-idle-change-delay')
557      after the last change to the buffer.
558
559 `new-line'
560      Check syntax immediately after a new line was inserted into
561      the buffer.
562
563 `mode-enabled'
564      Check syntax immediately when variable `flycheck-mode' is
565      non-nil.
566
567 Flycheck performs a syntax checks only on events, which are
568 contained in this list.  For instance, if the value of this
569 variable is `(mode-enabled save)', Flycheck will only check if
570 the mode is enabled or the buffer was saved, but never after
571 changes to the buffer contents.
572
573 If nil, never check syntax automatically.  In this case, use
574 `flycheck-buffer' to start a syntax check manually."
575   :group 'flycheck
576   :type '(set (const :tag "After the buffer was saved" save)
577               (const :tag "After the buffer was changed and idle" idle-change)
578               (const :tag "After a new line was inserted" new-line)
579               (const :tag "After `flycheck-mode' was enabled" mode-enabled))
580   :package-version '(flycheck . "0.12")
581   :safe #'flycheck-symbol-list-p)
582
583 (defcustom flycheck-idle-change-delay 0.5
584   "How many seconds to wait before checking syntax automatically.
585
586 After the buffer was changed, Flycheck will wait as many seconds
587 as the value of this variable before starting a syntax check.  If
588 the buffer is modified during this time, Flycheck will wait
589 again.
590
591 This variable has no effect, if `idle-change' is not contained in
592 `flycheck-check-syntax-automatically'."
593   :group 'flycheck
594   :type 'number
595   :package-version '(flycheck . "0.13")
596   :safe #'numberp)
597
598 (defcustom flycheck-standard-error-navigation t
599   "Whether to support error navigation with `next-error'.
600
601 If non-nil, enable navigation of Flycheck errors with
602 `next-error', `previous-error' and `first-error'.  Otherwise,
603 these functions just navigate errors from compilation modes.
604
605 Flycheck error navigation with `flycheck-next-error',
606 `flycheck-previous-error' and `flycheck-first-error' is always
607 enabled, regardless of the value of this variable.
608
609 Note that this setting only takes effect when variable
610 `flycheck-mode' is non-nil.  Changing it will not affect buffers
611 where variable `flycheck-mode' is already non-nil."
612   :group 'flycheck
613   :type 'boolean
614   :package-version '(flycheck . "0.15")
615   :safe #'booleanp)
616
617 (define-widget 'flycheck-minimum-level 'lazy
618   "A radio-type choice of minimum error levels.
619
620 See `flycheck-navigation-minimum-level' and
621 `flycheck-error-list-minimum-level'."
622   :type '(radio (const :tag "All locations" nil)
623                 (const :tag "Informational messages" info)
624                 (const :tag "Warnings" warning)
625                 (const :tag "Errors" error)
626                 (symbol :tag "Custom error level")))
627
628 (defcustom flycheck-navigation-minimum-level nil
629   "The minimum level of errors to navigate.
630
631 If set to an error level, only navigate errors whose error level
632 is at least as severe as this one.  If nil, navigate all errors."
633   :group 'flycheck
634   :type 'flycheck-minimum-level
635   :safe #'flycheck-error-level-p
636   :package-version '(flycheck . "0.21"))
637
638 (defcustom flycheck-error-list-minimum-level nil
639   "The minimum level of errors to display in the error list.
640
641 If set to an error level, only display errors whose error level
642 is at least as severe as this one in the error list.  If nil,
643 display all errors.
644
645 This is the default level, used when the error list is opened.
646 You can temporarily change the level using
647 \\[flycheck-error-list-set-filter], or reset it to this value
648 using \\[flycheck-error-list-reset-filter]."
649   :group 'flycheck
650   :type 'flycheck-minimum-level
651   :safe #'flycheck-error-level-p
652   :package-version '(flycheck . "0.24"))
653
654 (defcustom flycheck-completing-read-function #'completing-read
655   "Function to read from minibuffer with completion.
656
657 The function must be compatible to the built-in `completing-read'
658 function."
659   :group 'flycheck
660   :type '(choice (const :tag "Default" completing-read)
661                  (const :tag "IDO" ido-completing-read)
662                  (function :tag "Custom function"))
663   :risky t
664   :package-version '(flycheck . "26"))
665
666 (defcustom flycheck-temp-prefix "flycheck"
667   "Prefix for temporary files created by Flycheck."
668   :group 'flycheck
669   :type 'string
670   :package-version '(flycheck . "0.19")
671   :risky t)
672
673 (defcustom flycheck-mode-hook nil
674   "Hooks to run after command `flycheck-mode' is toggled."
675   :group 'flycheck
676   :type 'hook
677   :risky t)
678
679 (defcustom flycheck-after-syntax-check-hook nil
680   "Functions to run after each syntax check.
681
682 This hook is run after a syntax check was finished.
683
684 At this point, *all* chained checkers were run, and all errors
685 were parsed, highlighted and reported.  The variable
686 `flycheck-current-errors' contains all errors from all syntax
687 checkers run during the syntax check, so you can apply any error
688 analysis functions.
689
690 Note that this hook does *not* run after each individual syntax
691 checker in the syntax checker chain, but only after the *last
692 checker*.
693
694 This variable is a normal hook.  See Info node `(elisp)Hooks'."
695   :group 'flycheck
696   :type 'hook
697   :risky t)
698
699 (defcustom flycheck-before-syntax-check-hook nil
700   "Functions to run before each syntax check.
701
702 This hook is run right before a syntax check starts.
703
704 Error information from the previous syntax check is *not*
705 cleared before this hook runs.
706
707 Note that this hook does *not* run before each individual syntax
708 checker in the syntax checker chain, but only before the *first
709 checker*.
710
711 This variable is a normal hook.  See Info node `(elisp)Hooks'."
712   :group 'flycheck
713   :type 'hook
714   :risky t)
715
716 (defcustom flycheck-syntax-check-failed-hook nil
717   "Functions to run if a syntax check failed.
718
719 This hook is run whenever an error occurs during Flycheck's
720 internal processing.  No information about the error is given to
721 this hook.
722
723 You should use this hook to conduct additional cleanup actions
724 when Flycheck failed.
725
726 This variable is a normal hook.  See Info node `(elisp)Hooks'."
727   :group 'flycheck
728   :type 'hook
729   :risky t)
730
731 (defcustom flycheck-status-changed-functions nil
732   "Functions to run if the Flycheck status changed.
733
734 This hook is run whenever the status of Flycheck changes.  Each
735 hook function takes the status symbol as single argument, as
736 given to `flycheck-report-status', which see.
737
738 This variable is an abnormal hook.  See Info
739 node `(elisp)Hooks'."
740   :group 'flycheck
741   :type 'hook
742   :risky t
743   :package-version '(flycheck . "0.20"))
744
745 (defcustom flycheck-error-list-after-refresh-hook nil
746   "Functions to run after the error list was refreshed.
747
748 This hook is run whenever the error list is refreshed.
749
750 This variable is a normal hook.  See Info node `(elisp)Hooks'."
751   :group 'flycheck
752   :type 'hook
753   :risky t
754   :package-version '(flycheck . "0.21"))
755
756 (defface flycheck-error
757   '((((supports :underline (:style wave)))
758      :underline (:style wave :color "Red1"))
759     (t
760      :underline t :inherit error))
761   "Flycheck face for errors."
762   :package-version '(flycheck . "0.13")
763   :group 'flycheck-faces)
764
765 (defface flycheck-warning
766   '((((supports :underline (:style wave)))
767      :underline (:style wave :color "DarkOrange"))
768     (t
769      :underline t :inherit warning))
770   "Flycheck face for warnings."
771   :package-version '(flycheck . "0.13")
772   :group 'flycheck-faces)
773
774 (defface flycheck-info
775   '((((supports :underline (:style wave)))
776      :underline (:style wave :color "ForestGreen"))
777     (t
778      :underline t :inherit success))
779   "Flycheck face for informational messages."
780   :package-version '(flycheck . "0.15")
781   :group 'flycheck-faces)
782
783 (defface flycheck-fringe-error
784   '((t :inherit error))
785   "Flycheck face for fringe error indicators."
786   :package-version '(flycheck . "0.13")
787   :group 'flycheck-faces)
788
789 (defface flycheck-fringe-warning
790   '((t :inherit warning))
791   "Flycheck face for fringe warning indicators."
792   :package-version '(flycheck . "0.13")
793   :group 'flycheck-faces)
794
795 (defface flycheck-fringe-info
796   ;; Semantically `success' is probably not the right face, but it looks nice as
797   ;; a base face
798   '((t :inherit success))
799   "Flycheck face for fringe info indicators."
800   :package-version '(flycheck . "0.15")
801   :group 'flycheck-faces)
802
803 (defface flycheck-error-list-error
804   '((t :inherit error))
805   "Flycheck face for error messages in the error list."
806   :package-version '(flycheck . "0.16")
807   :group 'flycheck-faces)
808
809 (defface flycheck-error-list-warning
810   '((t :inherit warning))
811   "Flycheck face for warning messages in the error list."
812   :package-version '(flycheck . "0.16")
813   :group 'flycheck-faces)
814
815 (defface flycheck-error-list-info
816   '((t :inherit success))
817   "Flycheck face for info messages in the error list."
818   :package-version '(flycheck . "0.16")
819   :group 'flycheck-faces)
820
821 ;; The base faces for the following two faces are inspired by Compilation Mode
822 (defface flycheck-error-list-line-number
823   '((t :inherit font-lock-constant-face))
824   "Face for line numbers in the error list."
825   :group 'flycheck-faces
826   :package-version '(flycheck . "0.16"))
827
828 (defface flycheck-error-list-column-number
829   '((t :inherit font-lock-constant-face))
830   "Face for line numbers in the error list."
831   :group 'flycheck-faces
832   :package-version '(flycheck . "0.16"))
833
834 (defface flycheck-error-list-filename
835   '((t :inherit font-lock-variable-name-face))
836   "Face for filenames in the error list."
837   :group 'flycheck-faces
838   :package-version '(flycheck . "32"))
839
840 (defface flycheck-error-list-id
841   '((t :inherit font-lock-type-face))
842   "Face for the error ID in the error list."
843   :group 'flycheck-faces
844   :package-version '(flycheck . "0.22"))
845
846 (defface flycheck-error-list-id-with-explainer
847   '((t :inherit flycheck-error-list-id
848        :box (:style released-button)))
849   "Face for the error ID in the error list, for errors that have an explainer."
850   :group 'flycheck-faces
851   :package-version '(flycheck . "30"))
852
853 (defface flycheck-error-list-checker-name
854   '((t :inherit font-lock-function-name-face))
855   "Face for the syntax checker name in the error list."
856   :group 'flycheck-faces
857   :package-version '(flycheck . "0.21"))
858
859 (defface flycheck-error-list-highlight
860   '((t :inherit highlight))
861   "Flycheck face to highlight errors in the error list."
862   :package-version '(flycheck . "0.15")
863   :group 'flycheck-faces)
864
865 (defvar flycheck-command-map
866   (let ((map (make-sparse-keymap)))
867     (define-key map "c"         #'flycheck-buffer)
868     (define-key map "C"         #'flycheck-clear)
869     (define-key map (kbd "C-c") #'flycheck-compile)
870     (define-key map "n"         #'flycheck-next-error)
871     (define-key map "p"         #'flycheck-previous-error)
872     (define-key map "l"         #'flycheck-list-errors)
873     (define-key map (kbd "C-w") #'flycheck-copy-errors-as-kill)
874     (define-key map "s"         #'flycheck-select-checker)
875     (define-key map "?"         #'flycheck-describe-checker)
876     (define-key map "h"         #'flycheck-display-error-at-point)
877     (define-key map "e"         #'flycheck-explain-error-at-point)
878     (define-key map "H"         #'display-local-help)
879     (define-key map "i"         #'flycheck-manual)
880     (define-key map "V"         #'flycheck-version)
881     (define-key map "v"         #'flycheck-verify-setup)
882     (define-key map "x"         #'flycheck-disable-checker)
883     map)
884   "Keymap of Flycheck interactive commands.")
885
886 (defcustom flycheck-keymap-prefix (kbd "C-c !")
887   "Prefix for key bindings of Flycheck.
888
889 Changing this variable outside Customize does not have any
890 effect.  To change the keymap prefix from Lisp, you need to
891 explicitly re-define the prefix key:
892
893     (define-key flycheck-mode-map flycheck-keymap-prefix nil)
894     (setq flycheck-keymap-prefix (kbd \"C-c f\"))
895     (define-key flycheck-mode-map flycheck-keymap-prefix
896                 flycheck-command-map)
897
898 Please note that Flycheck's manual documents the default
899 keybindings.  Changing this variable is at your own risk."
900   :group 'flycheck
901   :package-version '(flycheck . "0.19")
902   :type 'string
903   :risky t
904   :set
905   (lambda (variable key)
906     (when (and (boundp variable) (boundp 'flycheck-mode-map))
907       (define-key flycheck-mode-map (symbol-value variable) nil)
908       (define-key flycheck-mode-map key flycheck-command-map))
909     (set-default variable key)))
910
911 (defcustom flycheck-mode-line '(:eval (flycheck-mode-line-status-text))
912   "Mode line lighter for Flycheck.
913
914 The value of this variable is a mode line template as in
915 `mode-line-format'.  See Info Node `(elisp)Mode Line Format' for
916 more information.  Note that it should contain a _single_ mode
917 line construct only.
918
919 Customize this variable to change how Flycheck reports its status
920 in the mode line.  You may use `flycheck-mode-line-status-text'
921 to obtain a human-readable status text, including an
922 error/warning count.
923
924 You may also assemble your own status text.  The current status
925 of Flycheck is available in `flycheck-last-status-change'.  The
926 errors in the current buffer are stored in
927 `flycheck-current-errors', and the function
928 `flycheck-count-errors' may be used to obtain the number of
929 errors grouped by error level.
930
931 Set this variable to nil to disable the mode line completely."
932   :group 'flycheck
933   :type 'sexp
934   :risky t
935   :package-version '(flycheck . "0.20"))
936
937 (defcustom flycheck-mode-line-prefix "FlyC"
938   "Base mode line lighter for Flycheck.
939
940 This will have an effect only with the default
941 `flycheck-mode-line'.
942
943 If you've customized `flycheck-mode-line' then the customized
944 function must be updated to use this variable."
945   :group 'flycheck
946   :type 'string
947   :package-version '(flycheck . "26"))
948
949 (defcustom flycheck-error-list-mode-line
950   `(,(propertized-buffer-identification "%12b")
951     " for buffer "
952     (:eval (flycheck-error-list-propertized-source-name))
953     (:eval (flycheck-error-list-mode-line-filter-indicator)))
954   "Mode line construct for Flycheck error list.
955
956 The value of this variable is a mode line template as in
957 `mode-line-format', to be used as
958 `mode-line-buffer-identification' in `flycheck-error-list-mode'.
959 See Info Node `(elisp)Mode Line Format' for more information.
960
961 Customize this variable to change how the error list appears in
962 the mode line.  The default shows the name of the buffer and the
963 name of the source buffer, i.e. the buffer whose errors are
964 currently listed."
965   :group 'flycheck
966   :type 'sexp
967   :risky t
968   :package-version '(flycheck . "0.20"))
969
970 (defcustom flycheck-global-modes t
971   "Modes for which option `flycheck-mode' is turned on.
972
973 If t, Flycheck Mode is turned on for all major modes.  If a list,
974 Flycheck Mode is turned on for all `major-mode' symbols in that
975 list.  If the `car' of the list is `not', Flycheck Mode is turned
976 on for all `major-mode' symbols _not_ in that list.  If nil,
977 Flycheck Mode is never turned on by command
978 `global-flycheck-mode'.
979
980 Note that Flycheck is never turned on for modes whose
981 `mode-class' property is `special' (see Info node `(elisp)Major
982 Mode Conventions'), regardless of the value of this option.
983
984 Only has effect when variable `global-flycheck-mode' is non-nil."
985   :group 'flycheck
986   :type '(choice (const :tag "none" nil)
987                  (const :tag "all" t)
988                  (set :menu-tag "mode specific" :tag "modes"
989                       :value (not)
990                       (const :tag "Except" not)
991                       (repeat :inline t (symbol :tag "mode"))))
992   :risky t
993   :package-version '(flycheck . "0.23"))
994
995 ;; Add built-in functions to our hooks, via `add-hook', to make sure that our
996 ;; functions are really present, even if the variable was implicitly defined by
997 ;; another call to `add-hook' that occurred before Flycheck was loaded.  See
998 ;; http://lists.gnu.org/archive/html/emacs-devel/2015-02/msg01271.html for why
999 ;; we don't initialize the hook variables right away.  We append our own
1000 ;; functions, because a user likely expects that their functions come first,
1001 ;; even if the added them before Flycheck was loaded.
1002 (dolist (hook (list #'flycheck-locate-config-file-by-path
1003                     #'flycheck-locate-config-file-ancestor-directories
1004                     #'flycheck-locate-config-file-home))
1005   (add-hook 'flycheck-locate-config-file-functions hook 'append))
1006
1007 (add-hook 'flycheck-process-error-functions #'flycheck-add-overlay 'append)
1008
1009
1010 ;;; Global Flycheck menu
1011 (defvar flycheck-mode-menu-map
1012   (easy-menu-create-menu
1013    "Syntax Checking"
1014    '(["Enable on-the-fly syntax checking" flycheck-mode
1015       :style toggle :selected flycheck-mode
1016       :enable (or flycheck-mode
1017                   ;; Don't let users toggle the mode if there is no syntax
1018                   ;; checker for this buffer
1019                   (seq-find #'flycheck-checker-supports-major-mode-p
1020                             flycheck-checkers))]
1021      ["Check current buffer" flycheck-buffer flycheck-mode]
1022      ["Clear errors in buffer" flycheck-clear t]
1023      "---"
1024      ["Go to next error" flycheck-next-error flycheck-mode]
1025      ["Go to previous error" flycheck-previous-error flycheck-mode]
1026      ["Show all errors" flycheck-list-errors flycheck-mode]
1027      "---"
1028      ["Copy messages at point" flycheck-copy-errors-as-kill
1029       (flycheck-overlays-at (point))]
1030      ["Explain error at point" flycheck-explain-error-at-point]
1031      "---"
1032      ["Select syntax checker" flycheck-select-checker flycheck-mode]
1033      ["Disable syntax checker" flycheck-disable-checker flycheck-mode]
1034      ["Set executable of syntax checker" flycheck-set-checker-executable
1035       flycheck-mode]
1036      "---"
1037      ["Describe syntax checker" flycheck-describe-checker t]
1038      ["Show Flycheck version" flycheck-version t]
1039      ["Read the Flycheck manual" flycheck-info t]))
1040   "Menu of command `flycheck-mode'.")
1041
1042 (easy-menu-add-item nil '("Tools") flycheck-mode-menu-map "Spell Checking")
1043
1044
1045 ;;; Version information, manual and loading of Flycheck
1046 (defun flycheck-version (&optional show-version)
1047   "Get the Flycheck version as string.
1048
1049 If called interactively or if SHOW-VERSION is non-nil, show the
1050 version in the echo area and the messages buffer.
1051
1052 The returned string includes both, the version from package.el
1053 and the library version, if both a present and different.
1054
1055 If the version number could not be determined, signal an error,
1056 if called interactively, or if SHOW-VERSION is non-nil, otherwise
1057 just return nil."
1058   (interactive (list t))
1059   (let ((version (pkg-info-version-info 'flycheck)))
1060     (when show-version
1061       (message "Flycheck version: %s" version))
1062     version))
1063
1064 (defun flycheck-unload-function ()
1065   "Unload function for Flycheck."
1066   (global-flycheck-mode -1)
1067   (easy-menu-remove-item nil '("Tools") (cadr flycheck-mode-menu-map))
1068   (remove-hook 'kill-emacs-hook #'flycheck-global-teardown)
1069   (setq find-function-regexp-alist
1070         (assq-delete-all 'flycheck-checker find-function-regexp-alist)))
1071
1072 ;;;###autoload
1073 (defun flycheck-manual ()
1074   "Open the Flycheck manual."
1075   (interactive)
1076   (browse-url "http://www.flycheck.org"))
1077
1078 (define-obsolete-function-alias 'flycheck-info
1079   'flycheck-manual "26" "Open the Flycheck manual.")
1080
1081
1082 ;;; Utility functions
1083 (defun flycheck-sexp-to-string (sexp)
1084   "Convert SEXP to a string.
1085
1086 Like `prin1-to-string' but ensure that the returned string
1087 is loadable."
1088   (let ((print-quoted t)
1089         (print-length nil)
1090         (print-level nil))
1091     (prin1-to-string sexp)))
1092
1093 (defun flycheck-string-to-number-safe (string)
1094   "Safely convert STRING to a number.
1095
1096 If STRING is of string type and a numeric string, convert STRING
1097 to a number and return it.  Otherwise return nil."
1098   (let ((number-re (rx string-start (one-or-more (any digit)) string-end)))
1099     (when (and (stringp string) (string-match-p number-re string))
1100       (string-to-number string))))
1101
1102 (defun flycheck-string-list-p (obj)
1103   "Determine if OBJ is a list of strings."
1104   (and (listp obj) (seq-every-p #'stringp obj)))
1105
1106 (defun flycheck-symbol-list-p (obj)
1107   "Determine if OBJ is a list of symbols."
1108   (and (listp obj) (seq-every-p #'symbolp obj)))
1109
1110 (defun flycheck-same-files-p (file-a file-b)
1111   "Determine whether FILE-A and FILE-B refer to the same file."
1112   (let ((file-a (expand-file-name file-a))
1113         (file-b (expand-file-name file-b)))
1114     ;; We must resolve symbolic links here, since some syntax checker always
1115     ;; output canonical file names with all symbolic links resolved.  However,
1116     ;; we still do a simple path compassion first, to avoid the comparatively
1117     ;; expensive file system call if possible.  See
1118     ;; https://github.com/flycheck/flycheck/issues/561
1119     (or (string= (directory-file-name file-a) (directory-file-name file-b))
1120         (string= (directory-file-name (file-truename file-a))
1121                  (directory-file-name (file-truename file-b))))))
1122
1123 (defvar-local flycheck-temporaries nil
1124   "Temporary files and directories created by Flycheck.")
1125
1126 (defun flycheck-temp-dir-system ()
1127   "Create a unique temporary directory.
1128
1129 Use `flycheck-temp-prefix' as prefix, and add the directory to
1130 `flycheck-temporaries'.
1131
1132 Return the path of the directory"
1133   (let* ((tempdir (make-temp-file flycheck-temp-prefix 'directory)))
1134     (push tempdir flycheck-temporaries)
1135     tempdir))
1136
1137 (defun flycheck-temp-file-system (filename)
1138   "Create a temporary file named after FILENAME.
1139
1140 If FILENAME is non-nil, this function creates a temporary
1141 directory with `flycheck-temp-dir-system', and creates a file
1142 with the same name as FILENAME in this directory.
1143
1144 Otherwise this function creates a temporary file with
1145 `flycheck-temp-prefix' and a random suffix.  The path of the file
1146 is added to `flycheck-temporaries'.
1147
1148 Return the path of the file."
1149   (let ((tempfile (convert-standard-filename
1150                    (if filename
1151                        (expand-file-name (file-name-nondirectory filename)
1152                                          (flycheck-temp-dir-system))
1153                      (make-temp-file flycheck-temp-prefix)))))
1154     (push tempfile flycheck-temporaries)
1155     tempfile))
1156
1157 (defun flycheck-temp-file-inplace (filename)
1158   "Create an in-place copy of FILENAME.
1159
1160 Prefix the file with `flycheck-temp-prefix' and add the path of
1161 the file to `flycheck-temporaries'.
1162
1163 If FILENAME is nil, fall back to `flycheck-temp-file-system'.
1164
1165 Return the path of the file."
1166   (if filename
1167       (let* ((tempname (format "%s_%s"
1168                                flycheck-temp-prefix
1169                                (file-name-nondirectory filename)))
1170              (tempfile (convert-standard-filename
1171                         (expand-file-name tempname
1172                                           (file-name-directory filename)))))
1173         (push tempfile flycheck-temporaries)
1174         tempfile)
1175     (flycheck-temp-file-system filename)))
1176
1177 (defun flycheck-temp-directory (checker)
1178   "Return the directory where CHECKER writes temporary files.
1179
1180 Return nil if the CHECKER does not write temporary files."
1181   (let ((args (flycheck-checker-arguments checker)))
1182     (cond
1183      ((memq 'source args) temporary-file-directory)
1184      ((memq 'source-inplace args)
1185       (if buffer-file-name (file-name-directory buffer-file-name)
1186         temporary-file-directory))
1187      (t nil))))
1188
1189 (defun flycheck-temp-files-writable-p (checker)
1190   "Whether CHECKER can write temporary files.
1191
1192 If CHECKER has `source' or `source-inplace' in its `:command',
1193 return whether flycheck has the permissions to create the
1194 respective temporary files.
1195
1196 Return t if CHECKER does not use temporary files."
1197   (let ((dir (flycheck-temp-directory checker)))
1198     (or (not dir) (file-writable-p dir))))
1199
1200 (defun flycheck-save-buffer-to-file (file-name)
1201   "Save the contents of the current buffer to FILE-NAME."
1202   (make-directory (file-name-directory file-name) t)
1203   (let ((jka-compr-inhibit t))
1204     (write-region nil nil file-name nil 0)))
1205
1206 (defun flycheck-save-buffer-to-temp (temp-file-fn)
1207   "Save buffer to temp file returned by TEMP-FILE-FN.
1208
1209 Return the name of the temporary file."
1210   (let ((filename (funcall temp-file-fn (buffer-file-name))))
1211     ;; Do not flush short-lived temporary files onto disk
1212     (let ((write-region-inhibit-fsync t))
1213       (flycheck-save-buffer-to-file filename))
1214     filename))
1215
1216 (defun flycheck-prepend-with-option (option items &optional prepend-fn)
1217   "Prepend OPTION to each item in ITEMS, using PREPEND-FN.
1218
1219 Prepend OPTION to each item in ITEMS.
1220
1221 ITEMS is a list of strings to pass to the syntax checker.  OPTION
1222 is the option, as string.  PREPEND-FN is a function called to
1223 prepend OPTION to each item in ITEMS.  It receives the option and
1224 a single item from ITEMS as argument, and must return a string or
1225 a list of strings with OPTION prepended to the item.  If
1226 PREPEND-FN is nil or omitted, use `list'.
1227
1228 Return a list of strings where OPTION is prepended to each item
1229 in ITEMS using PREPEND-FN.  If PREPEND-FN returns a list, it is
1230 spliced into the resulting list."
1231   (unless (stringp option)
1232     (error "Option %S is not a string" option))
1233   (unless prepend-fn
1234     (setq prepend-fn #'list))
1235   (let ((prepend
1236          (lambda (item)
1237            (let ((result (funcall prepend-fn option item)))
1238              (cond
1239               ((and (listp result) (seq-every-p #'stringp result)) result)
1240               ((stringp result) (list result))
1241               (t (error "Invalid result type for option: %S" result)))))))
1242     (apply #'append (seq-map prepend items))))
1243
1244 (defun flycheck-find-in-buffer (pattern)
1245   "Find PATTERN in the current buffer.
1246
1247 Return the result of the first matching group of PATTERN, or nil,
1248 if PATTERN did not match."
1249   (save-restriction
1250     (widen)
1251     (save-excursion
1252       (goto-char (point-min))
1253       (when (re-search-forward pattern nil 'no-error)
1254         (match-string-no-properties 1)))))
1255
1256 (defun flycheck-buffer-empty-p (&optional buffer)
1257   "Whether a BUFFER is empty.
1258
1259 If buffer is nil or omitted check the current buffer.
1260
1261 Return non-nil if so, or nil if the buffer has content."
1262   (<= (buffer-size buffer) 0))
1263
1264 (defun flycheck-ephemeral-buffer-p ()
1265   "Determine whether the current buffer is an ephemeral buffer.
1266
1267 See Info node `(elisp)Buffer Names' for information about
1268 ephemeral buffers."
1269   (string-prefix-p " " (buffer-name)))
1270
1271 (defun flycheck-encrypted-buffer-p ()
1272   "Determine whether the current buffer is an encrypted file.
1273
1274 See Info node `(epa)Top' for Emacs' interface to encrypted
1275 files."
1276   ;; The EPA file handler sets this variable locally to remember the recipients
1277   ;; of the encrypted file for re-encryption.  Hence, a local binding of this
1278   ;; variable is a good indication that the buffer is encrypted.  I haven't
1279   ;; found any better indicator anyway.
1280   (local-variable-p 'epa-file-encrypt-to))
1281
1282 (defun flycheck-autoloads-file-p ()
1283   "Determine whether the current buffer is an autoloads file.
1284
1285 Autoloads are generated by package.el during installation."
1286   (string-suffix-p "-autoloads.el" (buffer-name)))
1287
1288 (defun flycheck-in-user-emacs-directory-p (filename)
1289   "Whether FILENAME is in `user-emacs-directory'."
1290   (string-prefix-p (file-name-as-directory (file-truename user-emacs-directory))
1291                    (file-truename filename)))
1292
1293 (defun flycheck-safe-delete (file-or-dir)
1294   "Safely delete FILE-OR-DIR."
1295   (ignore-errors
1296     (if (file-directory-p file-or-dir)
1297         (delete-directory file-or-dir 'recursive)
1298       (delete-file file-or-dir))))
1299
1300 (defun flycheck-safe-delete-temporaries ()
1301   "Safely delete all temp files and directories of Flycheck.
1302
1303 Safely delete all files and directories listed in
1304 `flycheck-temporaries' and set the variable's value to nil."
1305   (seq-do #'flycheck-safe-delete flycheck-temporaries)
1306   (setq flycheck-temporaries nil))
1307
1308 (defun flycheck-rx-file-name (form)
1309   "Translate the `(file-name)' FORM into a regular expression."
1310   (let ((body (or (cdr form) '((minimal-match
1311                                 (one-or-more not-newline))))))
1312     (rx-submatch-n `(group-n 1 ,@body))))
1313
1314 (defun flycheck-rx-message (form)
1315   "Translate the `(message)' FORM into a regular expression."
1316   (let ((body (or (cdr form) '((one-or-more not-newline)))))
1317     (rx-submatch-n `(group-n 4 ,@body))))
1318
1319 (defun flycheck-rx-id (form)
1320   "Translate the `(id)' FORM into a regular expression."
1321   (rx-submatch-n `(group-n 5 ,@(cdr form))))
1322
1323 (defun flycheck-rx-to-string (form &optional no-group)
1324   "Like `rx-to-string' for FORM, but with special keywords:
1325
1326 `line'
1327      matches the line number.
1328
1329 `column'
1330      matches the column number.
1331
1332 `(file-name SEXP ...)'
1333      matches the file name.  SEXP describes the file name.  If no
1334      SEXP is given, use a default body of `(minimal-match
1335      (one-or-more not-newline))'.
1336
1337 `(message SEXP ...)'
1338      matches the message.  SEXP constitutes the body of the
1339      message.  If no SEXP is given, use a default body
1340      of `(one-or-more not-newline)'.
1341
1342 `(id SEXP ...)'
1343      matches an error ID.  SEXP describes the ID.
1344
1345 NO-GROUP is passed to `rx-to-string'.
1346
1347 See `rx' for a complete list of all built-in `rx' forms."
1348   (let ((rx-constituents
1349          (append
1350           `((line . ,(rx (group-n 2 (one-or-more digit))))
1351             (column . ,(rx (group-n 3 (one-or-more digit))))
1352             (file-name flycheck-rx-file-name 0 nil)
1353             (message flycheck-rx-message 0 nil)
1354             (id flycheck-rx-id 0 nil))
1355           rx-constituents nil)))
1356     (rx-to-string form no-group)))
1357
1358 (defun flycheck-current-load-file ()
1359   "Get the source file currently being loaded.
1360
1361 Always return the name of the corresponding source file, never
1362 any byte-compiled file.
1363
1364 Return nil, if the currently loaded file cannot be determined."
1365   (-when-let* ((this-file (cond
1366                            (load-in-progress load-file-name)
1367                            ((bound-and-true-p byte-compile-current-file))
1368                            (t (buffer-file-name))))
1369                ;; A best guess for the source file of a compiled library. Works
1370                ;; well in most cases, and especially for ELPA packages
1371                (source-file (concat (file-name-sans-extension this-file)
1372                                     ".el")))
1373     (when (file-exists-p source-file)
1374       source-file)))
1375
1376 (defun flycheck-module-root-directory (module &optional file-name)
1377   "Get the root directory for a MODULE in FILE-NAME.
1378
1379 MODULE is a qualified module name, either a string with
1380 components separated by a dot, or as list of components.
1381 FILE-NAME is the name of the file or directory containing the
1382 module as string.  When nil or omitted, defaults to the return
1383 value of function `buffer-file-name'.
1384
1385 Return the root directory of the module, that is, the directory,
1386 from which FILE-NAME can be reached by descending directories
1387 along each part of MODULE.
1388
1389 If the MODULE name does not match the directory hierarchy upwards
1390 from FILE-NAME, return the directory containing FILE-NAME.  When
1391 FILE-NAME is nil, return `default-directory'."
1392   (let ((file-name (or file-name (buffer-file-name)))
1393         (module-components (if (stringp module)
1394                                (split-string module (rx "."))
1395                              (copy-sequence module))))
1396     (if (and module-components file-name)
1397         (let ((parts (nreverse module-components))
1398               (base-directory (directory-file-name
1399                                (file-name-sans-extension file-name))))
1400           (while (and parts
1401                       (string= (file-name-nondirectory base-directory)
1402                                (car parts)))
1403             (pop parts)
1404             (setq base-directory (directory-file-name
1405                                   (file-name-directory base-directory))))
1406           (file-name-as-directory base-directory))
1407       (if file-name
1408           (file-name-directory file-name)
1409         (expand-file-name default-directory)))))
1410
1411
1412 ;;; Minibuffer tools
1413 (defvar read-flycheck-checker-history nil
1414   "`completing-read' history of `read-flycheck-checker'.")
1415
1416 (defun flycheck-completing-read (prompt candidates default &optional history)
1417   "Read a value from the minibuffer.
1418
1419 Use `flycheck-completing-read-function' to read input from the
1420 minibuffer with completion.
1421
1422 Show PROMPT and read one of CANDIDATES, defaulting to DEFAULT.
1423 HISTORY is passed to `flycheck-completing-read-function'."
1424   (funcall flycheck-completing-read-function
1425            prompt candidates nil 'require-match nil history default))
1426
1427 (defun read-flycheck-checker (prompt &optional default property candidates)
1428   "Read a flycheck checker from minibuffer with PROMPT and DEFAULT.
1429
1430 PROMPT is a string to show in the minibuffer as prompt.  It
1431 should end with a single space.  DEFAULT is a symbol denoting the
1432 default checker to use, if the user did not select any checker.
1433 PROPERTY is a symbol denoting a syntax checker property.  If
1434 non-nil, only complete syntax checkers which have a non-nil value
1435 for PROPERTY.  CANDIDATES is an optional list of all syntax
1436 checkers available for completion, defaulting to all defined
1437 checkers.  If given, PROPERTY is ignored.
1438
1439 Return the checker as symbol, or DEFAULT if no checker was
1440 chosen.  If DEFAULT is nil and no checker was chosen, signal a
1441 `user-error' if the underlying completion system does not provide
1442 a default on its own."
1443   (when (and default (not (flycheck-valid-checker-p default)))
1444     (error "%S is no valid Flycheck checker" default))
1445   (let* ((candidates (seq-map #'symbol-name
1446                               (or candidates
1447                                   (flycheck-defined-checkers property))))
1448          (default (and default (symbol-name default)))
1449          (input (flycheck-completing-read
1450                  prompt candidates default
1451                  'read-flycheck-checker-history)))
1452     (when (string-empty-p input)
1453       (unless default
1454         (user-error "No syntax checker selected"))
1455       (setq input default))
1456     (let ((checker (intern input)))
1457       (unless (flycheck-valid-checker-p checker)
1458         (error "%S is not a valid Flycheck syntax checker" checker))
1459       checker)))
1460
1461 (defun read-flycheck-error-level (prompt)
1462   "Read an error level from the user with PROMPT.
1463
1464 Only offers level for which errors currently exist, in addition
1465 to the default levels."
1466   (let* ((levels (seq-map #'flycheck-error-level
1467                           (flycheck-error-list-current-errors)))
1468          (levels-with-defaults (append '(info warning error) levels))
1469          (uniq-levels (seq-uniq levels-with-defaults))
1470          (level (flycheck-completing-read prompt uniq-levels nil)))
1471     (and (stringp level) (intern level))))
1472
1473
1474 ;;; Checker API
1475 (defun flycheck-defined-checkers (&optional property)
1476   "Find all defined syntax checkers, optionally with PROPERTY.
1477
1478 PROPERTY is a symbol.  If given, only return syntax checkers with
1479 a non-nil value for PROPERTY.
1480
1481 The returned list is sorted alphapetically by the symbol name of
1482 the syntax checkers."
1483   (let (defined-checkers)
1484     (mapatoms (lambda (symbol)
1485                 (when (and (flycheck-valid-checker-p symbol)
1486                            (or (null property)
1487                                (flycheck-checker-get symbol property)))
1488                   (push symbol defined-checkers))))
1489     (sort defined-checkers #'string<)))
1490
1491 (defun flycheck-registered-checker-p (checker)
1492   "Determine whether CHECKER is registered.
1493
1494 A checker is registered if it is contained in
1495 `flycheck-checkers'."
1496   (and (flycheck-valid-checker-p checker)
1497        (memq checker flycheck-checkers)))
1498
1499 (defun flycheck-disabled-checker-p (checker)
1500   "Determine whether CHECKER is disabled.
1501
1502 A checker is disabled if it is contained in
1503 `flycheck-disabled-checkers'."
1504   (memq checker flycheck-disabled-checkers))
1505
1506
1507 ;;; Generic syntax checkers
1508 (defconst flycheck-generic-checker-version 2
1509   "The internal version of generic syntax checker declarations.
1510
1511 Flycheck will not use syntax checkers whose generic version is
1512 less than this constant.")
1513
1514 (defsubst flycheck--checker-property-name (property)
1515   "Return the SYMBOL property for checker PROPERTY."
1516   (intern (concat "flycheck-" (symbol-name property))))
1517
1518 (defun flycheck-checker-get (checker property)
1519   "Get the value of CHECKER's PROPERTY."
1520   (get checker (flycheck--checker-property-name property)))
1521
1522 (gv-define-setter flycheck-checker-get (value checker property)
1523   `(setf (get ,checker (flycheck--checker-property-name ,property)) ,value))
1524
1525 (defun flycheck-validate-next-checker (next &optional strict)
1526   "Validate NEXT checker.
1527
1528 With STRICT non-nil, also check whether the syntax checker and
1529 the error level in NEXT are valid.  Otherwise just check whether
1530 these are symbols.
1531
1532 Signal an error if NEXT is not a valid entry for
1533 `:next-checkers'."
1534   (when (symbolp next)
1535     (setq next (cons t next)))
1536   (pcase next
1537     (`(,level . ,checker)
1538      (if strict
1539          (progn
1540            (unless (or (eq level t) (flycheck-error-level-p level))
1541              (error "%S is not a valid Flycheck error level" level))
1542            (unless (flycheck-valid-checker-p checker)
1543              (error "%s is not a valid Flycheck syntax checker" checker)))
1544        (unless (symbolp level)
1545          (error "Error level %S must be a symbol" level))
1546        (unless (symbolp checker)
1547          (error "Checker %S must be a symbol" checker))))
1548     (_ (error "%S must be a symbol or cons cell" next)))
1549   t)
1550
1551 (defun flycheck-define-generic-checker (symbol docstring &rest properties)
1552   "Define SYMBOL as generic syntax checker.
1553
1554 Any syntax checker defined with this macro is eligible for manual
1555 syntax checker selection with `flycheck-select-checker'.  To make
1556 the new syntax checker available for automatic selection, it must
1557 be registered in `flycheck-checkers'.
1558
1559 DOCSTRING is the documentation of the syntax checker, for
1560 `flycheck-describe-checker'.  The following PROPERTIES constitute
1561 a generic syntax checker.  Unless otherwise noted, all properties
1562 are mandatory.
1563
1564 `:start FUNCTION'
1565      A function to start the syntax checker.
1566
1567      FUNCTION shall take two arguments and return a context
1568      object if the checker is started successfully.  Otherwise it
1569      shall signal an error.
1570
1571      The first argument is the syntax checker being started.  The
1572      second is a callback function to report state changes to
1573      Flycheck.  The callback takes two arguments STATUS DATA,
1574      where STATUS is a symbol denoting the syntax checker status
1575      and DATA an optional argument with additional data for the
1576      status report.  See `flycheck-report-buffer-checker-status'
1577      for more information about STATUS and DATA.
1578
1579      FUNCTION may be synchronous or asynchronous, i.e. it may
1580      call the given callback either immediately, or at some later
1581      point (e.g. from a process sentinel).
1582
1583      A syntax checker _must_ call CALLBACK at least once with a
1584      STATUS that finishes the current syntax checker.  Otherwise
1585      Flycheck gets stuck at the current syntax check with this
1586      syntax checker.
1587
1588      The context object returned by FUNCTION is passed to
1589      `:interrupt'.
1590
1591 `:interrupt FUNCTION'
1592      A function to interrupt the syntax check.
1593
1594      FUNCTION is called with the syntax checker and the context
1595      object returned by the `:start' function and shall try to
1596      interrupt the syntax check.  The context may be nil, if the
1597      syntax check is interrupted before actually started.
1598      FUNCTION should handle this situation.
1599
1600      If it cannot interrupt the syntax check, it may either
1601      signal an error or silently ignore the attempt to interrupt
1602      the syntax checker, depending on the severity of the
1603      situation.
1604
1605      If interrupting the syntax check failed, Flycheck will let
1606      the syntax check continue, but ignore any status reports.
1607      Notably, it won't highlight any errors reported by the
1608      syntax check in the buffer.
1609
1610      This property is optional.  If omitted, Flycheck won't
1611      attempt to interrupt syntax checks wit this syntax checker,
1612      and simply ignore their results.
1613
1614 `:print-doc FUNCTION'
1615      A function to print additional documentation into the Help
1616      buffer of this checker.
1617
1618      FUNCTION is called when creating the Help buffer for the
1619      syntax checker, with the syntax checker as single argument,
1620      after printing the name of the syntax checker and its modes
1621      and predicate, but before printing DOCSTRING.  It may insert
1622      additional documentation into the current buffer.
1623
1624      The call occurs within `with-help-window'.  Hence
1625      `standard-output' points to the current buffer, so you may
1626      use `princ' and friends to add content.  Also, the current
1627      buffer is put into Help mode afterwards, which automatically
1628      turns symbols into references, if possible.
1629
1630      This property is optional.  If omitted, no additional
1631      documentation is printed for this syntax checker.
1632
1633 :verify FUNCTION
1634      A function to verify the checker for the current buffer.
1635
1636      FUNCTION is called with the syntax checker as single
1637      argument, and shall return a list of
1638      `flycheck-verification-result' objects indicating whether
1639      the syntax checker could be used in the current buffer, and
1640      highlighting potential setup problems.
1641
1642      This property is optional.  If omitted, no additional
1643      verification occurs for this syntax checker.  It is however
1644      absolutely recommended that you add a `:verify' function to
1645      your syntax checker, because it will help users to spot
1646      potential setup problems.
1647
1648 `:modes MODES'
1649      A major mode symbol or a list thereof, denoting major modes
1650      to use this syntax checker in.
1651
1652      This syntax checker will only be used in buffers whose
1653      `major-mode' is contained in MODES.
1654
1655      If `:predicate' is also given the syntax checker will only
1656      be used in buffers for which the `:predicate' returns
1657      non-nil.
1658
1659 `:predicate FUNCTION'
1660      A function to determine whether to use the syntax checker in
1661      the current buffer.
1662
1663      FUNCTION is called without arguments and shall return
1664      non-nil if this syntax checker shall be used to check the
1665      current buffer.  Otherwise it shall return nil.
1666
1667      If this checker has a `:working-directory' FUNCTION is
1668      called with `default-directory' bound to the checker's
1669      working directory.
1670
1671      FUNCTION is only called in matching major modes.
1672
1673      This property is optional.
1674
1675 `:enabled FUNCTION'
1676      A function to determine whether to use the syntax checker in
1677      the current buffer.
1678
1679      This property behaves as `:predicate', except that it's only
1680      called the first time a syntax checker is to be used in a buffer.
1681
1682      FUNCTION is called without arguments and shall return
1683      non-nil if this syntax checker shall be used to check the
1684      current buffer.  Otherwise it shall return nil.
1685
1686      If FUNCTION returns a non-nil value the checker is put in a
1687      whitelist in `flycheck-enabled-checkers' to prevent further
1688      invocations of `:enabled'.  Otherwise it is disabled via
1689      `flycheck-disabled-checkers' to prevent any further use of
1690      it.
1691
1692      If this checker has a `:working-directory' FUNCTION is
1693      called with `default-directory' bound to the checker's
1694      working directory.
1695
1696      FUNCTION is only called in matching major modes.
1697
1698      This property is optional.
1699
1700 `:error-filter FUNCTION'
1701      A function to filter the errors returned by this checker.
1702
1703      FUNCTION is called with the list of `flycheck-error' objects
1704      returned by the syntax checker and shall return another list
1705      of `flycheck-error' objects, which is considered the final
1706      result of this syntax checker.
1707
1708      FUNCTION is free to add, remove or modify errors, whether in
1709      place or by copying.
1710
1711      This property is optional.  The default filter is
1712      `identity'.
1713
1714 `:error-explainer FUNCTION'
1715      A function to return an explanation text for errors
1716      generated by this checker.
1717
1718      FUNCTION is called with a `flycheck-error' object and shall
1719      return an explanation message for this error as a string, or
1720      nil if there is no explanation for this error.
1721
1722      This property is optional.
1723
1724 `:next-checkers NEXT-CHECKERS'
1725      A list denoting syntax checkers to apply after this syntax
1726      checker, in what we call \"chaining\" of syntax checkers.
1727
1728      Each ITEM is a cons cell `(LEVEL . CHECKER)'.  CHECKER is a
1729      syntax checker to run after this syntax checker.  LEVEL is
1730      an error level.  CHECKER will only be used if there are no
1731      current errors of at least LEVEL.  LEVEL may also be t, in
1732      which case CHECKER is used regardless of the current errors.
1733
1734      ITEM may also be a syntax checker symbol, which is
1735      equivalent to `(t . ITEM)'.
1736
1737      Flycheck tries all items in order of declaration, and uses
1738      the first whose LEVEL matches and whose CHECKER is
1739      registered and can be used for the current buffer.
1740
1741      This feature is typically used to apply more than one syntax
1742      checker to a buffer.  For instance, you might first use a
1743      compiler to check a buffer for syntax and type errors, and
1744      then run a linting tool that checks for insecure code, or
1745      questionable style.
1746
1747      This property is optional.  If omitted, it defaults to the
1748      nil, i.e. no other syntax checkers are applied after this
1749      syntax checker.
1750
1751 `:working-directory FUNCTION'
1752      The value of `default-directory' when invoking `:start'.
1753
1754      FUNCTION is a function taking the syntax checker as sole
1755      argument.  It shall return the absolute path to an existing
1756      directory to use as `default-directory' for `:start' or
1757      nil to fall back to the `default-directory' of the current
1758      buffer.
1759
1760      This property is optional.  If omitted, invoke `:start'
1761      from the `default-directory' of the buffer being checked.
1762
1763 Signal an error, if any property has an invalid value."
1764   (declare (indent 1)
1765            (doc-string 2))
1766   (let ((start (plist-get properties :start))
1767         (interrupt (plist-get properties :interrupt))
1768         (print-doc (plist-get properties :print-doc))
1769         (modes (plist-get properties :modes))
1770         (predicate (plist-get properties :predicate))
1771         (verify (plist-get properties :verify))
1772         (enabled (plist-get properties :enabled))
1773         (filter (or (plist-get properties :error-filter) #'identity))
1774         (explainer (plist-get properties :error-explainer))
1775         (next-checkers (plist-get properties :next-checkers))
1776         (file (flycheck-current-load-file))
1777         (working-directory (plist-get properties :working-directory)))
1778
1779     (unless (listp modes)
1780       (setq modes (list modes)))
1781
1782     (unless (functionp start)
1783       (error ":start %S of syntax checker %s is not a function" start symbol))
1784     (unless (or (null interrupt) (functionp interrupt))
1785       (error ":interrupt %S of syntax checker %s is not a function"
1786              interrupt symbol))
1787     (unless (or (null print-doc) (functionp print-doc))
1788       (error ":print-doc %S of syntax checker %s is not a function"
1789              print-doc symbol))
1790     (unless (or (null verify) (functionp verify))
1791       (error ":verify %S of syntax checker %S is not a function"
1792              verify symbol))
1793     (unless (or (null enabled) (functionp enabled))
1794       (error ":enabled %S of syntax checker %S is not a function"
1795              enabled symbol))
1796     (unless modes
1797       (error "Missing :modes in syntax checker %s" symbol))
1798     (dolist (mode modes)
1799       (unless (symbolp mode)
1800         (error "Invalid :modes %s in syntax checker %s, %s must be a symbol"
1801                modes symbol mode)))
1802     (unless (or (null predicate) (functionp predicate))
1803       (error ":predicate %S of syntax checker %s  is not a function"
1804              predicate symbol))
1805     (unless (functionp filter)
1806       (error ":error-filter %S of syntax checker %s is not a function"
1807              filter symbol))
1808     (unless (or (null explainer) (functionp explainer))
1809       (error ":error-explainer %S of syntax checker %S is not a function"
1810              explainer symbol))
1811     (dolist (checker next-checkers)
1812       (flycheck-validate-next-checker checker))
1813
1814     (let ((real-predicate
1815            (and predicate
1816                 (lambda ()
1817                   ;; Run predicate in the checker's default directory
1818                   (let ((default-directory
1819                           (flycheck-compute-working-directory symbol)))
1820                     (funcall predicate)))))
1821           (real-enabled
1822            (lambda ()
1823              (if (flycheck-valid-checker-p symbol)
1824                  (or (null enabled)
1825                      ;; Run enabled in the checker's default directory
1826                      (let ((default-directory
1827                              (flycheck-compute-working-directory symbol)))
1828                        (funcall enabled)))
1829                (lwarn 'flycheck
1830                       :warning "%S is no valid Flycheck syntax checker.
1831 Try to reinstall the package defining this syntax checker." symbol)
1832                nil))))
1833       (pcase-dolist (`(,prop . ,value)
1834                      `((start             . ,start)
1835                        (interrupt         . ,interrupt)
1836                        (print-doc         . ,print-doc)
1837                        (modes             . ,modes)
1838                        (predicate         . ,real-predicate)
1839                        (verify            . ,verify)
1840                        (enabled           . ,real-enabled)
1841                        (error-filter      . ,filter)
1842                        (error-explainer   . ,explainer)
1843                        (next-checkers     . ,next-checkers)
1844                        (documentation     . ,docstring)
1845                        (file              . ,file)
1846                        (working-directory . ,working-directory)))
1847         (setf (flycheck-checker-get symbol prop) value)))
1848
1849     ;; Track the version, to avoid breakage if the internal format changes
1850     (setf (flycheck-checker-get symbol 'generic-checker-version)
1851           flycheck-generic-checker-version)))
1852
1853 (defun flycheck-valid-checker-p (checker)
1854   "Check whether a CHECKER is valid.
1855
1856 A valid checker is a symbol defined as syntax checker with
1857 `flycheck-define-checker'."
1858   (and (symbolp checker)
1859        (= (or (get checker 'flycheck-generic-checker-version) 0)
1860           flycheck-generic-checker-version)))
1861
1862 (defun flycheck-checker-supports-major-mode-p (checker &optional mode)
1863   "Whether CHECKER supports the given major MODE.
1864
1865 CHECKER is a syntax checker symbol and MODE a major mode symbol.
1866 Look at the `modes' property of CHECKER to determine whether
1867 CHECKER supports buffers in the given major MODE.
1868
1869 MODE defaults to the value of `major-mode' if omitted or nil.
1870
1871 Return non-nil if CHECKER supports MODE and nil otherwise."
1872   (let ((mode (or mode major-mode)))
1873     (memq mode (flycheck-checker-get checker 'modes))))
1874
1875 (defvar-local flycheck-enabled-checkers nil
1876   "Syntax checkers included in automatic selection.
1877
1878 A list of Flycheck syntax checkers included in automatic
1879 selection for current buffer.")
1880
1881 (defun flycheck-may-enable-checker (checker)
1882   "Whether a generic CHECKER may be enabled for current buffer.
1883
1884 Return non-nil if CHECKER may be used for the current buffer, and
1885 nil otherwise."
1886   (let* ((enabled (flycheck-checker-get checker 'enabled))
1887          (shall-enable (and (not (flycheck-disabled-checker-p checker))
1888                             (or (memq checker flycheck-enabled-checkers)
1889                                 (null enabled)
1890                                 (funcall enabled)))))
1891     (if shall-enable
1892         (cl-pushnew checker flycheck-enabled-checkers)
1893       (cl-pushnew checker flycheck-disabled-checkers))
1894     shall-enable))
1895
1896 (defun flycheck-may-use-checker (checker)
1897   "Whether a generic CHECKER may be used.
1898
1899 Return non-nil if CHECKER may be used for the current buffer, and
1900 nil otherwise."
1901   (let ((predicate (flycheck-checker-get checker 'predicate)))
1902     (and (flycheck-valid-checker-p checker)
1903          (flycheck-checker-supports-major-mode-p checker)
1904          (flycheck-may-enable-checker checker)
1905          (or (null predicate) (funcall predicate)))))
1906
1907 (defun flycheck-may-use-next-checker (next-checker)
1908   "Determine whether NEXT-CHECKER may be used."
1909   (when (symbolp next-checker)
1910     (push t next-checker))
1911   (let ((level (car next-checker))
1912         (next-checker (cdr next-checker)))
1913     (and (or (eq level t)
1914              (flycheck-has-max-current-errors-p level))
1915          (flycheck-registered-checker-p next-checker)
1916          (flycheck-may-use-checker next-checker))))
1917
1918
1919 ;;; Help for generic syntax checkers
1920 (define-button-type 'help-flycheck-checker-def
1921   :supertype 'help-xref
1922   'help-function #'flycheck-goto-checker-definition
1923   'help-echo "mouse-2, RET: find Flycheck checker definition")
1924
1925 (defconst flycheck-find-checker-regexp
1926   (rx line-start (zero-or-more (syntax whitespace))
1927       "(" symbol-start "flycheck-define-checker" symbol-end
1928       (eval (list 'regexp find-function-space-re))
1929       symbol-start
1930       "%s"
1931       symbol-end
1932       (or (syntax whitespace) line-end))
1933   "Regular expression to find a checker definition.")
1934
1935 (add-to-list 'find-function-regexp-alist
1936              '(flycheck-checker . flycheck-find-checker-regexp))
1937
1938 (defun flycheck-goto-checker-definition (checker file)
1939   "Go to to the definition of CHECKER in FILE."
1940   (let ((location (find-function-search-for-symbol
1941                    checker 'flycheck-checker file)))
1942     (pop-to-buffer (car location))
1943     (if (cdr location)
1944         (goto-char (cdr location))
1945       (message "Unable to find checker location in file"))))
1946
1947 (defun flycheck-checker-at-point ()
1948   "Return the Flycheck checker found at or before point.
1949
1950 Return nil if there is no checker."
1951   (let ((symbol (variable-at-point 'any-symbol)))
1952     (when (flycheck-valid-checker-p symbol)
1953       symbol)))
1954
1955 (defun flycheck-describe-checker (checker)
1956   "Display the documentation of CHECKER.
1957
1958 CHECKER is a checker symbol.
1959
1960 Pop up a help buffer with the documentation of CHECKER."
1961   (interactive
1962    (let* ((enable-recursive-minibuffers t)
1963           (default (or (flycheck-checker-at-point)
1964                        (ignore-errors (flycheck-get-checker-for-buffer))))
1965           (prompt (if default
1966                       (format "Describe syntax checker (default %s): " default)
1967                     "Describe syntax checker: ")))
1968      (list (read-flycheck-checker prompt default))))
1969   (unless (flycheck-valid-checker-p checker)
1970     (user-error "You didn't specify a Flycheck syntax checker"))
1971   (help-setup-xref (list #'flycheck-describe-checker checker)
1972                    (called-interactively-p 'interactive))
1973   (save-excursion
1974     (with-help-window (help-buffer)
1975       (let ((filename (flycheck-checker-get checker 'file))
1976             (modes (flycheck-checker-get checker 'modes))
1977             (predicate (flycheck-checker-get checker 'predicate))
1978             (print-doc (flycheck-checker-get checker 'print-doc))
1979             (next-checkers (flycheck-checker-get checker 'next-checkers)))
1980         (princ (format "%s is a Flycheck syntax checker" checker))
1981         (when filename
1982           (princ (format " in `%s'" (file-name-nondirectory filename)))
1983           (with-current-buffer standard-output
1984             (save-excursion
1985               (re-search-backward "`\\([^`']+\\)'" nil t)
1986               (help-xref-button 1 'help-flycheck-checker-def
1987                                 checker filename))))
1988         (princ ".\n\n")
1989
1990         (let ((modes-start (with-current-buffer standard-output (point-max))))
1991           ;; Track the start of the modes documentation, to properly re-fill
1992           ;; it later
1993           (princ "  This syntax checker checks syntax in the major mode(s) ")
1994           (princ (string-join
1995                   (seq-map (apply-partially #'format "`%s'") modes)
1996                   ", "))
1997           (when predicate
1998             (princ ", and uses a custom predicate"))
1999           (princ ".")
2000           (when next-checkers
2001             (princ "  It runs the following checkers afterwards:"))
2002           (with-current-buffer standard-output
2003             (save-excursion
2004               (fill-region-as-paragraph modes-start (point-max))))
2005           (princ "\n")
2006
2007           ;; Print the list of next checkers
2008           (when next-checkers
2009             (princ "\n")
2010             (let ((beg-checker-list (with-current-buffer standard-output
2011                                       (point))))
2012               (dolist (next-checker next-checkers)
2013                 (if (symbolp next-checker)
2014                     (princ (format "     * `%s'\n" next-checker))
2015                   (princ (format "     * `%s' (maximum level `%s')\n"
2016                                  (cdr next-checker) (car next-checker)))))
2017               ;;
2018               (with-current-buffer standard-output
2019                 (save-excursion
2020                   (while (re-search-backward "`\\([^`']+\\)'"
2021                                              beg-checker-list t)
2022                     (when (flycheck-valid-checker-p
2023                            (intern-soft (match-string 1)))
2024                       (help-xref-button 1 'help-flycheck-checker-def checker
2025                                         filename))))))))
2026         ;; Call the custom print-doc function of the checker, if present
2027         (when print-doc
2028           (funcall print-doc checker))
2029         ;; Ultimately, print the docstring
2030         (princ "\nDocumentation:\n")
2031         (princ (flycheck-checker-get checker 'documentation))))))
2032
2033
2034 ;;; Syntax checker verification
2035 (cl-defstruct (flycheck-verification-result
2036                (:constructor flycheck-verification-result-new))
2037   "Structure for storing a single verification result.
2038
2039 Slots:
2040
2041 `label'
2042      A label for this result, as string
2043
2044 `message'
2045      A message for this result, as string
2046
2047 `face'
2048      The face to use for the `message'.
2049
2050      You can either use a face symbol, or a list of face symbols."
2051   label message face)
2052
2053 (defun flycheck-verify-generic-checker (checker)
2054   "Verify a generic CHECKER in the current buffer.
2055
2056 Return a list of `flycheck-verification-result' objects."
2057   (let (results
2058         (predicate (flycheck-checker-get checker 'predicate))
2059         (enabled (flycheck-checker-get checker 'enabled))
2060         (verify (flycheck-checker-get checker 'verify)))
2061     (when enabled
2062       (let ((result (funcall enabled)))
2063         (push (flycheck-verification-result-new
2064                :label "may enable"
2065                :message (if result "yes" "Automatically disabled!")
2066                :face (if result 'success '(bold warning)))
2067               results)))
2068     (when predicate
2069       (let ((result (funcall predicate)))
2070         (push (flycheck-verification-result-new
2071                :label "predicate"
2072                :message (prin1-to-string (not (null result)))
2073                :face (if result 'success '(bold warning)))
2074               results)))
2075     (append (nreverse results)
2076             (and verify (funcall verify checker)))))
2077
2078 (define-button-type 'help-flycheck-checker-doc
2079   :supertype 'help-xref
2080   'help-function #'flycheck-describe-checker
2081   'help-echo "mouse-2, RET: describe Flycheck checker")
2082
2083 (defun flycheck--verify-princ-checker (checker buffer &optional with-mm)
2084   "Print verification result of CHECKER for BUFFER.
2085
2086 When WITH-MM is given and non-nil, also include the major mode
2087 into the verification results."
2088   (princ "  ")
2089   (insert-button (symbol-name checker)
2090                  'type 'help-flycheck-checker-doc
2091                  'help-args (list checker))
2092   (when (with-current-buffer buffer (flycheck-disabled-checker-p checker))
2093     (insert (propertize " (disabled)" 'face '(bold error))))
2094   (princ "\n")
2095   (let ((results (with-current-buffer buffer
2096                    (flycheck-verify-generic-checker checker))))
2097     (when with-mm
2098       (with-current-buffer buffer
2099         (let ((message-and-face
2100                (if (flycheck-checker-supports-major-mode-p checker)
2101                    (cons (format "`%s' supported" major-mode) 'success)
2102                  (cons (format "`%s' not supported" major-mode) 'error))))
2103           (push (flycheck-verification-result-new
2104                  :label "major mode"
2105                  :message (car message-and-face)
2106                  :face (cdr message-and-face))
2107                 results))))
2108     (let* ((label-length
2109             (seq-max (mapcar
2110                       (lambda (res)
2111                         (length (flycheck-verification-result-label res)))
2112                       results)))
2113            (message-column (+ 8 label-length)))
2114       (dolist (result results)
2115         (princ "    - ")
2116         (princ (flycheck-verification-result-label result))
2117         (princ ": ")
2118         (princ (make-string (- message-column (current-column)) ?\ ))
2119         (let ((message (flycheck-verification-result-message result))
2120               (face (flycheck-verification-result-face result)))
2121           (insert (propertize message 'face face)))
2122         (princ "\n"))))
2123   (princ "\n"))
2124
2125 (defun flycheck--verify-print-header (desc buffer)
2126   "Print a title with DESC for BUFFER in the current buffer.
2127
2128 DESC is an arbitrary string containing a description, and BUFFER
2129 is the buffer being verified.  The name and the major mode mode
2130 of BUFFER are printed.
2131
2132 DESC and information about BUFFER are printed in the current
2133 buffer."
2134   (princ desc)
2135   (insert (propertize (buffer-name buffer) 'face 'bold))
2136   (princ " in ")
2137   (let ((mode (buffer-local-value 'major-mode buffer)))
2138     (insert-button (symbol-name mode)
2139                    'type 'help-function
2140                    'help-args (list mode)))
2141   (princ ":\n\n"))
2142
2143 (defun flycheck--verify-print-footer (buffer)
2144   "Print a footer for BUFFER in the current buffer.
2145
2146 BUFFER is the buffer being verified."
2147   (princ "Flycheck Mode is ")
2148   (let ((enabled (buffer-local-value 'flycheck-mode buffer)))
2149     (insert (propertize (if enabled "enabled" "disabled")
2150                         'face (if enabled 'success '(warning bold)))))
2151   (princ
2152    (with-current-buffer buffer
2153      ;; Use key binding state in the verified buffer to print the help.
2154      (substitute-command-keys
2155       ".  Use \\[universal-argument] \\[flycheck-disable-checker] \
2156 to enable disabled checkers.")))
2157   (save-excursion
2158     (let ((end (point)))
2159       (backward-paragraph)
2160       (fill-region-as-paragraph (point) end)))
2161
2162   (princ "\n\n--------------------\n\n")
2163   (princ (format "Flycheck version: %s\n" (flycheck-version)))
2164   (princ (format "Emacs version:    %s\n" emacs-version))
2165   (princ (format "System:           %s\n" system-configuration))
2166   (princ (format "Window system:    %S\n" window-system)))
2167
2168 (defun flycheck-verify-checker (checker)
2169   "Check whether a CHECKER can be used in this buffer.
2170
2171 Show a buffer listing possible problems that prevent CHECKER from
2172 being used for the current buffer.
2173
2174 Note: Do not use this function to check whether a syntax checker
2175 is applicable from Emacs Lisp code.  Use
2176 `flycheck-may-use-checker' instead."
2177   (interactive (list (read-flycheck-checker "Checker to verify: ")))
2178   (unless (flycheck-valid-checker-p checker)
2179     (user-error "%s is not a syntax checker" checker))
2180
2181   ;; Save the buffer to make sure that all predicates are good
2182   (when (and (buffer-file-name) (buffer-modified-p))
2183     (save-buffer))
2184
2185   (let ((buffer (current-buffer)))
2186     (with-help-window (get-buffer-create " *Flycheck checker*")
2187       (with-current-buffer standard-output
2188         (flycheck--verify-print-header "Syntax checker in buffer " buffer)
2189         (flycheck--verify-princ-checker checker buffer 'with-mm)
2190         (if (with-current-buffer buffer (flycheck-may-use-checker checker))
2191             (insert (propertize
2192                      "Flycheck can use this syntax checker for this buffer.\n"
2193                      'face 'success))
2194           (insert (propertize
2195                    "Flycheck cannot use this syntax checker for this buffer.\n"
2196                    'face 'error)))
2197         (insert "\n")
2198         (flycheck--verify-print-footer buffer)))))
2199
2200 (defun flycheck-verify-setup ()
2201   "Check whether Flycheck can be used in this buffer.
2202
2203 Display a new buffer listing all syntax checkers that could be
2204 applicable in the current buffer.  For each syntax checkers,
2205 possible problems are shown."
2206   (interactive)
2207   (when (and (buffer-file-name) (buffer-modified-p))
2208     ;; Save the buffer
2209     (save-buffer))
2210
2211   (let ((buffer (current-buffer))
2212         ;; Get all checkers that support the current major mode
2213         (checkers (seq-filter #'flycheck-checker-supports-major-mode-p
2214                               flycheck-checkers))
2215         (help-buffer (get-buffer-create " *Flycheck checkers*")))
2216
2217     ;; Now print all applicable checkers
2218     (with-help-window help-buffer
2219       (with-current-buffer standard-output
2220         (flycheck--verify-print-header "Syntax checkers for buffer " buffer)
2221         (unless checkers
2222           (insert (propertize
2223                    "There are no syntax checkers for this buffer!\n\n"
2224                    'face '(bold error))))
2225         (dolist (checker checkers)
2226           (flycheck--verify-princ-checker checker buffer))
2227
2228         (-when-let (selected-checker
2229                     (buffer-local-value 'flycheck-checker buffer))
2230           (insert
2231            (propertize
2232             "The following checker is explicitly selected for this buffer:\n\n"
2233             'face 'bold))
2234           (flycheck--verify-princ-checker selected-checker buffer 'with-mm))
2235
2236         (let ((unregistered-checkers
2237                (seq-difference (flycheck-defined-checkers) flycheck-checkers)))
2238           (when unregistered-checkers
2239             (insert (propertize
2240                      "\nThe following syntax checkers are not registered:\n\n"
2241                      'face '(bold warning)))
2242             (dolist (checker unregistered-checkers)
2243               (princ "  - ")
2244               (princ checker)
2245               (princ "\n"))
2246             (princ
2247              "\nTry adding these syntax checkers to `flycheck-checkers'.\n")))
2248
2249         (flycheck--verify-print-footer buffer)))
2250
2251     (with-current-buffer help-buffer
2252       (setq-local revert-buffer-function
2253                   (lambda (_ignore-auto _noconfirm)
2254                     (with-current-buffer buffer (flycheck-verify-setup)))))))
2255
2256
2257 ;;; Predicates for generic syntax checkers
2258 (defun flycheck-buffer-saved-p (&optional buffer)
2259   "Determine whether BUFFER is saved to a file.
2260
2261 BUFFER is the buffer to check.  If omitted or nil, use the
2262 current buffer as BUFFER.
2263
2264 Return non-nil if the BUFFER is backed by a file, and not
2265 modified, or nil otherwise."
2266   (let ((file-name (buffer-file-name buffer)))
2267     (and file-name (file-exists-p file-name) (not (buffer-modified-p buffer)))))
2268
2269
2270 ;;; Extending generic checkers
2271 (defun flycheck-add-next-checker (checker next &optional append)
2272   "After CHECKER add a NEXT checker.
2273
2274 CHECKER is a syntax checker symbol, to which to add NEXT checker.
2275
2276 NEXT is a cons cell `(LEVEL . NEXT-CHECKER)'.  NEXT-CHECKER is a
2277 symbol denoting the syntax checker to run after CHECKER.  LEVEL
2278 is an error level.  NEXT-CHECKER will only be used if there is no
2279 current error whose level is more severe than LEVEL.  LEVEL may
2280 also be t, in which case NEXT-CHECKER is used regardless of the
2281 current errors.
2282
2283 NEXT can also be a syntax checker symbol only, which is
2284 equivalent to `(t . NEXT)'.
2285
2286 NEXT-CHECKER is prepended before other next checkers, unless
2287 APPEND is non-nil."
2288   (unless (flycheck-valid-checker-p checker)
2289     (error "%s is not a valid syntax checker" checker))
2290   (flycheck-validate-next-checker next 'strict)
2291   (if append
2292       (setf (flycheck-checker-get checker 'next-checkers)
2293             (append (flycheck-checker-get checker 'next-checkers) (list next)))
2294     (push next (flycheck-checker-get checker 'next-checkers))))
2295
2296 (defun flycheck-add-mode (checker mode)
2297   "To CHECKER add a new major MODE.
2298
2299 CHECKER and MODE are symbols denoting a syntax checker and a
2300 major mode respectively.
2301
2302 Add MODE to the `:modes' property of CHECKER, so that CHECKER
2303 will be used in buffers with MODE."
2304   (unless (flycheck-valid-checker-p checker)
2305     (error "%s is not a valid syntax checker" checker))
2306   (unless (symbolp mode)
2307     (error "%s is not a symbol" mode))
2308   (push mode (flycheck-checker-get checker 'modes)))
2309
2310
2311 ;;; Generic syntax checks
2312 (cl-defstruct (flycheck-syntax-check
2313                (:constructor flycheck-syntax-check-new))
2314   "Structure for storing syntax check state.
2315
2316 Slots:
2317
2318 `buffer'
2319      The buffer being checked.
2320
2321 `checker'
2322      The syntax checker being used.
2323
2324 `context'
2325      The context object.
2326
2327 `working-directory'
2328      Working directory for the syntax checker. Serve as a value for
2329      `default-directory' for a checker."
2330   buffer checker context working-directory)
2331
2332 (defun flycheck-syntax-check-start (syntax-check callback)
2333   "Start a SYNTAX-CHECK with CALLBACK."
2334   (let ((checker (flycheck-syntax-check-checker syntax-check))
2335         (default-directory
2336           (flycheck-syntax-check-working-directory syntax-check)))
2337     (setf (flycheck-syntax-check-context syntax-check)
2338           (funcall (flycheck-checker-get checker 'start) checker callback))))
2339
2340 (defun flycheck-syntax-check-interrupt (syntax-check)
2341   "Interrupt a SYNTAX-CHECK."
2342   (let* ((checker (flycheck-syntax-check-checker syntax-check))
2343          (interrupt-fn (flycheck-checker-get checker 'interrupt))
2344          (context (flycheck-syntax-check-context syntax-check)))
2345     (when interrupt-fn
2346       (funcall interrupt-fn checker context))))
2347
2348
2349 ;;; Syntax checking mode
2350
2351 (defvar flycheck-mode-map
2352   (let ((map (make-sparse-keymap)))
2353     (define-key map flycheck-keymap-prefix flycheck-command-map)
2354     ;; We place the menu under a custom menu key.  Since this menu key is not
2355     ;; present in the menu of the global map, no top-level menu entry is added
2356     ;; to the global menu bar.  However, it still appears on the mode line
2357     ;; lighter.
2358     (define-key map [menu-bar flycheck] flycheck-mode-menu-map)
2359     map)
2360   "Keymap of command `flycheck-mode'.")
2361
2362 (defvar-local flycheck-old-next-error-function nil
2363   "Remember the old `next-error-function'.")
2364
2365 (defconst flycheck-hooks-alist
2366   '(
2367     ;; Handle events that may start automatic syntax checks
2368     (after-save-hook        . flycheck-handle-save)
2369     (after-change-functions . flycheck-handle-change)
2370     ;; Handle events that may triggered pending deferred checks
2371     (window-configuration-change-hook . flycheck-perform-deferred-syntax-check)
2372     (post-command-hook                . flycheck-perform-deferred-syntax-check)
2373     ;; Teardown Flycheck whenever the buffer state is about to get lost, to
2374     ;; clean up temporary files and directories.
2375     (kill-buffer-hook       . flycheck-teardown)
2376     (change-major-mode-hook . flycheck-teardown)
2377     (before-revert-hook     . flycheck-teardown)
2378     ;; Update the error list if necessary
2379     (post-command-hook . flycheck-error-list-update-source)
2380     (post-command-hook . flycheck-error-list-highlight-errors)
2381     ;; Display errors.  Show errors at point after commands (like movements) and
2382     ;; when Emacs gets focus.  Cancel the display timer when Emacs looses focus
2383     ;; (as there's no need to display errors if the user can't see them), and
2384     ;; hide the error buffer (for large error messages) if necessary.  Note that
2385     ;; the focus hooks only work on Emacs 24.4 and upwards, but since undefined
2386     ;; hooks are perfectly ok we don't need a version guard here.  They'll just
2387     ;; not work silently.
2388     (post-command-hook . flycheck-display-error-at-point-soon)
2389     (focus-in-hook     . flycheck-display-error-at-point-soon)
2390     (focus-out-hook    . flycheck-cancel-error-display-error-at-point-timer)
2391     (post-command-hook . flycheck-hide-error-buffer)
2392     ;; Immediately show error popups when navigating to an error
2393     (next-error-hook . flycheck-display-error-at-point))
2394   "Hooks which Flycheck needs to hook in.
2395
2396 The `car' of each pair is a hook variable, the `cdr' a function
2397 to be added or removed from the hook variable if Flycheck mode is
2398 enabled and disabled respectively.")
2399
2400 ;;;###autoload
2401 (define-minor-mode flycheck-mode
2402   "Minor mode for on-the-fly syntax checking.
2403
2404 When called interactively, toggle `flycheck-mode'.  With prefix
2405 ARG, enable `flycheck-mode' if ARG is positive, otherwise disable
2406 it.
2407
2408 When called from Lisp, enable `flycheck-mode' if ARG is omitted,
2409 nil or positive.  If ARG is `toggle', toggle `flycheck-mode'.
2410 Otherwise behave as if called interactively.
2411
2412 In `flycheck-mode' the buffer is automatically syntax-checked
2413 using the first suitable syntax checker from `flycheck-checkers'.
2414 Use `flycheck-select-checker' to select a checker for the current
2415 buffer manually.
2416
2417 \\{flycheck-mode-map}"
2418   :init-value nil
2419   :keymap flycheck-mode-map
2420   :lighter flycheck-mode-line
2421   :after-hook (flycheck-buffer-automatically 'mode-enabled 'force-deferred)
2422   (cond
2423    (flycheck-mode
2424     (flycheck-clear)
2425
2426     (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist)
2427       (add-hook hook fn nil 'local))
2428
2429     (setq flycheck-old-next-error-function
2430           (if flycheck-standard-error-navigation
2431               next-error-function
2432             :unset))
2433     (when flycheck-standard-error-navigation
2434       (setq next-error-function #'flycheck-next-error-function)))
2435    (t
2436     (unless (eq flycheck-old-next-error-function :unset)
2437       (setq next-error-function flycheck-old-next-error-function))
2438
2439     (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist)
2440       (remove-hook hook fn 'local))
2441
2442     (flycheck-teardown))))
2443
2444
2445 ;;; Syntax checker selection for the current buffer
2446 (defun flycheck-get-checker-for-buffer ()
2447   "Find the checker for the current buffer.
2448
2449 Use the selected checker for the current buffer, if any,
2450 otherwise search for the best checker from `flycheck-checkers'.
2451
2452 Return checker if there is a checker for the current buffer, or
2453 nil otherwise."
2454   (if flycheck-checker
2455       (when (flycheck-may-use-checker flycheck-checker)
2456         flycheck-checker)
2457     (seq-find #'flycheck-may-use-checker flycheck-checkers)))
2458
2459 (defun flycheck-get-next-checker-for-buffer (checker)
2460   "Get the checker to run after CHECKER for the current buffer."
2461   (let ((next (seq-find #'flycheck-may-use-next-checker
2462                         (flycheck-checker-get checker 'next-checkers))))
2463     (when next
2464       (if (symbolp next) next (cdr next)))))
2465
2466 (defun flycheck-select-checker (checker)
2467   "Select CHECKER for the current buffer.
2468
2469 CHECKER is a syntax checker symbol (see `flycheck-checkers') or
2470 nil.  In the former case, use CHECKER for the current buffer,
2471 otherwise deselect the current syntax checker (if any) and use
2472 automatic checker selection via `flycheck-checkers'.
2473
2474 If called interactively prompt for CHECKER.  With prefix arg
2475 deselect the current syntax checker and enable automatic
2476 selection again.
2477
2478 Set `flycheck-checker' to CHECKER and automatically start a new
2479 syntax check if the syntax checker changed.
2480
2481 CHECKER will be used, even if it is not contained in
2482 `flycheck-checkers', or if it is disabled via
2483 `flycheck-disabled-checkers'."
2484   (interactive
2485    (if current-prefix-arg
2486        (list nil)
2487      (list (read-flycheck-checker "Select checker: "
2488                                   (flycheck-get-checker-for-buffer)))))
2489   (when (not (eq checker flycheck-checker))
2490     (unless (or (not checker) (flycheck-may-use-checker checker))
2491       (flycheck-verify-checker checker)
2492       (user-error "Can't use syntax checker %S in this buffer" checker))
2493     (setq flycheck-checker checker)
2494     (when flycheck-mode
2495       (flycheck-buffer))))
2496
2497 (defun flycheck-disable-checker (checker &optional enable)
2498   "Interactively disable CHECKER for the current buffer.
2499
2500 Interactively, prompt for a syntax checker to disable, and add
2501 the syntax checker to the buffer-local value of
2502 `flycheck-disabled-checkers'.
2503
2504 With non-nil ENABLE or with prefix arg, prompt for a disabled
2505 syntax checker and re-enable it by removing it from the
2506 buffer-local value of `flycheck-disabled-checkers'."
2507   (declare
2508    (interactive-only "Directly set `flycheck-disabled-checkers' instead"))
2509   (interactive
2510    (let* ((enable current-prefix-arg)
2511           (candidates (if enable flycheck-disabled-checkers flycheck-checkers))
2512           (prompt (if enable "Enable syntax checker: "
2513                     "Disable syntax checker: ")))
2514      (when (and enable (not candidates))
2515        (user-error "No syntax checkers disabled in this buffer"))
2516      (list (read-flycheck-checker prompt nil nil candidates) enable)))
2517   (unless checker
2518     (user-error "No syntax checker given"))
2519   (if enable
2520       ;; We must use `remq' instead of `delq', because we must _not_ modify the
2521       ;; list.  Otherwise we could potentially modify the global default value,
2522       ;; in case the list is the global default.
2523       (when (memq checker flycheck-disabled-checkers)
2524         (setq flycheck-disabled-checkers
2525               (remq checker flycheck-disabled-checkers))
2526         (flycheck-buffer))
2527     (unless (memq checker flycheck-disabled-checkers)
2528       (push checker flycheck-disabled-checkers)
2529       (flycheck-buffer))))
2530
2531
2532 ;;; Syntax checks for the current buffer
2533 (defvar-local flycheck-current-syntax-check nil
2534   "The current syntax check in the this buffer.")
2535 (put 'flycheck-current-syntax-check 'permanent-local t)
2536
2537 (defun flycheck-start-current-syntax-check (checker)
2538   "Start a syntax check in the current buffer with CHECKER.
2539
2540 Set `flycheck-current-syntax-check' accordingly."
2541   ;; Allocate the current syntax check *before* starting it.  This allows for
2542   ;; synchronous checks, which call the status callback immediately in their
2543   ;; start function.
2544   (let* ((check
2545           (flycheck-syntax-check-new
2546            :buffer (current-buffer)
2547            :checker checker
2548            :context nil
2549            :working-directory (flycheck-compute-working-directory checker)))
2550          (callback (flycheck-buffer-status-callback check)))
2551     (setq flycheck-current-syntax-check check)
2552     (flycheck-report-status 'running)
2553     (flycheck-syntax-check-start check callback)))
2554
2555 (defun flycheck-running-p ()
2556   "Determine whether a syntax check is running in the current buffer."
2557   (not (null flycheck-current-syntax-check)))
2558
2559 (defun flycheck-stop ()
2560   "Stop any ongoing syntax check in the current buffer."
2561   (when (flycheck-running-p)
2562     (flycheck-syntax-check-interrupt flycheck-current-syntax-check)
2563     ;; Remove the current syntax check, to reset Flycheck into a non-running
2564     ;; state, and to make `flycheck-report-buffer-checker-status' ignore any
2565     ;; status reports from the current syntax check.
2566     (setq flycheck-current-syntax-check nil)
2567     (flycheck-report-status 'interrupted)))
2568
2569 (defun flycheck-buffer-status-callback (syntax-check)
2570   "Create a status callback for SYNTAX-CHECK in the current buffer."
2571   (lambda (&rest args)
2572     (apply #'flycheck-report-buffer-checker-status
2573            syntax-check args)))
2574
2575 (defun flycheck-buffer ()
2576   "Start checking syntax in the current buffer.
2577
2578 Get a syntax checker for the current buffer with
2579 `flycheck-get-checker-for-buffer', and start it."
2580   (interactive)
2581   (flycheck-clean-deferred-check)
2582   (if flycheck-mode
2583       (unless (flycheck-running-p)
2584         ;; Clear error list and mark all overlays for deletion.  We do not
2585         ;; delete all overlays immediately to avoid excessive re-displays and
2586         ;; flickering, if the same errors gets highlighted again after the check
2587         ;; completed.
2588         (run-hooks 'flycheck-before-syntax-check-hook)
2589         (flycheck-clear-errors)
2590         (flycheck-mark-all-overlays-for-deletion)
2591         (condition-case err
2592             (let* ((checker (flycheck-get-checker-for-buffer)))
2593               (if checker
2594                   (flycheck-start-current-syntax-check checker)
2595                 (flycheck-clear)
2596                 (flycheck-report-status 'no-checker)))
2597           (error
2598            (flycheck-report-failed-syntax-check)
2599            (signal (car err) (cdr err)))))
2600     (user-error "Flycheck mode disabled")))
2601
2602 (defun flycheck-report-buffer-checker-status
2603     (syntax-check status &optional data)
2604   "In BUFFER, report a SYNTAX-CHECK STATUS with DATA.
2605
2606 SYNTAX-CHECK is the `flycheck-syntax-check' which reported
2607 STATUS.  STATUS denotes the status of CHECKER, with an optional
2608 DATA.  STATUS may be one of the following symbols:
2609
2610 `errored'
2611      The syntax checker has errored.  DATA is an optional error
2612      message.
2613
2614      This report finishes the current syntax check.
2615
2616 `interrupted'
2617      The syntax checker was interrupted.  DATA is ignored.
2618
2619      This report finishes the current syntax check.
2620
2621 `finished'
2622      The syntax checker has finished with a proper error report
2623      for the current buffer.  DATA is the (potentially empty)
2624      list of `flycheck-error' objects reported by the syntax
2625      check.
2626
2627      This report finishes the current syntax check.
2628
2629 `suspicious'
2630      The syntax checker encountered a suspicious state, which the
2631      user needs to be informed about.  DATA is an optional
2632      message.
2633
2634 A syntax checker _must_ report a status at least once with any
2635 symbol that finishes the current syntax checker.  Otherwise
2636 Flycheck gets stuck with the current syntax check.
2637
2638 If CHECKER is not the currently used syntax checker in
2639 `flycheck-current-syntax-check', the status report is largely
2640 ignored.  Notably, any errors reported by the checker are
2641 discarded."
2642   (let ((buffer (flycheck-syntax-check-buffer syntax-check)))
2643     ;; Ignore the status report if the buffer is gone, or if this syntax check
2644     ;; isn't the current one in buffer (which can happen if this is an old
2645     ;; report of an interrupted syntax check, and a new syntax check was started
2646     ;; since this check was interrupted)
2647     (when (and (buffer-live-p buffer)
2648                (eq syntax-check
2649                    (buffer-local-value 'flycheck-current-syntax-check buffer)))
2650       (with-current-buffer buffer
2651         (let ((checker (flycheck-syntax-check-checker syntax-check)))
2652           (pcase status
2653             ((or `errored `interrupted)
2654              (flycheck-report-failed-syntax-check status)
2655              (when (eq status 'errored)
2656                ;; In case of error, show the error message
2657                (message "Error from syntax checker %s: %s"
2658                         checker (or data "UNKNOWN!"))))
2659             (`suspicious
2660              (when flycheck-mode
2661                (message "Suspicious state from syntax checker %s: %s"
2662                         checker (or data "UNKNOWN!")))
2663              (flycheck-report-status 'suspicious))
2664             (`finished
2665              (when flycheck-mode
2666                ;; Only report errors from the checker if Flycheck Mode is
2667                ;; still enabled.
2668                (flycheck-finish-current-syntax-check
2669                 data
2670                 (flycheck-syntax-check-working-directory syntax-check))))
2671             (_
2672              (error "Unknown status %s from syntax checker %s"
2673                     status checker))))))))
2674
2675 (defun flycheck-finish-current-syntax-check (errors working-dir)
2676   "Finish the current syntax-check in the current buffer with ERRORS.
2677
2678 ERRORS is a list of `flycheck-error' objects reported by the
2679 current syntax check in `flycheck-current-syntax-check'.
2680
2681 Report all ERRORS and potentially start any next syntax checkers.
2682
2683 If the current syntax checker reported excessive errors, it is
2684 disabled via `flycheck-disable-excessive-checker' for subsequent
2685 syntax checks.
2686
2687 Relative file names in ERRORS will be expanded relative to
2688 WORKING-DIR."
2689   (let* ((syntax-check flycheck-current-syntax-check)
2690          (checker (flycheck-syntax-check-checker syntax-check))
2691          (errors (flycheck-relevant-errors
2692                   (flycheck-fill-and-expand-error-file-names
2693                    (flycheck-filter-errors
2694                     (flycheck-assert-error-list-p errors) checker)
2695                    working-dir))))
2696     (unless (flycheck-disable-excessive-checker checker errors)
2697       (flycheck-report-current-errors errors))
2698     (let ((next-checker (flycheck-get-next-checker-for-buffer checker)))
2699       (if next-checker
2700           (flycheck-start-current-syntax-check next-checker)
2701         (setq flycheck-current-syntax-check nil)
2702         (flycheck-report-status 'finished)
2703         ;; Delete overlays only after the very last checker has run, to avoid
2704         ;; flickering on intermediate re-displays
2705         (flycheck-delete-marked-overlays)
2706         (flycheck-error-list-refresh)
2707         (run-hooks 'flycheck-after-syntax-check-hook)
2708         (when (eq (current-buffer) (window-buffer))
2709           (flycheck-display-error-at-point))
2710         ;; Immediately try to run any pending deferred syntax check, which
2711         ;; were triggered by intermediate automatic check event, to make sure
2712         ;; that we quickly refine outdated error information
2713         (flycheck-perform-deferred-syntax-check)))))
2714
2715 (defun flycheck-disable-excessive-checker (checker errors)
2716   "Disable CHECKER if it reported excessive ERRORS.
2717
2718 If ERRORS has more items than `flycheck-checker-error-threshold',
2719 add CHECKER to `flycheck-disabled-checkers', and show a warning.
2720
2721 Return t when CHECKER was disabled, or nil otherwise."
2722   (when (and flycheck-checker-error-threshold
2723              (> (length errors) flycheck-checker-error-threshold))
2724     ;; Disable CHECKER for this buffer (`flycheck-disabled-checkers' is a local
2725     ;; variable).
2726     (lwarn '(flycheck syntax-checker) :warning
2727            "Syntax checker %s reported too many errors (%s) and is disabled."
2728            checker (length errors))
2729     (push checker flycheck-disabled-checkers)
2730     t))
2731
2732 (defun flycheck-clear (&optional shall-interrupt)
2733   "Clear all errors in the current buffer.
2734
2735 With prefix arg or SHALL-INTERRUPT non-nil, also interrupt the
2736 current syntax check."
2737   (interactive "P")
2738   (when shall-interrupt
2739     (flycheck-stop))
2740   (flycheck-delete-all-overlays)
2741   (flycheck-clear-errors)
2742   (flycheck-error-list-refresh)
2743   (flycheck-hide-error-buffer))
2744
2745 (defun flycheck-teardown ()
2746   "Teardown Flycheck in the current buffer..
2747
2748 Completely clear the whole Flycheck state.  Remove overlays, kill
2749 running checks, and empty all variables used by Flycheck."
2750   (flycheck-safe-delete-temporaries)
2751   (flycheck-stop)
2752   (flycheck-clean-deferred-check)
2753   (flycheck-clear)
2754   (flycheck-cancel-error-display-error-at-point-timer))
2755
2756
2757 ;;; Automatic syntax checking in a buffer
2758 (defun flycheck-may-check-automatically (&optional condition)
2759   "Determine whether the buffer may be checked under CONDITION.
2760
2761 Read-only buffers may never be checked automatically.
2762
2763 If CONDITION is non-nil, determine whether syntax may checked
2764 automatically according to
2765 `flycheck-check-syntax-automatically'."
2766   (and (not (or buffer-read-only (flycheck-ephemeral-buffer-p)))
2767        (file-exists-p default-directory)
2768        (or (not condition)
2769            (memq condition flycheck-check-syntax-automatically))))
2770
2771 (defun flycheck-buffer-automatically (&optional condition force-deferred)
2772   "Automatically check syntax at CONDITION.
2773
2774 Syntax is not checked if `flycheck-may-check-automatically'
2775 returns nil for CONDITION.
2776
2777 The syntax check is deferred if FORCE-DEFERRED is non-nil, or if
2778 `flycheck-must-defer-check' returns t."
2779   (when (and flycheck-mode (flycheck-may-check-automatically condition))
2780     (if (or force-deferred (flycheck-must-defer-check))
2781         (flycheck-buffer-deferred)
2782       (with-demoted-errors "Error while checking syntax automatically: %S"
2783         (flycheck-buffer)))))
2784
2785 (defvar-local flycheck-idle-change-timer nil
2786   "Timer to mark the idle time since the last change.")
2787
2788 (defun flycheck-clear-idle-change-timer ()
2789   "Clear the idle change timer."
2790   (when flycheck-idle-change-timer
2791     (cancel-timer flycheck-idle-change-timer)
2792     (setq flycheck-idle-change-timer nil)))
2793
2794 (defun flycheck-handle-change (beg end _len)
2795   "Handle a buffer change between BEG and END.
2796
2797 BEG and END mark the beginning and end of the change text.  _LEN
2798 is ignored.
2799
2800 Start a syntax check if a new line has been inserted into the
2801 buffer."
2802   ;; Save and restore the match data, as recommended in (elisp)Change Hooks
2803   (save-match-data
2804     (when flycheck-mode
2805       ;; The buffer was changed, thus clear the idle timer
2806       (flycheck-clear-idle-change-timer)
2807       (if (string-match-p (rx "\n") (buffer-substring beg end))
2808           (flycheck-buffer-automatically 'new-line 'force-deferred)
2809         (setq flycheck-idle-change-timer
2810               (run-at-time flycheck-idle-change-delay nil
2811                            #'flycheck--handle-idle-change-in-buffer
2812                            (current-buffer)))))))
2813
2814 (defun flycheck--handle-idle-change-in-buffer (buffer)
2815   "Handle an expired idle timer in BUFFER since the last change.
2816 This thin wrapper around `flycheck-handle-idle-change' is needed
2817 because some users override that function, as described in URL
2818 `https://github.com/flycheck/flycheck/pull/1305'."
2819   (when (buffer-live-p buffer)
2820     (with-current-buffer buffer
2821       (flycheck-handle-idle-change))))
2822
2823 (defun flycheck-handle-idle-change ()
2824   "Handle an expired idle timer since the last change."
2825   (flycheck-clear-idle-change-timer)
2826   (flycheck-buffer-automatically 'idle-change))
2827
2828 (defun flycheck-handle-save ()
2829   "Handle a save of the buffer."
2830   (flycheck-buffer-automatically 'save))
2831
2832
2833 ;;; Deferred syntax checking
2834 (defvar-local flycheck-deferred-syntax-check nil
2835   "If non-nil, a deferred syntax check is pending.")
2836
2837 (defun flycheck-must-defer-check ()
2838   "Determine whether the syntax check has to be deferred.
2839
2840 A check has to be deferred if the buffer is not visible, or if the buffer is
2841 currently being reverted.
2842
2843 Return t if the check is to be deferred, or nil otherwise."
2844   (or (not (get-buffer-window))
2845       ;; We defer the syntax check if Flycheck is already running, to
2846       ;; immediately start a new syntax check after the current one finished,
2847       ;; because the result of the current check will most likely be outdated by
2848       ;; the time it is finished.
2849       (flycheck-running-p)
2850       ;; We must defer checks while a buffer is being reverted, to avoid race
2851       ;; conditions while the buffer contents are being restored.
2852       revert-buffer-in-progress-p))
2853
2854 (defun flycheck-deferred-check-p ()
2855   "Determine whether the current buffer has a deferred check.
2856
2857 Return t if so, or nil otherwise."
2858   flycheck-deferred-syntax-check)
2859
2860 (defun flycheck-buffer-deferred ()
2861   "Defer syntax check for the current buffer."
2862   (setq flycheck-deferred-syntax-check t))
2863
2864 (defun flycheck-clean-deferred-check ()
2865   "Clean a deferred syntax checking state."
2866   (setq flycheck-deferred-syntax-check nil))
2867
2868 (defun flycheck-perform-deferred-syntax-check ()
2869   "Perform the deferred syntax check."
2870   (when (flycheck-deferred-check-p)
2871     (flycheck-clean-deferred-check)
2872     (flycheck-buffer-automatically)))
2873
2874
2875 ;;; Syntax checking in all buffers
2876 (defun flycheck-may-enable-mode ()
2877   "Determine whether Flycheck mode may be enabled.
2878
2879 Flycheck mode is not enabled for
2880
2881 - the minibuffer,
2882 - `fundamental-mode'
2883 - major modes whose `mode-class' property is `special',
2884 - ephemeral buffers (see `flycheck-ephemeral-buffer-p'),
2885 - encrypted buffers (see `flycheck-encrypted-buffer-p'),
2886 - remote files (see `file-remote-p'),
2887 - and major modes excluded by `flycheck-global-modes'.
2888
2889 Return non-nil if Flycheck mode may be enabled, and nil
2890 otherwise."
2891   (and (pcase flycheck-global-modes
2892          ;; Whether `major-mode' is disallowed by `flycheck-global-modes'
2893          (`t t)
2894          (`(not . ,modes) (not (memq major-mode modes)))
2895          (modes (memq major-mode modes)))
2896        (not (or (minibufferp)
2897                 (eq major-mode 'fundamental-mode)
2898                 (eq (get major-mode 'mode-class) 'special)
2899                 (flycheck-ephemeral-buffer-p)
2900                 (flycheck-encrypted-buffer-p)
2901                 (and (buffer-file-name)
2902                      (file-remote-p (buffer-file-name) 'method))))))
2903
2904 (defun flycheck-mode-on-safe ()
2905   "Enable command `flycheck-mode' if it is safe to do so.
2906
2907 Command `flycheck-mode' is only enabled if
2908 `flycheck-may-enable-mode' returns a non-nil result."
2909   (when (flycheck-may-enable-mode)
2910     (flycheck-mode)))
2911
2912 ;;;###autoload
2913 (define-globalized-minor-mode global-flycheck-mode flycheck-mode
2914   flycheck-mode-on-safe
2915   :init-value nil
2916   ;; Do not expose Global Flycheck Mode on customize interface, because the
2917   ;; interaction between package.el and customize is currently broken.  See
2918   ;; https://github.com/flycheck/flycheck/issues/595
2919
2920   ;; :require 'flycheck :group
2921   ;; 'flycheck
2922   )
2923
2924 (defun flycheck-global-teardown ()
2925   "Teardown Flycheck in all buffers.
2926
2927 Completely clear the whole Flycheck state in all buffers, stop
2928 all running checks, remove all temporary files, and empty all
2929 variables of Flycheck."
2930   (dolist (buffer (buffer-list))
2931     (with-current-buffer buffer
2932       (when flycheck-mode
2933         (flycheck-teardown)))))
2934
2935 ;; Clean up the entire state of Flycheck when Emacs is killed, to get rid of any
2936 ;; pending temporary files.
2937 (add-hook 'kill-emacs-hook #'flycheck-global-teardown)
2938
2939
2940 ;;; Errors from syntax checks
2941 (cl-defstruct (flycheck-error
2942                (:constructor flycheck-error-new)
2943                (:constructor flycheck-error-new-at
2944                              (line column
2945                                    &optional level message
2946                                    &key checker id group
2947                                    (filename (buffer-file-name))
2948                                    (buffer (current-buffer)))))
2949   "Structure representing an error reported by a syntax checker.
2950 Slots:
2951
2952 `buffer'
2953      The buffer that the error was reported for, as buffer object.
2954
2955 `checker'
2956      The syntax checker which reported this error, as symbol.
2957
2958 `filename'
2959      The file name the error refers to, as string.
2960
2961 `line'
2962      The line number the error refers to, as number.
2963
2964 `column' (optional)
2965      The column number the error refers to, as number.
2966
2967      For compatibility with external tools and unlike Emacs
2968      itself (e.g. in Compile Mode) Flycheck uses _1-based_
2969      columns: The first character on a line is column 1.
2970
2971      Occasionally some tools try to proactively adapt to Emacs
2972      and emit 0-based columns automatically.  In these cases, the
2973      columns must be adjusted for Flycheck, see
2974      `flycheck-increment-error-columns'.
2975
2976 `message' (optional)
2977      The error message as a string, if any.
2978
2979 `level'
2980      The error level, as either `info', `warning' or `error'.
2981
2982 `id' (optional)
2983      An ID identifying the kind of error.
2984
2985 `group` (optional)
2986      A symbol identifying the group the error belongs to.
2987
2988      Some tools will emit multiple errors that relate to the same
2989      issue (e.g., lifetime errors in Rust).  All related errors
2990      collected by a checker should have the same `group` value,
2991      in order to be able to present them to the user.
2992
2993      See `flycheck-related-errors`."
2994   buffer checker filename line column message level id group)
2995
2996 (defmacro flycheck-error-with-buffer (err &rest forms)
2997   "Switch to the buffer of ERR and evaluate FORMS.
2998
2999 If the buffer of ERR is not live, FORMS are not evaluated."
3000   (declare (indent 1) (debug t))
3001   `(when (buffer-live-p (flycheck-error-buffer ,err))
3002      (with-current-buffer (flycheck-error-buffer ,err)
3003        ,@forms)))
3004
3005 (defun flycheck-error-line-region (err)
3006   "Get the line region of ERR.
3007
3008 ERR is a Flycheck error whose region to get.
3009
3010 Return a cons cell `(BEG . END)' where BEG is the first
3011 non-whitespace character on the line ERR refers to, and END the
3012 end of the line."
3013   (flycheck-error-with-buffer err
3014     (save-restriction
3015       (save-excursion
3016         (widen)
3017         (goto-char (point-min))
3018         (forward-line (- (flycheck-error-line err) 1))
3019         ;; We are at the beginning of the line now, so move to the beginning of
3020         ;; its indentation, similar to `back-to-indentation'
3021         (let ((end (line-end-position)))
3022           (skip-syntax-forward " " end)
3023           (backward-prefix-chars)
3024           ;; If the current line is empty, include the previous line break
3025           ;; character(s) to have any region at all.  When called with 0,
3026           ;; `line-end-position' gives us the end of the previous line
3027           (cons (if (eolp) (line-end-position 0) (point)) end))))))
3028
3029 (defun flycheck-error-column-region (err)
3030   "Get the error column region of ERR.
3031
3032 ERR is a Flycheck error whose region to get.
3033
3034 Return a cons cell `(BEG . END)' where BEG is the character
3035 before the error column, and END the actual error column, or nil
3036 if ERR has no column."
3037   (flycheck-error-with-buffer err
3038     (save-restriction
3039       (save-excursion
3040         (-when-let (column (flycheck-error-column err))
3041           (widen)
3042           (goto-char (point-min))
3043           (forward-line (- (flycheck-error-line err) 1))
3044           (cond
3045            ((eobp)                    ; Line beyond EOF
3046             ;; If we are at the end of the file (i.e. the line was beyond the
3047             ;; end of the file), use the very last column in the file.
3048             (cons (- (point-max) 1) (point-max)))
3049            ((eolp)                    ; Empty line
3050             ;; If the target line is empty, there's no column to highlight on
3051             ;; this line, so return the last column of the previous line.
3052             (cons (line-end-position 0) (point)))
3053            (t
3054             ;; The end is either the column offset of the line, or the end of
3055             ;; the line, if the column offset points beyond the end of the
3056             ;; line.
3057             (let ((end (min (+ (point) column)
3058                             (+ (line-end-position) 1))))
3059               (cons (- end 1) end)))))))))
3060
3061 (defun flycheck-error-thing-region (thing err)
3062   "Get the region of THING at the column of ERR.
3063
3064 ERR is a Flycheck error whose region to get.  THING is a
3065 understood by `thing-at-point'.
3066
3067 Return a cons cell `(BEG . END)' where BEG is the beginning of
3068 the THING at the error column, and END the end of the symbol.  If
3069 ERR has no error column, or if there is no THING at this column,
3070 return nil."
3071   (-when-let (column (car (flycheck-error-column-region err)))
3072     (flycheck-error-with-buffer err
3073       (save-excursion
3074         (save-restriction
3075           (widen)
3076           (goto-char column)
3077           (bounds-of-thing-at-point thing))))))
3078
3079 (defun flycheck-error-region-for-mode (err mode)
3080   "Get the region of ERR for the highlighting MODE.
3081
3082 ERR is a Flycheck error.  MODE may be one of the following symbols:
3083
3084 `columns'
3085      Get the column region of ERR, or the line region if ERR
3086      has no column.
3087
3088 `symbols'
3089      Get the symbol region of ERR, or the result of `columns', if
3090      there is no sexp at the error column.
3091
3092 `sexps'
3093      Get the sexp region of ERR, or the result of `columns', if
3094      there is no sexp at the error column.
3095
3096 `lines'
3097      Return the line region.
3098
3099 Otherwise signal an error."
3100   ;; Ignoring fields speeds up calls to `line-end-position' in
3101   ;; `flycheck-error-column-region' and `flycheck-error-line-region'.
3102   (let ((inhibit-field-text-motion t))
3103     (pcase mode
3104       (`columns (or (flycheck-error-column-region err)
3105                     (flycheck-error-line-region err)))
3106       (`symbols (or (flycheck-error-thing-region 'symbol err)
3107                     (flycheck-error-region-for-mode err 'columns)))
3108       (`sexps (or (flycheck-error-thing-region 'sexp err)
3109                   (flycheck-error-region-for-mode err 'columns)))
3110       (`lines (flycheck-error-line-region err))
3111       (_ (error "Invalid mode %S" mode)))))
3112
3113 (defun flycheck-error-pos (err)
3114   "Get the buffer position of ERR.
3115
3116 ERR is a Flycheck error whose position to get.
3117
3118 The error position is the error column, or the first
3119 non-whitespace character of the error line, if ERR has no error column."
3120   (car (or (flycheck-error-column-region err)
3121            (flycheck-error-line-region err))))
3122
3123 (defun flycheck-error-format-message-and-id (err)
3124   "Format the message and id of ERR as human-readable string."
3125   (let ((id (flycheck-error-id err))
3126         (filename (flycheck-error-filename err)))
3127     (concat (when (and filename (not (equal filename (buffer-file-name))))
3128               (format "In \"%s\":\n"
3129                       (file-relative-name filename default-directory)))
3130             (flycheck-error-message err)
3131             (when id
3132               (format " [%s]" id)))))
3133
3134 (defun flycheck-error-format (err &optional with-file-name)
3135   "Format ERR as human-readable string, optionally WITH-FILE-NAME.
3136
3137 Return a string that represents the given ERR.  If WITH-FILE-NAME
3138 is given and non-nil, include the file-name as well, otherwise
3139 omit it."
3140   (let* ((line (flycheck-error-line err))
3141          (column (flycheck-error-column err))
3142          (level (symbol-name (flycheck-error-level err)))
3143          (checker (symbol-name (flycheck-error-checker err)))
3144          (format `(,@(when with-file-name
3145                        (list (flycheck-error-filename err) ":"))
3146                    ,(number-to-string line) ":"
3147                    ,@(when column (list (number-to-string column) ":"))
3148                    ,level ": "
3149                    ,(flycheck-error-format-message-and-id err)
3150                    " (" ,checker ")")))
3151     (apply #'concat format)))
3152
3153 (defun flycheck-error-< (err1 err2)
3154   "Determine whether ERR1 is less than ERR2 by location.
3155
3156 Compare by line numbers and then by column numbers."
3157   (let ((line1 (flycheck-error-line err1))
3158         (line2 (flycheck-error-line err2)))
3159     (if (= line1 line2)
3160         (let ((col1 (flycheck-error-column err1))
3161               (col2 (flycheck-error-column err2)))
3162           (and col2
3163                ;; Sort errors for the whole line first
3164                (or (not col1) (< col1 col2))))
3165       (< line1 line2))))
3166
3167 (defun flycheck-error-level-< (err1 err2)
3168   "Determine whether ERR1 is less than ERR2 by error level.
3169
3170 Like `flycheck-error-<', but compares by error level severity
3171 first.  Levels of the same severity are compared by name."
3172   (let* ((level1 (flycheck-error-level err1))
3173          (level2 (flycheck-error-level err2))
3174          (severity1 (flycheck-error-level-severity level1))
3175          (severity2 (flycheck-error-level-severity level2)))
3176     (cond
3177      ((= severity1 severity2)
3178       (if (string= level1 level2)
3179           (flycheck-error-< err1 err2)
3180         (string< level1 level2)))
3181      (t (< severity1 severity2)))))
3182
3183 (defun flycheck-assert-error-list-p (errors)
3184   "Assert that all items in ERRORS are of `flycheck-error' type.
3185
3186 Signal an error if any item in ERRORS is not a `flycheck-error'
3187 object, as by `flycheck-error-p'.  Otherwise return ERRORS
3188 again."
3189   (unless (listp errors)
3190     (signal 'wrong-type-argument (list 'listp errors)))
3191   (dolist (err errors)
3192     (unless (flycheck-error-p err)
3193       (signal 'wrong-type-argument (list 'flycheck-error-p err))))
3194   errors)
3195
3196
3197 ;;; Errors in the current buffer
3198 (defvar-local flycheck-current-errors nil
3199   "A list of all errors and warnings in the current buffer.")
3200
3201 (defun flycheck-report-current-errors (errors)
3202   "Report ERRORS in the current buffer.
3203
3204 Add ERRORS to `flycheck-current-errors' and process each error
3205 with `flycheck-process-error-functions'."
3206   (setq flycheck-current-errors (sort (append errors flycheck-current-errors)
3207                                       #'flycheck-error-<))
3208   (overlay-recenter (point-max))
3209   (seq-do (lambda (err)
3210             (run-hook-with-args-until-success 'flycheck-process-error-functions
3211                                               err))
3212           errors))
3213
3214 (defun flycheck-clear-errors ()
3215   "Remove all error information from the current buffer."
3216   (setq flycheck-current-errors nil)
3217   (flycheck-report-status 'not-checked))
3218
3219 (defun flycheck-fill-and-expand-error-file-names (errors directory)
3220   "Fill and expand file names in ERRORS relative to DIRECTORY.
3221
3222 Expand all file names of ERRORS against DIRECTORY.  If the file
3223 name of an error is nil fill in the result of function
3224 `buffer-file-name' in the current buffer.
3225
3226 Return ERRORS, modified in-place."
3227   (seq-do (lambda (err)
3228             (setf (flycheck-error-filename err)
3229                   (-if-let (filename (flycheck-error-filename err))
3230                       (expand-file-name filename directory)
3231                     (buffer-file-name))))
3232           errors)
3233   errors)
3234
3235 (defun flycheck-relevant-error-other-file-p (err)
3236   "Determine whether ERR is a relevant error for another file."
3237   (let ((file-name (flycheck-error-filename err)))
3238     (and file-name
3239          (or (null buffer-file-name)
3240              (not (flycheck-same-files-p buffer-file-name file-name)))
3241          (eq 'error (flycheck-error-level err)))))
3242
3243 (defun flycheck-relevant-error-p (err)
3244   "Determine whether ERR is relevant for the current buffer.
3245
3246 Return t if ERR may be shown for the current buffer, or nil
3247 otherwise."
3248   (flycheck-error-with-buffer err
3249     (let ((file-name (flycheck-error-filename err))
3250           (message (flycheck-error-message err)))
3251       (and
3252        (or
3253         ;; Neither the error nor buffer have a file name
3254         (and (not file-name) (not buffer-file-name))
3255         ;; Both have files, and they match
3256         (and buffer-file-name file-name
3257              (flycheck-same-files-p file-name buffer-file-name))
3258         ;; This is a significant error from another file
3259         (flycheck-relevant-error-other-file-p err))
3260        message
3261        (not (string-empty-p message))
3262        (flycheck-error-line err)))))
3263
3264 (defun flycheck-relevant-errors (errors)
3265   "Filter the relevant errors from ERRORS.
3266
3267 Return a list of all errors that are relevant for their
3268 corresponding buffer."
3269   (seq-filter #'flycheck-relevant-error-p errors))
3270
3271 (defun flycheck-related-errors (err &optional error-set)
3272   "Get all the errors that are in the same group as ERR.
3273
3274 Return a list of all errors (from ERROR-SET) that have the same
3275 `flycheck-error-group' as ERR, including ERR itself.
3276
3277 If ERROR-SET is nil, `flycheck-current-errors' is used instead."
3278   (let ((group (flycheck-error-group err))
3279         (checker (flycheck-error-checker err)))
3280     (if group
3281         (seq-filter (lambda (e)
3282                       (and (eq (flycheck-error-checker e) checker)
3283                            (eq (flycheck-error-group e) group)))
3284                     (or error-set flycheck-current-errors))
3285       (list err))))
3286
3287
3288 ;;; Status reporting for the current buffer
3289 (defvar-local flycheck-last-status-change 'not-checked
3290   "The last status change in the current buffer.")
3291
3292 (defun flycheck-report-failed-syntax-check (&optional status)
3293   "Report a failed Flycheck syntax check with STATUS.
3294
3295 STATUS is a status symbol for `flycheck-report-status',
3296 defaulting to `errored'.
3297
3298 Clear Flycheck state, run `flycheck-syntax-check-failed-hook' and
3299 report an error STATUS."
3300   (flycheck-clear)
3301   (setq flycheck-current-syntax-check nil)
3302   (run-hooks 'flycheck-syntax-check-failed-hook)
3303   (flycheck-report-status (or status 'errored)))
3304
3305 (defun flycheck-report-status (status)
3306   "Report Flycheck STATUS.
3307
3308 STATUS is one of the following symbols:
3309
3310 `not-checked'
3311      The current buffer was not checked.
3312
3313 `no-checker'
3314      Automatic syntax checker selection did not find a suitable
3315      syntax checker.
3316
3317 `running'
3318      A syntax check is now running in the current buffer.
3319
3320 `errored'
3321      The current syntax check has errored.
3322
3323 `finished'
3324      The current syntax check was finished normally.
3325
3326 `interrupted'
3327      The current syntax check was interrupted.
3328
3329 `suspicious'
3330      The last syntax check had a suspicious result.
3331
3332 Set `flycheck-last-status-change' and call
3333 `flycheck-status-changed-functions' with STATUS.  Afterwards
3334 refresh the mode line."
3335   (setq flycheck-last-status-change status)
3336   (run-hook-with-args 'flycheck-status-changed-functions status)
3337   (force-mode-line-update))
3338
3339 (defun flycheck-mode-line-status-text (&optional status)
3340   "Get a text describing STATUS for use in the mode line.
3341
3342 STATUS defaults to `flycheck-last-status-change' if omitted or
3343 nil."
3344   (let ((text (pcase (or status flycheck-last-status-change)
3345                 (`not-checked "")
3346                 (`no-checker "-")
3347                 (`running "*")
3348                 (`errored "!")
3349                 (`finished
3350                  (let-alist (flycheck-count-errors flycheck-current-errors)
3351                    (if (or .error .warning)
3352                        (format ":%s/%s" (or .error 0) (or .warning 0))
3353                      "")))
3354                 (`interrupted ".")
3355                 (`suspicious "?"))))
3356     (concat " " flycheck-mode-line-prefix text)))
3357
3358
3359 ;;; Error levels
3360 ;;;###autoload
3361 (defun flycheck-define-error-level (level &rest properties)
3362   "Define a new error LEVEL with PROPERTIES.
3363
3364 The following PROPERTIES constitute an error level:
3365
3366 `:severity SEVERITY'
3367      A number denoting the severity of this level.  The higher
3368      the number, the more severe is this level compared to other
3369      levels.  Defaults to 0.
3370
3371      The severity is used by `flycheck-error-level-<' to
3372      determine the ordering of errors according to their levels.
3373
3374 `:compilation-level LEVEL'
3375
3376      A number indicating the broad class of messages that errors
3377      at this level belong to: one of 0 (info), 1 (warning), or
3378      2 or nil (error).  Defaults to nil.
3379
3380      This is used by `flycheck-checker-pattern-to-error-regexp'
3381      to map error levels into `compilation-mode''s hierarchy and
3382      to get proper highlighting of errors in `compilation-mode'.
3383
3384 `:overlay-category CATEGORY'
3385      A symbol denoting the overlay category to use for error
3386      highlight overlays for this level.  See Info
3387      node `(elisp)Overlay Properties' for more information about
3388      overlay categories.
3389
3390      A category for an error level overlay should at least define
3391      the `face' property, for error highlighting.  Another useful
3392      property for error level categories is `priority', to
3393      influence the stacking of multiple error level overlays.
3394
3395 `:fringe-bitmap BITMAP'
3396      A fringe bitmap symbol denoting the bitmap to use for fringe
3397      indicators for this level.  See Info node `(elisp)Fringe
3398      Bitmaps' for more information about fringe bitmaps,
3399      including a list of built-in fringe bitmaps.
3400
3401 `:fringe-face FACE'
3402      A face symbol denoting the face to use for fringe indicators
3403      for this level.
3404
3405 `:error-list-face FACE'
3406      A face symbol denoting the face to use for messages of this
3407      level in the error list.  See `flycheck-list-errors'."
3408   (declare (indent 1))
3409   (setf (get level 'flycheck-error-level) t)
3410   (setf (get level 'flycheck-error-severity)
3411         (or (plist-get properties :severity) 0))
3412   (setf (get level 'flycheck-compilation-level)
3413         (plist-get properties :compilation-level))
3414   (setf (get level 'flycheck-overlay-category)
3415         (plist-get properties :overlay-category))
3416   (setf (get level 'flycheck-fringe-bitmap-double-arrow)
3417         (plist-get properties :fringe-bitmap))
3418   (setf (get level 'flycheck-fringe-face)
3419         (plist-get properties :fringe-face))
3420   (setf (get level 'flycheck-error-list-face)
3421         (plist-get properties :error-list-face)))
3422
3423 (defun flycheck-error-level-p (level)
3424   "Determine whether LEVEL is a Flycheck error level."
3425   (get level 'flycheck-error-level))
3426
3427 (defun flycheck-error-level-severity (level)
3428   "Get the numeric severity of LEVEL."
3429   (or (get level 'flycheck-error-severity) 0))
3430
3431 (defun flycheck-error-level-compilation-level (level)
3432   "Get the compilation level for LEVEL."
3433   (get level 'flycheck-compilation-level))
3434
3435 (defun flycheck-error-level-overlay-category (level)
3436   "Get the overlay category for LEVEL."
3437   (get level 'flycheck-overlay-category))
3438
3439 (defun flycheck-error-level-fringe-bitmap (level)
3440   "Get the fringe bitmap for LEVEL."
3441   (get level 'flycheck-fringe-bitmap-double-arrow))
3442
3443 (defun flycheck-error-level-fringe-face (level)
3444   "Get the fringe face for LEVEL."
3445   (get level 'flycheck-fringe-face))
3446
3447 (defun flycheck-error-level-error-list-face (level)
3448   "Get the error list face for LEVEL."
3449   (get level 'flycheck-error-list-face))
3450
3451 (defun flycheck-error-level-make-fringe-icon (level side)
3452   "Create the fringe icon for LEVEL at SIDE.
3453
3454 Return a propertized string that shows a fringe bitmap according
3455 to LEVEL and the given fringe SIDE.
3456
3457 LEVEL is a Flycheck error level defined with
3458 `flycheck-define-error-level', and SIDE is either `left-fringe'
3459 or `right-fringe'.
3460
3461 Return a propertized string representing the fringe icon,
3462 intended for use as `before-string' of an overlay to actually
3463 show the icon."
3464   (unless (memq side '(left-fringe right-fringe))
3465     (error "Invalid fringe side: %S" side))
3466   (propertize "!" 'display
3467               (list side
3468                     (flycheck-error-level-fringe-bitmap level)
3469                     (flycheck-error-level-fringe-face level))))
3470
3471
3472 ;;; Built-in error levels
3473 (when (fboundp 'define-fringe-bitmap)
3474   (define-fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
3475     (vector #b00000000
3476             #b00000000
3477             #b00000000
3478             #b00000000
3479             #b00000000
3480             #b10011000
3481             #b01101100
3482             #b00110110
3483             #b00011011
3484             #b00110110
3485             #b01101100
3486             #b10011000
3487             #b00000000
3488             #b00000000
3489             #b00000000
3490             #b00000000
3491             #b00000000)))
3492
3493 (setf (get 'flycheck-error-overlay 'face) 'flycheck-error)
3494 (setf (get 'flycheck-error-overlay 'priority) 110)
3495
3496 (flycheck-define-error-level 'error
3497   :severity 100
3498   :compilation-level 2
3499   :overlay-category 'flycheck-error-overlay
3500   :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
3501   :fringe-face 'flycheck-fringe-error
3502   :error-list-face 'flycheck-error-list-error)
3503
3504 (setf (get 'flycheck-warning-overlay 'face) 'flycheck-warning)
3505 (setf (get 'flycheck-warning-overlay 'priority) 100)
3506
3507 (flycheck-define-error-level 'warning
3508   :severity 10
3509   :compilation-level 1
3510   :overlay-category 'flycheck-warning-overlay
3511   :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
3512   :fringe-face 'flycheck-fringe-warning
3513   :error-list-face 'flycheck-error-list-warning)
3514
3515 (setf (get 'flycheck-info-overlay 'face) 'flycheck-info)
3516 (setf (get 'flycheck-info-overlay 'priority) 90)
3517
3518 (flycheck-define-error-level 'info
3519   :severity -10
3520   :compilation-level 0
3521   :overlay-category 'flycheck-info-overlay
3522   :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
3523   :fringe-face 'flycheck-fringe-info
3524   :error-list-face 'flycheck-error-list-info)
3525
3526
3527 ;;; Error filtering
3528 (defun flycheck-filter-errors (errors checker)
3529   "Filter ERRORS from CHECKER.
3530
3531 Apply the error filter of CHECKER to ERRORs and return the
3532 result.  If CHECKER has no error filter, fall back to
3533 `flycheck-sanitize-errors'."
3534   (let ((filter (or (flycheck-checker-get checker 'error-filter)
3535                     #'flycheck-sanitize-errors)))
3536     (funcall filter errors)))
3537
3538 (defun flycheck-sanitize-errors (errors)
3539   "Sanitize ERRORS.
3540
3541 Sanitize ERRORS by trimming leading and trailing whitespace in
3542 all error messages, and by replacing 0 columns and empty error
3543 messages with nil.
3544
3545 Returns sanitized ERRORS."
3546   (dolist (err errors)
3547     (flycheck-error-with-buffer err
3548       (let ((message (flycheck-error-message err))
3549             (column (flycheck-error-column err))
3550             (id (flycheck-error-id err)))
3551         (when message
3552           (setq message (string-trim message))
3553           (setf (flycheck-error-message err)
3554                 (if (string-empty-p message) nil message)))
3555         (when (and id (string-empty-p id))
3556           (setf (flycheck-error-id err) nil))
3557         (when (eq column 0)
3558           (setf (flycheck-error-column err) nil)))))
3559   errors)
3560
3561 (defun flycheck-remove-error-file-names (file-name errors)
3562   "Remove matching FILE-NAME from ERRORS.
3563
3564 Use as `:error-filter' for syntax checkers that output faulty
3565 filenames.  Flycheck will later fill in the buffer file name.
3566
3567 Return ERRORS."
3568   (seq-do (lambda (err)
3569             (when (and (flycheck-error-filename err)
3570                        (string= (flycheck-error-filename err) file-name))
3571               (setf (flycheck-error-filename err) nil)))
3572           errors)
3573   errors)
3574
3575 (defun flycheck-increment-error-columns (errors &optional offset)
3576   "Increment all columns of ERRORS by OFFSET.
3577
3578 Use this as `:error-filter' if a syntax checker outputs 0-based
3579 columns."
3580   (seq-do (lambda (err)
3581             (let ((column (flycheck-error-column err)))
3582               (when column
3583                 (setf (flycheck-error-column err)
3584                       (+ column (or offset 1))))))
3585           errors)
3586   errors)
3587
3588 (defun flycheck-collapse-error-message-whitespace (errors)
3589   "Collapse whitespace in all messages of ERRORS.
3590
3591 Return ERRORS."
3592   (dolist (err errors)
3593     (-when-let (message (flycheck-error-message err))
3594       (setf (flycheck-error-message err)
3595             (replace-regexp-in-string (rx (one-or-more (any space "\n" "\r")))
3596                                       " " message 'fixed-case 'literal))))
3597   errors)
3598
3599 (defun flycheck-dedent-error-messages (errors)
3600   "Dedent all messages of ERRORS.
3601
3602 For each error in ERRORS, determine the indentation offset from
3603 the leading whitespace of the first line, and dedent all further
3604 lines accordingly.
3605
3606 Return ERRORS, with in-place modifications."
3607   (dolist (err errors)
3608     (-when-let (message (flycheck-error-message err))
3609       (with-temp-buffer
3610         (insert message)
3611         ;; Determine the indentation offset
3612         (goto-char (point-min))
3613         (back-to-indentation)
3614         (let* ((indent-offset (- (point) (point-min))))
3615           ;; Now iterate over all lines and dedent each according to
3616           ;; `indent-offset'
3617           (while (not (eobp))
3618             (back-to-indentation)
3619             ;; If the current line starts with sufficient whitespace, delete the
3620             ;; indendation offset.  Otherwise keep the line intact, as we might
3621             ;; loose valuable information
3622             (when (>= (- (point) (line-beginning-position)) indent-offset)
3623               (delete-char (- indent-offset)))
3624             (forward-line 1)))
3625         (delete-trailing-whitespace (point-min) (point-max))
3626         (setf (flycheck-error-message err)
3627               (buffer-substring-no-properties (point-min) (point-max))))))
3628   errors)
3629
3630 (defun flycheck-fold-include-levels (errors sentinel-message)
3631   "Fold levels of ERRORS from included files.
3632
3633 ERRORS is a list of `flycheck-error' objects.  SENTINEL-MESSAGE
3634 is a regular expression matched against the error message to
3635 determine whether the errror denotes errors from an included
3636 file.  Alternatively, it is a function that is given an error and
3637 shall return non-nil, if the error denotes errors from an
3638 included file."
3639   (unless (or (stringp sentinel-message) (functionp sentinel-message))
3640     (error "Sentinel must be string or function: %S" sentinel-message))
3641   (let ((sentinel (if (functionp sentinel-message)
3642                       sentinel-message
3643                     (lambda (err)
3644                       (string-match-p sentinel-message
3645                                       (flycheck-error-message err)))))
3646         (remaining-errors errors))
3647     (while remaining-errors
3648       (let* ((current-error (pop remaining-errors)))
3649         (when (funcall sentinel current-error)
3650           ;; We found an error denoting errors in the included file:
3651           ;; 1. process all subsequent errors until faulty include file is found
3652           ;; 2. process again all subsequent errors until an error has the
3653           ;;    current file name again
3654           ;; 3. find the most severe error level
3655           (let ((current-filename (flycheck-error-filename current-error))
3656                 (current-level nil)
3657                 (faulty-include-filename nil)
3658                 (filename nil)
3659                 (done (null remaining-errors)))
3660
3661             (while (not done)
3662               (setq filename (flycheck-error-filename (car remaining-errors)))
3663               (unless faulty-include-filename
3664                 (unless (string= filename current-filename)
3665                   (setq faulty-include-filename filename)))
3666
3667               (let* ((error-in-include (pop remaining-errors))
3668                      (in-include-level (flycheck-error-level error-in-include)))
3669                 (unless (funcall sentinel error-in-include)
3670                   ;; Ignore nested "included file" errors, we are only
3671                   ;; interested in real errors because these define our level
3672                   (when (or (not current-level)
3673                             (> (flycheck-error-level-severity in-include-level)
3674                                (flycheck-error-level-severity current-level)))
3675                     (setq current-level in-include-level))))
3676
3677               (setq done (or (null remaining-errors)
3678                              (and faulty-include-filename
3679                                   (string= filename current-filename)))))
3680
3681             (setf (flycheck-error-level current-error) current-level
3682                   (flycheck-error-message current-error)
3683                   (format "In include %s" faulty-include-filename))))))
3684     errors))
3685
3686 (defun flycheck-dequalify-error-ids (errors)
3687   "De-qualify error ids in ERRORS.
3688
3689 Remove all qualifications from error ids in ERRORS, by stripping
3690 all leading dotted components from error IDs.  For instance, if
3691 the error ID is com.foo.E100, replace it with E100.
3692
3693 This error filter is mainly useful to simplify error IDs obtained
3694 from parsing Checkstyle XML, which frequently has very verbose
3695 IDs, that include the name of the tool."
3696   (seq-do (lambda (err)
3697             (let ((id (flycheck-error-id err)))
3698               (when id
3699                 (setf (flycheck-error-id err)
3700                       (replace-regexp-in-string
3701                        (rx string-start
3702                            (group
3703                             (optional (zero-or-more not-newline) "."))
3704                            (one-or-more (not (any ".")))
3705                            string-end)
3706                        "" id 'fixedcase 'literal 1)))))
3707           errors)
3708   errors)
3709
3710 (defun flycheck-remove-error-ids (errors)
3711   "Remove all error ids from ERRORS."
3712   (seq-do (lambda (err) (setf (flycheck-error-id err) nil)) errors)
3713   errors)
3714
3715 (defun flycheck-fill-empty-line-numbers (errors)
3716   "Set ERRORS without lines to line 0.
3717
3718 Use as `:error-filter' for syntax checkers that output errors
3719 without line numbers.
3720
3721 Return ERRORS."
3722   (seq-do (lambda (err)
3723             (unless (flycheck-error-line err)
3724               (setf (flycheck-error-line err) 0)))
3725           errors)
3726   errors)
3727
3728
3729 ;;; Error analysis
3730 (defun flycheck-count-errors (errors)
3731   "Count the number of ERRORS, grouped by level..
3732
3733 Return an alist, where each ITEM is a cons cell whose `car' is an
3734 error level, and whose `cdr' is the number of errors of that
3735 level."
3736   (let (counts-by-level)
3737     (dolist (err errors)
3738       (let* ((level (flycheck-error-level err))
3739              (item (assq level counts-by-level)))
3740         (if item
3741             (cl-incf (cdr item))
3742           (push (cons level 1) counts-by-level))))
3743     counts-by-level))
3744
3745 (defun flycheck-has-max-errors-p (errors level)
3746   "Check if there is no error in ERRORS more severe than LEVEL."
3747   (let ((severity (flycheck-error-level-severity level)))
3748     (seq-every-p (lambda (e) (<= (flycheck-error-level-severity
3749                                   (flycheck-error-level e))
3750                                  severity))
3751                  errors)))
3752
3753 (defun flycheck-has-max-current-errors-p (level)
3754   "Check if there is no current error more severe than LEVEL."
3755   (flycheck-has-max-errors-p flycheck-current-errors level))
3756
3757 (defun flycheck-has-errors-p (errors level)
3758   "Determine if there are any ERRORS with LEVEL."
3759   (seq-some (lambda (e) (eq (flycheck-error-level e) level)) errors))
3760
3761 (defun flycheck-has-current-errors-p (&optional level)
3762   "Determine if the current buffer has errors with LEVEL.
3763
3764 If LEVEL is omitted if the current buffer has any errors at all."
3765   (if level
3766       (flycheck-has-errors-p flycheck-current-errors level)
3767     (and flycheck-current-errors t)))
3768
3769
3770 ;;; Error overlays in the current buffer
3771 (defun flycheck-add-overlay (err)
3772   "Add overlay for ERR.
3773
3774 Return the created overlay."
3775   ;; We must have a proper error region for the sake of fringe indication,
3776   ;; error display and error navigation, even if the highlighting is disabled.
3777   ;; We erase the highlighting later on in this case
3778   (pcase-let* ((`(,beg . ,end)
3779                 (if (flycheck-relevant-error-other-file-p err)
3780                     ;; Display overlays for other-file errors on the first line
3781                     (cons (point-min)
3782                           (save-excursion (goto-char (point-min))
3783                                           (point-at-eol)))
3784                   (flycheck-error-region-for-mode
3785                    err (or flycheck-highlighting-mode 'lines))))
3786                (overlay (make-overlay beg end))
3787                (level (flycheck-error-level err))
3788                (category (flycheck-error-level-overlay-category level)))
3789     (unless (flycheck-error-level-p level)
3790       (error "Undefined error level: %S" level))
3791     (setf (overlay-get overlay 'flycheck-overlay) t)
3792     (setf (overlay-get overlay 'flycheck-error) err)
3793     (setf (overlay-get overlay 'category) category)
3794     (unless flycheck-highlighting-mode
3795       ;; Erase the highlighting from the overlay if requested by the user
3796       (setf (overlay-get overlay 'face) nil))
3797     (when flycheck-indication-mode
3798       (setf (overlay-get overlay 'before-string)
3799             (flycheck-error-level-make-fringe-icon
3800              level flycheck-indication-mode)))
3801     (setf (overlay-get overlay 'help-echo) #'flycheck-help-echo)
3802     overlay))
3803
3804 (defun flycheck-help-echo (_window object pos)
3805   "Construct a tooltip message.
3806
3807 Most of the actual work is done by calling
3808 `flycheck-help-echo-function' with the appropriate list of
3809 errors.  Arguments WINDOW, OBJECT and POS are as described in
3810 info node `(elisp)Special properties', as this function is
3811 intended to be used as the 'help-echo property of flycheck error
3812 overlays."
3813   (-when-let (buf (cond ((bufferp object) object)
3814                         ((overlayp object) (overlay-buffer object))))
3815     (with-current-buffer buf
3816       (-when-let* ((fn flycheck-help-echo-function)
3817                    (errs (flycheck-overlay-errors-at pos)))
3818         (funcall fn errs)))))
3819
3820 (defun flycheck-help-echo-all-error-messages (errs)
3821   "Concatenate error messages and ids from ERRS."
3822   (mapconcat
3823    (lambda (err)
3824      (when err
3825        (if (flycheck-error-message err)
3826            (flycheck-error-format-message-and-id err)
3827          (format "Unknown %s" (flycheck-error-level err)))))
3828    (reverse errs) "\n\n"))
3829
3830 (defun flycheck-filter-overlays (overlays)
3831   "Get all Flycheck overlays from OVERLAYS."
3832   (seq-filter (lambda (o) (overlay-get o 'flycheck-overlay)) overlays))
3833
3834 (defun flycheck-overlays-at (pos)
3835   "Get all Flycheck overlays at POS."
3836   (flycheck-filter-overlays (overlays-at pos)))
3837
3838 (defun flycheck-overlays-in (beg end)
3839   "Get all Flycheck overlays between BEG and END."
3840   (flycheck-filter-overlays (overlays-in beg end)))
3841
3842 (defun flycheck-overlay-errors-at (pos)
3843   "Return a list of all flycheck errors overlayed at POS."
3844   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
3845            (flycheck-overlays-at pos)))
3846
3847 (defun flycheck-overlay-errors-in (beg end)
3848   "Return a list of all flycheck errors overlayed between BEG and END."
3849   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
3850            (flycheck-overlays-in beg end)))
3851
3852 (defvar-local flycheck-overlays-to-delete nil
3853   "Overlays mark for deletion after all syntax checks completed.")
3854 (put 'flycheck-overlays-to-delete 'permanent-local t)
3855
3856 (defun flycheck-delete-all-overlays ()
3857   "Remove all flycheck overlays in the current buffer."
3858   (overlay-recenter (point-max))
3859   (flycheck-delete-marked-overlays)
3860   (save-restriction
3861     (widen)
3862     (seq-do #'delete-overlay (flycheck-overlays-in (point-min) (point-max)))))
3863
3864 (defun flycheck-mark-all-overlays-for-deletion ()
3865   "Mark all current overlays for deletion."
3866   (setq flycheck-overlays-to-delete
3867         (append (flycheck-overlays-in (point-min) (point-max))
3868                 flycheck-overlays-to-delete)))
3869
3870 (defun flycheck-delete-marked-overlays ()
3871   "Delete all overlays marked for deletion."
3872   (overlay-recenter (point-max))
3873   (seq-do #'delete-overlay flycheck-overlays-to-delete)
3874   (setq flycheck-overlays-to-delete nil))
3875
3876
3877 ;;; Error navigation in the current buffer
3878 (defun flycheck-error-level-interesting-at-pos-p (pos)
3879   "Check if error severity at POS passes `flycheck-error-level-interesting-p'."
3880   (flycheck-error-level-interesting-p (get-char-property pos 'flycheck-error)))
3881
3882 (defun flycheck-error-level-interesting-p (err)
3883   "Check if ERR severity is >= `flycheck-navigation-minimum-level'."
3884   (when (flycheck-error-p err)
3885     (-if-let (min-level flycheck-navigation-minimum-level)
3886         (<= (flycheck-error-level-severity min-level)
3887             (flycheck-error-level-severity (flycheck-error-level err)))
3888       t)))
3889
3890 (defun flycheck-next-error-pos (n &optional reset)
3891   "Get the position of the N-th next error.
3892
3893 With negative N, get the position of the (-N)-th previous error
3894 instead.  With non-nil RESET, search from `point-min', otherwise
3895 search from the current point.
3896
3897 Return the position of the next or previous error, or nil if
3898 there is none."
3899   (let ((n (or n 1))
3900         (pos (if reset (point-min) (point))))
3901     (if (>= n 0)
3902         ;; Search forwards
3903         (while (and pos (> n 0))
3904           (setq n (1- n))
3905           (when (get-char-property pos 'flycheck-error)
3906             ;; Move beyond from the current error if any
3907             (setq pos (next-single-char-property-change pos 'flycheck-error)))
3908           (while (not (or (= pos (point-max))
3909                           (flycheck-error-level-interesting-at-pos-p pos)))
3910             ;; Scan for the next error
3911             (setq pos (next-single-char-property-change pos 'flycheck-error)))
3912           (when (and (= pos (point-max))
3913                      (not (flycheck-error-level-interesting-at-pos-p pos)))
3914             ;; If we reached the end of the buffer, but no error, we didn't find
3915             ;; any
3916             (setq pos nil)))
3917       ;; Search backwards
3918       (while (and pos (< n 0))
3919         (setq n (1+ n))
3920         ;; Loop until we find an error.  We need to check the position *before*
3921         ;; the current one, because `previous-single-char-property-change'
3922         ;; always moves to the position *of* the change.
3923         (while (not (or (= pos (point-min))
3924                         (flycheck-error-level-interesting-at-pos-p (1- pos))))
3925           (setq pos (previous-single-char-property-change pos 'flycheck-error)))
3926         (when (and (= pos (point-min))
3927                    (not (flycheck-error-level-interesting-at-pos-p pos)))
3928           ;; We didn't find any error.
3929           (setq pos nil))
3930         (when pos
3931           ;; We found an error, so move to its beginning
3932           (setq pos (previous-single-char-property-change pos
3933                                                           'flycheck-error)))))
3934     pos))
3935
3936 (defun flycheck-next-error-function (n reset)
3937   "Visit the N-th error from the current point.
3938
3939 N is the number of errors to advance by, where a negative N
3940 advances backwards.  With non-nil RESET, advance from the
3941 beginning of the buffer, otherwise advance from the current
3942 position.
3943
3944 Intended for use with `next-error-function'."
3945   (-if-let* ((pos (flycheck-next-error-pos n reset))
3946              (err (get-char-property pos 'flycheck-error)))
3947       (flycheck-jump-to-error err)
3948     (user-error "No more Flycheck errors")))
3949
3950 (defun flycheck-next-error (&optional n reset)
3951   "Visit the N-th error from the current point.
3952
3953 N is the number of errors to advance by, where a negative N
3954 advances backwards.  With non-nil RESET, advance from the
3955 beginning of the buffer, otherwise advance from the current
3956 position."
3957   (interactive "P")
3958   (when (consp n)
3959     ;; Universal prefix argument means reset
3960     (setq reset t n nil))
3961   (flycheck-next-error-function n reset)
3962   (flycheck-display-error-at-point))
3963
3964 (defun flycheck-previous-error (&optional n)
3965   "Visit the N-th previous error.
3966
3967 If given, N specifies the number of errors to move backwards by.
3968 If N is negative, move forwards instead."
3969   (interactive "P")
3970   (flycheck-next-error (- (or n 1))))
3971
3972 (defun flycheck-first-error (&optional n)
3973   "Visit the N-th error from beginning of the buffer.
3974
3975 If given, N specifies the number of errors to move forward from
3976 the beginning of the buffer."
3977   (interactive "P")
3978   (flycheck-next-error n 'reset))
3979
3980
3981 ;;; Listing errors in buffers
3982 (defconst flycheck-error-list-buffer "*Flycheck errors*"
3983   "The name of the buffer to show error lists.")
3984
3985 (defvar flycheck-error-list-mode-map
3986   (let ((map (make-sparse-keymap)))
3987     (define-key map (kbd "f") #'flycheck-error-list-set-filter)
3988     (define-key map (kbd "F") #'flycheck-error-list-reset-filter)
3989     (define-key map (kbd "n") #'flycheck-error-list-next-error)
3990     (define-key map (kbd "p") #'flycheck-error-list-previous-error)
3991     (define-key map (kbd "g") #'flycheck-error-list-check-source)
3992     (define-key map (kbd "e") #'flycheck-error-list-explain-error)
3993     (define-key map (kbd "RET") #'flycheck-error-list-goto-error)
3994     map)
3995   "The keymap of `flycheck-error-list-mode'.")
3996
3997 (defun flycheck-error-list-make-last-column (message checker)
3998   "Compute contents of the last error list cell.
3999
4000 MESSAGE and CHECKER are displayed in a single column to allow the
4001 message to stretch arbitrarily far."
4002   (let ((checker-name (propertize (symbol-name checker)
4003                                   'face 'flycheck-error-list-checker-name)))
4004     (format "%s (%s)" message checker-name)))
4005
4006 (defconst flycheck-error-list-format
4007   `[("File" 6)
4008     ("Line" 5 flycheck-error-list-entry-< :right-align t)
4009     ("Col" 3 nil :right-align t)
4010     ("Level" 8 flycheck-error-list-entry-level-<)
4011     ("ID" 6 t)
4012     (,(flycheck-error-list-make-last-column "Message" 'Checker) 0 t)]
4013   "Table format for the error list.")
4014
4015 (defconst flycheck-error-list-padding 1
4016   "Padding used in error list.")
4017
4018 (defconst flycheck--error-list-msg-offset
4019   (seq-reduce
4020    (lambda (offset fmt)
4021      (pcase-let* ((`(,_ ,width ,_ . ,props) fmt)
4022                   (padding (or (plist-get props :pad-right) 1)))
4023        (+ offset width padding)))
4024    (seq-subseq flycheck-error-list-format 0 -1)
4025    flycheck-error-list-padding)
4026   "Amount of space to use in `flycheck-flush-multiline-message'.")
4027
4028 (define-derived-mode flycheck-error-list-mode tabulated-list-mode
4029   "Flycheck errors"
4030   "Major mode for listing Flycheck errors.
4031
4032 \\{flycheck-error-list-mode-map}"
4033   (setq tabulated-list-format flycheck-error-list-format
4034         ;; Sort by location initially
4035         tabulated-list-sort-key (cons "Line" nil)
4036         tabulated-list-padding flycheck-error-list-padding
4037         tabulated-list-entries #'flycheck-error-list-entries
4038         ;; `revert-buffer' updates the mode line for us, so all we need to do is
4039         ;; set the corresponding mode line construct.
4040         mode-line-buffer-identification flycheck-error-list-mode-line)
4041   ;; Guard `truncate-string-ellipsis' for Emacs 24.
4042   ;; TODO: Remove when dropping Emacs 24 compatibility
4043   (when (boundp 'truncate-string-ellipsis)
4044     ;; See https://github.com/flycheck/flycheck/issues/1101
4045     (setq-local truncate-string-ellipsis "…"))
4046   (tabulated-list-init-header))
4047
4048 (defvar-local flycheck-error-list-source-buffer nil
4049   "The current source buffer of the error list.")
4050 ;; Needs to permanently local to preserve the source buffer across buffer
4051 ;; reversions
4052 (put 'flycheck-error-list-source-buffer 'permanent-local t)
4053
4054 (defun flycheck-error-list-set-source (buffer)
4055   "Set BUFFER as the source buffer of the error list."
4056   (when (get-buffer flycheck-error-list-buffer)
4057     (with-current-buffer flycheck-error-list-buffer
4058       ;; Only update the source when required
4059       (unless (eq buffer flycheck-error-list-source-buffer)
4060         (setq flycheck-error-list-source-buffer buffer)
4061         (flycheck-error-list-refresh)))))
4062
4063 (defun flycheck-error-list-update-source ()
4064   "Update the source buffer of the error list."
4065   (when (not (eq (current-buffer) (get-buffer flycheck-error-list-buffer)))
4066     ;; We must not update the source buffer, if the current buffer is the error
4067     ;; list itself.
4068     (flycheck-error-list-set-source (current-buffer))))
4069
4070 (defun flycheck-error-list-check-source ()
4071   "Trigger a syntax check in the source buffer of the error list."
4072   (interactive)
4073   (let ((buffer (get-buffer flycheck-error-list-source-buffer)))
4074     (when (buffer-live-p buffer)
4075       (with-current-buffer buffer
4076         (flycheck-buffer)))))
4077
4078 (define-button-type 'flycheck-error-list
4079   'action #'flycheck-error-list-button-goto-error
4080   'help-echo "mouse-2, RET: goto error"
4081   'face nil)
4082
4083 (defun flycheck-error-list-button-goto-error (button)
4084   "Go to the error at BUTTON."
4085   (flycheck-error-list-goto-error (button-start button)))
4086
4087 (define-button-type 'flycheck-error-list-explain-error
4088   'action #'flycheck-error-list-button-explain-error
4089   'help-echo "mouse-2, RET: explain error")
4090
4091 (defun flycheck-error-list-button-explain-error (button)
4092   "Explain the error at BUTTON."
4093   (flycheck-error-list-explain-error (button-start button)))
4094
4095 (defsubst flycheck-error-list-make-cell (text &optional face help-echo type)
4096   "Make an error list cell with TEXT and FACE.
4097
4098 If FACE is nil don't set a FACE on TEXT.  If TEXT already has
4099 face properties, do not specify a FACE.  Note though, that if
4100 TEXT gets truncated it will not inherit any previous face
4101 properties.  If you expect TEXT to be truncated in the error
4102 list, do specify a FACE explicitly!
4103
4104 If HELP-ECHO is non-nil, set a help-echo property on TEXT, with
4105 value HELP-ECHO.  This is convenient if you expect TEXT to be
4106 truncated.
4107
4108 The cell will have the type TYPE unless TYPE is nil, and the
4109 default type `flycheck-error-list' will be used instead."
4110   (append (list text 'type (if type type
4111                              'flycheck-error-list))
4112           (and face (list 'face face))
4113           (and help-echo (list 'help-echo help-echo))))
4114
4115 (defsubst flycheck-error-list-make-number-cell (number face)
4116   "Make a table cell for a NUMBER with FACE.
4117
4118 Convert NUMBER to string, fontify it with FACE and return the
4119 string with attached text properties."
4120   (flycheck-error-list-make-cell
4121    (if (numberp number) (number-to-string number) "")
4122    face))
4123
4124 (defun flycheck-error-list-make-entry (error)
4125   "Make a table cell for the given ERROR.
4126
4127 Return a list with the contents of the table cell."
4128   (let* ((level (flycheck-error-level error))
4129          (level-face (flycheck-error-level-error-list-face level))
4130          (filename (flycheck-error-filename error))
4131          (line (flycheck-error-line error))
4132          (column (flycheck-error-column error))
4133          (message (or (flycheck-error-message error)
4134                       (format "Unknown %s" (symbol-name level))))
4135          (flushed-msg (flycheck-flush-multiline-message message))
4136          (id (flycheck-error-id error))
4137          (id-str (if id (format "%s" id) ""))
4138          (checker (flycheck-error-checker error))
4139          (msg-and-checker
4140           (flycheck-error-list-make-last-column flushed-msg checker))
4141          (explainer (flycheck-checker-get checker 'error-explainer)))
4142     (list error
4143           (vector (flycheck-error-list-make-cell
4144                    (if filename
4145                        (file-name-nondirectory filename)
4146                      "")
4147                    'flycheck-error-list-filename)
4148                   (flycheck-error-list-make-number-cell
4149                    line 'flycheck-error-list-line-number)
4150                   (flycheck-error-list-make-number-cell
4151                    column 'flycheck-error-list-column-number)
4152                   (flycheck-error-list-make-cell
4153                    (symbol-name (flycheck-error-level error)) level-face)
4154                   ;; Error ID use a different face when an error-explainer is
4155                   ;; present
4156                   (flycheck-error-list-make-cell
4157                    id-str (if explainer 'flycheck-error-list-id-with-explainer
4158                             'flycheck-error-list-id)
4159                    id-str 'flycheck-error-list-explain-error)
4160                   (flycheck-error-list-make-cell
4161                    msg-and-checker nil msg-and-checker)))))
4162
4163 (defun flycheck-flush-multiline-message (msg)
4164   "Prepare error message MSG for display in the error list.
4165
4166 Prepend all lines of MSG except the first with enough space to
4167 ensure that they line up properly once the message is displayed."
4168   (let* ((spc-spec `(space . (:width ,flycheck--error-list-msg-offset)))
4169          (spc (propertize " " 'display spc-spec))
4170          (rep (concat "\\1" spc "\\2")))
4171     (replace-regexp-in-string "\\([\r\n]+\\)\\(.\\)" rep msg)))
4172
4173 (defun flycheck-error-list-current-errors ()
4174   "Read the list of errors in `flycheck-error-list-source-buffer'."
4175   (when (buffer-live-p flycheck-error-list-source-buffer)
4176     (buffer-local-value 'flycheck-current-errors
4177                         flycheck-error-list-source-buffer)))
4178
4179 (defun flycheck-error-list-entries ()
4180   "Create the entries for the error list."
4181   (-when-let* ((errors (flycheck-error-list-current-errors))
4182                (filtered (flycheck-error-list-apply-filter errors)))
4183     (seq-map #'flycheck-error-list-make-entry filtered)))
4184
4185 (defun flycheck-error-list-entry-< (entry1 entry2)
4186   "Determine whether ENTRY1 is before ENTRY2 by location.
4187
4188 See `flycheck-error-<'."
4189   (flycheck-error-< (car entry1) (car entry2)))
4190
4191 (defun flycheck-error-list-entry-level-< (entry1 entry2)
4192   "Determine whether ENTRY1 is before ENTRY2 by level.
4193
4194 See `flycheck-error-level-<'."
4195   (not (flycheck-error-level-< (car entry1) (car entry2))))
4196
4197 (defvar flycheck-error-list-mode-line-map
4198   (let ((map (make-sparse-keymap)))
4199     (define-key map [mode-line mouse-1]
4200       #'flycheck-error-list-mouse-switch-to-source)
4201     map)
4202   "Keymap for error list mode line.")
4203
4204 (defun flycheck-error-list-propertized-source-name ()
4205   "Get the name of the current source buffer for the mode line.
4206
4207 Propertize the name of the current source buffer for use in the
4208 mode line indication of `flycheck-error-list-mode'."
4209   (let ((name (replace-regexp-in-string
4210                (rx "%") "%%"
4211                (buffer-name flycheck-error-list-source-buffer)
4212                'fixed-case 'literal)))
4213     (propertize name 'face 'mode-line-buffer-id
4214                 'mouse-face 'mode-line-highlight
4215                 'help-echo "mouse-1: switch to source"
4216                 'local-map flycheck-error-list-mode-line-map)))
4217
4218 (defun flycheck-error-list-mouse-switch-to-source (event)
4219   "Switch to the error list source buffer of the EVENT window."
4220   (interactive "e")
4221   (save-selected-window
4222     (when (eventp event)
4223       (select-window (posn-window (event-start event))))
4224     (when (buffer-live-p flycheck-error-list-source-buffer)
4225       (switch-to-buffer flycheck-error-list-source-buffer))))
4226
4227 (defun flycheck-get-error-list-window-list (&optional all-frames)
4228   "Get all windows displaying the error list.
4229
4230 ALL-FRAMES specifies the frames to consider, as in
4231 `get-buffer-window-list'."
4232   (-when-let (buf (get-buffer flycheck-error-list-buffer))
4233     (get-buffer-window-list buf nil all-frames)))
4234
4235 (defun flycheck-get-error-list-window (&optional all-frames)
4236   "Get a window displaying the error list, or nil if none.
4237
4238 ALL-FRAMES specifies the frames to consider, as in
4239 `get-buffer-window'."
4240   (-when-let (buf (get-buffer flycheck-error-list-buffer))
4241     (get-buffer-window buf all-frames)))
4242
4243 (defun flycheck-error-list-recenter-at (pos)
4244   "Recenter the error list at POS."
4245   (dolist (window (flycheck-get-error-list-window-list t))
4246     (with-selected-window window
4247       (goto-char pos)
4248       (let ((recenter-redisplay nil))
4249         (recenter)))))
4250
4251 (defun flycheck-error-list-refresh ()
4252   "Refresh the current error list.
4253
4254 Add all errors currently reported for the current
4255 `flycheck-error-list-source-buffer', and recenter the error
4256 list."
4257   ;; We only refresh the error list, when it is visible in a window, and we
4258   ;; select this window while reverting, because Tabulated List mode attempts to
4259   ;; recenter the error at the old location, so it must have the proper window
4260   ;; selected.
4261   (-when-let (window (flycheck-get-error-list-window t))
4262     (with-selected-window window
4263       (revert-buffer))
4264     (run-hooks 'flycheck-error-list-after-refresh-hook)
4265     (let ((preserve-pos (eq (current-buffer)
4266                             (get-buffer flycheck-error-list-buffer))))
4267       ;; If the error list is the current buffer, don't recenter when
4268       ;; highlighting
4269       (flycheck-error-list-highlight-errors preserve-pos))))
4270
4271 (defun flycheck-error-list-mode-line-filter-indicator ()
4272   "Create a string representing the current error list filter."
4273   (if flycheck-error-list-minimum-level
4274       (format " [>= %s]" flycheck-error-list-minimum-level)
4275     ""))
4276
4277 (defun flycheck-error-list-set-filter (level)
4278   "Restrict the error list to errors at level LEVEL or higher.
4279
4280 LEVEL is either an error level symbol, or nil, to remove the filter."
4281   (interactive
4282    (list (read-flycheck-error-level
4283           "Minimum error level (errors at lower levels will be hidden): ")))
4284   (when (and level (not (flycheck-error-level-p level)))
4285     (user-error "Invalid level: %s" level))
4286   (-when-let (buf (get-buffer flycheck-error-list-buffer))
4287     (with-current-buffer buf
4288       (setq-local flycheck-error-list-minimum-level level))
4289     (flycheck-error-list-refresh)
4290     (flycheck-error-list-recenter-at (point-min))))
4291
4292 (defun flycheck-error-list-reset-filter ()
4293   "Remove filters and show all errors in the error list."
4294   (interactive)
4295   (kill-local-variable 'flycheck-error-list-minimum-level))
4296
4297 (defun flycheck-error-list-apply-filter (errors)
4298   "Filter ERRORS according to `flycheck-error-list-minimum-level'."
4299   (-if-let* ((min-level flycheck-error-list-minimum-level)
4300              (min-severity (flycheck-error-level-severity min-level)))
4301       (seq-filter (lambda (err) (>= (flycheck-error-level-severity
4302                                      (flycheck-error-level err))
4303                                     min-severity))
4304                   errors)
4305     errors))
4306
4307 (defun flycheck-error-list-goto-error (&optional pos)
4308   "Go to the location of the error at POS in the error list.
4309
4310 POS defaults to `point'."
4311   (interactive)
4312   (-when-let* ((error (tabulated-list-get-id pos)))
4313     (flycheck-jump-to-error error)))
4314
4315 (defun flycheck-jump-to-error (error)
4316   "Go to the location of ERROR."
4317   (let* ((error-copy (copy-flycheck-error error))
4318          (filename (flycheck-error-filename error))
4319          (other-file-error (flycheck-relevant-error-other-file-p error))
4320          (buffer (if filename
4321                      (find-file-noselect filename)
4322                    (flycheck-error-buffer error))))
4323     (when (buffer-live-p buffer)
4324       (setf (flycheck-error-buffer error-copy) buffer)
4325       (flycheck-jump-in-buffer buffer error-copy)
4326       ;; When jumping to an error in another file, it may not have
4327       ;; this error available for highlighting yet, so we trigger a check
4328       ;; if necessary.
4329       (when other-file-error
4330         (with-current-buffer buffer
4331           (unless (seq-contains flycheck-current-errors error-copy 'equal)
4332             (when flycheck-mode
4333               (flycheck-buffer))))))))
4334
4335 (defun flycheck-jump-in-buffer (buffer error)
4336   "In BUFFER, jump to ERROR."
4337   ;; FIXME: we assume BUFFER and the buffer of ERROR are the same.  We don't
4338   ;; need the first argument then.
4339   (if (eq (window-buffer) (get-buffer flycheck-error-list-buffer))
4340       ;; When called from within the error list, keep the error list,
4341       ;; otherwise replace the current buffer.
4342       (pop-to-buffer buffer 'other-window)
4343     (switch-to-buffer buffer))
4344   (let ((pos (flycheck-error-pos error)))
4345     (unless (eq (goto-char pos) (point))
4346       ;; If widening gets in the way of moving to the right place, remove it
4347       ;; and try again
4348       (widen)
4349       (goto-char pos)))
4350   ;; Re-highlight the errors
4351   (flycheck-error-list-highlight-errors 'preserve-pos))
4352
4353 (defun flycheck-error-list-explain-error (&optional pos)
4354   "Explain the error at POS in the error list.
4355
4356 POS defaults to `point'."
4357   (interactive)
4358   (-when-let* ((error (tabulated-list-get-id pos))
4359                (explainer (flycheck-checker-get (flycheck-error-checker error)
4360                                                 'error-explainer))
4361                (explanation (funcall explainer error)))
4362     (flycheck-display-error-explanation explanation)))
4363
4364 (defun flycheck-error-list-next-error-pos (pos &optional n)
4365   "Starting from POS get the N'th next error in the error list.
4366
4367 N defaults to 1.  If N is negative, search for the previous error
4368 instead.
4369
4370 Get the beginning position of the N'th next error from POS, or
4371 nil, if there is no next error."
4372   (let ((n (or n 1)))
4373     (if (>= n 0)
4374         ;; Search forward
4375         (while (and pos (/= n 0))
4376           (setq n (1- n))
4377           (setq pos (next-single-property-change pos 'tabulated-list-id)))
4378       ;; Search backwards
4379       (while (/= n 0)
4380         (setq n (1+ n))
4381         ;; We explicitly give the limit here to explicitly have the minimum
4382         ;; point returned, to be able to move to the first error (which starts
4383         ;; at `point-min')
4384         (setq pos (previous-single-property-change pos 'tabulated-list-id
4385                                                    nil (point-min)))))
4386     pos))
4387
4388 (defun flycheck-error-list-previous-error (n)
4389   "Go to the N'th previous error in the error list."
4390   (interactive "P")
4391   (flycheck-error-list-next-error (- (or n 1))))
4392
4393 (defun flycheck-error-list-next-error (n)
4394   "Go to the N'th next error in the error list."
4395   (interactive "P")
4396   (let ((pos (flycheck-error-list-next-error-pos (point) n)))
4397     (when (and pos (/= pos (point)))
4398       (goto-char pos)
4399       (save-selected-window
4400         ;; Keep the error list selected, so that the user can navigate errors by
4401         ;; repeatedly pressing n/p, without having to re-select the error list
4402         ;; window.
4403         (flycheck-error-list-goto-error)))))
4404
4405 (defvar-local flycheck-error-list-highlight-overlays nil
4406   "Error highlight overlays in the error list buffer.")
4407 (put 'flycheck-error-list-highlight-overlays 'permanent-local t)
4408
4409 (defun flycheck-error-list-highlight-errors (&optional preserve-pos)
4410   "Highlight errors in the error list.
4411
4412 Highlight all errors in the error lists that are at point in the
4413 source buffer, and on the same line as point.  Then recenter the
4414 error list to the highlighted error, unless PRESERVE-POS is
4415 non-nil."
4416   (when (get-buffer flycheck-error-list-buffer)
4417     (let ((current-errors (flycheck-overlay-errors-in (line-beginning-position)
4418                                                       (line-end-position))))
4419       (with-current-buffer flycheck-error-list-buffer
4420         (let ((old-overlays flycheck-error-list-highlight-overlays)
4421               (min-point (point-max))
4422               (max-point (point-min)))
4423           ;; Display the new overlays first, to avoid re-display flickering
4424           (setq flycheck-error-list-highlight-overlays nil)
4425           (when current-errors
4426             (let ((next-error-pos (point-min)))
4427               (while next-error-pos
4428                 (let* ((beg next-error-pos)
4429                        (end (flycheck-error-list-next-error-pos beg))
4430                        (err (tabulated-list-get-id beg)))
4431                   (when (member err current-errors)
4432                     (setq min-point (min min-point beg)
4433                           max-point (max max-point beg))
4434                     (let ((ov (make-overlay beg
4435                                             ;; Extend overlay to the beginning
4436                                             ;; of the next line, to highlight
4437                                             ;; the whole line
4438                                             (or end (point-max)))))
4439                       (push ov flycheck-error-list-highlight-overlays)
4440                       (setf (overlay-get ov 'flycheck-error-highlight-overlay)
4441                             t)
4442                       (setf (overlay-get ov 'face)
4443                             'flycheck-error-list-highlight)))
4444                   (setq next-error-pos end)))))
4445           ;; Delete the old overlays
4446           (seq-do #'delete-overlay old-overlays)
4447           (when (and (not preserve-pos) current-errors)
4448             ;; Move point to the middle error
4449             (goto-char (+ min-point (/ (- max-point min-point) 2)))
4450             (beginning-of-line)
4451             ;; And recenter the error list at this position
4452             (flycheck-error-list-recenter-at (point))))))))
4453
4454 (defun flycheck-list-errors ()
4455   "Show the error list for the current buffer."
4456   (interactive)
4457   (unless flycheck-mode
4458     (user-error "Flycheck mode not enabled"))
4459   ;; Create and initialize the error list
4460   (unless (get-buffer flycheck-error-list-buffer)
4461     (with-current-buffer (get-buffer-create flycheck-error-list-buffer)
4462       (flycheck-error-list-mode)))
4463   (flycheck-error-list-set-source (current-buffer))
4464   ;; Reset the error filter
4465   (flycheck-error-list-reset-filter)
4466   ;; Show the error list in a window, and re-select the old window
4467   (display-buffer flycheck-error-list-buffer)
4468   ;; Finally, refresh the error list to show the most recent errors
4469   (flycheck-error-list-refresh))
4470
4471 (defalias 'list-flycheck-errors 'flycheck-list-errors)
4472
4473
4474 ;;; Displaying errors in the current buffer
4475 (defun flycheck-display-errors (errors)
4476   "Display ERRORS using `flycheck-display-errors-function'."
4477   (when flycheck-display-errors-function
4478     (funcall flycheck-display-errors-function errors)))
4479
4480 (defvar-local flycheck-display-error-at-point-timer nil
4481   "Timer to automatically show the error at point in minibuffer.")
4482
4483 (defun flycheck-cancel-error-display-error-at-point-timer ()
4484   "Cancel the error display timer for the current buffer."
4485   (when flycheck-display-error-at-point-timer
4486     (cancel-timer flycheck-display-error-at-point-timer)
4487     (setq flycheck-display-error-at-point-timer nil)))
4488
4489 (defun flycheck-display-error-at-point ()
4490   "Display the all error messages at point in minibuffer."
4491   (interactive)
4492   ;; This function runs from a timer, so we must take care to not ignore any
4493   ;; errors
4494   (with-demoted-errors "Flycheck error display error: %s"
4495     (flycheck-cancel-error-display-error-at-point-timer)
4496     (when flycheck-mode
4497       (-when-let (errors (flycheck-overlay-errors-at (point)))
4498         (flycheck-display-errors errors)))))
4499
4500 (defun flycheck-display-error-at-point-soon ()
4501   "Display the first error message at point in minibuffer delayed."
4502   (flycheck-cancel-error-display-error-at-point-timer)
4503   (when (flycheck-overlays-at (point))
4504     (setq flycheck-display-error-at-point-timer
4505           (run-at-time flycheck-display-errors-delay nil
4506                        'flycheck-display-error-at-point))))
4507
4508
4509 ;;; Functions to display errors
4510 (defconst flycheck-error-message-buffer "*Flycheck error messages*"
4511   "The name of the buffer to show long error messages in.")
4512
4513 (defun flycheck-error-message-buffer ()
4514   "Get the buffer object to show long error messages in.
4515
4516 Get the buffer named by variable `flycheck-error-message-buffer',
4517 or nil if the buffer does not exist."
4518   (get-buffer flycheck-error-message-buffer))
4519
4520 (defun flycheck-may-use-echo-area-p ()
4521   "Determine whether the echo area may be used.
4522
4523 The echo area may be used if the cursor is not in the echo area,
4524 and if the echo area is not occupied by minibuffer input."
4525   (not (or cursor-in-echo-area (active-minibuffer-window))))
4526
4527 (defun flycheck-display-error-messages (errors)
4528   "Display the messages of ERRORS.
4529
4530 Concatenate all non-nil messages of ERRORS separated by empty
4531 lines, and display them with `display-message-or-buffer', which
4532 shows the messages either in the echo area or in a separate
4533 buffer, depending on the number of lines.  See Info
4534 node `(elisp)Displaying Messages' for more information.
4535
4536 In the latter case, show messages in the buffer denoted by
4537 variable `flycheck-error-message-buffer'."
4538   (when (and errors (flycheck-may-use-echo-area-p))
4539     (let ((messages (seq-map #'flycheck-error-format-message-and-id errors)))
4540       (display-message-or-buffer (string-join messages "\n\n")
4541                                  flycheck-error-message-buffer
4542                                  'not-this-window))))
4543
4544 (defun flycheck-display-error-messages-unless-error-list (errors)
4545   "Show messages of ERRORS unless the error list is visible.
4546
4547 Like `flycheck-display-error-messages', but only if the error
4548 list (see `flycheck-list-errors') is not visible in any window in
4549 the current frame."
4550   (unless (flycheck-get-error-list-window 'current-frame)
4551     (flycheck-display-error-messages errors)))
4552
4553 (defun flycheck-hide-error-buffer ()
4554   "Hide the Flycheck error buffer if necessary.
4555
4556 Hide the error buffer if there is no error under point."
4557   (-when-let* ((buffer (flycheck-error-message-buffer))
4558                (window (get-buffer-window buffer)))
4559     (unless (flycheck-overlays-at (point))
4560       ;; save-selected-window prevents `quit-window' from changing the current
4561       ;; buffer (see https://github.com/flycheck/flycheck/issues/648).
4562       (save-selected-window
4563         (quit-window nil window)))))
4564
4565
4566 ;;; Working with errors
4567 (defun flycheck-copy-errors-as-kill (pos &optional formatter)
4568   "Copy each error at POS into kill ring, using FORMATTER.
4569
4570 FORMATTER is a function to turn an error into a string,
4571 defaulting to `flycheck-error-message'.
4572
4573 Interactively, use `flycheck-error-format-message-and-id' as
4574 FORMATTER with universal prefix arg, and `flycheck-error-id' with
4575 normal prefix arg, i.e. copy the message and the ID with
4576 universal prefix arg, and only the id with normal prefix arg."
4577   (interactive (list (point)
4578                      (pcase current-prefix-arg
4579                        ((pred not) #'flycheck-error-message)
4580                        ((pred consp) #'flycheck-error-format-message-and-id)
4581                        (_ #'flycheck-error-id))))
4582   (let ((messages (delq nil (seq-map (or formatter #'flycheck-error-message)
4583                                      (flycheck-overlay-errors-at pos)))))
4584     (when messages
4585       (seq-do #'kill-new (reverse messages))
4586       (message (string-join messages "\n")))))
4587
4588 (defun flycheck-explain-error-at-point ()
4589   "Display an explanation for the first explainable error at point.
4590
4591 The first explainable error at point is the first error at point
4592 with a non-nil `:error-explainer' function defined in its
4593 checker.  The `:error-explainer' function is then called with
4594 this error to produce the explanation to display."
4595   (interactive)
4596   (-when-let* ((first-error
4597                 ;; Get the first error at point that has an `error-explainer'.
4598                 (seq-find (lambda (error)
4599                             (flycheck-checker-get
4600                              (flycheck-error-checker error) 'error-explainer))
4601                           (flycheck-overlay-errors-at (point))))
4602                (explainer
4603                 (flycheck-checker-get (flycheck-error-checker first-error)
4604                                       'error-explainer))
4605                (explanation (funcall explainer first-error)))
4606     (flycheck-display-error-explanation explanation)))
4607
4608 (defconst flycheck-explain-error-buffer "*Flycheck error explanation*"
4609   "The name of the buffer to show error explanations.")
4610
4611 (defun flycheck-display-error-explanation (explanation)
4612   "Display the EXPLANATION string in a help buffer."
4613   (with-help-window (get-buffer-create flycheck-explain-error-buffer)
4614     (princ explanation)))
4615
4616
4617 ;;; Syntax checkers using external commands
4618 (defun flycheck-command-argument-p (arg)
4619   "Check whether ARG is a valid command argument."
4620   (pcase arg
4621     ((pred stringp) t)
4622     ((or `source `source-inplace `source-original) t)
4623     ((or `temporary-directory `temporary-file-name) t)
4624     (`null-device t)
4625     (`(config-file ,option-name ,config-file-var)
4626      (and (stringp option-name)
4627           (symbolp config-file-var)))
4628     (`(config-file ,option-name ,config-file-var ,prepender)
4629      (and (stringp option-name)
4630           (symbolp config-file-var)
4631           (symbolp prepender)))
4632     (`(,(or `option `option-list) ,option-name ,option-var)
4633      (and (stringp option-name)
4634           (symbolp option-var)))
4635     (`(,(or `option `option-list) ,option-name ,option-var ,prepender)
4636      (and (stringp option-name)
4637           (symbolp option-var)
4638           (symbolp prepender)))
4639     (`(,(or `option `option-list) ,option-name ,option-var ,prepender ,filter)
4640      (and (stringp option-name)
4641           (symbolp option-var)
4642           (symbolp prepender)
4643           (symbolp filter)))
4644     (`(option-flag ,option-name ,option-var)
4645      (and (stringp option-name)
4646           (symbolp option-var)))
4647     (`(eval ,_) t)
4648     (_ nil)))
4649
4650 (defun flycheck-compute-working-directory (checker)
4651   "Get the default working directory for CHECKER.
4652
4653 Compute the value of `default-directory' for the invocation of
4654 the syntax checker command, by calling the function in the
4655 `working-directory' property of CHECKER, with CHECKER as sole
4656 argument, and returning its value.  Signal an error if the
4657 function returns a non-existing working directory.
4658
4659 If the property is undefined or if the function returns nil
4660 return the `default-directory' of the current buffer."
4661   (let* ((def-directory-fn (flycheck-checker-get checker 'working-directory))
4662          (directory (or (and def-directory-fn
4663                              (funcall def-directory-fn checker))
4664                         ;; Default to the `default-directory' of the current
4665                         ;; buffer
4666                         default-directory)))
4667     (unless (file-exists-p directory)
4668       (error ":working-directory %s of syntax checker %S does not exist"
4669              directory checker))
4670     directory))
4671
4672 ;;;###autoload
4673 (defun flycheck-define-command-checker (symbol docstring &rest properties)
4674   "Define SYMBOL as syntax checker to run a command.
4675
4676 Define SYMBOL as generic syntax checker via
4677 `flycheck-define-generic-checker', which uses an external command
4678 to check the buffer.  SYMBOL and DOCSTRING are the same as for
4679 `flycheck-define-generic-checker'.
4680
4681 In addition to the properties understood by
4682 `flycheck-define-generic-checker', the following PROPERTIES
4683 constitute a command syntax checker.  Unless otherwise noted, all
4684 properties are mandatory.  Note that the default `:error-filter'
4685 of command checkers is `flycheck-sanitize-errors'.
4686
4687 `:command COMMAND'
4688      The command to run for syntax checking.
4689
4690      COMMAND is a list of the form `(EXECUTABLE [ARG ...])'.
4691
4692      EXECUTABLE is a string with the executable of this syntax
4693      checker.  It can be overridden with the variable
4694      `flycheck-SYMBOL-executable'.  Note that this variable is
4695      NOT implicitly defined by this function.  Use
4696      `flycheck-def-executable-var' to define this variable.
4697
4698      Each ARG is an argument to the executable, either as string,
4699      or as special symbol or form for
4700      `flycheck-substitute-argument', which see.
4701
4702 `:error-patterns PATTERNS'
4703      A list of patterns to parse the output of the `:command'.
4704
4705      Each ITEM in PATTERNS is a list `(LEVEL SEXP ...)', where
4706      LEVEL is a Flycheck error level (see
4707      `flycheck-define-error-level'), followed by one or more RX
4708      `SEXP's which parse an error of that level and extract line,
4709      column, file name and the message.
4710
4711      See `rx' for general information about RX, and
4712      `flycheck-rx-to-string' for some special RX forms provided
4713      by Flycheck.
4714
4715      All patterns are applied in the order of declaration to the
4716      whole output of the syntax checker.  Output already matched
4717      by a pattern will not be matched by subsequent patterns.  In
4718      other words, the first pattern wins.
4719
4720      This property is optional.  If omitted, however, an
4721      `:error-parser' is mandatory.
4722
4723 `:error-parser FUNCTION'
4724      A function to parse errors with.
4725
4726      The function shall accept three arguments OUTPUT CHECKER
4727      BUFFER.  OUTPUT is the syntax checker output as string,
4728      CHECKER the syntax checker that was used, and BUFFER a
4729      buffer object representing the checked buffer.  The function
4730      must return a list of `flycheck-error' objects parsed from
4731      OUTPUT.
4732
4733      This property is optional.  If omitted, it defaults to
4734      `flycheck-parse-with-patterns'.  In this case,
4735      `:error-patterns' is mandatory.
4736
4737 `:standard-input t'
4738      Whether to send the buffer contents on standard input.
4739
4740      If this property is given and has a non-nil value, send the
4741      contents of the buffer on standard input.
4742
4743      Defaults to nil.
4744
4745 Note that you may not give `:start', `:interrupt', and
4746 `:print-doc' for a command checker.  You can give a custom
4747 `:verify' function, though, whose results will be appended to the
4748 default `:verify' function of command checkers."
4749   (declare (indent 1)
4750            (doc-string 2))
4751   (dolist (prop '(:start :interrupt :print-doc))
4752     (when (plist-get properties prop)
4753       (error "%s not allowed in definition of command syntax checker %s"
4754              prop symbol)))
4755
4756   (unless (plist-get properties :error-filter)
4757     ;; Default to `flycheck-sanitize-errors' as error filter
4758     (setq properties (plist-put properties :error-filter
4759                                 #'flycheck-sanitize-errors)))
4760   (let ((verify-fn (plist-get properties :verify)))
4761     (setq properties
4762           (plist-put properties :verify
4763                      (lambda (checker)
4764                        (append (flycheck-verify-command-checker checker)
4765                                (and verify-fn
4766                                     (funcall verify-fn checker)))))))
4767
4768   (let ((command (plist-get properties :command))
4769         (patterns (plist-get properties :error-patterns))
4770         (parser (or (plist-get properties :error-parser)
4771                     #'flycheck-parse-with-patterns))
4772         (enabled (plist-get properties :enabled))
4773         (standard-input (plist-get properties :standard-input)))
4774     (unless command
4775       (error "Missing :command in syntax checker %s" symbol))
4776     (unless (stringp (car command))
4777       (error "Command executable for syntax checker %s must be a string: %S"
4778              symbol (car command)))
4779     (dolist (arg (cdr command))
4780       (unless (flycheck-command-argument-p arg)
4781         (error "Invalid command argument %S in syntax checker %s" arg symbol)))
4782     (when (and (eq parser 'flycheck-parse-with-patterns)
4783                (not patterns))
4784       (error "Missing :error-patterns in syntax checker %s" symbol))
4785
4786     (setq properties
4787           ;; Automatically disable command checkers if the executable does not
4788           ;; exist.
4789           (plist-put properties :enabled
4790                      (lambda ()
4791                        (and (flycheck-find-checker-executable symbol)
4792                             (flycheck-temp-files-writable-p symbol)
4793                             (or (not enabled) (funcall enabled))))))
4794
4795     (apply #'flycheck-define-generic-checker symbol docstring
4796            :start #'flycheck-start-command-checker
4797            :interrupt #'flycheck-interrupt-command-checker
4798            :print-doc #'flycheck-command-checker-print-doc
4799            properties)
4800
4801     ;; Pre-compile all errors patterns into strings, so that we don't need to do
4802     ;; that on each error parse
4803     (let ((patterns (seq-map (lambda (p)
4804                                (cons (flycheck-rx-to-string `(and ,@(cdr p))
4805                                                             'no-group)
4806                                      (car p)))
4807                              patterns)))
4808       (pcase-dolist (`(,prop . ,value)
4809                      `((command        . ,command)
4810                        (error-parser   . ,parser)
4811                        (error-patterns . ,patterns)
4812                        (standard-input . ,standard-input)))
4813         (setf (flycheck-checker-get symbol prop) value)))))
4814
4815 (eval-and-compile
4816   ;; Make this function available during byte-compilation, since we need it
4817   ;; at macro expansion of `flycheck-def-executable-var'.
4818   (defun flycheck-checker-executable-variable (checker)
4819     "Get the executable variable of CHECKER.
4820
4821 The executable variable is named `flycheck-CHECKER-executable'."
4822     (intern (format "flycheck-%s-executable" checker))))
4823
4824 (defun flycheck-checker-default-executable (checker)
4825   "Get the default executable of CHECKER."
4826   (car (flycheck-checker-get checker 'command)))
4827
4828 (defun flycheck-checker-executable (checker)
4829   "Get the command executable of CHECKER.
4830
4831 The executable is either the value of the variable
4832 `flycheck-CHECKER-executable', or the default executable given in
4833 the syntax checker definition, if the variable is nil."
4834   (let ((var (flycheck-checker-executable-variable checker)))
4835     (or (and (boundp var) (symbol-value var))
4836         (flycheck-checker-default-executable checker))))
4837
4838 (defun flycheck-find-checker-executable (checker)
4839   "Get the full path of the executable of CHECKER.
4840
4841 Return the full absolute path to the executable of CHECKER, or
4842 nil if the executable does not exist."
4843   (funcall flycheck-executable-find (flycheck-checker-executable checker)))
4844
4845 (defun flycheck-checker-arguments (checker)
4846   "Get the command arguments of CHECKER."
4847   (cdr (flycheck-checker-get checker 'command)))
4848
4849 (defun flycheck-substitute-argument (arg checker)
4850   "Substitute ARG for CHECKER.
4851
4852 Return a list of real arguments for the executable of CHECKER,
4853 substituted for the symbolic argument ARG.  Single arguments,
4854 e.g. if ARG is a literal strings, are wrapped in a list.
4855
4856 ARG may be one of the following forms:
4857
4858 STRING
4859      Return ARG unchanged.
4860
4861 `source', `source-inplace'
4862      Create a temporary file to check and return its path.  With
4863      `source-inplace' create the temporary file in the same
4864      directory as the original file.  The value of
4865      `flycheck-temp-prefix' is used as prefix of the file name.
4866
4867      With `source', try to retain the non-directory component of
4868      the buffer's file name in the temporary file.
4869
4870      `source' is the preferred way to pass the input file to a
4871      syntax checker.  `source-inplace' should only be used if the
4872      syntax checker needs other files from the source directory,
4873      such as include files in C.
4874
4875 `source-original'
4876      Return the path of the actual file to check, or an empty
4877      string if the buffer has no file name.
4878
4879      Note that the contents of the file may not be up to date
4880      with the contents of the buffer to check.  Do not use this
4881      as primary input to a checker, unless absolutely necessary.
4882
4883      When using this symbol as primary input to the syntax
4884      checker, add `flycheck-buffer-saved-p' to the `:predicate'.
4885
4886 `temporary-directory'
4887      Create a unique temporary directory and return its path.
4888
4889 `temporary-file-name'
4890      Return a unique temporary filename.  The file is *not*
4891      created.
4892
4893      To ignore the output of syntax checkers, try `null-device'
4894      first.
4895
4896 `null-device'
4897      Return the value of `null-device', i.e the system null
4898      device.
4899
4900      Use this option to ignore the output of a syntax checker.
4901      If the syntax checker cannot handle the null device, or
4902      won't write to an existing file, try `temporary-file-name'
4903      instead.
4904
4905 `(config-file OPTION VARIABLE [PREPEND-FN])'
4906      Search the configuration file bound to VARIABLE with
4907      `flycheck-locate-config-file' and return a list of arguments
4908      that pass this configuration file to the syntax checker, or
4909      nil if the configuration file was not found.
4910
4911      PREPEND-FN is called with the OPTION and the located
4912      configuration file, and should return OPTION prepended
4913      before the file, either a string or as list.  If omitted,
4914      PREPEND-FN defaults to `list'.
4915
4916 `(option OPTION VARIABLE [PREPEND-FN [FILTER]])'
4917      Retrieve the value of VARIABLE and return a list of
4918      arguments that pass this value as value for OPTION to the
4919      syntax checker.
4920
4921      PREPEND-FN is called with the OPTION and the value of
4922      VARIABLE, and should return OPTION prepended before the
4923      file, either a string or as list.  If omitted, PREPEND-FN
4924      defaults to `list'.
4925
4926      FILTER is an optional function to be applied to the value of
4927      VARIABLE before prepending.  This function must return nil
4928      or a string.  In the former case, return nil.  In the latter
4929      case, return a list of arguments as described above.
4930
4931 `(option-list OPTION VARIABLE [PREPEND-FN [FILTER]])'
4932      Retrieve the value of VARIABLE, which must be a list,
4933      and prepend OPTION before each item in this list, using
4934      PREPEND-FN.
4935
4936      PREPEND-FN is called with the OPTION and each item of the
4937      list as second argument, and should return OPTION prepended
4938      before the item, either as string or as list.  If omitted,
4939      PREPEND-FN defaults to `list'.
4940
4941      FILTER is an optional function to be applied to each item in
4942      the list before prepending OPTION.  It shall return the
4943      option value for each item as string, or nil, if the item is
4944      to be ignored.
4945
4946 `(option-flag OPTION VARIABLE)'
4947      Retrieve the value of VARIABLE and return OPTION, if the
4948      value is non-nil.  Otherwise return nil.
4949
4950 `(eval FORM)'
4951      Return the result of evaluating FORM in the buffer to be
4952      checked.  FORM must either return a string or a list of
4953      strings, or nil to indicate that nothing should be
4954      substituted for CELL.  For all other return types, signal an
4955      error
4956
4957      _No_ further substitutions are performed, neither in FORM
4958      before it is evaluated, nor in the result of evaluating
4959      FORM.
4960
4961 In all other cases, signal an error.
4962
4963 Note that substitution is *not* recursive.  No symbols or cells
4964 are substituted within the body of cells!"
4965   (pcase arg
4966     ((pred stringp) (list arg))
4967     (`source
4968      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-system)))
4969     (`source-inplace
4970      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)))
4971     (`source-original (list (or (buffer-file-name) "")))
4972     (`temporary-directory (list (flycheck-temp-dir-system)))
4973     (`temporary-file-name
4974      (let ((directory (flycheck-temp-dir-system)))
4975        (list (make-temp-name (expand-file-name "flycheck" directory)))))
4976     (`null-device (list null-device))
4977     (`(config-file ,option-name ,file-name-var)
4978      (-when-let* ((value (symbol-value file-name-var))
4979                   (file-name (flycheck-locate-config-file value checker)))
4980        (flycheck-prepend-with-option option-name (list file-name))))
4981     (`(config-file ,option-name ,file-name-var ,prepend-fn)
4982      (-when-let* ((value (symbol-value file-name-var))
4983                   (file-name (flycheck-locate-config-file value checker)))
4984        (flycheck-prepend-with-option option-name (list file-name) prepend-fn)))
4985     (`(option ,option-name ,variable)
4986      (-when-let (value (symbol-value variable))
4987        (unless (stringp value)
4988          (error "Value %S of %S for option %s is not a string"
4989                 value variable option-name))
4990        (flycheck-prepend-with-option option-name (list value))))
4991     (`(option ,option-name ,variable ,prepend-fn)
4992      (-when-let (value (symbol-value variable))
4993        (unless (stringp value)
4994          (error "Value %S of %S for option %s is not a string"
4995                 value variable option-name))
4996        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
4997     (`(option ,option-name ,variable ,prepend-fn ,filter)
4998      (-when-let (value (funcall filter (symbol-value variable)))
4999        (unless (stringp value)
5000          (error "Value %S of %S (filter: %S) for option %s is not a string"
5001                 value variable filter option-name))
5002        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
5003     (`(option-list ,option-name ,variable)
5004      (let ((value (symbol-value variable)))
5005        (unless (and (listp value) (seq-every-p #'stringp value))
5006          (error "Value %S of %S for option %S is not a list of strings"
5007                 value variable option-name))
5008        (flycheck-prepend-with-option option-name value)))
5009     (`(option-list ,option-name ,variable ,prepend-fn)
5010      (let ((value (symbol-value variable)))
5011        (unless (and (listp value) (seq-every-p #'stringp value))
5012          (error "Value %S of %S for option %S is not a list of strings"
5013                 value variable option-name))
5014        (flycheck-prepend-with-option option-name value prepend-fn)))
5015     (`(option-list ,option-name ,variable ,prepend-fn ,filter)
5016      (let ((value (delq nil (seq-map filter (symbol-value variable)))))
5017        (unless (and (listp value) (seq-every-p #'stringp value))
5018          (error "Value %S of %S for option %S is not a list of strings"
5019                 value variable option-name))
5020        (flycheck-prepend-with-option option-name value prepend-fn)))
5021     (`(option-flag ,option-name ,variable)
5022      (when (symbol-value variable)
5023        (list option-name)))
5024     (`(eval ,form)
5025      (let ((result (eval form)))
5026        (cond
5027         ((and (listp result) (seq-every-p #'stringp result)) result)
5028         ((stringp result) (list result))
5029         (t (error "Invalid result from evaluation of %S: %S" form result)))))
5030     (_ (error "Unsupported argument %S" arg))))
5031
5032 (defun flycheck-checker-substituted-arguments (checker)
5033   "Get the substituted arguments of a CHECKER.
5034
5035 Substitute each argument of CHECKER using
5036 `flycheck-substitute-argument'.  This replaces any special
5037 symbols in the command."
5038   (apply #'append
5039          (seq-map (lambda (arg) (flycheck-substitute-argument arg checker))
5040                   (flycheck-checker-arguments checker))))
5041
5042 (defun flycheck--process-send-buffer-contents-chunked (process)
5043   "Send contents of current buffer to PROCESS in small batches.
5044
5045 Send the entire buffer to the standard input of PROCESS in chunks
5046 of 4096 characters.  Chunking is done in Emacs Lisp, hence this
5047 function is probably far less efficient than
5048 `send-process-region'.  Use only when required."
5049   (let ((from (point-min)))
5050     (while (< from (point-max))
5051       (let ((to (min (+ from 4096) (point-max))))
5052         (process-send-region process from to)
5053         (setq from to)))))
5054
5055 (defvar flycheck-chunked-process-input
5056   ;; Chunk process output on Windows to work around
5057   ;; https://github.com/flycheck/flycheck/issues/794 and
5058   ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22344.  The presence of
5059   ;; `w32-pipe-buffer-size' denotes an Emacs version (> Emacs 25.1 )where pipe
5060   ;; writes on Windows are fixed.
5061   ;;
5062   ;; TODO: Remove option and chunking when dropping Emacs 24 support, see
5063   ;; https://github.com/flycheck/flycheck/issues/856
5064   (and (eq system-type 'windows-nt) (not (boundp 'w32-pipe-buffer-size)))
5065   "If non-nil send process input in small chunks.
5066
5067 If this variable is non-nil `flycheck-process-send-buffer' sends
5068 buffer contents in small chunks.
5069
5070 Defaults to nil, except on Windows to work around Emacs bug
5071 #22344.")
5072
5073 (defun flycheck-process-send-buffer (process)
5074   "Send all contents of current buffer to PROCESS.
5075
5076 Sends all contents of the current buffer to the standard input of
5077 PROCESS, and terminates standard input with EOF.
5078
5079 If `flycheck-chunked-process-input' is non-nil, send buffer
5080 contents in chunks via
5081 `flycheck--process-send-buffer-contents-chunked', which see.
5082 Otherwise use `process-send-region' to send all contents at once
5083 and rely on Emacs' own buffering and chunking."
5084   (save-restriction
5085     (widen)
5086     (if flycheck-chunked-process-input
5087         (flycheck--process-send-buffer-contents-chunked process)
5088       (process-send-region process (point-min) (point-max))))
5089   (process-send-eof process))
5090
5091 (defun flycheck-start-command-checker (checker callback)
5092   "Start a command CHECKER with CALLBACK."
5093   (let (process)
5094     (condition-case err
5095         (let* ((program (flycheck-find-checker-executable checker))
5096                (args (flycheck-checker-substituted-arguments checker))
5097                (command (funcall flycheck-command-wrapper-function
5098                                  (cons program args)))
5099                ;; Use pipes to receive output from the syntax checker.  They are
5100                ;; more efficient and more robust than PTYs, which Emacs uses by
5101                ;; default, and since we don't need any job control features, we
5102                ;; can easily use pipes.
5103                (process-connection-type nil))
5104           ;; We pass do not associate the process with any buffer, by
5105           ;; passing nil for the BUFFER argument of `start-process'.
5106           ;; Instead, we just remember the buffer being checked in a
5107           ;; process property (see below).  This neatly avoids all
5108           ;; side-effects implied by attached a process to a buffer, which
5109           ;; may cause conflicts with other packages.
5110           ;;
5111           ;; See https://github.com/flycheck/flycheck/issues/298 for an
5112           ;; example for such a conflict.
5113           (setq process (apply 'start-process (format "flycheck-%s" checker)
5114                                nil command))
5115           (setf (process-sentinel process) #'flycheck-handle-signal)
5116           (setf (process-filter process) #'flycheck-receive-checker-output)
5117           (set-process-query-on-exit-flag process nil)
5118           ;; Remember the syntax checker, the buffer and the callback
5119           (process-put process 'flycheck-checker checker)
5120           (process-put process 'flycheck-callback callback)
5121           (process-put process 'flycheck-buffer (current-buffer))
5122           ;; The default directory is bound in the `flycheck-syntax-check-start'
5123           ;; function.
5124           (process-put process 'flycheck-working-directory default-directory)
5125           ;; Track the temporaries created by argument substitution in the
5126           ;; process itself, to get rid of the global state ASAP.
5127           (process-put process 'flycheck-temporaries flycheck-temporaries)
5128           (setq flycheck-temporaries nil)
5129           ;; Send the buffer to the process on standard input, if enabled.
5130           (when (flycheck-checker-get checker 'standard-input)
5131             (flycheck-process-send-buffer process))
5132           ;; Return the process.
5133           process)
5134       (error
5135        ;; In case of error, clean up our resources, and report the error back to
5136        ;; Flycheck.
5137        (flycheck-safe-delete-temporaries)
5138        (when process
5139          ;; No need to explicitly delete the temporary files of the process,
5140          ;; because deleting runs the sentinel, which will delete them anyway.
5141          (delete-process process))
5142        (signal (car err) (cdr err))))))
5143
5144 (defun flycheck-interrupt-command-checker (_checker process)
5145   "Interrupt a PROCESS."
5146   ;; Deleting the process always triggers the sentinel, which does the cleanup
5147   (when process
5148     (delete-process process)))
5149
5150 (defun flycheck-command-checker-print-doc (checker)
5151   "Print additional documentation for a command CHECKER."
5152   (let ((executable (flycheck-checker-default-executable checker))
5153         (config-file-var (flycheck-checker-get checker 'config-file-var))
5154         (option-vars (seq-sort #'string<
5155                                (flycheck-checker-get checker 'option-vars))))
5156     (princ "\n")
5157
5158     (let ((doc-start (with-current-buffer standard-output (point-max))))
5159       ;; Track the start of our documentation so that we can re-indent it
5160       ;; properly
5161       (princ "  This syntax checker executes \"")
5162       (princ executable)
5163       (princ "\"")
5164       (when config-file-var
5165         (princ ", using a configuration file from `")
5166         (princ (symbol-name config-file-var))
5167         (princ "'"))
5168       (princ ". The executable can be overridden with `")
5169       (princ (symbol-name (flycheck-checker-executable-variable checker)))
5170       (princ "'.")
5171
5172       (with-current-buffer standard-output
5173         (save-excursion
5174           (fill-region-as-paragraph doc-start (point-max)))))
5175     (princ "\n")
5176     (when option-vars
5177       (princ
5178        "\n  This syntax checker can be configured with these options:\n\n")
5179       (dolist (var option-vars)
5180         (princ (format "     * `%s'\n" var))))))
5181
5182 (defun flycheck-verify-command-checker (checker)
5183   "Verify a command CHECKER in the current buffer.
5184
5185 Return a list of `flycheck-verification-result' objects for
5186 CHECKER."
5187   (let ((executable (flycheck-find-checker-executable checker))
5188         (config-file-var (flycheck-checker-get checker 'config-file-var)))
5189     `(
5190       ,(flycheck-verification-result-new
5191         :label "executable"
5192         :message (if executable (format "Found at %s" executable) "Not found")
5193         :face (if executable 'success '(bold error)))
5194       ,@(when config-file-var
5195           (let* ((value (symbol-value config-file-var))
5196                  (path (and value (flycheck-locate-config-file value checker))))
5197             (list (flycheck-verification-result-new
5198                    :label "configuration file"
5199                    :message (if path (format "Found at %S" path) "Not found")
5200                    :face (if path 'success 'warning)))))
5201       ,@(when (not (flycheck-temp-files-writable-p checker))
5202           (list (flycheck-verification-result-new
5203                  :label "temp directory"
5204                  :message (format "%s is not writable"
5205                                   (flycheck-temp-directory checker))
5206                  :face 'error))))))
5207
5208
5209 ;;; Process management for command syntax checkers
5210 (defun flycheck-receive-checker-output (process output)
5211   "Receive a syntax checking PROCESS OUTPUT."
5212   (push output (process-get process 'flycheck-pending-output)))
5213
5214 (defun flycheck-get-output (process)
5215   "Get the complete output of PROCESS."
5216   (with-demoted-errors "Error while retrieving process output: %S"
5217     (let ((pending-output (process-get process 'flycheck-pending-output)))
5218       (apply #'concat (nreverse pending-output)))))
5219
5220 (defun flycheck-handle-signal (process _event)
5221   "Handle a signal from the syntax checking PROCESS.
5222
5223 _EVENT is ignored."
5224   (when (memq (process-status process) '(signal exit))
5225     (let ((files (process-get process 'flycheck-temporaries))
5226           (buffer (process-get process 'flycheck-buffer))
5227           (callback (process-get process 'flycheck-callback))
5228           (cwd (process-get process 'flycheck-working-directory)))
5229       ;; Delete the temporary files
5230       (seq-do #'flycheck-safe-delete files)
5231       (when (buffer-live-p buffer)
5232         (with-current-buffer buffer
5233           (condition-case err
5234               (pcase (process-status process)
5235                 (`signal
5236                  (funcall callback 'interrupted))
5237                 (`exit
5238                  (flycheck-finish-checker-process
5239                   (process-get process 'flycheck-checker)
5240                   (process-exit-status process)
5241                   files
5242                   (flycheck-get-output process) callback cwd)))
5243             ((debug error)
5244              (funcall callback 'errored (error-message-string err)))))))))
5245
5246 (defun flycheck-finish-checker-process
5247     (checker exit-status files output callback cwd)
5248   "Finish a checker process from CHECKER with EXIT-STATUS.
5249
5250 FILES is a list of files given as input to the checker.  OUTPUT
5251 is the output of the syntax checker.  CALLBACK is the status
5252 callback to use for reporting.
5253
5254 Parse the OUTPUT and report an appropriate error status.
5255
5256 Resolve all errors in OUTPUT using CWD as working directory."
5257   (let ((errors (flycheck-parse-output output checker (current-buffer))))
5258     (when (and (/= exit-status 0) (not errors))
5259       ;; Warn about a suspicious result from the syntax checker.  We do right
5260       ;; after parsing the errors, before filtering, because a syntax checker
5261       ;; might report errors from other files (e.g. includes) even if there
5262       ;; are no errors in the file being checked.
5263       (funcall callback 'suspicious
5264                (format "Flycheck checker %S returned non-zero \
5265 exit code %s, but its output contained no errors: %s\nTry \
5266 installing a more recent version of %S, and please open a bug \
5267 report if the issue persists in the latest release.  Thanks!"
5268                        checker exit-status output checker)))
5269     (funcall callback 'finished
5270              ;; Fix error file names, by substituting them backwards from the
5271              ;; temporaries.
5272              (seq-map (lambda (e) (flycheck-fix-error-filename e files cwd))
5273                       errors))))
5274
5275
5276 ;;; Executables of command checkers.
5277 (defmacro flycheck-def-executable-var (checker default-executable)
5278   "Define the executable variable for CHECKER.
5279
5280 DEFAULT-EXECUTABLE is the default executable.  It is only used in
5281 the docstring of the variable.
5282
5283 The variable is defined with `defcustom' in the
5284 `flycheck-executables' group.  It's also defined to be risky as
5285 file-local variable, to avoid arbitrary executables being used
5286 for syntax checking."
5287   (let ((executable-var (flycheck-checker-executable-variable checker)))
5288     `(progn
5289        (defcustom ,executable-var nil
5290          ,(format "The executable of the %s syntax checker.
5291
5292 Either a string containing the name or the path of the
5293 executable, or nil to use the default executable from the syntax
5294 checker declaration.
5295
5296 The default executable is %S." checker default-executable)
5297          :type '(choice (const :tag "Default executable" nil)
5298                         (string :tag "Name or path"))
5299          :group 'flycheck-executables
5300          :risky t))))
5301
5302 (defun flycheck-set-checker-executable (checker &optional executable)
5303   "Set the executable of CHECKER in the current buffer.
5304
5305 CHECKER is a syntax checker symbol.  EXECUTABLE is a string with
5306 the name of an executable or the path to an executable file, which
5307 is to be used as executable for CHECKER.  If omitted or nil,
5308 reset the executable of CHECKER.
5309
5310 Interactively, prompt for a syntax checker and an executable
5311 file, and set the executable of the selected syntax checker.
5312 With prefix arg, prompt for a syntax checker only, and reset the
5313 executable of the select checker to the default.
5314
5315 Set the executable variable of CHECKER, that is,
5316 `flycheck-CHECKER-executable' to EXECUTABLE.  Signal
5317 `user-error', if EXECUTABLE does not denote a command or an
5318 executable file.
5319
5320 This command is intended for interactive use only.  In Lisp, just
5321 `let'-bind the corresponding variable, or set it directly.  Use
5322 `flycheck-checker-executable-variable' to obtain the executable
5323 variable symbol for a syntax checker."
5324   (declare (interactive-only "Set the executable variable directly instead"))
5325   (interactive
5326    (let* ((checker (read-flycheck-checker "Syntax checker: "))
5327           (default-executable (flycheck-checker-default-executable checker))
5328           (executable (if current-prefix-arg
5329                           nil
5330                         (read-file-name "Executable: " nil default-executable
5331                                         nil nil flycheck-executable-find))))
5332      (list checker executable)))
5333   (when (and executable (not (funcall flycheck-executable-find executable)))
5334     (user-error "%s is no executable" executable))
5335   (let ((variable (flycheck-checker-executable-variable checker)))
5336     (set (make-local-variable variable) executable)))
5337
5338
5339 ;;; Configuration files and options for command checkers
5340 (defun flycheck-register-config-file-var (var checkers)
5341   "Register VAR as config file var for CHECKERS.
5342
5343 CHECKERS is a single syntax checker or a list thereof."
5344   (when (symbolp checkers)
5345     (setq checkers (list checkers)))
5346   (dolist (checker checkers)
5347     (setf (flycheck-checker-get checker 'config-file-var) var)))
5348
5349 ;;;###autoload
5350 (defmacro flycheck-def-config-file-var (symbol checker &optional file-name
5351                                                &rest custom-args)
5352   "Define SYMBOL as config file variable for CHECKER, with default FILE-NAME.
5353
5354 SYMBOL is declared as customizable variable using `defcustom', to
5355 provide a configuration file for the given syntax CHECKER.
5356 CUSTOM-ARGS are forwarded to `defcustom'.
5357
5358 FILE-NAME is the initial value of the new variable.  If omitted,
5359 the default value is nil.
5360
5361 Use this together with the `config-file' form in the `:command'
5362 argument to `flycheck-define-checker'."
5363   ;; FIXME: We should allow multiple config files per checker as well as
5364   ;; multiple checkers per config file
5365   (declare (indent 3))
5366   `(progn
5367      (defcustom ,symbol ,file-name
5368        ,(format "Configuration file for `%s'.
5369
5370 If set to a string, locate the configuration file using the
5371 functions from `flycheck-locate-config-file-functions'.  If the
5372 file is found pass it to the syntax checker as configuration
5373 file.
5374
5375 If no configuration file is found, or if this variable is set to
5376 nil, invoke the syntax checker without a configuration file.
5377
5378 Use this variable as file-local variable if you need a specific
5379 configuration file a buffer." checker)
5380        :type '(choice (const :tag "No configuration file" nil)
5381                       (string :tag "File name or path"))
5382        :group 'flycheck-config-files
5383        ,@custom-args)
5384      (flycheck-register-config-file-var ',symbol ',checker)))
5385
5386 (defun flycheck-locate-config-file (filename checker)
5387   "Locate the configuration file FILENAME for CHECKER.
5388
5389 Locate the configuration file using
5390 `flycheck-locate-config-file-functions'.
5391
5392 Return the absolute path of the configuration file, or nil if no
5393 configuration file was found."
5394   (-when-let (filepath (run-hook-with-args-until-success
5395                         'flycheck-locate-config-file-functions
5396                         filename checker))
5397     (when (file-exists-p filepath)
5398       filepath)))
5399
5400 (defun flycheck-locate-config-file-by-path (filepath _checker)
5401   "Locate a configuration file by a FILEPATH.
5402
5403 If FILEPATH is a contains a path separator, expand it against the
5404 default directory and return it if it points to an existing file.
5405 Otherwise return nil.
5406
5407 _CHECKER is ignored."
5408   ;; If the path is just a plain file name, skip it.
5409   (unless (string= (file-name-nondirectory filepath) filepath)
5410     (let ((file-name (expand-file-name filepath)))
5411       (and (file-exists-p file-name) file-name))))
5412
5413 (defun flycheck-locate-config-file-ancestor-directories (filename _checker)
5414   "Locate a configuration FILENAME in ancestor directories.
5415
5416 If the current buffer has a file name, search FILENAME in the
5417 directory of the current buffer and all ancestors thereof (see
5418 `locate-dominating-file').  If the file is found, return its
5419 absolute path.  Otherwise return nil.
5420
5421 _CHECKER is ignored."
5422   (-when-let* ((basefile (buffer-file-name))
5423                (directory (locate-dominating-file basefile filename)))
5424     (expand-file-name filename directory)))
5425
5426 (defun flycheck-locate-config-file-home (filename _checker)
5427   "Locate a configuration FILENAME in the home directory.
5428
5429 Return the absolute path, if FILENAME exists in the user's home
5430 directory, or nil otherwise."
5431   (let ((path (expand-file-name filename "~")))
5432     (when (file-exists-p path)
5433       path)))
5434
5435 (seq-do (apply-partially #'custom-add-frequent-value
5436                          'flycheck-locate-config-file-functions)
5437         '(flycheck-locate-config-file-by-path
5438           flycheck-locate-config-file-ancestor-directories
5439           flycheck-locate-config-file-home))
5440
5441 (defun flycheck-register-option-var (var checkers)
5442   "Register an option VAR with CHECKERS.
5443
5444 VAR is an option symbol, and CHECKERS a syntax checker symbol or
5445 a list thereof.  Register VAR with all CHECKERS so that it
5446 appears in the help output."
5447   (when (symbolp checkers)
5448     (setq checkers (list checkers)))
5449   (dolist (checker checkers)
5450     (cl-pushnew var (flycheck-checker-get checker 'option-vars))))
5451
5452 ;;;###autoload
5453 (defmacro flycheck-def-option-var (symbol init-value checkers docstring
5454                                           &rest custom-args)
5455   "Define SYMBOL as option variable with INIT-VALUE for CHECKER.
5456
5457 SYMBOL is declared as customizable variable using `defcustom', to
5458 provide an option for the given syntax CHECKERS (a checker or a
5459 list of checkers).  INIT-VALUE is the initial value of the
5460 variable, and DOCSTRING is its docstring.  CUSTOM-ARGS are
5461 forwarded to `defcustom'.
5462
5463 Use this together with the `option', `option-list' and
5464 `option-flag' forms in the `:command' argument to
5465 `flycheck-define-checker'."
5466   (declare (indent 3)
5467            (doc-string 4))
5468   `(progn
5469      (defcustom ,symbol ,init-value
5470        ,(concat docstring "
5471
5472 This variable is an option for the following syntax checkers:
5473
5474 "
5475                 (mapconcat (lambda (c) (format "  - `%s'" c))
5476                            (if (symbolp checkers) (list checkers) checkers)
5477                            "\n"))
5478        :group 'flycheck-options
5479        ,@custom-args)
5480      (flycheck-register-option-var ',symbol ',checkers)))
5481
5482 (defun flycheck-option-int (value)
5483   "Convert an integral option VALUE to a string.
5484
5485 If VALUE is nil, return nil.  Otherwise return VALUE converted to
5486 a string."
5487   (and value (number-to-string value)))
5488
5489 (defun flycheck-option-symbol (value)
5490   "Convert a symbol option VALUE to string.
5491
5492 If VALUE is nil return nil.  Otherwise return VALUE converted to
5493 a string."
5494   (and value (symbol-name value)))
5495
5496 (defun flycheck-option-comma-separated-list (value &optional separator filter)
5497   "Convert VALUE into a list separated by SEPARATOR.
5498
5499 SEPARATOR is a string to separate items in VALUE, defaulting to
5500 \",\".  FILTER is an optional function, which takes a single
5501 argument and returns either a string or nil.
5502
5503 If VALUE is a list, apply FILTER to each item in VALUE, remove
5504 all nil items, and return a single string of all remaining items
5505 separated by SEPARATOR.
5506
5507 Otherwise, apply FILTER to VALUE and return the result.
5508 SEPARATOR is ignored in this case."
5509   (let ((filter (or filter #'identity))
5510         (separator (or separator ",")))
5511     (if (listp value)
5512         (-when-let (value (delq nil (seq-map filter value)))
5513           (string-join value separator))
5514       (funcall filter value))))
5515
5516 (defmacro flycheck-def-args-var (symbol checkers &rest custom-args)
5517   "Define SYMBOL as argument variable for CHECKERS.
5518
5519 SYMBOL is declared as customizable, risky and buffer-local
5520 variable using `defcustom' to provide an option for arbitrary
5521 arguments for the given syntax CHECKERS (either a single checker
5522 or a list of checkers).  CUSTOM-ARGS is forwarded to `defcustom'.
5523
5524 Use the `eval' form to splice this variable into the
5525 `:command'."
5526   (declare (indent 2))
5527   `(flycheck-def-option-var ,symbol nil ,checkers
5528      "A list of additional command line arguments.
5529
5530 The value of this variable is a list of strings with additional
5531 command line arguments."
5532      :risky t
5533      :type '(repeat (string :tag "Argument"))
5534      ,@custom-args))
5535
5536
5537 ;;; Command syntax checkers as compile commands
5538 (defun flycheck-checker-pattern-to-error-regexp (pattern)
5539   "Convert PATTERN into an error regexp for compile.el.
5540
5541 Return a list representing PATTERN, suitable as element in
5542 `compilation-error-regexp-alist'."
5543   (let* ((regexp (car pattern))
5544          (level (cdr pattern))
5545          (level-no (flycheck-error-level-compilation-level level)))
5546     (list regexp 1 2 3 level-no)))
5547
5548 (defun flycheck-checker-compilation-error-regexp-alist (checker)
5549   "Convert error patterns of CHECKER for use with compile.el.
5550
5551 Return an alist of all error patterns of CHECKER, suitable for
5552 use with `compilation-error-regexp-alist'."
5553   (seq-map #'flycheck-checker-pattern-to-error-regexp
5554            (flycheck-checker-get checker 'error-patterns)))
5555
5556 (defun flycheck-checker-shell-command (checker)
5557   "Get a shell command for CHECKER.
5558
5559 Perform substitution in the arguments of CHECKER, but with
5560 `flycheck-substitute-shell-argument'.
5561
5562 Return the command of CHECKER as single string, suitable for
5563 shell execution."
5564   ;; Note: Do NOT use `combine-and-quote-strings' here.  Despite it's name it
5565   ;; does not properly quote shell arguments, and actually breaks for special
5566   ;; characters.  See https://github.com/flycheck/flycheck/pull/522
5567   (let* ((args (apply #'append
5568                       (seq-map
5569                        (lambda (arg)
5570                          (if (memq arg '(source source-inplace source-original))
5571                              (list (buffer-file-name))
5572                            (flycheck-substitute-argument arg checker)))
5573                        (flycheck-checker-arguments checker))))
5574          (command (mapconcat
5575                    #'shell-quote-argument
5576                    (funcall flycheck-command-wrapper-function
5577                             (cons (flycheck-checker-executable checker) args))
5578                    " ")))
5579     (if (flycheck-checker-get checker 'standard-input)
5580         ;; If the syntax checker expects the source from standard input add an
5581         ;; appropriate shell redirection
5582         (concat command " < " (shell-quote-argument (buffer-file-name)))
5583       command)))
5584
5585 (defun flycheck-compile-name (_name)
5586   "Get a name for a Flycheck compilation buffer.
5587
5588 _NAME is ignored."
5589   (format "*Flycheck %s*" (buffer-file-name)))
5590
5591 (defun flycheck-compile (checker)
5592   "Run CHECKER via `compile'.
5593
5594 CHECKER must be a valid syntax checker.  Interactively, prompt
5595 for a syntax checker to run.
5596
5597 Instead of highlighting errors in the buffer, this command pops
5598 up a separate buffer with the entire output of the syntax checker
5599 tool, just like `compile' (\\[compile])."
5600   (interactive
5601    (let ((default (flycheck-get-checker-for-buffer)))
5602      (list (read-flycheck-checker "Run syntax checker as compile command: "
5603                                   (when (flycheck-checker-get default 'command)
5604                                     default)
5605                                   'command))))
5606   (unless (flycheck-valid-checker-p checker)
5607     (user-error "%S is not a valid syntax checker" checker))
5608   (unless (buffer-file-name)
5609     (user-error "Cannot compile buffers without backing file"))
5610   (unless (flycheck-may-use-checker checker)
5611     (user-error "Cannot use syntax checker %S in this buffer" checker))
5612   (unless (flycheck-checker-executable checker)
5613     (user-error "Cannot run checker %S as shell command" checker))
5614   (let* ((default-directory (flycheck-compute-working-directory checker))
5615          (command (flycheck-checker-shell-command checker))
5616          (buffer (compilation-start command nil #'flycheck-compile-name)))
5617     (with-current-buffer buffer
5618       (setq-local compilation-error-regexp-alist
5619                   (flycheck-checker-compilation-error-regexp-alist checker)))))
5620
5621
5622 ;;; General error parsing for command checkers
5623 (defun flycheck-parse-output (output checker buffer)
5624   "Parse OUTPUT from CHECKER in BUFFER.
5625
5626 OUTPUT is a string with the output from the checker symbol
5627 CHECKER.  BUFFER is the buffer which was checked.
5628
5629 Return the errors parsed with the error patterns of CHECKER."
5630   (funcall (flycheck-checker-get checker 'error-parser) output checker buffer))
5631
5632 (defun flycheck-fix-error-filename (err buffer-files cwd)
5633   "Fix the file name of ERR from BUFFER-FILES.
5634
5635 Resolves error file names relative to CWD directory.
5636
5637 Make the file name of ERR absolute.  If the absolute file name of
5638 ERR is in BUFFER-FILES, replace it with the return value of the
5639 function `buffer-file-name'."
5640   (flycheck-error-with-buffer err
5641     (-when-let (filename (flycheck-error-filename err))
5642       (when (seq-some (apply-partially #'flycheck-same-files-p
5643                                        (expand-file-name filename cwd))
5644                       buffer-files)
5645         (setf (flycheck-error-filename err) buffer-file-name)
5646         (when (and buffer-file-name (flycheck-error-message err))
5647           (setf (flycheck-error-message err)
5648                 (replace-regexp-in-string
5649                  (regexp-quote filename) buffer-file-name
5650                  (flycheck-error-message err) 'fixed-case 'literal))))))
5651   err)
5652
5653
5654 ;;; Error parsers for command syntax checkers
5655 (defun flycheck-parse-xml-region (beg end)
5656   "Parse the xml region between BEG and END.
5657
5658 Wrapper around `xml-parse-region' which transforms the return
5659 value of this function into one compatible to
5660 `libxml-parse-xml-region' by simply returning the first element
5661 from the node list."
5662   (ignore-errors (car (xml-parse-region beg end))))
5663
5664 (defun flycheck-parse-xml-region-with-fallback (beg end)
5665   "Parse the xml region between BEG and END.
5666
5667 Try parsing with libxml first; if that fails, revert to
5668 `flycheck-parse-xml-region'.  Failures can be caused by incorrect
5669 XML (see URL `https://github.com/flycheck/flycheck/issues/1298'),
5670 or on Windows by a missing libxml DLL with a libxml-enabled Emacs
5671 \(see URL `https://github.com/flycheck/flycheck/issues/1330')."
5672   ;; FIXME use `libxml-available-p' when it gets implemented.
5673   (or (and (fboundp 'libxml-parse-xml-region)
5674            (libxml-parse-xml-region beg end))
5675       (flycheck-parse-xml-region beg end)))
5676
5677 (defvar flycheck-xml-parser 'flycheck-parse-xml-region-with-fallback
5678   "Function used to parse an xml string from a region.
5679
5680 The default uses libxml if available, and falls back to
5681 `flycheck-parse-xml-region' otherwise.")
5682
5683 (defun flycheck-parse-xml-string (xml)
5684   "Parse an XML string.
5685
5686 Return the document tree parsed from XML in the form `(ROOT ATTRS
5687 BODY...)'.  ROOT is a symbol identifying the name of the root
5688 element.  ATTRS is an alist of the attributes of the root node.
5689 BODY is zero or more body elements, either as strings (in case of
5690 text nodes) or as XML nodes, in the same for as the root node."
5691   (with-temp-buffer
5692     (insert xml)
5693     (funcall flycheck-xml-parser (point-min) (point-max))))
5694
5695 (defun flycheck-parse-checkstyle (output checker buffer)
5696   "Parse Checkstyle errors from OUTPUT.
5697
5698 Parse Checkstyle-like XML output.  Use this error parser for
5699 checkers that have an option to output errors in this format.
5700
5701 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
5702 the BUFFER that was checked respectively.
5703
5704 See URL `http://checkstyle.sourceforge.net/' for information
5705 about Checkstyle."
5706   (pcase (flycheck-parse-xml-string output)
5707     (`(checkstyle ,_ . ,file-nodes)
5708      (let (errors)
5709        (dolist (node file-nodes)
5710          (pcase node
5711            (`(file ,file-attrs . ,error-nodes)
5712             (dolist (node error-nodes)
5713               (pcase node
5714                 (`(error ,error-attrs . ,_)
5715                  (let-alist error-attrs
5716                    (push (flycheck-error-new-at
5717                           (flycheck-string-to-number-safe .line)
5718                           (flycheck-string-to-number-safe .column)
5719                           (pcase .severity
5720                             (`"error"   'error)
5721                             (`"warning" 'warning)
5722                             (`"info"    'info)
5723                             ;; Default to error for unknown .severity
5724                             (_          'error))
5725                           .message
5726                           :checker checker :id .source
5727                           :buffer buffer
5728                           :filename (cdr (assq 'name file-attrs)))
5729                          errors))))))))
5730        (nreverse errors)))))
5731
5732 (defun flycheck-parse-cppcheck (output checker buffer)
5733   "Parse Cppcheck errors from OUTPUT.
5734
5735 Parse Cppcheck XML v2 output.
5736
5737 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
5738 the BUFFER that was checked respectively.
5739
5740 See URL `http://cppcheck.sourceforge.net/' for more information
5741 about Cppcheck."
5742   (pcase (flycheck-parse-xml-string output)
5743     (`(results ,_ . ,body)
5744      (let (errors)
5745        (dolist (node body)
5746          (pcase node
5747            (`(errors ,_ . ,error-nodes)
5748             (dolist (node error-nodes)
5749               (pcase node
5750                 (`(error ,error-attrs . ,loc-nodes)
5751                  (let ((id (cdr (assq 'id error-attrs)))
5752                        (message (cdr (assq 'verbose error-attrs)))
5753                        (level (pcase (cdr (assq 'severity error-attrs))
5754                                 (`"error" 'error)
5755                                 (`"style" 'info)
5756                                 (`"information" 'info)
5757                                 (_ 'warning))))
5758                    (dolist (node loc-nodes)
5759                      (pcase node
5760                        (`(location ,loc-attrs . ,_)
5761                         (let-alist loc-attrs
5762                           (push (flycheck-error-new-at
5763                                  (flycheck-string-to-number-safe .line)
5764                                  nil
5765                                  level
5766                                  ;; cppcheck return newline characters as "\012"
5767                                  (replace-regexp-in-string "\\\\012" "\n"
5768                                                            message)
5769                                  :id id
5770                                  :checker checker
5771                                  :buffer buffer
5772                                  :filename .file)
5773                                 errors))))))))))))
5774        (nreverse errors)))))
5775
5776 (defun flycheck-parse-phpmd (output checker buffer)
5777   "Parse phpmd errors from OUTPUT.
5778
5779 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
5780 the BUFFER that was checked respectively.
5781
5782 See URL `http://phpmd.org/' for more information about phpmd."
5783   (pcase (flycheck-parse-xml-string output)
5784     (`(pmd ,_ . ,body)
5785      (let (errors)
5786        (dolist (node body)
5787          (pcase node
5788            (`(file ,file-attrs . ,violation-nodes)
5789             (let ((filename (cdr (assq 'name file-attrs))))
5790               (dolist (node violation-nodes)
5791                 (pcase node
5792                   (`(violation ,vio-attrs ,(and message (pred stringp)))
5793                    (let-alist vio-attrs
5794                      (push
5795                       (flycheck-error-new-at
5796                        (flycheck-string-to-number-safe .beginline)
5797                        nil
5798                        'warning (string-trim message)
5799                        :id .rule
5800                        :checker checker
5801                        :buffer buffer
5802                        :filename filename)
5803                       errors)))))))))
5804        (nreverse errors)))))
5805
5806 (defun flycheck-parse-reek (output checker buffer)
5807   "Parse Reek warnings from JSON OUTPUT.
5808
5809 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
5810 the BUFFER that was checked respectively.
5811
5812 See URL `https://github.com/troessner/reek' for more information
5813 about Reek."
5814   (let ((errors nil))
5815     (dolist (message (car (flycheck-parse-json output)))
5816       (let-alist message
5817         (dolist (line (delete-dups .lines))
5818           (push
5819            (flycheck-error-new-at
5820             line
5821             nil
5822             'warning (concat .context " " .message)
5823             :id .smell_type
5824             :checker checker
5825             :buffer buffer
5826             :filename .source)
5827            errors))))
5828     (nreverse errors)))
5829
5830 (defun flycheck-parse-tslint (output checker buffer)
5831   "Parse TSLint errors from JSON OUTPUT.
5832
5833 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
5834 the BUFFER that was checked respectively.
5835
5836 See URL `https://palantir.github.io/tslint/' for more information
5837 about TSLint."
5838   (let ((json-array-type 'list))
5839     (seq-map (lambda (message)
5840                (let-alist message
5841                  (flycheck-error-new-at
5842                   (+ 1 .startPosition.line)
5843                   (+ 1 .startPosition.character)
5844                   'warning .failure
5845                   :id .ruleName
5846                   :checker checker
5847                   :buffer buffer
5848                   :filename .name)))
5849              ;; Don't try to parse empty output as JSON
5850              (and (not (string-empty-p output))
5851                   (car (flycheck-parse-json output))))))
5852
5853 (defun flycheck-parse-rust-collect-spans (span)
5854   "Return a list of spans contained in a SPAN object."
5855   (let ((spans))
5856     (let-alist span
5857       ;; With macro expansion errors, some spans will point to phony file names
5858       ;; to indicate an error inside the std rust lib.  We skip these spans as
5859       ;; they won't appear in flycheck anyway.
5860       (unless (string= .file_name "<std macros>")
5861         (push span spans))
5862
5863       ;; Macro expansion errors will have a span in the 'expansion' field, so we
5864       ;; recursively collect it.
5865       (if .expansion.span
5866           (append (flycheck-parse-rust-collect-spans .expansion.span)
5867                   spans)
5868         spans))))
5869
5870 (defun flycheck-parse-rustc-diagnostic (diagnostic checker buffer)
5871   "Turn a rustc DIAGNOSTIC into a `flycheck-error'.
5872
5873 CHECKER and BUFFER denote the CHECKER that returned DIAGNOSTIC
5874 and the BUFFER that was checked respectively.
5875
5876 DIAGNOSTIC should be a parsed JSON object describing a rustc
5877 diagnostic, following the format described there:
5878
5879 https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139"
5880   (let ((error-message)
5881         (error-level)
5882         (error-code)
5883         (primary-filename)
5884         (primary-line)
5885         (primary-column)
5886         (group (make-symbol "group"))
5887         (spans)
5888         (children)
5889         (errors))
5890     ;; The diagnostic format is described in the link above.  The gist of it is
5891     ;; that a diagnostic can have several causes in the source text; these
5892     ;; causes are represented by spans.  The diagnostic has a message and a
5893     ;; level (error, warning), while the spans have a filename, line, column,
5894     ;; and an optional label.  The primary span points to the root cause of the
5895     ;; error in the source text, while non-primary spans point to related
5896     ;; causes.  Spans may have an 'expansion' field for macro expansion errors;
5897     ;; these expansion fields will contain another span (and so on).  In
5898     ;; addition, a diagnostic can also have children diagnostics that are used
5899     ;; to provide additional information through their message field, but do not
5900     ;; seem to contain any spans (yet).
5901     ;;
5902     ;; We first gather spans in order to turn every span into a flycheck error
5903     ;; object, that we collect into the `errors' list.
5904
5905     ;; Nested `let-alist' cause compilation warnings, hence we `setq' all
5906     ;; these values here first to avoid nesting.
5907     (let-alist diagnostic
5908       (setq error-message .message
5909             error-level (pcase .level
5910                           (`"error" 'error)
5911                           (`"warning" 'warning)
5912                           (`"note" 'info)
5913                           (_ 'error))
5914             ;; The 'code' field of the diagnostic contains the actual error
5915             ;; code and an optional explanation that we ignore
5916             error-code .code.code
5917             ;; Collect all spans recursively
5918             spans (seq-mapcat #'flycheck-parse-rust-collect-spans .spans)
5919             children .children))
5920
5921     ;; Turn each span into a flycheck error
5922     (dolist (span spans)
5923       (let-alist span
5924         ;; Children may not have filename/line/column information, so we use
5925         ;; those from the primary span
5926         (when .is_primary
5927           (setq primary-filename .file_name
5928                 primary-line .line_start
5929                 primary-column .column_start))
5930         (push
5931          (flycheck-error-new-at
5932           .line_start
5933           .column_start
5934           ;; Non-primary spans are used for notes
5935           (if .is_primary error-level 'info)
5936           (if .is_primary
5937               ;; Primary spans may have labels with additional information
5938               (concat error-message (when .label
5939                                       (format " (%s)" .label)))
5940             ;; If the label is empty, fallback on the error message,
5941             ;; otherwise we won't be able to display anything
5942             (or .label error-message))
5943           :id error-code
5944           :checker checker
5945           :buffer buffer
5946           :filename .file_name
5947           :group group)
5948          errors)))
5949
5950     ;; Then we turn children messages into flycheck errors pointing to the
5951     ;; location of the primary span.
5952     (dolist (child children)
5953       (let-alist child
5954         (push
5955          (flycheck-error-new-at
5956           ;; Use the line/column from the first span if there is one, or
5957           ;; fallback to the line/column information from the primary span of
5958           ;; the diagnostic.
5959           (or (cdr (assq 'line_start (car .spans)))
5960               primary-line)
5961           (or (cdr (assq 'column_start (car .spans)))
5962               primary-column)
5963           'info
5964           ;; Messages from `cargo clippy' may suggest replacement code.  In
5965           ;; these cases, the `message' field itself is an unhelpful `try' or
5966           ;; `change this to'.  We add the `suggested_replacement' field in
5967           ;; these cases.
5968           (-if-let (replacement
5969                     (cdr (assq 'suggested_replacement (car .spans))))
5970               (format "%s: `%s`" .message replacement)
5971             .message)
5972           :id error-code
5973           :checker checker
5974           :buffer buffer
5975           :filename primary-filename
5976           :group group)
5977          errors)))
5978
5979     ;; If there are no spans, the error is not associated with a specific
5980     ;; file but with the project as a whole.  We still need to report it to
5981     ;; the user by emitting a corresponding flycheck-error object.
5982     (unless spans
5983       (push (flycheck-error-new-at
5984              ;; We have no specific position to attach the error to, so
5985              ;; let's use the top of the file.
5986              1 1
5987              error-level
5988              error-message
5989              :id error-code
5990              :checker checker
5991              :buffer buffer
5992              :group group)
5993             errors))
5994     (nreverse errors)))
5995
5996 (defun flycheck-parse-json (output)
5997   "Return parsed JSON data from OUTPUT.
5998
5999 OUTPUT is a string that contains JSON data.  Each line of OUTPUT
6000 may be either plain text, a JSON array (starting with `['), or a
6001 JSON object (starting with `{').
6002
6003 This function ignores the plain text lines, parses the JSON
6004 lines, and returns the parsed JSON lines in a list."
6005   (let ((objects nil)
6006         (json-array-type 'list)
6007         (json-false nil))
6008     (with-temp-buffer
6009       (insert output)
6010       (goto-char (point-min))
6011       (while (not (eobp))
6012         (when (memq (char-after) '(?\{ ?\[))
6013           (push (json-read) objects))
6014         (forward-line)))
6015     (nreverse objects)))
6016
6017 (defun flycheck-parse-rustc (output checker buffer)
6018   "Parse rustc errors from OUTPUT and return a list of `flycheck-error'.
6019
6020 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
6021 the BUFFER that was checked respectively.
6022
6023 The expected format for OUTPUT is a mix of plain text lines and
6024 JSON lines.  This function ignores the plain text lines and
6025 parses only JSON lines.  Each JSON line is expected to be a JSON
6026 object that corresponds to a diagnostic from the compiler.  The
6027 expected diagnostic format is described there:
6028
6029 https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139"
6030   (seq-mapcat (lambda (msg)
6031                 (flycheck-parse-rustc-diagnostic msg checker buffer))
6032               (flycheck-parse-json output)))
6033
6034 (defun flycheck-parse-cargo-rustc (output checker buffer)
6035   "Parse Cargo errors from OUTPUT and return a list of `flycheck-error'.
6036
6037 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
6038 the BUFFER that was checked respectively.
6039
6040 The expected format for OUTPUT is a mix of plain text lines and
6041 JSON lines.  This function ignores the plain text lines and
6042 parses only JSON lines.  Each JSON line is expected to be a JSON
6043 object that represents a message from Cargo.  The format of
6044 messages emitted by Cargo is described in cargo's
6045 machine_message.rs at URL `https://git.io/vh24R'."
6046   (let ((errors))
6047     (dolist (msg (flycheck-parse-json output))
6048       (let-alist msg
6049         ;; Errors and warnings from rustc are wrapped by cargo, so we filter and
6050         ;; unwrap them, and delegate the actual construction of `flycheck-error'
6051         ;; objects to `flycheck-parse-rustc-diagnostic'.
6052         (when (string= .reason "compiler-message")
6053           (push (flycheck-parse-rustc-diagnostic .message checker buffer)
6054                 errors))))
6055     (apply #'nconc errors)))
6056
6057
6058 ;;; Error parsing with regular expressions
6059 (defun flycheck-get-regexp (patterns)
6060   "Create a single regular expression from PATTERNS."
6061   (rx-to-string `(or ,@(seq-map (lambda (p) (list 'regexp (car p))) patterns))
6062                 'no-group))
6063
6064 (defun flycheck-tokenize-output-with-patterns (output patterns)
6065   "Tokenize OUTPUT with PATTERNS.
6066
6067 Split the output into error tokens, using all regular expressions
6068 from the error PATTERNS.  An error token is simply a string
6069 containing a single error from OUTPUT.  Such a token can then be
6070 parsed into a structured error by applying the PATTERNS again,
6071 see `flycheck-parse-errors-with-patterns'.
6072
6073 Return a list of error tokens."
6074   (let ((regexp (flycheck-get-regexp patterns))
6075         (last-match 0)
6076         errors)
6077     (while (string-match regexp output last-match)
6078       (push (match-string 0 output) errors)
6079       (setq last-match (match-end 0)))
6080     (reverse errors)))
6081
6082 (defun flycheck-try-parse-error-with-pattern (err pattern checker)
6083   "Try to parse a single ERR with a PATTERN for CHECKER.
6084
6085 Return the parsed error if PATTERN matched ERR, or nil
6086 otherwise."
6087   (let ((regexp (car pattern))
6088         (level (cdr pattern)))
6089     (when (string-match regexp err)
6090       (let ((filename (match-string 1 err))
6091             (line (match-string 2 err))
6092             (column (match-string 3 err))
6093             (message (match-string 4 err))
6094             (id (match-string 5 err)))
6095         (flycheck-error-new-at
6096          (flycheck-string-to-number-safe line)
6097          (flycheck-string-to-number-safe column)
6098          level
6099          (unless (string-empty-p message) message)
6100          :id (unless (string-empty-p id) id)
6101          :checker checker
6102          :filename (if (or (null filename) (string-empty-p filename))
6103                        (buffer-file-name)
6104                      filename))))))
6105
6106 (defun flycheck-parse-error-with-patterns (err patterns checker)
6107   "Parse a single ERR with error PATTERNS for CHECKER.
6108
6109 Apply each pattern in PATTERNS to ERR, in the given order, and
6110 return the first parsed error."
6111   ;; Try to parse patterns in the order of declaration to make sure that the
6112   ;; first match wins.
6113   (let (parsed-error)
6114     (while (and patterns
6115                 (not (setq parsed-error
6116                            (flycheck-try-parse-error-with-pattern
6117                             err (car patterns) checker))))
6118       (setq patterns (cdr patterns)))
6119     parsed-error))
6120
6121 (defun flycheck-parse-with-patterns (output checker buffer)
6122   "Parse OUTPUT from CHECKER with error patterns.
6123
6124 Uses the error patterns of CHECKER to tokenize the output and
6125 tries to parse each error token with all patterns, in the order
6126 of declaration.  Hence an error is never matched twice by two
6127 different patterns.  The pattern declared first always wins.
6128
6129 _BUFFER is ignored.
6130
6131 Return a list of parsed errors and warnings (as `flycheck-error'
6132 objects)."
6133   (with-current-buffer buffer
6134     (let ((patterns (flycheck-checker-get checker 'error-patterns)))
6135       (seq-map (lambda (err)
6136                  (flycheck-parse-error-with-patterns err patterns checker))
6137                (flycheck-tokenize-output-with-patterns output patterns)))))
6138
6139
6140 ;;; Convenience definition of command-syntax checkers
6141 (defmacro flycheck-define-checker (symbol docstring &rest properties)
6142   "Define SYMBOL as command syntax checker with DOCSTRING and PROPERTIES.
6143
6144 Like `flycheck-define-command-checker', but PROPERTIES must not
6145 be quoted.  Also, implicitly define the executable variable for
6146 SYMBOL with `flycheck-def-executable-var'."
6147   (declare (indent 1)
6148            (doc-string 2))
6149   (let ((command (plist-get properties :command))
6150         (parser (plist-get properties :error-parser))
6151         (filter (plist-get properties :error-filter))
6152         (explainer (plist-get properties :error-explainer))
6153         (predicate (plist-get properties :predicate))
6154         (enabled-fn (plist-get properties :enabled))
6155         (verify-fn (plist-get properties :verify)))
6156
6157     `(progn
6158        (flycheck-def-executable-var ,symbol ,(car command))
6159
6160        (flycheck-define-command-checker ',symbol
6161          ,docstring
6162          :command ',command
6163          ,@(when parser
6164              `(:error-parser #',parser))
6165          :error-patterns ',(plist-get properties :error-patterns)
6166          ,@(when filter
6167              `(:error-filter #',filter))
6168          ,@(when explainer
6169              `(:error-explainer #',explainer))
6170          :modes ',(plist-get properties :modes)
6171          ,@(when predicate
6172              `(:predicate #',predicate))
6173          :next-checkers ',(plist-get properties :next-checkers)
6174          ,@(when enabled-fn
6175              `(:enabled #',enabled-fn))
6176          ,@(when verify-fn
6177              `(:verify #',verify-fn))
6178          :standard-input ',(plist-get properties :standard-input)
6179          :working-directory ',(plist-get properties :working-directory)))))
6180
6181
6182 ;;; Built-in checkers
6183 (flycheck-def-args-var flycheck-gnat-args ada-gnat
6184   :package-version '(flycheck . "0.20"))
6185
6186 (flycheck-def-option-var flycheck-gnat-include-path nil ada-gnat
6187   "A list of include directories for GNAT.
6188
6189 The value of this variable is a list of strings, where each
6190 string is a directory to add to the include path of gcc.
6191 Relative paths are relative to the file being checked."
6192   :type '(repeat (directory :tag "Include directory"))
6193   :safe #'flycheck-string-list-p
6194   :package-version '(flycheck . "0.20"))
6195
6196 (flycheck-def-option-var flycheck-gnat-language-standard "2012" ada-gnat
6197   "The language standard to use in GNAT.
6198
6199 The value of this variable is either a string denoting a language
6200 standard, or nil, to use the default standard. When non-nil, pass
6201 the language standard via the `-std' option."
6202   :type '(choice (const :tag "Default standard" nil)
6203                  (string :tag "Language standard"))
6204   :safe #'stringp
6205   :package-version '(flycheck . "0.20"))
6206
6207 (flycheck-def-option-var flycheck-gnat-warnings
6208     '("wa") ada-gnat
6209   "A list of additional Ada warnings to enable in GNAT.
6210
6211 The value of this variable is a list of strings, where each
6212 string is the name of a warning category to enable. By default,
6213 most optional warnings are recommended, as in `-gnata'.
6214
6215 Refer to Info Node `(gnat_ugn_unw)Warning Message Control' for
6216 more information about GNAT warnings."
6217   :type '(repeat :tag "Warnings" (string :tag "Warning name"))
6218   :safe #'flycheck-string-list-p
6219   :package-version '(flycheck . "0.20"))
6220
6221 (flycheck-define-checker ada-gnat
6222   "An Ada syntax checker using GNAT.
6223
6224 Uses the GNAT compiler from GCC.  See URL
6225 `https://www.adacore.com/community/'."
6226   :command ("gnatmake"
6227             "-c"                        ; Just compile, don't bind
6228             "-f"                        ; Force re-compilation
6229             "-u"                        ; Compile the main file only
6230             "-gnatf"                    ; Full error information
6231             "-gnatef"                   ; Full source file name
6232             "-D" temporary-directory
6233             (option-list "-gnat" flycheck-gnat-warnings concat)
6234             (option-list "-I" flycheck-gnat-include-path concat)
6235             (option "-gnat" flycheck-gnat-language-standard concat)
6236             (eval flycheck-gnat-args)
6237             source)
6238   :error-patterns
6239   ((error line-start
6240           (message "In file included from") " " (file-name) ":" line ":"
6241           column ":"
6242           line-end)
6243    (info line-start (file-name) ":" line ":" column
6244          ": note: " (message) line-end)
6245    (warning line-start (file-name) ":" line ":" column
6246             ": warning: " (message) line-end)
6247    ;; no specific error prefix in Ada
6248    (error line-start (file-name) ":" line ":" column
6249           ": " (message) line-end))
6250   :modes ada-mode)
6251
6252 (flycheck-define-checker asciidoc
6253   "A AsciiDoc syntax checker using the AsciiDoc compiler.
6254
6255 See URL `http://www.methods.co.nz/asciidoc'."
6256   :command ("asciidoc" "-o" null-device "-")
6257   :standard-input t
6258   :error-patterns
6259   ((error line-start
6260           "asciidoc: ERROR: <stdin>: Line " line ": " (message)
6261           line-end)
6262    (warning line-start
6263             "asciidoc: WARNING: <stdin>: Line " line ": " (message)
6264             line-end)
6265    (info line-start
6266          "asciidoc: DEPRECATED: <stdin>: Line " line ": " (message)
6267          line-end))
6268   :modes adoc-mode)
6269
6270 (flycheck-define-checker asciidoctor
6271   "An AsciiDoc syntax checker using the Asciidoctor compiler.
6272
6273 See URL `http://asciidoctor.org'."
6274   :command ("asciidoctor" "-o" null-device "-")
6275   :standard-input t
6276   :error-patterns
6277   ((error line-start
6278           "asciidoctor: ERROR: <stdin>: Line " line ": " (message)
6279           line-end)
6280    (warning line-start
6281             "asciidoctor: WARNING: <stdin>: Line " line ": " (message)
6282             line-end))
6283   :modes adoc-mode)
6284
6285 (flycheck-def-args-var flycheck-clang-args c/c++-clang
6286   :package-version '(flycheck . "0.22"))
6287
6288 (flycheck-def-option-var flycheck-clang-blocks nil c/c++-clang
6289   "Enable blocks in Clang.
6290
6291 When non-nil, enable blocks in Clang with `-fblocks'.  See URL
6292 `http://clang.llvm.org/docs/BlockLanguageSpec.html' for more
6293 information about blocks."
6294   :type 'boolean
6295   :safe #'booleanp
6296   :package-version '(flycheck . "0.20"))
6297
6298 (flycheck-def-option-var flycheck-clang-definitions nil c/c++-clang
6299   "Additional preprocessor definitions for Clang.
6300
6301 The value of this variable is a list of strings, where each
6302 string is an additional definition to pass to Clang, via the `-D'
6303 option."
6304   :type '(repeat (string :tag "Definition"))
6305   :safe #'flycheck-string-list-p
6306   :package-version '(flycheck . "0.15"))
6307
6308 (flycheck-def-option-var flycheck-clang-include-path nil c/c++-clang
6309   "A list of include directories for Clang.
6310
6311 The value of this variable is a list of strings, where each
6312 string is a directory to add to the include path of Clang.
6313 Relative paths are relative to the file being checked."
6314   :type '(repeat (directory :tag "Include directory"))
6315   :safe #'flycheck-string-list-p
6316   :package-version '(flycheck . "0.14"))
6317
6318 (flycheck-def-option-var flycheck-clang-includes nil c/c++-clang
6319   "A list of additional include files for Clang.
6320
6321 The value of this variable is a list of strings, where each
6322 string is a file to include before syntax checking.  Relative
6323 paths are relative to the file being checked."
6324   :type '(repeat (file :tag "Include file"))
6325   :safe #'flycheck-string-list-p
6326   :package-version '(flycheck . "0.15"))
6327
6328 (flycheck-def-option-var flycheck-clang-language-standard nil c/c++-clang
6329   "The language standard to use in Clang.
6330
6331 The value of this variable is either a string denoting a language
6332 standard, or nil, to use the default standard.  When non-nil,
6333 pass the language standard via the `-std' option."
6334   :type '(choice (const :tag "Default standard" nil)
6335                  (string :tag "Language standard"))
6336   :safe #'stringp
6337   :package-version '(flycheck . "0.15"))
6338 (make-variable-buffer-local 'flycheck-clang-language-standard)
6339
6340 (flycheck-def-option-var flycheck-clang-ms-extensions nil c/c++-clang
6341   "Whether to enable Microsoft extensions to C/C++ in Clang.
6342
6343 When non-nil, enable Microsoft extensions to C/C++ via
6344 `-fms-extensions'."
6345   :type 'boolean
6346   :safe #'booleanp
6347   :package-version '(flycheck . "0.16"))
6348
6349 (flycheck-def-option-var flycheck-clang-no-exceptions nil c/c++-clang
6350   "Whether to disable exceptions in Clang.
6351
6352 When non-nil, disable exceptions for syntax checks, via
6353 `-fno-exceptions'."
6354   :type 'boolean
6355   :safe #'booleanp
6356   :package-version '(flycheck . "0.20"))
6357
6358 (flycheck-def-option-var flycheck-clang-no-rtti nil c/c++-clang
6359   "Whether to disable RTTI in Clang.
6360
6361 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
6362   :type 'boolean
6363   :safe #'booleanp
6364   :package-version '(flycheck . "0.15"))
6365
6366 (flycheck-def-option-var flycheck-clang-pedantic nil c/c++-clang
6367   "Whether to warn about language extensions in Clang.
6368
6369 For ISO C, follows the version specified by any -std option used.
6370 When non-nil, disable non-ISO extensions to C/C++ via
6371 `-pedantic'."
6372   :type 'boolean
6373   :safe #'booleanp
6374   :package-version '(flycheck . "0.23"))
6375
6376 (flycheck-def-option-var flycheck-clang-pedantic-errors nil c/c++-clang
6377   "Whether to error on language extensions in Clang.
6378
6379 For ISO C, follows the version specified by any -std option used.
6380 When non-nil, disable non-ISO extensions to C/C++ via
6381 `-pedantic-errors'."
6382   :type 'boolean
6383   :safe #'booleanp
6384   :package-version '(flycheck . "0.23"))
6385
6386 (flycheck-def-option-var flycheck-clang-standard-library nil c/c++-clang
6387   "The standard library to use for Clang.
6388
6389 The value of this variable is the name of a standard library as
6390 string, or nil to use the default standard library.
6391
6392 Refer to the Clang manual at URL
6393 `http://clang.llvm.org/docs/UsersManual.html' for more
6394 information about the standard library."
6395   :type '(choice (const "libc++")
6396                  (const :tag "GNU libstdc++" "libstdc++")
6397                  (string :tag "Library name"))
6398   :safe #'stringp
6399   :package-version '(flycheck . "0.15"))
6400
6401 (flycheck-def-option-var flycheck-clang-warnings '("all" "extra") c/c++-clang
6402   "A list of additional warnings to enable in Clang.
6403
6404 The value of this variable is a list of strings, where each string
6405 is the name of a warning category to enable.  By default, all
6406 recommended warnings and some extra warnings are enabled (as by
6407 `-Wall' and `-Wextra' respectively).
6408
6409 Refer to the Clang manual at URL
6410 `http://clang.llvm.org/docs/UsersManual.html' for more
6411 information about warnings."
6412   :type '(choice (const :tag "No additional warnings" nil)
6413                  (repeat :tag "Additional warnings"
6414                          (string :tag "Warning name")))
6415   :safe #'flycheck-string-list-p
6416   :package-version '(flycheck . "0.14"))
6417
6418 (defun flycheck-c/c++-quoted-include-directory ()
6419   "Get the directory for quoted includes.
6420
6421 C/C++ compiles typicall look up includes with quotation marks in
6422 the directory of the file being compiled.  However, since
6423 Flycheck uses temporary copies for syntax checking, it needs to
6424 explicitly determine the directory for quoted includes.
6425
6426 This function determines the directory by looking at function
6427 `buffer-file-name', or if that is nil, at `default-directory'."
6428   (-if-let (fn (buffer-file-name))
6429       (file-name-directory fn)
6430     ;; If the buffer has no file name, fall back to its default directory
6431     default-directory))
6432
6433 (flycheck-define-checker c/c++-clang
6434   "A C/C++ syntax checker using Clang.
6435
6436 See URL `http://clang.llvm.org/'."
6437   :command ("clang"
6438             "-fsyntax-only"
6439             "-fno-color-diagnostics"    ; Do not include color codes in output
6440             "-fno-caret-diagnostics"    ; Do not visually indicate the source
6441                                         ; location
6442             "-fno-diagnostics-show-option" ; Do not show the corresponding
6443                                         ; warning group
6444             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
6445             (option "-std=" flycheck-clang-language-standard concat)
6446             (option-flag "-pedantic" flycheck-clang-pedantic)
6447             (option-flag "-pedantic-errors" flycheck-clang-pedantic-errors)
6448             (option "-stdlib=" flycheck-clang-standard-library concat)
6449             (option-flag "-fms-extensions" flycheck-clang-ms-extensions)
6450             (option-flag "-fno-exceptions" flycheck-clang-no-exceptions)
6451             (option-flag "-fno-rtti" flycheck-clang-no-rtti)
6452             (option-flag "-fblocks" flycheck-clang-blocks)
6453             (option-list "-include" flycheck-clang-includes)
6454             (option-list "-W" flycheck-clang-warnings concat)
6455             (option-list "-D" flycheck-clang-definitions concat)
6456             (option-list "-I" flycheck-clang-include-path)
6457             (eval flycheck-clang-args)
6458             "-x" (eval
6459                   (pcase major-mode
6460                     (`c++-mode "c++")
6461                     (`c-mode "c")))
6462             ;; Read from standard input
6463             "-")
6464   :standard-input t
6465   :error-patterns
6466   ((error line-start
6467           (message "In file included from") " " (or "<stdin>" (file-name))
6468           ":" line ":" line-end)
6469    (info line-start (or "<stdin>" (file-name)) ":" line ":" column
6470          ": note: " (optional (message)) line-end)
6471    (warning line-start (or "<stdin>" (file-name)) ":" line ":" column
6472             ": warning: " (optional (message)) line-end)
6473    (error line-start (or "<stdin>" (file-name)) ":" line ":" column
6474           ": " (or "fatal error" "error") ": " (optional (message)) line-end))
6475   :error-filter
6476   (lambda (errors)
6477     (let ((errors (flycheck-sanitize-errors errors)))
6478       (dolist (err errors)
6479         ;; Clang will output empty messages for #error/#warning pragmas without
6480         ;; messages.  We fill these empty errors with a dummy message to get
6481         ;; them past our error filtering
6482         (setf (flycheck-error-message err)
6483               (or (flycheck-error-message err) "no message")))
6484       (flycheck-fold-include-levels errors "In file included from")))
6485   :modes (c-mode c++-mode)
6486   :next-checkers ((warning . c/c++-cppcheck)))
6487
6488 (flycheck-def-args-var flycheck-gcc-args c/c++-gcc
6489   :package-version '(flycheck . "0.22"))
6490
6491 (flycheck-def-option-var flycheck-gcc-definitions nil c/c++-gcc
6492   "Additional preprocessor definitions for GCC.
6493
6494 The value of this variable is a list of strings, where each
6495 string is an additional definition to pass to GCC, via the `-D'
6496 option."
6497   :type '(repeat (string :tag "Definition"))
6498   :safe #'flycheck-string-list-p
6499   :package-version '(flycheck . "0.20"))
6500
6501 (flycheck-def-option-var flycheck-gcc-include-path nil c/c++-gcc
6502   "A list of include directories for GCC.
6503
6504 The value of this variable is a list of strings, where each
6505 string is a directory to add to the include path of gcc.
6506 Relative paths are relative to the file being checked."
6507   :type '(repeat (directory :tag "Include directory"))
6508   :safe #'flycheck-string-list-p
6509   :package-version '(flycheck . "0.20"))
6510
6511 (flycheck-def-option-var flycheck-gcc-includes nil c/c++-gcc
6512   "A list of additional include files for GCC.
6513
6514 The value of this variable is a list of strings, where each
6515 string is a file to include before syntax checking.  Relative
6516 paths are relative to the file being checked."
6517   :type '(repeat (file :tag "Include file"))
6518   :safe #'flycheck-string-list-p
6519   :package-version '(flycheck . "0.20"))
6520
6521 (flycheck-def-option-var flycheck-gcc-language-standard nil c/c++-gcc
6522   "The language standard to use in GCC.
6523
6524 The value of this variable is either a string denoting a language
6525 standard, or nil, to use the default standard.  When non-nil,
6526 pass the language standard via the `-std' option."
6527   :type '(choice (const :tag "Default standard" nil)
6528                  (string :tag "Language standard"))
6529   :safe #'stringp
6530   :package-version '(flycheck . "0.20"))
6531 (make-variable-buffer-local 'flycheck-gcc-language-standard)
6532
6533 (flycheck-def-option-var flycheck-gcc-no-exceptions nil c/c++-gcc
6534   "Whether to disable exceptions in GCC.
6535
6536 When non-nil, disable exceptions for syntax checks, via
6537 `-fno-exceptions'."
6538   :type 'boolean
6539   :safe #'booleanp
6540   :package-version '(flycheck . "0.20"))
6541
6542 (flycheck-def-option-var flycheck-gcc-no-rtti nil c/c++-gcc
6543   "Whether to disable RTTI in GCC.
6544
6545 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
6546   :type 'boolean
6547   :safe #'booleanp
6548   :package-version '(flycheck . "0.20"))
6549
6550 (flycheck-def-option-var flycheck-gcc-openmp nil c/c++-gcc
6551   "Whether to enable OpenMP in GCC.
6552
6553 When non-nil, enable OpenMP for syntax checkers, via
6554 `-fopenmp'."
6555   :type 'boolean
6556   :safe #'booleanp
6557   :package-version '(flycheck . "0.21"))
6558
6559 (flycheck-def-option-var flycheck-gcc-pedantic nil c/c++-gcc
6560   "Whether to warn about language extensions in GCC.
6561
6562 For ISO C, follows the version specified by any -std option used.
6563 When non-nil, disable non-ISO extensions to C/C++ via
6564 `-pedantic'."
6565   :type 'boolean
6566   :safe #'booleanp
6567   :package-version '(flycheck . "0.23"))
6568
6569 (flycheck-def-option-var flycheck-gcc-pedantic-errors nil c/c++-gcc
6570   "Whether to error on language extensions in GCC.
6571
6572 For ISO C, follows the version specified by any -std option used.
6573 When non-nil, disable non-ISO extensions to C/C++ via
6574 `-pedantic-errors'."
6575   :type 'boolean
6576   :safe #'booleanp
6577   :package-version '(flycheck . "0.23"))
6578
6579 (flycheck-def-option-var flycheck-gcc-warnings '("all" "extra") c/c++-gcc
6580   "A list of additional warnings to enable in GCC.
6581
6582 The value of this variable is a list of strings, where each string
6583 is the name of a warning category to enable.  By default, all
6584 recommended warnings and some extra warnings are enabled (as by
6585 `-Wall' and `-Wextra' respectively).
6586
6587 Refer to the gcc manual at URL
6588 `https://gcc.gnu.org/onlinedocs/gcc/' for more information about
6589 warnings."
6590   :type '(choice (const :tag "No additional warnings" nil)
6591                  (repeat :tag "Additional warnings"
6592                          (string :tag "Warning name")))
6593   :safe #'flycheck-string-list-p
6594   :package-version '(flycheck . "0.20"))
6595
6596 (flycheck-define-checker c/c++-gcc
6597   "A C/C++ syntax checker using GCC.
6598
6599 Requires GCC 4.4 or newer.  See URL `https://gcc.gnu.org/'."
6600   :command ("gcc"
6601             "-fshow-column"
6602             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
6603             (option "-std=" flycheck-gcc-language-standard concat)
6604             (option-flag "-pedantic" flycheck-gcc-pedantic)
6605             (option-flag "-pedantic-errors" flycheck-gcc-pedantic-errors)
6606             (option-flag "-fno-exceptions" flycheck-gcc-no-exceptions)
6607             (option-flag "-fno-rtti" flycheck-gcc-no-rtti)
6608             (option-flag "-fopenmp" flycheck-gcc-openmp)
6609             (option-list "-include" flycheck-gcc-includes)
6610             (option-list "-W" flycheck-gcc-warnings concat)
6611             (option-list "-D" flycheck-gcc-definitions concat)
6612             (option-list "-I" flycheck-gcc-include-path)
6613             (eval flycheck-gcc-args)
6614             "-x" (eval
6615                   (pcase major-mode
6616                     (`c++-mode "c++")
6617                     (`c-mode "c")))
6618             ;; GCC performs full checking only when actually compiling, so
6619             ;; `-fsyntax-only' is not enough. Just let it generate assembly
6620             ;; code.
6621             "-S" "-o" null-device
6622             ;; Read from standard input
6623             "-")
6624   :standard-input t
6625   :error-patterns
6626   ((error line-start
6627           (message "In file included from") " " (or "<stdin>" (file-name))
6628           ":" line ":" column ":" line-end)
6629    (info line-start (or "<stdin>" (file-name)) ":" line ":" column
6630          ": note: " (message) line-end)
6631    (warning line-start (or "<stdin>" (file-name)) ":" line ":" column
6632             ": warning: " (message (one-or-more (not (any "\n["))))
6633             (optional "[" (id (one-or-more not-newline)) "]") line-end)
6634    (error line-start (or "<stdin>" (file-name)) ":" line ":" column
6635           ": " (or "fatal error" "error") ": " (message) line-end))
6636   :error-filter
6637   (lambda (errors)
6638     (flycheck-fold-include-levels (flycheck-sanitize-errors errors)
6639                                   "In file included from"))
6640   :modes (c-mode c++-mode)
6641   :next-checkers ((warning . c/c++-cppcheck)))
6642
6643 (flycheck-def-option-var flycheck-cppcheck-checks '("style") c/c++-cppcheck
6644   "Enabled checks for Cppcheck.
6645
6646 The value of this variable is a list of strings, where each
6647 string is the name of an additional check to enable.  By default,
6648 all coding style checks are enabled.
6649
6650 See section \"Enable message\" in the Cppcheck manual at URL
6651 `http://cppcheck.sourceforge.net/manual.pdf', and the
6652 documentation of the `--enable' option for more information,
6653 including a list of supported checks."
6654   :type '(repeat :tag "Additional checks"
6655                  (string :tag "Check name"))
6656   :safe #'flycheck-string-list-p
6657   :package-version '(flycheck . "0.14"))
6658
6659 (flycheck-def-option-var flycheck-cppcheck-standards nil c/c++-cppcheck
6660   "The standards to use in cppcheck.
6661
6662 The value of this variable is either a list of strings denoting
6663 the standards to use, or nil to pass nothing to cppcheck.  When
6664 non-nil, pass the standards via one or more `--std=' options."
6665   :type '(choice (const :tag "Default" nil)
6666                  (repeat :tag "Custom standards"
6667                          (string :tag "Standard name")))
6668   :safe #'flycheck-string-list-p
6669   :package-version '(flycheck . "28"))
6670 (make-variable-buffer-local 'flycheck-cppcheck-standards)
6671
6672 (flycheck-def-option-var flycheck-cppcheck-suppressions-file nil c/c++-cppcheck
6673   "The suppressions file to use in cppcheck.
6674
6675 The value of this variable is a file with the suppressions to
6676 use, or nil to pass nothing to cppcheck.  When non-nil, pass the
6677 suppressions file via the `--suppressions-list=' option."
6678   :type '(choice (const :tag "Default" nil)
6679                  (file :tag "Suppressions file"))
6680   :safe #'stringp
6681   :package-version '(flycheck . "32"))
6682 (make-variable-buffer-local 'flycheck-cppcheck-suppressions-file)
6683
6684 (flycheck-def-option-var flycheck-cppcheck-suppressions nil c/c++-cppcheck
6685   "The suppressions to use in cppcheck.
6686
6687 The value of this variable is either a list of strings denoting
6688 the suppressions to use, or nil to pass nothing to cppcheck.
6689 When non-nil, pass the suppressions via one or more `--suppress='
6690 options."
6691   :type '(choice (const :tag "Default" nil)
6692                  (repeat :tag "Additional suppressions"
6693                          (string :tag "Suppression")))
6694   :safe #'flycheck-string-list-p
6695   :package-version '(flycheck . "28"))
6696
6697 (flycheck-def-option-var flycheck-cppcheck-inconclusive nil c/c++-cppcheck
6698   "Whether to enable Cppcheck inconclusive checks.
6699
6700 When non-nil, enable Cppcheck inconclusive checks.  This allows Cppcheck to
6701 report warnings it's not certain of, but it may result in false positives.
6702
6703 This will have no effect when using Cppcheck 1.53 and older."
6704   :type 'boolean
6705   :safe #'booleanp
6706   :package-version '(flycheck . "0.19"))
6707
6708 (flycheck-def-option-var flycheck-cppcheck-include-path nil c/c++-cppcheck
6709   "A list of include directories for cppcheck.
6710
6711 The value of this variable is a list of strings, where each
6712 string is a directory to add to the include path of cppcheck.
6713 Relative paths are relative to the file being checked."
6714   :type '(repeat (directory :tag "Include directory"))
6715   :safe #'flycheck-string-list-p
6716   :package-version '(flycheck . "0.24"))
6717
6718 (flycheck-define-checker c/c++-cppcheck
6719   "A C/C++ checker using cppcheck.
6720
6721 See URL `http://cppcheck.sourceforge.net/'."
6722   :command ("cppcheck" "--quiet" "--xml-version=2" "--inline-suppr"
6723             (option "--enable=" flycheck-cppcheck-checks concat
6724                     flycheck-option-comma-separated-list)
6725             (option-flag "--inconclusive" flycheck-cppcheck-inconclusive)
6726             (option-list "-I" flycheck-cppcheck-include-path)
6727             (option-list "--std=" flycheck-cppcheck-standards concat)
6728             (option-list "--suppress=" flycheck-cppcheck-suppressions concat)
6729             (option "--suppressions-list="
6730                     flycheck-cppcheck-suppressions-file concat)
6731             "-x" (eval
6732                   (pcase major-mode
6733                     (`c++-mode "c++")
6734                     (`c-mode "c")))
6735             source)
6736   :error-parser flycheck-parse-cppcheck
6737   :modes (c-mode c++-mode))
6738
6739 (flycheck-define-checker cfengine
6740   "A CFEngine syntax checker using cf-promises.
6741
6742 See URL `https://cfengine.com/'."
6743   :command ("cf-promises" "-Wall" "-f"
6744             ;; We must stay in the same directory to resolve @include
6745             source-inplace)
6746   :error-patterns
6747   ((warning line-start (file-name) ":" line ":" column
6748             ": warning: " (message) line-end)
6749    (error line-start (file-name) ":" line ":" column
6750           ": error: " (message) line-end))
6751   :modes (cfengine-mode cfengine3-mode))
6752
6753 (flycheck-def-option-var flycheck-foodcritic-tags nil chef-foodcritic
6754   "A list of tags to select for Foodcritic.
6755
6756 The value of this variable is a list of strings where each string
6757 is a tag expression describing Foodcritic rules to enable or
6758 disable, via the `--tags' option.  To disable a tag, prefix it
6759 with `~'."
6760   :type '(repeat :tag "Tags" (string :tag "Tag expression"))
6761   :safe #'flycheck-string-list-p
6762   :package-version '(flycheck . "0.23"))
6763
6764 (flycheck-define-checker chef-foodcritic
6765   "A Chef cookbooks syntax checker using Foodcritic.
6766
6767 See URL `http://www.foodcritic.io'."
6768   ;; Use `source-inplace' to allow resource discovery with relative paths.
6769   ;; foodcritic interprets these as relative to the source file, so we need to
6770   ;; stay within the source tree.  See
6771   ;; https://github.com/flycheck/flycheck/pull/556
6772   :command ("foodcritic"
6773             (option-list "--tags" flycheck-foodcritic-tags)
6774             source-inplace)
6775   :error-patterns
6776   ((error line-start (id (one-or-more alnum)) ": "
6777           (message) ": " (file-name) ":" line line-end))
6778   :modes (enh-ruby-mode ruby-mode)
6779   :predicate
6780   (lambda ()
6781     (let ((parent-dir (file-name-directory
6782                        (directory-file-name
6783                         (expand-file-name default-directory)))))
6784       (or
6785        ;; Chef CookBook
6786        ;; http://docs.opscode.com/chef/knife.html#id38
6787        (locate-dominating-file parent-dir "recipes")
6788        ;; Knife Solo
6789        ;; http://matschaffer.github.io/knife-solo/#label-Init+command
6790        (locate-dominating-file parent-dir "cookbooks")))))
6791
6792 (flycheck-define-checker coffee
6793   "A CoffeeScript syntax checker using coffee.
6794
6795 See URL `https://coffeescript.org/'."
6796   ;; --print suppresses generation of compiled .js files
6797   :command ("coffee" "--compile" "--print" "--stdio")
6798   :standard-input t
6799   :error-patterns
6800   ((error line-start "[stdin]:" line ":" column
6801           ": error: " (message) line-end))
6802   :modes coffee-mode
6803   :next-checkers ((warning . coffee-coffeelint)))
6804
6805 (flycheck-def-config-file-var flycheck-coffeelintrc coffee-coffeelint
6806                               ".coffeelint.json"
6807   :safe #'stringp)
6808
6809 (flycheck-define-checker coffee-coffeelint
6810   "A CoffeeScript style checker using coffeelint.
6811
6812 See URL `http://www.coffeelint.org/'."
6813   :command
6814   ("coffeelint"
6815    (config-file "--file" flycheck-coffeelintrc)
6816    "--stdin" "--reporter" "checkstyle")
6817   :standard-input t
6818   :error-parser flycheck-parse-checkstyle
6819   :error-filter (lambda (errors)
6820                   (flycheck-remove-error-file-names
6821                    "stdin" (flycheck-remove-error-ids
6822                             (flycheck-sanitize-errors errors))))
6823   :modes coffee-mode)
6824
6825 (flycheck-define-checker coq
6826   "A Coq syntax checker using the Coq compiler.
6827
6828 See URL `https://coq.inria.fr/'."
6829   ;; We use coqtop in batch mode, because coqc is picky about file names.
6830   :command ("coqtop" "-batch" "-load-vernac-source" source)
6831   :error-patterns
6832   ((error line-start "File \"" (file-name) "\", line " line
6833           ;; TODO: Parse the end column, once Flycheck supports that
6834           ", characters " column "-" (one-or-more digit) ":\n"
6835           (or "Syntax error:" "Error:")
6836           ;; Most Coq error messages span multiple lines, and end with a dot.
6837           ;; There are simple one-line messages, too, though.
6838           (message (or (and (one-or-more (or not-newline "\n")) ".")
6839                        (one-or-more not-newline)))
6840           line-end))
6841   :error-filter
6842   (lambda (errors)
6843     (dolist (err (flycheck-sanitize-errors errors))
6844       (setf (flycheck-error-message err)
6845             (replace-regexp-in-string (rx (1+ (syntax whitespace)) line-end)
6846                                       "" (flycheck-error-message err)
6847                                       'fixedcase 'literal)))
6848     (flycheck-increment-error-columns errors))
6849   :modes coq-mode)
6850
6851 (flycheck-define-checker css-csslint
6852   "A CSS syntax and style checker using csslint.
6853
6854 See URL `https://github.com/CSSLint/csslint'."
6855   :command ("csslint" "--format=checkstyle-xml" source)
6856   :error-parser flycheck-parse-checkstyle
6857   :error-filter flycheck-dequalify-error-ids
6858   :modes css-mode)
6859
6860 (defconst flycheck-stylelint-args '("--formatter" "json")
6861   "Common arguments to stylelint invocations.")
6862
6863 (flycheck-def-config-file-var flycheck-stylelintrc
6864     (css-stylelint scss-stylelint less-stylelint) nil
6865   :safe #'stringp)
6866
6867 (flycheck-def-option-var flycheck-stylelint-quiet
6868     nil (css-stylelint scss-stylelint less-stylelint)
6869   "Whether to run stylelint in quiet mode.
6870
6871 When non-nil, enable quiet mode, via `--quiet'."
6872   :type 'boolean
6873   :safe #'booleanp
6874   :package-version '(flycheck . 26))
6875
6876 (defconst flycheck-stylelint-error-re
6877   (flycheck-rx-to-string
6878    '(: line-start (id (one-or-more word)) ": " (message) line-end)))
6879
6880 (defun flycheck-parse-stylelint (output checker buffer)
6881   "Parse stylelint errors from OUTPUT.
6882
6883 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
6884 the BUFFER that was checked respectively.
6885
6886 The CHECKER usually returns the errors as JSON.
6887
6888 If the CHECKER throws an Error it returns an Error message with a stacktrace."
6889   (condition-case nil
6890       (flycheck-parse-stylelint-json output checker buffer)
6891
6892     ;; The output could not be parsed as JSON
6893     (json-error
6894
6895      ;; Extract a flycheck error from the output (with a regular expression)
6896      ;; For match-string 4/5 see flycheck-rx-message/flycheck-rx-id
6897      (when (string-match flycheck-stylelint-error-re output)
6898        (list (flycheck-error-new-at
6899               1 nil 'error
6900               (match-string 4 output)
6901               :id (match-string 5 output)
6902               :checker checker
6903               :buffer buffer
6904               :filename (buffer-file-name buffer)))))))
6905
6906 (defun flycheck-parse-stylelint-json (output checker buffer)
6907   "Parse stylelint JSON errors from OUTPUT.
6908
6909 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
6910 the BUFFER that was checked respectively.
6911
6912 See URL `http://stylelint.io/developer-guide/formatters/' for information
6913 about the JSON format of stylelint."
6914   (let ((json-object-type 'plist))
6915
6916     ;; stylelint returns a vector of result objects
6917     ;; Since we only passed one file, the first element is enough
6918     (let* ((stylelint-output (elt (json-read-from-string output) 0))
6919            (filename (buffer-file-name buffer))
6920
6921            ;; Turn all deprecations into warnings
6922            (deprecations
6923             (mapcar (lambda (d)
6924                       (flycheck-error-new-at
6925                        1 nil 'warning
6926                        (plist-get d :text)
6927                        :id "Deprecation Warning"
6928                        :checker checker
6929                        :buffer buffer
6930                        :filename filename))
6931                     (plist-get stylelint-output :deprecations)))
6932
6933            ;; Turn all invalid options into errors
6934            (invalid-options
6935             (mapcar (lambda (io)
6936                       (flycheck-error-new-at
6937                        1 nil 'error
6938                        (plist-get io :text)
6939                        :id "Invalid Option"
6940                        :checker checker
6941                        :buffer buffer
6942                        :filename filename))
6943                     (plist-get stylelint-output :invalidOptionWarnings)))
6944
6945            ;; Read all linting warnings
6946            (warnings
6947             (mapcar (lambda (w)
6948                       (flycheck-error-new-at
6949                        (plist-get w :line) (plist-get w :column)
6950                        (pcase (plist-get w :severity)
6951                          (`"error"   'error)
6952                          (`"warning" 'warning)
6953                          ;; Default to info for unknown .severity
6954                          (_          'info))
6955                        (plist-get w :text)
6956                        :id (plist-get w :rule)
6957                        :checker checker
6958                        :buffer buffer
6959                        :filename filename))
6960                     (plist-get stylelint-output :warnings))))
6961
6962       ;; Return the combined errors (deprecations, invalid options, warnings)
6963       (append deprecations invalid-options warnings))))
6964
6965 (flycheck-define-checker css-stylelint
6966   "A CSS syntax and style checker using stylelint.
6967
6968 See URL `http://stylelint.io/'."
6969   :command ("stylelint"
6970             (eval flycheck-stylelint-args)
6971             (option-flag "--quiet" flycheck-stylelint-quiet)
6972             (config-file "--config" flycheck-stylelintrc))
6973   :standard-input t
6974   :error-parser flycheck-parse-stylelint
6975   :modes (css-mode))
6976
6977 (flycheck-def-option-var flycheck-cwl-schema-path nil cwl
6978   "A path for the schema file for Common Workflow Language.
6979
6980 The value of this variable is a string that denotes a path for
6981 the schema file of Common Workflow Language."
6982   :type 'string
6983   :safe #'stringp)
6984
6985 (flycheck-define-checker cwl
6986   "A CWL syntax checker using Schema Salad validator.
6987
6988 Requires Schema Salad 2.6.20171101113912 or newer.
6989 See URL `https://www.commonwl.org/v1.0/SchemaSalad.html'."
6990   :command ("schema-salad-tool"
6991             "--quiet"
6992             "--print-oneline"
6993             (eval flycheck-cwl-schema-path)
6994             source-inplace)
6995   :error-patterns
6996   ((error line-start
6997           (file-name) ":" line ":" column ":" (zero-or-more blank)
6998           (message (one-or-more not-newline))
6999           line-end))
7000   :modes cwl-mode)
7001
7002 (defconst flycheck-d-module-re
7003   (rx "module" (one-or-more (syntax whitespace))
7004       (group (one-or-more (not (syntax whitespace))))
7005       (zero-or-more (syntax whitespace))
7006       ";")
7007   "Regular expression to match a D module declaration.")
7008
7009 (defun flycheck-d-base-directory ()
7010   "Get the relative base directory path for this module."
7011   (let* ((file-name (buffer-file-name))
7012          (module-file (if (string= (file-name-nondirectory file-name)
7013                                    "package.d")
7014                           (directory-file-name (file-name-directory file-name))
7015                         file-name)))
7016     (flycheck-module-root-directory
7017      (flycheck-find-in-buffer flycheck-d-module-re)
7018      module-file)))
7019
7020 (flycheck-def-option-var flycheck-dmd-include-path nil d-dmd
7021   "A list of include directories for dmd.
7022
7023 The value of this variable is a list of strings, where each
7024 string is a directory to add to the include path of dmd.
7025 Relative paths are relative to the file being checked."
7026   :type '(repeat (directory :tag "Include directory"))
7027   :safe #'flycheck-string-list-p
7028   :package-version '(flycheck . "0.18"))
7029
7030 (flycheck-def-args-var flycheck-dmd-args d-dmd
7031   :package-version '(flycheck . "0.24"))
7032
7033 (flycheck-define-checker d-dmd
7034   "A D syntax checker using the DMD compiler.
7035
7036 Requires DMD 2.066 or newer.  See URL `https://dlang.org/'."
7037   :command ("dmd"
7038             "-debug"                    ; Compile in debug mode
7039             "-o-"                       ; Don't generate an object file
7040             "-vcolumns"                 ; Add columns in output
7041             "-wi" ; Compilation will continue even if there are warnings
7042             (eval (concat "-I" (flycheck-d-base-directory)))
7043             (option-list "-I" flycheck-dmd-include-path concat)
7044             (eval flycheck-dmd-args)
7045             source)
7046   :error-patterns
7047   ((error line-start
7048           (file-name) "(" line "," column "): Error: " (message)
7049           line-end)
7050    (warning line-start (file-name) "(" line "," column "): "
7051             (or "Warning" "Deprecation") ": " (message) line-end)
7052    (info line-start (file-name) "(" line "," column "): "
7053          (one-or-more " ") (message) line-end))
7054   :modes d-mode)
7055
7056 (flycheck-define-checker dockerfile-hadolint
7057   "A Dockerfile syntax checker using the hadolint.
7058
7059 See URL `http://github.com/hadolint/hadolint/'."
7060   :command ("hadolint" "-")
7061   :standard-input t
7062   :error-patterns
7063   ((error line-start
7064           (file-name) ":" line ":" column " " (message)
7065           line-end)
7066    (warning line-start
7067             (file-name) ":" line " " (id (one-or-more alnum)) " " (message)
7068             line-end))
7069   :error-filter
7070   (lambda (errors)
7071     (flycheck-sanitize-errors
7072      (flycheck-remove-error-file-names "/dev/stdin" errors)))
7073   :modes dockerfile-mode)
7074
7075 (defconst flycheck-this-emacs-executable
7076   (concat invocation-directory invocation-name)
7077   "The path to the currently running Emacs executable.")
7078
7079 (defconst flycheck-emacs-args '("-Q" "--batch")
7080   "Common arguments to Emacs invocations.")
7081
7082 (defmacro flycheck-prepare-emacs-lisp-form (&rest body)
7083   "Prepare BODY for use as check form in a subprocess."
7084   (declare (indent 0))
7085   `(flycheck-sexp-to-string
7086     '(progn
7087        (defvar jka-compr-inhibit)
7088        (unwind-protect
7089            ;; Flycheck inhibits compression of temporary files, thus we
7090            ;; must not attempt to decompress.
7091            (let ((jka-compr-inhibit t))
7092              ;; Strip option-argument separator from arguments, if present
7093              (when (equal (car command-line-args-left) "--")
7094                (setq command-line-args-left (cdr command-line-args-left)))
7095              ,@body)
7096          ;; Prevent Emacs from processing the arguments on its own, see
7097          ;; https://github.com/flycheck/flycheck/issues/319
7098          (setq command-line-args-left nil)))))
7099
7100 (defconst flycheck-emacs-lisp-check-form
7101   (flycheck-prepare-emacs-lisp-form
7102     ;; Keep track of the generated bytecode files, to delete them after byte
7103     ;; compilation.
7104     (defvar flycheck-byte-compiled-files nil)
7105     (let ((byte-compile-dest-file-function
7106            (lambda (source)
7107              (let ((temp-file (make-temp-file (file-name-nondirectory source))))
7108                (push temp-file flycheck-byte-compiled-files)
7109                temp-file))))
7110       (unwind-protect
7111           (byte-compile-file (car command-line-args-left))
7112         (mapc (lambda (f) (ignore-errors (delete-file f)))
7113               flycheck-byte-compiled-files))
7114       (when (bound-and-true-p flycheck-emacs-lisp-check-declare)
7115         (check-declare-file (car command-line-args-left))))))
7116
7117 (flycheck-def-option-var flycheck-emacs-lisp-load-path nil emacs-lisp
7118   "Load path to use in the Emacs Lisp syntax checker.
7119
7120 When set to `inherit', use the `load-path' of the current Emacs
7121 session during syntax checking.
7122
7123 When set to a list of strings, add each directory in this list to
7124 the `load-path' before invoking the byte compiler.  Relative
7125 paths in this list are expanded against the `default-directory'
7126 of the buffer to check.
7127
7128 When nil, do not explicitly set the `load-path' during syntax
7129 checking.  The syntax check only uses the built-in `load-path' of
7130 Emacs in this case.
7131
7132 Note that changing this variable can lead to wrong results of the
7133 syntax check, e.g. if an unexpected version of a required library
7134 is used."
7135   :type '(choice (const :tag "Inherit current `load-path'" inherit)
7136                  (repeat :tag "Load path" directory))
7137   :risky t
7138   :package-version '(flycheck . "0.14"))
7139
7140 (flycheck-def-option-var flycheck-emacs-lisp-initialize-packages
7141     'auto emacs-lisp
7142   "Whether to initialize packages in the Emacs Lisp syntax checker.
7143
7144 When nil, never initialize packages.  When `auto', initialize
7145 packages only when checking `user-init-file' or files from
7146 `user-emacs-directory'.  For any other non-nil value, always
7147 initialize packages.
7148
7149 When initializing packages is enabled the `emacs-lisp' syntax
7150 checker calls `package-initialize' before byte-compiling the file
7151 to be checked.  It also sets `package-user-dir' according to
7152 `flycheck-emacs-lisp-package-user-dir'."
7153   :type '(choice (const :tag "Do not initialize packages" nil)
7154                  (const :tag "Initialize packages for configuration only" auto)
7155                  (const :tag "Always initialize packages" t))
7156   :risky t
7157   :package-version '(flycheck . "0.14"))
7158
7159 (defconst flycheck-emacs-lisp-package-initialize-form
7160   (flycheck-sexp-to-string
7161    '(with-demoted-errors "Error during package initialization: %S"
7162       (package-initialize)))
7163   "Form used to initialize packages.")
7164
7165 (defun flycheck-option-emacs-lisp-package-initialize (value)
7166   "Option VALUE filter for `flycheck-emacs-lisp-initialize-packages'."
7167   (let ((shall-initialize
7168          (if (eq value 'auto)
7169              (or (flycheck-in-user-emacs-directory-p (buffer-file-name))
7170                  ;; `user-init-file' is nil in non-interactive sessions.  Now,
7171                  ;; no user would possibly use Flycheck in a non-interactive
7172                  ;; session, but our unit tests run non-interactively, so we
7173                  ;; have to handle this case anyway
7174                  (and user-init-file
7175                       (flycheck-same-files-p (buffer-file-name)
7176                                              user-init-file)))
7177            value)))
7178     (when shall-initialize
7179       ;; If packages shall be initialized, return the corresponding form,
7180       ;; otherwise make Flycheck ignore the option by returning nil.
7181       flycheck-emacs-lisp-package-initialize-form)))
7182
7183 (flycheck-def-option-var flycheck-emacs-lisp-package-user-dir nil emacs-lisp
7184   "Package directory for the Emacs Lisp syntax checker.
7185
7186 If set to a string set `package-user-dir' to the value of this
7187 variable before initializing packages. If set to nil just inherit
7188 the value of `package-user-dir' from the running Emacs session.
7189
7190 This variable has no effect, if
7191 `flycheck-emacs-lisp-initialize-packages' is nil."
7192   :type '(choice (const :tag "Default package directory" nil)
7193                  (directory :tag "Custom package directory"))
7194   :risky t
7195   :package-version '(flycheck . "0.14"))
7196
7197 (defun flycheck-option-emacs-lisp-package-user-dir (value)
7198   "Option VALUE filter for `flycheck-emacs-lisp-package-user-dir'."
7199   ;; Inherit the package directory from our Emacs session
7200   (let ((value (or value (bound-and-true-p package-user-dir))))
7201     (when value
7202       (flycheck-sexp-to-string `(setq package-user-dir ,value)))))
7203
7204 (flycheck-def-option-var flycheck-emacs-lisp-check-declare nil emacs-lisp
7205   "If non-nil, check ‘declare-function’ forms using ‘check-declare-file’."
7206   :type '(choice (const :tag "Do not check declare forms" nil)
7207                  (const :tag "Check declare forms" t))
7208   :risky t
7209   :package-version '(flycheck . "31"))
7210
7211 (defun flycheck-option-emacs-lisp-check-declare (value)
7212   "Option VALUE filter for `flycheck-emacs-lisp-check-declare'."
7213   (when value
7214     (flycheck-sexp-to-string
7215      `(progn
7216         (defvar flycheck-emacs-lisp-check-declare)
7217         (setq flycheck-emacs-lisp-check-declare ,value)))))
7218
7219 (flycheck-define-checker emacs-lisp
7220   "An Emacs Lisp syntax checker using the Emacs Lisp Byte compiler.
7221
7222 See Info Node `(elisp)Byte Compilation'."
7223   :command ("emacs" (eval flycheck-emacs-args)
7224             (eval
7225              (let ((path (pcase flycheck-emacs-lisp-load-path
7226                            (`inherit load-path)
7227                            (p (seq-map #'expand-file-name p)))))
7228                (flycheck-prepend-with-option "--directory" path)))
7229             (option "--eval" flycheck-emacs-lisp-package-user-dir nil
7230                     flycheck-option-emacs-lisp-package-user-dir)
7231             (option "--eval" flycheck-emacs-lisp-initialize-packages nil
7232                     flycheck-option-emacs-lisp-package-initialize)
7233             (option "--eval" flycheck-emacs-lisp-check-declare nil
7234                     flycheck-option-emacs-lisp-check-declare)
7235             "--eval" (eval flycheck-emacs-lisp-check-form)
7236             "--"
7237             source-inplace)
7238   :error-patterns
7239   ((error line-start (file-name) ":" line ":" column ":Error:"
7240           (message (zero-or-more not-newline)
7241                    (zero-or-more "\n    " (zero-or-more not-newline)))
7242           line-end)
7243    (warning line-start (file-name) ":" line ":" column ":Warning:"
7244             (message (zero-or-more not-newline)
7245                      (zero-or-more "\n    " (zero-or-more not-newline)))
7246             line-end)
7247    (warning line-start (file-name) ":" line (optional ":" column)
7248             ":Warning (check-declare): said\n"
7249             (message (zero-or-more "    " (zero-or-more not-newline))
7250                      (zero-or-more "\n    " (zero-or-more not-newline)))
7251             line-end)
7252    ;; The following is for Emacs 24 ‘check-declare-file’, which uses a
7253    ;; less informative format.
7254    (warning line-start "Warning (check-declare): " (file-name) " said "
7255             (message (zero-or-more not-newline))
7256             line-end))
7257   :error-filter
7258   (lambda (errors)
7259     (flycheck-fill-empty-line-numbers
7260      (flycheck-collapse-error-message-whitespace
7261       (flycheck-sanitize-errors errors))))
7262   :modes (emacs-lisp-mode lisp-interaction-mode)
7263   :predicate
7264   (lambda ()
7265     (and
7266      ;; Ensure that we only check buffers with a backing file.  For buffers
7267      ;; without a backing file we cannot guarantee that file names in error
7268      ;; messages are properly resolved, because `byte-compile-file' emits file
7269      ;; names *relative to the directory of the checked file* instead of the
7270      ;; working directory.  Hence our backwards-substitution will fail, because
7271      ;; the checker process has a different base directory to resolve relative
7272      ;; file names than the Flycheck code working on the buffer to check.
7273      (buffer-file-name)
7274      ;; Do not check buffers which should not be byte-compiled.  The checker
7275      ;; process will refuse to compile these, which would confuse Flycheck
7276      (not (bound-and-true-p no-byte-compile))
7277      ;; Do not check buffers used for autoloads generation during package
7278      ;; installation.  These buffers are too short-lived for being checked, and
7279      ;; doing so causes spurious errors.  See
7280      ;; https://github.com/flycheck/flycheck/issues/45 and
7281      ;; https://github.com/bbatsov/prelude/issues/248.  We must also not check
7282      ;; compilation buffers, but as these are ephemeral, Flycheck won't check
7283      ;; them anyway.
7284      (not (flycheck-autoloads-file-p))))
7285   :next-checkers (emacs-lisp-checkdoc))
7286
7287 (defconst flycheck-emacs-lisp-checkdoc-form
7288   (flycheck-prepare-emacs-lisp-form
7289     (unless (require 'elisp-mode nil 'no-error)
7290       ;; TODO: Fallback for Emacs 24, remove when dropping support for 24
7291       (require 'lisp-mode))
7292     (require 'checkdoc)
7293
7294     (let ((source (car command-line-args-left))
7295           ;; Remember the default directory of the process
7296           (process-default-directory default-directory))
7297       ;; Note that we deliberately use our custom approach even despite of
7298       ;; `checkdoc-file' which was added to Emacs 25.1.  While it's conceptually
7299       ;; the better thing, its implementation has too many flaws to be of use
7300       ;; for us.
7301       (with-temp-buffer
7302         (insert-file-contents source 'visit)
7303         (setq buffer-file-name source)
7304         ;; And change back to the process default directory to make file-name
7305         ;; back-substutition work
7306         (setq default-directory process-default-directory)
7307         (with-demoted-errors "Error in checkdoc: %S"
7308           ;; Checkdoc needs the Emacs Lisp syntax table and comment syntax to
7309           ;; parse sexps and identify docstrings correctly; see
7310           ;; https://github.com/flycheck/flycheck/issues/833
7311           (delay-mode-hooks (emacs-lisp-mode))
7312           (setq delayed-mode-hooks nil)
7313           (checkdoc-current-buffer t)
7314           (with-current-buffer checkdoc-diagnostic-buffer
7315             (princ (buffer-substring-no-properties (point-min) (point-max)))
7316             (kill-buffer)))))))
7317
7318 (defconst flycheck-emacs-lisp-checkdoc-variables
7319   '(checkdoc-symbol-words
7320     checkdoc-arguments-in-order-flag
7321     checkdoc-force-history-flag
7322     checkdoc-permit-comma-termination-flag
7323     checkdoc-force-docstrings-flag
7324     checkdoc-package-keywords-flag
7325     checkdoc-spellcheck-documentation-flag
7326     checkdoc-verb-check-experimental-flag
7327     checkdoc-max-keyref-before-warn
7328     sentence-end-double-space)
7329   "Variables inherited by the checkdoc subprocess.")
7330
7331 (defun flycheck-emacs-lisp-checkdoc-variables-form ()
7332   "Make a sexp to pass relevant variables to a checkdoc subprocess.
7333
7334 Variables are taken from `flycheck-emacs-lisp-checkdoc-variables'."
7335   `(progn
7336      ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt)))
7337                 (seq-filter #'boundp flycheck-emacs-lisp-checkdoc-variables))))
7338
7339 (flycheck-define-checker emacs-lisp-checkdoc
7340   "An Emacs Lisp style checker using CheckDoc.
7341
7342 The checker runs `checkdoc-current-buffer'."
7343   :command ("emacs" (eval flycheck-emacs-args)
7344             "--eval" (eval (flycheck-sexp-to-string
7345                             (flycheck-emacs-lisp-checkdoc-variables-form)))
7346             "--eval" (eval flycheck-emacs-lisp-checkdoc-form)
7347             "--" source)
7348   :error-patterns
7349   ((warning line-start (file-name) ":" line ": " (message) line-end))
7350   :modes (emacs-lisp-mode)
7351   :predicate
7352   (lambda ()
7353     ;; Do not check Autoloads, Cask/Carton and dir-locals files.  These files
7354     ;; really don't need to follow Checkdoc conventions.
7355     (not (or (flycheck-autoloads-file-p)
7356              (and (buffer-file-name)
7357                   (member (file-name-nondirectory (buffer-file-name))
7358                           '("Cask" "Carton" ".dir-locals.el")))))))
7359
7360 (dolist (checker '(emacs-lisp emacs-lisp-checkdoc))
7361   (setf (car (flycheck-checker-get checker 'command))
7362         flycheck-this-emacs-executable))
7363
7364 (flycheck-def-option-var flycheck-erlang-include-path nil erlang
7365   "A list of include directories for Erlang.
7366
7367 The value of this variable is a list of strings, where each
7368 string is a directory to add to the include path of erlc.
7369 Relative paths are relative to the file being checked."
7370   :type '(repeat (directory :tag "Include directory"))
7371   :safe #'flycheck-string-list-p
7372   :package-version '(flycheck . "0.24"))
7373
7374 (flycheck-def-option-var flycheck-erlang-library-path nil erlang
7375   "A list of library directories for Erlang.
7376
7377 The value of this variable is a list of strings, where each
7378 string is a directory to add to the library path of erlc.
7379 Relative paths are relative to the file being checked."
7380   :type '(repeat (directory :tag "Library directory"))
7381   :safe #'flycheck-string-list-p
7382   :package-version '(flycheck . "0.24"))
7383
7384 (flycheck-define-checker erlang
7385   "An Erlang syntax checker using the Erlang interpreter.
7386
7387 See URL `http://www.erlang.org/'."
7388   :command ("erlc"
7389             "-o" temporary-directory
7390             (option-list "-I" flycheck-erlang-include-path)
7391             (option-list "-pa" flycheck-erlang-library-path)
7392             "-Wall"
7393             source)
7394   :error-patterns
7395   ((warning line-start (file-name) ":" line ": Warning:" (message) line-end)
7396    (error line-start (file-name) ":" line ": " (message) line-end))
7397   :modes erlang-mode
7398   :enabled (lambda () (string-suffix-p ".erl" (buffer-file-name))))
7399
7400 (defun contains-rebar-config (dir-name)
7401   "Return DIR-NAME if DIR-NAME/rebar.config exists, nil otherwise."
7402   (when (file-exists-p (expand-file-name "rebar.config" dir-name))
7403     dir-name))
7404
7405 (defun locate-rebar3-project-root (file-name &optional prev-file-name acc)
7406   "Find the top-most rebar project root for source FILE-NAME.
7407
7408 A project root directory is any directory containing a
7409 rebar.config file.  Find the top-most directory to move out of any
7410 nested dependencies.
7411
7412 FILE-NAME is a source file for which to find the project.
7413
7414 PREV-FILE-NAME helps us prevent infinite looping
7415
7416 ACC is an accumulator that keeps the list of results, the first
7417 non-nil of which will be our project root.
7418
7419 Return the absolute path to the directory"
7420   (if (string= file-name prev-file-name)
7421       (car (remove nil acc))
7422     (let ((current-dir (file-name-directory file-name)))
7423       (locate-rebar3-project-root
7424        (directory-file-name current-dir)
7425        file-name
7426        (cons (contains-rebar-config current-dir) acc)))))
7427
7428 (defun flycheck-rebar3-project-root (&optional _checker)
7429   "Return directory where rebar.config is located."
7430   (locate-rebar3-project-root buffer-file-name))
7431
7432 (flycheck-define-checker erlang-rebar3
7433   "An Erlang syntax checker using the rebar3 build tool."
7434   :command ("rebar3" "compile")
7435   :error-parser
7436   (lambda (output checker buffer)
7437     ;; rebar3 outputs ANSI terminal colors, which don't match up with
7438     ;; :error-patterns, so we strip those color codes from the output
7439     ;; here before passing it along to the default behavior. The
7440     ;; relevant discussion can be found at
7441     ;; https://github.com/flycheck/flycheck/pull/1144
7442     (require 'ansi-color)
7443     (flycheck-parse-with-patterns
7444      (and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output))
7445      checker buffer))
7446   :error-patterns
7447   ((warning line-start
7448             (file-name) ":" line ": Warning:" (message) line-end)
7449    (error line-start
7450           (file-name) ":" line ": " (message) line-end))
7451   :modes erlang-mode
7452   :enabled flycheck-rebar3-project-root
7453   :predicate flycheck-buffer-saved-p
7454   :working-directory flycheck-rebar3-project-root)
7455
7456 (flycheck-define-checker eruby-erubis
7457   "An eRuby syntax checker using the `erubis' command.
7458
7459 See URL `http://www.kuwata-lab.com/erubis/'."
7460   :command ("erubis" "-z" source)
7461   :error-patterns
7462   ((error line-start (file-name) ":" line ": " (message) line-end))
7463   :modes (html-erb-mode rhtml-mode))
7464
7465 (flycheck-def-args-var flycheck-gfortran-args fortran-gfortran
7466   :package-version '(flycheck . "0.22"))
7467
7468 (flycheck-def-option-var flycheck-gfortran-include-path nil fortran-gfortran
7469   "A list of include directories for GCC Fortran.
7470
7471 The value of this variable is a list of strings, where each
7472 string is a directory to add to the include path of gcc.
7473 Relative paths are relative to the file being checked."
7474   :type '(repeat (directory :tag "Include directory"))
7475   :safe #'flycheck-string-list-p
7476   :package-version '(flycheck . "0.20"))
7477
7478 (flycheck-def-option-var flycheck-gfortran-language-standard "f95"
7479                          fortran-gfortran
7480   "The language standard to use in GFortran.
7481
7482 The value of this variable is either a string denoting a language
7483 standard, or nil, to use the default standard.  When non-nil,
7484 pass the language standard via the `-std' option."
7485   :type '(choice (const :tag "Default standard" nil)
7486                  (string :tag "Language standard"))
7487   :safe #'stringp
7488   :package-version '(flycheck . "0.20"))
7489
7490 (flycheck-def-option-var flycheck-gfortran-layout nil fortran-gfortran
7491   "The source code layout to use in GFortran.
7492
7493 The value of this variable is one of the following symbols:
7494
7495 nil
7496      Let gfortran determine the layout from the extension
7497
7498 `free'
7499      Use free form layout
7500
7501
7502 `fixed'
7503      Use fixed form layout
7504
7505 In any other case, an error is signaled."
7506   :type '(choice (const :tag "Guess layout from extension" nil)
7507                  (const :tag "Free form layout" free)
7508                  (const :tag "Fixed form layout" fixed))
7509   :safe (lambda (value) (or (not value) (memq value '(free fixed))))
7510   :package-version '(flycheck . "0.20"))
7511
7512 (defun flycheck-option-gfortran-layout (value)
7513   "Option VALUE filter for `flycheck-gfortran-layout'."
7514   (pcase value
7515     (`nil nil)
7516     (`free "free-form")
7517     (`fixed "fixed-form")
7518     (_ (error "Invalid value for flycheck-gfortran-layout: %S" value))))
7519
7520 (flycheck-def-option-var flycheck-gfortran-warnings '("all" "extra")
7521                          fortran-gfortran
7522   "A list of warnings for GCC Fortran.
7523
7524 The value of this variable is a list of strings, where each string
7525 is the name of a warning category to enable.  By default, all
7526 recommended warnings and some extra warnings are enabled (as by
7527 `-Wall' and `-Wextra' respectively).
7528
7529 Refer to the gfortran manual at URL
7530 `https://gcc.gnu.org/onlinedocs/gfortran/' for more information
7531 about warnings"
7532   :type '(choice (const :tag "No additional warnings" nil)
7533                  (repeat :tag "Additional warnings"
7534                          (string :tag "Warning name")))
7535   :safe #'flycheck-string-list-p
7536   :package-version '(flycheck . "0.20"))
7537
7538 (flycheck-define-checker fortran-gfortran
7539   "An Fortran syntax checker using GCC.
7540
7541 Uses GCC's Fortran compiler gfortran.  See URL
7542 `https://gcc.gnu.org/onlinedocs/gfortran/'."
7543   :command ("gfortran"
7544             "-fsyntax-only"
7545             "-fshow-column"
7546             ;; Do not visually indicate the source location
7547             "-fno-diagnostics-show-caret"
7548             ;; Do not show the corresponding warning group
7549             "-fno-diagnostics-show-option"
7550             ;; Fortran has similar include processing as C/C++
7551             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
7552             (option "-std=" flycheck-gfortran-language-standard concat)
7553             (option "-f" flycheck-gfortran-layout concat
7554                     flycheck-option-gfortran-layout)
7555             (option-list "-W" flycheck-gfortran-warnings concat)
7556             (option-list "-I" flycheck-gfortran-include-path concat)
7557             (eval flycheck-gfortran-args)
7558             source)
7559   :error-patterns
7560   ((error line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
7561           (or (= 3 (zero-or-more not-newline) "\n") "")
7562           (or "Error" "Fatal Error") ": "
7563           (message) line-end)
7564    (warning line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
7565             (or (= 3 (zero-or-more not-newline) "\n") "")
7566             "Warning: " (message) line-end))
7567   :modes (fortran-mode f90-mode))
7568
7569 (flycheck-define-checker go-gofmt
7570   "A Go syntax and style checker using the gofmt utility.
7571
7572 See URL `https://golang.org/cmd/gofmt/'."
7573   :command ("gofmt")
7574   :standard-input t
7575   :error-patterns
7576   ((error line-start "<standard input>:" line ":" column ": "
7577           (message) line-end))
7578   :modes go-mode
7579   :next-checkers ((warning . go-golint)
7580                   ;; Fall back, if go-golint doesn't exist
7581                   (warning . go-vet)
7582                   ;; Fall back, if go-vet doesn't exist
7583                   (warning . go-build) (warning . go-test)
7584                   (warning . go-errcheck)
7585                   (warning . go-unconvert)
7586                   (warning . go-megacheck)))
7587
7588 (flycheck-define-checker go-golint
7589   "A Go style checker using Golint.
7590
7591 See URL `https://github.com/golang/lint'."
7592   :command ("golint" source)
7593   :error-patterns
7594   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
7595   :modes go-mode
7596   :next-checkers (go-vet
7597                   ;; Fall back, if go-vet doesn't exist
7598                   go-build go-test go-errcheck go-unconvert go-megacheck))
7599
7600 (flycheck-def-option-var flycheck-go-vet-print-functions nil go-vet
7601   "A list of print-like functions for `go tool vet'.
7602
7603 Go vet will check these functions for format string problems and
7604 issues, such as a mismatch between the number of formats used,
7605 and the number of arguments given.
7606
7607 Each entry is in the form Name:N where N is the zero-based
7608 argument position of the first argument involved in the print:
7609 either the format or the first print argument for non-formatted
7610 prints.  For example, if you have Warn and Warnf functions that
7611 take an io.Writer as their first argument, like Fprintf,
7612 -printfuncs=Warn:1,Warnf:1 "
7613   :type '(repeat :tag "print-like functions"
7614                  (string :tag "function"))
7615   :safe #'flycheck-string-list-p)
7616
7617 (flycheck-def-option-var flycheck-go-vet-shadow nil go-vet
7618   "Whether to check for shadowed variables with `go tool vet'.
7619
7620 When non-nil check for shadowed variables.  When `strict' check
7621 more strictly, which can very noisy.  When nil do not check for
7622 shadowed variables.
7623
7624 This option requires Go 1.6 or newer."
7625   :type '(choice (const :tag "Do not check for shadowed variables" nil)
7626                  (const :tag "Check for shadowed variables" t)
7627                  (const :tag "Strictly check for shadowed variables" strict)))
7628
7629 (flycheck-def-option-var flycheck-go-megacheck-disabled-checkers nil
7630                          go-megacheck
7631   "A list of checkers to disable when running `megacheck'.
7632
7633 The value of this variable is a list of strings, where each
7634 string is a checker to be disabled. Valid checkers are `simple',
7635 `staticcheck' and `unused'. When nil, all checkers will be
7636 enabled. "
7637   :type '(set (const :tag "Disable simple" "simple")
7638               (const :tag "Disable staticcheck" "staticcheck")
7639               (const :tag "Disable unused" "unused"))
7640   :safe #'flycheck-string-list-p)
7641
7642 (flycheck-define-checker go-vet
7643   "A Go syntax checker using the `go tool vet' command.
7644
7645 See URL `https://golang.org/cmd/go/' and URL
7646 `https://golang.org/cmd/vet/'."
7647   :command ("go" "tool" "vet" "-all"
7648             (option "-printfuncs=" flycheck-go-vet-print-functions concat
7649                     flycheck-option-comma-separated-list)
7650             (option-flag "-shadow" flycheck-go-vet-shadow)
7651             (option-list "-tags=" flycheck-go-build-tags concat)
7652             (eval (when (eq flycheck-go-vet-shadow 'strict) "-shadowstrict"))
7653             source)
7654   :error-patterns
7655   ((warning line-start (file-name) ":" line ": " (message) line-end))
7656   :modes go-mode
7657   ;; We must explicitly check whether the "vet" tool is available
7658   :predicate (lambda ()
7659                (let ((go (flycheck-checker-executable 'go-vet)))
7660                  (member "vet" (ignore-errors (process-lines go "tool")))))
7661   :next-checkers (go-build
7662                   go-test
7663                   ;; Fall back if `go build' or `go test' can be used
7664                   go-errcheck
7665                   go-unconvert
7666                   go-megacheck)
7667   :verify (lambda (_)
7668             (let* ((go (flycheck-checker-executable 'go-vet))
7669                    (have-vet (member "vet" (ignore-errors
7670                                              (process-lines go "tool")))))
7671               (list
7672                (flycheck-verification-result-new
7673                 :label "go tool vet"
7674                 :message (if have-vet "present" "missing")
7675                 :face (if have-vet 'success '(bold error)))))))
7676
7677 (flycheck-def-option-var flycheck-go-build-install-deps nil (go-build go-test)
7678   "Whether to install dependencies in `go build' and `go test'.
7679
7680 If non-nil automatically install dependencies with `go build'
7681 while syntax checking."
7682   :type 'boolean
7683   :safe #'booleanp
7684   :package-version '(flycheck . "0.25"))
7685
7686 (flycheck-def-option-var flycheck-go-build-tags nil go-build
7687   "A list of tags for `go build'.
7688
7689 Each item is a string with a tag to be given to `go build'."
7690   :type '(repeat (string :tag "Tag"))
7691   :safe #'flycheck-string-list-p
7692   :package-version '(flycheck . "0.25"))
7693
7694 (flycheck-define-checker go-build
7695   "A Go syntax and type checker using the `go build' command.
7696
7697 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
7698   :command ("go" "build"
7699             (option-flag "-i" flycheck-go-build-install-deps)
7700             ;; multiple tags are listed as "dev debug ..."
7701             (option-list "-tags=" flycheck-go-build-tags concat)
7702             "-o" null-device)
7703   :error-patterns
7704   ((error line-start (file-name) ":" line ":"
7705           (optional column ":") " "
7706           (message (one-or-more not-newline)
7707                    (zero-or-more "\n\t" (one-or-more not-newline)))
7708           line-end)
7709    ;; Catch error message about multiple packages in a directory, which doesn't
7710    ;; follow the standard error message format.
7711    (info line-start
7712          (message "can't load package: package "
7713                   (one-or-more (not (any ?: ?\n)))
7714                   ": found packages "
7715                   (one-or-more not-newline))
7716          line-end))
7717   :error-filter
7718   (lambda (errors)
7719     (dolist (error errors)
7720       (unless (flycheck-error-line error)
7721         ;; Flycheck ignores errors without line numbers, but the error
7722         ;; message about multiple packages in a directory doesn't come with a
7723         ;; line number, so inject a fake one.
7724         (setf (flycheck-error-line error) 1)))
7725     errors)
7726   :modes go-mode
7727   :predicate (lambda ()
7728                (and (flycheck-buffer-saved-p)
7729                     (not (string-suffix-p "_test.go" (buffer-file-name)))))
7730   :next-checkers ((warning . go-errcheck)
7731                   (warning . go-unconvert)
7732                   (warning . go-megacheck)))
7733
7734 (flycheck-define-checker go-test
7735   "A Go syntax and type checker using the `go test' command.
7736
7737 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
7738   :command ("go" "test"
7739             (option-flag "-i" flycheck-go-build-install-deps)
7740             (option-list "-tags=" flycheck-go-build-tags concat)
7741             "-c" "-o" null-device)
7742   :error-patterns
7743   ((error line-start (file-name) ":" line ":"
7744           (optional column ":") " "
7745           (message (one-or-more not-newline)
7746                    (zero-or-more "\n\t" (one-or-more not-newline)))
7747           line-end))
7748   :modes go-mode
7749   :predicate
7750   (lambda () (and (flycheck-buffer-saved-p)
7751                   (string-suffix-p "_test.go" (buffer-file-name))))
7752   :next-checkers ((warning . go-errcheck)
7753                   (warning . go-unconvert)
7754                   (warning . go-megacheck)))
7755
7756 (flycheck-define-checker go-errcheck
7757   "A Go checker for unchecked errors.
7758
7759 Requires errcheck newer than commit 8515d34 (Aug 28th, 2015).
7760
7761 See URL `https://github.com/kisielk/errcheck'."
7762   :command ("errcheck"
7763             "-abspath"
7764             (option-list "-tags=" flycheck-go-build-tags concat)
7765             ".")
7766   :error-patterns
7767   ((warning line-start
7768             (file-name) ":" line ":" column (or (one-or-more "\t") ": " ":\t")
7769             (message)
7770             line-end))
7771   :error-filter
7772   (lambda (errors)
7773     (let ((errors (flycheck-sanitize-errors errors)))
7774       (dolist (err errors)
7775         (-when-let (message (flycheck-error-message err))
7776           ;; Improve the messages reported by errcheck to make them more clear.
7777           (setf (flycheck-error-message err)
7778                 (format "Ignored `error` returned from `%s`" message)))))
7779     errors)
7780   :modes go-mode
7781   :predicate (lambda () (flycheck-buffer-saved-p))
7782   :next-checkers ((warning . go-unconvert)
7783                   (warning . go-megacheck)))
7784
7785 (flycheck-define-checker go-unconvert
7786   "A Go checker looking for unnecessary type conversions.
7787
7788 See URL `https://github.com/mdempsky/unconvert'."
7789   :command ("unconvert" ".")
7790   :error-patterns
7791   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
7792   :modes go-mode
7793   :predicate (lambda () (flycheck-buffer-saved-p))
7794   :next-checkers ((warning . go-megacheck)))
7795
7796 (flycheck-define-checker go-megacheck
7797   "A Go checker that performs static analysis and linting using the `megacheck'
7798 command.
7799
7800 Requires Go 1.6 or newer. See URL
7801 `https://github.com/dominikh/go-tools'."
7802   :command ("megacheck"
7803             (option-list "-tags=" flycheck-go-build-tags concat)
7804             (eval (mapcar (lambda (checker) (concat "-" checker
7805                                                     ".enabled=false"))
7806                           flycheck-go-megacheck-disabled-checkers))
7807             ;; Run in current directory to make megacheck aware of symbols
7808             ;; declared in other files.
7809             ".")
7810   :error-patterns
7811   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
7812   :modes go-mode)
7813
7814 (flycheck-define-checker groovy
7815   "A groovy syntax checker using groovy compiler API.
7816
7817 See URL `http://www.groovy-lang.org'."
7818   :command ("groovy" "-e"
7819             "import org.codehaus.groovy.control.*
7820
7821 unit = new CompilationUnit()
7822 unit.addSource(\"input\", System.in)
7823
7824 try {
7825     unit.compile(Phases.CONVERSION)
7826 } catch (MultipleCompilationErrorsException e) {
7827     e.errorCollector.write(new PrintWriter(System.out, true), null)
7828 }")
7829   :standard-input t
7830   :error-patterns
7831   ((error line-start "input: " line ":" (message)
7832           " @ line " line ", column " column "." line-end))
7833   :modes groovy-mode)
7834
7835 (flycheck-define-checker haml
7836   "A Haml syntax checker using the Haml compiler.
7837
7838 See URL `http://haml.info'."
7839   :command ("haml" "-c" "--stdin")
7840   :standard-input t
7841   :error-patterns
7842   ((error line-start "Syntax error on line " line ": " (message) line-end)
7843    (error line-start ":" line ": syntax error, " (message) line-end))
7844   :modes haml-mode)
7845
7846 (flycheck-define-checker handlebars
7847   "A Handlebars syntax checker using the Handlebars compiler.
7848
7849 See URL `http://handlebarsjs.com/'."
7850   :command ("handlebars" "-i-")
7851   :standard-input t
7852   :error-patterns
7853   ((error line-start
7854           "Error: Parse error on line " line ":" (optional "\r") "\n"
7855           (zero-or-more not-newline) "\n" (zero-or-more not-newline) "\n"
7856           (message) line-end))
7857   :modes (handlebars-mode handlebars-sgml-mode web-mode)
7858   :predicate
7859   (lambda ()
7860     (if (eq major-mode 'web-mode)
7861         ;; Check if this is a handlebars file since web-mode does not store the
7862         ;; non-canonical engine name
7863         (let* ((regexp-alist (bound-and-true-p web-mode-engine-file-regexps))
7864                (pattern (cdr (assoc "handlebars" regexp-alist))))
7865           (and pattern (buffer-file-name)
7866                (string-match-p pattern (buffer-file-name))))
7867       t)))
7868
7869 (defconst flycheck-haskell-module-re
7870   (rx line-start (zero-or-more (or "\n" (any space)))
7871       "module" (one-or-more (or "\n" (any space)))
7872       (group (one-or-more (not (any space "(" "\n")))))
7873   "Regular expression for a Haskell module name.")
7874
7875 (flycheck-def-args-var flycheck-ghc-args (haskell-stack-ghc haskell-ghc)
7876   :package-version '(flycheck . "0.22"))
7877
7878 (flycheck-def-option-var flycheck-ghc-stack-use-nix nil haskell-stack-ghc
7879   "Whether to enable nix support in stack.
7880
7881 When non-nil, stack will append '--nix' flag to any call."
7882   :type 'boolean
7883   :safe #'booleanp
7884   :package-version '(flycheck . "26"))
7885
7886 (flycheck-def-option-var flycheck-ghc-stack-project-file nil haskell-stack-ghc
7887   "Override project stack.yaml file.
7888
7889 The value of this variable is a file path that refers to a yaml
7890 file for the current stack project. Relative file paths are
7891 resolved against the checker's working directory. When non-nil,
7892 stack will get overridden value via `--stack-yaml'."
7893   :type 'string
7894   :safe #'stringp
7895   :package-version '(flycheck . "32"))
7896
7897 (flycheck-def-option-var flycheck-ghc-no-user-package-database nil haskell-ghc
7898   "Whether to disable the user package database in GHC.
7899
7900 When non-nil, disable the user package database in GHC, via
7901 `-no-user-package-db'."
7902   :type 'boolean
7903   :safe #'booleanp
7904   :package-version '(flycheck . "0.16"))
7905
7906 (flycheck-def-option-var flycheck-ghc-package-databases nil haskell-ghc
7907   "Additional module databases for GHC.
7908
7909 The value of this variable is a list of strings, where each
7910 string is a directory of a package database.  Each package
7911 database is given to GHC via `-package-db'."
7912   :type '(repeat (directory :tag "Package database"))
7913   :safe #'flycheck-string-list-p
7914   :package-version '(flycheck . "0.16"))
7915
7916 (flycheck-def-option-var flycheck-ghc-search-path nil
7917                          (haskell-stack-ghc haskell-ghc)
7918   "Module search path for (Stack) GHC.
7919
7920 The value of this variable is a list of strings, where each
7921 string is a directory containing Haskell modules.  Each directory
7922 is added to the GHC search path via `-i'."
7923   :type '(repeat (directory :tag "Module directory"))
7924   :safe #'flycheck-string-list-p
7925   :package-version '(flycheck . "0.16"))
7926
7927 (flycheck-def-option-var flycheck-ghc-language-extensions nil
7928                          (haskell-stack-ghc haskell-ghc)
7929   "Language extensions for (Stack) GHC.
7930
7931 The value of this variable is a list of strings, where each
7932 string is a Haskell language extension, as in the LANGUAGE
7933 pragma.  Each extension is enabled via `-X'."
7934   :type '(repeat (string :tag "Language extension"))
7935   :safe #'flycheck-string-list-p
7936   :package-version '(flycheck . "0.19"))
7937
7938 (defvar flycheck-haskell-ghc-cache-directory nil
7939   "The cache directory for `ghc' output.")
7940
7941 (defun flycheck-haskell-ghc-cache-directory ()
7942   "Get the cache location for `ghc' output.
7943
7944 If no cache directory exists yet, create one and return it.
7945 Otherwise return the previously used cache directory."
7946   (setq flycheck-haskell-ghc-cache-directory
7947         (or flycheck-haskell-ghc-cache-directory
7948             (make-temp-file "flycheck-haskell-ghc-cache" 'directory))))
7949
7950 (defun flycheck--locate-dominating-file-matching (directory regexp)
7951   "Search for a file in directory hierarchy starting at DIRECTORY.
7952
7953 Look up the directory hierarchy from DIRECTORY for a directory
7954 containing a file that matches REGEXP."
7955   (locate-dominating-file
7956    directory
7957    (lambda (dir)
7958      (directory-files dir nil regexp t))))
7959
7960 (defun flycheck-haskell--find-default-directory (checker)
7961   "Come up with a suitable default directory for Haskell to run CHECKER in.
7962
7963 In case of `haskell-stack-ghc' checker it is directory with
7964 stack.yaml file.  If there's no stack.yaml file in any parent
7965 directory, it will be the directory that \"stack path --project-root\"
7966 command returns.
7967
7968 For all other checkers, it is the closest parent directory that
7969 contains a cabal file."
7970   (pcase checker
7971     (`haskell-stack-ghc
7972      (or
7973       (when (buffer-file-name)
7974         (flycheck--locate-dominating-file-matching
7975          (file-name-directory (buffer-file-name))
7976          "stack.*\\.yaml\\'"))
7977       (-when-let* ((stack (funcall flycheck-executable-find "stack"))
7978                    (output (ignore-errors
7979                              (process-lines stack
7980                                             "--no-install-ghc"
7981                                             "path" "--project-root")))
7982                    (stack-dir (car output)))
7983         (and (file-directory-p stack-dir) stack-dir))))
7984     (_
7985      (when (buffer-file-name)
7986        (flycheck--locate-dominating-file-matching
7987         (file-name-directory (buffer-file-name))
7988         "\\.cabal\\'\\|\\`package\\.yaml\\'")))))
7989
7990 (flycheck-define-checker haskell-stack-ghc
7991   "A Haskell syntax and type checker using `stack ghc'.
7992
7993 See URL `https://github.com/commercialhaskell/stack'."
7994   :command ("stack"
7995             "--no-install-ghc"
7996             (option "--stack-yaml" flycheck-ghc-stack-project-file)
7997             (option-flag "--nix" flycheck-ghc-stack-use-nix)
7998             "ghc" "--" "-Wall" "-no-link"
7999             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
8000             (option-list "-X" flycheck-ghc-language-extensions concat)
8001             (option-list "-i" flycheck-ghc-search-path concat)
8002             (eval (concat
8003                    "-i"
8004                    (flycheck-module-root-directory
8005                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
8006             (eval flycheck-ghc-args)
8007             "-x" (eval
8008                   (pcase major-mode
8009                     (`haskell-mode "hs")
8010                     (`literate-haskell-mode "lhs")))
8011             source)
8012   :error-patterns
8013   ((warning line-start (file-name) ":" line ":" column ":"
8014             (or " " "\n    ") (in "Ww") "arning:"
8015             (optional " " "[" (id (one-or-more not-newline)) "]")
8016             (optional "\n")
8017             (message
8018              (one-or-more " ") (one-or-more not-newline)
8019              (zero-or-more "\n"
8020                            (one-or-more " ")
8021                            (one-or-more (not (any ?\n ?|)))))
8022             line-end)
8023    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
8024           (or (message (one-or-more not-newline))
8025               (and "\n"
8026                    (message
8027                     (one-or-more " ") (one-or-more not-newline)
8028                     (zero-or-more "\n"
8029                                   (one-or-more " ")
8030                                   (one-or-more (not (any ?\n ?|)))))))
8031           line-end))
8032   :error-filter
8033   (lambda (errors)
8034     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
8035   :modes (haskell-mode literate-haskell-mode)
8036   :next-checkers ((warning . haskell-hlint))
8037   :working-directory flycheck-haskell--find-default-directory)
8038
8039 (flycheck-define-checker haskell-ghc
8040   "A Haskell syntax and type checker using ghc.
8041
8042 See URL `https://www.haskell.org/ghc/'."
8043   :command ("ghc" "-Wall" "-no-link"
8044             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
8045             (option-flag "-no-user-package-db"
8046                          flycheck-ghc-no-user-package-database)
8047             (option-list "-package-db" flycheck-ghc-package-databases)
8048             (option-list "-i" flycheck-ghc-search-path concat)
8049             ;; Include the parent directory of the current module tree, to
8050             ;; properly resolve local imports
8051             (eval (concat
8052                    "-i"
8053                    (flycheck-module-root-directory
8054                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
8055             (option-list "-X" flycheck-ghc-language-extensions concat)
8056             (eval flycheck-ghc-args)
8057             "-x" (eval
8058                   (pcase major-mode
8059                     (`haskell-mode "hs")
8060                     (`literate-haskell-mode "lhs")))
8061             source)
8062   :error-patterns
8063   ((warning line-start (file-name) ":" line ":" column ":"
8064             (or " " "\n    ") (in "Ww") "arning:"
8065             (optional " " "[" (id (one-or-more not-newline)) "]")
8066             (optional "\n")
8067             (message
8068              (one-or-more " ") (one-or-more not-newline)
8069              (zero-or-more "\n"
8070                            (one-or-more " ")
8071                            (one-or-more (not (any ?\n ?|)))))
8072             line-end)
8073    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
8074           (or (message (one-or-more not-newline))
8075               (and "\n"
8076                    (message
8077                     (one-or-more " ") (one-or-more not-newline)
8078                     (zero-or-more "\n"
8079                                   (one-or-more " ")
8080                                   (one-or-more (not (any ?\n ?|)))))))
8081           line-end))
8082   :error-filter
8083   (lambda (errors)
8084     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
8085   :modes (haskell-mode literate-haskell-mode)
8086   :next-checkers ((warning . haskell-hlint))
8087   :working-directory flycheck-haskell--find-default-directory)
8088
8089 (flycheck-def-config-file-var flycheck-hlintrc haskell-hlint "HLint.hs"
8090   :safe #'stringp)
8091
8092 (flycheck-def-args-var flycheck-hlint-args haskell-hlint
8093   :package-version '(flycheck . "0.25"))
8094
8095 (flycheck-def-option-var flycheck-hlint-language-extensions
8096     nil haskell-hlint
8097   "Extensions list to enable for hlint.
8098
8099 The value of this variable is a list of strings, where each
8100 string is a name of extension to enable in
8101 hlint (e.g. \"QuasiQuotes\")."
8102   :type '(repeat :tag "Extensions" (string :tag "Extension"))
8103   :safe #'flycheck-string-list-p
8104   :package-version '(flycheck . "0.24"))
8105
8106 (flycheck-def-option-var flycheck-hlint-ignore-rules
8107     nil haskell-hlint
8108   "Ignore rules list for hlint checks.
8109
8110 The value of this variable is a list of strings, where each
8111 string is an ignore rule (e.g. \"Use fmap\")."
8112   :type '(repeat :tag "Ignore rules" (string :tag "Ignore rule"))
8113   :safe #'flycheck-string-list-p
8114   :package-version '(flycheck . "0.24"))
8115
8116 (flycheck-def-option-var flycheck-hlint-hint-packages
8117     nil haskell-hlint
8118   "Hint packages to include for hlint checks.
8119
8120 The value of this variable is a list of strings, where each
8121 string is a default hint package (e.g. (\"Generalise\"
8122 \"Default\" \"Dollar\"))."
8123   :type '(repeat :tag "Hint packages" (string :tag "Hint package"))
8124   :safe #'flycheck-string-list-p
8125   :package-version '(flycheck . "0.24"))
8126
8127 (flycheck-define-checker haskell-hlint
8128   "A Haskell style checker using hlint.
8129
8130 See URL `https://github.com/ndmitchell/hlint'."
8131   :command ("hlint"
8132             (option-list "-X" flycheck-hlint-language-extensions concat)
8133             (option-list "-i=" flycheck-hlint-ignore-rules concat)
8134             (option-list "-h" flycheck-hlint-hint-packages concat)
8135             (config-file "-h" flycheck-hlintrc)
8136             (eval flycheck-hlint-args)
8137             source-inplace)
8138   :error-patterns
8139   ((info line-start
8140          (file-name) ":" line ":" column
8141          ": Suggestion: "
8142          (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
8143          line-end)
8144    (warning line-start
8145             (file-name) ":" line ":" column
8146             ": Warning: "
8147             (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
8148             line-end)
8149    (error line-start
8150           (file-name) ":" line ":" column
8151           ": Error: "
8152           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
8153           line-end))
8154   :modes (haskell-mode literate-haskell-mode))
8155
8156 (flycheck-def-config-file-var flycheck-tidyrc html-tidy ".tidyrc"
8157   :safe #'stringp)
8158
8159 (flycheck-define-checker html-tidy
8160   "A HTML syntax and style checker using Tidy.
8161
8162 See URL `https://github.com/htacg/tidy-html5'."
8163   :command ("tidy" (config-file "-config" flycheck-tidyrc)
8164             "-lang" "en"
8165             "-e" "-q")
8166   :standard-input t
8167   :error-patterns
8168   ((error line-start
8169           "line " line
8170           " column " column
8171           " - Error: " (message) line-end)
8172    (warning line-start
8173             "line " line
8174             " column " column
8175             " - Warning: " (message) line-end))
8176   :modes (html-mode mhtml-mode nxhtml-mode))
8177
8178 (flycheck-def-config-file-var flycheck-jshintrc javascript-jshint ".jshintrc"
8179   :safe #'stringp)
8180
8181 (flycheck-def-option-var flycheck-jshint-extract-javascript nil
8182                          javascript-jshint
8183   "Whether jshint should extract Javascript from HTML.
8184
8185 If nil no extract rule is given to jshint.  If `auto' only
8186 extract Javascript if a HTML file is detected.  If `always' or
8187 `never' extract Javascript always or never respectively.
8188
8189 Refer to the jshint manual at the URL
8190 `http://jshint.com/docs/cli/#flags' for more information."
8191   :type
8192   '(choice (const :tag "No extraction rule" nil)
8193            (const :tag "Try to extract Javascript when detecting HTML files"
8194                   auto)
8195            (const :tag "Always try to extract Javascript" always)
8196            (const :tag "Never try to extract Javascript" never))
8197   :safe #'symbolp
8198   :package-version '(flycheck . "26"))
8199
8200 (flycheck-define-checker javascript-jshint
8201   "A Javascript syntax and style checker using jshint.
8202
8203 See URL `http://www.jshint.com'."
8204   :command ("jshint" "--reporter=checkstyle"
8205             "--filename" source-original
8206             (config-file "--config" flycheck-jshintrc)
8207             (option "--extract=" flycheck-jshint-extract-javascript
8208                     concat flycheck-option-symbol)
8209             "-")
8210   :standard-input t
8211   :error-parser flycheck-parse-checkstyle
8212   :error-filter
8213   (lambda (errors)
8214     (flycheck-remove-error-file-names
8215      "stdin" (flycheck-dequalify-error-ids errors)))
8216   :modes (js-mode js2-mode js3-mode rjsx-mode))
8217
8218 (flycheck-def-args-var flycheck-eslint-args javascript-eslint
8219   :package-version '(flycheck . "32"))
8220
8221 (flycheck-def-option-var flycheck-eslint-rules-directories nil javascript-eslint
8222   "A list of directories with custom rules for ESLint.
8223
8224 The value of this variable is a list of strings, where each
8225 string is a directory with custom rules for ESLint.
8226
8227 Refer to the ESLint manual at URL
8228 `http://eslint.org/docs/user-guide/command-line-interface#--rulesdir'
8229 for more information about the custom directories."
8230   :type '(repeat (directory :tag "Custom rules directory"))
8231   :safe #'flycheck-string-list-p
8232   :package-version '(flycheck . "29"))
8233
8234 (defun flycheck-eslint-config-exists-p ()
8235   "Whether there is a valid eslint config for the current buffer."
8236   (let* ((executable (flycheck-find-checker-executable 'javascript-eslint))
8237          (exitcode (and executable (call-process executable nil nil nil
8238                                                  "--print-config" "."))))
8239     (eq exitcode 0)))
8240
8241 (defun flycheck-parse-eslint (output checker buffer)
8242   "Parse ESLint errors/warnings from JSON OUTPUT.
8243
8244 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
8245 the BUFFER that was checked respectively.
8246
8247 See URL `https://eslint.org' for more information about ESLint."
8248   (mapcar (lambda (err)
8249             (let-alist err
8250               (flycheck-error-new-at
8251                .line
8252                .column
8253                (pcase .severity
8254                  (2 'error)
8255                  (1 'warning)
8256                  (_ 'warning))
8257                .message
8258                :id .ruleId
8259                :checker checker
8260                :buffer buffer
8261                :filename (buffer-file-name buffer))))
8262           (let-alist (caar (flycheck-parse-json output))
8263             .messages)))
8264
8265 (defun flycheck-eslint--find-working-directory (_checker)
8266   "Look for a working directory to run ESLint CHECKER in.
8267
8268 This will be the directory that contains the `node_modules'
8269 directory.  If no such directory is found in the directory
8270 hierarchy, it looks first for `.eslintignore' and then for
8271 `.eslintrc' files to detect the project root."
8272   (let* ((regex-config (concat "\\`\\.eslintrc"
8273                                "\\(\\.\\(js\\|ya?ml\\|json\\)\\)?\\'")))
8274     (when buffer-file-name
8275       (or (locate-dominating-file buffer-file-name "node_modules")
8276           (locate-dominating-file buffer-file-name ".eslintignore")
8277           (locate-dominating-file
8278            (file-name-directory buffer-file-name)
8279            (lambda (directory)
8280              (> (length (directory-files directory nil regex-config t)) 0)))))))
8281
8282 (flycheck-define-checker javascript-eslint
8283   "A Javascript syntax and style checker using eslint.
8284
8285 See URL `https://eslint.org/'."
8286   :command ("eslint" "--format=json"
8287             (option-list "--rulesdir" flycheck-eslint-rules-directories)
8288             (eval flycheck-eslint-args)
8289             "--stdin" "--stdin-filename" source-original)
8290   :standard-input t
8291   :error-parser flycheck-parse-eslint
8292   :enabled (lambda () (flycheck-eslint-config-exists-p))
8293   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode)
8294   :working-directory flycheck-eslint--find-working-directory
8295   :verify
8296   (lambda (_)
8297     (let* ((default-directory
8298              (flycheck-compute-working-directory 'javascript-eslint))
8299            (have-config (flycheck-eslint-config-exists-p)))
8300       (list
8301        (flycheck-verification-result-new
8302         :label "config file"
8303         :message (if have-config "found" "missing or incorrect")
8304         :face (if have-config 'success '(bold error)))))))
8305
8306 (flycheck-define-checker javascript-standard
8307   "A Javascript code and style checker for the (Semi-)Standard Style.
8308
8309 This checker works with `standard' and `semistandard', defaulting
8310 to the former.  To use it with the latter, set
8311 `flycheck-javascript-standard-executable' to `semistandard'.
8312
8313 See URL `https://github.com/standard/standard' and URL
8314 `https://github.com/Flet/semistandard'."
8315   :command ("standard" "--stdin")
8316   :standard-input t
8317   :error-patterns
8318   ((error line-start "  <text>:" line ":" column ":" (message) line-end))
8319   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode))
8320
8321 (flycheck-define-checker json-jsonlint
8322   "A JSON syntax and style checker using jsonlint.
8323
8324 See URL `https://github.com/zaach/jsonlint'."
8325   ;; We can't use standard input for jsonlint, because it doesn't output errors
8326   ;; anymore when using -c -q with standard input :/
8327   :command ("jsonlint" "-c" "-q" source)
8328   :error-patterns
8329   ((error line-start
8330           (file-name)
8331           ": line " line
8332           ", col " column ", "
8333           (message) line-end))
8334   :error-filter
8335   (lambda (errors)
8336     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
8337   :modes json-mode)
8338
8339 (flycheck-define-checker json-python-json
8340   "A JSON syntax checker using Python json.tool module.
8341
8342 See URL `https://docs.python.org/3.5/library/json.html#command-line-interface'."
8343   :command ("python" "-m" "json.tool" source
8344             ;; Send the pretty-printed output to the null device
8345             null-device)
8346   :error-patterns
8347   ((error line-start
8348           (message) ": line " line " column " column
8349           ;; Ignore the rest of the line which shows the char position.
8350           (one-or-more not-newline)
8351           line-end))
8352   :modes json-mode
8353   ;; The JSON parser chokes if the buffer is empty and has no JSON inside
8354   :predicate (lambda () (not (flycheck-buffer-empty-p))))
8355
8356 (flycheck-define-checker jsonnet
8357   "A Jsonnet syntax checker using the jsonnet binary.
8358
8359 See URL `https://jsonnet.org'."
8360   :command ("jsonnet" source-inplace)
8361   :error-patterns
8362   ((error line-start "STATIC ERROR: " (file-name) ":" line ":" column
8363           (zero-or-one (group "-" (one-or-more digit))) ": "
8364           (message) line-end)
8365    (error line-start "RUNTIME ERROR: " (message) "\n"
8366           (one-or-more space) (file-name) ":" (zero-or-one "(")
8367           line ":" column (zero-or-more not-newline) line-end))
8368   :modes jsonnet-mode)
8369
8370 (flycheck-define-checker less
8371   "A LESS syntax checker using lessc.
8372
8373 Requires lessc 1.4 or newer.
8374
8375 See URL `http://lesscss.org'."
8376   :command ("lessc" "--lint" "--no-color"
8377             "-")
8378   :standard-input t
8379   :error-patterns
8380   ((error line-start (one-or-more word) ":"
8381           (message)
8382           " in - on line " line
8383           ", column " column ":"
8384           line-end))
8385   :modes less-css-mode)
8386
8387 (flycheck-define-checker less-stylelint
8388   "A LESS syntax and style checker using stylelint.
8389
8390 See URL `http://stylelint.io/'."
8391   :command ("stylelint"
8392             (eval flycheck-stylelint-args)
8393             "--syntax" "less"
8394             (option-flag "--quiet" flycheck-stylelint-quiet)
8395             (config-file "--config" flycheck-stylelintrc))
8396   :standard-input t
8397   :error-parser flycheck-parse-stylelint
8398   :modes (less-css-mode))
8399
8400 (flycheck-define-checker llvm-llc
8401   "Flycheck LLVM IR checker using llc.
8402
8403 See URL `http://llvm.org/docs/CommandGuide/llc.html'."
8404   :command ("llc" "-o" null-device source)
8405   :error-patterns
8406   ((error line-start
8407           ;; llc prints the executable path
8408           (zero-or-one (minimal-match (one-or-more not-newline)) ": ")
8409           (file-name) ":" line ":" column ": error: " (message)
8410           line-end))
8411   :error-filter
8412   (lambda (errors)
8413     ;; sanitize errors occurring in inline assembly
8414     (flycheck-sanitize-errors
8415      (flycheck-remove-error-file-names "<inline asm>" errors)))
8416   :modes llvm-mode)
8417
8418 (flycheck-def-config-file-var flycheck-luacheckrc lua-luacheck ".luacheckrc"
8419   :safe #'stringp)
8420
8421 (flycheck-def-option-var flycheck-luacheck-standards nil lua-luacheck
8422   "The standards to use in luacheck.
8423
8424 The value of this variable is either a list of strings denoting
8425 the standards to use, or nil to pass nothing to luacheck.  When
8426 non-nil, pass the standards via one or more `--std' options."
8427   :type '(choice (const :tag "Default" nil)
8428                  (repeat :tag "Custom standards"
8429                          (string :tag "Standard name")))
8430   :safe #'flycheck-string-list-p)
8431 (make-variable-buffer-local 'flycheck-luacheck-standards)
8432
8433 (flycheck-define-checker lua-luacheck
8434   "A Lua syntax checker using luacheck.
8435
8436 See URL `https://github.com/mpeterv/luacheck'."
8437   :command ("luacheck"
8438             "--formatter" "plain"
8439             "--codes"                   ; Show warning codes
8440             "--no-color"
8441             (option-list "--std" flycheck-luacheck-standards)
8442             (config-file "--config" flycheck-luacheckrc)
8443             "--filename" source-original
8444             ;; Read from standard input
8445             "-")
8446   :standard-input t
8447   :error-patterns
8448   ((warning line-start
8449             (optional (file-name))
8450             ":" line ":" column
8451             ": (" (id "W" (one-or-more digit)) ") "
8452             (message) line-end)
8453    (error line-start
8454           (optional (file-name))
8455           ":" line ":" column ":"
8456           ;; `luacheck' before 0.11.0 did not output codes for errors, hence
8457           ;; the ID is optional here
8458           (optional " (" (id "E" (one-or-more digit)) ") ")
8459           (message) line-end))
8460   :modes lua-mode)
8461
8462 (flycheck-define-checker lua
8463   "A Lua syntax checker using the Lua compiler.
8464
8465 See URL `http://www.lua.org/'."
8466   :command ("luac" "-p" "-")
8467   :standard-input t
8468   :error-patterns
8469   ((error line-start
8470           ;; Skip the name of the luac executable.
8471           (minimal-match (zero-or-more not-newline))
8472           ": stdin:" line ": " (message) line-end))
8473   :modes lua-mode)
8474
8475 (flycheck-def-option-var flycheck-perl-include-path nil perl
8476   "A list of include directories for Perl.
8477
8478 The value of this variable is a list of strings, where each
8479 string is a directory to add to the include path of Perl.
8480 Relative paths are relative to the file being checked."
8481   :type '(repeat (directory :tag "Include directory"))
8482   :safe #'flycheck-string-list-p
8483   :package-version '(flycheck . "0.24"))
8484
8485 (flycheck-def-option-var flycheck-perl-module-list nil perl
8486   "A list of modules to use for Perl.
8487
8488 The value of this variable is a list of strings, where each
8489 string is a module to 'use' in Perl."
8490   :type '(repeat :tag "Module")
8491   :safe #'flycheck-string-list-p
8492   :package-version '(flycheck . "32"))
8493
8494 (flycheck-define-checker perl
8495   "A Perl syntax checker using the Perl interpreter.
8496
8497 See URL `https://www.perl.org'."
8498   :command ("perl" "-w" "-c"
8499             (option-list "-I" flycheck-perl-include-path)
8500             (option-list "-M" flycheck-perl-module-list concat))
8501   :standard-input t
8502   :error-patterns
8503   ((error line-start (minimal-match (message))
8504           " at - line " line
8505           (or "." (and ", " (zero-or-more not-newline))) line-end))
8506   :modes (perl-mode cperl-mode)
8507   :next-checkers (perl-perlcritic))
8508
8509 (flycheck-def-option-var flycheck-perlcritic-severity nil perl-perlcritic
8510   "The message severity for Perl Critic.
8511
8512 The value of this variable is a severity level as integer, for
8513 the `--severity' option to Perl Critic."
8514   :type '(integer :tag "Severity level")
8515   :safe #'integerp
8516   :package-version '(flycheck . "0.18"))
8517
8518 (flycheck-def-config-file-var flycheck-perlcriticrc perl-perlcritic
8519                               ".perlcriticrc"
8520   :safe #'stringp
8521   :package-version '(flycheck . "26"))
8522
8523 (flycheck-define-checker perl-perlcritic
8524   "A Perl syntax checker using Perl::Critic.
8525
8526 See URL `https://metacpan.org/pod/Perl::Critic'."
8527   :command ("perlcritic" "--no-color" "--verbose" "%f/%l/%c/%s/%p/%m (%e)\n"
8528             (config-file "--profile" flycheck-perlcriticrc)
8529             (option "--severity" flycheck-perlcritic-severity nil
8530                     flycheck-option-int))
8531   :standard-input t
8532   :error-patterns
8533   ((info line-start
8534          "STDIN/" line "/" column "/" (any "1") "/"
8535          (id (one-or-more (not (any "/")))) "/" (message)
8536          line-end)
8537    (warning line-start
8538             "STDIN/" line "/" column "/" (any "234") "/"
8539             (id (one-or-more (not (any "/")))) "/" (message)
8540             line-end)
8541    (error line-start
8542           "STDIN/" line "/" column "/" (any "5") "/"
8543           (id (one-or-more (not (any "/")))) "/" (message)
8544           line-end))
8545   :modes (cperl-mode perl-mode))
8546
8547 (flycheck-define-checker php
8548   "A PHP syntax checker using the PHP command line interpreter.
8549
8550 See URL `http://php.net/manual/en/features.commandline.php'."
8551   :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1"
8552             "-d" "log_errors=0" source)
8553   :error-patterns
8554   ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") " "
8555           (message) " in " (file-name) " on line " line line-end))
8556   :modes (php-mode php+-mode)
8557   :next-checkers ((warning . php-phpmd)
8558                   (warning . php-phpcs)))
8559
8560 (flycheck-def-option-var flycheck-phpmd-rulesets
8561     '("cleancode" "codesize" "controversial" "design" "naming" "unusedcode")
8562     php-phpmd
8563   "The rule sets for PHP Mess Detector.
8564
8565 Set default rule sets and custom rule set files.
8566
8567 See section \"Using multiple rule sets\" in the PHP Mess Detector
8568 manual at URL `https://phpmd.org/documentation/index.html'."
8569   :type '(repeat :tag "rule sets"
8570                  (string :tag "A filename or rule set"))
8571   :safe #'flycheck-string-list-p)
8572
8573 (flycheck-define-checker php-phpmd
8574   "A PHP style checker using PHP Mess Detector.
8575
8576 See URL `https://phpmd.org/'."
8577   :command ("phpmd" source "xml"
8578             (eval (flycheck-option-comma-separated-list
8579                    flycheck-phpmd-rulesets)))
8580   :error-parser flycheck-parse-phpmd
8581   :modes (php-mode php+-mode)
8582   :next-checkers (php-phpcs))
8583
8584 (flycheck-def-option-var flycheck-phpcs-standard nil php-phpcs
8585   "The coding standard for PHP CodeSniffer.
8586
8587 When nil, use the default standard from the global PHP
8588 CodeSniffer configuration.  When set to a string, pass the string
8589 to PHP CodeSniffer which will interpret it as name as a standard,
8590 or as path to a standard specification."
8591   :type '(choice (const :tag "Default standard" nil)
8592                  (string :tag "Standard name or file"))
8593   :safe #'stringp)
8594
8595 (flycheck-define-checker php-phpcs
8596   "A PHP style checker using PHP Code Sniffer.
8597
8598 Needs PHP Code Sniffer 2.6 or newer.
8599
8600 See URL `http://pear.php.net/package/PHP_CodeSniffer/'."
8601   :command ("phpcs" "--report=checkstyle"
8602             ;; Use -q flag to force quiet mode
8603             ;; Quiet mode prevents errors from extra output when phpcs has
8604             ;; been configured with show_progress enabled
8605             "-q"
8606             (option "--standard=" flycheck-phpcs-standard concat)
8607             ;; Pass original file name to phpcs.  We need to concat explicitly
8608             ;; here, because phpcs really insists to get option and argument as
8609             ;; a single command line argument :|
8610             (eval (when (buffer-file-name)
8611                     (concat "--stdin-path=" (buffer-file-name))))
8612             ;; Read from standard input
8613             "-")
8614   :standard-input t
8615   :error-parser flycheck-parse-checkstyle
8616   :error-filter
8617   (lambda (errors)
8618     (flycheck-sanitize-errors
8619      (flycheck-remove-error-file-names "STDIN" errors)))
8620   :modes (php-mode php+-mode)
8621   ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
8622   ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
8623   :predicate (lambda () (not (flycheck-buffer-empty-p))))
8624
8625 (flycheck-define-checker processing
8626   "Processing command line tool.
8627
8628 See https://github.com/processing/processing/wiki/Command-Line"
8629   :command ("processing-java" "--force"
8630             ;; Don't change the order of these arguments, processing is pretty
8631             ;; picky
8632             (eval (concat "--sketch=" (file-name-directory (buffer-file-name))))
8633             (eval (concat "--output=" (flycheck-temp-dir-system)))
8634             "--build")
8635   :error-patterns
8636   ((error line-start (file-name) ":" line ":" column
8637           (zero-or-more (or digit ":")) (message) line-end))
8638   :modes processing-mode
8639   ;; This syntax checker needs a file name
8640   :predicate (lambda () (buffer-file-name)))
8641
8642 (defun flycheck-proselint-parse-errors (output checker buffer)
8643   "Parse proselint json output errors from OUTPUT.
8644
8645 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
8646 the BUFFER that was checked respectively.
8647
8648 See URL `http://proselint.com/' for more information about proselint."
8649   (mapcar (lambda (err)
8650             (let-alist err
8651               (flycheck-error-new-at
8652                .line
8653                .column
8654                (pcase .severity
8655                  (`"suggestion" 'info)
8656                  (`"warning"    'warning)
8657                  (`"error"      'error)
8658                  ;; Default to error
8659                  (_             'error))
8660                .message
8661                :id .check
8662                :buffer buffer
8663                :checker checker)))
8664           (let-alist (car (flycheck-parse-json output))
8665             .data.errors)))
8666
8667 (flycheck-define-checker proselint
8668   "Flycheck checker using Proselint.
8669
8670 See URL `http://proselint.com/'."
8671   :command ("proselint" "--json" "-")
8672   :standard-input t
8673   :error-parser flycheck-proselint-parse-errors
8674   :modes (text-mode markdown-mode gfm-mode message-mode))
8675
8676 (flycheck-define-checker protobuf-protoc
8677   "A protobuf syntax checker using the protoc compiler.
8678
8679 See URL `https://developers.google.com/protocol-buffers/'."
8680   :command ("protoc" "--error_format" "gcc"
8681             (eval (concat "--java_out=" (flycheck-temp-dir-system)))
8682             ;; Add the file directory of protobuf path to resolve import
8683             ;; directives
8684             (eval (concat "--proto_path="
8685                           (file-name-directory (buffer-file-name))))
8686             source-inplace)
8687   :error-patterns
8688   ((info line-start (file-name) ":" line ":" column
8689          ": note: " (message) line-end)
8690    (error line-start (file-name) ":" line ":" column
8691           ": " (message) line-end)
8692    (error line-start
8693           (message "In file included from") " " (file-name) ":" line ":"
8694           column ":" line-end))
8695   :modes protobuf-mode
8696   :predicate (lambda () (buffer-file-name)))
8697
8698 (flycheck-define-checker pug
8699   "A Pug syntax checker using the pug compiler.
8700
8701 See URL `https://pugjs.org/'."
8702   :command ("pug" "-p" (eval (expand-file-name (buffer-file-name))))
8703   :standard-input t
8704   :error-patterns
8705   ;; errors with includes/extends (e.g. missing files)
8706   ((error "Error: " (message) (zero-or-more not-newline) "\n"
8707           (zero-or-more not-newline) "at "
8708           (zero-or-more not-newline) " line " line)
8709    ;; syntax/runtime errors (e.g. type errors, bad indentation, etc.)
8710    (error line-start
8711           (optional "Type") "Error: "  (file-name) ":"
8712           line (optional ":" column)
8713           (zero-or-more not-newline) "\n"
8714           (one-or-more (or (zero-or-more not-newline) "|"
8715                            (zero-or-more not-newline) "\n")
8716                        (zero-or-more "-")  (zero-or-more not-newline) "|"
8717                        (zero-or-more not-newline) "\n")
8718           (zero-or-more not-newline) "\n"
8719           (one-or-more
8720            (zero-or-more not-newline) "|"
8721            (zero-or-more not-newline) "\n")
8722           (zero-or-more not-newline) "\n"
8723           (message)
8724           line-end))
8725   :modes pug-mode)
8726
8727 (flycheck-define-checker puppet-parser
8728   "A Puppet DSL syntax checker using puppet's own parser.
8729
8730 See URL `https://puppet.com/'."
8731   :command ("puppet" "parser" "validate" "--color=false")
8732   :standard-input t
8733   :error-patterns
8734   (
8735    ;; Patterns for Puppet 4
8736    (error line-start "Error: Could not parse for environment "
8737           (one-or-more (in "a-z" "0-9" "_")) ":"
8738           (message) "(line: " line ", column: " column ")" line-end)
8739    ;; Errors from Puppet < 4
8740    (error line-start "Error: Could not parse for environment "
8741           (one-or-more (in "a-z" "0-9" "_")) ":"
8742           (message (minimal-match (one-or-more anything)))
8743           " at line " line line-end)
8744    (error line-start
8745           ;; Skip over the path of the Puppet executable
8746           (minimal-match (zero-or-more not-newline))
8747           ": Could not parse for environment " (one-or-more word)
8748           ": " (message (minimal-match (zero-or-more anything)))
8749           " at " (file-name "/" (zero-or-more not-newline)) ":" line line-end))
8750   :modes puppet-mode
8751   :next-checkers ((warning . puppet-lint)))
8752
8753 (flycheck-def-config-file-var flycheck-puppet-lint-rc puppet-lint
8754                               ".puppet-lint.rc"
8755   :safe #'stringp
8756   :package-version '(flycheck . "26"))
8757
8758 (flycheck-def-option-var flycheck-puppet-lint-disabled-checks nil puppet-lint
8759   "Disabled checkers for `puppet-lint'.
8760
8761 The value of this variable is a list of strings, where each
8762 string is the name of a check to disable (e.g. \"80chars\" or
8763 \"double_quoted_strings\").
8764
8765 See URL `http://puppet-lint.com/checks/' for a list of all checks
8766 and their names."
8767   :type '(repeat (string :tag "Check Name"))
8768   :package-version '(flycheck . "26"))
8769
8770 (defun flycheck-puppet-lint-disabled-arg-name (check)
8771   "Create an argument to disable a puppetlint CHECK."
8772   (concat "--no-" check "-check"))
8773
8774 (flycheck-define-checker puppet-lint
8775   "A Puppet DSL style checker using puppet-lint.
8776
8777 See URL `http://puppet-lint.com/'."
8778   ;; We must check the original file, because Puppetlint is quite picky on the
8779   ;; names of files and there place in the directory structure, to comply with
8780   ;; Puppet's autoload directory layout.  For instance, a class foo::bar is
8781   ;; required to be in a file foo/bar.pp.  Any other place, such as a Flycheck
8782   ;; temporary file will cause an error.
8783   :command ("puppet-lint"
8784             (config-file "--config" flycheck-puppet-lint-rc)
8785             "--log-format"
8786             "%{path}:%{line}:%{kind}: %{message} (%{check})"
8787             (option-list "" flycheck-puppet-lint-disabled-checks concat
8788                          flycheck-puppet-lint-disabled-arg-name)
8789             source-original)
8790   :error-patterns
8791   ((warning line-start (file-name) ":" line ":warning: " (message) line-end)
8792    (error line-start (file-name) ":" line ":error: " (message) line-end))
8793   :modes puppet-mode
8794   ;; Since we check the original file, we can only use this syntax checker if
8795   ;; the buffer is actually linked to a file, and if it is not modified.
8796   :predicate flycheck-buffer-saved-p)
8797
8798 (defun flycheck-python-find-module (checker module)
8799   "Check if a Python MODULE is available.
8800 CHECKER's executable is assumed to be a Python REPL."
8801   (-when-let* ((py (flycheck-find-checker-executable checker))
8802                (script (concat "import sys; sys.path.pop(0);"
8803                                (format "import %s; print(%s.__file__)"
8804                                        module module))))
8805     (with-temp-buffer
8806       (and (eq (ignore-errors (call-process py nil t nil "-c" script)) 0)
8807            (string-trim (buffer-string))))))
8808
8809 (defun flycheck-python-needs-module-p (checker)
8810   "Determines whether CHECKER needs to be invoked through Python.
8811 Previous versions of Flycheck called pylint and flake8 directly;
8812 this check ensures that we don't break existing code."
8813   (not (string-match-p (rx (or "pylint" "flake8")
8814                            (or "-script.pyw" ".exe" ".bat" "")
8815                            eos)
8816                        (flycheck-checker-executable checker))))
8817
8818 (defun flycheck-python-verify-module (checker module)
8819   "Verify that a Python MODULE is available.
8820 Return nil if CHECKER's executable is not a Python REPL.  This
8821 function's is suitable for a checker's :verify."
8822   (when (flycheck-python-needs-module-p checker)
8823     (let ((mod-path (flycheck-python-find-module checker module)))
8824       (list (flycheck-verification-result-new
8825              :label (format "`%s' module" module)
8826              :message (if mod-path (format "Found at %S" mod-path) "Missing")
8827              :face (if mod-path 'success '(bold error)))))))
8828
8829 (defun flycheck-python-module-args (checker module-name)
8830   "Compute arguments to pass to CHECKER's executable to run MODULE-NAME.
8831 Return nil if CHECKER's executable is not a Python REPL.
8832 Otherwise, return a list starting with -c (-m is not enough
8833 because it adds the current directory to Python's path)."
8834   (when (flycheck-python-needs-module-p checker)
8835     `("-c" ,(concat "import sys,runpy;sys.path.pop(0);"
8836                     (format "runpy.run_module(%S)" module-name)))))
8837
8838 (flycheck-def-config-file-var flycheck-flake8rc python-flake8 ".flake8rc"
8839   :safe #'stringp)
8840
8841 (flycheck-def-option-var flycheck-flake8-error-level-alist
8842     '(("^E9.*$"  . error)               ; Syntax errors from pep8
8843       ("^F82.*$" . error)               ; undefined variables from pyflakes
8844       ("^F83.*$" . error)               ; Duplicate arguments from flake8
8845       ("^D.*$"   . info)                ; Docstring issues from flake8-pep257
8846       ("^N.*$"   . info)                ; Naming issues from pep8-naming
8847       )
8848     python-flake8
8849   "An alist mapping flake8 error IDs to Flycheck error levels.
8850
8851 Each item in this list is a cons cell `(PATTERN . LEVEL)' where
8852 PATTERN is a regular expression matched against the error ID, and
8853 LEVEL is a Flycheck error level symbol.
8854
8855 Each PATTERN is matched in the order of appearance in this list
8856 against the error ID.  If it matches the ID, the level of the
8857 corresponding error is set to LEVEL.  An error that is not
8858 matched by any PATTERN defaults to warning level.
8859
8860 The default value of this option matches errors from flake8
8861 itself and from the following flake8 plugins:
8862
8863 - pep8-naming
8864 - flake8-pep257
8865
8866 You may add your own mappings to this option in order to support
8867 further flake8 plugins."
8868   :type '(repeat (cons (regexp :tag "Error ID pattern")
8869                        (symbol :tag "Error level")))
8870   :package-version '(flycheck . "0.22"))
8871
8872 (flycheck-def-option-var flycheck-flake8-maximum-complexity nil python-flake8
8873   "The maximum McCabe complexity of methods.
8874
8875 If nil, do not check the complexity of methods.  If set to an
8876 integer, report any complexity greater than the value of this
8877 variable as warning.
8878
8879 If set to an integer, this variable overrules any similar setting
8880 in the configuration file denoted by `flycheck-flake8rc'."
8881   :type '(choice (const :tag "Do not check McCabe complexity" nil)
8882                  (integer :tag "Maximum complexity"))
8883   :safe #'integerp)
8884
8885 (flycheck-def-option-var flycheck-flake8-maximum-line-length nil python-flake8
8886   "The maximum length of lines.
8887
8888 If set to an integer, the value of this variable denotes the
8889 maximum length of lines, overruling any similar setting in the
8890 configuration file denoted by `flycheck-flake8rc'.  An error will
8891 be reported for any line longer than the value of this variable.
8892
8893 If set to nil, use the maximum line length from the configuration
8894 file denoted by `flycheck-flake8rc', or the PEP 8 recommendation
8895 of 79 characters if there is no configuration with this setting."
8896   :type '(choice (const :tag "Default value")
8897                  (integer :tag "Maximum line length in characters"))
8898   :safe #'integerp)
8899
8900 (defun flycheck-flake8-fix-error-level (err)
8901   "Fix the error level of ERR.
8902
8903 Update the error level of ERR according to
8904 `flycheck-flake8-error-level-alist'."
8905   (pcase-dolist (`(,pattern . ,level) flycheck-flake8-error-level-alist)
8906     (when (string-match-p pattern (flycheck-error-id err))
8907       (setf (flycheck-error-level err) level)))
8908   err)
8909
8910 (flycheck-define-checker python-flake8
8911   "A Python syntax and style checker using Flake8.
8912
8913 Requires Flake8 3.0 or newer. See URL
8914 `https://flake8.readthedocs.io/'."
8915   ;; Not calling flake8 directly makes it easier to switch between different
8916   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
8917   :command ("python"
8918             (eval (flycheck-python-module-args 'python-flake8 "flake8"))
8919             "--format=default"
8920             (config-file "--config" flycheck-flake8rc)
8921             (option "--max-complexity" flycheck-flake8-maximum-complexity nil
8922                     flycheck-option-int)
8923             (option "--max-line-length" flycheck-flake8-maximum-line-length nil
8924                     flycheck-option-int)
8925             "-")
8926   :standard-input t
8927   :error-filter (lambda (errors)
8928                   (let ((errors (flycheck-sanitize-errors errors)))
8929                     (seq-map #'flycheck-flake8-fix-error-level errors)))
8930   :error-patterns
8931   ((warning line-start
8932             "stdin:" line ":" (optional column ":") " "
8933             (id (one-or-more (any alpha)) (one-or-more digit)) " "
8934             (message (one-or-more not-newline))
8935             line-end))
8936   :enabled (lambda ()
8937              (or (not (flycheck-python-needs-module-p 'python-flake8))
8938                  (flycheck-python-find-module 'python-flake8 "flake8")))
8939   :verify (lambda (_) (flycheck-python-verify-module 'python-flake8 "flake8"))
8940   :modes python-mode)
8941
8942 (flycheck-def-config-file-var flycheck-pylintrc python-pylint ".pylintrc"
8943   :safe #'stringp)
8944
8945 (flycheck-def-option-var flycheck-pylint-use-symbolic-id t python-pylint
8946   "Whether to use pylint message symbols or message codes.
8947
8948 A pylint message has both an opaque identifying code (such as `F0401') and a
8949 more meaningful symbolic code (such as `import-error').  This option governs
8950 which should be used and reported to the user."
8951   :type 'boolean
8952   :safe #'booleanp
8953   :package-version '(flycheck . "0.25"))
8954
8955 (flycheck-define-checker python-pylint
8956   "A Python syntax and style checker using Pylint.
8957
8958 This syntax checker requires Pylint 1.0 or newer.
8959
8960 See URL `https://www.pylint.org/'."
8961   ;; --reports=n disables the scoring report.
8962   ;; Not calling pylint directly makes it easier to switch between different
8963   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
8964   :command ("python"
8965             (eval (flycheck-python-module-args 'python-pylint "pylint"))
8966             "--reports=n"
8967             "--output-format=text"
8968             (eval (if flycheck-pylint-use-symbolic-id
8969                       "--msg-template={path}:{line}:{column}:{C}:{symbol}:{msg}"
8970                     "--msg-template={path}:{line}:{column}:{C}:{msg_id}:{msg}"))
8971             (config-file "--rcfile=" flycheck-pylintrc concat)
8972             ;; Need `source-inplace' for relative imports (e.g. `from .foo
8973             ;; import bar'), see https://github.com/flycheck/flycheck/issues/280
8974             source-inplace)
8975   :error-filter
8976   (lambda (errors)
8977     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
8978   :error-patterns
8979   ((error line-start (file-name) ":" line ":" column ":"
8980           (or "E" "F") ":"
8981           (id (one-or-more (not (any ":")))) ":"
8982           (message) line-end)
8983    (warning line-start (file-name) ":" line ":" column ":"
8984             (or "W" "R") ":"
8985             (id (one-or-more (not (any ":")))) ":"
8986             (message) line-end)
8987    (info line-start (file-name) ":" line ":" column ":"
8988          (or "C" "I") ":"
8989          (id (one-or-more (not (any ":")))) ":"
8990          (message) line-end))
8991   :enabled (lambda ()
8992              (or (not (flycheck-python-needs-module-p 'python-pylint))
8993                  (flycheck-python-find-module 'python-pylint "pylint")))
8994   :verify (lambda (_) (flycheck-python-verify-module 'python-pylint "pylint"))
8995   :modes python-mode)
8996
8997 (flycheck-define-checker python-pycompile
8998   "A Python syntax checker using Python's builtin compiler.
8999
9000 See URL `https://docs.python.org/3.4/library/py_compile.html'."
9001   :command ("python" "-m" "py_compile" source)
9002   :error-patterns
9003   ;; Python 2.7
9004   ((error line-start "  File \"" (file-name) "\", line " line "\n"
9005           (>= 2 (zero-or-more not-newline) "\n")
9006           "SyntaxError: " (message) line-end)
9007    (error line-start "Sorry: IndentationError: "
9008           (message) "(" (file-name) ", line " line ")"
9009           line-end)
9010    ;; 2.6
9011    (error line-start "SyntaxError: ('" (message (one-or-more (not (any "'"))))
9012           "', ('" (file-name (one-or-more (not (any "'")))) "', "
9013           line ", " column ", " (one-or-more not-newline) line-end))
9014   :modes python-mode)
9015
9016 (flycheck-def-config-file-var flycheck-python-mypy-ini python-mypy
9017                               "mypy.ini"
9018   :safe #'stringp)
9019
9020 (flycheck-def-option-var flycheck-python-mypy-cache-dir nil python-mypy
9021   "Directory used to write .mypy_cache directories."
9022   :safe #'stringp
9023   :type '(choice
9024           (const :tag "Write to the working directory" nil)
9025           (const :tag "Never write .mypy_cache directories" null-device)
9026           (string :tag "Path"))
9027   :package-version '(flycheck . "32"))
9028
9029 (flycheck-define-checker python-mypy
9030   "Mypy syntax and type checker.  Requires mypy>=0.580.
9031
9032 See URL `http://mypy-lang.org/'."
9033   :command ("mypy"
9034             "--show-column-numbers"
9035             (config-file "--config-file" flycheck-python-mypy-ini)
9036             (option "--cache-dir" flycheck-python-mypy-cache-dir)
9037             source-original)
9038   :error-patterns
9039   ((error line-start (file-name) ":" line ":" column ": error:" (message)
9040           line-end)
9041    (warning line-start (file-name) ":" line ":" column  ": warning:" (message)
9042             line-end))
9043   :modes python-mode
9044   ;; Ensure the file is saved, to work around
9045   ;; https://github.com/python/mypy/issues/4746.
9046   :predicate flycheck-buffer-saved-p
9047   :next-checkers '(t . python-flake8))
9048
9049 (flycheck-def-option-var flycheck-lintr-caching t r-lintr
9050   "Whether to enable caching in lintr.
9051
9052 By default, lintr caches all expressions in a file and re-checks
9053 only those that have changed.  Setting this option to nil
9054 disables caching in case there are problems."
9055   :type 'boolean
9056   :safe #'booleanp
9057   :package-version '(flycheck . "0.23"))
9058
9059 (flycheck-def-option-var flycheck-lintr-linters "default_linters" r-lintr
9060   "Linters to use with lintr.
9061
9062 The value of this variable is a string containing an R
9063 expression, which selects linters for lintr."
9064   :type 'string
9065   :risky t
9066   :package-version '(flycheck . "0.23"))
9067
9068 (defun flycheck-r-has-lintr (R)
9069   "Whether R has installed the `lintr' library."
9070   (with-temp-buffer
9071     (let ((process-environment (append '("LC_ALL=C") process-environment)))
9072       (call-process R nil t nil
9073                     "--slave" "--restore" "--no-save" "-e"
9074                     "library('lintr')")
9075       (goto-char (point-min))
9076       (not (re-search-forward "there is no package called 'lintr'"
9077                               nil 'no-error)))))
9078
9079 (flycheck-define-checker r-lintr
9080   "An R style and syntax checker using the lintr package.
9081
9082 See URL `https://github.com/jimhester/lintr'."
9083   :command ("R" "--slave" "--restore" "--no-save" "-e"
9084             (eval (concat
9085                    "library(lintr);"
9086                    "try(lint(commandArgs(TRUE)"
9087                    ", cache=" (if flycheck-lintr-caching "TRUE" "FALSE")
9088                    ", " flycheck-lintr-linters
9089                    "))"))
9090             "--args" source)
9091   :error-patterns
9092   ((info line-start (file-name) ":" line ":" column ": style: " (message)
9093          line-end)
9094    (warning line-start (file-name) ":" line ":" column ": warning: " (message)
9095             line-end)
9096    (error line-start (file-name) ":" line ":" column ": error: " (message)
9097           line-end))
9098   :modes ess-mode
9099   :predicate
9100   ;; Don't check ESS files which do not contain R, and make sure that lintr is
9101   ;; actually available
9102   (lambda ()
9103     (and (equal ess-language "S")
9104          (flycheck-r-has-lintr (flycheck-checker-executable 'r-lintr))))
9105   :verify (lambda (checker)
9106             (let ((has-lintr (flycheck-r-has-lintr
9107                               (flycheck-checker-executable checker))))
9108               (list
9109                (flycheck-verification-result-new
9110                 :label "lintr library"
9111                 :message (if has-lintr "present" "missing")
9112                 :face (if has-lintr 'success '(bold error)))))))
9113
9114 (defun flycheck-racket-has-expand-p (checker)
9115   "Whether the executable of CHECKER provides the `expand' command."
9116   (let ((raco (flycheck-find-checker-executable checker)))
9117     (when raco
9118       (with-temp-buffer
9119         (call-process raco nil t nil "expand")
9120         (goto-char (point-min))
9121         (not (looking-at-p (rx bol (1+ not-newline)
9122                                "Unrecognized command: expand"
9123                                eol)))))))
9124
9125 (flycheck-define-checker racket
9126   "A Racket syntax checker with `raco expand'.
9127
9128 The `compiler-lib' racket package is required for this syntax
9129 checker.
9130
9131 See URL `https://racket-lang.org/'."
9132   :command ("raco" "expand" source-inplace)
9133   :predicate
9134   (lambda ()
9135     (and (or (not (eq major-mode 'scheme-mode))
9136              ;; In `scheme-mode' we must check the current Scheme implementation
9137              ;; being used
9138              (and (boundp 'geiser-impl--implementation)
9139                   (eq geiser-impl--implementation 'racket)))
9140          (flycheck-racket-has-expand-p 'racket)))
9141   :verify
9142   (lambda (checker)
9143     (let ((has-expand (flycheck-racket-has-expand-p checker))
9144           (in-scheme-mode (eq major-mode 'scheme-mode))
9145           (geiser-impl (bound-and-true-p geiser-impl--implementation)))
9146       (list
9147        (flycheck-verification-result-new
9148         :label "compiler-lib package"
9149         :message (if has-expand "present" "missing")
9150         :face (if has-expand 'success '(bold error)))
9151        (flycheck-verification-result-new
9152         :label "Geiser Implementation"
9153         :message (cond
9154                   ((not in-scheme-mode) "Using Racket Mode")
9155                   ((eq geiser-impl 'racket) "Racket")
9156                   (geiser-impl (format "Other: %s" geiser-impl))
9157                   (t "Geiser not active"))
9158         :face (cond
9159                ((or (not in-scheme-mode) (eq geiser-impl 'racket)) 'success)
9160                (t '(bold error)))))))
9161   :error-filter
9162   (lambda (errors)
9163     (flycheck-sanitize-errors
9164      (flycheck-increment-error-columns
9165       (seq-remove
9166        (lambda (err)
9167          (string=
9168           "/usr/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt"
9169           (flycheck-error-filename err)))
9170        errors))))
9171   :error-patterns
9172   ((error line-start (zero-or-more space)
9173           (file-name) ":" line ":" column ":" (message) line-end))
9174   :modes (racket-mode scheme-mode))
9175
9176 (flycheck-define-checker rpm-rpmlint
9177   "A RPM SPEC file syntax checker using rpmlint.
9178
9179 See URL `https://sourceforge.net/projects/rpmlint/'."
9180   :command ("rpmlint" source)
9181   :error-patterns
9182   ((error line-start
9183           (file-name) ":" (optional line ":") " E: " (message)
9184           line-end)
9185    (warning line-start
9186             (file-name) ":" (optional line ":") " W: " (message)
9187             line-end))
9188   :error-filter
9189   ;; Add fake line numbers if they are missing in the lint output
9190   (lambda (errors)
9191     (dolist (err errors)
9192       (unless (flycheck-error-line err)
9193         (setf (flycheck-error-line err) 1)))
9194     errors)
9195   :error-explainer
9196   (lambda (error)
9197     (-when-let* ((error-message (flycheck-error-message error))
9198                  (message-id (save-match-data
9199                                (string-match "\\([^ ]+\\)" error-message)
9200                                (match-string 1 error-message))))
9201       (with-output-to-string
9202         (call-process "rpmlint" nil standard-output nil "-I" message-id))))
9203   :modes (sh-mode rpm-spec-mode)
9204   :predicate (lambda () (or (not (eq major-mode 'sh-mode))
9205                             ;; In `sh-mode', we need the proper shell
9206                             (eq sh-shell 'rpm))))
9207
9208 (flycheck-def-config-file-var flycheck-markdown-markdownlint-cli-config
9209     markdown-markdownlint-cli nil
9210   :safe #'stringp
9211   :package-version '(flycheck . "32"))
9212
9213 (flycheck-define-checker markdown-markdownlint-cli
9214   "Markdown checker using markdownlint-cli.
9215
9216 See URL `https://github.com/igorshubovych/markdownlint-cli'."
9217   :command ("markdownlint"
9218             (config-file "--config" flycheck-markdown-markdownlint-cli-config)
9219             source)
9220   :error-patterns
9221   ((error line-start
9222           (file-name) ": " line ": " (id (one-or-more (not (any space))))
9223           " " (message) line-end))
9224   :error-filter
9225   (lambda (errors)
9226     (flycheck-sanitize-errors
9227      (flycheck-remove-error-file-names "(string)" errors)))
9228   :modes (markdown-mode gfm-mode))
9229
9230 (flycheck-def-option-var flycheck-markdown-mdl-rules nil markdown-mdl
9231   "Rules to enable for mdl.
9232
9233 The value of this variable is a list of strings each of which is
9234 the name of a rule to enable.
9235
9236 By default all rules are enabled.
9237
9238 See URL `https://git.io/vhi2t'."
9239   :type '(repeat :tag "Enabled rules"
9240                  (string :tag "rule name"))
9241   :safe #'flycheck-string-list-p
9242   :package-version '(flycheck . "27"))
9243
9244 (flycheck-def-option-var flycheck-markdown-mdl-tags nil markdown-mdl
9245   "Rule tags to enable for mdl.
9246
9247 The value of this variable is a list of strings each of which is
9248 the name of a rule tag.  Only rules with these tags are enabled.
9249
9250 By default all rules are enabled.
9251
9252 See URL `https://git.io/vhi2t'."
9253   :type '(repeat :tag "Enabled tags"
9254                  (string :tag "tag name"))
9255   :safe #'flycheck-string-list-p
9256   :package-version '(flycheck . "27"))
9257
9258 (flycheck-def-config-file-var flycheck-markdown-mdl-style markdown-mdl nil
9259   :safe #'stringp
9260   :package-version '(flycheck . "27"))
9261
9262 (flycheck-define-checker markdown-mdl
9263   "Markdown checker using mdl.
9264
9265 See URL `https://github.com/markdownlint/markdownlint'."
9266   :command ("mdl"
9267             (config-file "--style" flycheck-markdown-mdl-style)
9268             (option "--tags=" flycheck-markdown-mdl-rules concat
9269                     flycheck-option-comma-separated-list)
9270             (option "--rules=" flycheck-markdown-mdl-rules concat
9271                     flycheck-option-comma-separated-list))
9272   :standard-input t
9273   :error-patterns
9274   ((error line-start
9275           (file-name) ":" line ": " (id (one-or-more alnum)) " " (message)
9276           line-end))
9277   :error-filter
9278   (lambda (errors)
9279     (flycheck-sanitize-errors
9280      (flycheck-remove-error-file-names "(stdin)" errors)))
9281   :modes (markdown-mode gfm-mode))
9282
9283 (flycheck-define-checker nix
9284   "Nix checker using nix-instantiate.
9285
9286 See URL `https://nixos.org/nix/manual/#sec-nix-instantiate'."
9287   :command ("nix-instantiate" "--parse" "-")
9288   :standard-input t
9289   :error-patterns
9290   ((error line-start
9291           "error: " (message) " at " (file-name) ":" line ":" column
9292           line-end))
9293   :error-filter
9294   (lambda (errors)
9295     (flycheck-sanitize-errors
9296      (flycheck-remove-error-file-names "(string)" errors)))
9297   :modes nix-mode)
9298
9299 (defun flycheck-locate-sphinx-source-directory ()
9300   "Locate the Sphinx source directory for the current buffer.
9301
9302 Return the source directory, or nil, if the current buffer is not
9303 part of a Sphinx project."
9304   (-when-let* ((filename (buffer-file-name))
9305                (dir (locate-dominating-file filename "conf.py")))
9306     (expand-file-name dir)))
9307
9308 (flycheck-define-checker rst
9309   "A ReStructuredText (RST) syntax checker using Docutils.
9310
9311 See URL `http://docutils.sourceforge.net/'."
9312   ;; We need to use source-inplace to properly resolve relative paths in
9313   ;; include:: directives
9314   :command ("rst2pseudoxml.py" "--report=2" "--halt=5"
9315             ;; Read from standard input and throw output away
9316             "-" null-device)
9317   :standard-input t
9318   :error-patterns
9319   ((warning line-start "<stdin>:" line ": (WARNING/2) " (message) line-end)
9320    (error line-start "<stdin>:" line
9321           ": (" (or "ERROR/3" "SEVERE/4") ") "
9322           (message) line-end))
9323   :modes rst-mode)
9324
9325 (flycheck-def-option-var flycheck-sphinx-warn-on-missing-references t rst-sphinx
9326   "Whether to warn about missing references in Sphinx.
9327
9328 When non-nil (the default), warn about all missing references in
9329 Sphinx via `-n'."
9330   :type 'boolean
9331   :safe #'booleanp
9332   :package-version '(flycheck . "0.17"))
9333
9334 (flycheck-define-checker rst-sphinx
9335   "A ReStructuredText (RST) syntax checker using Sphinx.
9336
9337 Requires Sphinx 1.2 or newer.  See URL `http://sphinx-doc.org'."
9338   :command ("sphinx-build" "-b" "pseudoxml"
9339             "-q" "-N"                   ; Reduced output and no colors
9340             (option-flag "-n" flycheck-sphinx-warn-on-missing-references)
9341             (eval (flycheck-locate-sphinx-source-directory))
9342             temporary-directory         ; Redirect the output to a temporary
9343                                         ; directory
9344             source-original)            ; Sphinx needs the original document
9345   :error-patterns
9346   ((warning line-start (file-name) ":" line ": WARNING: " (message) line-end)
9347    (error line-start
9348           (file-name) ":" line
9349           ": " (or "ERROR" "SEVERE") ": "
9350           (message) line-end))
9351   :modes rst-mode
9352   :predicate (lambda () (and (flycheck-buffer-saved-p)
9353                              (flycheck-locate-sphinx-source-directory))))
9354
9355 (defun flycheck-ruby--find-project-root (_checker)
9356   "Compute an appropriate working-directory for flycheck-ruby.
9357
9358 This is either a parent directory containing a Gemfile, or nil."
9359   (and
9360    buffer-file-name
9361    (locate-dominating-file buffer-file-name "Gemfile")))
9362
9363 (flycheck-def-config-file-var flycheck-rubocoprc ruby-rubocop ".rubocop.yml"
9364   :safe #'stringp)
9365
9366 (flycheck-def-option-var flycheck-rubocop-lint-only nil ruby-rubocop
9367   "Whether to only report code issues in Rubocop.
9368
9369 When non-nil, only report code issues in Rubocop, via `--lint'.
9370 Otherwise report style issues as well."
9371   :safe #'booleanp
9372   :type 'boolean
9373   :package-version '(flycheck . "0.16"))
9374
9375 (flycheck-define-checker ruby-rubocop
9376   "A Ruby syntax and style checker using the RuboCop tool.
9377
9378 You need at least RuboCop 0.34 for this syntax checker.
9379
9380 See URL `http://batsov.com/rubocop/'."
9381   :command ("rubocop"
9382             "--display-cop-names"
9383             "--force-exclusion"
9384             "--format" "emacs"
9385             ;; Explicitly disable caching to prevent Rubocop 0.35.1 and earlier
9386             ;; from caching standard input.  Later versions of Rubocop
9387             ;; automatically disable caching with --stdin, see
9388             ;; https://github.com/flycheck/flycheck/issues/844 and
9389             ;; https://github.com/bbatsov/rubocop/issues/2576
9390             "--cache" "false"
9391             (config-file "--config" flycheck-rubocoprc)
9392             (option-flag "--lint" flycheck-rubocop-lint-only)
9393             ;; Rubocop takes the original file name as argument when reading
9394             ;; from standard input
9395             "--stdin" source-original)
9396   :standard-input t
9397   :working-directory flycheck-ruby--find-project-root
9398   :error-patterns
9399   ((info line-start (file-name) ":" line ":" column ": C: "
9400          (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end)
9401    (warning line-start (file-name) ":" line ":" column ": W: "
9402             (optional (id (one-or-more (not (any ":")))) ": ") (message)
9403             line-end)
9404    (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": "
9405           (optional (id (one-or-more (not (any ":")))) ": ") (message)
9406           line-end))
9407   :modes (enh-ruby-mode ruby-mode)
9408   :next-checkers ((warning . ruby-reek)
9409                   (warning . ruby-rubylint)))
9410
9411 ;; Default to `nil' to let Reek find its configuration file by itself
9412 (flycheck-def-config-file-var flycheck-reekrc ruby-reek nil
9413   :safe #'string-or-null-p
9414   :package-version '(flycheck . "30"))
9415
9416 (flycheck-define-checker ruby-reek
9417   "A Ruby smell checker using reek.
9418
9419 See URL `https://github.com/troessner/reek'."
9420   :command ("reek" "--format" "json"
9421             (config-file "--config" flycheck-reekrc)
9422             source)
9423   :error-parser flycheck-parse-reek
9424   :modes (enh-ruby-mode ruby-mode)
9425   :next-checkers ((warning . ruby-rubylint)))
9426
9427 ;; Default to `nil' to let Rubylint find its configuration file by itself, and
9428 ;; to maintain backwards compatibility with older Rubylint and Flycheck releases
9429 (flycheck-def-config-file-var flycheck-rubylintrc ruby-rubylint nil
9430   :safe #'stringp)
9431
9432 (flycheck-define-checker ruby-rubylint
9433   "A Ruby syntax and code analysis checker using ruby-lint.
9434
9435 Requires ruby-lint 2.0.2 or newer.  See URL
9436 `https://github.com/YorickPeterse/ruby-lint'."
9437   :command ("ruby-lint" "--presenter=syntastic"
9438             (config-file "--config" flycheck-rubylintrc)
9439             source)
9440   ;; Ruby Lint can't read from standard input
9441   :error-patterns
9442   ((info line-start
9443          (file-name) ":I:" line ":" column ": " (message) line-end)
9444    (warning line-start
9445             (file-name) ":W:" line ":" column ": " (message) line-end)
9446    (error line-start
9447           (file-name) ":E:" line ":" column ": " (message) line-end))
9448   :modes (enh-ruby-mode ruby-mode))
9449
9450 (flycheck-define-checker ruby
9451   "A Ruby syntax checker using the standard Ruby interpreter.
9452
9453 Please note that the output of different Ruby versions and
9454 implementations varies wildly.  This syntax checker supports
9455 current versions of MRI and JRuby, but may break when used with
9456 other implementations or future versions of these
9457 implementations.
9458
9459 Please consider using `ruby-rubocop' or `ruby-reek' instead.
9460
9461 See URL `https://www.ruby-lang.org/'."
9462   :command ("ruby" "-w" "-c")
9463   :standard-input t
9464   :error-patterns
9465   ;; These patterns support output from JRuby, too, to deal with RVM or Rbenv
9466   ((error line-start "SyntaxError in -:" line ": " (message) line-end)
9467    (warning line-start "-:" line ":" (optional column ":")
9468             " warning: " (message) line-end)
9469    (error line-start "-:" line ": " (message) line-end))
9470   :modes (enh-ruby-mode ruby-mode)
9471   :next-checkers ((warning . ruby-rubylint)))
9472
9473 (flycheck-define-checker ruby-jruby
9474   "A Ruby syntax checker using the JRuby interpreter.
9475
9476 This syntax checker is very primitive, and may break on future
9477 versions of JRuby.
9478
9479 Please consider using `ruby-rubocop' or `ruby-rubylint' instead.
9480
9481 See URL `http://jruby.org/'."
9482   :command ("jruby" "-w" "-c")
9483   :standard-input t
9484   :error-patterns
9485   ((error   line-start "SyntaxError in -:" line ": " (message) line-end)
9486    (warning line-start "-:" line ": warning: " (message) line-end)
9487    (error   line-start "-:" line ": "          (message) line-end))
9488   :modes (enh-ruby-mode ruby-mode)
9489   :next-checkers ((warning . ruby-rubylint)))
9490
9491 (flycheck-def-args-var flycheck-cargo-check-args (rust-cargo)
9492   :package-version '(flycheck . "32"))
9493
9494 (flycheck-def-args-var flycheck-rust-args (rust)
9495   :package-version '(flycheck . "0.24"))
9496
9497 (flycheck-def-option-var flycheck-rust-check-tests t (rust-cargo rust)
9498   "Whether to check test code in Rust.
9499
9500 For the `rust' checker: When non-nil, `rustc' is passed the
9501 `--test' flag, which will check any code marked with the
9502 `#[cfg(test)]' attribute and any functions marked with
9503 `#[test]'. Otherwise, `rustc' is not passed `--test' and test
9504 code will not be checked.  Skipping `--test' is necessary when
9505 using `#![no_std]', because compiling the test runner requires
9506 `std'.
9507
9508 For the `rust-cargo' checker: When non-nil, calls `cargo test
9509 --no-run' instead of `cargo check'."
9510   :type 'boolean
9511   :safe #'booleanp
9512   :package-version '("flycheck" . "0.19"))
9513
9514 (flycheck-def-option-var flycheck-rust-crate-root nil rust
9515   "A path to the crate root for the current buffer.
9516
9517 The value of this variable is either a string with the path to
9518 the crate root for the current buffer, or nil if the current buffer
9519 is a crate.  A relative path is relative to the current buffer.
9520
9521 If this variable is non nil the current buffer will only be checked
9522 if it is not modified, i.e. after it has been saved."
9523   :type 'string
9524   :package-version '(flycheck . "0.20")
9525   :safe #'stringp)
9526 (make-variable-buffer-local 'flycheck-rust-crate-root)
9527
9528 (flycheck-def-option-var flycheck-rust-crate-type "lib" (rust-cargo rust)
9529   "The type of the Rust Crate to check.
9530
9531 For `rust-cargo', the value should be a string denoting the
9532 target type passed to Cargo.  See
9533 `flycheck-rust-valid-crate-type-p' for the list of allowed
9534 values.
9535
9536 For `rust', the value should be a string denoting the crate type
9537 for the `--crate-type' flag of rustc."
9538   :type '(choice (const :tag "nil (rust/rust-cargo)" nil)
9539                  (const :tag "lib (rust/rust-cargo)" "lib")
9540                  (const :tag "bin (rust/rust-cargo)" "bin")
9541                  (const :tag "example (rust-cargo)" "example")
9542                  (const :tag "test (rust-cargo)" "test")
9543                  (const :tag "bench (rust-cargo)" "bench")
9544                  (const :tag "rlib (rust)" "rlib")
9545                  (const :tag "dylib (rust)" "dylib")
9546                  (const :tag "cdylib (rust)" "cdylib")
9547                  (const :tag "staticlib (rust)" "staticlib")
9548                  (const :tag "metadata (rust)" "metadata"))
9549   :safe #'stringp
9550   :package-version '(flycheck . "0.20"))
9551 (make-variable-buffer-local 'flycheck-rust-crate-type)
9552
9553 (flycheck-def-option-var flycheck-rust-binary-name nil rust-cargo
9554   "The name of the binary to pass to `cargo check --CRATE-TYPE'.
9555
9556 The value of this variable is a string denoting the name of the
9557 target to check: usually the name of the crate, or the name of
9558 one of the files under `src/bin', `tests', `examples' or
9559 `benches'.
9560
9561 This always requires a non-nil value, unless
9562 `flycheck-rust-crate-type' is `lib' or nil, in which case it is
9563 ignored."
9564   :type 'string
9565   :safe #'stringp
9566   :package-version '(flycheck . "28"))
9567 (make-variable-buffer-local 'flycheck-rust-binary-name)
9568
9569 (flycheck-def-option-var flycheck-rust-features nil rust-cargo
9570   "List of features to activate during build or check.
9571
9572 The value of this variable is a list of strings denoting features
9573 that will be activated to build the target to check. Features will
9574 be passed to `cargo check --features=FEATURES'."
9575   :type '(repeat :tag "Features to activate"
9576                  (string :tag "Feature"))
9577   :safe #'flycheck-string-list-p
9578   :package-version '(flycheck . "32"))
9579 (make-variable-buffer-local 'flycheck-rust-features)
9580
9581 (flycheck-def-option-var flycheck-rust-library-path nil rust
9582   "A list of library directories for Rust.
9583
9584 The value of this variable is a list of strings, where each
9585 string is a directory to add to the library path of Rust.
9586 Relative paths are relative to the file being checked."
9587   :type '(repeat (directory :tag "Library directory"))
9588   :safe #'flycheck-string-list-p
9589   :package-version '(flycheck . "0.18"))
9590
9591 (defun flycheck-rust-error-explainer (error)
9592   "Return an explanation text for the given `flycheck-error' ERROR."
9593   (-when-let (error-code (flycheck-error-id error))
9594     (with-output-to-string
9595       (call-process "rustc" nil standard-output nil "--explain" error-code))))
9596
9597 (defun flycheck-rust-error-filter (errors)
9598   "Filter ERRORS from rustc output that have no explanatory value."
9599   (seq-remove
9600    (lambda (err)
9601      (or
9602       ;; Macro errors emit a diagnostic in a phony file,
9603       ;; e.g. "<println macros>".
9604       (-when-let (filename (flycheck-error-filename err))
9605         (string-match-p (rx "macros>" line-end) filename))
9606       ;; Redundant message giving the number of failed errors
9607       (-when-let (msg (flycheck-error-message err))
9608         (string-match-p
9609          (rx
9610           (or (: "aborting due to " (optional (one-or-more num) " ")
9611                  "previous error")
9612               (: "For more information about this error, try `rustc --explain "
9613                  (one-or-more alnum) "`.")))
9614          msg))))
9615    errors))
9616
9617 (defun flycheck-rust-manifest-directory ()
9618   "Return the nearest directory holding the Cargo manifest.
9619
9620 Return the nearest directory containing the `Cargo.toml' manifest
9621 file, starting from the current buffer and using
9622 `locate-dominating-file'.  Return nil if there is no such file,
9623 or if the current buffer has no file name."
9624   (and buffer-file-name
9625        (locate-dominating-file buffer-file-name "Cargo.toml")))
9626
9627 (defun flycheck-rust-cargo-metadata ()
9628   "Run 'cargo metadata' and return the result as parsed JSON object."
9629   (car (flycheck-parse-json
9630         (with-output-to-string
9631           (call-process "cargo" nil standard-output nil
9632                         "metadata" "--no-deps" "--format-version" "1")))))
9633
9634 (defun flycheck-rust-cargo-workspace-root ()
9635   "Return the path to the workspace root of a Rust Cargo project.
9636
9637 Return nil if the workspace root does not exist (for Rust
9638 versions inferior to 1.25)."
9639   (let-alist (flycheck-rust-cargo-metadata)
9640     .workspace_root))
9641
9642 (defun flycheck-rust-cargo-has-command-p (command)
9643   "Whether Cargo has COMMAND in its list of commands.
9644
9645 Execute `cargo --list' to find out whether COMMAND is present."
9646   (let ((cargo (funcall flycheck-executable-find "cargo")))
9647     (member command (mapcar #'string-trim-left
9648                             (ignore-errors (process-lines cargo "--list"))))))
9649
9650 (defun flycheck-rust-valid-crate-type-p (crate-type)
9651   "Whether CRATE-TYPE is a valid target type for Cargo.
9652
9653 A valid Cargo target type is one of `lib', `bin', `example',
9654 `test' or `bench'."
9655   (member crate-type '(nil "lib" "bin" "example" "test" "bench")))
9656
9657 (flycheck-define-checker rust-cargo
9658   "A Rust syntax checker using Cargo.
9659
9660 This syntax checker requires Rust 1.17 or newer.  See URL
9661 `https://www.rust-lang.org'."
9662   :command ("cargo"
9663             (eval (if flycheck-rust-check-tests
9664                       "test"
9665                     "check"))
9666             (eval (when flycheck-rust-check-tests
9667                     "--no-run"))
9668             (eval (when flycheck-rust-crate-type
9669                     (concat "--" flycheck-rust-crate-type)))
9670             ;; All crate targets except "lib" need a binary name
9671             (eval (when (and flycheck-rust-crate-type
9672                              (not (string= flycheck-rust-crate-type "lib")))
9673                     flycheck-rust-binary-name))
9674             (option "--features=" flycheck-rust-features concat
9675                     flycheck-option-comma-separated-list)
9676             (eval flycheck-cargo-check-args)
9677             "--message-format=json")
9678   :error-parser flycheck-parse-cargo-rustc
9679   :error-filter (lambda (errors)
9680                   ;; In Rust 1.25+, filenames are relative to the workspace
9681                   ;; root.
9682                   (let ((root (flycheck-rust-cargo-workspace-root)))
9683                     (seq-do (lambda (err)
9684                               (setf (flycheck-error-filename err)
9685                                     (expand-file-name
9686                                      (flycheck-error-filename err) root)))
9687                             (flycheck-rust-error-filter errors))))
9688   :error-explainer flycheck-rust-error-explainer
9689   :modes rust-mode
9690   :predicate flycheck-buffer-saved-p
9691   :enabled flycheck-rust-manifest-directory
9692   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
9693   :verify
9694   (lambda (_)
9695     (and buffer-file-name
9696          (let* ((has-toml (flycheck-rust-manifest-directory))
9697                 (valid-crate-type (flycheck-rust-valid-crate-type-p
9698                                    flycheck-rust-crate-type))
9699                 (need-binary-name
9700                  (and flycheck-rust-crate-type
9701                       (not (string= flycheck-rust-crate-type "lib")))))
9702            (list
9703             (flycheck-verification-result-new
9704              :label "Cargo.toml"
9705              :message (if has-toml "Found" "Missing")
9706              :face (if has-toml 'success '(bold warning)))
9707             (flycheck-verification-result-new
9708              :label "Crate type"
9709              :message (if valid-crate-type
9710                           (format "%s" flycheck-rust-crate-type)
9711                         (format "%s (invalid, should be one of 'lib', 'bin', \
9712 'test', 'example' or 'bench')"
9713                                 flycheck-rust-crate-type))
9714              :face (if valid-crate-type 'success '(bold error)))
9715             (flycheck-verification-result-new
9716              :label "Binary name"
9717              :message (cond
9718                        ((not need-binary-name) "Not required")
9719                        ((not flycheck-rust-binary-name) "Required")
9720                        (t (format "%s" flycheck-rust-binary-name)))
9721              :face (cond
9722                     ((not need-binary-name) 'success)
9723                     ((not flycheck-rust-binary-name) '(bold error))
9724                     (t 'success))))))))
9725
9726 (flycheck-define-checker rust
9727   "A Rust syntax checker using Rust compiler.
9728
9729 This syntax checker needs Rust 1.18 or newer.  See URL
9730 `https://www.rust-lang.org'."
9731   :command ("rustc"
9732             (option "--crate-type" flycheck-rust-crate-type)
9733             "--emit=mir" "-o" "/dev/null" ; avoid creating binaries
9734             "--error-format=json"
9735             (option-flag "--test" flycheck-rust-check-tests)
9736             (option-list "-L" flycheck-rust-library-path concat)
9737             (eval flycheck-rust-args)
9738             (eval (or flycheck-rust-crate-root
9739                       (flycheck-substitute-argument 'source-original 'rust))))
9740   :error-parser flycheck-parse-rustc
9741   :error-filter flycheck-rust-error-filter
9742   :error-explainer flycheck-rust-error-explainer
9743   :modes rust-mode
9744   :predicate flycheck-buffer-saved-p)
9745
9746 (flycheck-define-checker rust-clippy
9747   "A Rust syntax checker using clippy.
9748
9749 See URL `https://github.com/rust-lang-nursery/rust-clippy'."
9750   :command ("cargo" "+nightly" "clippy" "--message-format=json")
9751   :error-parser flycheck-parse-cargo-rustc
9752   :error-filter flycheck-rust-error-filter
9753   :error-explainer flycheck-rust-error-explainer
9754   :modes rust-mode
9755   :predicate flycheck-buffer-saved-p
9756   :enabled (lambda ()
9757              (and (flycheck-rust-cargo-has-command-p "clippy")
9758                   (flycheck-rust-manifest-directory)))
9759   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
9760   :verify
9761   (lambda (_)
9762     (and buffer-file-name
9763          (let ((has-toml (flycheck-rust-manifest-directory))
9764                (has-clippy (flycheck-rust-cargo-has-command-p "clippy")))
9765            (list
9766             (flycheck-verification-result-new
9767              :label "Clippy"
9768              :message (if has-clippy "Found"
9769                         "Cannot find the `cargo clippy' command")
9770              :face (if has-clippy 'success '(bold warning)))
9771             (flycheck-verification-result-new
9772              :label "Cargo.toml"
9773              :message (if has-toml "Found" "Missing")
9774              :face (if has-toml 'success '(bold warning))))))))
9775
9776 (defvar flycheck-sass-scss-cache-directory nil
9777   "The cache directory for `sass' and `scss'.")
9778
9779 (defun flycheck-sass-scss-cache-location ()
9780   "Get the cache location for `sass' and `scss'.
9781
9782 If no cache directory exists yet, create one and return it.
9783 Otherwise return the previously used cache directory."
9784   (setq flycheck-sass-scss-cache-directory
9785         (or flycheck-sass-scss-cache-directory
9786             (make-temp-file "flycheck-sass-scss-cache" 'directory))))
9787
9788 (flycheck-def-option-var flycheck-sass-compass nil sass
9789   "Whether to enable the Compass CSS framework.
9790
9791 When non-nil, enable the Compass CSS framework, via `--compass'."
9792   :type 'boolean
9793   :safe #'booleanp
9794   :package-version '(flycheck . "0.16"))
9795
9796 (flycheck-define-checker sass
9797   "A Sass syntax checker using the Sass compiler.
9798
9799 See URL `http://sass-lang.com'."
9800   :command ("sass"
9801             "--cache-location" (eval (flycheck-sass-scss-cache-location))
9802             (option-flag "--compass" flycheck-sass-compass)
9803             "--check" "--stdin")
9804   :standard-input t
9805   :error-patterns
9806   ((error line-start
9807           (or "Syntax error: " "Error: ")
9808           (message (one-or-more not-newline)
9809                    (zero-or-more "\n"
9810                                  (one-or-more " ")
9811                                  (one-or-more not-newline)))
9812           (optional "\r") "\n" (one-or-more " ") "on line " line
9813           " of standard input"
9814           line-end)
9815    (warning line-start
9816             "WARNING: "
9817             (message (one-or-more not-newline)
9818                      (zero-or-more "\n"
9819                                    (one-or-more " ")
9820                                    (one-or-more not-newline)))
9821             (optional "\r") "\n" (one-or-more " ") "on line " line
9822             " of " (one-or-more not-newline)
9823             line-end))
9824   :modes sass-mode)
9825
9826 (flycheck-def-config-file-var flycheck-sass-lintrc sass/scss-sass-lint
9827                               ".sass-lint.yml"
9828   :safe #'stringp
9829   :package-version '(flycheck . "30"))
9830
9831 (flycheck-define-checker sass/scss-sass-lint
9832   "A SASS/SCSS syntax checker using sass-Lint.
9833
9834 See URL `https://github.com/sasstools/sass-lint'."
9835   :command ("sass-lint"
9836             "--verbose"
9837             "--no-exit"
9838             "--format" "Checkstyle"
9839             (config-file "--config" flycheck-sass-lintrc)
9840             source)
9841   :error-parser flycheck-parse-checkstyle
9842   :modes (sass-mode scss-mode))
9843
9844 (flycheck-define-checker scala
9845   "A Scala syntax checker using the Scala compiler.
9846
9847 See URL `https://www.scala-lang.org/'."
9848   :command ("scalac" "-Ystop-after:parser" source)
9849   :error-patterns
9850   ((error line-start (file-name) ":" line ": error: " (message) line-end))
9851   :modes scala-mode
9852   :next-checkers ((warning . scala-scalastyle)))
9853
9854 (flycheck-def-config-file-var flycheck-scalastylerc scala-scalastyle nil
9855   :safe #'stringp
9856   :package-version '(flycheck . "0.20"))
9857
9858 (flycheck-define-checker scala-scalastyle
9859   "A Scala style checker using scalastyle.
9860
9861 Note that this syntax checker is not used if
9862 `flycheck-scalastylerc' is nil or refers to a non-existing file.
9863
9864 See URL `http://www.scalastyle.org'."
9865   :command ("scalastyle"
9866             (config-file "-c" flycheck-scalastylerc)
9867             source)
9868   :error-patterns
9869   ((error line-start "error file=" (file-name) " message="
9870           (message) " line=" line (optional " column=" column) line-end)
9871    (warning line-start "warning file=" (file-name) " message="
9872             (message) " line=" line (optional " column=" column) line-end))
9873   :error-filter (lambda (errors)
9874                   (flycheck-sanitize-errors
9875                    (flycheck-increment-error-columns errors)))
9876   :modes scala-mode
9877   :predicate
9878   ;; Inhibit this syntax checker if the JAR or the configuration are unset or
9879   ;; missing
9880   (lambda () (and flycheck-scalastylerc
9881                   (flycheck-locate-config-file flycheck-scalastylerc
9882                                                'scala-scalastyle)))
9883   :verify (lambda (checker)
9884             (let ((config-file (and flycheck-scalastylerc
9885                                     (flycheck-locate-config-file
9886                                      flycheck-scalastylerc checker))))
9887               (list
9888                (flycheck-verification-result-new
9889                 :label "Configuration file"
9890                 :message (cond
9891                           ((not flycheck-scalastylerc)
9892                            "`flycheck-scalastyletrc' not set")
9893                           ((not config-file)
9894                            (format "file %s not found" flycheck-scalastylerc))
9895                           (t (format "found at %s" config-file)))
9896                 :face (cond
9897                        ((not flycheck-scalastylerc) '(bold warning))
9898                        ((not config-file) '(bold error))
9899                        (t 'success)))))))
9900
9901 (flycheck-def-args-var flycheck-scheme-chicken-args scheme-chicken
9902   :package-version '(flycheck . "32"))
9903
9904 (flycheck-define-checker scheme-chicken
9905   "A CHICKEN Scheme syntax checker using the CHICKEN compiler `csc'.
9906
9907 See URL `http://call-cc.org/'."
9908   :command ("csc" "-analyze-only" "-local"
9909             (eval flycheck-scheme-chicken-args)
9910             source)
9911   :error-patterns
9912   ((info line-start
9913          "Note: " (zero-or-more not-newline) ":\n"
9914          (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
9915          line-end)
9916    (warning line-start
9917             "Warning: " (zero-or-more not-newline) ",\n"
9918             (one-or-more (any space)) (zero-or-more not-newline) ":\n"
9919             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
9920             line-end)
9921    (warning line-start
9922             "Warning: " (zero-or-more not-newline) ":\n"
9923             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
9924             line-end)
9925    (error line-start "Error: (line " line ") " (message) line-end)
9926    (error line-start "Syntax error: (" (file-name) ":" line ")"
9927           (zero-or-more not-newline) " - "
9928           (message (one-or-more not-newline)
9929                    (zero-or-more "\n"
9930                                  (zero-or-more space)
9931                                  (zero-or-more not-newline))
9932                    (one-or-more space) "<--")
9933           line-end)
9934    ;; A of version 4.12.0, the chicken compiler doesn't provide a
9935    ;; line number for this error.
9936    (error line-start "Syntax error: "
9937           (message (one-or-more not-newline)
9938                    (zero-or-more "\n"
9939                                  (zero-or-more space)
9940                                  (zero-or-more not-newline))
9941                    (one-or-more space) "<--")
9942           line-end)
9943    (error line-start
9944           "Error: " (zero-or-more not-newline) ":\n"
9945           (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
9946           line-end)
9947    ;; A of version 4.12.0, the chicken compiler doesn't provide a
9948    ;; line number for this error.
9949    (error line-start "Error: "
9950           (message (one-or-more not-newline)
9951                    (zero-or-more "\n"
9952                                  (zero-or-more space)
9953                                  (zero-or-more not-newline))
9954                    (one-or-more space) "<--")))
9955   :error-filter flycheck-fill-empty-line-numbers
9956   :predicate
9957   (lambda ()
9958     ;; In `scheme-mode' we must check the current Scheme implementation
9959     ;; being used
9960     (and (boundp 'geiser-impl--implementation)
9961          (eq geiser-impl--implementation 'chicken)))
9962   :verify
9963   (lambda (_checker)
9964     (let ((geiser-impl (bound-and-true-p geiser-impl--implementation)))
9965       (list
9966        (flycheck-verification-result-new
9967         :label "Geiser Implementation"
9968         :message (cond
9969                   ((eq geiser-impl 'chicken) "Chicken Scheme")
9970                   (geiser-impl (format "Other: %s" geiser-impl))
9971                   (t "Geiser not active"))
9972         :face (cond
9973                ((eq geiser-impl 'chicken) 'success)
9974                (t '(bold error)))))))
9975   :modes scheme-mode)
9976
9977 (defconst flycheck-scss-lint-checkstyle-re
9978   (rx "cannot load such file" (1+ not-newline) "scss_lint_reporter_checkstyle")
9979   "Regular expression to parse missing checkstyle error.")
9980
9981 (defun flycheck-parse-scss-lint (output checker buffer)
9982   "Parse SCSS-Lint OUTPUT from CHECKER and BUFFER.
9983
9984 Like `flycheck-parse-checkstyle', but catches errors about
9985 missing checkstyle reporter from SCSS-Lint."
9986   (if (string-match-p flycheck-scss-lint-checkstyle-re output)
9987       (list (flycheck-error-new-at
9988              1 nil 'error "Checkstyle reporter for SCSS-Lint missing.
9989 Please run gem install scss_lint_reporter_checkstyle"
9990              :checker checker
9991              :buffer buffer
9992              :filename (buffer-file-name buffer)))
9993     (flycheck-parse-checkstyle output checker buffer)))
9994
9995 (flycheck-def-config-file-var flycheck-scss-lintrc scss-lint ".scss-lint.yml"
9996   :safe #'stringp
9997   :package-version '(flycheck . "0.23"))
9998
9999 (flycheck-define-checker scss-lint
10000   "A SCSS syntax checker using SCSS-Lint.
10001
10002 Needs SCSS-Lint 0.43.2 or newer.
10003
10004 See URL `https://github.com/brigade/scss-lint'."
10005   :command ("scss-lint"
10006             "--require=scss_lint_reporter_checkstyle"
10007             "--format=Checkstyle"
10008             (config-file "--config" flycheck-scss-lintrc)
10009             "--stdin-file-path" source-original "-")
10010   :standard-input t
10011   ;; We cannot directly parse Checkstyle XML, since for some mysterious reason
10012   ;; SCSS-Lint doesn't have a built-in Checkstyle reporter, and instead ships it
10013   ;; as an addon which might not be installed.  We use a custom error parser to
10014   ;; check whether the addon is missing and turn that into a special kind of
10015   ;; Flycheck error.
10016   :error-parser flycheck-parse-scss-lint
10017   :modes scss-mode
10018   :verify
10019   (lambda (checker)
10020     (let* ((executable (flycheck-find-checker-executable checker))
10021            (reporter-missing
10022             (and executable
10023                  (with-temp-buffer
10024                    (call-process executable nil t nil
10025                                  "--require=scss_lint_reporter_checkstyle")
10026                    (goto-char (point-min))
10027                    (re-search-forward
10028                     flycheck-scss-lint-checkstyle-re
10029                     nil 'no-error)))))
10030       (when executable
10031         (list
10032          (flycheck-verification-result-new
10033           :label "checkstyle reporter"
10034           :message (if reporter-missing
10035                        "scss_lint_reporter_checkstyle missing"
10036                      "present")
10037           :face (if reporter-missing
10038                     '(bold error)
10039                   'success)))))))
10040
10041 (flycheck-define-checker scss-stylelint
10042   "A SCSS syntax and style checker using stylelint.
10043
10044 See URL `http://stylelint.io/'."
10045   :command ("stylelint"
10046             (eval flycheck-stylelint-args)
10047             "--syntax" "scss"
10048             (option-flag "--quiet" flycheck-stylelint-quiet)
10049             (config-file "--config" flycheck-stylelintrc))
10050   :standard-input t
10051   :error-parser flycheck-parse-stylelint
10052   :modes (scss-mode))
10053
10054 (flycheck-def-option-var flycheck-scss-compass nil scss
10055   "Whether to enable the Compass CSS framework.
10056
10057 When non-nil, enable the Compass CSS framework, via `--compass'."
10058   :type 'boolean
10059   :safe #'booleanp
10060   :package-version '(flycheck . "0.16"))
10061
10062 (flycheck-define-checker scss
10063   "A SCSS syntax checker using the SCSS compiler.
10064
10065 See URL `http://sass-lang.com'."
10066   :command ("scss"
10067             "--cache-location" (eval (flycheck-sass-scss-cache-location))
10068             (option-flag "--compass" flycheck-scss-compass)
10069             "--check" "--stdin")
10070   :standard-input t
10071   :error-patterns
10072   ((error line-start
10073           (or "Syntax error: " "Error: ")
10074           (message (one-or-more not-newline)
10075                    (zero-or-more "\n"
10076                                  (one-or-more " ")
10077                                  (one-or-more not-newline)))
10078           (optional "\r") "\n" (one-or-more " ") "on line " line
10079           " of standard input"
10080           line-end)
10081    (warning line-start
10082             "WARNING: "
10083             (message (one-or-more not-newline)
10084                      (zero-or-more "\n"
10085                                    (one-or-more " ")
10086                                    (one-or-more not-newline)))
10087             (optional "\r") "\n" (one-or-more " ") "on line " line
10088             " of an unknown file"
10089             line-end))
10090   :modes scss-mode)
10091
10092 (flycheck-def-args-var flycheck-sh-bash-args (sh-bash)
10093   :package-version '(flycheck . "32"))
10094
10095 (flycheck-define-checker sh-bash
10096   "A Bash syntax checker using the Bash shell.
10097
10098 See URL `http://www.gnu.org/software/bash/'."
10099   :command ("bash" "--norc" "-n"
10100             (eval flycheck-sh-bash-args)
10101             "--")
10102   :standard-input t
10103   :error-patterns
10104   ((error line-start
10105           ;; The name/path of the bash executable
10106           (one-or-more (not (any ":"))) ":"
10107           ;; A label "line", possibly localized
10108           (one-or-more (not (any digit)))
10109           line (zero-or-more " ") ":" (zero-or-more " ")
10110           (message) line-end))
10111   :modes sh-mode
10112   :predicate (lambda () (eq sh-shell 'bash))
10113   :next-checkers ((warning . sh-shellcheck)))
10114
10115 (flycheck-define-checker sh-posix-dash
10116   "A POSIX Shell syntax checker using the Dash shell.
10117
10118 See URL `http://gondor.apana.org.au/~herbert/dash/'."
10119   :command ("dash" "-n")
10120   :standard-input t
10121   :error-patterns
10122   ((error line-start (one-or-more (not (any ":"))) ": " line ": " (message)))
10123   :modes sh-mode
10124   :predicate (lambda () (eq sh-shell 'sh))
10125   :next-checkers ((warning . sh-shellcheck)))
10126
10127 (flycheck-define-checker sh-posix-bash
10128   "A POSIX Shell syntax checker using the Bash shell.
10129
10130 See URL `http://www.gnu.org/software/bash/'."
10131   :command ("bash" "--posix" "--norc" "-n" "--")
10132   :standard-input t
10133   :error-patterns
10134   ((error line-start
10135           ;; The name/path of the bash executable
10136           (one-or-more (not (any ":"))) ":"
10137           ;; A label "line", possibly localized
10138           (one-or-more (not (any digit)))
10139           line (zero-or-more " ") ":" (zero-or-more " ")
10140           (message) line-end))
10141   :modes sh-mode
10142   :predicate (lambda () (eq sh-shell 'sh))
10143   :next-checkers ((warning . sh-shellcheck)))
10144
10145 (flycheck-define-checker sh-zsh
10146   "A Zsh syntax checker using the Zsh shell.
10147
10148 See URL `http://www.zsh.org/'."
10149   :command ("zsh" "--no-exec" "--no-globalrcs" "--no-rcs" source)
10150   :error-patterns
10151   ((error line-start (file-name) ":" line ": " (message) line-end))
10152   :modes sh-mode
10153   :predicate (lambda () (eq sh-shell 'zsh))
10154   :next-checkers ((warning . sh-shellcheck)))
10155
10156 (defconst flycheck-shellcheck-supported-shells '(bash ksh88 sh)
10157   "Shells supported by ShellCheck.")
10158
10159 (flycheck-def-option-var flycheck-shellcheck-excluded-warnings nil sh-shellcheck
10160   "A list of excluded warnings for ShellCheck.
10161
10162 The value of this variable is a list of strings, where each
10163 string is a warning code to be excluded from ShellCheck reports.
10164 By default, no warnings are excluded."
10165   :type '(repeat :tag "Excluded warnings"
10166                  (string :tag "Warning code"))
10167   :safe #'flycheck-string-list-p
10168   :package-version '(flycheck . "0.21"))
10169
10170 (flycheck-def-option-var flycheck-shellcheck-follow-sources t sh-shellcheck
10171   "Whether to follow external sourced files in scripts.
10172
10173 Shellcheck will follow and parse sourced files so long as a
10174 pre-runtime resolvable path to the file is present.  This can
10175 either be part of the source command itself:
10176    source /full/path/to/file.txt
10177 or added as a shellcheck directive before the source command:
10178    # shellcheck source=/full/path/to/file.txt."
10179   :type 'boolean
10180   :safe #'booleanp
10181   :package-version '(flycheck . "31"))
10182
10183 (flycheck-define-checker sh-shellcheck
10184   "A shell script syntax and style checker using Shellcheck.
10185
10186 See URL `https://github.com/koalaman/shellcheck/'."
10187   :command ("shellcheck"
10188             "--format" "checkstyle"
10189             "--shell" (eval (symbol-name sh-shell))
10190             (option-flag "--external-sources"
10191                          flycheck-shellcheck-follow-sources)
10192             (option "--exclude" flycheck-shellcheck-excluded-warnings list
10193                     flycheck-option-comma-separated-list)
10194             "-")
10195   :standard-input t
10196   :error-parser flycheck-parse-checkstyle
10197   :error-filter
10198   (lambda (errors)
10199     (flycheck-remove-error-file-names
10200      "-" (flycheck-dequalify-error-ids errors)))
10201   :modes sh-mode
10202   :predicate (lambda () (memq sh-shell flycheck-shellcheck-supported-shells))
10203   :verify (lambda (_)
10204             (let ((supports-shell (memq sh-shell
10205                                         flycheck-shellcheck-supported-shells)))
10206               (list
10207                (flycheck-verification-result-new
10208                 :label (format "Shell %s supported" sh-shell)
10209                 :message (if supports-shell "yes" "no")
10210                 :face (if supports-shell 'success '(bold warning)))))))
10211
10212 (flycheck-define-checker slim
10213   "A Slim syntax checker using the Slim compiler.
10214
10215 See URL `http://slim-lang.com'."
10216   :command ("slimrb" "--compile")
10217   :standard-input t
10218   :error-patterns
10219   ((error line-start
10220           "Slim::Parser::SyntaxError:" (message) (optional "\r") "\n  "
10221           "STDIN, Line " line (optional ", Column " column)
10222           line-end))
10223   :modes slim-mode
10224   :next-checkers ((warning . slim-lint)))
10225
10226 (flycheck-define-checker slim-lint
10227   "A Slim linter.
10228
10229 See URL `https://github.com/sds/slim-lint'."
10230   :command ("slim-lint" "--reporter=checkstyle" source)
10231   :error-parser flycheck-parse-checkstyle
10232   :modes slim-mode)
10233
10234 (flycheck-define-checker sql-sqlint
10235   "A SQL syntax checker using the sqlint tool.
10236
10237 See URL `https://github.com/purcell/sqlint'."
10238   :command ("sqlint")
10239   :standard-input t
10240   :error-patterns
10241   ((warning line-start "stdin:" line ":" column ":WARNING "
10242             (message (one-or-more not-newline)
10243                      (zero-or-more "\n"
10244                                    (one-or-more "  ")
10245                                    (one-or-more not-newline)))
10246             line-end)
10247    (error line-start "stdin:" line ":" column ":ERROR "
10248           (message (one-or-more not-newline)
10249                    (zero-or-more "\n"
10250                                  (one-or-more "  ")
10251                                  (one-or-more not-newline)))
10252           line-end))
10253   :modes (sql-mode))
10254
10255 (flycheck-define-checker systemd-analyze
10256   "A systemd unit checker using systemd-analyze(1).
10257
10258 See URL
10259 `https://www.freedesktop.org/software/systemd/man/systemd-analyze.html'."
10260   :command ("systemd-analyze" "verify" source)
10261   :error-patterns
10262   ((error line-start "[" (file-name) ":" line "] " (message) line-end))
10263   :modes (systemd-mode))
10264
10265 (flycheck-def-config-file-var flycheck-chktexrc tex-chktex ".chktexrc"
10266   :safe #'stringp)
10267
10268 (flycheck-define-checker tcl-nagelfar
10269   "An extensible tcl syntax checker
10270
10271 See URL `http://nagelfar.sourceforge.net/'."
10272   :command ("nagelfar" "-H" source)
10273   :error-patterns
10274   ;; foo.tcl: 29: E Wrong number of arguments (4) to "set"
10275   ;; foo.tcl: 29: W Expr without braces
10276   ((info    line-start (file-name) ": " line ": N " (message) line-end)
10277    (warning line-start (file-name) ": " line ": W " (message) line-end)
10278    (error   line-start (file-name) ": " line ": E " (message) line-end))
10279   :modes tcl-mode)
10280
10281 (flycheck-define-checker tex-chktex
10282   "A TeX and LaTeX syntax and style checker using chktex.
10283
10284 See URL `http://www.nongnu.org/chktex/'."
10285   :command ("chktex"
10286             (config-file "--localrc" flycheck-chktexrc)
10287             ;; Compact error messages, and no version information, and execute
10288             ;; \input statements
10289             "--verbosity=0" "--quiet" "--inputfiles")
10290   :standard-input t
10291   :error-patterns
10292   ((warning line-start "stdin:" line ":" column ":"
10293             (id (one-or-more digit)) ":" (message) line-end))
10294   :error-filter
10295   (lambda (errors)
10296     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
10297   :modes (latex-mode plain-tex-mode))
10298
10299 (flycheck-define-checker tex-lacheck
10300   "A LaTeX syntax and style checker using lacheck.
10301
10302 See URL `http://www.ctan.org/pkg/lacheck'."
10303   :command ("lacheck" source-inplace)
10304   :error-patterns
10305   ((warning line-start
10306             "\"" (file-name) "\", line " line ": " (message)
10307             line-end))
10308   :modes latex-mode)
10309
10310 (flycheck-define-checker texinfo
10311   "A Texinfo syntax checker using makeinfo.
10312
10313 See URL `http://www.gnu.org/software/texinfo/'."
10314   :command ("makeinfo" "-o" null-device "-")
10315   :standard-input t
10316   :error-patterns
10317   ((warning line-start
10318             "-:" line (optional ":" column) ": " "warning: " (message)
10319             line-end)
10320    (error line-start
10321           "-:" line (optional ":" column) ": " (message)
10322           line-end))
10323   :modes texinfo-mode)
10324
10325 (flycheck-def-config-file-var flycheck-typescript-tslint-config
10326     typescript-tslint "tslint.json"
10327   :safe #'stringp
10328   :package-version '(flycheck . "27"))
10329
10330 (flycheck-def-option-var flycheck-typescript-tslint-rulesdir
10331     nil typescript-tslint
10332   "The directory of custom rules for TSLint.
10333
10334 The value of this variable is either a string containing the path
10335 to a directory with custom rules, or nil, to not give any custom
10336 rules to TSLint.
10337
10338 Refer to the TSLint manual at URL
10339 `http://palantir.github.io/tslint/usage/cli/'
10340 for more information about the custom directory."
10341   :type '(choice (const :tag "No custom rules directory" nil)
10342                  (directory :tag "Custom rules directory"))
10343   :safe #'stringp
10344   :package-version '(flycheck . "27"))
10345
10346 (flycheck-def-args-var flycheck-tslint-args (typescript-tslint)
10347   :package-version '(flycheck . "31"))
10348
10349 (flycheck-define-checker typescript-tslint
10350   "TypeScript style checker using TSLint.
10351
10352 Note that this syntax checker is not used if
10353 `flycheck-typescript-tslint-config' is nil or refers to a
10354 non-existing file.
10355
10356 See URL `https://github.com/palantir/tslint'."
10357   :command ("tslint" "--format" "json"
10358             (config-file "--config" flycheck-typescript-tslint-config)
10359             (option "--rules-dir" flycheck-typescript-tslint-rulesdir)
10360             (eval flycheck-tslint-args)
10361             source-inplace)
10362   :error-parser flycheck-parse-tslint
10363   :modes (typescript-mode))
10364
10365 (flycheck-def-option-var flycheck-verilator-include-path nil verilog-verilator
10366   "A list of include directories for Verilator.
10367
10368 The value of this variable is a list of strings, where each
10369 string is a directory to add to the include path of Verilator.
10370 Relative paths are relative to the file being checked."
10371   :type '(repeat (directory :tag "Include directory"))
10372   :safe #'flycheck-string-list-p
10373   :package-version '(flycheck . "0.24"))
10374
10375 (flycheck-define-checker verilog-verilator
10376   "A Verilog syntax checker using the Verilator Verilog HDL simulator.
10377
10378 See URL `https://www.veripool.org/wiki/verilator'."
10379   :command ("verilator" "--lint-only" "-Wall"
10380             (option-list "-I" flycheck-verilator-include-path concat)
10381             source)
10382   :error-patterns
10383   ((warning line-start "%Warning-" (zero-or-more not-newline) ": "
10384             (file-name) ":" line ": " (message) line-end)
10385    (error line-start "%Error: " (file-name) ":"
10386           line ": " (message) line-end))
10387   :modes verilog-mode)
10388
10389 (flycheck-def-option-var flycheck-ghdl-language-standard nil vhdl-ghdl
10390   "The language standard to use in GHDL.
10391
10392 The value of this variable is either a string denoting a language
10393 standard, or nil, to use the default standard.  When non-nil,
10394 pass the language standard via the `--std' option."
10395   :type '(choice (const :tag "Default standard" nil)
10396                  (string :tag "Language standard"))
10397   :safe #'stringp
10398   :package-version '(flycheck . "32"))
10399 (make-variable-buffer-local 'flycheck-ghdl-language-standard)
10400
10401 (flycheck-def-option-var flycheck-ghdl-workdir nil vhdl-ghdl
10402   "The directory to use for the file library
10403
10404 The value of this variable is either a string with the directory
10405 to use for the file library, or nil, to use the default value.
10406 When non-nil, pass the directory via the `--workdir' option."
10407   :type '(choice (const :tag "Default directory" nil)
10408                  (string :tag "Directory for the file library"))
10409   :safe #'stringp
10410   :package-version '(flycheck . "32"))
10411 (make-variable-buffer-local 'flycheck-ghdl-workdir)
10412
10413 (flycheck-define-checker vhdl-ghdl
10414   "A VHDL syntax checker using GHDL.
10415
10416 See URL `https://github.com/ghdl/ghdl'."
10417   :command ("ghdl"
10418             "-s" ; only do the syntax checking
10419             (option "--std=" flycheck-ghdl-language-standard concat)
10420             (option "--workdir=" flycheck-ghdl-workdir concat)
10421             source)
10422   :error-patterns
10423   ((error line-start (file-name) ":" line ":" column ": " (message) line-end))
10424   :modes vhdl-mode)
10425
10426 (flycheck-def-option-var flycheck-xml-xmlstarlet-xsd-path nil xml-xmlstarlet
10427   "An XSD schema to validate against."
10428   :type '(file :tag "XSD schema")
10429   :safe #'stringp
10430   :package-version '(flycheck . "31"))
10431
10432 (flycheck-define-checker xml-xmlstarlet
10433   "A XML syntax checker and validator using the xmlstarlet utility.
10434
10435 See URL `http://xmlstar.sourceforge.net/'."
10436   ;; Validate standard input with verbose error messages, and do not dump
10437   ;; contents to standard output
10438   :command ("xmlstarlet" "val" "--err" "--quiet"
10439             (option "--xsd" flycheck-xml-xmlstarlet-xsd-path)
10440             "-")
10441   :standard-input t
10442   :error-patterns
10443   ((error line-start "-:" line "." column ": " (message) line-end))
10444   :modes (xml-mode nxml-mode))
10445
10446 (flycheck-def-option-var flycheck-xml-xmllint-xsd-path nil xml-xmllint
10447   "An XSD schema to validate against."
10448   :type '(file :tag "XSD schema")
10449   :safe #'stringp
10450   :package-version '(flycheck . "31"))
10451
10452 (flycheck-define-checker xml-xmllint
10453   "A XML syntax checker and validator using the xmllint utility.
10454
10455 The xmllint is part of libxml2, see URL
10456 `http://www.xmlsoft.org/'."
10457   :command ("xmllint" "--noout"
10458             (option "--schema" flycheck-xml-xmllint-xsd-path)
10459             "-")
10460   :standard-input t
10461   :error-patterns
10462   ((error line-start "-:" line ": " (message) line-end))
10463   :modes (xml-mode nxml-mode))
10464
10465 (flycheck-define-checker yaml-jsyaml
10466   "A YAML syntax checker using JS-YAML.
10467
10468 See URL `https://github.com/nodeca/js-yaml'."
10469   :command ("js-yaml")
10470   :standard-input t
10471   :error-patterns
10472   ((error line-start
10473           (or "JS-YAML" "YAMLException") ": "
10474           (message) " at line " line ", column " column ":"
10475           line-end))
10476   :modes yaml-mode
10477   :next-checkers ((warning . cwl)))
10478
10479 (flycheck-define-checker yaml-ruby
10480   "A YAML syntax checker using Ruby's YAML parser.
10481
10482 This syntax checker uses the YAML parser from Ruby's standard
10483 library.
10484
10485 See URL `http://www.ruby-doc.org/stdlib-2.0.0/libdoc/yaml/rdoc/YAML.html'."
10486   :command ("ruby" "-ryaml" "-e" "begin;
10487    YAML.load(STDIN); \
10488  rescue Exception => e; \
10489    STDERR.puts \"stdin:#{e}\"; \
10490  end")
10491   :standard-input t
10492   :error-patterns
10493   ((error line-start "stdin:" (zero-or-more not-newline) ":" (message)
10494           "at line " line " column " column line-end))
10495   :modes yaml-mode
10496   :next-checkers ((warning . cwl)))
10497
10498 (provide 'flycheck)
10499
10500 ;; Local Variables:
10501 ;; coding: utf-8
10502 ;; indent-tabs-mode: nil
10503 ;; End:
10504
10505 ;;; flycheck.el ends here